]> git.saurik.com Git - apple/file_cmds.git/commitdiff
file_cmds-264.1.1.tar.gz macos-1012 os-x-1012 v264.1.1
authorApple <opensource@apple.com>
Fri, 19 Aug 2016 02:39:10 +0000 (02:39 +0000)
committerApple <opensource@apple.com>
Fri, 19 Aug 2016 02:39:10 +0000 (02:39 +0000)
15 files changed:
chmod/chmod_acl.c
ipcrm/ipcrm.c
mtree/commoncrypto.c
mtree/commoncrypto.h
mtree/compare.c
mtree/create.c
mtree/extern.h
mtree/misc.c
mtree/mtree.8
mtree/mtree.h
mtree/spec.c
mtree/specspec.c
mtree/verify.c
mv/mv.c
rm/rm.c

index 34708fc0490757d726d7aac6c49368201b4b104c..5ac4c177c04dd179c684c96f1053c35179c547b7 100644 (file)
@@ -676,7 +676,7 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos
        unsigned aindex  = 0, flag_new_acl = 0;
        acl_entry_t newent = NULL;
        acl_entry_t entry = NULL;
-       unsigned retval = 0 ;
+       unsigned retval = 0;
 
        extern int fflag;
 
@@ -699,17 +699,36 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos
 
        if (optflags & ACL_CLEAR_FLAG) {
                filesec_t fsec = filesec_init();
-               if (fsec == NULL)
+               if (fsec == NULL) {
                        err(1, "filesec_init() failed");
-               if (filesec_set_property(fsec, FILESEC_ACL,
-                                        _FILESEC_REMOVE_ACL) != 0)
+               }
+               if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) {
                        err(1, "filesec_set_property() failed");
-               if (chmodx_np(path, fsec) != 0) {
-                       if (!fflag)
-                               warn("Failed to clear ACL on file %s", path);
-                       retval = 1;
-               } else
-                       retval = 0;
+                }
+               if (follow) {
+                       if (chmodx_np(path, fsec) != 0) {
+                                if (!fflag) {
+                                       warn("Failed to clear ACL on file %s", path);
+                               }
+                               retval = 1;
+                       }
+               } else {
+                       int fd = open(path, O_SYMLINK);
+                       if (fd != -1) {
+                               if (fchmodx_np(fd, fsec) != 0) {
+                                       if (!fflag) {
+                                               warn("Failed to clear ACL on file %s", path);
+                                       }
+                                       retval = 1;
+                               }
+                               close(fd);
+                       } else {
+                               if (!fflag) {
+                                       warn("Failed to open file %s", path);
+                               }
+                               retval = 1;
+                       }
+               }
                filesec_free(fsec);
                return (retval);
        }
index 2a401f398bfd66bd1338b44713439de16cc342fd..e90aaa1977ab1d8fe095e889325104934760f1cb 100644 (file)
@@ -83,14 +83,12 @@ static int shmrm(key_t key, int id)
 
 static int semrm(key_t key, int id)
 {
-    union semun arg;
-
     if (key) {
        id = semget(key, 0, 0);
        if (id == -1)
            return -1;
     }
-    return semctl(id, 0, IPC_RMID, arg);
+    return semctl(id, 0, IPC_RMID);
 }
 
 static void not_configured(__unused int unused)
index 0dda1f04dfc4b2b560d41b193b2ef757f54b3519..88efada8db3785118aec86c32505ec4d6fa6ad96 100644 (file)
@@ -2,14 +2,29 @@
 #include <os/assumes.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <string.h>
+#include <sys/xattr.h>
+#include <stdbool.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/attr.h>
+#include <unistd.h>
 
 #include "commoncrypto.h"
 
+const int kSHA256NullTerminatedBuffLen = 65;
+static const char hex[] = "0123456789abcdef";
+
+/* Functions for SHA256_File_XATTRs */
+#define SHA256_Data(d, s, b)    Digest_Data(kCCDigestSHA256, d, s, b)
+char *Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf);
+void Quicksort(char **array, int num);
+
 /* Generic version of libmd's *_File() functions. */
 char *
 Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
 {
-       static const char hex[] = "0123456789abcdef";
        int fd;
        __block CCDigestCtx ctx;
        dispatch_queue_t queue;
@@ -75,6 +90,150 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
                buf[i+i+1] = hex[digest[i] & 0x0f];
        }
        buf[i+i] = '\0';
