This patch: * adds -h. * switches to utimensat(2) for greater precision (and as specified by POSIX.1). * uses UTIME_OMIT rather than read-modify-write for -a/-m. * uses UTIME_NOW rather than gettimeofday(2). * fixes -d to parse fractional seconds correctly. * fixes -t to not accept fractional seconds (neither POSIX nor coreutils do, and toybox was broken, suggesting no one could be relying on this anyway). * adds support for POSIX.1's use of ',' as an alternative to '.'.
index 71ddc43..258cb57 100644 --- a/toys/posix/touch.c +++ b/toys/posix/touch.c @@ -4,21 +4,22 @@ * * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html -USE_TOUCH(NEWTOY(touch, "acd:mr:t:[!dtr]", TOYFLAG_BIN)) +USE_TOUCH(NEWTOY(touch, "acd:hmr:t:[!dtr]", TOYFLAG_BIN)) config TOUCH bool "touch" default y help - usage: touch [-amc] [-d DATE] [-t TIME] [-r FILE] FILE... + usage: touch [-amc] [-h] [-d DATE] [-t TIME] [-r FILE] FILE... Update the access and modification times of each FILE to the current time. -a change access time -m change modification time -c don't create file + -h change symbolic link rather than what it points to -d set time to DATE (in YYYY-MM-DDThh:mm:SS[.frac][tz] format) - -t set time to TIME (in [[CC]YY]MMDDhhmm[.ss][frac] format) + -t set time to TIME (in [[CC]YY]MMDDhhmm[.SS] format) -r set time same as reference FILE */ @@ -31,41 +32,21 @@ GLOBALS( char *date; ) -// Fetch access and/or modification time of a file -int fetch(char *file, struct timeval *tv, unsigned flags) -{ - struct stat st; - - if (stat(file, &st)) return 1; - - if (flags & FLAG_a) { - tv[0].tv_sec = st.st_atime; - tv[0].tv_usec = st.st_atim.tv_nsec/1000; - } - if (flags & FLAG_m) { - tv[1].tv_sec = st.st_mtime; - tv[1].tv_usec = st.st_mtim.tv_nsec/1000; - } - - return 0; -} - void touch_main(void) { - struct timeval tv[2]; + struct timespec ts[2]; char **ss; int flag, fd, i; // Set time from clock? - - gettimeofday(tv, NULL); + ts[0].tv_nsec = UTIME_NOW; if (toys.optflags & (FLAG_t|FLAG_d)) { char *s, *date; struct tm tm; int len; - localtime_r(&(tv->tv_sec), &tm); + localtime_r(&(ts->tv_sec), &tm); // Set time from -d? @@ -77,13 +58,18 @@ void touch_main(void) if (toupper(date[i-1])=='Z') { date[i-1] = 0; setenv("TZ", "UTC0", 1); - localtime_r(&(tv->tv_sec), &tm); + localtime_r(&(ts->tv_sec), &tm); } s = strptime(date, "%Y-%m-%dT%T", &tm); - if (s && *s=='.') { + // Fractional seconds too? + ts->tv_nsec = 0; + if (s && (*s=='.' || *s==',')) { sscanf(s, ".%d%n", &i, &len); s += len; - tv->tv_usec = i; + if (i < 0 || i > 1e9) error_exit("ns out of range: %s", date); + ts->tv_nsec = i; + for (i = 0; i < (10 - len); ++i) + ts->tv_nsec *= 10; } } else s = 0; @@ -97,32 +83,35 @@ void touch_main(void) if (s) break; toybuf[1]='y'; } - if (s && *s=='.') { - int count = sscanf(s, ".%2d%u%n", &(tm.tm_sec), &i, &len); - - if (count==2) tv->tv_usec = i; - s += len; - } + // No fractional seconds with -t. + ts->tv_nsec = 0; } errno = 0; - tv->tv_sec = mktime(&tm); - if (!s || *s || errno == EOVERFLOW) perror_exit("bad '%s'", date); + ts->tv_sec = mktime(&tm); + if (!s || *s || errno == EOVERFLOW) perror_exit("bad time '%s'", date); } - tv[1]=tv[0]; + ts[1]=ts[0]; // Set time from -r? + if (TT.file) { + struct stat st; + if (stat(TT.file, &st)) perror_exit("-r '%s'", TT.file); + if (toys.optflags & FLAG_a) + ts[0] = st.st_atim; + if (toys.optflags & FLAG_m) + ts[1] = st.st_mtim; + } - if (TT.file && fetch(TT.file, tv, FLAG_a|FLAG_m)) - perror_exit("-r '%s'", TT.file); - - // Ok, we've got a time. Flip -am flags so now it's the ones we _keep_. + // Which time(s) should we actually change? + if (!(toys.optflags & FLAG_a)) ts[0].tv_nsec = UTIME_OMIT; + if (!(toys.optflags & FLAG_m)) ts[1].tv_nsec = UTIME_OMIT; - flag = (~toys.optflags) & (FLAG_m|FLAG_a); + flag = (toys.optflags & FLAG_h) ? AT_SYMLINK_NOFOLLOW : 0; // Loop through files on command line for (ss=toys.optargs; *ss;) { - if ((flag == (FLAG_m|FLAG_a) || !fetch(*ss, tv, flag)) && !utimes(*ss, tv)) + if (!utimensat(AT_FDCWD, *ss, ts, flag)) ss++; else if (toys.optflags & FLAG_c) ss++; else if (-1 != (fd = open(*ss, O_CREAT, 0666))) close(fd); _______________________________________________ Toybox mailing list [email protected] http://lists.landley.net/listinfo.cgi/toybox-landley.net
