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

Reply via email to