diff --git a/src/unix/fs.c b/src/unix/fs.c index 52b3123f..2684c814 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -438,7 +438,12 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { return -1; } +#if defined(__MVS__) + len = os390_readlink(req->path, buf, len); +#else len = readlink(req->path, buf, len); +#endif + if (len == -1) { uv__free(buf); diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index ea4e11ac..ca539c26 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -327,3 +327,72 @@ char* mkdtemp(char* path) { return path; } + + +ssize_t os390_readlink(const char* path, char* buf, size_t len) { + ssize_t rlen; + ssize_t vlen; + ssize_t plen; + char* delimiter; + char old_delim; + char* tmpbuf; + char realpathstr[PATH_MAX + 1]; + + tmpbuf = uv__malloc(len + 1); + if (tmpbuf == NULL) { + errno = ENOMEM; + return -1; + } + + rlen = readlink(path, tmpbuf, len); + if (rlen < 0) { + uv__free(tmpbuf); + return rlen; + } + + if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { + /* Straightforward readlink. */ + memcpy(buf, tmpbuf, rlen); + uv__free(tmpbuf); + return rlen; + } + + /* + * There is a parmlib variable at the beginning + * which needs interpretation. + */ + tmpbuf[rlen] = '\0'; + delimiter = strchr(tmpbuf + 2, '/'); + if (delimiter == NULL) + /* No slash at the end */ + delimiter = strchr(tmpbuf + 2, '\0'); + + /* Read real path of the variable. */ + old_delim = *delimiter; + *delimiter = '\0'; + if (realpath(tmpbuf, realpathstr) == NULL) { + uv__free(tmpbuf); + return -1; + } + + /* realpathstr is not guaranteed to end with null byte.*/ + realpathstr[PATH_MAX] = '\0'; + + /* Reset the delimiter and fill up the buffer. */ + *delimiter = old_delim; + plen = strlen(delimiter); + vlen = strlen(realpathstr); + rlen = plen + vlen; + if (rlen > len) { + uv__free(tmpbuf); + errno = ENAMETOOLONG; + return -1; + } + memcpy(buf, realpathstr, vlen); + memcpy(buf + vlen, delimiter, plen); + + /* Done using temporary buffer. */ + uv__free(tmpbuf); + + return rlen; +} diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index 61a7cee8..7aba3d27 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -65,5 +65,6 @@ int scandir(const char* maindir, struct dirent*** namelist, int (*compar)(const struct dirent **, const struct dirent **)); char *mkdtemp(char* path); +ssize_t os390_readlink(const char* path, char* buf, size_t len); #endif /* UV_OS390_SYSCALL_H_ */