]> 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.
  */
 
  * SUCH DAMAGE.
  */
 
+#ifndef _CHMOD_ACL_H_
+#define _CHMOD_ACL_H_
+
 #ifdef __APPLE__
 #include <pwd.h>
 #include <grp.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__*/
 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 $
  */
 
  * $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
 #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
 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 $
  */
 
  * $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 */
 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
 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 $
  */
 
  * $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 */
 /* 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
 #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 $
  */
 
  * $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);
 #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[];
 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;
                };
                        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" */;
                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 */; };
                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 */; };
                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 */
 /* 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 */;
                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>"; };
                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; };
                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 = (
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               729D06D8230B5E42000716E5 /* CoreFoundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        path = tests;
                        sourceTree = "<group>";
                };
                        path = tests;
                        sourceTree = "<group>";
                };
+               729D06D6230B5E42000716E5 /* Frameworks */ = {
+                       isa = PBXGroup;
+                       children = (
+                               729D06D7230B5E42000716E5 /* CoreFoundation.framework */,
+                       );
+                       name = Frameworks;
+                       sourceTree = "<group>";
+               };
                FCB1BDAD14B645D00070FACB = {
                        isa = PBXGroup;
                        children = (
                FCB1BDAD14B645D00070FACB = {
                        isa = PBXGroup;
                        children = (
                                FCB1BE8614B6460C0070FACB /* touch */,
                                FDAD94A71808BCB700B4D5A0 /* Libraries */,
                                FCB1BDB914B645D10070FACB /* Products */,
                                FCB1BE8614B6460C0070FACB /* touch */,
                                FDAD94A71808BCB700B4D5A0 /* Libraries */,
                                FCB1BDB914B645D10070FACB /* Products */,
+                               729D06D6230B5E42000716E5 /* Frameworks */,
                        );
                        indentWidth = 8;
                        sourceTree = "<group>";
                        );
                        indentWidth = 8;
                        sourceTree = "<group>";
                                FCB1BE4114B6460C0070FACB /* specspec.c */,
                                FCB1BE4214B6460C0070FACB /* test */,
                                FCB1BE4814B6460C0070FACB /* verify.c */,
                                FCB1BE4114B6460C0070FACB /* specspec.c */,
                                FCB1BE4214B6460C0070FACB /* test */,
                                FCB1BE4814B6460C0070FACB /* verify.c */,
+                               7D0A20E82499364700F0F6D7 /* metrics.h */,
+                               7D0A20E92499364700F0F6D7 /* metrics.c */,
                        );
                        path = mtree;
                        sourceTree = "<group>";
                        );
                        path = mtree;
                        sourceTree = "<group>";
                                FC8A8CC814B65F92001B97AD /* uncompress */,
                                FC8A8C5014B650CF001B97AD /* unlink */,
                                3E966CE71FB2211F0019F7A1 /* tests */,
                                FC8A8CC814B65F92001B97AD /* uncompress */,
                                FC8A8C5014B650CF001B97AD /* unlink */,
                                3E966CE71FB2211F0019F7A1 /* tests */,
+                               729D07252347EC4D000716E5 /* macos_host_tools */,
                        );
                };
 /* End PBXProject section */
                        );
                };
 /* End PBXProject section */
                                FC8A8C1914B64A1A001B97AD /* create.c in Sources */,
                                FC8A8C1A14B64A22001B97AD /* excludes.c in Sources */,
                                FC8A8C1B14B64A27001B97AD /* misc.c in Sources */,
                                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 */,
                                FC8A8C1C14B64A2D001B97AD /* mtree.c in Sources */,
                                FC8A8C1D14B64A31001B97AD /* spec.c in Sources */,
                                FC8A8C1E14B64A34001B97AD /* specspec.c in Sources */,
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+               729D074E2347EC4D000716E5 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = FC8A8B8C14B648ED001B97AD /* mtree */;
+                       targetProxy = 729D074F2347EC4D000716E5 /* PBXContainerItemProxy */;
+               };
                FC8A8C4A14B64DE1001B97AD /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = FC8A8BC414B648EF001B97AD /* stat */;
                FC8A8C4A14B64DE1001B97AD /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = FC8A8BC414B648EF001B97AD /* stat */;
                        };
                        name = Release;
                };
                        };
                        name = Release;
                };
