[Top][All Lists]
[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, ×pec))
{
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, ×pec))
{
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, ×pec);
}
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)
- patch to add microsecond resolution support to cp -p, etc.,
Paul Eggert <=