]> git.saurik.com Git - apple/file_cmds.git/commitdiff
file_cmds-321.40.3.tar.gz macos-1101 macos-112 v321.40.3
authorApple <opensource@apple.com>
Sat, 29 Aug 2020 01:51:24 +0000 (01:51 +0000)
committerApple <opensource@apple.com>
Sat, 29 Aug 2020 01:51:24 +0000 (01:51 +0000)
43 files changed:
chmod/chmod_acl.h
cksum/extern.h
cp/extern.h
dd/dd.h
dd/extern.h
file_cmds.xcodeproj/project.pbxproj
install/pathnames.h
ln/ln.1
ln/ln.c
ls/extern.h
ls/ls.c
ls/ls.h
mtree/commoncrypto.c
mtree/commoncrypto.h
mtree/compare.c
mtree/create.c
mtree/excludes.c
mtree/extern.h
mtree/fix_failure_locations.py [new file with mode: 0755]
mtree/metrics.c [new file with mode: 0644]
mtree/metrics.h [new file with mode: 0644]
mtree/misc.c
mtree/mtree.c
mtree/mtree.h
mtree/spec.c
mtree/specspec.c
mtree/verify.c
mv/pathnames.h
pax/cache.h
pax/cpio.h
pax/extern.h
pax/ftree.h
pax/gen_subs.c
pax/options.h
pax/pat_rep.c
pax/pat_rep.h
pax/pax.c
pax/pax.h
pax/pax_format.h
pax/sel_subs.h
pax/tables.h
pax/tar.h
rm/rm.c

index c76d076daa3d928e2cddc7e7adac4fc42d2c3c54..b4667e9536dc3383973a8cd7d06d38a50c785c8e 100644 (file)
@@ -31,6 +31,9 @@
  * SUCH DAMAGE.
  */
 
+#ifndef _CHMOD_ACL_H_
+#define _CHMOD_ACL_H_
+
 #ifdef __APPLE__
 #include <pwd.h>
 #include <grp.h>
@@ -83,3 +86,5 @@ extern int modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
 extern int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow);
 extern uuid_t *name_to_uuid(char *tok, int nametype);
 #endif /* __APPLE__*/
+
+#endif /* _CHMOD_ACL_H_ */
index e9b594adf26290ba6c37728deb287a3b43af4f49..3e9c8c6c0799f6d0f71e683c3efa3b4fd241ada0 100644 (file)
@@ -34,6 +34,9 @@
  * $FreeBSD: src/usr.bin/cksum/extern.h,v 1.6 2003/03/13 23:32:28 robert Exp $
  */
 
+#ifndef _CKSUM_EXTERN_H_
+#define _CKSUM_EXTERN_H_
+
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
@@ -45,3 +48,5 @@ int   csum1(int, uint32_t *, off_t *);
 int    csum2(int, uint32_t *, off_t *);
 int    crc32(int, uint32_t *, off_t *);
 __END_DECLS
+
+#endif /* _CKSUM_EXTERN_H_ */
index c0ca0bcbe667863d8e255a90ac7ec145baef11cf..521091d5767c2b9abc66f6b43f4a36aa9b9f97e5 100644 (file)
@@ -30,6 +30,9 @@
  * $FreeBSD: src/bin/cp/extern.h,v 1.20 2005/09/05 04:36:08 csjp Exp $
  */
 
+#ifndef _CP_EXTERN_H_
+#define _CP_EXTERN_H_
+
 typedef struct {
        char    *p_end;                 /* pointer to NULL at end of path */
        char    *target_end;            /* pointer to end of target base */
@@ -54,3 +57,5 @@ int   preserve_dir_acls(struct stat *, char *, char *);
 int    preserve_fd_acls(int, int);
 void   usage(void);
 __END_DECLS
+
+#endif /* _CP_EXTERN_H_ */
diff --git a/dd/dd.h b/dd/dd.h
index d7e60a08d017499960369ec48c1e862e6c454bc2..c516ad26ced23691a7c2521ec6c161326ec1cf94 100644 (file)
--- a/dd/dd.h
+++ b/dd/dd.h
@@ -38,6 +38,9 @@
  * $FreeBSD: src/bin/dd/dd.h,v 1.17 2002/02/22 20:51:00 markm Exp $
  */
 
+#ifndef _DD_H_
+#define _DD_H_
+
 /* Input/output stream state. */
 typedef struct {
        u_char          *db;            /* buffer address */
@@ -95,3 +98,5 @@ typedef struct {
 #define        C_UNBLOCK       0x80000
 #define        C_OSYNC         0x100000
 #define        C_SPARSE        0x200000
+
+#endif /* _DD_H_ */
index 278c3688c078d342b34a11433300007f047cee4d..0ae63303e8ba92a50f7fbab579946cb2aad261cf 100644 (file)
@@ -38,6 +38,9 @@
  * $FreeBSD: src/bin/dd/extern.h,v 1.12 2002/02/02 06:24:12 imp Exp $
  */
 
+#ifndef _DD_EXTERN_H_
+#define _DD_EXTERN_H_
+
 #include <sys/cdefs.h>
 
 void block(void);
@@ -66,3 +69,5 @@ extern const u_char a2e_32V[], a2e_POSIX[];
 extern const u_char e2a_32V[], e2a_POSIX[];
 extern const u_char a2ibm_32V[], a2ibm_POSIX[];
 extern u_char casetab[];
+
+#endif /* _DD_EXTERN_H_ */
index c6e961099ba74505874b55acc7d528401f53bc8c..e4e94ec6ee45c97b885bfdcf4ad3387844c4200e 100644 (file)
                        name = tests;
                        productName = tests;
                };
+               729D07252347EC4D000716E5 /* macos_host_tools */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 729D07682347EC4D000716E5 /* Build configuration list for PBXAggregateTarget "macos_host_tools" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               729D074E2347EC4D000716E5 /* PBXTargetDependency */,
+                       );
+                       name = macos_host_tools;
+                       productName = macos_host_tools;
+               };
                FC8A8C3C14B64A9D001B97AD /* shar */ = {
                        isa = PBXAggregateTarget;
                        buildConfigurationList = FC8A8C3D14B64A9D001B97AD /* Build configuration list for PBXAggregateTarget "shar" */;
                3E59B9311D4A767600D3128C /* futimens.c in Sources */ = {isa = PBXBuildFile; fileRef = 3E59B9301D4A767600D3128C /* futimens.c */; };
                3E966CEE1FB2216F0019F7A1 /* file_cmds.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */; };
                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 */; };
                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 */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
+               729D074F2347EC4D000716E5 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = FC8A8B8C14B648ED001B97AD;
+                       remoteInfo = mtree;
+               };
                FC8A8C4914B64DE1001B97AD /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
                3E59B9301D4A767600D3128C /* futimens.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = futimens.c; sourceTree = "<group>"; };
                3E966CEB1FB2214F0019F7A1 /* chgrp.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = chgrp.sh; sourceTree = "<group>"; };
                3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = file_cmds.plist; sourceTree = "<group>"; };
+               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>"; };
                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; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               729D06D8230B5E42000716E5 /* CoreFoundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        path = tests;
                        sourceTree = "<group>";
                };
+               729D06D6230B5E42000716E5 /* Frameworks */ = {
+                       isa = PBXGroup;
+                       children = (
+                               729D06D7230B5E42000716E5 /* CoreFoundation.framework */,
+                       );
+                       name = Frameworks;
+                       sourceTree = "<group>";
+               };
                FCB1BDAD14B645D00070FACB = {
                        isa = PBXGroup;
                        children = (
                                FCB1BE8614B6460C0070FACB /* touch */,
                                FDAD94A71808BCB700B4D5A0 /* Libraries */,
                                FCB1BDB914B645D10070FACB /* Products */,
+                               729D06D6230B5E42000716E5 /* Frameworks */,
                        );
                        indentWidth = 8;
                        sourceTree = "<group>";
                                FCB1BE4114B6460C0070FACB /* specspec.c */,
                                FCB1BE4214B6460C0070FACB /* test */,
                                FCB1BE4814B6460C0070FACB /* verify.c */,
+                               7D0A20E82499364700F0F6D7 /* metrics.h */,
+                               7D0A20E92499364700F0F6D7 /* metrics.c */,
                        );
                        path = mtree;
                        sourceTree = "<group>";
                                FC8A8CC814B65F92001B97AD /* uncompress */,
                                FC8A8C5014B650CF001B97AD /* unlink */,
                                3E966CE71FB2211F0019F7A1 /* tests */,
+                               729D07252347EC4D000716E5 /* macos_host_tools */,
                        );
                };
 /* End PBXProject section */
                                FC8A8C1914B64A1A001B97AD /* create.c in Sources */,
                                FC8A8C1A14B64A22001B97AD /* excludes.c in Sources */,
                                FC8A8C1B14B64A27001B97AD /* misc.c in Sources */,
+                               7D0A20EA2499364700F0F6D7 /* metrics.c in Sources */,
                                FC8A8C1C14B64A2D001B97AD /* mtree.c in Sources */,
                                FC8A8C1D14B64A31001B97AD /* spec.c in Sources */,
                                FC8A8C1E14B64A34001B97AD /* specspec.c in Sources */,
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+               729D074E2347EC4D000716E5 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FC8A8B8C14B648ED001B97AD /* mtree */;
+                       targetProxy = 729D074F2347EC4D000716E5 /* PBXContainerItemProxy */;
+               };
                FC8A8C4A14B64DE1001B97AD /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = FC8A8BC414B648EF001B97AD /* stat */;
                        };
                        name = Release;
                };
+               729D07692347EC4D000716E5 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               INSTALL_PATH = /usr/bin;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
                FC8A8B1114B648D7001B97AD /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                        ENABLE_SHA1,
                                        ENABLE_SHA256,
                                );
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
                                INSTALL_PATH = /usr/sbin;
                                "OTHER_LDFLAGS[sdk=macosx*]" = "-lCrashReporterClient";
                        };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               729D07682347EC4D000716E5 /* Build configuration list for PBXAggregateTarget "macos_host_tools" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               729D07692347EC4D000716E5 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                FC8A8B1014B648D7001B97AD /* Build configuration list for PBXNativeTarget "chmod" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
index 853b83c0244e6054d403403365f53dd23666347e..5099eb04bc7f08d890cd90e4273145cc017128ca 100644 (file)
@@ -33,4 +33,9 @@
  *     @(#)pathnames.h 8.1 (Berkeley) 6/6/93
  */
 
+#ifndef _INSTALL_PATHNAMES_H_
+#define _INSTALL_PATHNAMES_H_
+
 #define        _PATH_STRIP     "/usr/bin/strip"
+
+#endif /* _INSTALL_PATHNAMES_H_ */
diff --git a/ln/ln.1 b/ln/ln.1
index 37100d3787375683595449d2b9ce8d53a33f7e33..d9edf003235468607b96c385ef2042f7cbb6aa32 100644 (file)
--- a/ln/ln.1
+++ b/ln/ln.1
@@ -32,7 +32,7 @@
 .\"    @(#)ln.1        8.2 (Berkeley) 12/30/93
 .\" $FreeBSD: src/bin/ln/ln.1,v 1.31 2006/02/14 11:08:05 glebius Exp $
 .\"
-.Dd February 14, 2006
+.Dd July 12, 2019
 .Dt LN 1
 .Os
 .Sh NAME
 .Nm ln
 .Op Fl Ffhinsv
 .Ar source_file
-.Op Ar target_file
+.Op Ar link_name
 .Nm ln
 .Op Fl Ffhinsv
 .Ar source_file ...
-.Ar target_dir
+.Ar link_dirname
 .Nm link
-.Ar source_file Ar target_file
+.Ar source_file Ar link_name
 .Sh DESCRIPTION
 The
 .Nm ln
@@ -70,7 +70,7 @@ The options are as follows:
 .Bl -tag -width flag
 .\" ==========
 .It Fl F
-If the target file already exists and is a directory, then remove it
+If the proposed link (link_name) already exists and is a directory, then remove it
 so that the link may occur.
 The
 .Fl F
@@ -89,16 +89,16 @@ option is a no-op unless
 option is specified.
 .It Fl h
 If the
-.Ar target_file
+.Ar link_name
 or
-.Ar target_dir
+.Ar link_dirname
 is a symbolic link, do not follow it.
 This is most useful with the
 .Fl f
 option, to replace a symlink which may point to a directory.
 .\" ==========
 .It Fl f
-If the target file already exists,
+If the proposed link (link_name) already exists,
 then unlink it so that the link may occur.
 (The
 .Fl f
@@ -109,12 +109,12 @@ options.)
 .It Fl i
 Cause
 .Nm ln
-to write a prompt to standard error if the target file exists.
+to write a prompt to standard error if the proposed link exists.
 If the response from the standard input begins with the character
 .Sq Li y
 or
 .Sq Li Y ,
-then unlink the target file so that the link may occur.
+then unlink the proposed link so that the link may occur.
 Otherwise, do not attempt the link.
 (The
 .Fl i
@@ -168,9 +168,9 @@ Given one or two arguments,
 creates a link to an existing file
 .Ar source_file .
 If
-.Ar target_file
+.Ar link_name
 is given, the link has that name;
-.Ar target_file
+.Ar link_name
 may also be a directory in which to place the link;
 otherwise it is placed in the current directory.
 If only the directory is specified, the link will be made
@@ -180,7 +180,7 @@ to the last component of
 Given more than two arguments,
 .Nm ln
 makes links in
-.Ar target_dir
+.Ar link_dirname
 to all the named source files.
 The links made will have the same name as the files being linked to.
 .Pp
diff --git a/ln/ln.c b/ln/ln.c
index 183800e31ee4e334442bb931e1ccca220491b7e0..0455dcef6dc53e9193f3e54ccd44a42868e404c8 100644 (file)
--- a/ln/ln.c
+++ b/ln/ln.c
@@ -265,8 +265,8 @@ void
 usage(void)
 {
        (void)fprintf(stderr, "%s\n%s\n%s\n",
-           "usage: ln [-Ffhinsv] source_file [target_file]",
-           "       ln [-Ffhinsv] source_file ... target_dir",
-           "       link source_file target_file");
+           "usage: ln [-Ffhinsv] source_file [link_name]",
+           "       ln [-Ffhinsv] source_file ... linkname_dir",
+           "       link source_file link_name");
        exit(1);
 }
index 6c7755872cdf01886f88eee9d0fde586756eb0ea..a33bd97a8c057f3e23e371a35189b44fb15632bc 100644 (file)
@@ -34,6 +34,9 @@
  * $FreeBSD: src/bin/ls/extern.h,v 1.19 2002/05/19 02:51:36 tjr Exp $
  */
 