+               729D07692347EC4D000716E5 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               INSTALL_PATH = /usr/bin;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
                FC8A8B1114B648D7001B97AD /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                FC8A8B1114B648D7001B97AD /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                        ENABLE_SHA1,
                                        ENABLE_SHA256,
                                );
                                        ENABLE_SHA1,
                                        ENABLE_SHA256,
                                );
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
                                INSTALL_PATH = /usr/sbin;
                                "OTHER_LDFLAGS[sdk=macosx*]" = "-lCrashReporterClient";
                        };
                                INSTALL_PATH = /usr/sbin;
                                "OTHER_LDFLAGS[sdk=macosx*]" = "-lCrashReporterClient";
                        };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
                        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 = (
                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
  */
 
  *     @(#)pathnames.h 8.1 (Berkeley) 6/6/93
  */
 
+#ifndef _INSTALL_PATHNAMES_H_
+#define _INSTALL_PATHNAMES_H_
+
 #define        _PATH_STRIP     "/usr/bin/strip"
 #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 $
 .\"
 .\"    @(#)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
 .Dt LN 1
 .Os
 .Sh NAME
 .Nm ln
 .Op Fl Ffhinsv
 .Ar source_file
 .Nm ln
 .Op Fl Ffhinsv
 .Ar source_file
-.Op Ar target_file
+.Op Ar link_name
 .Nm ln
 .Op Fl Ffhinsv
 .Ar source_file ...
 .Nm ln
 .Op Fl Ffhinsv
 .Ar source_file ...
-.Ar target_dir
+.Ar link_dirname
 .Nm link
 .Nm link
-.Ar source_file Ar target_file
+.Ar source_file Ar link_name
 .Sh DESCRIPTION
 The
 .Nm ln
 .Sh DESCRIPTION
 The
 .Nm ln
@@ -70,7 +70,7 @@ The options are as follows:
 .Bl -tag -width flag
 .\" ==========
 .It Fl F
 .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
 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
 option is specified.
 .It Fl h
 If the
-.Ar target_file
+.Ar link_name
 or
 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
 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
 then unlink it so that the link may occur.
 (The
 .Fl f
@@ -109,12 +109,12 @@ options.)
 .It Fl i
 Cause
 .Nm ln
 .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 ,
 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
 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
 creates a link to an existing file
 .Ar source_file .
 If
-.Ar target_file
+.Ar link_name
 is given, the link has that 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
 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
 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
 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(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);
 }
        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 $
  */
 
  * $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 *);
 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
 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        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 **);
 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
 
        /*
 #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.
         */
         * 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
 #ifdef COLORLS
            && !f_color
 #endif
@@ -560,6 +562,11 @@ traverse(int argc, char *argv[], int options)
                                break;
                        }
 
                                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
                        /*
                         * 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 = ' ';
                                }
                                } else {
                                        np->mode_suffix = ' ';
                                }
-                               if (f_dataless && (sp->st_flags & SF_DATALESS)) {
+                               if (IS_DATALESS(sp)) {
                                        np->mode_suffix = '%';
                                }
                                if (!f_acl) {
                                        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 $
  */
 
  * $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 */
 #define NO_PRINT       1
 
 extern long blocksize;         /* block size units */
@@ -101,3 +104,5 @@ typedef struct {
 #endif /* __APPLE__ */
        char data[1];
 } NAMES;
 #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 <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 "commoncrypto.h"
+#include "extern.h"
+#include "metrics.h"
 
 const int kSHA256NullTerminatedBuffLen = 65;
 static const char hex[] = "0123456789abcdef";
 
 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; 
        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);
                }
                (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;
 
                if (error != 0) {
                        s_error = error;
+                       RECORD_FAILURE(27441, s_error);
                }
        });
        dispatch_release(io); // it will close on its own
                }
        });
        dispatch_release(io); // it will close on its own
@@ -94,11 +101,28 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
        return 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);
        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);
                
        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;
                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);
                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);
                        }
                        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)
                        
                        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);
                        }
                                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);
                }
                
                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);
                digest = SHA256_Data(xattrsSummary, strlen(xattrsSummary) * sizeof(char), buf);
                if (!digest)
                        err(1, "%s", xattrsSummary);
+
+               ai->digest = digest;
                
                free(xattrsSummary);
                
                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)
 {
 }
 
 char *SHA256_Path_ACL(char *path, char *buf)
 {
+       errno_t error           = 0;
        int result              = 0;
        char *data              = NULL;
        char *digest            = NULL;
        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);
        
        
        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 ) )
        
        // 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;
 }
 
        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"
 #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)
 
 #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 *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 <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>
 #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 <unistd.h>
 #include <vis.h>
 
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.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"; \
        }
 
                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
 compare(char *name __unused, NODE *s, FTSENT *p)
 {
+       int error = 0;
        struct timeval tv[2];
        uint32_t val;
        int fd, label;
        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:
        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;
                        goto typeerr;
+               }
                break;
        case F_CHAR:
                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;
                        goto typeerr;
