From b11bca01075e21c9da564227c61e482fe3410dd3 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 27 Mar 2007 18:51:17 +0000 Subject: [PATCH] * lib/stat-time.h (USE_BIRTHTIME): Remove. (get_stat_atime_ns, get_stat_ctime_ns, get_stat_mtime_ns): (get_stat_birthtime_ns): Do not try to use "spare" fields. (get_stat_birthtime_ns): Simplify compile-time tests. (get_stat_birthtime): Change the API to look like get_stat_mtime etc., except return a negative tv_nsec on error. * m4/stat-time.m4 (gl_STAT_TIME, gl_STAT_BIRTHTIME): Don't check for "spare" fields. (gl_STAT_BIRTHTIME): Don't check for struct stat.st_birthtimespec.tv_sec or for struct stat.st_birthtime, as these tests aren't used. * tests/test-stat-time.c (test_birthtime): Adjust to new API. --- ChangeLog | 14 ++++++ lib/stat-time.h | 116 ++++++++++++++----------------------------------- m4/stat-time.m4 | 28 +++++------- tests/test-stat-time.c | 7 ++- 4 files changed, 60 insertions(+), 105 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3e7ee2581..b8f5db0aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2007-03-27 Paul Eggert + + * lib/stat-time.h (USE_BIRTHTIME): Remove. + (get_stat_atime_ns, get_stat_ctime_ns, get_stat_mtime_ns): + (get_stat_birthtime_ns): Do not try to use "spare" fields. + (get_stat_birthtime_ns): Simplify compile-time tests. + (get_stat_birthtime): Change the API to look like + get_stat_mtime etc., except return a negative tv_nsec on error. + * m4/stat-time.m4 (gl_STAT_TIME, gl_STAT_BIRTHTIME): + Don't check for "spare" fields. + (gl_STAT_BIRTHTIME): Don't check for struct stat.st_birthtimespec.tv_sec + or for struct stat.st_birthtime, as these tests aren't used. + * tests/test-stat-time.c (test_birthtime): Adjust to new API. + 2007-03-27 Bruno Haible * lib/stat-time.h: Include . diff --git a/lib/stat-time.h b/lib/stat-time.h index 50e907c5a..e98cee3e9 100644 --- a/lib/stat-time.h +++ b/lib/stat-time.h @@ -45,13 +45,6 @@ # define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.st__tim.tv_nsec) #endif -#if defined HAVE_STRUCT_STAT_ST_BIRTHTIME || defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC || defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC || defined HAVE_STRUCT_STAT_ST_SPARE4 -# define USE_BIRTHTIME 1 -#else -# undef USE_BIRTHTIME -#endif - - /* Return the nanosecond component of *ST's access time. */ static inline long int get_stat_atime_ns (struct stat const *st) @@ -60,8 +53,6 @@ get_stat_atime_ns (struct stat const *st) return STAT_TIMESPEC (st, st_atim).tv_nsec; # elif defined STAT_TIMESPEC_NS return STAT_TIMESPEC_NS (st, st_atim); -# elif defined HAVE_STRUCT_STAT_ST_SPARE1 - return st->st_spare1 * 1000; # else return 0; # endif @@ -75,8 +66,6 @@ get_stat_ctime_ns (struct stat const *st) return STAT_TIMESPEC (st, st_ctim).tv_nsec; # elif defined STAT_TIMESPEC_NS return STAT_TIMESPEC_NS (st, st_ctim); -# elif defined HAVE_STRUCT_STAT_ST_SPARE1 - return st->st_spare3 * 1000; # else return 0; # endif @@ -90,8 +79,6 @@ get_stat_mtime_ns (struct stat const *st) return STAT_TIMESPEC (st, st_mtim).tv_nsec; # elif defined STAT_TIMESPEC_NS return STAT_TIMESPEC_NS (st, st_mtim); -# elif defined HAVE_STRUCT_STAT_ST_SPARE1 - return st->st_spare2 * 1000; # else return 0; # endif @@ -101,22 +88,13 @@ get_stat_mtime_ns (struct stat const *st) static inline long int get_stat_birthtime_ns (struct stat const *st) { -# if defined USE_BIRTHTIME -# if defined STAT_TIMESPEC && defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC +# if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC return STAT_TIMESPEC (st, st_birthtim).tv_nsec; -# elif defined STAT_TIMESPEC_NS && defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_SEC +# elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC return STAT_TIMESPEC_NS (st, st_birthtim); -# elif defined HAVE_STRUCT_STAT_ST_SPARE4 - /* Cygwin, without __CYGWIN_USE_BIG_TYPES__ */ - return st->st_spare4[1] * 1000L; -# else - /* Birthtime is available, but not at nanosecond resolution. */ - return 0; -# endif # else - /* Birthtime is not available, so indicate this in the returned value. */ return 0; -# endif +# endif } /* Return *ST's access time. */ @@ -161,69 +139,41 @@ get_stat_mtime (struct stat const *st) #endif } -/* Return *ST's birth time, if available, in *PTS. A nonzero value is - * returned if the stat structure appears to indicate that the - * timestamp is available. - * - * The return value of this function does not reliably indicate that the - * returned data is valid; see the comments within the body of the - * function for an explanation. - */ -static inline int -get_stat_birthtime (struct stat const *st, - struct timespec *pts) +/* Return *ST's birth time, if available; otherwise return a value + with negative tv_nsec. */ +static inline struct timespec +get_stat_birthtime (struct stat const *st) { -#if defined USE_BIRTHTIME -# ifdef STAT_TIMESPEC - *pts = STAT_TIMESPEC (st, st_birthtim); -# else struct timespec t; - pts->tv_sec = st->st_birthtime; - pts->tv_nsec = get_stat_birthtime_ns (st); -# endif - /* NetBSD sometimes signals the absence of knowledge of the file's - * birth time by using zero. We indicate we don't know, by - * returning 0 from this function when that happens. This is - * slightly problematic since (time_t)0 is otherwise a valid, albeit - * unlikely, timestamp. - * - * NetBSD sometimes returns 0 for unknown values (for example on - * ffs) and sometimes begative values for tv_nsec (for example on - * NFS). For some filesystems (e.g. msdos) NetBSD also appears to - * fail to update the st_birthtime member at all, and just leaves in - * there whatever junk existed int he uninitialised stat structure - * the caller provided. Therefore, callers are advised to initialise - * the tv_nsec number to a negative value before they call stat in - * order to detect this problem. - */ - if (pts->tv_sec == (time_t)0) - { - return 0; /* result probably invalid, see above. */ - } - else - { - /* Sometimes NetBSD returns junk in the birth time fields, so - * do a simple range check on the data, and return 0 to indicate - * that the data is invalid if it just looks wrong. - */ - return (pts->tv_nsec >= 0) && (pts->tv_nsec <= 1000000000); - } -#elif (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ - /* Woe32 native platforms (mingw, msvc, but not Cygwin) put the - * "file creation time" in st_ctime (!). See for example the - * article - * - */ - pts->tv_sec = st->st_ctime; - pts->tv_nsec = 0; - return 1; /* result is valid */ +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC + t = STAT_TIMESPEC (st, st_birthtim); +#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC + t.tv_sec = st->st_birthtime; + t.tv_nsec = st->st_birthtimensec; + + /* NetBSD sometimes signals the absence of knowledge by using zero. + Attempt to work around this bug. This sometimes reports failure + even for valid time stamps. Also, sometimes NetBSD returns junk + in the birth time fields; work around this bug if it it is + detected. There's no need to detect negative tv_nsec junk as + negative tv_nsec already indicates an error. */ + if (t.tv_sec == 0 || 1000000000 <= t.tv_nsec) + t.tv_nsec = -1; + +#elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* Woe32 native platforms (but not Cygwin) put the "file creation + time" in st_ctime (!). See + . */ + t.tv_sec = st->st_ctime; + t.tv_nsec = 0; #else - /* Birth time not supported. */ - pts->tv_sec = 0; - pts->tv_nsec = 0; - return 0; /* result is not valid */ + /* Birth time is not supported. Set tv_sec to avoid undefined behavior. */ + t.tv_sec = -1; + t.tv_nsec = -1; #endif + + return t; } #endif diff --git a/m4/stat-time.m4 b/m4/stat-time.m4 index 6b98dd73c..1460c82fb 100644 --- a/m4/stat-time.m4 +++ b/m4/stat-time.m4 @@ -13,9 +13,8 @@ dnl From Paul Eggert. # st_atimespec.tv_nsec - FreeBSD, NetBSD, if ! defined _POSIX_SOURCE # st_atimensec - FreeBSD, NetBSD, if defined _POSIX_SOURCE # st_atim.st__tim.tv_nsec - UnixWare (at least 2.1.2 through 7.1) -# st_spare1 - Cygwin? -# st_birthtimespec present on NetBSD (probably also FreBSD, OpenBSD) +# st_birthtimespec - FreeBSD, NetBSD (hidden on OpenBSD 3.9, anyway) AC_DEFUN([gl_STAT_TIME], [ @@ -49,11 +48,7 @@ AC_DEFUN([gl_STAT_TIME], fi], [AC_CHECK_MEMBERS([struct stat.st_atimespec.tv_nsec], [], [AC_CHECK_MEMBERS([struct stat.st_atimensec], [], - [AC_CHECK_MEMBERS([struct stat.st_atim.st__tim.tv_nsec], [], - [AC_CHECK_MEMBERS([struct stat.st_spare1], [], - [], - [#include - #include ])], + [AC_CHECK_MEMBERS([struct stat.st_atim.st__tim.tv_nsec], [], [], [#include #include ])], [#include @@ -64,23 +59,20 @@ AC_DEFUN([gl_STAT_TIME], #include ]) ]) -# Checks for st_birthtime, which is a feature from UFS2 (FreeBSD, NetBSD, OpenBSD, etc.) -# There was a time when this field was named st_createtime (21 June 2002 to 16 July 2002) -# But that window is very small and applied only to development code, so systems still -# using that configuration are not a realistic development target. -# See revisions 1.10 and 1.11 of FreeBSD's src/sys/ufs/ufs/dinode.h. +# Check for st_birthtime, a feature from UFS2 (FreeBSD, NetBSD, OpenBSD, etc.). +# There was a time when this field was named st_createtime (21 June +# 2002 to 16 July 2002) But that window is very small and applied only +# to development code, so systems still using that configuration are +# not supported. See revisions 1.10 and 1.11 of FreeBSD's +# src/sys/ufs/ufs/dinode.h. # AC_DEFUN([gl_STAT_BIRTHTIME], [ AC_REQUIRE([AC_C_INLINE]) AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CHECK_HEADERS_ONCE([sys/time.h]) - AC_CHECK_MEMBERS([struct stat.st_birthtimespec.tv_sec, struct stat.st_birthtimespec.tv_nsec], [], - [AC_CHECK_MEMBERS([struct stat.st_birthtime, struct stat.st_birthtimensec], [], - [AC_CHECK_MEMBERS([struct stat.st_spare4], [], - [], - [#include - #include ])], + AC_CHECK_MEMBERS([struct stat.st_birthtimespec.tv_nsec], [], + [AC_CHECK_MEMBERS([struct stat.st_birthtimensec], [], [], [#include #include ])], [#include diff --git a/tests/test-stat-time.c b/tests/test-stat-time.c index eaf87e97e..2d86b450e 100644 --- a/tests/test-stat-time.c +++ b/tests/test-stat-time.c @@ -135,10 +135,9 @@ test_birthtime (const struct stat *statinfo, /* Collect the birth times.. */ for (i = 0; i < NFILES; ++i) { - if (!get_stat_birthtime (&statinfo[i], &birthtimes[i])) - { - return; - } + birthtimes[i] = get_stat_birthtime (&statinfo[i]); + if (birthtimes[i].tv_nsec < 0) + return; } ASSERT (modtimes[0].tv_sec < birthtimes[1].tv_sec); /* mtime(stamp1) < birthtime(renamed) */ -- 2.11.0