This patch changes the function used to update timestamps in touch.

Before, utimes() and lutimes() were used, which had certain
disadvantages.
They are unable to handle nanosecond timestamps, and features like -h
and -a required some nasty hacks to implement.
Switching from using these functions enables the code to be considerably
cleaner
---
Unfortunately, I managed to break option parsing.
The -d and --date options no longer function properly, showing the filname 
argument
is invalid.
I tried to fix this but was not able to - I would appreciate if someone
else took a look for me.

 coreutils/touch.c | 91 +++++++++++++++++++----------------------------
 1 file changed, 36 insertions(+), 55 deletions(-)

diff --git a/coreutils/touch.c b/coreutils/touch.c
index e80720982..0cfe9dd75 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -27,20 +27,21 @@
 //config:      Enable touch to have the -h option.
 //config:      This requires libc support for lutimes() function.
 //config:
-//config:config FEATURE_TOUCH_SUSV3
+//config:config FEATURE_TOUCH_FANCY
 //config:      bool "Add support for SUSV3 features (-a -d -m -t -r)"
 //config:      default y
 //config:      depends on TOUCH
 //config:      help
 //config:      Enable touch to use a reference file or a given date/time 
argument.
+//config:
 
 //applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch))
 
 //kbuild:lib-$(CONFIG_TOUCH) += touch.o
 
 //usage:#define touch_trivial_usage
-//usage:       "[-c" IF_FEATURE_TOUCH_SUSV3("am") "]"
-//usage:       IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]")
+//usage:       "[-c" IF_FEATURE_TOUCH_FANCY("am") "]"
+//usage:       IF_FEATURE_TOUCH_FANCY(" [-d DATE] [-t DATE] [-r FILE]")
 //usage:       " FILE..."
 //usage:#define touch_full_usage "\n\n"
 //usage:       "Update the last-modified date on the given FILE[s]\n"
@@ -48,7 +49,7 @@
 //usage:       IF_FEATURE_TOUCH_NODEREF(
 //usage:     "\n       -h      Don't follow links"
 //usage:       )
-//usage:       IF_FEATURE_TOUCH_SUSV3(
+//usage:       IF_FEATURE_TOUCH_FANCY(
 //usage:     "\n       -a      Change only atime"
 //usage:     "\n       -m      Change only mtime"
 //usage:     "\n       -d DT   Date/time to use"
@@ -90,46 +91,43 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
        int opts;
        enum {
                OPT_c = (1 << 0),
-               OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_SUSV3,
-               OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3,
-               OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3,
-               OPT_a = (1 << 4) * ENABLE_FEATURE_TOUCH_SUSV3,
-               OPT_m = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3,
+               OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_FANCY,
+               OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_FANCY,
+               OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_FANCY,
+               OPT_a = (1 << 4) * ENABLE_FEATURE_TOUCH_FANCY,
+               OPT_m = (1 << 5) * ENABLE_FEATURE_TOUCH_FANCY,
                OPT_h = (1 << 6) * ENABLE_FEATURE_TOUCH_NODEREF,
        };
-       /* NULL = use current time */
-       const struct timeval *newtime = NULL;
+       /* timebuf[0] is atime, timebuf[1] is mtime */
+       struct timespec timebuf[2];
+       const struct timespec* newtime = NULL;
 #if ENABLE_LONG_OPTS
        static const char touch_longopts[] ALIGN1 =
                /* name, has_arg, val */
                "no-create\0"         No_argument       "c"
-               IF_FEATURE_TOUCH_SUSV3("reference\0"        Required_argument 
"r")
-               IF_FEATURE_TOUCH_SUSV3("date\0"             Required_argument 
"d")
+               IF_FEATURE_TOUCH_FANCY("reference\0"        Required_argument 
"r")
+               IF_FEATURE_TOUCH_FANCY("date\0"             Required_argument 
"d")
                IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h")
        ;
 #endif
-#if ENABLE_FEATURE_TOUCH_SUSV3
+#if ENABLE_FEATURE_TOUCH_FANCY
        char *reference_file = NULL;
        char *date_str = NULL;