+               }
                break;
        case F_DIR:
                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;
                        goto typeerr;
+               }
                break;
        case F_FIFO:
                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;
                        goto typeerr;
+               }
                break;
        case F_FILE:
                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;
                        goto typeerr;
+               }
                break;
        case F_LINK:
                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;
                        goto typeerr;
+               }
                break;
        case F_SOCK:
                if (!S_ISSOCK(p->fts_statp->st_mode)) {
                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));
 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);
                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",
                                (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
+                                   strerror(error));
+                       } else {
                                (void)printf(" modified\n");
                                (void)printf(" modified\n");
-               else
+                       }
+               } else {
                        (void)printf("\n");
                        (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);
                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",
                                (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
+                                   strerror(error));
+                       } else {
                                (void)printf(" modified\n");
                                (void)printf(" modified\n");
-               else
+                       }
+               } else {
                        (void)printf("\n");
                        (void)printf("\n");
+               }
                tab = "\t";
        }
        if (s->flags & F_MODE &&
                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);
                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",
                                (void)printf(" not modified: %s\n",
-                                   strerror(errno));
-                       else
+                                   strerror(error));
+                       } else {
                                (void)printf(" modified\n");
                                (void)printf(" modified\n");
-               else
+                       }
+               } else {
                        (void)printf("\n");
                        (void)printf("\n");
+               }
                tab = "\t";
        }
        if (s->flags & F_NLINK && s->type != F_DIR &&
                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))) {
        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;
        }
        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",
                        (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;
                        tab = "\t";
                } else if (crc(fd, &val, &len)) {
                        (void)close(fd);
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(14, error);
                        (void)printf("%scksum: %s: %s\n",
                        (void)printf("%scksum: %s: %s\n",
-                           tab, p->fts_accpath, strerror(errno));
+                           tab, p->fts_accpath, strerror(error));
                        tab = "\t";
                } else {
                        (void)close(fd);
                        tab = "\t";
                } else {
                        (void)close(fd);
@@ -245,26 +358,37 @@ typeerr:          LABEL;
                        (void)printf(" found \"%s\"", fflags);
                        free(fflags);
                        
                        (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",
                                        (void)printf(" not modified: %s\n",
-                                                    strerror(errno));
-                               else
+                                                    strerror(error));
+                               } else {
                                        (void)printf(" modified\n");
                                        (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];
                        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);
                new_digest = MD5File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
                if (!new_digest) {
                        LABEL;
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(16, error);
                        printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
                        printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
-                              strerror(errno));
+                              strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->md5digest)) {
                        LABEL;
                        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 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);
                new_digest = SHA1_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
                if (!new_digest) {
                        LABEL;
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(17, error);
                        printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
                        printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
-                              strerror(errno));
+                              strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->sha1digest)) {
                        LABEL;
                        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 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);
                new_digest = RIPEMD160_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
                if (!new_digest) {
                        LABEL;
                if (!new_digest) {
                        LABEL;
+                       error = errno;
+                       RECORD_FAILURE(18, error);
                        printf("%sRIPEMD160: %s: %s\n", tab,
                        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;
                        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;
                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,
                        printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
-                              strerror(errno));
+                              strerror(error));
                        tab = "\t";
                } else if (strcmp(new_digest, s->sha256digest)) {
                        LABEL;
                        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))) {
        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))) {
            }
        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))) {
            }
        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;
            }
        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",
                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";
                        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) {
                }
        }
        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)) {
        }
        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];
        }
        if (s->flags & F_ACL) {
                char *new_digest, buf[kSHA256NullTerminatedBuffLen];
@@ -418,6 +604,21 @@ typeerr:           LABEL;
                        tab = "\t";
                }
        }
                        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);
 }
        
        return (label);
 }