+#ifndef _LS_EXTERN_H_
+#define _LS_EXTERN_H_
+
 int     acccmp(const FTSENT *, const FTSENT *);
 int     revacccmp(const FTSENT *, const FTSENT *);
 int     modcmp(const FTSENT *, const FTSENT *);
@@ -66,3 +69,5 @@ extern  char    *ansi_coloff;
 extern  char    *attrs_off;
 extern  char    *enter_bold;
 #endif
+
+#endif /* _LS_EXTERN_H_ */
diff --git a/ls/ls.c b/ls/ls.c
index 7823b557a42f0e842b2b57077d62c6abd09a2879..e07933392be74e12087450f8e03962c86e69a3f3 100644 (file)
--- a/ls/ls.c
+++ b/ls/ls.c
@@ -89,6 +89,8 @@ __RCSID("$FreeBSD: src/bin/ls/ls.c,v 1.66 2002/09/21 01:28:36 wollman Exp $");
  */
 #define        STRBUF_SIZEOF(t)        (1 + CHAR_BIT * sizeof(t) / 3 + 1)
 
+#define        IS_DATALESS(sp)         (f_dataless && (sp) && ((sp)->st_flags & SF_DATALESS))
+
 static void     display(FTSENT *, FTSENT *);
 static u_quad_t         makenines(u_quad_t);
 static int      mastercmp(const FTSENT **, const FTSENT **);
@@ -417,11 +419,11 @@ main(int argc, char *argv[])
 #endif
 
        /*
-        * If not -F, -i, -l, -s or -t options, don't require stat
+        * If not -F, -i, -l, -s, -t or -% options, don't require stat
         * information, unless in color mode in which case we do
         * need this to determine which colors to display.
         */
-       if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type && !f_sizesort
+       if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type && !f_sizesort && !f_dataless
 #ifdef COLORLS
            && !f_color
 #endif
@@ -560,6 +562,11 @@ traverse(int argc, char *argv[], int options)
                                break;
                        }
 
+                       if (IS_DATALESS(p->fts_statp)) {
+                               fts_set(ftsp, p, FTS_SKIP);
+                               break;
+                       }
+
                        /*
                         * If already output something, put out a newline as
                         * a separator.  If multiple arguments, precede each
@@ -851,7 +858,7 @@ display(FTSENT *p, FTSENT *list)
                                } else {
                                        np->mode_suffix = ' ';
                                }
-                               if (f_dataless && (sp->st_flags & SF_DATALESS)) {
+                               if (IS_DATALESS(sp)) {
                                        np->mode_suffix = '%';
                                }
                                if (!f_acl) {
diff --git a/ls/ls.h b/ls/ls.h
index 5b4769b59bd309e2e54b795425ef0f1a8eacced4..d1ef0375b064b7038592bd7b4a8eb39f54482925 100644 (file)
--- a/ls/ls.h
+++ b/ls/ls.h
@@ -37,6 +37,9 @@
  * $FreeBSD: src/bin/ls/ls.h,v 1.18 2002/05/19 02:51:36 tjr Exp $
  */
 
+#ifndef _LS_H_
+#define _LS_H_
+
 #define NO_PRINT       1
 
 extern long blocksize;         /* block size units */
@@ -101,3 +104,5 @@ typedef struct {
 #endif /* __APPLE__ */
        char data[1];
 } NAMES;
+
+#endif /* _LS_H_ */
index f7556312fda56401bc6eefd5341b4c812197302b..11e97ceb085199f58afa79e19e050dc8cdf91043 100644 (file)
 #include <stdio.h>
 #include <sys/attr.h>
 #include <unistd.h>
+#include <sys/xattr.h>
+#include <sys/mount.h>
+#include <apfs/apfs_fsctl.h>
 
 #include "commoncrypto.h"
+#include "extern.h"
+#include "metrics.h"
 
 const int kSHA256NullTerminatedBuffLen = 65;
 static const char hex[] = "0123456789abcdef";
@@ -52,6 +57,7 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
        io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
                if (error != 0) {
                        s_error = error; 
+                       RECORD_FAILURE(27440, s_error);
                }
                (void)close(fd);
                (void)dispatch_semaphore_signal(sema);
@@ -67,6 +73,7 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
 
                if (error != 0) {
                        s_error = error;
+                       RECORD_FAILURE(27441, s_error);
                }
        });
        dispatch_release(io); // it will close on its own
@@ -94,11 +101,28 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
        return buf;
 }
 
-char *SHA256_Path_XATTRs(char *path, char *buf)
+xattr_info *
+SHA256_Path_XATTRs(char *path, char *buf) {
+       xattr_info *ai = NULL;
+
+       if (mflag) {
+               ai = get_xdstream_privateid(path, buf);
+       } else {
+               ai = calculate_SHA256_XATTRs(path, buf);
+       }
+
+       return ai;
+}
+
+
+xattr_info *
+calculate_SHA256_XATTRs(char *path, char *buf)
 {
+       errno_t error = 0;
        char *xattrsSummary = NULL;
        int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
        ssize_t nameBufSize = listxattr(path, NULL, 0, options);
+       uint64_t xd_obj_id = 0;
        if (nameBufSize > 0) {
                char *nameBuf = malloc(nameBufSize);
                
@@ -133,6 +157,8 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
                char *digest;
                ssize_t result = 0;
                char *oldSummary = NULL;
+               //XXX Make xattr_info an array of structs if necessary
+               xattr_info *ai = (xattr_info *) malloc(sizeof(xattr_info));
                for (int i = 0; i < xattrIndex; i++) {
                        char *name = xattrs[i];
                        ssize_t xlen = getxattr(path, name, NULL, 0, 0, options);
@@ -142,8 +168,11 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
                        }
                        bzero(xattrBuf, xattrBufLen);
                        result = getxattr(path, name, xattrBuf, xattrBufLen, 0, options);
-                       if (result < 0)
-                               err(1, "SHA256_Path_XATTRs getxattr of \"%s\" at path \"%s\" failed with error", name, path );
+                       if (result < 0) {
+                               error = errno;
+                               RECORD_FAILURE(27442, error);
+                               errc(1, error, "SHA256_Path_XATTRs getxattr of \"%s\" at path \"%s\" failed with error", name, path);
+                       }
                        
                        digest = SHA256_Data(xattrBuf, xattrBufLen, buf);
                        if (!digest)
@@ -157,6 +186,27 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
                                asprintf(&xattrsSummary, "%s, %s:%s", oldSummary, name, digest);
                                free(oldSummary);
                        }
+#ifdef APFSIOC_XDSTREAM_OBJ_ID
+                       // System volume has stream based xattrs only in form of resource forks
+                       if (!strncmp(name, XATTR_RESOURCEFORK_NAME, XATTR_MAXNAMELEN)) {
+                               struct xdstream_obj_id x_obj;
+                               x_obj.xdi_name = name;
+                               x_obj.xdi_xdtream_obj_id = 0;
+
+                               result = fsctl(path, APFSIOC_XDSTREAM_OBJ_ID, &x_obj, 0);
+                               if (!result) {
+                                       xd_obj_id = x_obj.xdi_xdtream_obj_id;
+                               } else if (errno == ENOTTY) {
+                                       // Not an apfs filesystem, return zero.
+                                       xd_obj_id = 0;
+                               } else {
+                                       error = errno;
+                                       RECORD_FAILURE(27444, error);
+                                       errc(1, error, "%s - SHA256_Path_XATTRs APFSIOC_XDSTREAM_OBJ_ID failed with %d", path, error);
+                               }
+                       }
+#endif
+                       ai->xdstream_priv_id = xd_obj_id;
                }
                
                free(xattrBuf);
@@ -166,15 +216,82 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
                digest = SHA256_Data(xattrsSummary, strlen(xattrsSummary) * sizeof(char), buf);
                if (!digest)
                        err(1, "%s", xattrsSummary);
+
+               ai->digest = digest;
                
                free(xattrsSummary);
-               return digest;
+               return ai;
+       }
+       return NULL;
+}
+
+xattr_info *
+get_xdstream_privateid(char *path, char *buf) {
+       errno_t error = 0;
+       int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
+       ssize_t nameBufSize = listxattr(path, NULL, 0, options);
+       uint64_t xd_obj_id = 0;
+
+       if (nameBufSize > 0) {
+               //XXX Make xattr_info an array of structs if necessary
+               xattr_info *ai = (xattr_info *) malloc(sizeof(xattr_info));
+               char *nameBuf = malloc(nameBufSize);
+               int result = 0;
+
+               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;
+               }
+
+               for (int i = 0; i < xattrIndex; i++) {
+                       char *name = xattrs[i];
+                       // System volume has stream based xattrs only in form of resource forks
+                       if (!strncmp(name, XATTR_RESOURCEFORK_NAME, XATTR_MAXNAMELEN)) {
+                               struct xdstream_obj_id x_obj;
+                               x_obj.xdi_name = name;
+                               x_obj.xdi_xdtream_obj_id = 0;
+
+                               result = fsctl(path, APFSIOC_XDSTREAM_OBJ_ID, &x_obj, 0);
+                               if (!result && x_obj.xdi_xdtream_obj_id != 0) {
+                                       xd_obj_id = x_obj.xdi_xdtream_obj_id;
+                               } else if (errno == ENOTTY) {
+                                       // Not an apfs filesystem, return zero.
+                                       xd_obj_id = 0;
+                               } else {
+                                       error = errno;
+                                       RECORD_FAILURE(29983, error);
+                                       errc(1, error, "%s - SHA256_Path_XATTRs APFSIOC_XDSTREAM_OBJ_ID failed with %d", path, error);
+                               }
+                       }
+               }
+
+               ai->xdstream_priv_id = xd_obj_id;
+               // insert a dummy value as digest is not used in presence of mflag
+               ai->digest = "authapfs";
+
+               free(nameBuf);
+               free(xattrs);
+               return ai;
        }
-       return kNone;
+
+       return NULL;
 }
 
 char *SHA256_Path_ACL(char *path, char *buf)
 {
+       errno_t error           = 0;
        int result              = 0;
        char *data              = NULL;
        char *digest            = NULL;
@@ -195,8 +312,11 @@ char *SHA256_Path_ACL(char *path, char *buf)
        
        result = getattrlist(path, &list, &aclBuf, sizeof(aclBuf), FSOPT_NOFOLLOW);
        
-       if (result)
-               err(1, "SHA256_Path_ACL: getattrlist");
+       if (result) {
+               error = errno;
+               RECORD_FAILURE(27445, error);
+               errc(1, error, "SHA256_Path_ACL: getattrlist");
+       }
        
        // if the path does not have an acl, return none
        if ( ( ! ( aclBuf.returned_attrs.commonattr & ATTR_CMN_EXTENDED_SECURITY ) )
@@ -237,3 +357,22 @@ Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf) {
        return buf;
 }
 
+uint64_t
+get_sibling_id(const char *path)
+{
+       struct attrlist attr_list = {0};
+       struct attrbuf attr_buf = {0};
+       errno_t error = 0;
+
+       attr_list.bitmapcount = ATTR_BIT_MAP_COUNT;
+       attr_list.forkattr = ATTR_CMNEXT_LINKID;
+
+       error = getattrlist(path, &attr_list, &attr_buf, sizeof(attr_buf), FSOPT_ATTR_CMN_EXTENDED | FSOPT_NOFOLLOW);
+       if (error) {
+               error = errno;
+               RECORD_FAILURE(27447, error);
+               errc(1, error, "get_sibling_id: getattrlist failed for %s\n", path);
+       }
+
+       return attr_buf.sibling_id;
+}
index a894749a38ec90024346096d80e4f82eef7c4c68..c547035f59691ec93730ce2d19c82273e72b6631 100644 (file)
@@ -1,3 +1,7 @@
+
+#ifndef _COMMON_CRYPTO_H_
+#define _COMMON_CRYPTO_H_
+
 #include <CommonCrypto/CommonDigestSPI.h>
 
 #define kNone "none"
@@ -9,7 +13,24 @@ extern const int kSHA256NullTerminatedBuffLen;
 #define RIPEMD160_File(f, b) Digest_File(kCCDigestRMD160, f, b)
 #define SHA256_File(f, b)    Digest_File(kCCDigestSHA256, f, b)
 
+typedef struct {
+    char *digest;
+    uint64_t xdstream_priv_id;
+} xattr_info;
+
+struct attrbuf {
+       uint32_t info_length;
+       uint64_t sibling_id;
+} __attribute__((aligned, packed));
+
+typedef struct attrbuf attrbuf_t;
+
 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
+xattr_info *calculate_SHA256_XATTRs(char *path, char *buf);
+xattr_info *SHA256_Path_XATTRs(char *path, char *buf);
+xattr_info *get_xdstream_privateid(char *path, char *buf);
+char *SHA256_Path_ACL(char *path, char *buf);
+uint64_t get_sibling_id(const char *path);
+
+#endif /* _COMMON_CRYPTO_H_ */
index 7413d2fd9bc3b8ae1adccc372aadc8ea4ac64804..e585928d4521f282de03cb2f37e4ff91336f001e 100644 (file)
@@ -35,6 +35,7 @@ static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $");
 
+#include <CoreFoundation/CoreFoundation.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -63,6 +64,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobe
 #include <unistd.h>
 #include <vis.h>
 
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
@@ -77,9 +79,79 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobe
                tab = "\t"; \
        }
 
