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