From 867b3d4100a6480f3c6c15d130c48d05c027c0ea Mon Sep 17 00:00:00 2001 From: Apple Date: Mon, 19 Apr 2021 17:12:51 +0000 Subject: [PATCH] file_cmds-321.100.10.0.1.tar.gz --- compress/compress.c | 18 +++++-- cp/utils.c | 50 ++++++++++++++++--- file_cmds.xcodeproj/project.pbxproj | 34 +++++++++++++ mtree/commoncrypto.c | 3 +- mtree/compare.c | 17 +++++-- mtree/extern.h | 2 +- mtree/mtree.8 | 3 ++ mtree/mtree.c | 14 +++--- mtree/spec.c | 10 +++- mtree/verify.c | 4 +- tests/cp.sh | 23 +++++++++ tests/file_cmds.plist | 36 ++++++++++++++ tests/touch.sh | 14 ++++++ touch/touch.c | 77 ++++++++++++++++------------- 14 files changed, 243 insertions(+), 62 deletions(-) create mode 100644 tests/cp.sh create mode 100644 tests/touch.sh diff --git a/compress/compress.c b/compress/compress.c index 26da7fa..97c70f2 100644 --- a/compress/compress.c +++ b/compress/compress.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD: src/usr.bin/compress/compress.c,v 1.23 2010/12/11 08:32:16 j #include #include #include +#include #include #include @@ -382,14 +383,21 @@ err: if (ofp) { void setfile(const char *name, struct stat *fs) { - static struct timeval tv[2]; + struct attrlist ts_req = {}; + struct { + struct timespec mtime; + struct timespec atime; + } set_ts; fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; - TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); - TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); - if (utimes(name, tv)) - cwarn("utimes: %s", name); + ts_req.bitmapcount = ATTR_BIT_MAP_COUNT; + ts_req.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME; + set_ts.mtime = fs->st_mtimespec; + set_ts.atime = fs->st_atimespec; + + if (setattrlist(name, &ts_req, &set_ts, sizeof(set_ts), 0)) + cwarn("setattrlist: %s", name); /* * Changing the ownership probably won't succeed, unless we're root diff --git a/cp/utils.c b/cp/utils.c index af05cc3..feecc0c 100644 --- a/cp/utils.c +++ b/cp/utils.c @@ -69,10 +69,22 @@ __FBSDID("$FreeBSD: src/bin/cp/utils.c,v 1.46 2005/09/05 04:36:08 csjp Exp $"); #include "extern.h" #define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y)) +/* Memory strategy threshold, in pages: if physmem is larger then this, use a + * large buffer */ +#define PHYSPAGES_THRESHOLD (32*1024) + +/* Maximum buffer size in bytes - do not allow it to grow larger than this */ +#define BUFSIZE_MAX (2*1024*1024) + +/* Small (default) buffer size in bytes. It's inefficient for this to be + * smaller than MAXPHYS */ +#define BUFSIZE_SMALL (MAXPHYS) + int copy_file(const FTSENT *entp, int dne) { - static char buf[MAXBSIZE]; + static char *buf = NULL; + static size_t bufsize; struct stat *fs; int ch, checkch, from_fd, rval, to_fd; ssize_t rcount; @@ -258,8 +270,23 @@ copy_file(const FTSENT *entp, int dne) } else #endif { + if (buf == NULL) { + /* + * Note that buf and bufsize are static. If + * malloc() fails, it will fail at the start + * and not copy only some files. + */ + if (sysconf(_SC_PHYS_PAGES) > + PHYSPAGES_THRESHOLD) + bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); + else + bufsize = BUFSIZE_SMALL; + buf = malloc(bufsize); + if (buf == NULL) + err(1, "Not enough memory"); + } wtotal = 0; - while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { + while ((rcount = read(from_fd, buf, bufsize)) > 0) { for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { wcount = write(to_fd, bufp, wresid); @@ -382,19 +409,28 @@ copy_special(struct stat *from_stat, int exists) int setfile(struct stat *fs, int fd) { - static struct timeval tv[2]; + struct attrlist ts_req = {}; struct stat ts; int rval, gotstat, islink, fdval; + struct { + struct timespec mtime; + struct timespec atime; + } set_ts; rval = 0; fdval = fd != -1; islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; + unsigned int options = islink ? FSOPT_NOFOLLOW : 0; + + ts_req.bitmapcount = ATTR_BIT_MAP_COUNT; + ts_req.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME; + set_ts.mtime = fs->st_mtimespec; + set_ts.atime = fs->st_atimespec; - TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); - TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); - if (fdval ? futimes(fd, tv) : (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv))) { - warn("%sutimes: %s", fdval ? "f" : (islink ? "l" : ""), to.p_path); + if (fdval ? fsetattrlist(fd, &ts_req, &set_ts, sizeof(set_ts), options) : + setattrlist(to.p_path, &ts_req, &set_ts, sizeof(set_ts), options)) { + warn("%ssetattrlist: %s", fdval ? "f" : "", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) : diff --git a/file_cmds.xcodeproj/project.pbxproj b/file_cmds.xcodeproj/project.pbxproj index e4e94ec..dcf7d02 100644 --- a/file_cmds.xcodeproj/project.pbxproj +++ b/file_cmds.xcodeproj/project.pbxproj @@ -111,6 +111,8 @@ isa = PBXAggregateTarget; buildConfigurationList = FC8A8C8114B655ED001B97AD /* Build configuration list for PBXAggregateTarget "executables" */; buildPhases = ( + D178BEFA253DAE01001FC103 /* Copy plist */, + D178BF21253DAE2E001FC103 /* Copy tests */, ); dependencies = ( FC8A8C8414B655FD001B97AD /* PBXTargetDependency */, @@ -213,6 +215,10 @@ 3E966CF01FB2218A0019F7A1 /* chgrp.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */; }; 729D06D8230B5E42000716E5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729D06D7230B5E42000716E5 /* CoreFoundation.framework */; }; 7D0A20EA2499364700F0F6D7 /* metrics.c in Sources */ = {isa = PBXBuildFile; fileRef = 7D0A20E92499364700F0F6D7 /* metrics.c */; }; + D178BEFB253DAE2A001FC103 /* file_cmds.plist in Copy plist */ = {isa = PBXBuildFile; fileRef = 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */; }; + D178BF22253DAE42001FC103 /* chgrp.sh in Copy tests */ = {isa = PBXBuildFile; fileRef = 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */; }; + D178BF48253DAE45001FC103 /* touch.sh in Copy tests */ = {isa = PBXBuildFile; fileRef = D11B5750253C22BD009A59BF /* touch.sh */; }; + D1B4221F25762FC8003E3A47 /* cp.sh in Copy tests */ = {isa = PBXBuildFile; fileRef = D1B421D325762E9E003E3A47 /* cp.sh */; }; FC8A8A2814B6486E001B97AD /* chflags.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDCC14B6460C0070FACB /* chflags.c */; }; FC8A8BE414B6494B001B97AD /* chflags.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDCB14B6460C0070FACB /* chflags.1 */; }; FC8A8BE514B64958001B97AD /* chmod.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDD014B6460C0070FACB /* chmod.c */; }; @@ -851,6 +857,30 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D178BEFA253DAE01001FC103 /* Copy plist */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /AppleInternal/CoreOS/BATS/unit_tests; + dstSubfolderSpec = 0; + files = ( + D178BEFB253DAE2A001FC103 /* file_cmds.plist in Copy plist */, + ); + name = "Copy plist"; + runOnlyForDeploymentPostprocessing = 0; + }; + D178BF21253DAE2E001FC103 /* Copy tests */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /AppleInternal/Tests/file_cmds; + dstSubfolderSpec = 0; + files = ( + D1B4221F25762FC8003E3A47 /* cp.sh in Copy tests */, + D178BF48253DAE45001FC103 /* touch.sh in Copy tests */, + D178BF22253DAE42001FC103 /* chgrp.sh in Copy tests */, + ); + name = "Copy tests"; + runOnlyForDeploymentPostprocessing = 0; + }; FC8A8B0F14B648D7001B97AD /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1203,6 +1233,8 @@ 729D06D7230B5E42000716E5 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 7D0A20E82499364700F0F6D7 /* metrics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = metrics.h; sourceTree = ""; }; 7D0A20E92499364700F0F6D7 /* metrics.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = metrics.c; sourceTree = ""; }; + D11B5750253C22BD009A59BF /* touch.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = touch.sh; sourceTree = ""; }; + D1B421D325762E9E003E3A47 /* cp.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = cp.sh; sourceTree = ""; }; FC8A8B1214B648D7001B97AD /* chmod */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chmod; sourceTree = BUILT_PRODUCTS_DIR; }; FC8A8B1A14B648E0001B97AD /* chown */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chown; sourceTree = BUILT_PRODUCTS_DIR; }; FC8A8B2214B648E3001B97AD /* cksum */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cksum; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1591,6 +1623,8 @@ children = ( 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */, 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */, + D11B5750253C22BD009A59BF /* touch.sh */, + D1B421D325762E9E003E3A47 /* cp.sh */, ); path = tests; sourceTree = ""; diff --git a/mtree/commoncrypto.c b/mtree/commoncrypto.c index 11e97ce..0ac621c 100644 --- a/mtree/commoncrypto.c +++ b/mtree/commoncrypto.c @@ -105,7 +105,8 @@ xattr_info * SHA256_Path_XATTRs(char *path, char *buf) { xattr_info *ai = NULL; - if (mflag) { + // mflag is passed during manifest comparision while xflag is used to generate the specification + if (mflag || xflag) { ai = get_xdstream_privateid(path, buf); } else { ai = calculate_SHA256_XATTRs(path, buf); diff --git a/mtree/compare.c b/mtree/compare.c index e585928..366f12f 100644 --- a/mtree/compare.c +++ b/mtree/compare.c @@ -534,11 +534,18 @@ typeerr: LABEL; int supported; struct timespec ptimespec = ptime(p->fts_accpath, &supported); if (!supported) { - LABEL; - (void)printf("%stime added to parent folder expected %.24s.%09ld found that it is not supported\n", - tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec); - tab = "\t"; - } else if (supported && ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) || + if (mflag) { + ptimespec.tv_sec = 0; + ptimespec.tv_nsec = 0; + supported = 1; + } else { + LABEL; + (void)printf("%stime added to parent folder expected %.24s.%09ld found that it is not supported\n", + tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec); + tab = "\t"; + } + } + if (supported && ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) || (s->st_ptimespec.tv_nsec != ptimespec.tv_nsec))) { if (!mflag) { LABEL; diff --git a/mtree/extern.h b/mtree/extern.h index 47533c2..fb7ea83 100644 --- a/mtree/extern.h +++ b/mtree/extern.h @@ -61,7 +61,7 @@ const char * ftype(u_int type); extern int ftsoptions; extern u_int keys; extern int lineno; -extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag, mflag, tflag; +extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag, mflag, tflag, xflag; extern int insert_mod, insert_birth, insert_access, insert_change, insert_parent; extern struct timespec ts; #ifdef MAXPATHLEN diff --git a/mtree/mtree.8 b/mtree/mtree.8 index 1aa529a..fb7cff8 100644 --- a/mtree/mtree.8 +++ b/mtree/mtree.8 @@ -148,6 +148,9 @@ This occurs when the directory is a symbolic link. Remove any files in the file hierarchy that are not described in the specification. .\" ========== +.It Fl S +Skip calculating the digest of the extended attributes of the file. +.\" ========== .It Fl s Ar seed Display a single checksum to the standard error output that represents all of the files for which the keyword diff --git a/mtree/mtree.c b/mtree/mtree.c index edf0cce..46cc2ae 100644 --- a/mtree/mtree.c +++ b/mtree/mtree.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp #define SECONDS_IN_A_DAY (60 * 60 * 24) int ftsoptions = FTS_PHYSICAL; -int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag, mflag, tflag; +int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag, mflag, tflag, xflag; int insert_mod, insert_birth, insert_access, insert_change, insert_parent; struct timespec ts; u_int keys; @@ -101,7 +101,7 @@ main(int argc, char *argv[]) atexit(do_cleanup); atexit(print_metrics_to_file); - while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:m:F:t:E:")) != -1) + while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:m:F:t:E:S")) != -1) switch((char)ch) { case 'c': cflag = 1; @@ -216,8 +216,10 @@ main(int argc, char *argv[]) } else { set_metrics_file(file); } - break; - + break; + case 'S': + xflag = 1; + break; case '?': default: RECORD_FAILURE(92, WARN_USAGE); @@ -279,7 +281,7 @@ main(int argc, char *argv[]) status = mtree_verifyspec(spec1); if (Uflag & (status == MISMATCHEXIT)) { status = 0; - } else { + } else if (status) { RECORD_FAILURE(100, status); } if (mflag && CFDictionaryGetCount(dict)) { @@ -296,7 +298,7 @@ static void usage(void) { (void)fprintf(stderr, -"usage: mtree [-LPUcdeinqruxw] [-f spec] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n" +"usage: mtree [-LPUScdeinqruxw] [-f spec] [-K key] [-k key] [-p path] [-s seed] [-m xml dictionary] [-t timestamp]\n" "\t[-X excludes]\n"); exit(1); } diff --git a/mtree/spec.c b/mtree/spec.c index f15d857..4119124 100644 --- a/mtree/spec.c +++ b/mtree/spec.c @@ -186,6 +186,7 @@ set(char *t, NODE *ip) mode_t *m; int value; char *ep; + char *l; for (; (kw = strtok(t, "= \t\n")); t = NULL) { ip->flags |= type = parsekey(kw, &value); @@ -415,14 +416,19 @@ set(char *t, NODE *ip) } break; case F_XATTRS: - ep = strtok(val,"."); + /* + * Note this is nested inside an strtok loop, + * strtok_r must be used to preserve the strtok context + * of the loop. + */ + ep = strtok_r(val,".", &l); ip->xattrsdigest = strdup(ep); if (!ip->xattrsdigest) { error = errno; RECORD_FAILURE(54, error); errc(1, error, "strdup"); } - val = strtok(NULL,"."); + val = strtok_r(NULL,".", &l); if (val) { ip->xdstream_priv_id = strtoull(val, &ep, 10); if (*ep) { diff --git a/mtree/verify.c b/mtree/verify.c index 7471652..4978098 100644 --- a/mtree/verify.c +++ b/mtree/verify.c @@ -70,7 +70,9 @@ mtree_verifyspec(FILE *fi) RECORD_FAILURE(60, WARN_MISMATCH); return rval; } else { - RECORD_FAILURE(61, WARN_MISMATCH); + if (mval != 0) { + RECORD_FAILURE(61, WARN_MISMATCH); + } return mval; } } diff --git a/tests/cp.sh b/tests/cp.sh new file mode 100644 index 0000000..24afa56 --- /dev/null +++ b/tests/cp.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# Regression test for 69452380 +function regression_69452380() +{ + echo "Verifying that cp -p preserves symlink's attributes, rather than the attributes of the symlink's target." + test_dir=`mktemp -d /tmp/69452380_src_XXXX` + touch ${test_dir}/target + mkdir ${test_dir}/link_dir + # Create symlink (must use relative path for the failure to occur) + cd ${test_dir}/link_dir + ln -s ../target link + # cp (with attribute preservation) the test dir containing both the + # target and the link (in a subdirectory) to a new dir. + # Prior to 69452380, this failed because we followed the symlink to + # try and preserve attributes for a non-existing file, instead of + # preserving the attributes of the symlink itself. + cp -R -P -p ${test_dir} /tmp/69452380_tgt_${RANDOM} +} + +set -eu -o pipefail + +regression_69452380 diff --git a/tests/file_cmds.plist b/tests/file_cmds.plist index 4e4d135..337d4b4 100644 --- a/tests/file_cmds.plist +++ b/tests/file_cmds.plist @@ -8,6 +8,42 @@ Tests + + Command + + /bin/sh + cp.sh + + AsRoot + + TestName + cp + WhenToRun + + PRESUBMISSION + NIGHTLY + + WorkingDirectory + /AppleInternal/Tests/file_cmds + + + Command + + /bin/sh + touch.sh + + AsRoot + + TestName + touch + WhenToRun + + PRESUBMISSION + NIGHTLY + + WorkingDirectory + /AppleInternal/Tests/file_cmds + Command diff --git a/tests/touch.sh b/tests/touch.sh new file mode 100644 index 0000000..d38684d --- /dev/null +++ b/tests/touch.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +file_name=`mktemp /tmp/XXXXXX` +file_ctime=`/usr/bin/stat -f%c ${file_name}` + +/usr/bin/touch $file_name +file_mtime=`/usr/bin/stat -f%m ${file_name}` + +if [ "$file_ctime" -gt "$file_mtime" ]; then + echo "file's mod time ($file_mtime) should be later than the file's creation time ($file_ctime)" + exit 1 +fi + +exit 0 diff --git a/touch/touch.c b/touch/touch.c index aca5b90..ccfcb9f 100644 --- a/touch/touch.c +++ b/touch/touch.c @@ -48,6 +48,7 @@ __used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; #include #include #include +#include #include #include @@ -59,10 +60,15 @@ __used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; #include #include +typedef struct { + struct timespec mtime; + struct timespec atime; +} set_ts; + int rw(char *, struct stat *, int); -void stime_arg1(char *, struct timeval *); -void stime_arg2(char *, int, struct timeval *); -void stime_file(char *, struct timeval *); +void stime_arg1(char *, set_ts *); +void stime_arg2(char *, int, set_ts *); +void stime_file(char *, set_ts *); int timeoffset(char *); void usage(char *); @@ -70,19 +76,24 @@ 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 *); int Aflag, aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset; char *p; char *myname; + struct attrlist ts_req = { + .bitmapcount = ATTR_BIT_MAP_COUNT, + .commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME, + }; + set_ts ts_struct = {}; myname = basename(argv[0]); Aflag = aflag = cflag = fflag = mflag = timeset = 0; stat_f = stat; utimes_f = utimes; - if (gettimeofday(&tv[0], NULL)) - err(1, "gettimeofday"); + if (clock_gettime(CLOCK_REALTIME, &ts_struct.mtime)) + err(1, "clock_gettime"); + ts_struct.atime = ts_struct.mtime; while ((ch = getopt(argc, argv, "A:acfhmr:t:")) != -1) switch(ch) { @@ -108,11 +119,11 @@ main(int argc, char *argv[]) break; case 'r': timeset = 1; - stime_file(optarg, tv); + stime_file(optarg, &ts_struct); break; case 't': timeset = 1; - stime_arg1(optarg, tv); + stime_arg1(optarg, &ts_struct); break; case '?': default: @@ -132,9 +143,9 @@ main(int argc, char *argv[]) * that time once and for all here. */ if (aflag) - tv[0].tv_sec += Aflag; + ts_struct.atime.tv_sec += Aflag; if (mflag) - tv[1].tv_sec += Aflag; + ts_struct.mtime.tv_sec += Aflag; Aflag = 0; /* done our job */ } } else { @@ -148,11 +159,9 @@ 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_struct); } } - /* Both times default to the same. */ - tv[1] = tv[0]; } if (*argv == NULL) @@ -187,9 +196,9 @@ main(int argc, char *argv[]) } if (!aflag) - TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec); + ts_struct.atime = sb.st_atimespec; if (!mflag) - TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); + ts_struct.mtime = sb.st_mtimespec; /* * We're adjusting the times based on the file times, not a @@ -197,17 +206,17 @@ main(int argc, char *argv[]) */ if (Aflag) { if (aflag) { - TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec); - tv[0].tv_sec += Aflag; + ts_struct.atime = sb.st_atimespec; + ts_struct.atime.tv_sec += Aflag; } if (mflag) { - TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); - tv[1].tv_sec += Aflag; + ts_struct.mtime = sb.st_mtimespec; + ts_struct.mtime.tv_sec += Aflag; } } - /* Try utimes(2). */ - if (!utimes_f(*argv, tv)) + /* Try setattrlist(2). */ + if (!setattrlist(*argv, &ts_req, &ts_struct, sizeof(ts_struct), 0)) continue; /* If the user specified a time, nothing else we can do. */ @@ -241,14 +250,14 @@ main(int argc, char *argv[]) #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; void -stime_arg1(char *arg, struct timeval *tvp) +stime_arg1(char *arg, set_ts *tsp) { time_t now; struct tm *t; int yearset; char *p; /* Start with the current time. */ - now = tvp[0].tv_sec; + now = tsp->atime.tv_sec; if ((t = localtime(&now)) == NULL) err(1, "localtime"); /* [[CC]YY]MMDDhhmm[.SS] */ @@ -293,21 +302,21 @@ stime_arg1(char *arg, struct timeval *tvp) } t->tm_isdst = -1; /* Figure out DST. */ - tvp[0].tv_sec = tvp[1].tv_sec = mktime(t); - if (tvp[0].tv_sec == -1) + tsp->atime.tv_sec = tsp->mtime.tv_sec = mktime(t); + if (tsp->atime.tv_sec == -1) terr: errx(1, "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); - tvp[0].tv_usec = tvp[1].tv_usec = 0; + tsp->atime.tv_nsec = tsp->mtime.tv_nsec = 0; } void -stime_arg2(char *arg, int year, struct timeval *tvp) +stime_arg2(char *arg, int year, set_ts *tsp) { time_t now; struct tm *t; /* Start with the current time. */ - now = tvp[0].tv_sec; + now = tsp->atime.tv_sec; if ((t = localtime(&now)) == NULL) err(1, "localtime"); @@ -323,12 +332,12 @@ stime_arg2(char *arg, int year, struct timeval *tvp) } t->tm_isdst = -1; /* Figure out DST. */ - tvp[0].tv_sec = tvp[1].tv_sec = mktime(t); - if (tvp[0].tv_sec == -1) + tsp->atime.tv_sec = tsp->mtime.tv_sec = mktime(t); + if (tsp->atime.tv_sec == -1) errx(1, "out of range or illegal time specification: MMDDhhmm[yy]"); - tvp[0].tv_usec = tvp[1].tv_usec = 0; + tsp->atime.tv_nsec = tsp->mtime.tv_nsec = 0; } /* Calculate a time offset in seconds, given an arg of the format [-]HHMMSS. */ @@ -362,14 +371,14 @@ timeoffset(char *arg) } void -stime_file(char *fname, struct timeval *tvp) +stime_file(char *fname, set_ts *ts_struct) { struct stat sb; if (stat(fname, &sb)) err(1, "%s", fname); - TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atimespec); - TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtimespec); + ts_struct->atime = sb.st_atimespec; + ts_struct->mtime = sb.st_mtimespec; } int -- 2.45.2