+extern CFMutableDictionaryRef dict;
+
+// max/min times apfs can store on disk
+#define APFS_MAX_TIME 0x7fffffffffffffffLL
+#define APFS_MIN_TIME (-0x7fffffffffffffffLL-1)
+
+static uint64_t
+timespec_to_apfs_timestamp(struct timespec *ts)
+{
+       int64_t total;
+       int64_t seconds;
+
+       // `tv_nsec' can be > one billion, so we split it into two components:
+       // seconds and actual nanoseconds
+       // this allows us to detect overflow on the *total* number of nanoseconds
+       // e.g. if (MAX_SECONDS+2, -2billion) is passed in, we return MAX_SECONDS
+       seconds = ((int64_t)ts->tv_nsec / (int64_t)NSEC_PER_SEC);
+
+       // compute total nanoseconds, checking for overflow:
+       // seconds = sec + (ns/10e9)
+       // total = seconds*10e9 + ns%10e9
+       if (__builtin_saddll_overflow(ts->tv_sec, seconds, &seconds) ||
+                       __builtin_smulll_overflow(seconds, NSEC_PER_SEC, &total) ||
+                       __builtin_saddll_overflow(((int64_t)ts->tv_nsec % (int64_t)NSEC_PER_SEC), total, &total)) {
+               // checking the sign of "seconds" tells us whether to cap the value at
+               // the max or min time
+               total = (ts->tv_sec > 0) ? APFS_MAX_TIME : APFS_MIN_TIME;
+       }
+
+       return (uint64_t)total;
+}
+
+static void
+set_key_value_pair(void *in_key, uint64_t *in_val, bool is_string)
+{
+       CFStringRef key;
+       CFNumberRef val;
+
+       if (is_string) {
+               key = CFStringCreateWithCString(NULL, (const char*)in_key, kCFStringEncodingUTF8);
+
+       } else {
+               key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%llu"), *(uint64_t*)in_key);
+       }
+
+       val = CFNumberCreate(NULL, kCFNumberSInt64Type, in_val);
+
+       // we always expect the key to be not present
+       if (key && val) {
+               CFDictionaryAddValue(dict, key, val);
+       } else {
+               if (key) {
+                       CFRelease(key);
+               }
+               if (val) {
+                       CFRelease(val);
+               }
+               RECORD_FAILURE(1, EINVAL);
+               errx(1, "set_key_value_pair: key/value is null");
+       }
+
+       if (key) {
+               CFRelease(key);
+       }
+       if (val) {
+               CFRelease(val);
+       }
+}
+
 int
 compare(char *name __unused, NODE *s, FTSENT *p)
 {
+       int error = 0;
        struct timeval tv[2];
        uint32_t val;
        int fd, label;
@@ -92,31 +164,44 @@ compare(char *name __unused, NODE *s, FTSENT *p)
        label = 0;
        switch(s->type) {
        case F_BLOCK:
-               if (!S_ISBLK(p->fts_statp->st_mode))
+               if (!S_ISBLK(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(2, EINVAL);
                        goto typeerr;
+               }
                break;
        case F_CHAR:
-               if (!S_ISCHR(p->fts_statp->st_mode))
+               if (!S_ISCHR(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(3, EINVAL);
                        goto typeerr;
+               }
                break;
        case F_DIR:
-               if (!S_ISDIR(p->fts_statp->st_mode))
+               if (!S_ISDIR(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(4, EINVAL);
                        goto typeerr;
+               }
                break;
        case F_FIFO:
-               if (!S_ISFIFO(p->fts_statp->st_mode))
+               if (!S_ISFIFO(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(5, EINVAL);
                        goto typeerr;
+               }
                break;
        case F_FILE:
-               if (!S_ISREG(p->fts_statp->st_mode))
+               if (!S_ISREG(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(6, EINVAL);
                        goto typeerr;
+               }
                break;
        case F_LINK:
-               if (!S_ISLNK(p->fts_statp->st_mode))
+               if (!S_ISLNK(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(7, EINVAL);
                        goto typeerr;
+               }
                break;
        case F_SOCK:
                if (!S_ISSOCK(p->fts_statp->st_mode)) {
+                       RECORD_FAILURE(8, EINVAL);
 typeerr:               LABEL;
                        (void)printf("\ttype expected %s found %s\n",
                            ftype(s->type), inotype(p->fts_statp->st_mode));
@@ -129,28 +214,36 @@ typeerr:          LABEL;
                LABEL;
                (void)printf("%suser expected %lu found %lu",
                    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
-               if (uflag)
-                       if (chown(p->fts_accpath, s->st_uid, -1))
+               if (uflag) {
+                       if (chown(p->fts_accpath, s->st_uid, -1)) {
+                               error = errno;
+                               RECORD_FAILURE(9, error);
                                (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
+                                   strerror(error));
+                       } else {
                                (void)printf(" modified\n");
-               else
+                       }
+               } else {
                        (void)printf("\n");
+               }
                tab = "\t";
        }
        if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
                LABEL;
                (void)printf("%sgid expected %lu found %lu",
                    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
-               if (uflag)
-                       if (chown(p->fts_accpath, -1, s->st_gid))
+               if (uflag) {
+                       if (chown(p->fts_accpath, -1, s->st_gid)) {
+                               error = errno;
+                               RECORD_FAILURE(10, error);
                                (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
+                                   strerror(error));
+                       } else {
                                (void)printf(" modified\n");
-               else
+                       }
+               } else {
                        (void)printf("\n");
+               }
                tab = "\t";
        }
        if (s->flags & F_MODE &&
@@ -159,14 +252,18 @@ typeerr:          LABEL;
                LABEL;
                (void)printf("%spermissions expected %#o found %#o",
                    tab, s->st_mode, p->fts_statp->st_mode & MBITS);
-               if (uflag)
-                       if (chmod(p->fts_accpath, s->st_mode))
+               if (uflag) {
+                       if (chmod(p->fts_accpath, s->st_mode)) {
+                               error = errno;
+                               RECORD_FAILURE(11, error);
                                (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
+                                   strerror(error));
+                       } else {
                                (void)printf(" modified\n");
-               else
+                       }
+               } else {
                        (void)printf("\n");
+               }
                tab = "\t";
        }
        if (s->flags & F_NLINK && s->type != F_DIR &&
@@ -186,35 +283,51 @@ typeerr:          LABEL;
        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.%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;
-                       tv[1] = tv[0];
-                       if (utimes(p->fts_accpath, tv))
-                               (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
-                               (void)printf(" modified\n");
-               } else
-                       (void)printf("\n");
-               tab = "\t";
+               if (!mflag) {
+                       LABEL;
+                       (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;
+                               tv[1] = tv[0];
+                               if (utimes(p->fts_accpath, tv)) {
+                                       error = errno;
+                                       RECORD_FAILURE(12, error);
+                                       (void)printf(" not modified: %s\n",
+                                                    strerror(error));
+                               } else {
+                                       (void)printf(" modified\n");
+                               }
+                       } else {
+                               (void)printf("\n");
+                       }
+                       tab = "\t";
+               }
+               if (!insert_mod && mflag) {
+                       uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_mtimespec);
+                       char *mod_string = "MODIFICATION";
+                       set_key_value_pair(mod_string, &s_mod_time, true);
+                       insert_mod = 1;
+               }
        }
        if (s->flags & F_CKSUM) {
                if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(13, error);
                        (void)printf("%scksum: %s: %s\n",
-                           tab, p->fts_accpath, strerror(errno));
+                           tab, p->fts_accpath, strerror(error));
                        tab = "\t";
                } else if (crc(fd, &val, &len)) {
                        (void)close(fd);
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(14, error);
                        (void)printf("%scksum: %s: %s\n",
-                           tab, p->fts_accpath, strerror(errno));
+                           tab, p->fts_accpath, strerror(error));
                        tab = "\t";
                } else {
                        (void)close(fd);
@@ -245,26 +358,37 @@ typeerr:          LABEL;
                        (void)printf(" found \"%s\"", fflags);
                        free(fflags);
                        
-                       if (uflag)
-                               if (chflags(p->fts_accpath, (u_int)s->st_flags))
+                       if (uflag) {
+                               if (chflags(p->fts_accpath, (u_int)s->st_flags)) {
+                                       error = errno;
+                                       RECORD_FAILURE(15, error);
                                        (void)printf(" not modified: %s\n",
-                                                    strerror(errno));
-                               else
+                                                    strerror(error));
+                               } else {
                                        (void)printf(" modified\n");
-                               else
-                                       (void)printf("\n");
+                               }
+                       } else {
+                               (void)printf("\n");
+                       }
                        tab = "\t";
                }
        }
 #ifdef ENABLE_MD5
        if (s->flags & F_MD5) {
                char *new_digest, buf[33];
-
+#ifdef __clang__
+/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                new_digest = MD5File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(16, error);
                        printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
-                              strerror(errno));
+                              strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->md5digest)) {
                        LABEL;
@@ -277,12 +401,19 @@ typeerr:          LABEL;
 #ifdef ENABLE_SHA1
        if (s->flags & F_SHA1) {
                char *new_digest, buf[41];
-
+#ifdef __clang__
+/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                new_digest = SHA1_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(17, error);
                        printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
-                              strerror(errno));
+                              strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->sha1digest)) {
                        LABEL;
@@ -295,12 +426,19 @@ typeerr:          LABEL;
 #ifdef ENABLE_RMD160
        if (s->flags & F_RMD160) {
                char *new_digest, buf[41];
-
+#ifdef __clang__
+/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                new_digest = RIPEMD160_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(18, error);
                        printf("%sRIPEMD160: %s: %s\n", tab,
-                              p->fts_accpath, strerror(errno));
+                              p->fts_accpath, strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->rmd160digest)) {
                        LABEL;
@@ -317,8 +455,10 @@ typeerr:           LABEL;
                new_digest = SHA256_File(p->fts_accpath, buf);
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(19, error);
                        printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
-                              strerror(errno));
+                              strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->sha256digest)) {
                        LABEL;
@@ -338,32 +478,57 @@ typeerr:          LABEL;
        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 (!mflag) {
+                           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 (!insert_birth && mflag) {
+                           uint64_t s_create_time = timespec_to_apfs_timestamp(&s->st_birthtimespec);
+                           char *birth_string = "BIRTH";
+                           set_key_value_pair(birth_string, &s_create_time, true);
+                           insert_birth = 1;
+                   }
            }
        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 (!mflag) {
+                           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 (!insert_access && mflag) {
+                           uint64_t s_access_time = timespec_to_apfs_timestamp(&s->st_atimespec);
+                           char *access_string = "ACCESS";
+                           set_key_value_pair(access_string, &s_access_time, true);
+                           insert_access = 1;
+
+                   }
            }
        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 (!mflag) {
+                           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 (!insert_change && mflag) {
+                           uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_ctimespec);
+                           char *change_string = "CHANGE";
+                           set_key_value_pair(change_string, &s_mod_time, true);
+                           insert_change = 1;
+                   }
            }
        if (s->flags & F_PTIME) {
                int supported;
@@ -371,38 +536,59 @@ typeerr:          LABEL;
                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, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
                        tab = "\t";
+               } else if (supported && ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) ||
+                          (s->st_ptimespec.tv_nsec != ptimespec.tv_nsec))) {
+                       if (!mflag) {
+                               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";
+                       } else if (!insert_parent && mflag) {
+                               uint64_t s_added_time = timespec_to_apfs_timestamp(&s->st_ptimespec);
+                               char *added_string = "DATEADDED";
+                               set_key_value_pair(added_string, &s_added_time, true);
+                               insert_parent = 1;
+                       }
                }
        }
        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";
+               char buf[kSHA256NullTerminatedBuffLen];
+               xattr_info *ai;
+               ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
+               if (!mflag) {
+                       if (ai && !ai->digest) {
+                               LABEL;
+                               printf("%sxattrsdigest missing, expected: %s\n", tab, s->xattrsdigest);
+                               tab = "\t";
+                       } else if (ai && strcmp(ai->digest, s->xattrsdigest)) {
+                               LABEL;
+                               printf("%sxattrsdigest expected %s found %s\n",
+                                      tab, s->xattrsdigest, ai->digest);
+                               tab = "\t";
+                       }
+               }
+               if (mflag) {
+                       if (ai && ai->xdstream_priv_id != s->xdstream_priv_id) {
+                               set_key_value_pair((void*)&ai->xdstream_priv_id, &s->xdstream_priv_id, false);
+                       }
                }
+               free(ai);
        }
        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 (!mflag) {
+                       LABEL;
+                       (void)printf("%sinode expected %llu found %llu\n",
+                                    tab, s->st_ino, p->fts_statp->st_ino);
+                       tab = "\t";
+               }
+               if (mflag) {
+                       set_key_value_pair((void*)&p->fts_statp->st_ino, &s->st_ino, false);
+               }
        }
        if (s->flags & F_ACL) {
                char *new_digest, buf[kSHA256NullTerminatedBuffLen];
@@ -418,6 +604,21 @@ typeerr:           LABEL;
                        tab = "\t";
                }
        }
+       if (s->flags & F_SIBLINGID) {
+               uint64_t new_sibling_id = get_sibling_id(p->fts_accpath);
+               new_sibling_id = (new_sibling_id != p->fts_statp->st_ino) ? new_sibling_id : 0;
+               if (new_sibling_id != s->sibling_id) {
+                       if (!mflag) {
+                               LABEL;
+                               (void)printf("%ssibling id expected %llu found %llu\n",
+                                            tab, s->sibling_id, new_sibling_id);
+                               tab = "\t";
+                       }
+                       if (mflag) {
+                               set_key_value_pair((void*)&new_sibling_id, &s->sibling_id, false);
+                       }
+               }
+       }
        
        return (label);
 }
@@ -473,11 +674,15 @@ ftype(u_int type)
 char *
 rlink(char *name)
 {
+       int error = 0;
        static char lbuf[MAXPATHLEN];
        ssize_t len;
 
-       if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
-               err(1, "line %d: %s", lineno, name);
+       if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) {
+               error = errno;
+               RECORD_FAILURE(20, error);
+               errc(1, error, "line %d: %s", lineno, name);
+       }
        lbuf[len] = '\0';
        return (lbuf);
 }
index 66992a73f2147063f6739834fdf30bdb91b0e40d..9300eaaf1a0e34890c8bed20ab68d786651861ea 100644 (file)
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/create.c,v 1.37 2005/03/29 11:44:17 tobez
 #include <time.h>
 #include <unistd.h>
 #include <vis.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
@@ -79,15 +80,17 @@ static mode_t mode;
 static u_long flags = 0xffffffff;
 static char *xattrs = kNone;
 static char *acl = kNone;
+static u_quad_t xdstream_id;
 
 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 *, char **, char **);
+static int     statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **, u_quad_t *);
 static void    statf(int, FTSENT *);
 
 void
 cwalk(void)
 {
+       int error = 0;
        FTS *t;
        FTSENT *p;
        time_t cl;
@@ -109,8 +112,11 @@ cwalk(void)
 
        argv[0] = dot;
        argv[1] = NULL;
-       if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
-               err(1, "fts_open()");
+       if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) {
+               error = errno;
+               RECORD_FAILURE(76, error);
+               errc(1, error, "fts_open()");
+       }
        while ((p = fts_read(t))) {
                if (iflag)
                        indent = p->fts_level * 4;
@@ -127,7 +133,7 @@ cwalk(void)
                                (void)printf("# %s\n", path);
                                free(path);
                        }
-                       statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl);
+                       statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl, &xdstream_id);
                        statf(indent, p);
                        break;
                case FTS_DP:
@@ -153,13 +159,16 @@ cwalk(void)
                }
        }
        (void)fts_close(t);
