Applied, thank you

On Sun, Apr 11, 2021 at 7:44 AM urmum-69 <urmu...@snopyta.org> wrote:
>
> This patch changes the functions used to update timestamps in touch.
>
> Before, utimes() and lutimes() were used, which had certain
> disadvantages.
> They are unable to handle nanosecond timestamps, and implementations of
> certain features like -a and -m require running stat() in a loop.
>
> Almost all implementations of utimes() and lutimes() are wrappers for
> utimensat(), this is the case for glibc, ulibc and musl libc.
> ---
> I forgot to initialize the nanoseconds of timebuf[x].tv_nsec, so if a
> date was specified, random values would be passed to utimes(), causing
> undefined behavior.
>
> This patch should be applied on top of Xabier Oneca's patches to
> implement the -a and -m options in touch.
>
>  coreutils/touch.c | 57 +++++++++++++++++------------------------------
>  1 file changed, 20 insertions(+), 37 deletions(-)
>
> diff --git a/coreutils/touch.c b/coreutils/touch.c
> index 8af602b5e..a12501616 100644
> --- a/coreutils/touch.c
> +++ b/coreutils/touch.c
> @@ -25,7 +25,6 @@
>  //config:      depends on TOUCH
>  //config:      help
>  //config:      Enable touch to have the -h option.
> -//config:      This requires libc support for lutimes() function.
>  //config:
>  //config:config FEATURE_TOUCH_SUSV3
>  //config:      bool "Add support for SUSV3 features (-a -d -m -t -r)"
> @@ -98,7 +97,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
>                 OPT_h = (1 << 6) * ENABLE_FEATURE_TOUCH_NODEREF,
>         };
>         /* NULL = use current time */
> -       const struct timeval *newtime = NULL;
> +       const struct timespec *newtime = NULL;
>  #if ENABLE_LONG_OPTS
>         static const char touch_longopts[] ALIGN1 =
>                 /* name, has_arg, val */
> @@ -112,12 +111,12 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
>         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;
> +       struct timespec timebuf[2];
> +       timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW;
>  #else
>  # define reference_file NULL
>  # define date_str       NULL
> -# define timebuf        ((struct timeval*)NULL)
> +# define timebuf        ((struct timespec*)NULL)
>  #endif
>
>         /* -d and -t both set time. In coreutils,
> @@ -144,10 +143,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;
>         }
>
> @@ -166,39 +163,25 @@ 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;
> +               timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0;
>                 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. But 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? */
>                                 if (opts & OPT_c) {
> @@ -208,9 +191,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
> busybox@busybox.net
> http://lists.busybox.net/mailman/listinfo/busybox
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to