@@ -473,11 +674,15 @@ ftype(u_int type)
 char *
 rlink(char *name)
 {
 char *
 rlink(char *name)
 {
+       int error = 0;
        static char lbuf[MAXPATHLEN];
        ssize_t len;
 
        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);
 }
        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 <time.h>
 #include <unistd.h>
 #include <vis.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.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_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     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)
 {
 static void    statf(int, FTSENT *);
 
 void
 cwalk(void)
 {
+       int error = 0;
        FTS *t;
        FTSENT *p;
        time_t cl;
        FTS *t;
        FTSENT *p;
        time_t cl;
@@ -109,8 +112,11 @@ cwalk(void)
 
        argv[0] = dot;
        argv[1] = NULL;
 
        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;
        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);
                        }
                                (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:
                        statf(indent, p);
                        break;
                case FTS_DP:
@@ -153,13 +159,16 @@ cwalk(void)
                }
        }
        (void)fts_close(t);
                }
        }
        (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);
                warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+       }
 }
 
 static void
 statf(int indent, FTSENT *p)
 {
 }
 
 static void
 statf(int indent, FTSENT *p)
 {
+       int error = 0;
        struct group *gr;
        struct passwd *pw;
        uint32_t val;
        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);
        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");
                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))
        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 (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);
                                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);
                                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);
                                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);
                }
                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 (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);
                                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);
                                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);
                                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);
                }
                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_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 ||
        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];
                (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);
                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];
                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);
                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];
                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);
                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 */
                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);
                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 */
                output(indent, &offset, "sha256digest=%s", digest);
        }
 #endif /* ENABLE_SHA256 */
@@ -290,38 +345,69 @@ statf(int indent, FTSENT *p)
                free(fflags);
        }
        if (keys & F_BTIME) {
                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)) {
        }
        // 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) {
        }
        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);
        }
        // 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) {
                        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) {
                }
        }
        if (keys & F_INODE) {
@@ -335,6 +421,11 @@ statf(int indent, FTSENT *p)
                        output(indent, &offset, "acldigest=%s", digest);
                }
        }
                        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');
 }
        
        (void)putchar('\n');
 }
@@ -346,8 +437,9 @@ statf(int indent, FTSENT *p)
 #define        MAXS 16
 
 static int
 #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;
        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_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) {
        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);
        }
 
                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);
                        (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);
                                (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);
                                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);
                                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 (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);
                                (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);
                                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);
                                errx(1, "Could not get gname for gid=%u", savegid);
+                       }
                }
                if (keys & F_GID)
                        (void)printf(" gid=%lu", (u_long)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)
                        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");
                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;
                *pflags = saveflags;
                *pxattrs = savexattrs;
                *pacl = saveacl;
+               *xdstream_id = savexdstream_id;
        }
        return (0);
 }
        }
        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>
 __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 <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 <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"
 
 /*
 #include "extern.h"
 
 /*
@@ -81,8 +81,10 @@ read_excludes_file(const char *name)
 
                str = malloc(len + 1);
                e = malloc(sizeof *e);
 
                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");
                        errx(1, "memory allocation error");
+               }
                e->glob = str;
                memcpy(str, line, len);
                str[len] = '\0';
                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 $
  */
  *     @(#)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_
 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 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
 #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>
 #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>
 __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 <stdint.h>
 #include <stdio.h>
 #include <unistd.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 #import <sys/attr.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
 #ifdef ENABLE_SHA256
        {"sha256digest",        F_SHA256,       NEEDVALUE},
 #endif
+       {"siblingid",           F_SIBLINGID,    NEEDVALUE},
        {"size",                F_SIZE,         NEEDVALUE},
        {"time",                F_TIME,         NEEDVALUE},
        {"type",                F_TYPE,         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);
        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);
                errx(1, "line %d: unknown keyword %s", lineno, name);
+       }
 
        if (needvaluep)
                *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
 
        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)
 {
 char *
 flags_to_string(u_long fflags)
 {
+       int error = 0;
        char *string;
 
        string = fflagstostr(fflags);
        char *string;
 
        string = fflagstostr(fflags);
@@ -126,8 +132,11 @@ flags_to_string(u_long fflags)
                free(string);
                string = strdup("none");
        }
                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;
 }
 
        return string;
 }
@@ -137,8 +146,10 @@ char *
 escape_path(char *string)
 {
        char *escapedPath = calloc(1, strlen(string) * 4  +  1);
 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");
                errx(1, "escape_path(): calloc() failed");
+       }
        strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
        
        return escapedPath;
        strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
        
        return escapedPath;
@@ -154,6 +165,7 @@ struct ptimebuf {
 struct timespec
 ptime(char *path, int *supported) {
        
 struct timespec
 ptime(char *path, int *supported) {
        
+       int error = 0;
        int ret = 0;
        struct ptimebuf buf;
        struct attrlist list = {
        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) {
        };
        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;
        }
        
        *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 <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>
 #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 <stdio.h>
 #include <stdint.h>
 #include <unistd.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
 #include "mtree.h"
 #include "extern.h"
 
+#define SECONDS_IN_A_DAY (60 * 60 * 24)
+
 int ftsoptions = FTS_PHYSICAL;
 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];
 u_int keys;
 char fullpath[MAXPATHLEN];
+CFMutableDictionaryRef dict;
+char *filepath;
 
 static void usage(void);
 
 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
 main(int argc, char *argv[])
 {
+       int error = 0;
        int ch;
        char *dir, *p;
        int status;
        FILE *spec1, *spec2;
        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;
 
        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;
                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");
                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");
                        } 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();
                                usage();
+                       }
                        break;
                case 'i':
                        iflag = 1;
                        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);
                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);
                                errx(1, "illegal seed value -- %s", optarg);