-       if (sflag && keys & F_CKSUM)
+       if (sflag && keys & F_CKSUM) {
+               RECORD_FAILURE(77, WARN_CHECKSUM);
                warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+       }
 }
 
 static void
 statf(int indent, FTSENT *p)
 {
+       int error = 0;
        struct group *gr;
        struct passwd *pw;
        uint32_t val;
@@ -169,8 +178,10 @@ statf(int indent, FTSENT *p)
        char *escaped_name;
 
        escaped_name = calloc(1, p->fts_namelen * 4  +  1);
-       if (escaped_name == NULL)
+       if (escaped_name == NULL) {
+               RECORD_FAILURE(78, ENOMEM);
                errx(1, "statf(): calloc() failed");
+       }
        strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB);
 
        if (iflag || S_ISDIR(p->fts_statp->st_mode))
@@ -190,15 +201,18 @@ statf(int indent, FTSENT *p)
        if (p->fts_statp->st_uid != uid) {
                if (keys & F_UNAME) {
                        pw = getpwuid(p->fts_statp->st_uid);
-                       if (pw != NULL)
+                       if (pw != NULL) {
                                output(indent, &offset, "uname=%s", pw->pw_name);
-                       else if (wflag)
+                       } else if (wflag) {
+                               RECORD_FAILURE(27448, WARN_UNAME);
                                warnx("Could not get uname for uid=%u",
                                    p->fts_statp->st_uid);
-                       else
+                       } else {
+                               RECORD_FAILURE(79, EINVAL);
                                errx(1,
                                    "Could not get uname for uid=%u",
                                    p->fts_statp->st_uid);
+                       }
                }
                if (keys & F_UID)
                        output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
@@ -206,15 +220,18 @@ statf(int indent, FTSENT *p)
        if (p->fts_statp->st_gid != gid) {
                if (keys & F_GNAME) {
                        gr = getgrgid(p->fts_statp->st_gid);
-                       if (gr != NULL)
+                       if (gr != NULL) {
                                output(indent, &offset, "gname=%s", gr->gr_name);
-                       else if (wflag)
+                       } else if (wflag) {
+                               RECORD_FAILURE(27449, WARN_UNAME);
                                warnx("Could not get gname for gid=%u",
                                    p->fts_statp->st_gid);
-                       else
+                       } else {
+                               RECORD_FAILURE(80, EINVAL);
                                errx(1,
                                    "Could not get gname for gid=%u",
                                    p->fts_statp->st_gid);
+                       }
                }
                if (keys & F_GID)
                        output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
@@ -226,44 +243,79 @@ statf(int indent, FTSENT *p)
        if (keys & F_SIZE)
                output(indent, &offset, "size=%jd",
                    (intmax_t)p->fts_statp->st_size);
-       if (keys & F_TIME)
-               output(indent, &offset, "time=%ld.%09ld",
-                   (long)p->fts_statp->st_mtimespec.tv_sec,
-                   p->fts_statp->st_mtimespec.tv_nsec);
+       if (keys & F_TIME) {
+               if (tflag && !insert_mod) {
+                       output(indent, &offset, "time=%ld.%09ld",
+                              (long)ts.tv_sec, ts.tv_nsec);
+                       insert_mod = 1;
+               }
+               if (!tflag) {
+                       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)) {
                if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
-                   crc(fd, &val, &len))
-                       err(1, "%s", p->fts_accpath);
+                   crc(fd, &val, &len)) {
+                       error = errno;
+                       RECORD_FAILURE(27450, error);
+                       errc(1, error, "%s", p->fts_accpath);
+               }
                (void)close(fd);
                output(indent, &offset, "cksum=%lu", (unsigned long)val);
        }
 #ifdef ENABLE_MD5
        if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
                char *digest, buf[33];
-
+#ifdef __clang__
+/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                digest = MD5File(p->fts_accpath, buf);
-               if (!digest)
-                       err(1, "%s", p->fts_accpath);
+#pragma clang diagnostic pop
+#endif
+               if (!digest) {
+                       error = errno;
+                       RECORD_FAILURE(81, error);
+                       errc(1, error, "%s", p->fts_accpath);
+               }
                output(indent, &offset, "md5digest=%s", digest);
        }
 #endif /* ENABLE_MD5 */
 #ifdef ENABLE_SHA1
        if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
                char *digest, buf[41];
-
+#ifdef __clang__
+/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                digest = SHA1_File(p->fts_accpath, buf);
-               if (!digest)
-                       err(1, "%s", p->fts_accpath);
+#pragma clang diagnostic pop
+#endif
+               if (!digest) {
+                       error = errno;
+                       RECORD_FAILURE(82, error);
+                       errc(1, error, "%s", p->fts_accpath);
+               }
                output(indent, &offset, "sha1digest=%s", digest);
        }
 #endif /* ENABLE_SHA1 */
 #ifdef ENABLE_RMD160
        if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
                char *digest, buf[41];
-
+#ifdef __clang__
+/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                digest = RIPEMD160_File(p->fts_accpath, buf);
-               if (!digest)
-                       err(1, "%s", p->fts_accpath);
+#pragma clang diagnostic pop
+#endif
+               if (!digest) {
+                       error = errno;
+                       RECORD_FAILURE(83, error);
+                       errc(1, error, "%s", p->fts_accpath);
+               }
                output(indent, &offset, "ripemd160digest=%s", digest);
        }
 #endif /* ENABLE_RMD160 */
@@ -272,8 +324,11 @@ statf(int indent, FTSENT *p)
                char *digest, buf[kSHA256NullTerminatedBuffLen];
 
                digest = SHA256_File(p->fts_accpath, buf);
-               if (!digest)
-                       err(1, "%s", p->fts_accpath);
+               if (!digest) {
+                       error = errno;
+                       RECORD_FAILURE(84, error);
+                       errc(1, error, "%s", p->fts_accpath);
+               }
                output(indent, &offset, "sha256digest=%s", digest);
        }
 #endif /* ENABLE_SHA256 */
@@ -290,38 +345,69 @@ statf(int indent, FTSENT *p)
                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);
+               if (tflag && !insert_birth) {
+                       output(indent, &offset, "btime=%ld.%09ld",
+                              ts.tv_sec, ts.tv_nsec);
+                       insert_birth = 1;
+               }
+               if (!tflag) {
+                       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 (tflag && !insert_access) {
+                       output(indent, &offset, "atime=%ld.%09ld",
+                              ts.tv_sec, ts.tv_nsec);
+                       insert_access = 1;
+               }
+               if (!tflag) {
+                       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);
+               if (tflag && !insert_change) {
+                       output(indent, &offset, "ctime=%ld.%09ld",
+                              ts.tv_sec, ts.tv_nsec);
+                       insert_change = 1;
+               }
+               if (!tflag) {
+                       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) {
+               if (tflag && !insert_parent) {
+                       output(indent, &offset, "ptime=%ld.%09ld",
+                              ts.tv_sec, ts.tv_nsec);
+                       insert_parent = 1;
+               }
+               if (!tflag && supported) {
                        output(indent, &offset, "ptime=%ld.%09ld",
                               ptimespec.tv_sec,
                               ptimespec.tv_nsec);
                }
        }
        if (keys & F_XATTRS) {
-               char *digest, buf[kSHA256NullTerminatedBuffLen];
+               char buf[kSHA256NullTerminatedBuffLen];
+               xattr_info *ai;
                
-               digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
-               if (digest && (strcmp(digest, xattrs) != 0)) {
-                       output(indent, &offset, "xattrsdigest=%s", digest);
+               ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
+               if (ai && ai->digest) {
+                       if ((strcmp(ai->digest, xattrs) != 0) || (ai->xdstream_priv_id != xdstream_id)) {
+                               output(indent, &offset, "xattrsdigest=%s.%llu", ai->digest, ai->xdstream_priv_id);
+                       }
+                       free(ai);
+                       ai = NULL;
                }
        }
        if (keys & F_INODE) {
@@ -335,6 +421,11 @@ statf(int indent, FTSENT *p)
                        output(indent, &offset, "acldigest=%s", digest);
                }
        }
+       if (keys & F_SIBLINGID) {
+               uint64_t sibling_id = get_sibling_id(p->fts_accpath);
+               sibling_id = (sibling_id != p->fts_statp->st_ino) ? sibling_id : 0;
+               output(indent, &offset, "siblingid=%llu", sibling_id);
+       }
        
        (void)putchar('\n');
 }
@@ -346,8 +437,9 @@ 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, char **pxattrs, char **pacl)
+statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl, u_quad_t *xdstream_id)
 {
+       int error = 0;
        FTSENT *p;
        gid_t sgid;
        uid_t suid;
@@ -361,14 +453,18 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
        u_long saveflags = *pflags;
        char *savexattrs = *pxattrs;
        char *saveacl = *pacl;
+       u_quad_t savexdstream_id = *xdstream_id;
        u_short maxgid, maxuid, maxmode, maxflags;
        u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
        char *fflags;
        static int first = 1;
 
        if ((p = fts_children(t, 0)) == NULL) {
-               if (errno)
-                       err(1, "%s", RP(parent));
+               error = errno;
+               if (error) {
+                       RECORD_FAILURE(85, error);
+                       errc(1, error, "%s", RP(parent));
+               }
                return (1);
        }
 
@@ -434,23 +530,29 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
                        (void)printf("/set type=file");
                if (keys & F_UNAME) {
                        pw = getpwuid(saveuid);
-                       if (pw != NULL)
+                       if (pw != NULL) {
                                (void)printf(" uname=%s", pw->pw_name);
-                       else if (wflag)
+                       } else if (wflag) {
+                               RECORD_FAILURE(27451, WARN_UNAME);
                                warnx( "Could not get uname for uid=%u", saveuid);
-                       else
+                       } else {
+                               RECORD_FAILURE(86, EINVAL);
                                errx(1, "Could not get uname for uid=%u", saveuid);
+                       }
                }
                if (keys & F_UID)
                        (void)printf(" uid=%lu", (u_long)saveuid);
                if (keys & F_GNAME) {
                        gr = getgrgid(savegid);
-                       if (gr != NULL)
+                       if (gr != NULL) {
                                (void)printf(" gname=%s", gr->gr_name);
-                       else if (wflag)
+                       } else if (wflag) {
+                               RECORD_FAILURE(27452, WARN_UNAME);
                                warnx("Could not get gname for gid=%u", savegid);
-                       else
+                       } else {
+                               RECORD_FAILURE(87, EINVAL);
                                errx(1, "Could not get gname for gid=%u", savegid);
+                       }
                }
                if (keys & F_GID)
                        (void)printf(" gid=%lu", (u_long)savegid);
@@ -464,7 +566,7 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
                        free(fflags);
                }
                if (keys & F_XATTRS)
-                       (void)printf(" xattrsdigest=%s", savexattrs);
+                       (void)printf(" xattrsdigest=%s.%llu", savexattrs, savexdstream_id);
                if (keys & F_ACL)
                        (void)printf(" acldigest=%s", saveacl);
                (void)printf("\n");
@@ -474,6 +576,7 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
                *pflags = saveflags;
                *pxattrs = savexattrs;
                *pacl = saveacl;
+               *xdstream_id = savexdstream_id;
        }
        return (0);
 }
index 89047711fc109132f9502975c6600e0e6262c21b..cb432bf9986e8dffeb77df79aed11429b4364a89 100644 (file)
 __FBSDID("$FreeBSD: src/usr.sbin/mtree/excludes.c,v 1.8 2003/10/21 08:27:05 phk Exp $");
 
 #include <sys/types.h>
-#include <sys/time.h>          /* XXX for mtree.h */
 #include <sys/queue.h>
 
 #include <err.h>
+#include <errno.h>
 #include <fnmatch.h>
 #include <fts.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 
-#include "mtree.h"             /* XXX for extern.h */
+#include "metrics.h"
 #include "extern.h"
 
 /*
@@ -81,8 +81,10 @@ read_excludes_file(const char *name)
 
                str = malloc(len + 1);
                e = malloc(sizeof *e);
-               if (str == 0 || e == 0)
+               if (str == 0 || e == 0) {
+                       RECORD_FAILURE(59, ENOMEM);
                        errx(1, "memory allocation error");
+               }
                e->glob = str;
                memcpy(str, line, len);
                str[len] = '\0';
index ff40b840362971d0429789d459026afac474dbeb..47533c2fc09792002cc80867433a3fc00c0104ec 100644 (file)
  *     @(#)extern.h    8.1 (Berkeley) 6/6/93
  * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.13 2004/01/11 19:38:48 phk Exp $
  */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+#include "mtree.h"
+
 extern uint32_t crc_total;
 
 #ifdef _FTS_H_
@@ -55,7 +61,11 @@ 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;
+extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag, mflag, tflag;
+extern int insert_mod, insert_birth, insert_access, insert_change, insert_parent;
+extern struct timespec ts;
 #ifdef MAXPATHLEN
 extern char fullpath[MAXPATHLEN];
 #endif
