From: Eric Blake Date: Sat, 19 Sep 2009 01:38:46 +0000 (-0600) Subject: openat: fix fstatat bugs on Solaris 9 X-Git-Tag: v0.1~5443 X-Git-Url: http://erislabs.org.uk/gitweb/?a=commitdiff_plain;h=ff971b940b619067d76bb7a893d0e567636f4fc2;p=gnulib.git openat: fix fstatat bugs on Solaris 9 fstatat(fd,"file/",buf,flag) mistakenly succeeded. * lib/fstatat.c (rpl_fstatat): Copy recent fixes from lstat and stat. * doc/posix-functions/fstatat.texi (fstatat): Document this. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 3c54062c9..e79f9dd41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2009-09-19 Eric Blake + openat: fix fstatat bugs on Solaris 9 + * lib/fstatat.c (rpl_fstatat): Copy recent fixes from lstat and + stat. + * doc/posix-functions/fstatat.texi (fstatat): Document this. + test-unlinkat: enhance test, to expose Solaris 9 bug * tests/test-unlink.c (main): Factor guts... * tests/test-unlink.h (test_rmdir_func): ...into new file. diff --git a/doc/posix-functions/fstatat.texi b/doc/posix-functions/fstatat.texi index 4b9fcbc4b..d1c4c8341 100644 --- a/doc/posix-functions/fstatat.texi +++ b/doc/posix-functions/fstatat.texi @@ -13,8 +13,22 @@ This function is missing on some platforms: glibc 2.3.6, MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Cygwin 1.5.x, mingw, Interix 3.5, BeOS. But the replacement function is not safe to be used in libraries and is not multithread-safe. +@item +On some platforms, @code{fstatat(fd,"file/",buf,flag)} succeeds instead of +failing with @code{ENOTDIR}. +Solaris 9. +@item +For symlinks, when the argument ends in a slash, some platforms don't +dereference the argument: +Solaris 9. @end itemize Portability problems not fixed by Gnulib: @itemize +@item +On platforms where @code{off_t} is a 32-bit type, @code{fstatat} may +not correctly report the size of files or block devices larger than 2 +GB. The fix is to use the @code{AC_SYS_LARGEFILE} macro. +@item +On Windows platforms (excluding Cygwin), @code{st_ino} is always 0. @end itemize diff --git a/lib/fstatat.c b/lib/fstatat.c index 9b0c1afa2..59d742224 100644 --- a/lib/fstatat.c +++ b/lib/fstatat.c @@ -28,31 +28,37 @@ #undef fstatat /* fstatat should always follow symbolic links that end in /, but on - Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified. This is - the same problem that lstat.c addresses, so solve it in a similar - way. */ + Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified. + Likewise, trailing slash on a non-directory should be an error. + These are the same problems that lstat.c and stat.c address, so + solve it in a similar way. */ int rpl_fstatat (int fd, char const *file, struct stat *st, int flag) { int result = fstatat (fd, file, st, flag); + size_t len; - if (result == 0 && (flag & AT_SYMLINK_NOFOLLOW) && S_ISLNK (st->st_mode) - && file[strlen (file) - 1] == '/') + if (result != 0) + return result; + len = strlen (file); + if (flag & AT_SYMLINK_NOFOLLOW) { - /* FILE refers to a symbolic link and the name ends with a slash. - Get info about the link's referent. */ - result = fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); - if (result == 0 && ! S_ISDIR (st->st_mode)) + /* Fix lstat behavior. */ + if (file[len - 1] != '/' || S_ISDIR (st->st_mode)) + return 0; + if (!S_ISLNK (st->st_mode)) { - /* fstatat succeeded and FILE references a non-directory. - But it was specified via a name including a trailing - slash. Fail with errno set to ENOTDIR to indicate the - contradiction. */ errno = ENOTDIR; return -1; } + result = fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); + } + /* Fix stat behavior. */ + if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/') + { + errno = ENOTDIR; + return -1; } - return result; }