+                       }
                        break;
                case 'U':
                        Uflag = 1;
                        break;
                case 'U':
                        Uflag = 1;
@@ -152,32 +190,105 @@ main(int argc, char *argv[])
                case 'X':
                        read_excludes_file(optarg);
                        break;
                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:
                case '?':
                default:
+                       RECORD_FAILURE(92, WARN_USAGE);
                        usage();
                }
        argc -= optind;
 //     argv += optind;
 
                        usage();
                }
        argc -= optind;
 //     argv += optind;
 
-       if (argc)
+       if (argc) {
+               RECORD_FAILURE(93, WARN_USAGE);
                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);
                errx(1, "%s", fullpath);
+       }
+
+       if (dir) {
+               set_metric_path(dir);
+       }
 
        if (cflag) {
                cwalk();
                exit(0);
        }
 
        if (cflag) {
                cwalk();
                exit(0);
        }
-       if (spec2 != NULL)
+       if (spec2 != NULL) {
                status = mtree_specspec(spec1, spec2);
                status = mtree_specspec(spec1, spec2);
-       else
+               if (Uflag & (status == MISMATCHEXIT)) {
+                       status = 0;
+               } else {
+                       RECORD_FAILURE(99, status);
+               }
+       } else {
                status = mtree_verifyspec(spec1);
                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);
 }
 
        exit(status);
 }
 
@@ -189,3 +300,59 @@ usage(void)
 "\t[-X excludes]\n");
        exit(1);
 }
 "\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 $
  */
 
  * $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>
 
 #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 */
        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 */
        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 */
 
 #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_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 */
        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)
 #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 <stdint.h>
 #include <unistd.h>
 #include <vis.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
 #include "mtree.h"
 #include "extern.h"
 
@@ -74,8 +75,10 @@ mtree_readspec(FILE *fi)
                        continue;
 
                /* Find end of line. */
                        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);
                        errx(1, "line %d too long", lineno);
+               }
 
                /* See if next line is continuation line. */
                if (p[-1] == '\\') {
 
                /* See if next line is continuation line. */
                if (p[-1] == '\\') {
@@ -102,8 +105,10 @@ mtree_readspec(FILE *fi)
                }
 
                /* Grab file name, "$", "set", or "unset". */
                }
 
                /* 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);
                        errx(1, "line %d: missing field", lineno);
+               }
 
                if (p[0] == '/')
                        switch(p[1]) {
 
                if (p[0] == '/')
                        switch(p[1]) {
@@ -119,9 +124,11 @@ mtree_readspec(FILE *fi)
                                continue;
                        }
 
                                continue;
                        }
 
-               if (index(p, '/'))
+               if (index(p, '/')) {
+                       RECORD_FAILURE(23, EINVAL);
                        errx(1, "line %d: slash character in file name",
                        lineno);
                        errx(1, "line %d: slash character in file name",
                        lineno);
+               }
 
                if (!strcmp(p, "..")) {
                        /* Don't go up, if haven't gone down. */
 
                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;
 
                        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");
                        errx(1, "calloc");
+               }
                *centry = ginfo;
 #define        MAGIC   "?*["
                if (strpbrk(p, MAGIC))
                        centry->flags |= F_MAGIC;
                *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);
                        errx(1, "filename %s is ill-encoded", p);
+               }
                set(NULL, centry);
 
                if (!root) {
                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)
 {
 static void
 set(char *t, NODE *ip)
 {
+       int error = 0;
        int type;
        char *kw, *val = NULL;
        struct group *gr;
        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);
 
        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);
                        errx(1, "line %d: missing value", lineno);
+               }
                switch(type) {
                        case F_CKSUM:
                                ip->cksum = strtoul(val, &ep, 10);
                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);
                                        errx(1, "line %d: invalid checksum %s",
                                             lineno, val);
+                               }
                                break;
                        case F_MD5:
                                ip->md5digest = strdup(val);
                                break;
                        case F_MD5:
                                ip->md5digest = strdup(val);
