[Top][All Lists]

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

touch -h

From: Eric Blake
Subject: touch -h
Date: Sat, 17 Oct 2009 09:40:26 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20090812 Thunderbird/ Mnenhy/

Hash: SHA1

As promised, I've now implemented touch -h.  I've tested it on machines
with and without utimensat/lutimes.  OK to apply?

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

>From 4ada45b208a3b0a8c89a8ff5938d58ebfadca546 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Sat, 17 Oct 2009 07:55:05 -0600
Subject: [PATCH] touch: add -h to change symlink timestamps, where supported

* src/touch.c (no_dereference): New flag variable.
(longopts): Add -h/--no-dereference.
(touch): Add symlink handling.
(usage): Document new option.
(main): Accept new option.
* NEWS: Document it.
* doc/coreutils.texi (touch invocation): Likewise.  Also mention
* tests/touch/no-dereference: New test.
* tests/Makefile.am (TESTS): Run it.
 NEWS                       |    3 ++
 doc/coreutils.texi         |   33 ++++++++++++++++--
 src/touch.c                |   28 ++++++++++++---
 tests/Makefile.am          |    1 +
 tests/touch/no-dereference |   80 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 136 insertions(+), 9 deletions(-)
 create mode 100755 tests/touch/no-dereference

diff --git a/NEWS b/NEWS
index f8269fc..87b3451 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   md5sum --check now also accepts openssl-style checksums.
   So do sha1sum, sha224sum, sha384sum and sha512sum.

+  touch now accepts the option --no-dereferene (-h), as a means to
+  change timestamps on symlinks for platforms that support that.

 * Noteworthy changes in release 8.0 (2009-10-06) [beta]

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 5026e76..64e0e95 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -9855,7 +9855,9 @@ touch invocation
 @end example

 @cindex empty files, creating
-Any @var{file} argument that does not exist is created empty.
+Any @var{file} argument that does not exist is created empty, unless
+option @option{--no-create} (@option{-c}) or @option{--no-dereference}
+(@option{-h}) was in effect.

 A @var{file} argument string of @samp{-} is handled specially and
 causes @command{touch} to change the times of the file associated with
@@ -9869,8 +9871,8 @@ touch invocation

 Although @command{touch} provides options for changing two of the times---the
 times of last access and modification---of a file, there is actually
-a third one as well: the inode change time.  This is often referred to
-as a file's @code{ctime}.
+a standard third one as well: the inode change time.  This is often
+referred to as a file's @code{ctime}.
 The inode change time represents the time when the file's meta-information
 last changed.  One common example of this is when the permissions of a
 file change.  Changing the permissions doesn't access the file, so
@@ -9882,6 +9884,9 @@ touch invocation
 Another operation that modifies a file's ctime without affecting
 the others is renaming.  In any case, it is not possible, in normal
 operations, for a user to change the ctime field to a user-specified value.
+Some operating systems and file systems support a fourth time: the
+birth time, when the file was first created; by definition, this
+timestamp never changes.

 @vindex TZ
 Time stamps assume the time zone rules specified by the @env{TZ}
@@ -9910,7 +9915,7 @@ touch invocation
 @itemx --no-create
 @opindex -c
 @opindex --no-create
-Do not create files that do not exist.
+Do not warn about or create files that do not exist.

 @item -d
 @itemx address@hidden
@@ -9931,6 +9936,24 @@ touch invocation
 @cindex BSD @command{touch} compatibility
 Ignored; for compatibility with BSD versions of @command{touch}.

address@hidden -h
address@hidden --no-dereference
address@hidden -h
address@hidden --no-dereference
address@hidden symbolic links, changing time
address@hidden lutimes
+Attempt to change the timestamps of a symbolic link, rather than what
+the link refers to.  When using this option, empty files are not
+created, but option @option{-c} must also be used to avoid warning
+about files that do not exist.  Not all systems support changing the
+timestamps of symlinks, since underlying system support for this
+action was not required until @acronym{POSIX} 2008.  Also, on some
+systems, the mere act of examining a symbolic link changes the access
+time, such that only changes to the modification time will persist
+long enough to be observable.  When coupled with option @option{-r}, a
+reference timestamp is taken from a symbolic link rather than the file
+it refers to.
 @item -m
 @itemx --time=mtime
 @itemx --time=modify
@@ -9950,6 +9973,8 @@ touch invocation
 the origin for any relative @var{time}s given, but is otherwise ignored.
 For example, @samp{-r foo -d '-5 seconds'} specifies a time stamp
 equal to five seconds before the corresponding time stamp for @file{foo}.