-       /* timebuf[0] is atime, timebuf[1] is mtime */
-       struct timeval timebuf[2];
-       timebuf[1].tv_usec = timebuf[0].tv_usec = 0;
 #else
 # define reference_file NULL
 # define date_str       NULL
-# define timebuf        ((struct timeval*)NULL)
 #endif
 
        /* -d and -t both set time. In coreutils,
         * accepted data format differs a bit between -d and -t.
         * We accept the same formats for both */
-       opts = getopt32long(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:am")
+       opts = getopt32long(argv, "c" IF_FEATURE_TOUCH_FANCY("r:d:t:am")
                                IF_FEATURE_TOUCH_NODEREF("h")
                                /*ignored:*/ "f",
                                touch_longopts
-                               IF_FEATURE_TOUCH_SUSV3(, &reference_file)
-                               IF_FEATURE_TOUCH_SUSV3(, &date_str)
-                               IF_FEATURE_TOUCH_SUSV3(, &date_str)
+                               IF_FEATURE_TOUCH_FANCY(, &reference_file)
+                               IF_FEATURE_TOUCH_FANCY(, &date_str)
+                               IF_FEATURE_TOUCH_FANCY(, &date_str)
        );
 
        argv += optind;
@@ -142,10 +140,8 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
                xstat(reference_file, &stbuf);
                timebuf[0].tv_sec = stbuf.st_atime;
                timebuf[1].tv_sec = stbuf.st_mtime;
-               /* Can use .st_mtim.tv_nsec
-                * (or is it .st_mtimensec?? see date.c)
-                * to set microseconds too.
-                */
+               timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec;
+               timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec;
                newtime = timebuf;
        }
 
@@ -164,38 +160,23 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
                t = validate_tm_time(date_str, &tm_time);
 
                timebuf[1].tv_sec = timebuf[0].tv_sec = t;
-               newtime = timebuf;
+               newtime = timebuf;
        }
-
-       if ((opts & (OPT_a | OPT_m)) && !newtime) {
-               time(&timebuf[0].tv_sec);
-               timebuf[1].tv_sec = timebuf[0].tv_sec;
+       if ((opts & OPT_a) && !(opts & OPT_m)) {
+               timebuf[1].tv_nsec = UTIME_OMIT;
+               newtime = timebuf;
+       }
+       if ((opts & OPT_m) && !(opts & OPT_a)) {
+               timebuf[0].tv_nsec = UTIME_OMIT;
                newtime = timebuf;
        }
 
        do {
-               int result;
-
-               if (opts & (OPT_a | OPT_m)) {
-                       /* Save original times */
-                       struct stat stbuf;
-                       if(stat(*argv, &stbuf) == 0) {
-                               /* As we must set both times, we lose original
-                                * file time microseconds.
-                                * Can use .st_mtim.tv_nsec
-                                * (or is it .st_mtimensec?? see date.c)
-                                * to set microseconds too.
-                                * Also, utimensat(2) allows to omit one of the
-                                * times to be set and it is SUSv4.
-                                */
-                               if (!(opts & OPT_a))
-                                       timebuf[0].tv_sec = stbuf.st_atime;
-                               if (!(opts & OPT_m))
-                                       timebuf[1].tv_sec = stbuf.st_mtime;
-                       }
-               }
-
-               result = (ENABLE_FEATURE_TOUCH_NODEREF && (opts & OPT_h) ? 
lutimes : utimes)(*argv, newtime);
+               int result =
+#if ENABLE_FEATURE_TOUCH_NODEREF
+                       (opts & OPT_h) ? utimensat(AT_FDCWD, *argv, newtime, 
AT_SYMLINK_NOFOLLOW) :
+#endif
+                       utimensat(AT_FDCWD, *argv, newtime, 0);
 
                if (result != 0) {
                        if (errno == ENOENT) { /* no such file? */
@@ -206,9 +187,9 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
                                /* Try to create the file */
                                fd = open(*argv, O_RDWR | O_CREAT, 0666);
                                if (fd >= 0) {
-                                       xclose(fd);
                                        if (reference_file || date_str)
-                                               utimes(*argv, newtime);
+                                               futimens(fd, newtime);
+                                       xclose(fd);
                                        continue;
                                }
                        }
-- 
2.31.1

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to