2009-09-19 Eric Blake <ebb9@byu.net>
+ 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.
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
#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;
}