diff options
Diffstat (limited to 'lib/readlinkat.c')
-rw-r--r-- | lib/readlinkat.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/lib/readlinkat.c b/lib/readlinkat.c index f4826f9202..c91cf0e820 100644 --- a/lib/readlinkat.c +++ b/lib/readlinkat.c @@ -18,7 +18,10 @@ #include <config.h> +#include <errno.h> #include <unistd.h> +#include <string.h> +#include <sys/stat.h> #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); } |