components/coreutils/patches/stat-birthtime.patch
author Rich Burridge <rich.burridge@oracle.com>
Thu, 17 Apr 2014 10:00:40 -0700
changeset 1833 0edb05d72e6b
permissions -rw-r--r--
16575074 stat could support birthtime/crtime on ZFS

Changes to implement:
16575074 stat could support birthtime/crtime on ZFS

These changes have already been accepted upstream. See:
http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=ea916c70a5fc47ee6036a05416bc7462fd8dc1cd

--- coreutils-8.16/configure.ac.orig	2014-03-18 20:12:23.362356112 -0700
+++ coreutils-8.16/configure.ac	2014-03-18 20:13:47.327463395 -0700
@@ -240,6 +240,13 @@
   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
--- coreutils-8.16/src/Makefile.am.orig	2014-03-18 20:19:34.447566111 -0700
+++ coreutils-8.16/src/Makefile.am	2014-03-18 20:20:20.876086076 -0700
@@ -326,6 +326,9 @@
 runcon_LDADD += $(LIB_SELINUX)
 stat_LDADD += $(LIB_SELINUX)
 
+# for nvlist_lookup_uint64_array
+stat_LDADD += $(LIB_NVPAIR)
+
 # for gettime, settime, utimecmp, utimens
 copy_LDADD += $(LIB_CLOCK_GETTIME)
 date_LDADD += $(LIB_CLOCK_GETTIME)
--- coreutils-8.16/src/stat.c.orig	2014-03-16 16:55:52.605732676 -0700
+++ coreutils-8.16/src/stat.c	2014-03-18 20:27:04.302699124 -0700
@@ -148,6 +148,11 @@
 # 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')
@@ -689,7 +694,7 @@
 /* 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;
@@ -861,6 +866,38 @@
   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)
@@ -874,7 +911,7 @@
 /* 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;
@@ -967,7 +1004,7 @@
       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
@@ -976,7 +1013,7 @@
       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)));
@@ -1051,9 +1088,9 @@
    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;
@@ -1102,7 +1139,8 @@
                 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;
@@ -1185,7 +1223,7 @@
       return false;
     }
 
-  bool fail = print_it (format, filename, print_statfs, &statfsbuf);
+  bool fail = print_it (format, -1, filename, print_statfs, &statfsbuf);
   return ! fail;
 }
 
@@ -1194,11 +1232,12 @@
 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;
@@ -1218,7 +1257,7 @@
   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;
 }