X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/1505643bb70ce66e86d6c72902fe7e9199e93606..70096743d5bed2c4c0221da32ebf824ad6a262c5:/lib/readlinkat.c diff --git a/lib/readlinkat.c b/lib/readlinkat.c index 83ea0af02e..c91cf0e820 100644 --- a/lib/readlinkat.c +++ b/lib/readlinkat.c @@ -1,5 +1,5 @@ /* Read a symlink relative to an open directory. - Copyright (C) 2009-2014 Free Software Foundation, Inc. + Copyright (C) 2009-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +18,10 @@ #include +#include #include +#include +#include #if HAVE_READLINKAT @@ -27,6 +30,21 @@ ssize_t rpl_readlinkat (int fd, char const *file, char *buf, size_t len) { +# if READLINK_TRAILING_SLASH_BUG + size_t file_len = strlen (file); + if (file_len && file[file_len - 1] == '/') + { + /* Even if FILE without the slash is a symlink to a directory, + both lstat() and stat() must resolve the trailing slash to + the directory rather than the symlink. We can therefore + safely use stat() to distinguish between EINVAL and + ENOTDIR/ENOENT, avoiding extra overhead of rpl_lstat(). */ + struct stat st; + if (stat (file, &st) == 0) + errno = EINVAL; + return -1; + } +# endif /* READLINK_TRAILING_SLASH_BUG */ return readlinkat (fd, file, buf, len); }