unix: do not require PATH_MAX to be defined

Some platforms (e.g. GNU/Hurd) do not define PATH_MAX.  Add a few other
variants and a fallback constant.  Also use alternatives where possible:

* For readlink(), use lstat() to read the length of the link first.
  If it is not a symlink, report EINVAL before trying to allocate.
  If the size reports as zero, fall back one of the PATH_MAX variants.

* For realpath(), POSIX 2008 allows us to pass a NULL buffer
  to tell it to malloc() internally.

This patch was inspired by downstream patches in Debian packaging.

PR-URL: https://github.com/libuv/libuv/pull/2008
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>

Bug-Debian: https://bugs.debian.org/897061
Bug-Debian: https://bugs.debian.org/909011
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1792647
Inspired-by: Mauricio Faria de Oliveira <mfo@canonical.com>
Inspired-by: Samuel Thibault <sthibault@debian.org>
This commit is contained in:
Brad King 2018-09-28 12:41:12 -04:00 committed by Ben Noordhuis
parent 0c2b3de331
commit b56d279b17

View File

@ -358,19 +358,22 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) {
return n; return n;
} }
#if defined(_POSIX_PATH_MAX)
# define UV__FS_PATH_MAX _POSIX_PATH_MAX
#elif defined(PATH_MAX)
# define UV__FS_PATH_MAX PATH_MAX
#else
# define UV__FS_PATH_MAX_FALLBACK 8192
# define UV__FS_PATH_MAX UV__FS_PATH_MAX_FALLBACK
#endif
static ssize_t uv__fs_pathmax_size(const char* path) { static ssize_t uv__fs_pathmax_size(const char* path) {
ssize_t pathmax; ssize_t pathmax;
pathmax = pathconf(path, _PC_PATH_MAX); pathmax = pathconf(path, _PC_PATH_MAX);
if (pathmax == -1) { if (pathmax == -1)
#if defined(PATH_MAX) pathmax = UV__FS_PATH_MAX;
return PATH_MAX;
#else
#error "PATH_MAX undefined in the current platform"
#endif
}
return pathmax; return pathmax;
} }
@ -381,7 +384,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
char* buf; char* buf;
char* newbuf; char* newbuf;
#if defined(UV__FS_PATH_MAX_FALLBACK)
/* We may not have a real PATH_MAX. Read size of link. */
struct stat st;
int ret;
ret = lstat(req->path, &st);
if (ret != 0)
return -1;
if (!S_ISLNK(st.st_mode)) {
errno = EINVAL;
return -1;
}
maxlen = st.st_size;
/* According to readlink(2) lstat can report st_size == 0
for some symlinks, such as those in /proc or /sys. */
if (maxlen == 0)
maxlen = uv__fs_pathmax_size(req->path); maxlen = uv__fs_pathmax_size(req->path);
#else
maxlen = uv__fs_pathmax_size(req->path);
#endif
buf = uv__malloc(maxlen); buf = uv__malloc(maxlen);
if (buf == NULL) { if (buf == NULL) {
@ -419,9 +443,15 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
} }
static ssize_t uv__fs_realpath(uv_fs_t* req) { static ssize_t uv__fs_realpath(uv_fs_t* req) {
ssize_t len;
char* buf; char* buf;
#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
buf = realpath(req->path, NULL);
if (buf == NULL)
return -1;
#else
ssize_t len;
len = uv__fs_pathmax_size(req->path); len = uv__fs_pathmax_size(req->path);
buf = uv__malloc(len + 1); buf = uv__malloc(len + 1);
@ -434,6 +464,7 @@ static ssize_t uv__fs_realpath(uv_fs_t* req) {
uv__free(buf); uv__free(buf);
return -1; return -1;
} }
#endif
req->ptr = buf; req->ptr = buf;