+       
+       return buf;
+}
+
+char *SHA256_Path_XATTRs(char *path, char *buf)
+{
+       char *xattrsSummary = NULL;
+       int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
+       ssize_t nameBufSize = listxattr(path, NULL, 0, options);
+       if (nameBufSize > 0) {
+               char *nameBuf = malloc(nameBufSize);
+               
+               listxattr(path, nameBuf, nameBufSize, options);
+               
+               size_t xattrsLen = 1;
+               size_t xattrIndex = 0;
+               char **xattrs = malloc(xattrsLen * sizeof(char *));
+               char *nextName = nameBuf;
+               while (nextName < nameBuf + nameBufSize)
+               {
+                       char *name = nextName;
+                       if (xattrIndex == xattrsLen) {
+                               xattrsLen *= 2;
+                               xattrs = realloc(xattrs, xattrsLen * sizeof(char *));
+                       }
+                       xattrs[xattrIndex++] = name;
+                       nextName += strlen(name) + 1;
+               }
+               
+               // sort the xattr array as they're not guaranteed to come in the same order
+               qsort_b(xattrs, xattrIndex, sizeof(char *), ^(const void *l, const void *r) {
+                       char *left = *(char **)l;
+                       char *right = *(char **)r;
+                       return strcmp(left, right);
+               });
+               
+               // gather the data for the xattrs
+               bool didAddXATTR = false;
+               int xattrBufLen = kSHA256NullTerminatedBuffLen;
+               void *xattrBuf = malloc(xattrBufLen); // resized if necessary
+               char *digest;
+               ssize_t result = 0;
+               char *oldSummary = NULL;
+               for (int i = 0; i < xattrIndex; i++) {
+                       char *name = xattrs[i];
+                       ssize_t xlen = getxattr(path, name, NULL, 0, 0, options);
+                       if (xlen > xattrBufLen) {
+                               xattrBufLen = xlen;
+                               xattrBuf = realloc(xattrBuf, xattrBufLen);
+                       }
+                       bzero(xattrBuf, xattrBufLen);
+                       result = getxattr(path, name, xattrBuf, xattrBufLen, 0, options);
+                       if (result < 0)
+                               err(1, "SHA256_Path_XATTRs: getxattr");
+                       
+                       digest = SHA256_Data(xattrBuf, xattrBufLen, buf);
+                       if (!digest)
+                               err(1, "%s", xattrsSummary);
+                       if (!didAddXATTR)
+                       {
+                               didAddXATTR = true;
+                               asprintf(&xattrsSummary, "%s:%s", name, digest);
+                       } else {
+                               oldSummary = xattrsSummary;
+                               asprintf(&xattrsSummary, "%s, %s:%s", oldSummary, name, digest);
+                               free(oldSummary);
+                       }
+               }
+               
+               free(xattrBuf);
+               free(nameBuf);
+               free(xattrs);
+               
+               digest = SHA256_Data(xattrsSummary, strlen(xattrsSummary) * sizeof(char), buf);
+               if (!digest)
+                       err(1, "%s", xattrsSummary);
+               
+               free(xattrsSummary);
+               return digest;
+       }
+       return kNone;
+}
+
+char *SHA256_Path_ACL(char *path, char *buf)
+{
+       int result              = 0;
+       char *data              = NULL;
+       char *digest            = NULL;
+       
+       struct attrlist list = {
+               .bitmapcount    = ATTR_BIT_MAP_COUNT,
+               .commonattr     = ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_EXTENDED_SECURITY,
+       };
+       
+       struct ACLBuf {
+               uint32_t                len;
+               attribute_set_t         returned_attrs;
+               attrreference_t         acl;
+               char                    buf[8192]; // current acls are up to 3116 bytes, but they may increase in the future
+       } __attribute__((aligned(4), packed));
+       
+       struct ACLBuf aclBuf;
+       
+       result = getattrlist(path, &list, &aclBuf, sizeof(aclBuf), FSOPT_NOFOLLOW);
+       
+       if (result)
+               err(1, "SHA256_Path_ACL: getattrlist");
+       
+       // if the path does not have an acl, return none
+       if ( ( ! ( aclBuf.returned_attrs.commonattr & ATTR_CMN_EXTENDED_SECURITY ) )
+           || ( aclBuf.acl.attr_length == 0 ) ) {
+               return kNone;
+       }
+       
+       data = ((char*)&aclBuf.acl) + aclBuf.acl.attr_dataoffset;
+       
+       digest = SHA256_Data(data, aclBuf.acl.attr_length, buf);
+       if (!digest)
+               err(1, "SHA256_Path_ACL: SHA256_Data");
+       
+       return digest;
+}
 