+
+#endif /* _EXTERN_H_ */
diff --git a/mtree/fix_failure_locations.py b/mtree/fix_failure_locations.py
new file mode 100755 (executable)
index 0000000..a49906e
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+
+#
+# This script is used to automatically fix up the location numbers in
+# calls to RECORD_FAILURE().  When adding a new call to RECORD_FAILURE,
+# write it like:
+#      RECORD_FAILURE(0, ...);
+# Don't put any white space between the open parenthesis, zero and comma.
+# Once you have added the new calls to RECORD_FAILURE, then run this script,
+# passing it the path to the directory, like this:
+#      python3 mtree/fix_failure_locations.py mtree/
+#
+# This script will edit the files, changing the "0" to the next available
+# location number.  It will also detect and complain if you have duplicate
+# location numbers.
+#
+# DO NOT reuse location numbers!  It is best if locations are consistent across
+# all versions that have that RECORD_FAILURE call.
+#
+
+import sys
+import os
+import re
+from collections import defaultdict
+from datetime import datetime,timezone
+
+class LocationUpdater(object):
+    epoch = datetime(2020, 6, 17, 23, 22, 46, 562458, tzinfo=timezone.utc)
+    location_base = int((datetime.now(timezone.utc) - epoch).total_seconds() / 60)
+    # Match the number in "RECORD_FAILURE(<number>,"
+    fail_re = (re.compile('(?<=\\bRECORD_FAILURE\\()\\d+(?=,)'),re.compile('(?<=\\bRECORD_FAILURE_MSG\\()\\d+(?=,)'))
+    
+    def __init__(self, path):
+        self.location = self.location_base
+        self.path = path
+        # Counters for how often each location number was found
+        self.counts = defaultdict(int)
+        self.locations_changed = 0
+    
+    # Replace the "0" in "RECORD_FAILURE(0," with next location number, in *.c
+    def fixLocations(self):
+        def replace_loc(match):
+            location = int(match.group(0))
+            if location == 0:
+                # Replace location 0 with the next available location
+                self.location += 1
+                self.locations_changed += 1
+                location = self.location
+            # Count the number of times this location number was used
+            self.counts[location] += 1
+            # Return the (possibly updated) location number
+            return str(location)
+        rootpath = self.path
+        for dirpath, dirnames, filenames in os.walk(rootpath):
+            for filename in filenames:
+                if filename.endswith(".c") or filename.endswith(".cpp"):
+                    path = os.path.join(dirpath, filename)
+                    content = open(path, "r").read()
+                    for fail_re in self.fail_re:
+                        if fail_re.search(content):
+                            locations_changed_before = self.locations_changed
+                            content = fail_re.sub(replace_loc, content)
+                            if self.locations_changed != locations_changed_before:
+                                # We updated a location number, so write the changed file
+                                print("Updating file {}".format(path))
+                                open(path,"w").write(content)
+    
+    def duplicates(self):
+        # Return the list of keys whose count is greater than 1
+        return [k for (k,v) in iter(self.counts.items()) if v > 1]
+
+updater = LocationUpdater(sys.argv[1])
+updater.fixLocations()
+dups = updater.duplicates()
+if len(dups):
+    print("WARNING!  Duplicate location numbers: {}".format(dups))
+    sys.exit(1)
diff --git a/mtree/metrics.c b/mtree/metrics.c
new file mode 100644 (file)
index 0000000..01a9fe2
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+* Copyright (c) 2020 Apple Inc. All rights reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "metrics.h"
+
+#define MAX_WARNINGS_LOGGED 5
+#define MAX_ERRORS_LOGGED 5
+#define WARN_FIRST -1
+
+#ifndef ROUNDUP
+#define ROUNDUP(COUNT, MULTIPLE) ((((COUNT) + (MULTIPLE) - 1) / (MULTIPLE)) * (MULTIPLE))
+#endif
+
+typedef struct failure_info {
+       int location;
+       int code;
+} failure_info_t;
+
+typedef struct metrics {
+       FILE *file;
+       time_t start_time;
+       int warning_count;
+       failure_info_t warnings[MAX_WARNINGS_LOGGED];
+       int error_count;
+       failure_info_t errors[MAX_ERRORS_LOGGED];
+       int last_error_location;
+       char *path;
+       int result;
+} metrics_t;
+metrics_t metrics = {};
+
+void
+set_metrics_file(FILE *file)
+{
+       metrics.file = file;
+}
+
+void
+set_metric_start_time(time_t time)
+{
+       metrics.start_time = time;
+}
+
+void
+set_metric_path(char *path)
+{
+       metrics.path = strdup(path);
+}
+
+void
+mtree_record_failure(int location, int code)
+{
+       if (code <= WARN_FIRST) {
+               if (metrics.warning_count < MAX_WARNINGS_LOGGED) {
+                       metrics.warning_count++;
+               } else {
+                       // Shift up the warnings to make space for the latest one.
+                       for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
+                               metrics.warnings[index] = metrics.warnings[index + 1];
+                       }
+               }
+               metrics.warnings[metrics.warning_count - 1].location = location;
+               metrics.warnings[metrics.warning_count - 1].code = code;
+       } else {
+               int error_index = -1;
+               if (metrics.error_count <= MAX_ERRORS_LOGGED) {
+                       if (metrics.error_count > 0) {
+                               // Log all but the last error which occured in the location and
+                               // code arrays. The last (location, error) is logged in
+                               // (metrics.last_error_location, metrics.error)
+                               error_index = metrics.error_count - 1;
+                       }
+                       metrics.error_count++;
+               } else {
+                       // Shift up the errors to make space for the latest one.
+                       for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
+                               metrics.errors[index] = metrics.errors[index + 1];
+                       }
+                       error_index = MAX_ERRORS_LOGGED - 1;
+               }
+               if (error_index >= 0) {
+                       metrics.errors[error_index].location = metrics.last_error_location;
+                       metrics.errors[error_index].code = metrics.result;
+               }
+               metrics.last_error_location = location;
+               metrics.result = code;
+       }
+}
+/*
+ * Note on format of metric string
+ * 1) dev points to the path
+ * 2) result is the overall result code from mtree
+ * 3) warnings and errors (upto 5 each) are printed in the format :
+ *     w:(location1:code1),(location2:code2).... and
+ *     e:(location1:code1),(location2:code2).... respectively.
+ * 4) fl is the last failure location of the run which is 0 if there is no failure
+ * 5) time is the total time taken for the run
+ */
+void
+print_metrics_to_file(void)
+{
+       if (metrics.file == NULL) {
+               return;
+       }
+
+       fprintf(metrics.file, "dev=%s result=%d ",
+               metrics.path ? metrics.path : "", metrics.result);
+       if (metrics.warning_count) {
+               fprintf(metrics.file, "w:");
+               for (int index = 0; index < metrics.warning_count; index++) {
+                       fprintf(metrics.file, "(%d:%d)",
+                               metrics.warnings[index].location, metrics.warnings[index].code);
+               }
+               fprintf(metrics.file, " ");
+       }
+       if (metrics.error_count > 1) {
+               fprintf(metrics.file, "e:");
+               for (int index = 0; index < metrics.error_count - 1; index++) {
+                       fprintf(metrics.file, "(%d:%d)",
+                               metrics.errors[index].location, metrics.errors[index].code);
+               }
+               fprintf(metrics.file, " ");
+       }
+       fprintf(metrics.file, "fl=%d time=%ld\n",
+               metrics.last_error_location, ROUNDUP((time(NULL) - metrics.start_time), 60) / 60);
+
+       fclose(metrics.file);
+       if (metrics.path) {
+               free(metrics.path);
+               metrics.path = NULL;
+       }
+}
diff --git a/mtree/metrics.h b/mtree/metrics.h
new file mode 100644 (file)
index 0000000..35dca43
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2020 Apple Inc. All rights reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#ifndef _METRICS_H_
+#define _METRICS_H_
+
+#include <sys/time.h>
+#include <stdio.h>
+
+// mtree error logging
+enum mtree_result {
+       SUCCESS = 0,
+       WARN_TIME = -1,
+       WARN_USAGE = -2,
+       WARN_CHECKSUM = -3,
+       WARN_MISMATCH = -4,
+       WARN_UNAME = -5,
+       /* Could also be a POSIX errno value */
+};
+
+void set_metrics_file(FILE *file);
+void set_metric_start_time(time_t time);
+void set_metric_path(char *path);
+#define RECORD_FAILURE(location, error) mtree_record_failure(location, error)
+void mtree_record_failure(int location, int code);
+void print_metrics_to_file(void);
+
+#endif /* _METRICS_H_ */
index 48518688000ceb185e22362ebfa44b8e873c523a..66e566ed95b22b9c44eadf4802b6de9e82d23666 100644 (file)
@@ -33,6 +33,7 @@ static char sccsid[] = "@(#)misc.c    8.1 (Berkeley) 6/6/93";
 #endif /*not lint */
 #endif
 #include <sys/cdefs.h>
+#include <errno.h>
 __FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez Exp $");
 
 #include <sys/types.h>
@@ -42,6 +43,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez E
 #include <stdint.h>
 #include <stdio.h>
 #include <unistd.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 #import <sys/attr.h>
@@ -84,6 +86,7 @@ static KEY keylist[] = {
 #ifdef ENABLE_SHA256
        {"sha256digest",        F_SHA256,       NEEDVALUE},
 #endif
+       {"siblingid",           F_SIBLINGID,    NEEDVALUE},
        {"size",                F_SIZE,         NEEDVALUE},
        {"time",                F_TIME,         NEEDVALUE},
        {"type",                F_TYPE,         NEEDVALUE},
@@ -102,8 +105,10 @@ parsekey(char *name, int *needvaluep)
        tmp.name = name;
        k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
            sizeof(KEY), keycompare);
-       if (k == NULL)
+       if (k == NULL) {
+               RECORD_FAILURE(107, EINVAL);
                errx(1, "line %d: unknown keyword %s", lineno, name);
+       }
 
        if (needvaluep)
                *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
@@ -119,6 +124,7 @@ keycompare(const void *a, const void *b)
 char *
 flags_to_string(u_long fflags)
 {
+       int error = 0;
        char *string;
 
        string = fflagstostr(fflags);
@@ -126,8 +132,11 @@ flags_to_string(u_long fflags)
                free(string);
                string = strdup("none");
        }
-       if (string == NULL)
-               err(1, NULL);
+       if (string == NULL) {
+               error = errno;
+               RECORD_FAILURE(108, error);
+               errc(1, error, NULL);
+       }
 
        return string;
 }
@@ -137,8 +146,10 @@ char *
 escape_path(char *string)
 {
        char *escapedPath = calloc(1, strlen(string) * 4  +  1);
-       if (escapedPath == NULL)
+       if (escapedPath == NULL) {
+               RECORD_FAILURE(109, ENOMEM);
                errx(1, "escape_path(): calloc() failed");
+       }
        strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
        
        return escapedPath;
@@ -154,6 +165,7 @@ struct ptimebuf {
 struct timespec
 ptime(char *path, int *supported) {
        
+       int error = 0;
        int ret = 0;
        struct ptimebuf buf;
        struct attrlist list = {
@@ -162,7 +174,9 @@ ptime(char *path, int *supported) {
        };
        ret = getattrlist(path, &list, &buf, sizeof(buf), FSOPT_NOFOLLOW);
        if (ret) {
-               err(1, "ptime: getattrlist");
+               error = errno;
+               RECORD_FAILURE(110, error);
+               errc(1, error, "ptime: getattrlist");
        }
        
        *supported = 0;
index 22bb6f00303605e05d8e150478e69fada61b3ffa..edf0cce5fdcc3dd3319db4f5498b8b3fdafc8c12 100644 (file)
@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)mtree.c   8.1 (Berkeley) 6/6/93";
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp $");
 
+#include <CoreFoundation/CoreFoundation.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <err.h>
@@ -49,31 +50,58 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp
 #include <stdio.h>
 #include <stdint.h>
 #include <unistd.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
+#define SECONDS_IN_A_DAY (60 * 60 * 24)
+
 int ftsoptions = FTS_PHYSICAL;
-int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag;
+int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag, mflag, tflag;
+int insert_mod, insert_birth, insert_access, insert_change, insert_parent;
+struct timespec ts;
 u_int keys;
 char fullpath[MAXPATHLEN];
+CFMutableDictionaryRef dict;
+char *filepath;
 
 static void usage(void);
+static bool write_plist_to_file(void);
+
+static void
+do_cleanup(void) {
+
+       if (mflag) {
+               if (dict)
+                       CFRelease(dict);
+               if (filepath)
+                       free(filepath);
+       }
+}
 
 int
 main(int argc, char *argv[])
 {
+       int error = 0;
        int ch;
        char *dir, *p;
        int status;
        FILE *spec1, *spec2;
+       char *timestamp = NULL;
+       char *timeformat = "%FT%T";
+       FILE *file = NULL;
 
        dir = NULL;
        keys = KEYDEFAULT;
        init_excludes();
        spec1 = stdin;
        spec2 = NULL;
+       set_metric_start_time(time(NULL));
 
-       while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:")) != -1)
+       atexit(do_cleanup);
+       atexit(print_metrics_to_file);
+
+       while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:m:F:t:E:")) != -1)
                switch((char)ch) {
                case 'c':
                        cflag = 1;
@@ -87,14 +115,22 @@ main(int argc, char *argv[])
                case 'f':
                        if (spec1 == stdin) {
                                spec1 = fopen(optarg, "r");
-                               if (spec1 == NULL)
-                                       err(1, "%s", optarg);
+                               if (spec1 == NULL) {
+                                       error = errno;
+                                       RECORD_FAILURE(88, error);
+                                       errc(1, error, "%s", optarg);
+                               }
                        } else if (spec2 == NULL) {
                                spec2 = fopen(optarg, "r");
-                               if (spec2 == NULL)
-                                       err(1, "%s", optarg);
-                       } else
+                               if (spec2 == NULL) {
+                                       error = errno;
+                                       RECORD_FAILURE(89, error);
+                                       errc(1, error, "%s", optarg);
+                               }
+                       } else {
+                               RECORD_FAILURE(90, WARN_USAGE);
                                usage();
+                       }
                        break;
                case 'i':
                        iflag = 1;
@@ -133,8 +169,10 @@ main(int argc, char *argv[])
                case 's':
                        sflag = 1;
                        crc_total = (uint32_t)~strtoul(optarg, &p, 0);
-                       if (*p)
+                       if (*p) {
+                               RECORD_FAILURE(91, WARN_USAGE);
                                errx(1, "illegal seed value -- %s", optarg);
+                       }
                        break;
                case 'U':
                        Uflag = 1;
@@ -152,32 +190,105 @@ main(int argc, char *argv[])
                case 'X':
                        read_excludes_file(optarg);
                        break;
+               case 'm':
+                       mflag = 1;
+                       filepath = strdup(optarg);
+                       dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                        &kCFTypeDictionaryKeyCallBacks,
+                                                        &kCFTypeDictionaryValueCallBacks);
+                       insert_access = insert_mod = insert_birth = insert_change = 0;
+                       break;
+               case 'F':
+                       timeformat = optarg;
+                       break;
+               case 't':
+                       timestamp = optarg;
+                       tflag = 1;
+                       break;
+               case 'E':
+                       if (!strcmp(optarg, "-")) {
+                               file = stdout;
+                       } else {
+                               file = fopen(optarg, "w");
+                       }
+                       if (file == NULL) {
+                               warnx("Could not open metrics log file %s", optarg);
+                       } else {
+                               set_metrics_file(file);
+                       }
+               break;
+
                case '?':
                default:
+                       RECORD_FAILURE(92, WARN_USAGE);
                        usage();
                }
        argc -= optind;
 //     argv += optind;
 
-       if (argc)
+       if (argc) {
+               RECORD_FAILURE(93, WARN_USAGE);
                usage();
+       }
 
-       if (dir && chdir(dir))
-               err(1, "%s", dir);
+       if (timestamp) {
+               struct tm t = {};
+               char *r = strptime(timestamp, timeformat, &t);
+               if (r && r[0] == '\0') {
+                       ts.tv_sec = mktime(&t);
+                       if ((ts.tv_sec - time(NULL)) > 30 * SECONDS_IN_A_DAY) {
+                               RECORD_FAILURE(94, WARN_TIME);
+                               errx(1, "Time is more then 30 days in the future");
+                       } else if (ts.tv_sec < 0) {
+                               RECORD_FAILURE(95, WARN_TIME);
+                               errx(1, "Time is too far in the past");
+                       }
+               } else {
+                       RECORD_FAILURE(96, WARN_TIME);
+                       errx(1,"Cannot parse timestamp '%s' using format \"%s\"\n", timestamp, timeformat);
+               }
+       }
+
+       if (dir && chdir(dir)) {
+               error = errno;
+               RECORD_FAILURE(97, error);
+               errc(1, error, "%s", dir);
+       }
 
-       if ((cflag || sflag) && !getwd(fullpath))
+       if ((cflag || sflag) && !getwd(fullpath)) {
+               RECORD_FAILURE(98, errno);
                errx(1, "%s", fullpath);
+       }
+
+       if (dir) {
+               set_metric_path(dir);
+       }
 
        if (cflag) {
                cwalk();
                exit(0);
        }
-       if (spec2 != NULL)
+       if (spec2 != NULL) {
                status = mtree_specspec(spec1, spec2);
-       else
+               if (Uflag & (status == MISMATCHEXIT)) {
+                       status = 0;
+               } else {
+                       RECORD_FAILURE(99, status);
+               }
+       } else {
                status = mtree_verifyspec(spec1);
-       if (Uflag & (status == MISMATCHEXIT))
-               status = 0;
+               if (Uflag & (status == MISMATCHEXIT)) {
+                       status = 0;
+               } else {
+                       RECORD_FAILURE(100, status);
+               }
+               if (mflag && CFDictionaryGetCount(dict)) {
+                       if (!write_plist_to_file()) {
+                               RECORD_FAILURE(101, EIO);
+                               errx(1, "could not write manifest to the file\n");
+                       }
+               }
+       }
        exit(status);
 }
 
@@ -189,3 +300,59 @@ usage(void)
 "\t[-X excludes]\n");
        exit(1);
 }
