summaryrefslogtreecommitdiff
path: root/lib/readlinkat.c
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2015-05-31 03:08:52 +0100
committerPádraig Brady <P@draigBrady.com>2015-05-31 03:44:51 +0100
commit8c9cfa07e6eb6a3365a516c90568fc6c5f3fcd34 (patch)
treed17818b3b9621dfb72add4e13ef646cfa487fbe0 /lib/readlinkat.c
parent04e445830cb607c69888534d88e6f1f6eb01839e (diff)
downloadgnulib-8c9cfa07e6eb6a3365a516c90568fc6c5f3fcd34.tar.gz
readlinkat: avoid OS X 10.10 trailing slash bug
* doc/posix-functions/readlink.texi: Mention that OS X 10.10 has this bug. * doc/posix-functions/readlinkat.texi: Likewise. Also mention that OS X 10.10 has this function. * lib/readlinkat.c (rpl_readlinkat): Handle the trailing slash bug, as done for readlink(). * m4/readlinkat.m4 (gl_FUNC_READLINKAT): Check for the readlink() trailing slash bug, and assume readlinkat() has the same issue. Also fix a typo where $gl_cv_decl_readlink_works was tested, rather than the correct $gl_cv_decl_readlinkat_works.
Diffstat (limited to 'lib/readlinkat.c')
-rw-r--r--lib/readlinkat.c18
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);
}