+/* Functions for Digest_Path_* */
+char *
+Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf) {
+       
+       uint8_t digest[32]; // SHA256 is the biggest
+       CCDigestCtx ctx;
+       size_t i, length;
+       
+       (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
+       (void)os_assumes_zero(CCDigestUpdate(&ctx, data, size));
+       
+       /* Finalize and convert to hex. */
+       (void)os_assumes_zero(CCDigestFinal(&ctx, digest));
+       length = CCDigestOutputSize(&ctx);
+       os_assert(length <= sizeof(digest));
+       for (i = 0; i < length; i++) {
+               buf[i+i] = hex[digest[i] >> 4];
+               buf[i+i+1] = hex[digest[i] & 0x0f];
+       }
+       buf[i+i] = '\0';
+       
        return buf;
 }
+
index cbef44a792888b56ccc8bb3026090a655e299c55..a894749a38ec90024346096d80e4f82eef7c4c68 100644 (file)
@@ -1,8 +1,15 @@
 #include <CommonCrypto/CommonDigestSPI.h>
 
+#define kNone "none"
+
+extern const int kSHA256NullTerminatedBuffLen;
+
 #define MD5File(f, b)        Digest_File(kCCDigestMD5, f, b)
 #define SHA1_File(f, b)      Digest_File(kCCDigestSHA1, f, b)
 #define RIPEMD160_File(f, b) Digest_File(kCCDigestRMD160, f, b)
 #define SHA256_File(f, b)    Digest_File(kCCDigestSHA256, f, b)
 
 char *Digest_File(CCDigestAlg algorithm, const char *filename, char *buf);
+
+char *SHA256_Path_XATTRs(char *path, char *buf);
+char *SHA256_Path_ACL(char *path, char *buf);
\ No newline at end of file
index 1bf7d51f7c034340ab8240ee429499b2e00f4cc6..7413d2fd9bc3b8ae1adccc372aadc8ea4ac64804 100644 (file)
@@ -86,7 +86,8 @@ compare(char *name __unused, NODE *s, FTSENT *p)
        off_t len;
        char *cp;
        const char *tab = "";
-       char *fflags;
+       char *fflags, *badflags;
+       u_long flags;
 
        label = 0;
        switch(s->type) {
@@ -182,18 +183,14 @@ typeerr:          LABEL;
                    (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size);
                tab = "\t";
        }
-       /*
-        * XXX
-        * Catches nano-second differences, but doesn't display them.
-        */
        if ((s->flags & F_TIME) &&
             ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
             (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
                LABEL;
-               (void)printf("%smodification time expected %.24s ",
-                   tab, ctime(&s->st_mtimespec.tv_sec));
-               (void)printf("found %.24s",
-                   ctime(&p->fts_statp->st_mtimespec.tv_sec));
+               (void)printf("%smodification time expected %.24s.%09ld ",
+                   tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
+               (void)printf("found %.24s.%09ld",
+                   ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
                if (uflag) {
                        tv[0].tv_sec = s->st_mtimespec.tv_sec;
                        tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
@@ -229,25 +226,35 @@ typeerr:          LABEL;
                        }
                }
        }
-       if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
-               LABEL;
-               fflags = flags_to_string(s->st_flags);
-               (void)printf("%sflags expected \"%s\"", tab, fflags);
-               free(fflags);
-
-               fflags = flags_to_string(p->fts_statp->st_flags);
-               (void)printf(" found \"%s\"", fflags);
+       if (s->flags & F_FLAGS) {
+               // There are unpublished flags that should not fail comparison
+               // we convert to string and back to filter them out
+               fflags = badflags = flags_to_string(p->fts_statp->st_flags);
+               if (strcmp("none", fflags) == 0) {
+                       flags = 0;
+               } else if (strtofflags(&badflags, &flags, NULL) != 0)
+                       errx(1, "invalid flag %s", badflags);
                free(fflags);
-
-               if (uflag)
-                       if (chflags(p->fts_accpath, (u_int)s->st_flags))
-                               (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
-                               (void)printf(" modified\n");
-               else
-                       (void)printf("\n");
-               tab = "\t";
+               if (s->st_flags != flags) {
+                       LABEL;
+                       fflags = flags_to_string(s->st_flags);
+                       (void)printf("%sflags expected \"%s\"", tab, fflags);
+                       free(fflags);
+                       
+                       fflags = flags_to_string(flags);
+                       (void)printf(" found \"%s\"", fflags);
+                       free(fflags);
+                       
+                       if (uflag)
+                               if (chflags(p->fts_accpath, (u_int)s->st_flags))
+                                       (void)printf(" not modified: %s\n",
+                                                    strerror(errno));
+                               else
+                                       (void)printf(" modified\n");
+                               else
+                                       (void)printf("\n");
+                       tab = "\t";
+               }
        }
 #ifdef ENABLE_MD5
        if (s->flags & F_MD5) {
@@ -305,7 +312,7 @@ typeerr:            LABEL;
 #endif /* ENABLE_RMD160 */
 #ifdef ENABLE_SHA256
        if (s->flags & F_SHA256) {
-               char *new_digest, buf[65];
+               char *new_digest, buf[kSHA256NullTerminatedBuffLen];
 
                new_digest = SHA256_File(p->fts_accpath, buf);
                if (!new_digest) {
@@ -328,6 +335,90 @@ typeerr:           LABEL;
                (void)printf("%slink_ref expected %s found %s\n",
                      tab, s->slink, cp);
        }
+       if ((s->flags & F_BTIME) &&
+           ((s->st_birthtimespec.tv_sec != p->fts_statp->st_birthtimespec.tv_sec) ||
+            (s->st_birthtimespec.tv_nsec != p->fts_statp->st_birthtimespec.tv_nsec))) {
+                   LABEL;
+                   (void)printf("%sbirth time expected %.24s.%09ld ",
+                                tab, ctime(&s->st_birthtimespec.tv_sec), s->st_birthtimespec.tv_nsec);
+                   (void)printf("found %.24s.%09ld\n",
+                                ctime(&p->fts_statp->st_birthtimespec.tv_sec), p->fts_statp->st_birthtimespec.tv_nsec);
+                   tab = "\t";
+           }
+       if ((s->flags & F_ATIME) &&
+           ((s->st_atimespec.tv_sec != p->fts_statp->st_atimespec.tv_sec) ||
+            (s->st_atimespec.tv_nsec != p->fts_statp->st_atimespec.tv_nsec))) {
+                   LABEL;
+                   (void)printf("%saccess time expected %.24s.%09ld ",
+                                tab, ctime(&s->st_atimespec.tv_sec), s->st_atimespec.tv_nsec);
+                   (void)printf("found %.24s.%09ld\n",
+                                ctime(&p->fts_statp->st_atimespec.tv_sec), p->fts_statp->st_atimespec.tv_nsec);
+                   tab = "\t";
+           }
+       if ((s->flags & F_CTIME) &&
+           ((s->st_ctimespec.tv_sec != p->fts_statp->st_ctimespec.tv_sec) ||
+            (s->st_ctimespec.tv_nsec != p->fts_statp->st_ctimespec.tv_nsec))) {
+                   LABEL;
+                   (void)printf("%smetadata modification time expected %.24s.%09ld ",
+                                tab, ctime(&s->st_ctimespec.tv_sec), s->st_ctimespec.tv_nsec);
+                   (void)printf("found %.24s.%09ld\n",
+                                ctime(&p->fts_statp->st_ctimespec.tv_sec), p->fts_statp->st_ctimespec.tv_nsec);
+                   tab = "\t";
+           }
+       if (s->flags & F_PTIME) {
+               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 ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) ||
+                   (s->st_ptimespec.tv_nsec != ptimespec.tv_nsec)) {
+                       LABEL;
+                       (void)printf("%stime added to parent folder expected %.24s.%09ld ",
+                                    tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
+                       (void)printf("found %.24s.%09ld\n",
+                                    ctime(&ptimespec.tv_sec), ptimespec.tv_nsec);
+                       tab = "\t";
+               }
+       }
+       if (s->flags & F_XATTRS) {
+               char *new_digest, buf[kSHA256NullTerminatedBuffLen];
+               new_digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
+               if (!new_digest) {
+                       LABEL;
+                       printf("%sxattrsdigest missing, expected: %s\n", tab, s->xattrsdigest);
+                       tab = "\t";
+               } else if (strcmp(new_digest, s->xattrsdigest)) {
+                       LABEL;
+                       printf("%sxattrsdigest expected %s found %s\n",
+                              tab, s->xattrsdigest, new_digest);
+                       tab = "\t";
+               }
+       }
+       if ((s->flags & F_INODE) &&
+           (p->fts_statp->st_ino != s->st_ino)) {
+               LABEL;
+               (void)printf("%sinode expected %llu found %llu\n",
+                            tab, s->st_ino, p->fts_ino);
+               tab = "\t";
+       }
+       if (s->flags & F_ACL) {
+               char *new_digest, buf[kSHA256NullTerminatedBuffLen];
+               new_digest = SHA256_Path_ACL(p->fts_accpath, buf);
+               if (!new_digest) {
+                       LABEL;
+                       printf("%sacldigest missing, expected: %s\n", tab, s->acldigest);
+                       tab = "\t";
+               } else if (strcmp(new_digest, s->acldigest)) {
+                       LABEL;
+                       printf("%sacldigest expected %s found %s\n",
+                              tab, s->acldigest, new_digest);
+                       tab = "\t";
+               }
+       }
+       
        return (label);
 }
 
index 44c32950554f03bb4e211f778656b79807c6fb9b..66992a73f2147063f6739834fdf30bdb91b0e40d 100644 (file)
@@ -77,10 +77,12 @@ static gid_t gid;
 static uid_t uid;
 static mode_t mode;
 static u_long flags = 0xffffffff;
+static char *xattrs = kNone;
+static char *acl = kNone;
 
 static int     dsort(const FTSENT **, const FTSENT **);
 static void    output(int, int *, const char *, ...) __printflike(3, 4);
-static int     statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
+static int     statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **);
 static void    statf(int, FTSENT *);
 
 void
@@ -92,6 +94,7 @@ cwalk(void)
        char *argv[2], host[MAXHOSTNAMELEN];
        char dot[] = ".";
        int indent = 0;
+       char *path;
 
        if (!nflag) {
                (void)time(&cl);
@@ -119,14 +122,20 @@ cwalk(void)
                case FTS_D:
                        if (!dflag)
                                (void)printf("\n");
-                       if (!nflag)
-                               (void)printf("# %s\n", p->fts_path);
-                       statd(t, p, &uid, &gid, &mode, &flags);
+                       if (!nflag) {
+                               path = escape_path(p->fts_path);
+                               (void)printf("# %s\n", path);
+                               free(path);
+                       }
+                       statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl);
                        statf(indent, p);
                        break;
                case FTS_DP:
-                       if (!nflag && (p->fts_level > 0))
-                               (void)printf("%*s# %s\n", indent, "", p->fts_path);
+                       if (!nflag && (p->fts_level > 0)) {
+                               path = escape_path(p->fts_path);
+                               (void)printf("%*s# %s\n", indent, "", path);
+                               free(path);
+                       }
                        (void)printf("%*s..\n", indent, "");
                        if (!dflag)
                                (void)printf("\n");
@@ -218,7 +227,7 @@ statf(int indent, FTSENT *p)
                output(indent, &offset, "size=%jd",
                    (intmax_t)p->fts_statp->st_size);
        if (keys & F_TIME)
-               output(indent, &offset, "time=%ld.%ld",
+               output(indent, &offset, "time=%ld.%09ld",
                    (long)p->fts_statp->st_mtimespec.tv_sec,
                    p->fts_statp->st_mtimespec.tv_nsec);
        if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
@@ -260,7 +269,7 @@ statf(int indent, FTSENT *p)
 #endif /* ENABLE_RMD160 */
 #ifdef ENABLE_SHA256
        if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) {
-               char *digest, buf[65];
+               char *digest, buf[kSHA256NullTerminatedBuffLen];
 
                digest = SHA256_File(p->fts_accpath, buf);
                if (!digest)
@@ -280,6 +289,53 @@ statf(int indent, FTSENT *p)
                output(indent, &offset, "flags=%s", fflags);
                free(fflags);
        }
+       if (keys & F_BTIME) {
+               output(indent, &offset, "btime=%ld.%09ld",
+                      p->fts_statp->st_birthtimespec.tv_sec,
+                      p->fts_statp->st_birthtimespec.tv_nsec);
+       }
+       // only check access time on regular files, as traversing a folder will update its access time
+       if (keys & F_ATIME && S_ISREG(p->fts_statp->st_mode)) {
+               output(indent, &offset, "atime=%ld.%09ld",
+                      p->fts_statp->st_atimespec.tv_sec,
+                      p->fts_statp->st_atimespec.tv_nsec);
+       }
+       if (keys & F_CTIME) {
+               output(indent, &offset, "ctime=%ld.%09ld",
+                      p->fts_statp->st_ctimespec.tv_sec,
+                      p->fts_statp->st_ctimespec.tv_nsec);
+       }
+       // date added to parent folder is only supported for files and directories
+       if (keys & F_PTIME && (S_ISREG(p->fts_statp->st_mode) ||
+                              S_ISDIR(p->fts_statp->st_mode))) {
+               int supported;
+               struct timespec ptimespec = ptime(p->fts_accpath, &supported);
+               if (supported) {
+                       output(indent, &offset, "ptime=%ld.%09ld",
+                              ptimespec.tv_sec,
+                              ptimespec.tv_nsec);
+               }
+       }
+       if (keys & F_XATTRS) {
+               char *digest, buf[kSHA256NullTerminatedBuffLen];
+               
+               digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
+               if (digest && (strcmp(digest, xattrs) != 0)) {
+                       output(indent, &offset, "xattrsdigest=%s", digest);
+               }
+       }
+       if (keys & F_INODE) {
+               output(indent, &offset, "inode=%llu", p->fts_statp->st_ino);
+       }
+       if (keys & F_ACL) {
+               char *digest, buf[kSHA256NullTerminatedBuffLen];
+               
+               digest = SHA256_Path_ACL(p->fts_accpath, buf);
+               if (digest && (strcmp(digest, acl) != 0)) {
+                       output(indent, &offset, "acldigest=%s", digest);
+               }
+       }
+       
        (void)putchar('\n');
 }
 
@@ -290,7 +346,7 @@ statf(int indent, FTSENT *p)
 #define        MAXS 16
 
 static int
-statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags)
+statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl)
 {
        FTSENT *p;
        gid_t sgid;
@@ -303,6 +359,8 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
        uid_t saveuid = *puid;
        mode_t savemode = *pmode;
        u_long saveflags = *pflags;
+       char *savexattrs = *pxattrs;
+       char *saveacl = *pacl;
        u_short maxgid, maxuid, maxmode, maxflags;
        u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
        char *fflags;
@@ -337,6 +395,12 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
                                saveuid = suid;
                                maxuid = u[suid];
                        }