+
+static bool
+write_plist_to_file(void)
+{
+       if (!dict || !filepath) {
+               RECORD_FAILURE(102, EINVAL);
+               return false;
+       }
+
+       CFIndex bytes_written = 0;
+       bool status = true;
+
+       CFStringRef file_path_str = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)filepath, kCFStringEncodingUTF8);
+
+       // Create a URL specifying the file to hold the XML data.
+       CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+                                                        file_path_str,           // file path name
+                                                        kCFURLPOSIXPathStyle,   // interpret as POSIX path
+                                                        false);                // is it a directory?
+
+       if (!fileURL) {
+               CFRelease(file_path_str);
+               RECORD_FAILURE(103, EINVAL);
+               return false;
+       }
+
+       CFWriteStreamRef output_stream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, fileURL);
+
+       if (!output_stream) {
+               CFRelease(file_path_str);
+               CFRelease(fileURL);
+               RECORD_FAILURE(104, EIO);
+               return false;
+       }
+
+       if ((status = CFWriteStreamOpen(output_stream))) {
+               bytes_written = CFPropertyListWrite((CFPropertyListRef)dict, output_stream, kCFPropertyListXMLFormat_v1_0, 0, NULL);
+               CFWriteStreamClose(output_stream);
+       } else {
+               status = false;
+               RECORD_FAILURE(105, EIO);
+               goto out;
+       }
+
+       if (!bytes_written) {
+               status = false;
+               RECORD_FAILURE(106, EIO);
+       }
+
+out:
+       CFRelease(output_stream);
+       CFRelease(fileURL);
+       CFRelease(file_path_str);
+
+       return status;
+}
index 02d1728475d3a59d35ffae51efa8a49d1a68aaba..16c927b5dd1b56f2745dc104a8eb5d4b0ff03b4f 100644 (file)
  * $FreeBSD: src/usr.sbin/mtree/mtree.h,v 1.7 2005/03/29 11:44:17 tobez Exp $
  */
 
+#ifndef _MTREE_H_
+#define _MTREE_H_
+
+#include <sys/time.h>
 #include <string.h>
 #include <stdlib.h>
 