-                               if(!ip->md5digest)
+                               if (!ip->md5digest) {
+                                       RECORD_FAILURE(29, ENOMEM);
                                        errx(1, "strdup");
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_SHA1:
                                ip->sha1digest = strdup(val);
                                break;
                        case F_SHA1:
                                ip->sha1digest = strdup(val);
-                               if(!ip->sha1digest)
+                               if (!ip->sha1digest) {
+                                       RECORD_FAILURE(30, ENOMEM);
                                        errx(1, "strdup");
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_SHA256:
                                ip->sha256digest = strdup(val);
                                break;
                        case F_SHA256:
                                ip->sha256digest = strdup(val);
-                               if(!ip->sha256digest)
+                               if (!ip->sha256digest) {
+                                       RECORD_FAILURE(31, ENOMEM);
                                        errx(1, "strdup");
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_RMD160:
                                ip->rmd160digest = strdup(val);
                                break;
                        case F_RMD160:
                                ip->rmd160digest = strdup(val);
-                               if(!ip->rmd160digest)
+                               if (!ip->rmd160digest) {
+                                       RECORD_FAILURE(32, ENOMEM);
                                        errx(1, "strdup");
                                        errx(1, "strdup");
+                               }
                                break;
                        case F_FLAGS:
                                break;
                        case F_FLAGS:
-                               if (strcmp("none", val) == 0)
+                               if (strcmp("none", val) == 0) {
                                        ip->st_flags = 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);
                                        errx(1, "line %d: invalid flag %s",lineno, val);
+                               }
                                break;
                        case F_GID:
                                ip->st_gid = (gid_t)strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid gid %s", lineno, val);
+                               }
                                break;
                        case F_GNAME:
                                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);
                                        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:
                                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);
                                        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);
                                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);
                                        errx(1, "line %d: invalid link count %s",
                                             lineno,  val);
+                               }
                                break;
                        case F_SIZE:
                                ip->st_size = strtoq(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid size %s",
                                             lineno, val);
+                               }
                                break;
                        case F_SLINK:
                                ip->slink = malloc(strlen(val) + 1);
                                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");
                                        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);
                                        errx(1, "symlink %s is ill-encoded", val);
+                               }
                                break;
                        case F_TIME:
                                ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_TYPE:
                                switch(*val) {
                                break;
                        case F_TYPE:
                                switch(*val) {
@@ -290,78 +335,127 @@ set(char *t, NODE *ip)
                                                        ip->type = F_SOCK;
                                                break;
                                        default:
                                                        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);
                                                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);
                                        errx(1, "line %d: invalid uid %s", lineno, val);
+                               }
                                break;
                        case F_UNAME:
                                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);
                                        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);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_birthtimespec.tv_nsec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_ATIME:
                                ip->st_atimespec.tv_sec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_atimespec.tv_nsec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_CTIME:
                                ip->st_ctimespec.tv_sec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_ctimespec.tv_nsec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_PTIME:
                                ip->st_ptimespec.tv_sec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                val = ep + 1;
                                ip->st_ptimespec.tv_nsec = strtoul(val, &ep, 10);
                                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);
                                        errx(1, "line %d: invalid time %s",
                                             lineno, val);
+                               }
                                break;
                        case F_XATTRS:
                                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);
                                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);
                                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 <stdio.h>
 #include <stdint.h>
 #include <unistd.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.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)
        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_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");
 }
        
        printf("\n");
 }
@@ -143,14 +146,17 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
                return 0;
        } else if (n1 == NULL) {
                differs = n2->flags;
                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;
                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;
                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);
        }
                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;
                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) {
        
        if (differs) {
+               RECORD_FAILURE(114, WARN_MISMATCH);
                mismatch(n1, n2, differs, path);
                return (1);
        }
                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)
 {
 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;
 
        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 (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);
                        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);
                } 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);
                        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);
                } 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);
                } 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);
                        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);
                } else {
                        i = compare_nodes(c1, c2, path);
+                       if (i) {
+                               RECORD_FAILURE(122, WARN_MISMATCH);
+                       }
                }
                r += i;
                c1 = n1;
                }
                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, "");
        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 (MISMATCHEXIT);