+                       
+                       /*
+                        * XXX
+                        * note that we don't count the most common xattr/acl digest
+                        * so set will always the default value (none)
+                        */
 
                        /*
                         * XXX
@@ -399,11 +463,17 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
                        (void)printf(" flags=%s", fflags);
                        free(fflags);
                }
+               if (keys & F_XATTRS)
+                       (void)printf(" xattrsdigest=%s", savexattrs);
+               if (keys & F_ACL)
+                       (void)printf(" acldigest=%s", saveacl);
                (void)printf("\n");
                *puid = saveuid;
                *pgid = savegid;
                *pmode = savemode;
                *pflags = saveflags;
+               *pxattrs = savexattrs;
+               *pacl = saveacl;
        }
        return (0);
 }
index 4c7adb2f68f8ebff9d59ddfb7b726812918e0d7f..ff40b840362971d0429789d459026afac474dbeb 100644 (file)
@@ -37,6 +37,8 @@ int    compare(char *, NODE *, FTSENT *);
 int     crc(int, uint32_t *, off_t *);
 void    cwalk(void);
 char   *flags_to_string(u_long);
+char   *escape_path(char *string);
+struct timespec        ptime(char *path, int *supported);
 
 const char     *inotype(u_int);
 u_int   parsekey(char *, int *);
index 4cf852fd1399a789c9512b56d16dbfd5e27ebaa2..48518688000ceb185e22362ebfa44b8e873c523a 100644 (file)
@@ -44,6 +44,8 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez E
 #include <unistd.h>
 #include "mtree.h"
 #include "extern.h"
+#import <sys/attr.h>
+#include <vis.h>
 
 typedef struct _key {
        const char *name;                       /* key name */
