bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

patch to add microsecond resolution support to cp -p, etc.


From: Paul Eggert
Subject: patch to add microsecond resolution support to cp -p, etc.
Date: Wed, 06 Aug 2003 18:29:40 -0700
User-agent: Gnus/5.1002 (Gnus v5.10.2) Emacs/21.2 (gnu/linux)

Sun patch 109933-02 for Solaris 8 sparc, released August 1, added
support to "cp -p" to set file timestamps to microsecond resolution,
instead of the old behavior, which set them only to 1-second
resolution.  Sun "make" relies on this new behavior so that "make"
actions like "dest: source; cp -p source dest" do not confuse "make".

Here is a patch to add this capability to GNU coreutils.

2003-08-06  Paul Eggert  <address@hidden>

        * NEWS: Add support for setting file timestamps to microsecond
        resolution, on hosts that support this.
        * lib/Makefile.am (libeftish_a_SOURCES): Add utimens.c, utimens.h.
        * lib/utimens.c, lib/utimens.h: New files.
        * m4/prereq.m4 (jm_PREREQ): Require gl_UTIMENS.
        * m4/timespec.m4: Sync with gnulib.
        * m4/utimens.m4: New file.
        * src/copy.c, src/cp.c, src/install.c, src/touch.c: Include timespec.h.
        * src/copy.c (copy_internal):
        Set file timestamps with utimens, not utimes.
        * src/cp.c (re_protect): Likewise.
        * src/install.c (change_timestamps): Likewise.
        * src/touch.c (newtime, touch, main): Likewise.

diff -Naurp coreutils/NEWS coreutils-cp-p/NEWS
--- coreutils/NEWS      2003-08-01 15:35:57.000000000 -0700
+++ coreutils-cp-p/NEWS 2003-08-06 18:12:31.948642000 -0700
@@ -29,6 +29,12 @@ GNU coreutils NEWS                      
   but POSIX did not actually require this undesirable behavior, so it
   has been removed.
 
+  cp, install, mv, and touch now preserve microsecond resolution on
+  file timestamps, on platforms that have the 'utimes' system call.
+  Unfortunately there is no system call yet to preserve file
+  timestamps to their full nanosecond resolution; microsecond
+  resolution is the best we can do right now.
+
 ** Bug fixes
 
   kill no longer tries to operate on argv[0] (introduced in 5.0.1)
diff -Naurp coreutils/lib/Makefile.am coreutils-cp-p/lib/Makefile.am
--- coreutils/lib/Makefile.am   2003-07-31 23:38:38.000000000 -0700
+++ coreutils-cp-p/lib/Makefile.am      2003-08-06 16:07:00.445934000 -0700
@@ -112,6 +112,7 @@ libfetish_a_SOURCES = \
   unistd-safer.h \
   unlocked-io.h \
   userspec.c \
+  utimens.c utimens.h \
   version-etc.c version-etc.h \
   xalloc.h \
   xgetcwd.c xgetcwd.h \
diff -Naurp coreutils/lib/utimens.c coreutils-cp-p/lib/utimens.c
--- coreutils/lib/utimens.c     1969-12-31 16:00:00.000000000 -0800
+++ coreutils-cp-p/lib/utimens.c        2003-08-06 17:22:16.829405000 -0700
@@ -0,0 +1,63 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by Paul Eggert.  */
+
+/* derived from a function in touch.c */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "utimens.h"
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+/* Some systems (even some that do have <utime.h>) don't declare this
+   structure anywhere.  */
+#ifndef HAVE_STRUCT_UTIMBUF
+struct utimbuf
+{
+  long actime;
+  long modtime;
+};
+#endif
+
+/* Set the access and modification time stamps of FILE to be
+   TIMESPEC[0] and TIMESPEC[1], respectively.  */
+
+int
+utimens (char const *file, struct timespec const timespec[2])
+{
+  /* There's currently no interface to set file timestamps with
+     nanosecond resolution, so do the best we can, discarding any
+     fractional part of the timestamp.  */
+#if HAVE_UTIMES
+  struct timeval timeval[2];
+  timeval[0].tv_sec = timespec[0].tv_sec;
+  timeval[0].tv_usec = timespec[0].tv_nsec / 1000;
+  timeval[1].tv_sec = timespec[1].tv_sec;
+  timeval[1].tv_usec = timespec[1].tv_nsec / 1000;
+  return utimes (file, timeval);
+#else
+  struct utimbuf utimbuf;
+  utimbuf.actime = timespec[0].tv_sec;
+  utimbuf.modtime = timespec[1].tv_sec;
+  return utime (file, &utimbuf);
+#endif
+}
diff -Naurp coreutils/lib/utimens.h coreutils-cp-p/lib/utimens.h
--- coreutils/lib/utimens.h     1969-12-31 16:00:00.000000000 -0800
+++ coreutils-cp-p/lib/utimens.h        2003-08-06 15:05:40.049938000 -0700
@@ -0,0 +1,2 @@
+#include "timespec.h"
+int utimens (char const *, struct timespec const [2]);
diff -Naurp coreutils/m4/prereq.m4 coreutils-cp-p/m4/prereq.m4
--- coreutils/m4/prereq.m4      2003-06-06 00:07:13.000000000 -0700
+++ coreutils-cp-p/m4/prereq.m4 2003-08-06 16:34:47.728722000 -0700
@@ -31,6 +31,7 @@ AC_DEFUN([jm_PREREQ],
   AC_REQUIRE([jm_PREREQ_STAT])
   AC_REQUIRE([jm_PREREQ_STRNLEN])
   AC_REQUIRE([jm_PREREQ_TEMPNAME]) # called by mkstemp
+  AC_REQUIRE([gl_UTIMENS])
   AC_REQUIRE([jm_PREREQ_XGETCWD])
   AC_REQUIRE([jm_PREREQ_XREADLINK])
 ])
