Add a -D option to touch, which acts like the -d option added to

chmod/chown/chgrp (probably others) in the not too far distant past,
and causes the operation to be a no-op if no actual change would be
made (avoiding updating the file's ctime for no reason).

That is, with touch, -D causes no modifying sys call to be made to
a file if that file's atime and mtime are already set to the values
that would be used.   A common case for this is when a "-r ref-file"
is also a target file for the operation.

Unfortunately -d was already taken in touch, so next best available is -D.
This commit is contained in:
kre 2024-02-10 00:19:30 +00:00
parent 69d75f9748
commit b064b3fad8
2 changed files with 72 additions and 9 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: touch.1,v 1.28 2024/02/09 23:41:48 kre Exp $
.\" $NetBSD: touch.1,v 1.29 2024/02/10 00:19:30 kre Exp $
.\"
.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -32,7 +32,7 @@
.\"
.\" @(#)touch.1 8.3 (Berkeley) 4/28/95
.\"
.Dd February 9, 2024
.Dd February 10, 2024
.Dt TOUCH 1
.Os
.Sh NAME
@ -40,7 +40,7 @@
.Nd change file access and modification times
.Sh SYNOPSIS
.Nm
.Op Fl acfhm
.Op Fl acDfhm
.Op Fl d Ar posix-datetime|human-datetime
.Op Fl Fl \|date Ar posix-datetime|human-datetime
.Op Fl R Ar ref-file
@ -77,6 +77,11 @@ The
.Nm
utility does not treat this as an error.
No error messages are displayed and the exit value is not affected.
.Pp
.It Fl D
Do not attempt to adjust a
.Ar file Ns 's
times if they are already set to the values specified.
.Pp
.It Fl d Ar posix-datetime
.It Fl d Ar human-datetime
@ -360,6 +365,56 @@ of the
.Ar path
file to the current time of day.
.Pp
.Dl touch -Dh -d human-datetime -t CCYYMMDDhhmm.ss -R file file
.Pp
Provided
.Ar file
exists, this parses the
.Ar human-datetime
and
.Ar CCYYMMDDhhmm.ss
arguments,
verifying that they would be suitable for use with
.Nm ,
then does nothing, as the final time specification
.Pq Fl R
specifies to take the times from
.Ar file
and apply them to
.Ar file
itself, changing nothing, which the
.Fl D
option then prevents from actually occurring.
That is, this merely tests that the
.Ar human-datetime
and
.Ar datetime
argumments to
.Fl d
and
.Fl t
respectively are valid, and could be used to specify a time.
Use of both
.Fl h
and
.Fl R
means this works if
.Ar file
is a symbolic link,
even one which does not reference an existing file,
as well as if it is some other file type.
Use of
.Fl R
requires that
.Ar file
exists,
though if it does not, and an error is generated for that reason,
the
.Fl d
and
.Fl t
arguments would have already been successfully processed.
.Pp
.Dl touch -m -d '-1 day' somefile
.Pp
Set the modify time for

View File

@ -1,4 +1,4 @@
/* $NetBSD: touch.c,v 1.39 2024/02/09 23:41:48 kre Exp $ */
/* $NetBSD: touch.c,v 1.40 2024/02/10 00:19:30 kre Exp $ */
/*
* Copyright (c) 1993
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1993\
#if 0
static char sccsid[] = "@(#)touch.c 8.2 (Berkeley) 4/28/95";
#endif
__RCSID("$NetBSD: touch.c,v 1.39 2024/02/09 23:41:48 kre Exp $");
__RCSID("$NetBSD: touch.c,v 1.40 2024/02/10 00:19:30 kre Exp $");
#endif /* not lint */
#include <sys/types.h>
@ -91,18 +91,18 @@ main(int argc, char *argv[])
{
struct stat sb;
struct timespec ts[2];
int aflag, cflag, hflag, mflag, ch, fd, len, rval, timeset;
int aflag, cflag, Dflag, hflag, mflag, ch, fd, len, rval, timeset;
char *p;
int (*change_file_times)(const char *, const struct timespec *);
int (*get_file_status)(const char *, struct stat *);
setlocale(LC_ALL, "");
aflag = cflag = hflag = mflag = timeset = 0;
aflag = cflag = Dflag = hflag = mflag = timeset = 0;
if (clock_gettime(CLOCK_REALTIME, &ts[0]))
err(1, "clock_gettime");
while ((ch = getopt_long(argc, argv, "acd:fhmR:r:t:", touch_longopts,
while ((ch = getopt_long(argc, argv, "acDd:fhmR:r:t:", touch_longopts,
NULL)) != -1)
switch (ch) {
case 'a':
@ -111,6 +111,9 @@ main(int argc, char *argv[])
case 'c':
cflag = 1;
break;
case 'D':
Dflag = 1;
break;
case 'd':
timeset = 1;
if (!stime_posix(optarg, ts))
@ -200,6 +203,11 @@ main(int argc, char *argv[])
if (!mflag)
ts[1] = sb.st_mtimespec;
if (Dflag &&
timespeccmp(&ts[0], &sb.st_atimespec, ==) &&
timespeccmp(&ts[1], &sb.st_mtimespec, ==))
continue;
/* Try utimes(2). */
if (!(*change_file_times)(*argv, ts))
continue;
@ -527,7 +535,7 @@ static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s [-acfhm] [-d|--date datetime] [-R|-r|--reference file]"
"Usage: %s [-acDfhm] [-d|--date datetime] [-R|-r|--reference file]"
" [-t time] file ...\n", getprogname());
exit(EXIT_FAILURE);
}