mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-28 04:24:45 +08:00
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 birthtime. * tests/touch/no-dereference: New test. * tests/Makefile.am (TESTS): Run it.
This commit is contained in:
parent
527fb951de
commit
9e13b6a0b4
3
NEWS
3
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-dereference (-h), as a means to
|
||||
change symlink timestamps on platforms with enough support.
|
||||
|
||||
|
||||
* Noteworthy changes in release 8.0 (2009-10-06) [beta]
|
||||
|
||||
|
@ -9855,7 +9855,9 @@ touch [@var{option}]@dots{} @var{file}@dots{}
|
||||
@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 @@ user must own the files.
|
||||
|
||||
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 @@ fresh copy of the file, including the new permissions value.
|
||||
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 @@ Change the access time only.
|
||||
@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 --date=@var{time}
|
||||
@ -9931,6 +9936,24 @@ silently ignore any excess precision here.
|
||||
@cindex BSD @command{touch} compatibility
|
||||
Ignored; for compatibility with BSD versions of @command{touch}.
|
||||
|
||||
@item -h
|
||||
@itemx --no-dereference
|
||||
@opindex -h
|
||||
@opindex --no-dereference
|
||||
@cindex symbolic links, changing time
|
||||
@findex 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 @@ If this option is combined with the @option{--date=@var{time}}
|
||||
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 [[@var{cc}]@var{yy}]@var{mmddhhmm}[.@var{ss}]
|
||||
Use the argument (optional four-digit or two-digit years, months,
|
||||
|
28
src/touch.c
28
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'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{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\
|
||||
\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\
|
||||
is supplied.\n\
|
||||
\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)) != -1)
|
||||
while ((c = getopt_long (argc, argv, "acd:fhmr:t:", longopts, &long_idx)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -284,6 +295,10 @@ main (int argc, char **argv)
|
||||
case 'f':
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
no_dereference = true;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
change_times |= CH_MTIME;
|
||||
break;
|
||||
@ -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);
|
||||
|
@ -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 \
|
||||
|
80
tests/touch/no-dereference
Executable file
80
tests/touch/no-dereference
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/sh
|
||||
# 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
|
||||
# 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
touch --version
|
||||
fi
|
||||
|
||||
. $srcdir/test-lib.sh
|
||||
|
||||
ln -s nowhere dangling || framework_failure
|
||||
touch file || framework_failure
|
||||
ln -s file link || framework_failure
|
||||
|
||||
fail=0
|
||||
|
||||
# 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 ;;
|
||||
esac
|
||||
case `stat --format=%y file` in
|
||||
2009-10-10*) fail=1;;
|
||||
esac
|
||||
|
||||
# Test interactions with -.
|
||||
touch -h - > file || fail=1
|
||||
|
||||
test="$abs_top_builddir/src/test"
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
Exit $fail
|
Loading…
Reference in New Issue
Block a user