diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2014-03-18 16:12:26 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2014-03-18 16:12:48 -0700 |
commit | ea916c70a5fc47ee6036a05416bc7462fd8dc1cd (patch) | |
tree | 4f89c7c262335c9920f3ea19ea919819bf540987 | |
parent | 0093ac8d57a0f1a16fd09d98f6a524dddb6053e7 (diff) | |
download | coreutils-ea916c70a5fc47ee6036a05416bc7462fd8dc1cd.tar.xz |
stat: port birthtime to Solaris 11
Problem reported by Rich Burridge.
* src/stat.c [HAVE_GETATTRAT]: Include <attr.h>, <sys/nvpair.h>.
(print_statfs, print_stat, print_it):
Pass fd, too, for the benefit of get_birthtime.
All uses changed.
(get_birthtime): New function, for porting to Solaris 11.
(print_stat): Use it.
* configure.ac (getattrat, LIB_NVPAIR): New checks.
* src/local.mk (src_stat_LDADD): Add $(LIB_NVPAIR).
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | src/local.mk | 3 | ||||
-rw-r--r-- | src/stat.c | 61 |
3 files changed, 60 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac index 768e62ddf..34f29558c 100644 --- a/configure.ac +++ b/configure.ac @@ -276,6 +276,13 @@ if test $utils_cv_localtime_cache = yes; then AC_DEFINE([LOCALTIME_CACHE], [1], [FIXME]) fi +# Assume that if getattrat exists, it's compatible with Solaris 11. +AC_CHECK_FUNCS([getattrat]) +if test $ac_cv_func_getattrat = yes; then + LIB_NVPAIR=-lnvpair + AC_SUBST([LIB_NVPAIR]) +fi + # SCO-ODT-3.0 is reported to need -los to link programs using initgroups AC_CHECK_FUNCS([initgroups]) if test $ac_cv_func_initgroups = no; then diff --git a/src/local.mk b/src/local.mk index f780ad427..40798d6e8 100644 --- a/src/local.mk +++ b/src/local.mk @@ -240,6 +240,9 @@ src_mknod_LDADD += $(LIB_SMACK) src_runcon_LDADD += $(LIB_SELINUX) src_stat_LDADD += $(LIB_SELINUX) +# for nvlist_lookup_uint64_array +src_stat_LDADD += $(LIB_NVPAIR) + # for gettime, settime, utimecmp, utimens copy_ldadd += $(LIB_CLOCK_GETTIME) src_date_LDADD += $(LIB_CLOCK_GETTIME) diff --git a/src/stat.c b/src/stat.c index 270c03301..fffebe3b6 100644 --- a/src/stat.c +++ b/src/stat.c @@ -152,6 +152,11 @@ statfs (char const *filename, struct fs_info *buf) # endif #endif +#if HAVE_GETATTRAT +# include <attr.h> +# include <sys/nvpair.h> +#endif + /* FIXME: these are used by printf.c, too */ #define isodigit(c) ('0' <= (c) && (c) <= '7') #define octtobin(c) ((c) - '0') @@ -731,7 +736,7 @@ out_file_context (char *pformat, size_t prefix_len, char const *filename) /* Print statfs info. Return zero upon success, nonzero upon failure. */ static bool ATTRIBUTE_WARN_UNUSED_RESULT print_statfs (char *pformat, size_t prefix_len, unsigned int m, - char const *filename, + int fd, char const *filename, void const *data) { STRUCT_STATVFS const *statfsbuf = data; @@ -903,6 +908,38 @@ print_mount_point: return fail; } +static struct timespec +get_birthtime (int fd, char const *filename, struct stat const *st) +{ + struct timespec ts = get_stat_birthtime (st); + +#if HAVE_GETATTRAT + if (ts.tv_nsec < 0) + { + nvlist_t *response; + if ((fd < 0 + ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response) + : fgetattr (fd, XATTR_VIEW_READWRITE, &response)) + == 0) + { + uint64_t *val; + uint_t n; + if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0 + && 2 <= n + && val[0] <= TYPE_MAXIMUM (time_t) + && val[1] < 1000000000 * 2 /* for leap seconds */) + { + ts.tv_sec = val[0]; + ts.tv_nsec = val[1]; + } + nvlist_free (response); + } + } +#endif + + return ts; +} + /* Map a TS with negative TS.tv_nsec to {0,0}. */ static inline struct timespec neg_to_zero (struct timespec ts) @@ -916,7 +953,7 @@ neg_to_zero (struct timespec ts) /* Print stat info. Return zero upon success, nonzero upon failure. */ static bool print_stat (char *pformat, size_t prefix_len, unsigned int m, - char const *filename, void const *data) + int fd, char const *filename, void const *data) { struct stat *statbuf = (struct stat *) data; struct passwd *pw_ent; @@ -1007,7 +1044,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, break; case 'w': { - struct timespec t = get_stat_birthtime (statbuf); + struct timespec t = get_birthtime (fd, filename, statbuf); if (t.tv_nsec < 0) out_string (pformat, prefix_len, "-"); else @@ -1016,7 +1053,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, break; case 'W': out_epoch_sec (pformat, prefix_len, statbuf, - neg_to_zero (get_stat_birthtime (statbuf))); + neg_to_zero (get_birthtime (fd, filename, statbuf))); break; case 'x': out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); @@ -1091,9 +1128,9 @@ print_esc_char (char c) calling PRINT_FUNC for each %-directive encountered. Return zero upon success, nonzero upon failure. */ static bool ATTRIBUTE_WARN_UNUSED_RESULT -print_it (char const *format, char const *filename, +print_it (char const *format, int fd, char const *filename, bool (*print_func) (char *, size_t, unsigned int, - char const *, void const *), + int, char const *, void const *), void const *data) { bool fail = false; @@ -1142,7 +1179,8 @@ print_it (char const *format, char const *filename, putchar ('%'); break; default: - fail |= print_func (dest, len + 1, fmt_code, filename, data); + fail |= print_func (dest, len + 1, fmt_code, + fd, filename, data); break; } break; @@ -1225,7 +1263,7 @@ do_statfs (char const *filename, char const *format) return false; } - bool fail = print_it (format, filename, print_statfs, &statfsbuf); + bool fail = print_it (format, -1, filename, print_statfs, &statfsbuf); return ! fail; } @@ -1234,11 +1272,12 @@ static bool ATTRIBUTE_WARN_UNUSED_RESULT do_stat (char const *filename, char const *format, char const *format2) { + int fd = STREQ (filename, "-") ? 0 : -1; struct stat statbuf; - if (STREQ (filename, "-")) + if (0 <= fd) { - if (fstat (STDIN_FILENO, &statbuf) != 0) + if (fstat (fd, &statbuf) != 0) { error (0, errno, _("cannot stat standard input")); return false; @@ -1258,7 +1297,7 @@ do_stat (char const *filename, char const *format, if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode)) format = format2; - bool fail = print_it (format, filename, print_stat, &statbuf); + bool fail = print_it (format, fd, filename, print_stat, &statbuf); return ! fail; } |