diff -Naurp coreutils/m4/timespec.m4 coreutils-cp-p/m4/timespec.m4
--- coreutils/m4/timespec.m4    2001-09-17 14:44:03.000000000 -0700
+++ coreutils-cp-p/m4/timespec.m4       2003-08-06 16:35:22.478602000 -0700
@@ -1,13 +1,28 @@
-#serial 5
+#serial 6
 
 dnl From Jim Meyering
 
+AC_DEFUN([gl_TIMESPEC],
+[
+  dnl Prerequisites of lib/timespec.h.
+  AC_REQUIRE([AC_HEADER_TIME])
+  AC_CHECK_HEADERS_ONCE(sys/time.h)
+  jm_CHECK_TYPE_STRUCT_TIMESPEC
+  AC_STRUCT_ST_MTIM_NSEC
+
+  dnl Persuade glibc <time.h> to declare nanosleep().
+  AC_REQUIRE([AC_GNU_SOURCE])
+
+  AC_CHECK_DECLS(nanosleep, , , [#include <time.h>])
+])
+
 dnl Define HAVE_STRUCT_TIMESPEC if `struct timespec' is declared
 dnl in time.h or sys/time.h.
 
 AC_DEFUN([jm_CHECK_TYPE_STRUCT_TIMESPEC],
 [
   AC_REQUIRE([AC_HEADER_TIME])
+  AC_CHECK_HEADERS_ONCE(sys/time.h)
   AC_CACHE_CHECK([for struct timespec], fu_cv_sys_struct_timespec,
     [AC_TRY_COMPILE(
       [
diff -Naurp coreutils/m4/utimens.m4 coreutils-cp-p/m4/utimens.m4
--- coreutils/m4/utimens.m4     1969-12-31 16:00:00.000000000 -0800
+++ coreutils-cp-p/m4/utimens.m4        2003-08-06 17:21:52.839505000 -0700
@@ -0,0 +1,15 @@
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+AC_DEFUN([gl_UTIMENS],
+[
+  dnl Prerequisites of lib/utimens.c.
+  AC_REQUIRE([gl_TIMESPEC])
+  AC_REQUIRE([jm_CHECK_TYPE_STRUCT_TIMESPEC])
+  AC_REQUIRE([jm_CHECK_TYPE_STRUCT_UTIMBUF])
+  AC_CHECK_FUNCS_ONCE(utimes)
+])
diff -Naurp coreutils/src/copy.c coreutils-cp-p/src/copy.c
--- coreutils/src/copy.c        2003-07-22 23:38:18.000000000 -0700
+++ coreutils-cp-p/src/copy.c   2003-08-06 17:21:52.489506000 -0700
@@ -40,6 +40,7 @@
 #include "path-concat.h"
 #include "quote.h"
 #include "same.h"
+#include "timespec.h"
 #include "xreadlink.h"
 
 #define DO_CHOWN(Chown, File, New_uid, New_gid)                                
\
@@ -1523,16 +1524,14 @@ copy_internal (const char *src_path, con
 
   if (x->preserve_timestamps)
     {
-      struct utimbuf utb;
+      struct timespec timespec[2];
 
-      /* There's currently no interface to set file timestamps with
-        better than 1-second resolution, so discard any fractional
-        part of the source timestamp.  */
+      timespec[0].tv_sec = src_sb.st_atime;
+      timespec[0].tv_nsec = TIMESPEC_NS (src_sb.st_atim);
+      timespec[1].tv_sec = src_sb.st_mtime;
+      timespec[1].tv_nsec = TIMESPEC_NS (src_sb.st_mtim);
 
-      utb.actime = src_sb.st_atime;
-      utb.modtime = src_sb.st_mtime;
-
-      if (utime (dst_path, &utb))
+      if (utimens (dst_path, &timespec))
        {
          error (0, errno, _("preserving times for %s"), quote (dst_path));
          if (x->require_preserve)
diff -Naurp coreutils/src/cp.c coreutils-cp-p/src/cp.c
--- coreutils/src/cp.c  2003-07-12 04:38:43.000000000 -0700
+++ coreutils-cp-p/src/cp.c     2003-08-06 17:21:52.139504000 -0700
@@ -32,6 +32,7 @@
 #include "dirname.h"
 #include "path-concat.h"
 #include "quote.h"
+#include "timespec.h"
 
 #define ASSIGN_BASENAME_STRDUPA(Dest, File_name)       \
   do                                                   \
@@ -307,16 +308,14 @@ re_protect (const char *const_dst_path, 
 
       if (x->preserve_timestamps)
        {
-         struct utimbuf utb;
+         struct timespec timespec[2];
 
-         /* There's currently no interface to set file timestamps with
-            better than 1-second resolution, so discard any fractional
-            part of the source timestamp.  */
+         timespec[0].tv_sec = src_sb.st_atime;
+         timespec[0].tv_nsec = TIMESPEC_NS (src_sb.st_atim);
+         timespec[1].tv_sec = src_sb.st_mtime;
+         timespec[1].tv_nsec = TIMESPEC_NS (src_sb.st_mtim);
 
-         utb.actime = src_sb.st_atime;
-         utb.modtime = src_sb.st_mtime;
-
-         if (utime (dst_path, &utb))
+         if (utimens (dst_path, &timespec))
            {
              error (0, errno, _("failed to preserve times for %s"),
                     quote (dst_path));
diff -Naurp coreutils/src/install.c coreutils-cp-p/src/install.c
--- coreutils/src/install.c     2003-07-12 04:38:43.000000000 -0700
+++ coreutils-cp-p/src/install.c        2003-08-06 17:21:51.789506000 -0700
@@ -34,6 +34,7 @@
 #include "modechange.h"
 #include "path-concat.h"
 #include "quote.h"
+#include "timespec.h"
 #include "xstrtol.h"
 
 /* The official name of this program (e.g., no `g' prefix).  */
@@ -485,7 +486,7 @@ static int
 change_timestamps (const char *from, const char *to)
 {
   struct stat stb;
-  struct utimbuf utb;
+  struct timespec timespec[2];
 
   if (stat (from, &stb))
     {
@@ -493,13 +494,11 @@ change_timestamps (const char *from, con
       return 1;
     }
 
-  /* There's currently no interface to set file timestamps with
-     better than 1-second resolution, so discard any fractional
-     part of the source timestamp.  */
-
-  utb.actime = stb.st_atime;
-  utb.modtime = stb.st_mtime;
-  if (utime (to, &utb))
+  timespec[0].tv_sec = stb.st_atime;
+  timespec[0].tv_nsec = TIMESPEC_NS (stb.st_atim);
+  timespec[1].tv_sec = stb.st_mtime;
+  timespec[1].tv_nsec = TIMESPEC_NS (stb.st_mtim);
+  if (utimens (to, timespec))
     {
       error (0, errno, _("cannot set time stamps for %s"), quote (to));
       return 1;
diff -Naurp coreutils/src/touch.c coreutils-cp-p/src/touch.c
--- coreutils/src/touch.c       2003-06-17 11:13:24.000000000 -0700
+++ coreutils-cp-p/src/touch.c  2003-08-06 17:45:50.037260000 -0700
@@ -31,6 +31,7 @@
 #include "posixver.h"
 #include "quote.h"
 #include "safe-read.h"
+#include "timespec.h"
 
 /* The official name of this program (e.g., no `g' prefix).  */
 #define PROGRAM_NAME "touch"
@@ -72,7 +73,7 @@ static int posix_date;
 static int amtime_now;
 
 /* New time to use when setting time. */
-static time_t newtime;
+static struct timespec newtime;
 
 /* File to use for -r. */
 static char *ref_file;
@@ -173,7 +174,7 @@ touch (const char *file)
     }
   else
     {
-      struct utimbuf utb;
+      struct timespec timespec[2];
 
       /* There's currently no interface to set file timestamps with
         better than 1-second resolution, so discard any fractional
@@ -181,19 +182,27 @@ touch (const char *file)
 
       if (use_ref)
        {
-         utb.actime = ref_stats.st_atime;
-         utb.modtime = ref_stats.st_mtime;
+         timespec[0].tv_sec = ref_stats.st_atime;
+         timespec[0].tv_nsec = TIMESPEC_NS (ref_stats.st_atim);
+         timespec[1].tv_sec = ref_stats.st_mtime;
+         timespec[1].tv_nsec = TIMESPEC_NS (ref_stats.st_mtim);
        }
       else
-       utb.actime = utb.modtime = newtime;
+       timespec[0] = timespec[1] = newtime;
 
       if (!(change_times & CH_ATIME))
-       utb.actime = sbuf.st_atime;
+       {
+         timespec[0].tv_sec = sbuf.st_atime;
+         timespec[0].tv_nsec = TIMESPEC_NS (sbuf.st_atim);
+       }
 
       if (!(change_times & CH_MTIME))
-       utb.modtime = sbuf.st_mtime;
+       {
+         timespec[1].tv_sec = sbuf.st_mtime;
+         timespec[1].tv_nsec = TIMESPEC_NS (sbuf.st_mtim);
+       }
 
-      status = utime (file, &utb);
+      status = utimens (file, &timespec);
     }
 
   if (status)
@@ -292,8 +301,9 @@ main (int argc, char **argv)
 
        case 'd':
          flexible_date++;
-         newtime = get_date (optarg, NULL);
-         if (newtime == (time_t) -1)
+         newtime.tv_sec = get_date (optarg, NULL);
+         newtime.tv_nsec = 0; /* FIXME: get_date should set this.  */
+         if (newtime.tv_sec == (time_t) -1)
            error (EXIT_FAILURE, 0, _("invalid date format %s"), quote 
(optarg));
          date_set++;
          break;
@@ -312,9 +322,10 @@ main (int argc, char **argv)
 
        case 't':
          posix_date++;
-         if (! posixtime (&newtime, optarg,
+         if (! posixtime (&newtime.tv_sec, optarg,
                           PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS))
            error (EXIT_FAILURE, 0, _("invalid date format %s"), quote 
(optarg));
+         newtime.tv_nsec = 0;
          date_set++;
          break;
 
@@ -355,11 +366,12 @@ main (int argc, char **argv)
   if (!date_set && 2 <= argc - optind && !STREQ (argv[optind - 1], "--")
       && posix2_version () < 200112)
     {
-      if (posixtime (&newtime, argv[optind], PDS_TRAILING_YEAR))
+      if (posixtime (&newtime.tv_sec, argv[optind], PDS_TRAILING_YEAR))
        {
+         newtime.tv_nsec = 0;
          if (! getenv ("POSIXLY_CORRECT"))
            {
-             struct tm const *tm = localtime (&newtime);
+             struct tm const *tm = localtime (&newtime.tv_sec);
              error (0, 0,
                     _("warning: `touch %s' is obsolete; use\
  `touch -t %04d%02d%02d%02d%02d.%02d'"),
@@ -377,7 +389,20 @@ main (int argc, char **argv)
       if ((change_times & (CH_ATIME | CH_MTIME)) == (CH_ATIME | CH_MTIME))
        amtime_now = 1;
       else
-       time (&newtime);
+       {
+         /* Get time of day, but only to microsecond resolution,
+            since 'utimes' currently supports only microsecond
+            resolution at best.  It would be cleaner here to invoke
+            gettime, but then we would have to link in more shared
+            libraries on platforms like Solaris, and we'd rather not
+            have 'touch' depend on libraries that it doesn't
+            need.  */
+         struct timeval timeval;
+         if (gettimeofday (&timeval, NULL) != 0)
+           error (EXIT_FAILURE, errno, _("cannot get time of day"));
+         newtime.tv_sec = timeval.tv_sec;
+         newtime.tv_nsec = timeval.tv_usec * 1000;
+       }
     }
 
   if (optind == argc)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]