]> git.saurik.com Git - apple/file_cmds.git/commitdiff
file_cmds-321.100.10.0.1.tar.gz master macos-113 v321.100.10.0.1
authorApple <opensource@apple.com>
Mon, 19 Apr 2021 17:12:51 +0000 (17:12 +0000)
committerApple <opensource@apple.com>
Mon, 19 Apr 2021 17:12:51 +0000 (17:12 +0000)
14 files changed:
compress/compress.c
cp/utils.c
file_cmds.xcodeproj/project.pbxproj
mtree/commoncrypto.c
mtree/compare.c
mtree/extern.h
mtree/mtree.8
mtree/mtree.c
mtree/spec.c
mtree/verify.c
tests/cp.sh [new file with mode: 0644]
tests/file_cmds.plist
tests/touch.sh [new file with mode: 0644]
touch/touch.c

index 26da7fa1b859b7a0eb81090b5b46461a5645ac53..97c70f291e278016d2e8e84133f16c35ee81569f 100644 (file)
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD: src/usr.bin/compress/compress.c,v 1.23 2010/12/11 08:32:16 j
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/attr.h>
 
 #include <err.h>
 #include <errno.h>
@@ -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
index af05cc3e966c4869a491c7b751fe6e108fb9672d..feecc0c85528a475ec18da490a513ddd2258e741 100644 (file)
@@ -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) :
index e4e94ec6ee45c97b885bfdcf4ad3387844c4200e..dcf7d022432304939773825aa6b260a4c719bc3e 100644 (file)
                        isa = PBXAggregateTarget;
                        buildConfigurationList = FC8A8C8114B655ED001B97AD /* Build configuration list for PBXAggregateTarget "executables" */;
                        buildPhases = (
+                               D178BEFA253DAE01001FC103 /* Copy plist */,
+                               D178BF21253DAE2E001FC103 /* Copy tests */,
                        );
                        dependencies = (
                                FC8A8C8414B655FD001B97AD /* PBXTargetDependency */,
                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 */; };
                        );
                        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;
                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 = "<group>"; };
                7D0A20E92499364700F0F6D7 /* metrics.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = metrics.c; sourceTree = "<group>"; };
+               D11B5750253C22BD009A59BF /* touch.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = touch.sh; sourceTree = "<group>"; };
+               D1B421D325762E9E003E3A47 /* cp.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = cp.sh; sourceTree = "<group>"; };
                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; };
                        children = (
                                3E966CEB1FB2214F0019F7A1 /* chgrp.sh */,
                                3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */,
+                               D11B5750253C22BD009A59BF /* touch.sh */,
+                               D1B421D325762E9E003E3A47 /* cp.sh */,
                        );
                        path = tests;
                        sourceTree = "<group>";
index 11e97ceb085199f58afa79e19e050dc8cdf91043..0ac621c8081f7e412726a8319c602e164a0310c9 100644 (file)
@@ -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);
index e585928d4521f282de03cb2f37e4ff91336f001e..366f12f61657b176161a45fa50491492d2725572 100644 (file)
@@ -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;
index 47533c2fc09792002cc80867433a3fc00c0104ec..fb7ea8304f4ca127308912069d4e4b75c30af44a 100644 (file)
@@ -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
index 1aa529a793841f8067f4121e9640eba90a9925bb..fb7cff8b6ec27ad1be4679f37af1f65f5bd8e0d9 100644 (file)
@@ -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
index edf0cce5fdcc3dd3319db4f5498b8b3fdafc8c12..46cc2ae5666ff86529d18433ad134f0e409d1c38 100644 (file)
@@ -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);
 }
index f15d85744849225a5d4aeb7ca632cf78ed03b630..4119124f13bacc80654e2da567545cc56f325aca 100644 (file)
@@ -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) {
index 7471652461f60664937942fd7eb4da201fc789f0..49780983059c80a6baca2874e7499939e5f74136 100644 (file)
@@ -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 (file)
index 0000000..24afa56
--- /dev/null
@@ -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
index 4e4d1354a1a22b0d9639c0a0bb562d57452a116f..337d4b4c110dae371d3fd0a65f3a9d08abfe14cb 100644 (file)
@@ -8,6 +8,42 @@
        <true/>
        <key>Tests</key>
        <array>
+               <dict>
+                       <key>Command</key>
+                       <array>
+                               <string>/bin/sh</string>
+                               <string>cp.sh</string>
+                       </array>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>TestName</key>
+                       <string>cp</string>
+                       <key>WhenToRun</key>
+                       <array>
+                               <string>PRESUBMISSION</string>
+                               <string>NIGHTLY</string>
+                       </array>
+                       <key>WorkingDirectory</key>
+                       <string>/AppleInternal/Tests/file_cmds</string>
+               </dict>
+               <dict>
+                       <key>Command</key>
+                       <array>
+                               <string>/bin/sh</string>
+                               <string>touch.sh</string>
+                       </array>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>TestName</key>
+                       <string>touch</string>
+                       <key>WhenToRun</key>
+                       <array>
+                               <string>PRESUBMISSION</string>
+                               <string>NIGHTLY</string>
+                       </array>
+                       <key>WorkingDirectory</key>
+                       <string>/AppleInternal/Tests/file_cmds</string>
+               </dict>
                <dict>
                        <key>Command</key>
                        <array>
diff --git a/tests/touch.sh b/tests/touch.sh
new file mode 100644 (file)
index 0000000..d38684d
--- /dev/null
@@ -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
index aca5b90e21ec7aacc7759e7668dbf2ed7f83cf3b..ccfcb9ff1179afd86082ea922dece77b3e978577 100644 (file)
@@ -48,6 +48,7 @@ __used static const char sccsid[] = "@(#)touch.c      8.1 (Berkeley) 6/6/93";
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/attr.h>
 
 #include <err.h>
 #include <errno.h>
@@ -59,10 +60,15 @@ __used static const char sccsid[] = "@(#)touch.c    8.1 (Berkeley) 6/6/93";
 #include <time.h>
 #include <unistd.h>
 
+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