@@ -55,32 +57,39 @@ typedef struct _key {
 
 /* NB: the following table must be sorted lexically. */
 static KEY keylist[] = {
-       {"cksum",       F_CKSUM,        NEEDVALUE},
-       {"flags",       F_FLAGS,        NEEDVALUE},
-       {"gid",         F_GID,          NEEDVALUE},
-       {"gname",       F_GNAME,        NEEDVALUE},
-       {"ignore",      F_IGN,          0},
-       {"link",        F_SLINK,        NEEDVALUE},
+       {"acldigest",           F_ACL,          NEEDVALUE},
+       {"atime",               F_ATIME,        NEEDVALUE},
+       {"btime",               F_BTIME,        NEEDVALUE},
+       {"cksum",               F_CKSUM,        NEEDVALUE},
+       {"ctime",               F_CTIME,        NEEDVALUE},
+       {"flags",               F_FLAGS,        NEEDVALUE},
+       {"gid",                 F_GID,          NEEDVALUE},
+       {"gname",               F_GNAME,        NEEDVALUE},
+       {"ignore",              F_IGN,          0},
+       {"inode",               F_INODE,        NEEDVALUE},
+       {"link",                F_SLINK,        NEEDVALUE},
 #ifdef ENABLE_MD5
-       {"md5digest",   F_MD5,          NEEDVALUE},
+       {"md5digest",           F_MD5,          NEEDVALUE},
 #endif
-       {"mode",        F_MODE,         NEEDVALUE},
-       {"nlink",       F_NLINK,        NEEDVALUE},
-       {"nochange",    F_NOCHANGE,     0},
+       {"mode",                F_MODE,         NEEDVALUE},
+       {"nlink",               F_NLINK,        NEEDVALUE},
+       {"nochange",            F_NOCHANGE,     0},
+       {"ptime",               F_PTIME,        NEEDVALUE},
 #ifdef ENABLE_RMD160
-       {"ripemd160digest", F_RMD160,   NEEDVALUE},
+       {"ripemd160digest",     F_RMD160,       NEEDVALUE},
 #endif
 #ifdef ENABLE_SHA1
-       {"sha1digest",  F_SHA1,         NEEDVALUE},
+       {"sha1digest",          F_SHA1,         NEEDVALUE},
 #endif
 #ifdef ENABLE_SHA256
-       {"sha256digest",        F_SHA256,               NEEDVALUE},
+       {"sha256digest",        F_SHA256,       NEEDVALUE},
 #endif
-       {"size",        F_SIZE,         NEEDVALUE},
-       {"time",        F_TIME,         NEEDVALUE},
-       {"type",        F_TYPE,         NEEDVALUE},
-       {"uid",         F_UID,          NEEDVALUE},
-       {"uname",       F_UNAME,        NEEDVALUE},
+       {"size",                F_SIZE,         NEEDVALUE},
+       {"time",                F_TIME,         NEEDVALUE},
+       {"type",                F_TYPE,         NEEDVALUE},
+       {"uid",                 F_UID,          NEEDVALUE},
+       {"uname",               F_UNAME,        NEEDVALUE},
+       {"xattrsdigest",        F_XATTRS,       NEEDVALUE},
 };
 
 int keycompare(const void *, const void *);
@@ -122,3 +131,45 @@ flags_to_string(u_long fflags)
 
        return string;
 }
+
+// escape path and always return a new string so it can be freed
+char *
+escape_path(char *string)
+{
+       char *escapedPath = calloc(1, strlen(string) * 4  +  1);
+       if (escapedPath == NULL)
+               errx(1, "escape_path(): calloc() failed");
+       strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
+       
+       return escapedPath;
+}
+
+struct ptimebuf {
+       uint32_t length;
+       attribute_set_t returned_attrs;
+       struct timespec st_ptimespec;
+} __attribute__((aligned(4), packed));
+
+// ptime is not supported on root filesystems or HFS filesystems older than the feature being introduced
+struct timespec
+ptime(char *path, int *supported) {
+       
+       int ret = 0;
+       struct ptimebuf buf;
+       struct attrlist list = {
+               .bitmapcount = ATTR_BIT_MAP_COUNT,
+               .commonattr = ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_ADDEDTIME,
+       };
+       ret = getattrlist(path, &list, &buf, sizeof(buf), FSOPT_NOFOLLOW);
+       if (ret) {
+               err(1, "ptime: getattrlist");
+       }
+       
+       *supported = 0;
+       if (buf.returned_attrs.commonattr & ATTR_CMN_ADDEDTIME) {
+               *supported = 1;
+       }
+       
+       return buf.st_ptimespec;
+       
+}
index 72536d3811ef66ee26a171e3afde71a4386e110e..1aa529a793841f8067f4121e9640eba90a9925bb 100644 (file)
@@ -246,6 +246,20 @@ The size, in bytes, of the file.
 The file the symbolic link is expected to reference.
 .It Cm time
 The last modification time of the file.
+.It Cm btime
+The creation (birth) time of the file.
+.It Cm atime
+The last access time of the file.
+.It Cm ctime
+The last metadata modification time of the file.
+.It Cm ptime
+The time the file was added to its parent folder.
+.It Cm inode
+The inode number of the file.
+.It Cm xattrsdigest
+Digest of the extended attributes of the file.
+.It Cm acldigest
+Digest of the access control list of the file.
 .It Cm type
 The type of the file; may be set to any one of the following:
 .Pp