+       }
        return (0);
 }
        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 <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];
 
 #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;
 static int     vwalk(void);
 
 int
 mtree_verifyspec(FILE *fi)
 {
        int rval, mval;
+       size_t path_length = 0;
 
        root = mtree_readspec(fi);
        rval = vwalk();
 
        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;
                return rval;
-       else
+       } else {
+               RECORD_FAILURE(61, WARN_MISMATCH);
                return mval;
                return mval;
+       }
 }
 
 static int
 vwalk(void)
 {
 }
 
 static int
 vwalk(void)
 {
+       int error = 0;
        FTS *t;
        FTSENT *p;
        NODE *ep, *level;
        FTS *t;
        FTSENT *p;
        NODE *ep, *level;
@@ -81,8 +88,11 @@ vwalk(void)
 
        argv[0] = dot;
        argv[1] = NULL;
 
        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))) {
        level = root;
        specdepth = rval = 0;
        while ((p = fts_read(t))) {
@@ -96,6 +106,7 @@ vwalk(void)
                        break;
                case FTS_DP:
                        if (level == NULL) {
                        break;
                case FTS_DP:
                        if (level == NULL) {
+                               RECORD_FAILURE(63, EINVAL);
                                errx(1 , "invalid root in vwalk");
                        }
                        if (specdepth > p->fts_level) {
                                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 &&
                            !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;
                                        rval = MISMATCHEXIT;
+                               }
                                if (ep->flags & F_IGN)
                                        (void)fts_set(t, p, FTS_SKIP);
                                else if (ep->child && ep->type == F_DIR &&
                                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));
 extra:
                if (!eflag) {
                        (void)printf("%s extra", RP(p));
+
                        if (rflag) {
                        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);
                        }
                        (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);
                warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+       }
        return (rval);
 }
 
 static int
        return (rval);
 }
 
 static int
-miss(NODE *p, char *tail)
+miss(NODE *p, char *tail, size_t path_length)
 {
        int create;
        char *tp;
 {
        int create;
        char *tp;
@@ -166,10 +214,17 @@ miss(NODE *p, char *tail)
        int serr;
        int rval = 0;
        int rrval = 0;
        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;
 
        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
                (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);
                                p->flags |= F_VISIT;
                        } else {
                                (void)printf("%s missing", path);
+                               RECORD_FAILURE(68, WARN_MISMATCH);
                                rval = MISMATCHEXIT;
                        }
                }
                                rval = MISMATCHEXIT;
                        }
                }
@@ -194,16 +250,19 @@ miss(NODE *p, char *tail)
                else
                        type = "directory";
                if (!(p->flags & F_VISIT) && uflag) {
                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);
                                (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);
                                (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",
                                        (void)printf(" (symlink not created: %s)\n",
-                                           strerror(errno));
-                               else
+                                           strerror(serr));
+                               } else {
                                        (void)printf(" (created)\n");
                                        (void)printf(" (created)\n");
+                               }
                                if (lchown(path, p->st_uid, p->st_gid) == -1) {
                                        serr = errno;
                                        if (p->st_uid == (uid_t)-1)
                                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;
                                        }
                                                what = "user";
                                                errno = serr;
                                        }
+                                       serr = errno;
+                                       RECORD_FAILURE(70, serr);
                                        (void)printf("%s: %s not modified: %s"
                                        (void)printf("%s: %s not modified: %s"
-                                           "\n", path, what, strerror(errno));
+                                           "\n", path, what, strerror(serr));
                                }
                                continue;
                                }
                                continue;
-                       } else if (!(p->flags & F_MODE))
+                       } else if (!(p->flags & F_MODE)) {
                            (void)printf(" (directory not created: mode not specified)");
                            (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)",
                                (void)printf(" (directory not created: %s)",
-                                   strerror(errno));
-                       else {
+                                   strerror(serr));
+                       else {
                                create = 1;
                                (void)printf(" (created)");
                        }
                                create = 1;
                                (void)printf(" (created)");
                        }
@@ -234,9 +297,13 @@ miss(NODE *p, char *tail)
 
                for (tp = tail; *tp; ++tp);
                *tp = '/';
 
                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;
                        rval = rrval;
+               }
+               path_length -= (file_name_length + 1);
                *tp = '\0';
 
                if (!create)
                *tp = '\0';
 
                if (!create)
@@ -251,16 +318,24 @@ miss(NODE *p, char *tail)
                                what = "user";
                                errno = serr;
                        }
                                what = "user";
                                errno = serr;
                        }
+                       serr = errno;
+                       RECORD_FAILURE(73, serr);
                        (void)printf("%s: %s not modified: %s\n",
                        (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",
                        (void)printf("%s: permissions not set: %s\n",
-                           path, strerror(errno));
+                           path, strerror(serr));
+               }
                if ((p->flags & F_FLAGS) && p->st_flags &&
                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",
                        (void)printf("%s: file flags not set: %s\n",
-                           path, strerror(errno));
+                           path, strerror(serr));
+               }
        }
        return rval;
 }
        }
        return rval;
 }