@@ -60,8 +64,10 @@ typedef struct _node {
        struct timespec st_ctimespec;           /* metadata modification time */
        struct timespec st_ptimespec;           /* time added to parent folder */
        char    *xattrsdigest;                  /* digest of extended attributes */
+       u_quad_t xdstream_priv_id;              /* private id of the xattr data stream */
        ino_t   st_ino;                         /* inode */
        char    *acldigest;                     /* digest of access control list */
+       u_quad_t  sibling_id;                   /* sibling id */
 
 #define        F_CKSUM         0x00000001              /* check sum */
 #define        F_DONE          0x00000002              /* directory done */
@@ -92,6 +98,7 @@ typedef struct _node {
 #define F_XATTRS       0x02000000              /* digest of extended attributes */
 #define F_INODE                0x04000000              /* inode */
 #define F_ACL          0x08000000              /* digest of access control list */
+#define F_SIBLINGID    0x10000000              /* sibling id */
        u_int   flags;                          /* items set */
 
 #define        F_BLOCK 0x001                           /* block special */
@@ -109,3 +116,5 @@ typedef struct _node {
 #define        RP(p)   \
        ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
            (p)->fts_path + 2 : (p)->fts_path)
+
+#endif /* _MTREE_H_ */
index 332accc1f23cc12b8d9205517c1a5de1ff47698c..f15d85744849225a5d4aeb7ca632cf78ed03b630 100644 (file)
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez E
 #include <stdint.h>
 #include <unistd.h>
 #include <vis.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
@@ -74,8 +75,10 @@ mtree_readspec(FILE *fi)
                        continue;
 
                /* Find end of line. */
-               if ((p = index(buf, '\n')) == NULL)
+               if ((p = index(buf, '\n')) == NULL) {
+                       RECORD_FAILURE(21, ERANGE);
                        errx(1, "line %d too long", lineno);
+               }
 
                /* See if next line is continuation line. */
                if (p[-1] == '\\') {
@@ -102,8 +105,10 @@ mtree_readspec(FILE *fi)
                }
 
                /* Grab file name, "$", "set", or "unset". */
-               if ((p = strtok(p, "\n\t ")) == NULL)
+               if ((p = strtok(p, "\n\t ")) == NULL) {
+                       RECORD_FAILURE(22, EINVAL);
                        errx(1, "line %d: missing field", lineno);
+               }
 
                if (p[0] == '/')
                        switch(p[1]) {
@@ -119,9 +124,11 @@ mtree_readspec(FILE *fi)
                                continue;
                        }
 
-               if (index(p, '/'))
+               if (index(p, '/')) {
+                       RECORD_FAILURE(23, EINVAL);
                        errx(1, "line %d: slash character in file name",
                        lineno);
+               }
 
                if (!strcmp(p, "..")) {
                        /* Don't go up, if haven't gone down. */
@@ -135,17 +142,22 @@ mtree_readspec(FILE *fi)
                        last->flags |= F_DONE;
                        continue;
 
-noparent:              errx(1, "line %d: no parent node", lineno);
+noparent:              RECORD_FAILURE(24, EINVAL);
+                       errx(1, "line %d: no parent node", lineno);
                }
 
-               if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
+               if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) {
+                       RECORD_FAILURE(25, ENOMEM);
                        errx(1, "calloc");
+               }
                *centry = ginfo;
 #define        MAGIC   "?*["
                if (strpbrk(p, MAGIC))
                        centry->flags |= F_MAGIC;
-               if (strunvis(centry->name, p) == -1)
+               if (strunvis(centry->name, p) == -1) {
+                       RECORD_FAILURE(26, EILSEQ);
                        errx(1, "filename %s is ill-encoded", p);
+               }
                set(NULL, centry);
 
                if (!root) {
@@ -166,6 +178,7 @@ noparent:           errx(1, "line %d: no parent node", lineno);
 static void
 set(char *t, NODE *ip)
 {
+       int error = 0;
        int type;
        char *kw, *val = NULL;
        struct group *gr;
@@ -176,90 +189,122 @@ set(char *t, NODE *ip)
 
        for (; (kw = strtok(t, "= \t\n")); t = NULL) {
                ip->flags |= type = parsekey(kw, &value);
-               if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL)
+               if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL) {
+                       RECORD_FAILURE(27, EINVAL);
                        errx(1, "line %d: missing value", lineno);
+               }
                switch(type) {
                        case F_CKSUM:
                                ip->cksum = strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(28, EINVAL);
                                        errx(1, "line %d: invalid checksum %s",
                                             lineno, val);
+                               }
                                break;
                        case F_MD5:
                                ip->md5digest = strdup(val);
-                               if(!ip->md5digest)
+                               if (!ip->md5digest) {
+                                       RECORD_FAILURE(29, ENOMEM);
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_SHA1:
                                ip->sha1digest = strdup(val);
-                               if(!ip->sha1digest)
+                               if (!ip->sha1digest) {
+                                       RECORD_FAILURE(30, ENOMEM);
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_SHA256:
                                ip->sha256digest = strdup(val);
-                               if(!ip->sha256digest)
+                               if (!ip->sha256digest) {
+                                       RECORD_FAILURE(31, ENOMEM);
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_RMD160:
                                ip->rmd160digest = strdup(val);
-                               if(!ip->rmd160digest)
+                               if (!ip->rmd160digest) {
+                                       RECORD_FAILURE(32, ENOMEM);
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_FLAGS:
-                               if (strcmp("none", val) == 0)
+                               if (strcmp("none", val) == 0) {
                                        ip->st_flags = 0;
-                               else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
+                               } else if (strtofflags(&val, &ip->st_flags, NULL) != 0) {
+                                       RECORD_FAILURE(33, EINVAL);
                                        errx(1, "line %d: invalid flag %s",lineno, val);
+                               }
                                break;
                        case F_GID:
                                ip->st_gid = (gid_t)strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(34, EINVAL);
                                        errx(1, "line %d: invalid gid %s", lineno, val);
+                               }
                                break;
                        case F_GNAME:
-                               if ((gr = getgrnam(val)) == NULL)
+                               if ((gr = getgrnam(val)) == NULL) {
+                                       RECORD_FAILURE(35, EINVAL);
                                        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)
+                               if ((m = setmode(val)) == NULL) {
+                                       RECORD_FAILURE(36, EINVAL);
                                        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)
+                               if (*ep) {
+                                       RECORD_FAILURE(37, EINVAL);
                                        errx(1, "line %d: invalid link count %s",
                                             lineno,  val);
+                               }
                                break;
                        case F_SIZE:
                                ip->st_size = strtoq(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(38, EINVAL);
                                        errx(1, "line %d: invalid size %s",
                                             lineno, val);
+                               }
                                break;
                        case F_SLINK:
                                ip->slink = malloc(strlen(val) + 1);
-                               if (ip->slink == NULL)
+                               if (ip->slink == NULL) {
+                                       RECORD_FAILURE(39, ENOMEM);
                                        errx(1, "malloc");
-                               if (strunvis(ip->slink, val) == -1)
+                               }
+                               if (strunvis(ip->slink, val) == -1) {
+                                       RECORD_FAILURE(40, EILSEQ);
                                        errx(1, "symlink %s is ill-encoded", val);
+                               }
                                break;
                        case F_TIME:
                                ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
-                               if (*ep != '.')
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(41, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(42, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_TYPE:
                                switch(*val) {
@@ -290,78 +335,127 @@ set(char *t, NODE *ip)
                                                        ip->type = F_SOCK;
                                                break;
                                        default:
+                                               RECORD_FAILURE(43, EINVAL);
                                                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)
+                               if (*ep) {
+                                       RECORD_FAILURE(44, EINVAL);
                                        errx(1, "line %d: invalid uid %s", lineno, val);
+                               }
                                break;
                        case F_UNAME:
-                               if ((pw = getpwnam(val)) == NULL)
+                               if ((pw = getpwnam(val)) == NULL) {
+                                       RECORD_FAILURE(45, EINVAL);
                                        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 != '.')
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(46, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_birthtimespec.tv_nsec = strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(47, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_ATIME:
                                ip->st_atimespec.tv_sec = strtoul(val, &ep, 10);
-                               if (*ep != '.')
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(48, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_atimespec.tv_nsec = strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(49, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_CTIME:
                                ip->st_ctimespec.tv_sec = strtoul(val, &ep, 10);
-                               if (*ep != '.')
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(50, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_ctimespec.tv_nsec = strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(51, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_PTIME:
                                ip->st_ptimespec.tv_sec = strtoul(val, &ep, 10);
-                               if (*ep != '.')
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(52, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_ptimespec.tv_nsec = strtoul(val, &ep, 10);
-                               if (*ep)
+                               if (*ep) {
+                                       RECORD_FAILURE(53, EINVAL);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_XATTRS:
-                               ip->xattrsdigest = strdup(val);
-                               if(!ip->xattrsdigest)
-                                       err(1, "strdup");
+                               ep = strtok(val,".");
+                               ip->xattrsdigest = strdup(ep);
+                               if (!ip->xattrsdigest) {
+                                       error = errno;
+                                       RECORD_FAILURE(54, error);
+                                       errc(1, error, "strdup");
+                               }
+                               val = strtok(NULL,".");
+                               if (val) {
+                                       ip->xdstream_priv_id = strtoull(val, &ep, 10);
+                                       if (*ep) {
+                                               RECORD_FAILURE(55, EINVAL);
+                                               errx(1, "line %d: invalid private id %s",
+                                                    lineno, val);
+                                       }
+                               } else {
+                                       ip->xdstream_priv_id = 0;
+                               }
                                break;
                        case F_INODE:
                                ip->st_ino = (ino_t)strtoull(val, &ep, 10);
-                               if (*ep)
-                                       errx(1, "line %d: invalid inode %s", lineno, val);
+                               if (*ep) {
+                                       RECORD_FAILURE(56, EINVAL);
+                                       errx(1, "line %d: invalid inode %s",
+                                            lineno, val);
+                               }
                                break;
                        case F_ACL:
                                ip->acldigest = strdup(val);
-                               if(!ip->acldigest)
-                                       err(1, "strdup");
+                               if (!ip->acldigest) {
+                                       error = errno;
+                                       RECORD_FAILURE(57, error);
+                                       errc(1, error, "strdup");
+                               }
+                               break;
+                       case F_SIBLINGID:
+                               ip->sibling_id = (quad_t)strtoull(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(58, EINVAL);
+                                       errx(1, "line %d: invalid sibling id %s", lineno, val);
+                               }
                }
        }
 }
index bbcd795c7433896ff27b6973968687cc9726755c..cb08384189a035995109138429b3955dbfb6f8bc 100644 (file)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/specspec.c,v 1.6 2005/03/29 11:44:17 tobe
 #include <stdio.h>
 #include <stdint.h>
 #include <unistd.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
@@ -98,11 +99,13 @@ shownode(NODE *n, int f, char const *path)
        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);
+               printf(" xattrsdigest=%s.%llu", n->xattrsdigest, n->xdstream_priv_id);
        if (f & F_INODE)
                printf(" inode=%llu", n->st_ino);
        if (f & F_ACL)
                printf(" acldigest=%s", n->acldigest);
+       if (f & F_SIBLINGID)
+               printf(" siblingid=%llu", n->sibling_id);
        
        printf("\n");
 }
@@ -143,14 +146,17 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
                return 0;
        } else if (n1 == NULL) {
                differs = n2->flags;
+               RECORD_FAILURE(111, WARN_MISMATCH);
                mismatch(n1, n2, differs, path);
                return (1);
        } else if (n2 == NULL) {
                differs = n1->flags;
+               RECORD_FAILURE(112, WARN_MISMATCH);
                mismatch(n1, n2, differs, path);
                return (1);
        } else if (n1->type != n2->type) {
                differs = 0;
+               RECORD_FAILURE(113, WARN_MISMATCH);
                mismatch(n1, n2, differs, path);
                return (1);
        }
@@ -198,8 +204,11 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
                differs |= F_INODE;
        if (FS(n1, n2, F_ACL, acldigest))
                differs |= F_ACL;
+       if (FF(n1, n2, F_SIBLINGID, sibling_id))
+               differs |= F_SIBLINGID;
        
        if (differs) {
+               RECORD_FAILURE(114, WARN_MISMATCH);
                mismatch(n1, n2, differs, path);
                return (1);
        }
@@ -208,7 +217,7 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
 static int
 walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
 {
-       int r, i;
+       int r, i, c;
        NODE *c1, *c2, *n1, *n2;
        char *np;
 
@@ -249,22 +258,49 @@ walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
                if (c1 == NULL && c2->type == F_DIR) {
                        asprintf(&np, "%s%s/", path, c2->name);
                        i = walk_in_the_forest(c1, c2, np);
+                       if (i) {
+                               RECORD_FAILURE(115, WARN_MISMATCH);
+                       }
                        free(np);
-                       i += compare_nodes(c1, c2, path);
+                       c = compare_nodes(c1, c2, path);
+                       if (c) {
+                               RECORD_FAILURE(116, WARN_MISMATCH);
+                       }
+                       i += c;
                } else if (c2 == NULL && c1->type == F_DIR) {
                        asprintf(&np, "%s%s/", path, c1->name);
                        i = walk_in_the_forest(c1, c2, np);
+                       if (i) {
+                               RECORD_FAILURE(117, WARN_MISMATCH);
+                       }
                        free(np);
-                       i += compare_nodes(c1, c2, path);
+                       c = compare_nodes(c1, c2, path);
+                       if (c) {
+                               RECORD_FAILURE(118, WARN_MISMATCH);
+                       }
+                       i += c;
                } else if (c1 == NULL || c2 == NULL) {
                        i = compare_nodes(c1, c2, path);
+                       if (i) {
+                               RECORD_FAILURE(119, WARN_MISMATCH);
+                       }
                } else if (c1->type == F_DIR && c2->type == F_DIR) {
                        asprintf(&np, "%s%s/", path, c1->name);
                        i = walk_in_the_forest(c1, c2, np);
+                       if (i) {
+                               RECORD_FAILURE(120, WARN_MISMATCH);
+                       }
                        free(np);
-                       i += compare_nodes(c1, c2, path);
+                       c = compare_nodes(c1, c2, path);
+                       if (c) {
+                               RECORD_FAILURE(121, WARN_MISMATCH);
+                       }
+                       i += c;
                } else {
                        i = compare_nodes(c1, c2, path);
+                       if (i) {
+                               RECORD_FAILURE(122, WARN_MISMATCH);
+                       }
                }
                r += i;
                c1 = n1;
@@ -283,7 +319,9 @@ mtree_specspec(FILE *fi, FILE *fj)
        root2 = mtree_readspec(fj);
        rval = walk_in_the_forest(root1, root2, "");
        rval += compare_nodes(root1, root2, "");
-       if (rval > 0)
+       if (rval > 0) {
+               RECORD_FAILURE(123, WARN_MISMATCH);
                return (MISMATCHEXIT);
+       }
        return (0);
 }
index 84a37ffe4c6c9b0a5eba5574ecc4f967d45cd350..7471652461f60664937942fd7eb4da201fc789f0 100644 (file)
@@ -45,33 +45,40 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian
 #include <stdio.h>
 #include <stdint.h>
 #include <unistd.h>
+#include <removefile.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
 static NODE *root;
 static char path[MAXPATHLEN];
 
-static int     miss(NODE *, char *);
+static int     miss(NODE *, char *, size_t path_length);
 static int     vwalk(void);
 
 int
 mtree_verifyspec(FILE *fi)
 {
        int rval, mval;
+       size_t path_length = 0;
 
        root = mtree_readspec(fi);
        rval = vwalk();
-       mval = miss(root, path);
+       mval = miss(root, path, path_length);
        
-       if (rval != 0)
+       if (rval != 0) {
+               RECORD_FAILURE(60, WARN_MISMATCH);
                return rval;
-       else
+       } else {
+               RECORD_FAILURE(61, WARN_MISMATCH);
                return mval;
+       }
 }
 
 static int
 vwalk(void)
 {
+       int error = 0;
        FTS *t;
        FTSENT *p;
        NODE *ep, *level;
@@ -81,8 +88,11 @@ vwalk(void)
 
        argv[0] = dot;
        argv[1] = NULL;
-       if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
-               err(1, "line %d: fts_open", lineno);
+       if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) {
+               error = errno;
+               RECORD_FAILURE(62, error);
+               errc(1, error, "line %d: fts_open", lineno);
+       }
        level = root;
        specdepth = rval = 0;
        while ((p = fts_read(t))) {
@@ -96,6 +106,7 @@ vwalk(void)
                        break;
                case FTS_DP:
                        if (level == NULL) {
+                               RECORD_FAILURE(63, EINVAL);
                                errx(1 , "invalid root in vwalk");
                        }
                        if (specdepth > p->fts_level) {
@@ -122,8 +133,10 @@ vwalk(void)
                            !strcmp(ep->name, p->fts_name)) {
                                ep->flags |= F_VISIT;
                                if ((ep->flags & F_NOCHANGE) == 0 &&
-                                   compare(ep->name, ep, p))
+                                   compare(ep->name, ep, p)) {
+                                       RECORD_FAILURE(64, WARN_MISMATCH);
                                        rval = MISMATCHEXIT;
+                               }
                                if (ep->flags & F_IGN)
                                        (void)fts_set(t, p, FTS_SKIP);
                                else if (ep->child && ep->type == F_DIR &&
@@ -139,26 +152,61 @@ vwalk(void)
 extra:
                if (!eflag) {
                        (void)printf("%s extra", RP(p));
+
                        if (rflag) {
-                               if ((S_ISDIR(p->fts_statp->st_mode)
-                                   ? rmdir : unlink)(p->fts_accpath)) {
-                                       (void)printf(", not removed: %s",
-                                           strerror(errno));
-                               } else
-                                       (void)printf(", removed");
+                               /* rflag implies: delete stuff if "extra" is observed" */
+                               if (mflag) {
+                                       /* -mflag is used for sealing & verification -- use removefile for recursive behavior */
+                                       removefile_state_t rmstate;
+                                       rmstate = removefile_state_alloc();
+                                       if (removefile(p->fts_accpath, rmstate, (REMOVEFILE_RECURSIVE))) {
+                                               error = errno;
+                                               RECORD_FAILURE(65, error);
+                                               errx (1, "\n error deleting item (or descendant) at path %s (%s)", RP(p), strerror(error));
+                                       }
+                                       else {
+                                               /* removefile success */
+                                               (void) printf(", removed");
+                                       }
+                                       removefile_state_free(rmstate);
+
+                               }
+                               else {
+                                       /* legacy: use rmdir/unlink if "-m" not specified */
+                                       int syserr = 0;
+
+                                       if (S_ISDIR(p->fts_statp->st_mode)){
+                                               syserr = rmdir(p->fts_accpath);
+                                       }
+                                       else {
+                                               syserr = unlink(p->fts_accpath);
+                                       }
+
+                                       /* log failures */
+                                       if (syserr) {
+                                               error = errno;
+                                               RECORD_FAILURE(66, error);
+                                               (void) printf(", not removed :%s", strerror(error));
+                                       }
+                               }
+                       } else if (mflag) {
+                               RECORD_FAILURE(68956, WARN_MISMATCH);
+                               errx(1, "cannot generate the XML dictionary");
                        }
                        (void)putchar('\n');
                }
                (void)fts_set(t, p, FTS_SKIP);
        }
        (void)fts_close(t);
-       if (sflag)
+       if (sflag) {
+               RECORD_FAILURE(67, WARN_CHECKSUM);
                warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+       }
        return (rval);
 }
 
 static int
-miss(NODE *p, char *tail)
+miss(NODE *p, char *tail, size_t path_length)
 {
        int create;
        char *tp;
@@ -166,10 +214,17 @@ miss(NODE *p, char *tail)
        int serr;
        int rval = 0;
        int rrval = 0;
+       size_t file_name_length = 0;
 
        for (; p; p = p->next) {
                if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
                        continue;
+               file_name_length = strnlen(p->name, MAXPATHLEN);
+               path_length += file_name_length;
+               if (path_length >= MAXPATHLEN) {
+                       RECORD_FAILURE(61971, ENAMETOOLONG);
+                       continue;
+               }
                (void)strcpy(tail, p->name);
                if (!(p->flags & F_VISIT)) {
                        /* Don't print missing message if file exists as a
@@ -180,6 +235,7 @@ miss(NODE *p, char *tail)
                                p->flags |= F_VISIT;
                        } else {
                                (void)printf("%s missing", path);
+                               RECORD_FAILURE(68, WARN_MISMATCH);
                                rval = MISMATCHEXIT;
                        }
                }
@@ -194,16 +250,19 @@ miss(NODE *p, char *tail)
                else
                        type = "directory";
                if (!(p->flags & F_VISIT) && uflag) {
-                       if (!(p->flags & (F_UID | F_UNAME)))
+                       if (!(p->flags & (F_UID | F_UNAME))) {
                                (void)printf(" (%s not created: user not specified)", type);
-                       else if (!(p->flags & (F_GID | F_GNAME)))
+                       } else if (!(p->flags & (F_GID | F_GNAME))) {
                                (void)printf(" (%s not created: group not specified)", type);
-                       else if (p->type == F_LINK) {
-                               if (symlink(p->slink, path))
+                       } else if (p->type == F_LINK) {
+                               if (symlink(p->slink, path)) {
+                                       serr = errno;
+                                       RECORD_FAILURE(69, serr);
                                        (void)printf(" (symlink not created: %s)\n",
-                                           strerror(errno));
-                               else
+                                           strerror(serr));
+                               } else {
                                        (void)printf(" (created)\n");
+                               }
                                if (lchown(path, p->st_uid, p->st_gid) == -1) {
                                        serr = errno;
                                        if (p->st_uid == (uid_t)-1)
@@ -215,16 +274,20 @@ miss(NODE *p, char *tail)
                                                what = "user";
                                                errno = serr;
                                        }
+                                       serr = errno;
+                                       RECORD_FAILURE(70, serr);
                                        (void)printf("%s: %s not modified: %s"
-                                           "\n", path, what, strerror(errno));
+                                           "\n", path, what, strerror(serr));
                                }
                                continue;
-                       } else if (!(p->flags & F_MODE))
+                       } else if (!(p->flags & F_MODE)) {
                            (void)printf(" (directory not created: mode not specified)");
-                       else if (mkdir(path, S_IRWXU))
+                       } else if (mkdir(path, S_IRWXU)) {
+                               serr = errno;
+                               RECORD_FAILURE(71, serr);
                                (void)printf(" (directory not created: %s)",
-                                   strerror(errno));
-                       else {
+                                   strerror(serr));
+                       else {
                                create = 1;
                                (void)printf(" (created)");
                        }
@@ -234,9 +297,13 @@ miss(NODE *p, char *tail)
 
                for (tp = tail; *tp; ++tp);
                *tp = '/';
-               rrval = miss(p->child, tp + 1);
-               if (rrval != 0)
+               ++path_length;
+               rrval = miss(p->child, tp + 1, path_length);
+               if (rrval != 0) {
+                       RECORD_FAILURE(72, WARN_MISMATCH);
                        rval = rrval;
+               }
+               path_length -= (file_name_length + 1);
                *tp = '\0';
 
                if (!create)
@@ -251,16 +318,24 @@ miss(NODE *p, char *tail)
                                what = "user";
                                errno = serr;
                        }
+                       serr = errno;
+                       RECORD_FAILURE(73, serr);
                        (void)printf("%s: %s not modified: %s\n",
-                           path, what, strerror(errno));
+                           path, what, strerror(serr));
                }
-               if (chmod(path, p->st_mode))
+               if (chmod(path, p->st_mode)) {
+                       serr = errno;
+                       RECORD_FAILURE(74, serr);
                        (void)printf("%s: permissions not set: %s\n",
-                           path, strerror(errno));
+                           path, strerror(serr));
+               }
                if ((p->flags & F_FLAGS) && p->st_flags &&
-                   chflags(path, (u_int)p->st_flags))
+                   chflags(path, (u_int)p->st_flags)) {
+                       serr = errno;
+                       RECORD_FAILURE(75, serr);
                        (void)printf("%s: file flags not set: %s\n",
-                           path, strerror(errno));
+                           path, strerror(serr));
+               }
        }
        return rval;
 }
index 514678ff264ea9d15f5c392df4baa69a464d29c0..fe1d6cd765067ebe43daa684d9b04af08bda3d6b 100644 (file)
  * $FreeBSD: src/bin/mv/pathnames.h,v 1.6 2002/05/17 11:38:48 jmallett Exp $
  */
 
+#ifndef _MV_PATHNAMES_H_
+#define _MV_PATHNAMES_H_
+
 #define        _PATH_RM        "/bin/rm"
 #ifdef __APPLE__
 #define _PATH_CP       "/bin/cp"
 #endif /* __APPLE__ */
+
+#endif /* _MV_PATHNAMES_H_ */
index 5c7b9b8b5f3c0698a0e8350ee67b95e9e8a71d1a..1a269d4dce5b80c76e18fbc1709fe556d5fdf33a 100644 (file)
@@ -36,6 +36,9 @@
  *      @(#)cache.h    8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
 /*
  * Constants and data structures used to implement group and password file
  * caches. Traditional passwd/group cache routines perform quite poorly with
@@ -71,3 +74,5 @@ typedef struct gidc {
        char name[GNMLEN];      /* gid name */
        gid_t gid;              /* cached gid */
 } GIDC;
+
+#endif /* _CACHE_H_ */
index dfbd03f21e3ec7809d0f55e58589775eb01073ce..93617b40043680c48edeb5b7b7a47f47d4537fc7 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)cpio.h      8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _CPIO_H_
+#define _CPIO_H_
+
 /*
  * Defines common to all versions of cpio
  */
@@ -148,3 +151,5 @@ typedef struct {
 #define VCPIO_PAD(x)   ((4 - ((x) & 3)) & 3)   /* pad to next 4 byte word */
 #define VCPIO_MASK     0xffffffff      /* mask for dev/ino fields */
 #endif /* _PAX_ */
+
+#endif /* _CPIO_H_ */
index 5dad640873690db57bf9a776a2da37121f5924ca..16d31958b261bda04572da0e22199bed63e4b282 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)extern.h    8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _PAX_EXTERN_H_
+#define _PAX_EXTERN_H_
+
 /*
  * External references from each source file
  */
@@ -340,3 +343,5 @@ void tty_prnt(const char *, ...);
 int tty_read(char *, int);
 void paxwarn(int, const char *, ...);
 void syswarn(int, int, const char *, ...);
+
+#endif /* _PAX_EXTERN_H_ */
index 9b4cffcc78f83aacf5d9a947d6cb96656f25eb98..02038153de66f324b9120bb990a0e20a3ad131c1 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)ftree.h     8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _FTREE_H_
+#define _FTREE_H_
+
 /*
  * Data structure used by the ftree.c routines to store the file args to be
  * handed to fts(). It keeps a reference count of which args generated a
@@ -49,3 +52,5 @@ typedef struct ftree {
        int             chflg;          /* change directory flag */
        struct ftree    *fow;           /* pointer to next entry on list */
 } FTREE;
+
+#endif /* _FTREE_H_ */
index 0b75b0d83b9d297449b9120b6763f34ac60bc01b..cf821fbf2232a98d3ca38695c504f5dc8a20652b 100644 (file)
@@ -216,17 +216,26 @@ ls_tty(ARCHD *arcn)
 void
 safe_print(const char *str, FILE *fp)
 {
-       char visbuf[5];
-       const char *cp;
-
        /*
-        * if printing to a tty, use vis(3) to print special characters.
+        * if printing to a tty, use strvis(3) to print special characters.
         */
        if (isatty(fileno(fp))) {
-               for (cp = str; *cp; cp++) {
-                       (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
-                       (void)fputs(visbuf, fp);
+               /*
+                * The size of visbuf must be four times the number
+                * of bytes encoded from str (plus one for the NUL).
+                */
+               char *visbuf = (char *) malloc(sizeof(char) * (4 * strlen(str) + 1));
+               if (visbuf == NULL) {
+                       paxwarn(1, "Out of memory");
+                       return;
                }
+               /*
+                * using strvis(3) instead of vis(3) to account for multibyte
+                * characters
+                */
+               (void)strvis(visbuf, str, VIS_CSTYLE);
+               (void)fputs(visbuf, fp);
+               free(visbuf);
        } else {
                (void)fputs(str, fp);
        }
index 873d8d559671bb2daedc6b65f6224b2793ec03fd..89eeaa5ff04f209679e5a1add8dc1e451def1244 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)options.h   8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _OPTIONS_H_
+#define _OPTIONS_H_
+
 /*
  * argv[0] names. Used for tar and cpio emulation
  */
 #define        BDARCH  (CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF)
 #define        BDCOPY  (AF|BF|FF|CBF|CEF)
 #define        BDLIST (AF|BF|IF|KF|LF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF)
+
+#endif /* _OPTIONS_H_ */
index ff2819e28218165b6b4bbbfe0688584701732358..fa778b961ac1d945bebadd2d109bbf9ee8432e23 100644 (file)
@@ -74,6 +74,10 @@ static int rep_name(char *, size_t, int *, int);
 int tty_rename(ARCHD *);
 static int fix_path(char *, int *, char *, int);
 static int fn_match(char *, char *, char **);
+#ifdef _HAVE_REGCOMP_
+static char* extract_equiv_pat(char *, char **);
+static int regex_match(char *, char *, char **);
+#endif
 static char * range_match(char *, int);
 static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *);
 
@@ -495,6 +499,10 @@ fn_match(char *pattern, char *string, char **pend)
 {
        char c;
        char test;
+#ifdef _HAVE_REGCOMP_
+       char *equiv_pat;
+       char *pat_pend = NULL;
+#endif
 
        *pend = NULL;
        for (;;) {
@@ -549,10 +557,33 @@ fn_match(char *pattern, char *string, char **pend)
                        /*
                         * range match
                         */
+#ifdef _HAVE_REGCOMP_
+                       /*
+                        * Check for equivalence class and use regex_match to
+                        * handle this case. Note pattern should include the
+                        * opening bracket '['
+                        */
+                       equiv_pat = extract_equiv_pat(pattern-1, &pat_pend);
+                       if (equiv_pat) {
+                               if (regex_match(equiv_pat, string, &string) == -1) {
+                                       free (equiv_pat);
+                                       return (-1);
+                               }
+                               
+                               free(equiv_pat);
+                               
+                               /*
+                                * Update the pattern string
+                                */
+                               pattern = pat_pend;
+                               break;
+                       }
+#endif
                        if (((test = *string++) == '\0') ||
                            ((pattern = range_match(pattern, test)) == NULL))
                                return (-1);
                        break;
+
                case '\\':
                default:
                        if (c != *string++)
@@ -563,6 +594,124 @@ fn_match(char *pattern, char *string, char **pend)
        /* NOTREACHED */
 }
 
+#ifdef _HAVE_REGCOMP_
+static char*
+extract_equiv_pat(char *pattern, char **pend)
+{
+       int pat_len = 2;
+       int found = 0;
+       int is_double_bracket = 0;
+       char* equiv_pat = NULL;
+       
+       if (*pattern == '\0' || pattern[1] == '\0' || pattern[2] == '\0')
+               return NULL;
+       
+       /*
+        * check if the pattern is
+        * "[= =]", "[[= =][= =]]", "[: :]", or "[[: :][: :]]"
+        * note that the full "pattern" string needs to be passed in
+        */
+       is_double_bracket = (*pattern == '[' && pattern[1] == '[');
+       if (!(*pattern == '[') && !is_double_bracket) {
+               return NULL;
+       }
+       
+       pattern ++;
+       
+       if (is_double_bracket) {
+               pattern ++;
+               pat_len ++;
+       }
+       
+       if (!(*pattern == ':') && !(*pattern == '=')) {
+               return NULL;
+       }
+       
+       pattern ++;
+       
+
+       for(; *pattern != '\0'; pat_len++, pattern++) {
+               if (!is_double_bracket) {
+                       if ((*pattern == '=' || *pattern == ':')
+                           && pattern[1] == ']') {
+                               found = 1;
+                               pattern += 2;
+                               pat_len += 2;
+                               break;
+                       }
+                       
+               } else {
+                       if ((*pattern == '=' || *pattern == ':')
+                           && pattern[1] == ']' && pattern[2] == ']') {
+                               found = 1;
+                               pattern += 3;
+                               pat_len += 3;
+                               break;
+                       }
+                           
+               }
+       }
+       
+       if (!found) {
+               return NULL;
+       }
+       
+       equiv_pat = strndup(pattern-pat_len, pat_len);
+       
+       if (equiv_pat == NULL) {
+               paxwarn(1, "Out of memory");
+               return NULL;
+       }
+       
+       /*
+        * set pend to the remaining pattern to be matched
+        */
+       if (pend != NULL) {
+               *pend = pattern;
+       }
+       
+       return equiv_pat;
+}
+
+static int
+regex_match(char *pattern, char *string, char **pend)
+{
+       int res;
+       regex_t preg;
+       regmatch_t pmatch;
+       char rebuf[BUFSIZ];
+       
+       if ((res = regcomp(&(preg), pattern, REG_EXTENDED)) != 0) {
+               regerror(res, &(preg), rebuf, sizeof(rebuf));
+               paxwarn(1, "%s while compiling pattern %s", rebuf, pattern);
+               return(-1);
+       }
+       
+       if (regexec(&(preg), string, 1, &(pmatch), 0) != 0) {
+               regfree(&(preg));
+               return(-1);
+       }
+       
+       regfree(&(preg));
+       
+       /*
+        * starting position of the match must be 0
+        */
+       if (pmatch.rm_so != 0) {
+               return(-1);
+       }
+       
+       /*
+        * set pend to the remaining string to be matched
+        */
+       if (pend != NULL) {
+               *pend = string + pmatch.rm_eo;
+       }
+       
+       return(0);
+}
+#endif
+
 static char *
 range_match(char *pattern, int test)
 {
index 9138d22fae3d449019eb6d921a95828c7097b9e1..4d65a8ea7386866a5ee385bbd4357b7a21379a48 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)pat_rep.h   8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _PAT_REP_H_
+#define _PAT_REP_H_
+
 /*
  * data structure for storing user supplied replacement strings (-s)
  */
@@ -49,3 +52,5 @@ typedef struct replace {
 } REPLACE;
 
 int tty_rename(ARCHD *);       /* used for -o invalid=rename recovery */
+
+#endif /* _PAT_REP_H_ */
index 7c278f04903d4ce606babb238b8040f2ac0c7f17..ec180b79de1387ba6a25a1362f267eccb6c0a32f 100644 (file)
--- a/pax/pax.c
+++ b/pax/pax.c
@@ -63,6 +63,7 @@ __used static const char rcsid[] = "$OpenBSD: pax.c,v 1.28 2005/08/04 10:02:44 m
 #include <err.h>
 #include <fcntl.h>
 #include <paths.h>
+#include <locale.h>
 #include "pax.h"
 #include "extern.h"
 static int gen_init(void);
@@ -236,6 +237,10 @@ main(int argc, char **argv)
 {
        char *tmpdir;
        size_t tdlen;
+#ifdef _HAVE_REGCOMP_
+       setlocale(LC_CTYPE, "");
+       setlocale(LC_COLLATE, "");
+#endif
 
        listf = stderr;
        /*
index 4d74aa001aa9a109c1f6409f74830309ed554845..1caff0c55ceeb19c2f49b2842e5ed5ef2cae6dfa 100644 (file)
--- a/pax/pax.h
+++ b/pax/pax.h
@@ -36,6 +36,9 @@
  *     @(#)pax.h       8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _PAX_H_
+#define _PAX_H_
+
 /*
  * BSD PAX global data structures and constants.
  */
@@ -246,4 +249,7 @@ typedef struct oplist {
 #define HEX            16
 #define OCT            8
 #define _PAX_          1
+#define _HAVE_REGCOMP_ 1
 #define _TFILE_BASE    "paxXXXXXXXXXX"
+
+#endif /* _PAX_H_ */
index 506ce5818c429e141e4c99679d7b5d2243a05c62..4ac409435dd594881f6417035f7a8496c8447977 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)tar.h       8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _PAX_FORMAT_H_
+#define _PAX_FORMAT_H_
+
 /*
  * defines and data structures common to all tar formats
  */
@@ -151,3 +154,5 @@ typedef struct {
        char devminor[8];               /* minor device number */
        char prefix[TPFSZ];             /* linked to name */
 } HD_USTAR;
+
+#endif /* _PAX_FORMAT_H_ */
index b699ee83ef353f35de8ce769f6601b566f12652e..4516545b4cec8d7ce281ab547d3dcb55ee26c4d1 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)sel_subs.h  8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _SEL_SUBS_H_
+#define _SEL_SUBS_H_
+
 /*
  * data structure for storing uid/grp selects (-U, -G non standard options)
  */
@@ -70,3 +73,5 @@ typedef struct time_rng {
 #define CMPBOTH        (CMPMTME|CMPCTME)       /* compare inode and mod time */
        struct time_rng *fow;           /* next pattern */
 } TIME_RNG;
+
+#endif /* _SEL_SUBS_H_ */
index bc19f0669483f50e62a3fce335f2a62f9daccf70..3b1970f34bf31aa5431dbe60165a1fdb1447040c 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)tables.h    8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _TABLES_H_
+#define _TABLES_H_
+
 /*
  * data structures and constants used by the different databases kept by pax
  */
@@ -168,3 +171,5 @@ typedef struct dirdata {
        u_int16_t mode; /* file mode to restore */
        u_int16_t frc_mode;     /* do we force mode settings? */
 } DIRDATA;
+
+#endif /* _TABLES_H_ */
index 61bc6e133366ca0cc110e2b4f0f8e15294c05546..a78813cbfabd72973627049f4e596cb174a28b00 100644 (file)
--- a/pax/tar.h
+++ b/pax/tar.h
@@ -36,6 +36,9 @@
  *     @(#)tar.h       8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _TAR_H_
+#define _TAR_H_
+
 /*
  * defines and data structures common to all tar formats
  */
@@ -154,3 +157,5 @@ typedef struct {
        char devminor[8];               /* minor device number */
        char prefix[TPFSZ];             /* linked to name */
 } HD_USTAR;
+
+#endif /* _TAR_H_ */
diff --git a/rm/rm.c b/rm/rm.c
index 956c2456de4fcd57de8f8262fec0e7c66e44c3cc..ef457c5a19c0d978acc2a25ab1d5f3960150dbe3 100644 (file)
--- a/rm/rm.c
+++ b/rm/rm.c
@@ -286,12 +286,16 @@ rm_tree(argv)
                        case FTS_DP:
                        case FTS_DNR:
 #if __APPLE__
-                               if (p->fts_statp != NULL && (p->fts_statp->st_flags & SF_DATALESS) != 0)
-                                       rval = unlinkat(AT_FDCWD, p->fts_accpath, AT_REMOVEDIR_DATALESS);
-                               else
+                               rval = unlinkat(AT_FDCWD, p->fts_accpath, AT_REMOVEDIR_DATALESS);
+                               if (rval == -1 && errno == EINVAL) {
+                                       /*
+                                        * Kernel rejected AT_REMOVEDIR_DATALESS?
+                                        * I guess we fall back on the painful
+                                        * route (but it's better than failing).
+                                        */
                                        rval = rmdir(p->fts_accpath);
+                               }
 #else
-
                                rval = rmdir(p->fts_accpath);
 #endif
                                if (rval == 0 || (fflag && errno == ENOENT)) {