index 2b997975382810a3022213ce4a6f7a9592b7bff5..02d1728475d3a59d35ffae51efa8a49d1a68aaba 100644 (file)
@@ -55,29 +55,43 @@ typedef struct _node {
        mode_t  st_mode;                        /* mode */
        u_long  st_flags;                       /* flags */
        nlink_t st_nlink;                       /* link count */
+       struct timespec st_birthtimespec;       /* birth time (creation time) */
+       struct timespec st_atimespec;           /* access time */
+       struct timespec st_ctimespec;           /* metadata modification time */
+       struct timespec st_ptimespec;           /* time added to parent folder */
+       char    *xattrsdigest;                  /* digest of extended attributes */
+       ino_t   st_ino;                         /* inode */
+       char    *acldigest;                     /* digest of access control list */
 
-#define        F_CKSUM 0x0001                          /* check sum */
-#define        F_DONE  0x0002                          /* directory done */
-#define        F_GID   0x0004                          /* gid */
-#define        F_GNAME 0x0008                          /* group name */
-#define        F_IGN   0x0010                          /* ignore */
-#define        F_MAGIC 0x0020                          /* name has magic chars */
-#define        F_MODE  0x0040                          /* mode */
-#define        F_NLINK 0x0080                          /* number of links */
-#define        F_SIZE  0x0100                          /* size */
-#define        F_SLINK 0x0200                          /* link count */
-#define        F_TIME  0x0400                          /* modification time */
-#define        F_TYPE  0x0800                          /* file type */
-#define        F_UID   0x1000                          /* uid */
-#define        F_UNAME 0x2000                          /* user name */
-#define        F_VISIT 0x4000                          /* file visited */
-#define F_MD5  0x8000                          /* MD5 digest */
-#define F_NOCHANGE 0x10000                     /* If owner/mode "wrong", do */
+#define        F_CKSUM         0x00000001              /* check sum */
+#define        F_DONE          0x00000002              /* directory done */
+#define        F_GID           0x00000004              /* gid */
+#define        F_GNAME         0x00000008              /* group name */
+#define        F_IGN           0x00000010              /* ignore */
+#define        F_MAGIC         0x00000020              /* name has magic chars */
+#define        F_MODE          0x00000040              /* mode */
+#define        F_NLINK         0x00000080              /* number of links */
+#define        F_SIZE          0x00000100              /* size */
+#define        F_SLINK         0x00000200              /* The file the symbolic link is expected to reference */
+#define        F_TIME          0x00000400              /* modification time (mtime) */
+#define        F_TYPE          0x00000800              /* file type */
+#define        F_UID           0x00001000              /* uid */
+#define        F_UNAME         0x00002000              /* user name */
+#define        F_VISIT         0x00004000              /* file visited */
+#define F_MD5          0x00008000              /* MD5 digest */
+#define F_NOCHANGE     0x00010000              /* If owner/mode "wrong", do */
                                                /* not change */
-#define        F_SHA1  0x20000                         /* SHA-1 digest */
-#define        F_RMD160 0x40000                        /* RIPEMD160 digest */
-#define        F_FLAGS 0x80000                         /* file flags */
-#define        F_SHA256        0x100000                                /* SHA-256 digest */
+#define        F_SHA1          0x00020000              /* SHA-1 digest */
+#define        F_RMD160        0x00040000              /* RIPEMD160 digest */
+#define        F_FLAGS         0x00080000              /* file flags */
+#define        F_SHA256        0x00100000              /* SHA-256 digest */
+#define F_BTIME                0x00200000              /* creation time */
+#define F_ATIME                0x00400000              /* access time */
+#define F_CTIME                0x00800000              /* metadata modification time (ctime) */
+#define F_PTIME                0x01000000              /* time added to parent folder */
+#define F_XATTRS       0x02000000              /* digest of extended attributes */
+#define F_INODE                0x04000000              /* inode */
+#define F_ACL          0x08000000              /* digest of access control list */
        u_int   flags;                          /* items set */
 
 #define        F_BLOCK 0x001                           /* block special */
index 915858c93a75671b8b913887ecd9a5af8fd446d3..332accc1f23cc12b8d9205517c1a5de1ff47698c 100644 (file)
@@ -179,131 +179,189 @@ set(char *t, NODE *ip)
                if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL)
                        errx(1, "line %d: missing value", lineno);
                switch(type) {
-               case F_CKSUM:
-                       ip->cksum = strtoul(val, &ep, 10);
-                       if (*ep)
-                               errx(1, "line %d: invalid checksum %s",
-                               lineno, val);
-                       break;
-               case F_MD5:
-                       ip->md5digest = strdup(val);
-                       if(!ip->md5digest)
-                               errx(1, "strdup");
-                       break;
-               case F_SHA1:
-                       ip->sha1digest = strdup(val);
-                       if(!ip->sha1digest)
-                               errx(1, "strdup");
-                       break;
-               case F_SHA256:
-                       ip->sha256digest = strdup(val);
-                       if(!ip->sha256digest)
-                               errx(1, "strdup");
-                       break;
-               case F_RMD160:
-                       ip->rmd160digest = strdup(val);
-                       if(!ip->rmd160digest)
-                               errx(1, "strdup");
-                       break;
-               case F_FLAGS:
-                       if (strcmp("none", val) == 0)
-                               ip->st_flags = 0;
-                       else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
-                               errx(1, "line %d: invalid flag %s",lineno, val);
-                       break;
-               case F_GID:
-                       ip->st_gid = (gid_t)strtoul(val, &ep, 10);
-                       if (*ep)
-                               errx(1, "line %d: invalid gid %s", lineno, val);
-                       break;
-               case F_GNAME:
-                       if ((gr = getgrnam(val)) == NULL)
-                           errx(1, "line %d: unknown group %s", lineno, val);
-                       ip->st_gid = gr->gr_gid;
-                       break;
-               case F_IGN:
-                       /* just set flag bit */
-                       break;
-               case F_MODE:
-                       if ((m = setmode(val)) == NULL)
-                               errx(1, "line %d: invalid file mode %s",
-                               lineno, val);
-                       ip->st_mode = getmode(m, 0);
-                       free(m);
-                       break;
-               case F_NLINK:
-                       ip->st_nlink = strtoul(val, &ep, 10);
-                       if (*ep)
-                               errx(1, "line %d: invalid link count %s",
-                               lineno,  val);
-                       break;
-               case F_SIZE:
-                       ip->st_size = strtoq(val, &ep, 10);
-                       if (*ep)
-                               errx(1, "line %d: invalid size %s",
-                               lineno, val);
-                       break;
-               case F_SLINK:
-                       ip->slink = malloc(strlen(val) + 1);
-                       if (ip->slink == NULL)
-                               errx(1, "malloc");
-                       if (strunvis(ip->slink, val) == -1)
-                               errx(1, "symlink %s is ill-encoded", val);
-                       break;
-               case F_TIME:
-                       ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
-                       if (*ep != '.')
-                               errx(1, "line %d: invalid time %s",
-                               lineno, val);
-                       val = ep + 1;
-                       ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
-                       if (*ep)
-                               errx(1, "line %d: invalid time %s",
-                               lineno, val);
-                       break;
-               case F_TYPE:
-                       switch(*val) {
-                       case 'b':
-                               if (!strcmp(val, "block"))
-                                       ip->type = F_BLOCK;
+                       case F_CKSUM:
+                               ip->cksum = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid checksum %s",
+                                            lineno, val);
                                break;
-                       case 'c':
-                               if (!strcmp(val, "char"))
-                                       ip->type = F_CHAR;
+                       case F_MD5:
+                               ip->md5digest = strdup(val);
+                               if(!ip->md5digest)
+                                       errx(1, "strdup");
                                break;
-                       case 'd':
-                               if (!strcmp(val, "dir"))
-                                       ip->type = F_DIR;
+                       case F_SHA1:
+                               ip->sha1digest = strdup(val);
+                               if(!ip->sha1digest)
+                                       errx(1, "strdup");
                                break;
-                       case 'f':
-                               if (!strcmp(val, "file"))
-                                       ip->type = F_FILE;
-                               if (!strcmp(val, "fifo"))
-                                       ip->type = F_FIFO;
+                       case F_SHA256:
+                               ip->sha256digest = strdup(val);
+                               if(!ip->sha256digest)
+                                       errx(1, "strdup");
                                break;
-                       case 'l':
-                               if (!strcmp(val, "link"))
-                                       ip->type = F_LINK;
+                       case F_RMD160:
+                               ip->rmd160digest = strdup(val);
+                               if(!ip->rmd160digest)
+                                       errx(1, "strdup");
                                break;
-                       case 's':
-                               if (!strcmp(val, "socket"))
-                                       ip->type = F_SOCK;
+                       case F_FLAGS:
+                               if (strcmp("none", val) == 0)
+                                       ip->st_flags = 0;
+                               else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
+                                       errx(1, "line %d: invalid flag %s",lineno, val);
                                break;
-                       default:
-                               errx(1, "line %d: unknown file type %s",
-                               lineno, val);
-                       }
-                       break;
-               case F_UID:
-                       ip->st_uid = (uid_t)strtoul(val, &ep, 10);
-                       if (*ep)
-                               errx(1, "line %d: invalid uid %s", lineno, val);
-                       break;
-               case F_UNAME:
-                       if ((pw = getpwnam(val)) == NULL)
-                           errx(1, "line %d: unknown user %s", lineno, val);
-                       ip->st_uid = pw->pw_uid;
-                       break;
+                       case F_GID:
+                               ip->st_gid = (gid_t)strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid gid %s", lineno, val);
+                               break;
+                       case F_GNAME:
+                               if ((gr = getgrnam(val)) == NULL)
+                                       errx(1, "line %d: unknown group %s", lineno, val);
+                               ip->st_gid = gr->gr_gid;
+                               break;
+                       case F_IGN:
+                               /* just set flag bit */
+                               break;
+                       case F_MODE:
+                               if ((m = setmode(val)) == NULL)
+                                       errx(1, "line %d: invalid file mode %s",
+                                            lineno, val);
+                               ip->st_mode = getmode(m, 0);
+                               free(m);
+                               break;
+                       case F_NLINK:
+                               ip->st_nlink = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid link count %s",
+                                            lineno,  val);
+                               break;
+                       case F_SIZE:
+                               ip->st_size = strtoq(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid size %s",
+                                            lineno, val);
+                               break;
+                       case F_SLINK:
+                               ip->slink = malloc(strlen(val) + 1);
+                               if (ip->slink == NULL)
+                                       errx(1, "malloc");
+                               if (strunvis(ip->slink, val) == -1)
+                                       errx(1, "symlink %s is ill-encoded", val);
+                               break;
+                       case F_TIME:
+                               ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.')
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               val = ep + 1;
+                               ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               break;
+                       case F_TYPE:
+                               switch(*val) {
+                                       case 'b':
+                                               if (!strcmp(val, "block"))
+                                                       ip->type = F_BLOCK;
+                                               break;
+                                       case 'c':
+                                               if (!strcmp(val, "char"))
+                                                       ip->type = F_CHAR;
+                                               break;
+                                       case 'd':
+                                               if (!strcmp(val, "dir"))
+                                                       ip->type = F_DIR;
+                                               break;
+                                       case 'f':
+                                               if (!strcmp(val, "file"))
+                                                       ip->type = F_FILE;
+                                               if (!strcmp(val, "fifo"))
+                                                       ip->type = F_FIFO;
+                                               break;
+                                       case 'l':
+                                               if (!strcmp(val, "link"))
+                                                       ip->type = F_LINK;
+                                               break;
+                                       case 's':
+                                               if (!strcmp(val, "socket"))
+                                                       ip->type = F_SOCK;
+                                               break;
+                                       default:
+                                               errx(1, "line %d: unknown file type %s",
+                                                    lineno, val);
+                               }
+                               break;
+                       case F_UID:
+                               ip->st_uid = (uid_t)strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid uid %s", lineno, val);
+                               break;
+                       case F_UNAME:
+                               if ((pw = getpwnam(val)) == NULL)
+                                       errx(1, "line %d: unknown user %s", lineno, val);
+                               ip->st_uid = pw->pw_uid;
+                               break;
+                       case F_BTIME:
+                               ip->st_birthtimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.')
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               val = ep + 1;
+                               ip->st_birthtimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               break;
+                       case F_ATIME:
+                               ip->st_atimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.')
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               val = ep + 1;
+                               ip->st_atimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               break;
+                       case F_CTIME:
+                               ip->st_ctimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.')
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               val = ep + 1;
+                               ip->st_ctimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               break;
+                       case F_PTIME:
+                               ip->st_ptimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.')
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               val = ep + 1;
+                               ip->st_ptimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               break;
+                       case F_XATTRS:
+                               ip->xattrsdigest = strdup(val);
+                               if(!ip->xattrsdigest)
+                                       err(1, "strdup");
+                               break;
+                       case F_INODE:
+                               ip->st_ino = (ino_t)strtoull(val, &ep, 10);
+                               if (*ep)
+                                       errx(1, "line %d: invalid inode %s", lineno, val);
+                               break;
+                       case F_ACL:
+                               ip->acldigest = strdup(val);
+                               if(!ip->acldigest)
+                                       err(1, "strdup");
                }
        }
 }