index 514678ff264ea9d15f5c392df4baa69a464d29c0..fe1d6cd765067ebe43daa684d9b04af08bda3d6b 100644 (file)
  * $FreeBSD: src/bin/mv/pathnames.h,v 1.6 2002/05/17 11:38:48 jmallett Exp $
  */
 
  * $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__ */
 #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
  */
 
  *      @(#)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
 /*
  * 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;
        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
  */
 
  *     @(#)cpio.h      8.1 (Berkeley) 5/31/93
  */
 
+#ifndef _CPIO_H_
+#define _CPIO_H_
+
 /*
  * Defines common to all versions of cpio
  */
 /*
  * 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_ */
 #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
  */
 
  *     @(#)extern.h    8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _PAX_EXTERN_H_
+#define _PAX_EXTERN_H_
+
 /*
  * External references from each source file
  */
 /*
  * 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 *, ...);
 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
  */
 
  *     @(#)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
 /*
  * 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;
        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)
 {
 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))) {
         */
        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);
        }
        } else {
                (void)fputs(str, fp);
        }
index 873d8d559671bb2daedc6b65f6224b2793ec03fd..89eeaa5ff04f209679e5a1add8dc1e451def1244 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)options.h   8.2 (Berkeley) 4/18/94
  */
 
  *     @(#)options.h   8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _OPTIONS_H_
+#define _OPTIONS_H_
+
 /*
  * argv[0] names. Used for tar and cpio emulation
  */
 /*
  * 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)
 #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 **);
 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 *);
 
 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;
 {
        char c;
        char test;
+#ifdef _HAVE_REGCOMP_
+       char *equiv_pat;
+       char *pat_pend = NULL;
+#endif
 
        *pend = NULL;
        for (;;) {
 
        *pend = NULL;
        for (;;) {
@@ -549,10 +557,33 @@ fn_match(char *pattern, char *string, char **pend)
                        /*
                         * range match
                         */
                        /*
                         * 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;
                        if (((test = *string++) == '\0') ||
                            ((pattern = range_match(pattern, test)) == NULL))
                                return (-1);
                        break;
+
                case '\\':
                default:
                        if (c != *string++)
                case '\\':
                default:
                        if (c != *string++)
@@ -563,6 +594,124 @@ fn_match(char *pattern, char *string, char **pend)
        /* NOTREACHED */
 }
 
        /* 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)
 {
 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
  */
 
  *     @(#)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)
  */
 /*
  * 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 */
 } 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 <err.h>
 #include <fcntl.h>
 #include <paths.h>
+#include <locale.h>
 #include "pax.h"
 #include "extern.h"
 static int gen_init(void);
 #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;
 {
        char *tmpdir;
        size_t tdlen;
+#ifdef _HAVE_REGCOMP_
+       setlocale(LC_CTYPE, "");
+       setlocale(LC_COLLATE, "");
+#endif
 
        listf = stderr;
        /*
 
        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
  */
 
  *     @(#)pax.h       8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _PAX_H_
+#define _PAX_H_
+
 /*
  * BSD PAX global data structures and constants.
  */
 /*
  * BSD PAX global data structures and constants.
  */
@@ -246,4 +249,7 @@ typedef struct oplist {
 #define HEX            16
 #define OCT            8
 #define _PAX_          1
 #define HEX            16
 #define OCT            8
 #define _PAX_          1
+#define _HAVE_REGCOMP_ 1
 #define _TFILE_BASE    "paxXXXXXXXXXX"
 #define _TFILE_BASE    "paxXXXXXXXXXX"
+
+#endif /* _PAX_H_ */
index 506ce5818c429e141e4c99679d7b5d2243a05c62..4ac409435dd594881f6417035f7a8496c8447977 100644 (file)
@@ -36,6 +36,9 @@
  *     @(#)tar.h       8.2 (Berkeley) 4/18/94
  */
 
  *     @(#)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
  */
 /*
  * 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;
        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
  */
 
  *     @(#)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)
  */
 /*
  * 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;
 #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
  */
 
  *     @(#)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
  */
 /*
  * 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;
        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
  */
 
  *     @(#)tar.h       8.2 (Berkeley) 4/18/94
  */
 
+#ifndef _TAR_H_
+#define _TAR_H_
+
 /*
  * defines and data structures common to all tar formats
  */
 /*
  * 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;
        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__
                        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);
                                        rval = rmdir(p->fts_accpath);
+                               }
 #else
 #else
-
                                rval = rmdir(p->fts_accpath);
 #endif
                                if (rval == 0 || (fflag && errno == ENOENT)) {
                                rval = rmdir(p->fts_accpath);
 #endif
                                if (rval == 0 || (fflag && errno == ENOENT)) {