X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Futimens.c;h=8d8bef468ecdef2f444f2434d20cdbdbe3e0a31b;hb=2ddb59ff29a52f07859d76eeb92dc7cfded8bbc6;hp=0b2f3e4d091f5b7568d4241db93e63910effe706;hpb=9a66010992ca6ea590f26fc89362b5b288e5ffbd;p=gnulib.git diff --git a/lib/utimens.c b/lib/utimens.c index 0b2f3e4d0..8d8bef468 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -26,6 +26,7 @@ #include #include +#include #if HAVE_UTIME_H # include @@ -41,6 +42,16 @@ struct utimbuf }; #endif +/* Some systems don't have ENOSYS. */ +#ifndef ENOSYS +# ifdef ENOTSUP +# define ENOSYS ENOTSUP +# else +/* Some systems don't have ENOTSUP either. */ +# define ENOSYS EINVAL +# endif +#endif + #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ # define __attribute__(x) #endif @@ -53,7 +64,11 @@ struct utimbuf TIMESPEC[0] and TIMESPEC[1], respectively. FD must be either negative -- in which case it is ignored -- or a file descriptor that is open on FILE. - If TIMESPEC is null, set the time stamps to the current time. */ + If FD is nonnegative, then FILE can be NULL, which means + use just futimes (or equivalent) instead of utimes (or equivalent), + and fail if on an old system without futimes (or equivalent). + If TIMESPEC is null, set the time stamps to the current time. + Return 0 on success, -1 (setting errno) on failure. */ int futimens (int fd ATTRIBUTE_UNUSED, @@ -78,42 +93,64 @@ futimens (int fd ATTRIBUTE_UNUSED, # if HAVE_FUTIMESAT return fd < 0 ? futimesat (AT_FDCWD, file, t) : futimesat (fd, NULL, t); -# else -# if HAVE_FUTIMES +# elif HAVE_FUTIMES if (0 <= fd) { if (futimes (fd, t) == 0) return 0; - /* On GNU/Linux without the futimes syscall and without /proc - mounted, glibc futimes fails with errno == ENOENT. Fall back - on utimes if we get a weird error number like that. */ - switch (errno) - { - case EACCES: - case EIO: - case EPERM: - case EROFS: - return -1; - } + /* Don't worry about trying to speed things up by returning right + away here. glibc futimes can incorrectly fail with errno == + ENOENT if /proc isn't mounted. Also, Mandrake 10.0 in high + security mode doesn't allow ordinary users to read /proc/self, so + glibc futimes incorrectly fails with errno == EACCES. If futimes + fails with errno == EIO, EPERM, or EROFS, it's probably safe to + fail right away, but these cases are rare enough that they're not + worth optimizing, and who knows what other messed-up systems are + out there? So play it safe and fall back on the code below. */ } -# endif - return utimes (file, t); # endif +#endif -#else +#if ! HAVE_FUTIMESAT - struct utimbuf utimbuf; - struct utimbuf const *t; - if (timespec) + if (!file) { - utimbuf.actime = timespec[0].tv_sec; - utimbuf.modtime = timespec[1].tv_sec; - t = &utimbuf; +# if ! (HAVE_WORKING_UTIMES && HAVE_FUTIMES) + errno = ENOSYS; +# endif + + /* Prefer EBADF to ENOSYS if both error numbers apply. */ + if (errno == ENOSYS) + { + int fd2 = dup (fd); + int dup_errno = errno; + if (0 <= fd2) + close (fd2); + errno = (fd2 < 0 && dup_errno == EBADF ? EBADF : ENOSYS); + } + + return -1; } - else - t = NULL; - return utime (file, t); + +# if HAVE_WORKING_UTIMES + return utimes (file, t); +# else + { + struct utimbuf utimbuf; + struct utimbuf const *ut; + if (timespec) + { + utimbuf.actime = timespec[0].tv_sec; + utimbuf.modtime = timespec[1].tv_sec; + ut = &utimbuf; + } + else + ut = NULL; + + return utime (file, ut); + } +# endif #endif }