index 113d2fdc3c3d993f4498df742c6a1f29adfdf123..bbcd795c7433896ff27b6973968687cc9726755c 100644 (file)
@@ -68,6 +68,8 @@ shownode(NODE *n, int f, char const *path)
                printf(" nlink=%d", n->st_nlink);
        if (f & F_SIZE)
                printf(" size=%jd", (intmax_t)n->st_size);
+       if (f & F_TIME)
+               printf(" time=%ld.%09ld", n->st_mtimespec.tv_sec, n->st_mtimespec.tv_nsec);
        if (f & F_UID)
                printf(" uid=%d", n->st_uid);
        if (f & F_UNAME) {
@@ -87,6 +89,21 @@ shownode(NODE *n, int f, char const *path)
                printf(" sha256digest=%s", n->sha256digest);
        if (f & F_FLAGS)
                printf(" flags=%s", flags_to_string(n->st_flags));
+       if (f & F_BTIME)
+               printf(" btime=%ld.%09ld", n->st_birthtimespec.tv_sec, n->st_birthtimespec.tv_nsec);
+       if (f & F_ATIME)
+               printf(" atime=%ld.%09ld", n->st_atimespec.tv_sec, n->st_atimespec.tv_nsec);
+       if (f & F_CTIME)
+               printf(" ctime=%ld.%09ld", n->st_ctimespec.tv_sec, n->st_ctimespec.tv_nsec);
+       if (f & F_PTIME)
+               printf(" ptime=%ld.%09ld", n->st_ptimespec.tv_sec, n->st_ptimespec.tv_nsec);
+       if (f & F_XATTRS)
+               printf(" xattrsdigest=%s", n->xattrsdigest);
+       if (f & F_INODE)
+               printf(" inode=%llu", n->st_ino);
+       if (f & F_ACL)
+               printf(" acldigest=%s", n->acldigest);
+       
        printf("\n");
 }
 