+If @var{file} is a symbolic link, the reference timestamp is taken
+from the target of the symlink, unless @option{-h} was also in effect.

 @item -t address@hidden@address@hidden@var{ss}]
 Use the argument (optional four-digit or two-digit years, months,
diff --git a/src/touch.c b/src/touch.c
index b4c45a1..030c8f8 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -58,6 +58,9 @@ static bool no_create;
 /* (-r) If true, use times from a reference file.  */
 static bool use_ref;

+/* (-h) If true, change the times of an existing symlink, if possible.  */
+static bool no_dereference;
 /* If true, the only thing we have to do is change both the
    modification and access time to the current time, so we don't
    have to own the file, just be able to read and write it.
@@ -85,6 +88,7 @@ static struct option const longopts[] =
   {"date", required_argument, NULL, 'd'},
   {"file", required_argument, NULL, 'r'}, /* FIXME: remove --file in 2010 */
   {"reference", required_argument, NULL, 'r'},
+  {"no-dereference", no_argument, NULL, 'h'},
   {NULL, 0, NULL, 0}
@@ -126,7 +130,7 @@ touch (const char *file)

   if (STREQ (file, "-"))
     fd = STDOUT_FILENO;
-  else if (! no_create)
+  else if (! (no_create || no_dereference))
       /* Try to open FILE, creating it if necessary.  */
       fd = fd_reopen (STDIN_FILENO, file,
@@ -160,7 +164,8 @@ touch (const char *file)
       t = NULL;

-  ok = (gl_futimens (fd, (fd == STDOUT_FILENO ? NULL : file), t) == 0);
+  ok = ((no_dereference && fd == -1) ? lutimens (file, t)
+        : gl_futimens (fd, (fd == STDOUT_FILENO ? NULL : file), t)) == 0;

   if (fd == STDIN_FILENO)
@@ -211,7 +216,8 @@ usage (int status)
       fputs (_("\
 Update the access and modification times of each FILE to the current time.\n\
-A FILE argument that does not exist is created empty.\n\
+A FILE argument that does not exist is created empty, unless -c or -h\n\
+are supplied.\n\
 A FILE argument string of - is handled specially and causes touch to\n\
 change the times of the file associated with standard output.\n\
@@ -225,6 +231,11 @@ Mandatory arguments to long options are mandatory for 
short options too.\n\
   -c, --no-create        do not create any files\n\
   -d, --date=STRING      parse STRING and use it instead of current time\n\
   -f                     (ignored)\n\
+"), stdout);
+      fputs (_("\
+  -h, --no-dereference   affect each symbolic link instead of any referenced\n\
+                         file (useful only on systems that can change the\n\
+                         timestamps of a symlink)\n\
   -m                     change only the modification time\n\
 "), stdout);
       fputs (_("\
@@ -265,7 +276,7 @@ main (int argc, char **argv)
   change_times = 0;
   no_create = use_ref = false;

-  while ((c = getopt_long (argc, argv, "acd:fmr:t:", longopts, &long_idx)) != 
+  while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, &long_idx)) != 
       switch (c)
@@ -284,6 +295,10 @@ main (int argc, char **argv)
         case 'f':

+        case 'h':
+          no_dereference = true;
+          break;
         case 'm':
           change_times |= CH_MTIME;
@@ -333,7 +348,10 @@ main (int argc, char **argv)
   if (use_ref)
       struct stat ref_stats;
-      if (stat (ref_file, &ref_stats))
+      /* Don't use (no_dereference ? lstat : stat) (args), since stat
+         might be an object-like macro.  */
+      if (no_dereference ? lstat (ref_file, &ref_stats)
+          : stat (ref_file, &ref_stats))
         error (EXIT_FAILURE, errno,
                _("failed to get attributes of %s"), quote (ref_file));
       newtime[0] = get_stat_atime (&ref_stats);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8dc90f9..751db1c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -445,6 +445,7 @@ TESTS =                                             \
   touch/fail-diag                              \
   touch/fifo                                   \
   touch/no-create-missing                      \
+  touch/no-dereference                         \
   touch/no-rights                              \
   touch/not-owner                              \
   touch/obsolescent                            \
diff --git a/tests/touch/no-dereference b/tests/touch/no-dereference
new file mode 100755
index 0000000..28527e8
--- /dev/null
+++ b/tests/touch/no-dereference
@@ -0,0 +1,80 @@
+# Ensure that touch -h works.
+# Copyright (C) 2009 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 3 of the License, 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
+# 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, see <http://www.gnu.org/licenses/>.
+if test "$VERBOSE" = yes; then
+  set -x
+  touch --version
+. $srcdir/test-lib.sh
+ln -s nowhere dangling || framework_failure
+touch file || framework_failure
+ln -s file link || framework_failure
+# These first tests should work on every platform.
+# -h does not create files, but it warns.  Use -c to silence warning.
+touch -h no-file 2> err && fail=1
+test -s err || fail=1
+touch -h -c no-file 2> err || fail=1
+test -s err && fail=1
+# -h works on regular files
+touch -h file || fail=1
+# -h coupled with -r uses timestamp of the symlink, not the referent.
+touch -h -r dangling file || fail=1
+test -f nowhere && fail=1
+# The remaining tests of -h require kernel support for changing symlink times.
+grep '^#define HAVE_UTIMENSAT' "$CONFIG_HEADER" > /dev/null ||
+grep '^#define HAVE_LUTIMES' "$CONFIG_HEADER" > /dev/null ||
+  skip_test_ 'this system lacks the utimensat function'
+# Changing time of dangling symlink is okay.
+touch -h dangling || fail=1
+test -f nowhere && fail=1
+# Change the mtime of a symlink.
+touch -m -h -d 2009-10-10 link || fail=1
+case `stat --format=%y link` in
+  2009-10-10*) ;;
+  *) fail=1 ;;
+case `stat --format=%y file` in
+  2009-10-10*) fail=1;;
+# Test interactions with -.
+touch -h - > file || fail=1
+# If >&- works, test "touch -ch -" etc.
+# >&- apparently does not work in HP-UX 11.23.
+# This test is ineffective unless /dev/stdout also works.
+# If stdout is open, it is not a symlink.
+if "$test" -w /dev/stdout >/dev/null &&
+   "$test" ! -w /dev/stdout >&-; then
+  touch -h - >&- && fail=1
+  touch -h -c - >&- || fail=1
+Exit $fail

reply via email to

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