From e750c877b08d33378099af535438017657af4dc1 Mon Sep 17 00:00:00 2001 From: jilles Date: Sun, 10 Apr 2016 15:02:29 +0000 Subject: [PATCH] MFC r277645: cp,mv,touch: Set timestamps with nanosecond precision. This uses utimensat(). git-svn-id: svn://svn.freebsd.org/base/stable/10@297782 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- bin/cp/utils.c | 11 +++--- bin/mv/mv.c | 9 +++-- usr.bin/touch/touch.c | 79 +++++++++++++++++++++---------------------- 3 files changed, 48 insertions(+), 51 deletions(-) diff --git a/bin/cp/utils.c b/bin/cp/utils.c index 0b5202ecf..73a30007c 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -344,7 +344,7 @@ copy_special(struct stat *from_stat, int exists) int setfile(struct stat *fs, int fd) { - static struct timeval tv[2]; + static struct timespec tspec[2]; struct stat ts; int rval, gotstat, islink, fdval; @@ -354,10 +354,11 @@ setfile(struct stat *fs, int fd) fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; - TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim); - TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim); - if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { - warn("%sutimes: %s", islink ? "l" : "", to.p_path); + tspec[0] = fs->st_atim; + tspec[1] = fs->st_mtim; + if (utimensat(AT_FDCWD, to.p_path, tspec, + islink ? AT_SYMLINK_NOFOLLOW : 0)) { + warn("utimensat: %s", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : diff --git a/bin/mv/mv.c b/bin/mv/mv.c index 566167d03..a23b6daf6 100644 --- a/bin/mv/mv.c +++ b/bin/mv/mv.c @@ -273,7 +273,7 @@ do_move(const char *from, const char *to) static int fastcopy(const char *from, const char *to, struct stat *sbp) { - struct timeval tval[2]; + struct timespec ts[2]; static u_int blen = MAXPHYS; static char *bp = NULL; mode_t oldmode; @@ -341,10 +341,9 @@ err: if (unlink(to)) if (errno != EOPNOTSUPP || sbp->st_flags != 0) warn("%s: set flags (was: 0%07o)", to, sbp->st_flags); - tval[0].tv_sec = sbp->st_atime; - tval[1].tv_sec = sbp->st_mtime; - tval[0].tv_usec = tval[1].tv_usec = 0; - if (utimes(to, tval)) + ts[0] = sbp->st_atim; + ts[1] = sbp->st_mtim; + if (utimensat(AT_FDCWD, to, ts, 0)) warn("%s: set times", to); if (close(to_fd)) { diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c index 4439c07eb..c8bfd28d6 100644 --- a/usr.bin/touch/touch.c +++ b/usr.bin/touch/touch.c @@ -56,10 +56,10 @@ static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; #include #include -static void stime_arg1(const char *, struct timeval *); -static void stime_arg2(const char *, int, struct timeval *); -static void stime_darg(const char *, struct timeval *); -static void stime_file(const char *, struct timeval *); +static void stime_arg1(const char *, struct timespec *); +static void stime_arg2(const char *, int, struct timespec *); +static void stime_darg(const char *, struct timespec *); +static void stime_file(const char *, struct timespec *); static int timeoffset(const char *); static void usage(const char *); @@ -67,19 +67,17 @@ int main(int argc, char *argv[]) { struct stat sb; - struct timeval tv[2]; - int (*stat_f)(const char *, struct stat *); - int (*utimes_f)(const char *, const struct timeval *); + struct timespec ts[2]; + int atflag; int Aflag, aflag, cflag, mflag, ch, fd, len, rval, timeset; char *p; char *myname; myname = basename(argv[0]); Aflag = aflag = cflag = mflag = timeset = 0; - stat_f = stat; - utimes_f = utimes; - if (gettimeofday(&tv[0], NULL) == -1) - err(1, "gettimeofday"); + atflag = 0; + if (clock_gettime(CLOCK_REALTIME, &ts[0]) == -1) + err(1, "clock_gettime(CLOCK_REALTIME)"); while ((ch = getopt(argc, argv, "A:acd:fhmr:t:")) != -1) switch(ch) { @@ -94,26 +92,25 @@ main(int argc, char *argv[]) break; case 'd': timeset = 1; - stime_darg(optarg, tv); + stime_darg(optarg, ts); break; case 'f': /* No-op for compatibility. */ break; case 'h': cflag = 1; - stat_f = lstat; - utimes_f = lutimes; + atflag = AT_SYMLINK_NOFOLLOW; break; case 'm': mflag = 1; break; case 'r': timeset = 1; - stime_file(optarg, tv); + stime_file(optarg, ts); break; case 't': timeset = 1; - stime_arg1(optarg, tv); + stime_arg1(optarg, ts); break; default: usage(myname); @@ -132,9 +129,9 @@ main(int argc, char *argv[]) * that time once and for all here. */ if (aflag) - tv[0].tv_sec += Aflag; + ts[0].tv_sec += Aflag; if (mflag) - tv[1].tv_sec += Aflag; + ts[1].tv_sec += Aflag; Aflag = 0; /* done our job */ } } else { @@ -148,11 +145,11 @@ main(int argc, char *argv[]) len = p - argv[0]; if (*p == '\0' && (len == 8 || len == 10)) { timeset = 1; - stime_arg2(*argv++, len == 10, tv); + stime_arg2(*argv++, len == 10, ts); } } /* Both times default to the same. */ - tv[1] = tv[0]; + ts[1] = ts[0]; } if (*argv == NULL) @@ -163,7 +160,7 @@ main(int argc, char *argv[]) for (rval = 0; *argv; ++argv) { /* See if the file exists. */ - if (stat_f(*argv, &sb) != 0) { + if (fstatat(AT_FDCWD, *argv, &sb, atflag) != 0) { if (errno != ENOENT) { rval = 1; warn("%s", *argv); @@ -187,9 +184,9 @@ main(int argc, char *argv[]) } if (!aflag) - TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atim); + ts[0] = sb.st_atim; if (!mflag) - TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtim); + ts[1] = sb.st_mtim; /* * We're adjusting the times based on the file times, not a @@ -197,17 +194,17 @@ main(int argc, char *argv[]) */ if (Aflag) { if (aflag) { - TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atim); - tv[0].tv_sec += Aflag; + ts[0] = sb.st_atim; + ts[0].tv_sec += Aflag; } if (mflag) { - TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtim); - tv[1].tv_sec += Aflag; + ts[1] = sb.st_mtim; + ts[1].tv_sec += Aflag; } } - /* Try utimes(2). */ - if (!utimes_f(*argv, tv)) + /* Try utimensat(2). */ + if (!utimensat(AT_FDCWD, *argv, ts, atflag)) continue; /* If the user specified a time, nothing else we can do. */ @@ -223,7 +220,7 @@ main(int argc, char *argv[]) * The permission checks are different, too, in that the * ability to write the file is sufficient. Take a shot. */ - if (!utimes_f(*argv, NULL)) + if (!utimensat(AT_FDCWD, *argv, NULL, atflag)) continue; rval = 1; @@ -235,7 +232,7 @@ main(int argc, char *argv[]) #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; static void -stime_arg1(const char *arg, struct timeval *tvp) +stime_arg1(const char *arg, struct timespec *tvp) { time_t now; struct tm *t; @@ -291,7 +288,7 @@ stime_arg1(const char *arg, struct timeval *tvp) if (tvp[0].tv_sec == -1) goto terr; - tvp[0].tv_usec = tvp[1].tv_usec = 0; + tvp[0].tv_nsec = tvp[1].tv_nsec = 0; return; terr: @@ -299,7 +296,7 @@ terr: } static void -stime_arg2(const char *arg, int year, struct timeval *tvp) +stime_arg2(const char *arg, int year, struct timespec *tvp) { time_t now; struct tm *t; @@ -325,18 +322,18 @@ stime_arg2(const char *arg, int year, struct timeval *tvp) errx(1, "out of range or illegal time specification: MMDDhhmm[yy]"); - tvp[0].tv_usec = tvp[1].tv_usec = 0; + tvp[0].tv_nsec = tvp[1].tv_nsec = 0; } static void -stime_darg(const char *arg, struct timeval *tvp) +stime_darg(const char *arg, struct timespec *tvp) { struct tm t = { .tm_sec = 0 }; const char *fmt, *colon; char *p; int val, isutc = 0; - tvp[0].tv_usec = 0; + tvp[0].tv_nsec = 0; t.tm_isdst = -1; colon = strchr(arg, ':'); if (colon == NULL || strchr(colon + 1, ':') == NULL) @@ -349,9 +346,9 @@ stime_darg(const char *arg, struct timeval *tvp) /* POSIX: must have at least one digit after dot */ if ((*p == '.' || *p == ',') && isdigit((unsigned char)p[1])) { p++; - val = 100000; + val = 100000000; while (isdigit((unsigned char)*p)) { - tvp[0].tv_usec += val * (*p - '0'); + tvp[0].tv_nsec += val * (*p - '0'); p++; val /= 10; } @@ -403,14 +400,14 @@ timeoffset(const char *arg) } static void -stime_file(const char *fname, struct timeval *tvp) +stime_file(const char *fname, struct timespec *tsp) { struct stat sb; if (stat(fname, &sb)) err(1, "%s", fname); - TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atim); - TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtim); + tsp[0] = sb.st_atim; + tsp[1] = sb.st_mtim; } static void -- 2.42.0