@@ -167,6 +184,21 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
                differs |= F_SHA256;
        if (FF(n1, n2, F_FLAGS, st_flags))
                differs |= F_FLAGS;
+       if (FM(n1, n2, F_BTIME, st_birthtimespec))
+               differs |= F_BTIME;
+       if (FM(n1, n2, F_ATIME, st_atimespec))
+               differs |= F_ATIME;
+       if (FM(n1, n2, F_CTIME, st_ctimespec))
+               differs |= F_CTIME;
+       if (FM(n1, n2, F_PTIME, st_ptimespec))
+               differs |= F_PTIME;
+       if (FS(n1, n2, F_XATTRS, xattrsdigest))
+               differs |= F_XATTRS;
+       if (FF(n1, n2, F_INODE, st_ino))
+               differs |= F_INODE;
+       if (FS(n1, n2, F_ACL, acldigest))
+               differs |= F_ACL;
+       
        if (differs) {
                mismatch(n1, n2, differs, path);
                return (1);
index 0b3dc9b96217c55517e6298d58892b4a806278d9..84a37ffe4c6c9b0a5eba5574ecc4f967d45cd350 100644 (file)
@@ -51,18 +51,22 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian
 static NODE *root;
 static char path[MAXPATHLEN];
 
-static void    miss(NODE *, char *);
+static int     miss(NODE *, char *);
 static int     vwalk(void);
 
 int
 mtree_verifyspec(FILE *fi)
 {
-       int rval;
+       int rval, mval;
 
        root = mtree_readspec(fi);
        rval = vwalk();
-       miss(root, path);
-       return (rval);
+       mval = miss(root, path);
+       
+       if (rval != 0)
+               return rval;
+       else
+               return mval;
 }
 
 static int
@@ -153,13 +157,15 @@ extra:
        return (rval);
 }
 
-static void
+static int
 miss(NODE *p, char *tail)
 {
        int create;
        char *tp;
        const char *type, *what;
        int serr;
+       int rval = 0;
+       int rrval = 0;
 
        for (; p; p = p->next) {
                if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
@@ -170,10 +176,12 @@ miss(NODE *p, char *tail)
                           symbolic link and the -q flag is set. */
                        struct stat statbuf;
 
-                       if (qflag && stat(path, &statbuf) == 0)
+                       if (qflag && stat(path, &statbuf) == 0) {
                                p->flags |= F_VISIT;
-                       else
+                       } else {
                                (void)printf("%s missing", path);
+                               rval = MISMATCHEXIT;
+                       }
                }
                if (p->type != F_DIR && p->type != F_LINK) {
                        putchar('\n');
@@ -226,7 +234,9 @@ miss(NODE *p, char *tail)
 
                for (tp = tail; *tp; ++tp);
                *tp = '/';
-               miss(p->child, tp + 1);
+               rrval = miss(p->child, tp + 1);
+               if (rrval != 0)
+                       rval = rrval;
                *tp = '\0';
 
                if (!create)
@@ -252,4 +262,5 @@ miss(NODE *p, char *tail)
                        (void)printf("%s: file flags not set: %s\n",
                            path, strerror(errno));
        }
+       return rval;
 }
diff --git a/mv/mv.c b/mv/mv.c
index c1116d442955ee39cee9eb08d3abccfdb71bc84f..0576c433188b83b7de9e261e2da3f3ceb9097632 100644 (file)
--- a/mv/mv.c
+++ b/mv/mv.c
@@ -443,7 +443,7 @@ copy(char *from, char *to)
 {
        int pid, status;
        
-       /* posix_spawn mv from to && rm from */
+       /* posix_spawn cp from to && rm from */
 
        if ((pid = fork()) == 0) {
                execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to,
diff --git a/rm/rm.c b/rm/rm.c
index 4e78b46f24f4635ba107ac5947ecf7c705539236..ec13b2a4f50f05ac787ddcb42cf655b00b00743a 100644 (file)
--- a/rm/rm.c
+++ b/rm/rm.c
@@ -530,10 +530,24 @@ checkdot(argv)
 
        complained = 0;
        for (t = argv; *t;) {
-               if ((p = strrchr(*t, '/')) != NULL)
-                       ++p;
-               else
+               size_t len = strlen(*t);
+               char truncated[len];
+
+               if ((p = strrchr(*t, '/')) != NULL) {
+                       if (p[1] == '\0') { // trailing / -- treat as if not present
+                               strlcpy(truncated, *t, len);
+                               p = strrchr(truncated, '/');
+                               if (p) {
+                                       ++p;
+                               } else {
+                                       p = truncated;
+                               }
+                       } else {
+                               ++p;
+                       }
+               } else {
                        p = *t;
+               }
                if (ISDOT(p)) {
                        if (!complained++)
                                warnx("\".\" and \"..\" may not be removed");