mirror of
https://github.com/darlinghq/darling-file_cmds.git
synced 2024-11-26 20:50:38 +00:00
Update Source To file_cmds-321.100.11
This commit is contained in:
parent
bfd92c440e
commit
390e64e423
@ -31,6 +31,9 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _CHMOD_ACL_H_
|
||||
#define _CHMOD_ACL_H_
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
@ -83,3 +86,5 @@ extern int modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
|
||||
extern int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow);
|
||||
extern uuid_t *name_to_uuid(char *tok, int nametype);
|
||||
#endif /* __APPLE__*/
|
||||
|
||||
#endif /* _CHMOD_ACL_H_ */
|
||||
|
@ -84,11 +84,6 @@ const char *gname;
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
#ifdef DARLING
|
||||
// file ownership is pretty much a no-op under Darling at the moment,
|
||||
// so let's just silently pretend that chown/chgrp always succeeds
|
||||
return 0;
|
||||
#else
|
||||
FTS *ftsp;
|
||||
FTSENT *p;
|
||||
int Hflag, Lflag, Pflag, Rflag, fflag, hflag, vflag;
|
||||
@ -253,7 +248,6 @@ main(int argc, char **argv)
|
||||
if (errno)
|
||||
err(1, "fts_read");
|
||||
exit(rval);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -34,6 +34,9 @@
|
||||
* $FreeBSD: src/usr.bin/cksum/extern.h,v 1.6 2003/03/13 23:32:28 robert Exp $
|
||||
*/
|
||||
|
||||
#ifndef _CKSUM_EXTERN_H_
|
||||
#define _CKSUM_EXTERN_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
@ -45,3 +48,5 @@ int csum1(int, uint32_t *, off_t *);
|
||||
int csum2(int, uint32_t *, off_t *);
|
||||
int crc32(int, uint32_t *, off_t *);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _CKSUM_EXTERN_H_ */
|
||||
|
@ -46,6 +46,7 @@ __FBSDID("$FreeBSD: src/usr.bin/compress/compress.c,v 1.23 2010/12/11 08:32:16 j
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/attr.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
@ -382,14 +383,21 @@ err: if (ofp) {
|
||||
void
|
||||
setfile(const char *name, struct stat *fs)
|
||||
{
|
||||
static struct timeval tv[2];
|
||||
struct attrlist ts_req = {};
|
||||
struct {
|
||||
struct timespec mtime;
|
||||
struct timespec atime;
|
||||
} set_ts;
|
||||
|
||||
fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
|
||||
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
|
||||
if (utimes(name, tv))
|
||||
cwarn("utimes: %s", name);
|
||||
ts_req.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
ts_req.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME;
|
||||
set_ts.mtime = fs->st_mtimespec;
|
||||
set_ts.atime = fs->st_atimespec;
|
||||
|
||||
if (setattrlist(name, &ts_req, &set_ts, sizeof(set_ts), 0))
|
||||
cwarn("setattrlist: %s", name);
|
||||
|
||||
/*
|
||||
* Changing the ownership probably won't succeed, unless we're root
|
||||
|
@ -30,6 +30,9 @@
|
||||
* $FreeBSD: src/bin/cp/extern.h,v 1.20 2005/09/05 04:36:08 csjp Exp $
|
||||
*/
|
||||
|
||||
#ifndef _CP_EXTERN_H_
|
||||
#define _CP_EXTERN_H_
|
||||
|
||||
typedef struct {
|
||||
char *p_end; /* pointer to NULL at end of path */
|
||||
char *target_end; /* pointer to end of target base */
|
||||
@ -54,3 +57,5 @@ int preserve_dir_acls(struct stat *, char *, char *);
|
||||
int preserve_fd_acls(int, int);
|
||||
void usage(void);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _CP_EXTERN_H_ */
|
||||
|
50
cp/utils.c
50
cp/utils.c
@ -69,10 +69,22 @@ __FBSDID("$FreeBSD: src/bin/cp/utils.c,v 1.46 2005/09/05 04:36:08 csjp Exp $");
|
||||
#include "extern.h"
|
||||
#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y))
|
||||
|
||||
/* Memory strategy threshold, in pages: if physmem is larger then this, use a
|
||||
* large buffer */
|
||||
#define PHYSPAGES_THRESHOLD (32*1024)
|
||||
|
||||
/* Maximum buffer size in bytes - do not allow it to grow larger than this */
|
||||
#define BUFSIZE_MAX (2*1024*1024)
|
||||
|
||||
/* Small (default) buffer size in bytes. It's inefficient for this to be
|
||||
* smaller than MAXPHYS */
|
||||
#define BUFSIZE_SMALL (MAXPHYS)
|
||||
|
||||
int
|
||||
copy_file(const FTSENT *entp, int dne)
|
||||
{
|
||||
static char buf[MAXBSIZE];
|
||||
static char *buf = NULL;
|
||||
static size_t bufsize;
|
||||
struct stat *fs;
|
||||
int ch, checkch, from_fd, rval, to_fd;
|
||||
ssize_t rcount;
|
||||
@ -258,8 +270,23 @@ copy_file(const FTSENT *entp, int dne)
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (buf == NULL) {
|
||||
/*
|
||||
* Note that buf and bufsize are static. If
|
||||
* malloc() fails, it will fail at the start
|
||||
* and not copy only some files.
|
||||
*/
|
||||
if (sysconf(_SC_PHYS_PAGES) >
|
||||
PHYSPAGES_THRESHOLD)
|
||||
bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
|
||||
else
|
||||
bufsize = BUFSIZE_SMALL;
|
||||
buf = malloc(bufsize);
|
||||
if (buf == NULL)
|
||||
err(1, "Not enough memory");
|
||||
}
|
||||
wtotal = 0;
|
||||
while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
|
||||
while ((rcount = read(from_fd, buf, bufsize)) > 0) {
|
||||
for (bufp = buf, wresid = rcount; ;
|
||||
bufp += wcount, wresid -= wcount) {
|
||||
wcount = write(to_fd, bufp, wresid);
|
||||
@ -382,19 +409,28 @@ copy_special(struct stat *from_stat, int exists)
|
||||
int
|
||||
setfile(struct stat *fs, int fd)
|
||||
{
|
||||
static struct timeval tv[2];
|
||||
struct attrlist ts_req = {};
|
||||
struct stat ts;
|
||||
int rval, gotstat, islink, fdval;
|
||||
struct {
|
||||
struct timespec mtime;
|
||||
struct timespec atime;
|
||||
} set_ts;
|
||||
|
||||
rval = 0;
|
||||
fdval = fd != -1;
|
||||
islink = !fdval && S_ISLNK(fs->st_mode);
|
||||
fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
unsigned int options = islink ? FSOPT_NOFOLLOW : 0;
|
||||
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
|
||||
if (fdval ? futimes(fd, tv) : (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv))) {
|
||||
warn("%sutimes: %s", fdval ? "f" : (islink ? "l" : ""), to.p_path);
|
||||
ts_req.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
ts_req.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME;
|
||||
set_ts.mtime = fs->st_mtimespec;
|
||||
set_ts.atime = fs->st_atimespec;
|
||||
|
||||
if (fdval ? fsetattrlist(fd, &ts_req, &set_ts, sizeof(set_ts), options) :
|
||||
setattrlist(to.p_path, &ts_req, &set_ts, sizeof(set_ts), options)) {
|
||||
warn("%ssetattrlist: %s", fdval ? "f" : "", to.p_path);
|
||||
rval = 1;
|
||||
}
|
||||
if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) :
|
||||
|
5
dd/dd.h
5
dd/dd.h
@ -38,6 +38,9 @@
|
||||
* $FreeBSD: src/bin/dd/dd.h,v 1.17 2002/02/22 20:51:00 markm Exp $
|
||||
*/
|
||||
|
||||
#ifndef _DD_H_
|
||||
#define _DD_H_
|
||||
|
||||
/* Input/output stream state. */
|
||||
typedef struct {
|
||||
u_char *db; /* buffer address */
|
||||
@ -95,3 +98,5 @@ typedef struct {
|
||||
#define C_UNBLOCK 0x80000
|
||||
#define C_OSYNC 0x100000
|
||||
#define C_SPARSE 0x200000
|
||||
|
||||
#endif /* _DD_H_ */
|
||||
|
@ -38,6 +38,9 @@
|
||||
* $FreeBSD: src/bin/dd/extern.h,v 1.12 2002/02/02 06:24:12 imp Exp $
|
||||
*/
|
||||
|
||||
#ifndef _DD_EXTERN_H_
|
||||
#define _DD_EXTERN_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
void block(void);
|
||||
@ -66,3 +69,5 @@ extern const u_char a2e_32V[], a2e_POSIX[];
|
||||
extern const u_char e2a_32V[], e2a_POSIX[];
|
||||
extern const u_char a2ibm_32V[], a2ibm_POSIX[];
|
||||
extern u_char casetab[];
|
||||
|
||||
#endif /* _DD_EXTERN_H_ */
|
||||
|
@ -19,6 +19,17 @@
|
||||
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" */;
|
||||
@ -100,6 +111,8 @@
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = FC8A8C8114B655ED001B97AD /* Build configuration list for PBXAggregateTarget "executables" */;
|
||||
buildPhases = (
|
||||
D178BEFA253DAE01001FC103 /* Copy plist */,
|
||||
D178BF21253DAE2E001FC103 /* Copy tests */,
|
||||
);
|
||||
dependencies = (
|
||||
FC8A8C8414B655FD001B97AD /* PBXTargetDependency */,
|
||||
@ -200,6 +213,12 @@
|
||||
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 */; };
|
||||
D178BEFB253DAE2A001FC103 /* file_cmds.plist in Copy plist */ = {isa = PBXBuildFile; fileRef = 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */; };
|
||||
D178BF22253DAE42001FC103 /* chgrp.sh in Copy tests */ = {isa = PBXBuildFile; fileRef = 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */; };
|
||||
D178BF48253DAE45001FC103 /* touch.sh in Copy tests */ = {isa = PBXBuildFile; fileRef = D11B5750253C22BD009A59BF /* touch.sh */; };
|
||||
D1B4221F25762FC8003E3A47 /* cp.sh in Copy tests */ = {isa = PBXBuildFile; fileRef = D1B421D325762E9E003E3A47 /* cp.sh */; };
|
||||
FC8A8A2814B6486E001B97AD /* chflags.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDCC14B6460C0070FACB /* chflags.c */; };
|
||||
FC8A8BE414B6494B001B97AD /* chflags.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDCB14B6460C0070FACB /* chflags.1 */; };
|
||||
FC8A8BE514B64958001B97AD /* chmod.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDD014B6460C0070FACB /* chmod.c */; };
|
||||
@ -311,6 +330,13 @@
|
||||
/* 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 */;
|
||||
@ -831,6 +857,30 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D178BEFA253DAE01001FC103 /* Copy plist */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
D178BEFB253DAE2A001FC103 /* file_cmds.plist in Copy plist */,
|
||||
);
|
||||
name = "Copy plist";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D178BF21253DAE2E001FC103 /* Copy tests */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /AppleInternal/Tests/file_cmds;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
D1B4221F25762FC8003E3A47 /* cp.sh in Copy tests */,
|
||||
D178BF48253DAE45001FC103 /* touch.sh in Copy tests */,
|
||||
D178BF22253DAE42001FC103 /* chgrp.sh in Copy tests */,
|
||||
);
|
||||
name = "Copy tests";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FC8A8B0F14B648D7001B97AD /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -1180,6 +1230,11 @@
|
||||
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>"; };
|
||||
D11B5750253C22BD009A59BF /* touch.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = touch.sh; sourceTree = "<group>"; };
|
||||
D1B421D325762E9E003E3A47 /* cp.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = cp.sh; sourceTree = "<group>"; };
|
||||
FC8A8B1214B648D7001B97AD /* chmod */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chmod; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FC8A8B1A14B648E0001B97AD /* chown */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chown; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FC8A8B2214B648E3001B97AD /* cksum */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cksum; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -1490,6 +1545,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
729D06D8230B5E42000716E5 /* CoreFoundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1567,10 +1623,20 @@
|
||||
children = (
|
||||
3E966CEB1FB2214F0019F7A1 /* chgrp.sh */,
|
||||
3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */,
|
||||
D11B5750253C22BD009A59BF /* touch.sh */,
|
||||
D1B421D325762E9E003E3A47 /* cp.sh */,
|
||||
);
|
||||
path = tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
729D06D6230B5E42000716E5 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
729D06D7230B5E42000716E5 /* CoreFoundation.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FCB1BDAD14B645D00070FACB = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1606,6 +1672,7 @@
|
||||
FCB1BE8614B6460C0070FACB /* touch */,
|
||||
FDAD94A71808BCB700B4D5A0 /* Libraries */,
|
||||
FCB1BDB914B645D10070FACB /* Products */,
|
||||
729D06D6230B5E42000716E5 /* Frameworks */,
|
||||
);
|
||||
indentWidth = 8;
|
||||
sourceTree = "<group>";
|
||||
@ -1870,6 +1937,8 @@
|
||||
FCB1BE4114B6460C0070FACB /* specspec.c */,
|
||||
FCB1BE4214B6460C0070FACB /* test */,
|
||||
FCB1BE4814B6460C0070FACB /* verify.c */,
|
||||
7D0A20E82499364700F0F6D7 /* metrics.h */,
|
||||
7D0A20E92499364700F0F6D7 /* metrics.c */,
|
||||
);
|
||||
path = mtree;
|
||||
sourceTree = "<group>";
|
||||
@ -2548,6 +2617,7 @@
|
||||
FC8A8CC814B65F92001B97AD /* uncompress */,
|
||||
FC8A8C5014B650CF001B97AD /* unlink */,
|
||||
3E966CE71FB2211F0019F7A1 /* tests */,
|
||||
729D07252347EC4D000716E5 /* macos_host_tools */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@ -2863,6 +2933,7 @@
|
||||
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 */,
|
||||
@ -2962,6 +3033,11 @@
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
729D074E2347EC4D000716E5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = FC8A8B8C14B648ED001B97AD /* mtree */;
|
||||
targetProxy = 729D074F2347EC4D000716E5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
FC8A8C4A14B64DE1001B97AD /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = FC8A8BC414B648EF001B97AD /* stat */;
|
||||
@ -3328,6 +3404,14 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
729D07692347EC4D000716E5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
INSTALL_PATH = /usr/bin;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
FC8A8B1114B648D7001B97AD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@ -3465,6 +3549,7 @@
|
||||
ENABLE_SHA1,
|
||||
ENABLE_SHA256,
|
||||
);
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
INSTALL_PATH = /usr/sbin;
|
||||
"OTHER_LDFLAGS[sdk=macosx*]" = "-lCrashReporterClient";
|
||||
};
|
||||
@ -3631,6 +3716,14 @@
|
||||
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 = (
|
||||
|
@ -33,4 +33,9 @@
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#ifndef _INSTALL_PATHNAMES_H_
|
||||
#define _INSTALL_PATHNAMES_H_
|
||||
|
||||
#define _PATH_STRIP "/usr/bin/strip"
|
||||
|
||||
#endif /* _INSTALL_PATHNAMES_H_ */
|
||||
|
26
ln/ln.1
26
ln/ln.1
@ -32,7 +32,7 @@
|
||||
.\" @(#)ln.1 8.2 (Berkeley) 12/30/93
|
||||
.\" $FreeBSD: src/bin/ln/ln.1,v 1.31 2006/02/14 11:08:05 glebius Exp $
|
||||
.\"
|
||||
.Dd February 14, 2006
|
||||
.Dd July 12, 2019
|
||||
.Dt LN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -43,13 +43,13 @@
|
||||
.Nm ln
|
||||
.Op Fl Ffhinsv
|
||||
.Ar source_file
|
||||
.Op Ar target_file
|
||||
.Op Ar link_name
|
||||
.Nm ln
|
||||
.Op Fl Ffhinsv
|
||||
.Ar source_file ...
|
||||
.Ar target_dir
|
||||
.Ar link_dirname
|
||||
.Nm link
|
||||
.Ar source_file Ar target_file
|
||||
.Ar source_file Ar link_name
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm ln
|
||||
@ -70,7 +70,7 @@ The options are as follows:
|
||||
.Bl -tag -width flag
|
||||
.\" ==========
|
||||
.It Fl F
|
||||
If the target file already exists and is a directory, then remove it
|
||||
If the proposed link (link_name) already exists and is a directory, then remove it
|
||||
so that the link may occur.
|
||||
The
|
||||
.Fl F
|
||||
@ -89,16 +89,16 @@ option is a no-op unless
|
||||
option is specified.
|
||||
.It Fl h
|
||||
If the
|
||||
.Ar target_file
|
||||
.Ar link_name
|
||||
or
|
||||
.Ar target_dir
|
||||
.Ar link_dirname
|
||||
is a symbolic link, do not follow it.
|
||||
This is most useful with the
|
||||
.Fl f
|
||||
option, to replace a symlink which may point to a directory.
|
||||
.\" ==========
|
||||
.It Fl f
|
||||
If the target file already exists,
|
||||
If the proposed link (link_name) already exists,
|
||||
then unlink it so that the link may occur.
|
||||
(The
|
||||
.Fl f
|
||||
@ -109,12 +109,12 @@ options.)
|
||||
.It Fl i
|
||||
Cause
|
||||
.Nm ln
|
||||
to write a prompt to standard error if the target file exists.
|
||||
to write a prompt to standard error if the proposed link exists.
|
||||
If the response from the standard input begins with the character
|
||||
.Sq Li y
|
||||
or
|
||||
.Sq Li Y ,
|
||||
then unlink the target file so that the link may occur.
|
||||
then unlink the proposed link so that the link may occur.
|
||||
Otherwise, do not attempt the link.
|
||||
(The
|
||||
.Fl i
|
||||
@ -168,9 +168,9 @@ Given one or two arguments,
|
||||
creates a link to an existing file
|
||||
.Ar source_file .
|
||||
If
|
||||
.Ar target_file
|
||||
.Ar link_name
|
||||
is given, the link has that name;
|
||||
.Ar target_file
|
||||
.Ar link_name
|
||||
may also be a directory in which to place the link;
|
||||
otherwise it is placed in the current directory.
|
||||
If only the directory is specified, the link will be made
|
||||
@ -180,7 +180,7 @@ to the last component of
|
||||
Given more than two arguments,
|
||||
.Nm ln
|
||||
makes links in
|
||||
.Ar target_dir
|
||||
.Ar link_dirname
|
||||
to all the named source files.
|
||||
The links made will have the same name as the files being linked to.
|
||||
.Pp
|
||||
|
6
ln/ln.c
6
ln/ln.c
@ -265,8 +265,8 @@ void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "%s\n%s\n%s\n",
|
||||
"usage: ln [-Ffhinsv] source_file [target_file]",
|
||||
" ln [-Ffhinsv] source_file ... target_dir",
|
||||
" link source_file target_file");
|
||||
"usage: ln [-Ffhinsv] source_file [link_name]",
|
||||
" ln [-Ffhinsv] source_file ... linkname_dir",
|
||||
" link source_file link_name");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -34,6 +34,9 @@
|
||||
* $FreeBSD: src/bin/ls/extern.h,v 1.19 2002/05/19 02:51:36 tjr Exp $
|
||||
*/
|
||||
|
||||
#ifndef _LS_EXTERN_H_
|
||||
#define _LS_EXTERN_H_
|
||||
|
||||
int acccmp(const FTSENT *, const FTSENT *);
|
||||
int revacccmp(const FTSENT *, const FTSENT *);
|
||||
int modcmp(const FTSENT *, const FTSENT *);
|
||||
@ -66,3 +69,5 @@ extern char *ansi_coloff;
|
||||
extern char *attrs_off;
|
||||
extern char *enter_bold;
|
||||
#endif
|
||||
|
||||
#endif /* _LS_EXTERN_H_ */
|
||||
|
13
ls/ls.c
13
ls/ls.c
@ -89,6 +89,8 @@ __RCSID("$FreeBSD: src/bin/ls/ls.c,v 1.66 2002/09/21 01:28:36 wollman Exp $");
|
||||
*/
|
||||
#define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1)
|
||||
|
||||
#define IS_DATALESS(sp) (f_dataless && (sp) && ((sp)->st_flags & SF_DATALESS))
|
||||
|
||||
static void display(FTSENT *, FTSENT *);
|
||||
static u_quad_t makenines(u_quad_t);
|
||||
static int mastercmp(const FTSENT **, const FTSENT **);
|
||||
@ -417,11 +419,11 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If not -F, -i, -l, -s or -t options, don't require stat
|
||||
* If not -F, -i, -l, -s, -t or -% options, don't require stat
|
||||
* information, unless in color mode in which case we do
|
||||
* need this to determine which colors to display.
|
||||
*/
|
||||
if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type && !f_sizesort
|
||||
if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type && !f_sizesort && !f_dataless
|
||||
#ifdef COLORLS
|
||||
&& !f_color
|
||||
#endif
|
||||
@ -560,6 +562,11 @@ traverse(int argc, char *argv[], int options)
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_DATALESS(p->fts_statp)) {
|
||||
fts_set(ftsp, p, FTS_SKIP);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If already output something, put out a newline as
|
||||
* a separator. If multiple arguments, precede each
|
||||
@ -851,7 +858,7 @@ display(FTSENT *p, FTSENT *list)
|
||||
} else {
|
||||
np->mode_suffix = ' ';
|
||||
}
|
||||
if (f_dataless && (sp->st_flags & SF_DATALESS)) {
|
||||
if (IS_DATALESS(sp)) {
|
||||
np->mode_suffix = '%';
|
||||
}
|
||||
if (!f_acl) {
|
||||
|
5
ls/ls.h
5
ls/ls.h
@ -37,6 +37,9 @@
|
||||
* $FreeBSD: src/bin/ls/ls.h,v 1.18 2002/05/19 02:51:36 tjr Exp $
|
||||
*/
|
||||
|
||||
#ifndef _LS_H_
|
||||
#define _LS_H_
|
||||
|
||||
#define NO_PRINT 1
|
||||
|
||||
extern long blocksize; /* block size units */
|
||||
@ -101,3 +104,5 @@ typedef struct {
|
||||
#endif /* __APPLE__ */
|
||||
char data[1];
|
||||
} NAMES;
|
||||
|
||||
#endif /* _LS_H_ */
|
||||
|
@ -10,8 +10,13 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/attr.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <sys/mount.h>
|
||||
#include <apfs/apfs_fsctl.h>
|
||||
|
||||
#include "commoncrypto.h"
|
||||
#include "extern.h"
|
||||
#include "metrics.h"
|
||||
|
||||
const int kSHA256NullTerminatedBuffLen = 65;
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
@ -52,6 +57,7 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
|
||||
io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
|
||||
if (error != 0) {
|
||||
s_error = error;
|
||||
RECORD_FAILURE(27440, s_error);
|
||||
}
|
||||
(void)close(fd);
|
||||
(void)dispatch_semaphore_signal(sema);
|
||||
@ -67,6 +73,7 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
|
||||
|
||||
if (error != 0) {
|
||||
s_error = error;
|
||||
RECORD_FAILURE(27441, s_error);
|
||||
}
|
||||
});
|
||||
dispatch_release(io); // it will close on its own
|
||||
@ -94,11 +101,29 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *SHA256_Path_XATTRs(char *path, char *buf)
|
||||
xattr_info *
|
||||
SHA256_Path_XATTRs(char *path, char *buf) {
|
||||
xattr_info *ai = NULL;
|
||||
|
||||
// mflag is passed during manifest comparision while xflag is used to generate the specification
|
||||
if (mflag || xflag) {
|
||||
ai = get_xdstream_privateid(path, buf);
|
||||
} else {
|
||||
ai = calculate_SHA256_XATTRs(path, buf);
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
|
||||
xattr_info *
|
||||
calculate_SHA256_XATTRs(char *path, char *buf)
|
||||
{
|
||||
errno_t error = 0;
|
||||
char *xattrsSummary = NULL;
|
||||
int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
|
||||
ssize_t nameBufSize = listxattr(path, NULL, 0, options);
|
||||
uint64_t xd_obj_id = 0;
|
||||
if (nameBufSize > 0) {
|
||||
char *nameBuf = malloc(nameBufSize);
|
||||
|
||||
@ -133,6 +158,8 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
|
||||
char *digest;
|
||||
ssize_t result = 0;
|
||||
char *oldSummary = NULL;
|
||||
//XXX Make xattr_info an array of structs if necessary
|
||||
xattr_info *ai = (xattr_info *) malloc(sizeof(xattr_info));
|
||||
for (int i = 0; i < xattrIndex; i++) {
|
||||
char *name = xattrs[i];
|
||||
ssize_t xlen = getxattr(path, name, NULL, 0, 0, options);
|
||||
@ -142,8 +169,11 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
|
||||
}
|
||||
bzero(xattrBuf, xattrBufLen);
|
||||
result = getxattr(path, name, xattrBuf, xattrBufLen, 0, options);
|
||||
if (result < 0)
|
||||
err(1, "SHA256_Path_XATTRs getxattr of \"%s\" at path \"%s\" failed with error", name, path );
|
||||
if (result < 0) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(27442, error);
|
||||
errc(1, error, "SHA256_Path_XATTRs getxattr of \"%s\" at path \"%s\" failed with error", name, path);
|
||||
}
|
||||
|
||||
digest = SHA256_Data(xattrBuf, xattrBufLen, buf);
|
||||
if (!digest)
|
||||
@ -157,6 +187,27 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
|
||||
asprintf(&xattrsSummary, "%s, %s:%s", oldSummary, name, digest);
|
||||
free(oldSummary);
|
||||
}
|
||||
#ifdef APFSIOC_XDSTREAM_OBJ_ID
|
||||
// System volume has stream based xattrs only in form of resource forks
|
||||
if (!strncmp(name, XATTR_RESOURCEFORK_NAME, XATTR_MAXNAMELEN)) {
|
||||
struct xdstream_obj_id x_obj;
|
||||
x_obj.xdi_name = name;
|
||||
x_obj.xdi_xdtream_obj_id = 0;
|
||||
|
||||
result = fsctl(path, APFSIOC_XDSTREAM_OBJ_ID, &x_obj, 0);
|
||||
if (!result) {
|
||||
xd_obj_id = x_obj.xdi_xdtream_obj_id;
|
||||
} else if (errno == ENOTTY) {
|
||||
// Not an apfs filesystem, return zero.
|
||||
xd_obj_id = 0;
|
||||
} else {
|
||||
error = errno;
|
||||
RECORD_FAILURE(27444, error);
|
||||
errc(1, error, "%s - SHA256_Path_XATTRs APFSIOC_XDSTREAM_OBJ_ID failed with %d", path, error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ai->xdstream_priv_id = xd_obj_id;
|
||||
}
|
||||
|
||||
free(xattrBuf);
|
||||
@ -166,15 +217,82 @@ char *SHA256_Path_XATTRs(char *path, char *buf)
|
||||
digest = SHA256_Data(xattrsSummary, strlen(xattrsSummary) * sizeof(char), buf);
|
||||
if (!digest)
|
||||
err(1, "%s", xattrsSummary);
|
||||
|
||||
ai->digest = digest;
|
||||
|
||||
free(xattrsSummary);
|
||||
return digest;
|
||||
return ai;
|
||||
}
|
||||
return kNone;
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
char *SHA256_Path_ACL(char *path, char *buf)
|
||||
{
|
||||
errno_t error = 0;
|
||||
int result = 0;
|
||||
char *data = NULL;
|
||||
char *digest = NULL;
|
||||
@ -195,8 +313,11 @@ char *SHA256_Path_ACL(char *path, char *buf)
|
||||
|
||||
result = getattrlist(path, &list, &aclBuf, sizeof(aclBuf), FSOPT_NOFOLLOW);
|
||||
|
||||
if (result)
|
||||
err(1, "SHA256_Path_ACL: getattrlist");
|
||||
if (result) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(27445, error);
|
||||
errc(1, error, "SHA256_Path_ACL: getattrlist");
|
||||
}
|
||||
|
||||
// if the path does not have an acl, return none
|
||||
if ( ( ! ( aclBuf.returned_attrs.commonattr & ATTR_CMN_EXTENDED_SECURITY ) )
|
||||
@ -237,3 +358,22 @@ Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
get_sibling_id(const char *path)
|
||||
{
|
||||
struct attrlist attr_list = {0};
|
||||
struct attrbuf attr_buf = {0};
|
||||
errno_t error = 0;
|
||||
|
||||
attr_list.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
attr_list.forkattr = ATTR_CMNEXT_LINKID;
|
||||
|
||||
error = getattrlist(path, &attr_list, &attr_buf, sizeof(attr_buf), FSOPT_ATTR_CMN_EXTENDED | FSOPT_NOFOLLOW);
|
||||
if (error) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(27447, error);
|
||||
errc(1, error, "get_sibling_id: getattrlist failed for %s\n", path);
|
||||
}
|
||||
|
||||
return attr_buf.sibling_id;
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
|
||||
#ifndef _COMMON_CRYPTO_H_
|
||||
#define _COMMON_CRYPTO_H_
|
||||
|
||||
#include <CommonCrypto/CommonDigestSPI.h>
|
||||
|
||||
#define kNone "none"
|
||||
@ -9,7 +13,24 @@ extern const int kSHA256NullTerminatedBuffLen;
|
||||
#define RIPEMD160_File(f, b) Digest_File(kCCDigestRMD160, f, b)
|
||||
#define SHA256_File(f, b) Digest_File(kCCDigestSHA256, f, b)
|
||||
|
||||
typedef struct {
|
||||
char *digest;
|
||||
uint64_t xdstream_priv_id;
|
||||
} xattr_info;
|
||||
|
||||
struct attrbuf {
|
||||
uint32_t info_length;
|
||||
uint64_t sibling_id;
|
||||
} __attribute__((aligned, packed));
|
||||
|
||||
typedef struct attrbuf attrbuf_t;
|
||||
|
||||
char *Digest_File(CCDigestAlg algorithm, const char *filename, char *buf);
|
||||
|
||||
char *SHA256_Path_XATTRs(char *path, char *buf);
|
||||
char *SHA256_Path_ACL(char *path, char *buf);
|
||||
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_ */
|
||||
|
412
mtree/compare.c
412
mtree/compare.c
@ -35,6 +35,7 @@ static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $");
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
@ -63,6 +64,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobe
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
@ -77,9 +79,79 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobe
|
||||
tab = "\t"; \
|
||||
}
|
||||
|
||||
extern CFMutableDictionaryRef dict;
|
||||
|
||||
// max/min times apfs can store on disk
|
||||
#define APFS_MAX_TIME 0x7fffffffffffffffLL
|
||||
#define APFS_MIN_TIME (-0x7fffffffffffffffLL-1)
|
||||
|
||||
static uint64_t
|
||||
timespec_to_apfs_timestamp(struct timespec *ts)
|
||||
{
|
||||
int64_t total;
|
||||
int64_t seconds;
|
||||
|
||||
// `tv_nsec' can be > one billion, so we split it into two components:
|
||||
// seconds and actual nanoseconds
|
||||
// this allows us to detect overflow on the *total* number of nanoseconds
|
||||
// e.g. if (MAX_SECONDS+2, -2billion) is passed in, we return MAX_SECONDS
|
||||
seconds = ((int64_t)ts->tv_nsec / (int64_t)NSEC_PER_SEC);
|
||||
|
||||
// compute total nanoseconds, checking for overflow:
|
||||
// seconds = sec + (ns/10e9)
|
||||
// total = seconds*10e9 + ns%10e9
|
||||
if (__builtin_saddll_overflow(ts->tv_sec, seconds, &seconds) ||
|
||||
__builtin_smulll_overflow(seconds, NSEC_PER_SEC, &total) ||
|
||||
__builtin_saddll_overflow(((int64_t)ts->tv_nsec % (int64_t)NSEC_PER_SEC), total, &total)) {
|
||||
// checking the sign of "seconds" tells us whether to cap the value at
|
||||
// the max or min time
|
||||
total = (ts->tv_sec > 0) ? APFS_MAX_TIME : APFS_MIN_TIME;
|
||||
}
|
||||
|
||||
return (uint64_t)total;
|
||||
}
|
||||
|
||||
static void
|
||||
set_key_value_pair(void *in_key, uint64_t *in_val, bool is_string)
|
||||
{
|
||||
CFStringRef key;
|
||||
CFNumberRef val;
|
||||
|
||||
if (is_string) {
|
||||
key = CFStringCreateWithCString(NULL, (const char*)in_key, kCFStringEncodingUTF8);
|
||||
|
||||
} else {
|
||||
key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%llu"), *(uint64_t*)in_key);
|
||||
}
|
||||
|
||||
val = CFNumberCreate(NULL, kCFNumberSInt64Type, in_val);
|
||||
|
||||
// we always expect the key to be not present
|
||||
if (key && val) {
|
||||
CFDictionaryAddValue(dict, key, val);
|
||||
} else {
|
||||
if (key) {
|
||||
CFRelease(key);
|
||||
}
|
||||
if (val) {
|
||||
CFRelease(val);
|
||||
}
|
||||
RECORD_FAILURE(1, EINVAL);
|
||||
errx(1, "set_key_value_pair: key/value is null");
|
||||
}
|
||||
|
||||
if (key) {
|
||||
CFRelease(key);
|
||||
}
|
||||
if (val) {
|
||||
CFRelease(val);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
compare(char *name __unused, NODE *s, FTSENT *p)
|
||||
{
|
||||
int error = 0;
|
||||
struct timeval tv[2];
|
||||
uint32_t val;
|
||||
int fd, label;
|
||||
@ -92,31 +164,44 @@ compare(char *name __unused, NODE *s, FTSENT *p)
|
||||
label = 0;
|
||||
switch(s->type) {
|
||||
case F_BLOCK:
|
||||
if (!S_ISBLK(p->fts_statp->st_mode))
|
||||
if (!S_ISBLK(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(2, EINVAL);
|
||||
goto typeerr;
|
||||
}
|
||||
break;
|
||||
case F_CHAR:
|
||||
if (!S_ISCHR(p->fts_statp->st_mode))
|
||||
if (!S_ISCHR(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(3, EINVAL);
|
||||
goto typeerr;
|
||||
}
|
||||
break;
|
||||
case F_DIR:
|
||||
if (!S_ISDIR(p->fts_statp->st_mode))
|
||||
if (!S_ISDIR(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(4, EINVAL);
|
||||
goto typeerr;
|
||||
}
|
||||
break;
|
||||
case F_FIFO:
|
||||
if (!S_ISFIFO(p->fts_statp->st_mode))
|
||||
if (!S_ISFIFO(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(5, EINVAL);
|
||||
goto typeerr;
|
||||
}
|
||||
break;
|
||||
case F_FILE:
|
||||
if (!S_ISREG(p->fts_statp->st_mode))
|
||||
if (!S_ISREG(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(6, EINVAL);
|
||||
goto typeerr;
|
||||
}
|
||||
break;
|
||||
case F_LINK:
|
||||
if (!S_ISLNK(p->fts_statp->st_mode))
|
||||
if (!S_ISLNK(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(7, EINVAL);
|
||||
goto typeerr;
|
||||
}
|
||||
break;
|
||||
case F_SOCK:
|
||||
if (!S_ISSOCK(p->fts_statp->st_mode)) {
|
||||
RECORD_FAILURE(8, EINVAL);
|
||||
typeerr: LABEL;
|
||||
(void)printf("\ttype expected %s found %s\n",
|
||||
ftype(s->type), inotype(p->fts_statp->st_mode));
|
||||
@ -129,28 +214,36 @@ typeerr: LABEL;
|
||||
LABEL;
|
||||
(void)printf("%suser expected %lu found %lu",
|
||||
tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
|
||||
if (uflag)
|
||||
if (chown(p->fts_accpath, s->st_uid, -1))
|
||||
if (uflag) {
|
||||
if (chown(p->fts_accpath, s->st_uid, -1)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(9, error);
|
||||
(void)printf(" not modified: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
strerror(error));
|
||||
} else {
|
||||
(void)printf(" modified\n");
|
||||
else
|
||||
}
|
||||
} else {
|
||||
(void)printf("\n");
|
||||
}
|
||||
tab = "\t";
|
||||
}
|
||||
if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
|
||||
LABEL;
|
||||
(void)printf("%sgid expected %lu found %lu",
|
||||
tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
|
||||
if (uflag)
|
||||
if (chown(p->fts_accpath, -1, s->st_gid))
|
||||
if (uflag) {
|
||||
if (chown(p->fts_accpath, -1, s->st_gid)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(10, error);
|
||||
(void)printf(" not modified: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
strerror(error));
|
||||
} else {
|
||||
(void)printf(" modified\n");
|
||||
else
|
||||
}
|
||||
} else {
|
||||
(void)printf("\n");
|
||||
}
|
||||
tab = "\t";
|
||||
}
|
||||
if (s->flags & F_MODE &&
|
||||
@ -159,14 +252,18 @@ typeerr: LABEL;
|
||||
LABEL;
|
||||
(void)printf("%spermissions expected %#o found %#o",
|
||||
tab, s->st_mode, p->fts_statp->st_mode & MBITS);
|
||||
if (uflag)
|
||||
if (chmod(p->fts_accpath, s->st_mode))
|
||||
if (uflag) {
|
||||
if (chmod(p->fts_accpath, s->st_mode)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(11, error);
|
||||
(void)printf(" not modified: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
strerror(error));
|
||||
} else {
|
||||
(void)printf(" modified\n");
|
||||
else
|
||||
}
|
||||
} else {
|
||||
(void)printf("\n");
|
||||
}
|
||||
tab = "\t";
|
||||
}
|
||||
if (s->flags & F_NLINK && s->type != F_DIR &&
|
||||
@ -186,35 +283,51 @@ typeerr: LABEL;
|
||||
if ((s->flags & F_TIME) &&
|
||||
((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
|
||||
(s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
|
||||
LABEL;
|
||||
(void)printf("%smodification time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld",
|
||||
ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
|
||||
if (uflag) {
|
||||
tv[0].tv_sec = s->st_mtimespec.tv_sec;
|
||||
tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
|
||||
tv[1] = tv[0];
|
||||
if (utimes(p->fts_accpath, tv))
|
||||
(void)printf(" not modified: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
(void)printf(" modified\n");
|
||||
} else
|
||||
(void)printf("\n");
|
||||
tab = "\t";
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%smodification time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld",
|
||||
ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
|
||||
if (uflag) {
|
||||
tv[0].tv_sec = s->st_mtimespec.tv_sec;
|
||||
tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
|
||||
tv[1] = tv[0];
|
||||
if (utimes(p->fts_accpath, tv)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(12, error);
|
||||
(void)printf(" not modified: %s\n",
|
||||
strerror(error));
|
||||
} else {
|
||||
(void)printf(" modified\n");
|
||||
}
|
||||
} else {
|
||||
(void)printf("\n");
|
||||
}
|
||||
tab = "\t";
|
||||
}
|
||||
if (!insert_mod && mflag) {
|
||||
uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_mtimespec);
|
||||
char *mod_string = "MODIFICATION";
|
||||
set_key_value_pair(mod_string, &s_mod_time, true);
|
||||
insert_mod = 1;
|
||||
}
|
||||
}
|
||||
if (s->flags & F_CKSUM) {
|
||||
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
|
||||
LABEL;
|
||||
error = errno;
|
||||
RECORD_FAILURE(13, error);
|
||||
(void)printf("%scksum: %s: %s\n",
|
||||
tab, p->fts_accpath, strerror(errno));
|
||||
tab, p->fts_accpath, strerror(error));
|
||||
tab = "\t";
|
||||
} else if (crc(fd, &val, &len)) {
|
||||
(void)close(fd);
|
||||
LABEL;
|
||||
error = errno;
|
||||
RECORD_FAILURE(14, error);
|
||||
(void)printf("%scksum: %s: %s\n",
|
||||
tab, p->fts_accpath, strerror(errno));
|
||||
tab, p->fts_accpath, strerror(error));
|
||||
tab = "\t";
|
||||
} else {
|
||||
(void)close(fd);
|
||||
@ -245,26 +358,37 @@ typeerr: LABEL;
|
||||
(void)printf(" found \"%s\"", fflags);
|
||||
free(fflags);
|
||||
|
||||
if (uflag)
|
||||
if (chflags(p->fts_accpath, (u_int)s->st_flags))
|
||||
if (uflag) {
|
||||
if (chflags(p->fts_accpath, (u_int)s->st_flags)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(15, error);
|
||||
(void)printf(" not modified: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
strerror(error));
|
||||
} else {
|
||||
(void)printf(" modified\n");
|
||||
else
|
||||
(void)printf("\n");
|
||||
}
|
||||
} else {
|
||||
(void)printf("\n");
|
||||
}
|
||||
tab = "\t";
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_MD5
|
||||
if (s->flags & F_MD5) {
|
||||
char *new_digest, buf[33];
|
||||
|
||||
#ifdef __clang__
|
||||
/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
new_digest = MD5File(p->fts_accpath, buf);
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if (!new_digest) {
|
||||
LABEL;
|
||||
error = errno;
|
||||
RECORD_FAILURE(16, error);
|
||||
printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
|
||||
strerror(errno));
|
||||
strerror(error));
|
||||
tab = "\t";
|
||||
} else if (strcmp(new_digest, s->md5digest)) {
|
||||
LABEL;
|
||||
@ -277,12 +401,19 @@ typeerr: LABEL;
|
||||
#ifdef ENABLE_SHA1
|
||||
if (s->flags & F_SHA1) {
|
||||
char *new_digest, buf[41];
|
||||
|
||||
#ifdef __clang__
|
||||
/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
new_digest = SHA1_File(p->fts_accpath, buf);
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if (!new_digest) {
|
||||
LABEL;
|
||||
error = errno;
|
||||
RECORD_FAILURE(17, error);
|
||||
printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
|
||||
strerror(errno));
|
||||
strerror(error));
|
||||
tab = "\t";
|
||||
} else if (strcmp(new_digest, s->sha1digest)) {
|
||||
LABEL;
|
||||
@ -295,12 +426,19 @@ typeerr: LABEL;
|
||||
#ifdef ENABLE_RMD160
|
||||
if (s->flags & F_RMD160) {
|
||||
char *new_digest, buf[41];
|
||||
|
||||
#ifdef __clang__
|
||||
/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
new_digest = RIPEMD160_File(p->fts_accpath, buf);
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if (!new_digest) {
|
||||
LABEL;
|
||||
error = errno;
|
||||
RECORD_FAILURE(18, error);
|
||||
printf("%sRIPEMD160: %s: %s\n", tab,
|
||||
p->fts_accpath, strerror(errno));
|
||||
p->fts_accpath, strerror(error));
|
||||
tab = "\t";
|
||||
} else if (strcmp(new_digest, s->rmd160digest)) {
|
||||
LABEL;
|
||||
@ -317,8 +455,10 @@ typeerr: LABEL;
|
||||
new_digest = SHA256_File(p->fts_accpath, buf);
|
||||
if (!new_digest) {
|
||||
LABEL;
|
||||
error = errno;
|
||||
RECORD_FAILURE(19, error);
|
||||
printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
|
||||
strerror(errno));
|
||||
strerror(error));
|
||||
tab = "\t";
|
||||
} else if (strcmp(new_digest, s->sha256digest)) {
|
||||
LABEL;
|
||||
@ -338,71 +478,124 @@ typeerr: LABEL;
|
||||
if ((s->flags & F_BTIME) &&
|
||||
((s->st_birthtimespec.tv_sec != p->fts_statp->st_birthtimespec.tv_sec) ||
|
||||
(s->st_birthtimespec.tv_nsec != p->fts_statp->st_birthtimespec.tv_nsec))) {
|
||||
LABEL;
|
||||
(void)printf("%sbirth time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_birthtimespec.tv_sec), s->st_birthtimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&p->fts_statp->st_birthtimespec.tv_sec), p->fts_statp->st_birthtimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%sbirth time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_birthtimespec.tv_sec), s->st_birthtimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&p->fts_statp->st_birthtimespec.tv_sec), p->fts_statp->st_birthtimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
}
|
||||
if (!insert_birth && mflag) {
|
||||
uint64_t s_create_time = timespec_to_apfs_timestamp(&s->st_birthtimespec);
|
||||
char *birth_string = "BIRTH";
|
||||
set_key_value_pair(birth_string, &s_create_time, true);
|
||||
insert_birth = 1;
|
||||
}
|
||||
}
|
||||
if ((s->flags & F_ATIME) &&
|
||||
((s->st_atimespec.tv_sec != p->fts_statp->st_atimespec.tv_sec) ||
|
||||
(s->st_atimespec.tv_nsec != p->fts_statp->st_atimespec.tv_nsec))) {
|
||||
LABEL;
|
||||
(void)printf("%saccess time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_atimespec.tv_sec), s->st_atimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&p->fts_statp->st_atimespec.tv_sec), p->fts_statp->st_atimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%saccess time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_atimespec.tv_sec), s->st_atimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&p->fts_statp->st_atimespec.tv_sec), p->fts_statp->st_atimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
}
|
||||
if (!insert_access && mflag) {
|
||||
uint64_t s_access_time = timespec_to_apfs_timestamp(&s->st_atimespec);
|
||||
char *access_string = "ACCESS";
|
||||
set_key_value_pair(access_string, &s_access_time, true);
|
||||
insert_access = 1;
|
||||
|
||||
}
|
||||
}
|
||||
if ((s->flags & F_CTIME) &&
|
||||
((s->st_ctimespec.tv_sec != p->fts_statp->st_ctimespec.tv_sec) ||
|
||||
(s->st_ctimespec.tv_nsec != p->fts_statp->st_ctimespec.tv_nsec))) {
|
||||
LABEL;
|
||||
(void)printf("%smetadata modification time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_ctimespec.tv_sec), s->st_ctimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&p->fts_statp->st_ctimespec.tv_sec), p->fts_statp->st_ctimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%smetadata modification time expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_ctimespec.tv_sec), s->st_ctimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&p->fts_statp->st_ctimespec.tv_sec), p->fts_statp->st_ctimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
}
|
||||
if (!insert_change && mflag) {
|
||||
uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_ctimespec);
|
||||
char *change_string = "CHANGE";
|
||||
set_key_value_pair(change_string, &s_mod_time, true);
|
||||
insert_change = 1;
|
||||
}
|
||||
}
|
||||
if (s->flags & F_PTIME) {
|
||||
int supported;
|
||||
struct timespec ptimespec = ptime(p->fts_accpath, &supported);
|
||||
if (!supported) {
|
||||
LABEL;
|
||||
(void)printf("%stime added to parent folder expected %.24s.%09ld found that it is not supported\n",
|
||||
tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
} else if ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) ||
|
||||
(s->st_ptimespec.tv_nsec != ptimespec.tv_nsec)) {
|
||||
LABEL;
|
||||
(void)printf("%stime added to parent folder expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&ptimespec.tv_sec), ptimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
if (mflag) {
|
||||
ptimespec.tv_sec = 0;
|
||||
ptimespec.tv_nsec = 0;
|
||||
supported = 1;
|
||||
} else {
|
||||
LABEL;
|
||||
(void)printf("%stime added to parent folder expected %.24s.%09ld found that it is not supported\n",
|
||||
tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
}
|
||||
}
|
||||
if (supported && ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) ||
|
||||
(s->st_ptimespec.tv_nsec != ptimespec.tv_nsec))) {
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%stime added to parent folder expected %.24s.%09ld ",
|
||||
tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
|
||||
(void)printf("found %.24s.%09ld\n",
|
||||
ctime(&ptimespec.tv_sec), ptimespec.tv_nsec);
|
||||
tab = "\t";
|
||||
} else if (!insert_parent && mflag) {
|
||||
uint64_t s_added_time = timespec_to_apfs_timestamp(&s->st_ptimespec);
|
||||
char *added_string = "DATEADDED";
|
||||
set_key_value_pair(added_string, &s_added_time, true);
|
||||
insert_parent = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s->flags & F_XATTRS) {
|
||||
char *new_digest, buf[kSHA256NullTerminatedBuffLen];
|
||||
new_digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
|
||||
if (!new_digest) {
|
||||
LABEL;
|
||||
printf("%sxattrsdigest missing, expected: %s\n", tab, s->xattrsdigest);
|
||||
tab = "\t";
|
||||
} else if (strcmp(new_digest, s->xattrsdigest)) {
|
||||
LABEL;
|
||||
printf("%sxattrsdigest expected %s found %s\n",
|
||||
tab, s->xattrsdigest, new_digest);
|
||||
tab = "\t";
|
||||
char buf[kSHA256NullTerminatedBuffLen];
|
||||
xattr_info *ai;
|
||||
ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
|
||||
if (!mflag) {
|
||||
if (ai && !ai->digest) {
|
||||
LABEL;
|
||||
printf("%sxattrsdigest missing, expected: %s\n", tab, s->xattrsdigest);
|
||||
tab = "\t";
|
||||
} else if (ai && strcmp(ai->digest, s->xattrsdigest)) {
|
||||
LABEL;
|
||||
printf("%sxattrsdigest expected %s found %s\n",
|
||||
tab, s->xattrsdigest, ai->digest);
|
||||
tab = "\t";
|
||||
}
|
||||
}
|
||||
if (mflag) {
|
||||
if (ai && ai->xdstream_priv_id != s->xdstream_priv_id) {
|
||||
set_key_value_pair((void*)&ai->xdstream_priv_id, &s->xdstream_priv_id, false);
|
||||
}
|
||||
}
|
||||
free(ai);
|
||||
}
|
||||
if ((s->flags & F_INODE) &&
|
||||
(p->fts_statp->st_ino != s->st_ino)) {
|
||||
LABEL;
|
||||
(void)printf("%sinode expected %llu found %llu\n",
|
||||
tab, s->st_ino, p->fts_ino);
|
||||
tab = "\t";
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%sinode expected %llu found %llu\n",
|
||||
tab, s->st_ino, p->fts_statp->st_ino);
|
||||
tab = "\t";
|
||||
}
|
||||
if (mflag) {
|
||||
set_key_value_pair((void*)&p->fts_statp->st_ino, &s->st_ino, false);
|
||||
}
|
||||
}
|
||||
if (s->flags & F_ACL) {
|
||||
char *new_digest, buf[kSHA256NullTerminatedBuffLen];
|
||||
@ -418,6 +611,21 @@ typeerr: LABEL;
|
||||
tab = "\t";
|
||||
}
|
||||
}
|
||||
if (s->flags & F_SIBLINGID) {
|
||||
uint64_t new_sibling_id = get_sibling_id(p->fts_accpath);
|
||||
new_sibling_id = (new_sibling_id != p->fts_statp->st_ino) ? new_sibling_id : 0;
|
||||
if (new_sibling_id != s->sibling_id) {
|
||||
if (!mflag) {
|
||||
LABEL;
|
||||
(void)printf("%ssibling id expected %llu found %llu\n",
|
||||
tab, s->sibling_id, new_sibling_id);
|
||||
tab = "\t";
|
||||
}
|
||||
if (mflag) {
|
||||
set_key_value_pair((void*)&new_sibling_id, &s->sibling_id, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (label);
|
||||
}
|
||||
@ -473,11 +681,15 @@ ftype(u_int type)
|
||||
char *
|
||||
rlink(char *name)
|
||||
{
|
||||
int error = 0;
|
||||
static char lbuf[MAXPATHLEN];
|
||||
ssize_t len;
|
||||
|
||||
if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
|
||||
err(1, "line %d: %s", lineno, name);
|
||||
if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(20, error);
|
||||
errc(1, error, "line %d: %s", lineno, name);
|
||||
}
|
||||
lbuf[len] = '\0';
|
||||
return (lbuf);
|
||||
}
|
||||
|
209
mtree/create.c
209
mtree/create.c
@ -63,6 +63,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/create.c,v 1.37 2005/03/29 11:44:17 tobez
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
@ -79,15 +80,17 @@ static mode_t mode;
|
||||
static u_long flags = 0xffffffff;
|
||||
static char *xattrs = kNone;
|
||||
static char *acl = kNone;
|
||||
static u_quad_t xdstream_id;
|
||||
|
||||
static int dsort(const FTSENT **, const FTSENT **);
|
||||
static void output(int, int *, const char *, ...) __printflike(3, 4);
|
||||
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **);
|
||||
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **, u_quad_t *);
|
||||
static void statf(int, FTSENT *);
|
||||
|
||||
void
|
||||
cwalk(void)
|
||||
{
|
||||
int error = 0;
|
||||
FTS *t;
|
||||
FTSENT *p;
|
||||
time_t cl;
|
||||
@ -109,8 +112,11 @@ cwalk(void)
|
||||
|
||||
argv[0] = dot;
|
||||
argv[1] = NULL;
|
||||
if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
|
||||
err(1, "fts_open()");
|
||||
if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(76, error);
|
||||
errc(1, error, "fts_open()");
|
||||
}
|
||||
while ((p = fts_read(t))) {
|
||||
if (iflag)
|
||||
indent = p->fts_level * 4;
|
||||
@ -127,7 +133,7 @@ cwalk(void)
|
||||
(void)printf("# %s\n", path);
|
||||
free(path);
|
||||
}
|
||||
statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl);
|
||||
statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl, &xdstream_id);
|
||||
statf(indent, p);
|
||||
break;
|
||||
case FTS_DP:
|
||||
@ -153,13 +159,16 @@ cwalk(void)
|
||||
}
|
||||
}
|
||||
(void)fts_close(t);
|
||||
if (sflag && keys & F_CKSUM)
|
||||
if (sflag && keys & F_CKSUM) {
|
||||
RECORD_FAILURE(77, WARN_CHECKSUM);
|
||||
warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
statf(int indent, FTSENT *p)
|
||||
{
|
||||
int error = 0;
|
||||
struct group *gr;
|
||||
struct passwd *pw;
|
||||
uint32_t val;
|
||||
@ -169,8 +178,10 @@ statf(int indent, FTSENT *p)
|
||||
char *escaped_name;
|
||||
|
||||
escaped_name = calloc(1, p->fts_namelen * 4 + 1);
|
||||
if (escaped_name == NULL)
|
||||
if (escaped_name == NULL) {
|
||||
RECORD_FAILURE(78, ENOMEM);
|
||||
errx(1, "statf(): calloc() failed");
|
||||
}
|
||||
strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB);
|
||||
|
||||
if (iflag || S_ISDIR(p->fts_statp->st_mode))
|
||||
@ -190,15 +201,18 @@ statf(int indent, FTSENT *p)
|
||||
if (p->fts_statp->st_uid != uid) {
|
||||
if (keys & F_UNAME) {
|
||||
pw = getpwuid(p->fts_statp->st_uid);
|
||||
if (pw != NULL)
|
||||
if (pw != NULL) {
|
||||
output(indent, &offset, "uname=%s", pw->pw_name);
|
||||
else if (wflag)
|
||||
} else if (wflag) {
|
||||
RECORD_FAILURE(27448, WARN_UNAME);
|
||||
warnx("Could not get uname for uid=%u",
|
||||
p->fts_statp->st_uid);
|
||||
else
|
||||
} else {
|
||||
RECORD_FAILURE(79, EINVAL);
|
||||
errx(1,
|
||||
"Could not get uname for uid=%u",
|
||||
p->fts_statp->st_uid);
|
||||
}
|
||||
}
|
||||
if (keys & F_UID)
|
||||
output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
|
||||
@ -206,15 +220,18 @@ statf(int indent, FTSENT *p)
|
||||
if (p->fts_statp->st_gid != gid) {
|
||||
if (keys & F_GNAME) {
|
||||
gr = getgrgid(p->fts_statp->st_gid);
|
||||
if (gr != NULL)
|
||||
if (gr != NULL) {
|
||||
output(indent, &offset, "gname=%s", gr->gr_name);
|
||||
else if (wflag)
|
||||
} else if (wflag) {
|
||||
RECORD_FAILURE(27449, WARN_UNAME);
|
||||
warnx("Could not get gname for gid=%u",
|
||||
p->fts_statp->st_gid);
|
||||
else
|
||||
} else {
|
||||
RECORD_FAILURE(80, EINVAL);
|
||||
errx(1,
|
||||
"Could not get gname for gid=%u",
|
||||
p->fts_statp->st_gid);
|
||||
}
|
||||
}
|
||||
if (keys & F_GID)
|
||||
output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
|
||||
@ -226,44 +243,79 @@ statf(int indent, FTSENT *p)
|
||||
if (keys & F_SIZE)
|
||||
output(indent, &offset, "size=%jd",
|
||||
(intmax_t)p->fts_statp->st_size);
|
||||
if (keys & F_TIME)
|
||||
output(indent, &offset, "time=%ld.%09ld",
|
||||
(long)p->fts_statp->st_mtimespec.tv_sec,
|
||||
p->fts_statp->st_mtimespec.tv_nsec);
|
||||
if (keys & F_TIME) {
|
||||
if (tflag && !insert_mod) {
|
||||
output(indent, &offset, "time=%ld.%09ld",
|
||||
(long)ts.tv_sec, ts.tv_nsec);
|
||||
insert_mod = 1;
|
||||
}
|
||||
if (!tflag) {
|
||||
output(indent, &offset, "time=%ld.%09ld",
|
||||
(long)p->fts_statp->st_mtimespec.tv_sec,
|
||||
p->fts_statp->st_mtimespec.tv_nsec);
|
||||
}
|
||||
}
|
||||
if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
|
||||
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
|
||||
crc(fd, &val, &len))
|
||||
err(1, "%s", p->fts_accpath);
|
||||
crc(fd, &val, &len)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(27450, error);
|
||||
errc(1, error, "%s", p->fts_accpath);
|
||||
}
|
||||
(void)close(fd);
|
||||
output(indent, &offset, "cksum=%lu", (unsigned long)val);
|
||||
}
|
||||
#ifdef ENABLE_MD5
|
||||
if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
|
||||
char *digest, buf[33];
|
||||
|
||||
#ifdef __clang__
|
||||
/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
digest = MD5File(p->fts_accpath, buf);
|
||||
if (!digest)
|
||||
err(1, "%s", p->fts_accpath);
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if (!digest) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(81, error);
|
||||
errc(1, error, "%s", p->fts_accpath);
|
||||
}
|
||||
output(indent, &offset, "md5digest=%s", digest);
|
||||
}
|
||||
#endif /* ENABLE_MD5 */
|
||||
#ifdef ENABLE_SHA1
|
||||
if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
|
||||
char *digest, buf[41];
|
||||
|
||||
#ifdef __clang__
|
||||
/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
digest = SHA1_File(p->fts_accpath, buf);
|
||||
if (!digest)
|
||||
err(1, "%s", p->fts_accpath);
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if (!digest) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(82, error);
|
||||
errc(1, error, "%s", p->fts_accpath);
|
||||
}
|
||||
output(indent, &offset, "sha1digest=%s", digest);
|
||||
}
|
||||
#endif /* ENABLE_SHA1 */
|
||||
#ifdef ENABLE_RMD160
|
||||
if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
|
||||
char *digest, buf[41];
|
||||
|
||||
#ifdef __clang__
|
||||
/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
digest = RIPEMD160_File(p->fts_accpath, buf);
|
||||
if (!digest)
|
||||
err(1, "%s", p->fts_accpath);
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if (!digest) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(83, error);
|
||||
errc(1, error, "%s", p->fts_accpath);
|
||||
}
|
||||
output(indent, &offset, "ripemd160digest=%s", digest);
|
||||
}
|
||||
#endif /* ENABLE_RMD160 */
|
||||
@ -272,8 +324,11 @@ statf(int indent, FTSENT *p)
|
||||
char *digest, buf[kSHA256NullTerminatedBuffLen];
|
||||
|
||||
digest = SHA256_File(p->fts_accpath, buf);
|
||||
if (!digest)
|
||||
err(1, "%s", p->fts_accpath);
|
||||
if (!digest) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(84, error);
|
||||
errc(1, error, "%s", p->fts_accpath);
|
||||
}
|
||||
output(indent, &offset, "sha256digest=%s", digest);
|
||||
}
|
||||
#endif /* ENABLE_SHA256 */
|
||||
@ -290,38 +345,69 @@ statf(int indent, FTSENT *p)
|
||||
free(fflags);
|
||||
}
|
||||
if (keys & F_BTIME) {
|
||||
output(indent, &offset, "btime=%ld.%09ld",
|
||||
p->fts_statp->st_birthtimespec.tv_sec,
|
||||
p->fts_statp->st_birthtimespec.tv_nsec);
|
||||
if (tflag && !insert_birth) {
|
||||
output(indent, &offset, "btime=%ld.%09ld",
|
||||
ts.tv_sec, ts.tv_nsec);
|
||||
insert_birth = 1;
|
||||
}
|
||||
if (!tflag) {
|
||||
output(indent, &offset, "btime=%ld.%09ld",
|
||||
p->fts_statp->st_birthtimespec.tv_sec,
|
||||
p->fts_statp->st_birthtimespec.tv_nsec);
|
||||
}
|
||||
}
|
||||
// only check access time on regular files, as traversing a folder will update its access time
|
||||
if (keys & F_ATIME && S_ISREG(p->fts_statp->st_mode)) {
|
||||
output(indent, &offset, "atime=%ld.%09ld",
|
||||
p->fts_statp->st_atimespec.tv_sec,
|
||||
p->fts_statp->st_atimespec.tv_nsec);
|
||||
if (tflag && !insert_access) {
|
||||
output(indent, &offset, "atime=%ld.%09ld",
|
||||
ts.tv_sec, ts.tv_nsec);
|
||||
insert_access = 1;
|
||||
}
|
||||
if (!tflag) {
|
||||
output(indent, &offset, "atime=%ld.%09ld",
|
||||
p->fts_statp->st_atimespec.tv_sec,
|
||||
p->fts_statp->st_atimespec.tv_nsec);
|
||||
}
|
||||
}
|
||||
if (keys & F_CTIME) {
|
||||
output(indent, &offset, "ctime=%ld.%09ld",
|
||||
p->fts_statp->st_ctimespec.tv_sec,
|
||||
p->fts_statp->st_ctimespec.tv_nsec);
|
||||
if (tflag && !insert_change) {
|
||||
output(indent, &offset, "ctime=%ld.%09ld",
|
||||
ts.tv_sec, ts.tv_nsec);
|
||||
insert_change = 1;
|
||||
}
|
||||
if (!tflag) {
|
||||
output(indent, &offset, "ctime=%ld.%09ld",
|
||||
p->fts_statp->st_ctimespec.tv_sec,
|
||||
p->fts_statp->st_ctimespec.tv_nsec);
|
||||
}
|
||||
}
|
||||
// date added to parent folder is only supported for files and directories
|
||||
if (keys & F_PTIME && (S_ISREG(p->fts_statp->st_mode) ||
|
||||
S_ISDIR(p->fts_statp->st_mode))) {
|
||||
int supported;
|
||||
struct timespec ptimespec = ptime(p->fts_accpath, &supported);
|
||||
if (supported) {
|
||||
if (tflag && !insert_parent) {
|
||||
output(indent, &offset, "ptime=%ld.%09ld",
|
||||
ts.tv_sec, ts.tv_nsec);
|
||||
insert_parent = 1;
|
||||
}
|
||||
if (!tflag && supported) {
|
||||
output(indent, &offset, "ptime=%ld.%09ld",
|
||||
ptimespec.tv_sec,
|
||||
ptimespec.tv_nsec);
|
||||
}
|
||||
}
|
||||
if (keys & F_XATTRS) {
|
||||
char *digest, buf[kSHA256NullTerminatedBuffLen];
|
||||
char buf[kSHA256NullTerminatedBuffLen];
|
||||
xattr_info *ai;
|
||||
|
||||
digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
|
||||
if (digest && (strcmp(digest, xattrs) != 0)) {
|
||||
output(indent, &offset, "xattrsdigest=%s", digest);
|
||||
ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
|
||||
if (ai && ai->digest) {
|
||||
if ((strcmp(ai->digest, xattrs) != 0) || (ai->xdstream_priv_id != xdstream_id)) {
|
||||
output(indent, &offset, "xattrsdigest=%s.%llu", ai->digest, ai->xdstream_priv_id);
|
||||
}
|
||||
free(ai);
|
||||
ai = NULL;
|
||||
}
|
||||
}
|
||||
if (keys & F_INODE) {
|
||||
@ -335,6 +421,11 @@ statf(int indent, FTSENT *p)
|
||||
output(indent, &offset, "acldigest=%s", digest);
|
||||
}
|
||||
}
|
||||
if (keys & F_SIBLINGID) {
|
||||
uint64_t sibling_id = get_sibling_id(p->fts_accpath);
|
||||
sibling_id = (sibling_id != p->fts_statp->st_ino) ? sibling_id : 0;
|
||||
output(indent, &offset, "siblingid=%llu", sibling_id);
|
||||
}
|
||||
|
||||
(void)putchar('\n');
|
||||
}
|
||||
@ -346,8 +437,9 @@ statf(int indent, FTSENT *p)
|
||||
#define MAXS 16
|
||||
|
||||
static int
|
||||
statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl)
|
||||
statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl, u_quad_t *xdstream_id)
|
||||
{
|
||||
int error = 0;
|
||||
FTSENT *p;
|
||||
gid_t sgid;
|
||||
uid_t suid;
|
||||
@ -361,14 +453,18 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
|
||||
u_long saveflags = *pflags;
|
||||
char *savexattrs = *pxattrs;
|
||||
char *saveacl = *pacl;
|
||||
u_quad_t savexdstream_id = *xdstream_id;
|
||||
u_short maxgid, maxuid, maxmode, maxflags;
|
||||
u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
|
||||
char *fflags;
|
||||
static int first = 1;
|
||||
|
||||
if ((p = fts_children(t, 0)) == NULL) {
|
||||
if (errno)
|
||||
err(1, "%s", RP(parent));
|
||||
error = errno;
|
||||
if (error) {
|
||||
RECORD_FAILURE(85, error);
|
||||
errc(1, error, "%s", RP(parent));
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -434,23 +530,29 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
|
||||
(void)printf("/set type=file");
|
||||
if (keys & F_UNAME) {
|
||||
pw = getpwuid(saveuid);
|
||||
if (pw != NULL)
|
||||
if (pw != NULL) {
|
||||
(void)printf(" uname=%s", pw->pw_name);
|
||||
else if (wflag)
|
||||
} else if (wflag) {
|
||||
RECORD_FAILURE(27451, WARN_UNAME);
|
||||
warnx( "Could not get uname for uid=%u", saveuid);
|
||||
else
|
||||
} else {
|
||||
RECORD_FAILURE(86, EINVAL);
|
||||
errx(1, "Could not get uname for uid=%u", saveuid);
|
||||
}
|
||||
}
|
||||
if (keys & F_UID)
|
||||
(void)printf(" uid=%lu", (u_long)saveuid);
|
||||
if (keys & F_GNAME) {
|
||||
gr = getgrgid(savegid);
|
||||
if (gr != NULL)
|
||||
if (gr != NULL) {
|
||||
(void)printf(" gname=%s", gr->gr_name);
|
||||
else if (wflag)
|
||||
} else if (wflag) {
|
||||
RECORD_FAILURE(27452, WARN_UNAME);
|
||||
warnx("Could not get gname for gid=%u", savegid);
|
||||
else
|
||||
} else {
|
||||
RECORD_FAILURE(87, EINVAL);
|
||||
errx(1, "Could not get gname for gid=%u", savegid);
|
||||
}
|
||||
}
|
||||
if (keys & F_GID)
|
||||
(void)printf(" gid=%lu", (u_long)savegid);
|
||||
@ -464,7 +566,7 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
|
||||
free(fflags);
|
||||
}
|
||||
if (keys & F_XATTRS)
|
||||
(void)printf(" xattrsdigest=%s", savexattrs);
|
||||
(void)printf(" xattrsdigest=%s.%llu", savexattrs, savexdstream_id);
|
||||
if (keys & F_ACL)
|
||||
(void)printf(" acldigest=%s", saveacl);
|
||||
(void)printf("\n");
|
||||
@ -474,6 +576,7 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
|
||||
*pflags = saveflags;
|
||||
*pxattrs = savexattrs;
|
||||
*pacl = saveacl;
|
||||
*xdstream_id = savexdstream_id;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
@ -31,17 +31,17 @@
|
||||
__FBSDID("$FreeBSD: src/usr.sbin/mtree/excludes.c,v 1.8 2003/10/21 08:27:05 phk Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h> /* XXX for mtree.h */
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <fts.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mtree.h" /* XXX for extern.h */
|
||||
#include "metrics.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
@ -81,8 +81,10 @@ read_excludes_file(const char *name)
|
||||
|
||||
str = malloc(len + 1);
|
||||
e = malloc(sizeof *e);
|
||||
if (str == 0 || e == 0)
|
||||
if (str == 0 || e == 0) {
|
||||
RECORD_FAILURE(59, ENOMEM);
|
||||
errx(1, "memory allocation error");
|
||||
}
|
||||
e->glob = str;
|
||||
memcpy(str, line, len);
|
||||
str[len] = '\0';
|
||||
|
@ -29,6 +29,12 @@
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
||||
* $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.13 2004/01/11 19:38:48 phk Exp $
|
||||
*/
|
||||
|
||||
#ifndef _EXTERN_H_
|
||||
#define _EXTERN_H_
|
||||
|
||||
#include "mtree.h"
|
||||
|
||||
extern uint32_t crc_total;
|
||||
|
||||
#ifdef _FTS_H_
|
||||
@ -55,7 +61,11 @@ const char * ftype(u_int type);
|
||||
extern int ftsoptions;
|
||||
extern u_int keys;
|
||||
extern int lineno;
|
||||
extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag;
|
||||
extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag, mflag, tflag, xflag;
|
||||
extern int insert_mod, insert_birth, insert_access, insert_change, insert_parent;
|
||||
extern struct timespec ts;
|
||||
#ifdef MAXPATHLEN
|
||||
extern char fullpath[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
#endif /* _EXTERN_H_ */
|
||||
|
77
mtree/fix_failure_locations.py
Normal file
77
mtree/fix_failure_locations.py
Normal file
@ -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)
|
155
mtree/metrics.c
Normal file
155
mtree/metrics.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
48
mtree/metrics.h
Normal file
48
mtree/metrics.h
Normal file
@ -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_ */
|
24
mtree/misc.c
24
mtree/misc.c
@ -33,6 +33,7 @@ static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /*not lint */
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
#include <errno.h>
|
||||
__FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -42,6 +43,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez E
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
#import <sys/attr.h>
|
||||
@ -84,6 +86,7 @@ static KEY keylist[] = {
|
||||
#ifdef ENABLE_SHA256
|
||||
{"sha256digest", F_SHA256, NEEDVALUE},
|
||||
#endif
|
||||
{"siblingid", F_SIBLINGID, NEEDVALUE},
|
||||
{"size", F_SIZE, NEEDVALUE},
|
||||
{"time", F_TIME, NEEDVALUE},
|
||||
{"type", F_TYPE, NEEDVALUE},
|
||||
@ -102,8 +105,10 @@ parsekey(char *name, int *needvaluep)
|
||||
tmp.name = name;
|
||||
k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
|
||||
sizeof(KEY), keycompare);
|
||||
if (k == NULL)
|
||||
if (k == NULL) {
|
||||
RECORD_FAILURE(107, EINVAL);
|
||||
errx(1, "line %d: unknown keyword %s", lineno, name);
|
||||
}
|
||||
|
||||
if (needvaluep)
|
||||
*needvaluep = k->flags & NEEDVALUE ? 1 : 0;
|
||||
@ -119,6 +124,7 @@ keycompare(const void *a, const void *b)
|
||||
char *
|
||||
flags_to_string(u_long fflags)
|
||||
{
|
||||
int error = 0;
|
||||
char *string;
|
||||
|
||||
string = fflagstostr(fflags);
|
||||
@ -126,8 +132,11 @@ flags_to_string(u_long fflags)
|
||||
free(string);
|
||||
string = strdup("none");
|
||||
}
|
||||
if (string == NULL)
|
||||
err(1, NULL);
|
||||
if (string == NULL) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(108, error);
|
||||
errc(1, error, NULL);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
@ -137,8 +146,10 @@ char *
|
||||
escape_path(char *string)
|
||||
{
|
||||
char *escapedPath = calloc(1, strlen(string) * 4 + 1);
|
||||
if (escapedPath == NULL)
|
||||
if (escapedPath == NULL) {
|
||||
RECORD_FAILURE(109, ENOMEM);
|
||||
errx(1, "escape_path(): calloc() failed");
|
||||
}
|
||||
strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
|
||||
|
||||
return escapedPath;
|
||||
@ -154,6 +165,7 @@ struct ptimebuf {
|
||||
struct timespec
|
||||
ptime(char *path, int *supported) {
|
||||
|
||||
int error = 0;
|
||||
int ret = 0;
|
||||
struct ptimebuf buf;
|
||||
struct attrlist list = {
|
||||
@ -162,7 +174,9 @@ ptime(char *path, int *supported) {
|
||||
};
|
||||
ret = getattrlist(path, &list, &buf, sizeof(buf), FSOPT_NOFOLLOW);
|
||||
if (ret) {
|
||||
err(1, "ptime: getattrlist");
|
||||
error = errno;
|
||||
RECORD_FAILURE(110, error);
|
||||
errc(1, error, "ptime: getattrlist");
|
||||
}
|
||||
|
||||
*supported = 0;
|
||||
|
@ -148,6 +148,9 @@ This occurs when the directory is a symbolic link.
|
||||
Remove any files in the file hierarchy that are not described in the
|
||||
specification.
|
||||
.\" ==========
|
||||
.It Fl S
|
||||
Skip calculating the digest of the extended attributes of the file.
|
||||
.\" ==========
|
||||
.It Fl s Ar seed
|
||||
Display a single checksum to the standard error output that represents all
|
||||
of the files for which the keyword
|
||||
|
203
mtree/mtree.c
203
mtree/mtree.c
@ -41,6 +41,7 @@ static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp $");
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <err.h>
|
||||
@ -49,31 +50,58 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define SECONDS_IN_A_DAY (60 * 60 * 24)
|
||||
|
||||
int ftsoptions = FTS_PHYSICAL;
|
||||
int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag;
|
||||
int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag, mflag, tflag, xflag;
|
||||
int insert_mod, insert_birth, insert_access, insert_change, insert_parent;
|
||||
struct timespec ts;
|
||||
u_int keys;
|
||||
char fullpath[MAXPATHLEN];
|
||||
CFMutableDictionaryRef dict;
|
||||
char *filepath;
|
||||
|
||||
static void usage(void);
|
||||
static bool write_plist_to_file(void);
|
||||
|
||||
static void
|
||||
do_cleanup(void) {
|
||||
|
||||
if (mflag) {
|
||||
if (dict)
|
||||
CFRelease(dict);
|
||||
if (filepath)
|
||||
free(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int error = 0;
|
||||
int ch;
|
||||
char *dir, *p;
|
||||
int status;
|
||||
FILE *spec1, *spec2;
|
||||
char *timestamp = NULL;
|
||||
char *timeformat = "%FT%T";
|
||||
FILE *file = NULL;
|
||||
|
||||
dir = NULL;
|
||||
keys = KEYDEFAULT;
|
||||
init_excludes();
|
||||
spec1 = stdin;
|
||||
spec2 = NULL;
|
||||
set_metric_start_time(time(NULL));
|
||||
|
||||
while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:")) != -1)
|
||||
atexit(do_cleanup);
|
||||
atexit(print_metrics_to_file);
|
||||
|
||||
while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:m:F:t:E:S")) != -1)
|
||||
switch((char)ch) {
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
@ -87,14 +115,22 @@ main(int argc, char *argv[])
|
||||
case 'f':
|
||||
if (spec1 == stdin) {
|
||||
spec1 = fopen(optarg, "r");
|
||||
if (spec1 == NULL)
|
||||
err(1, "%s", optarg);
|
||||
if (spec1 == NULL) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(88, error);
|
||||
errc(1, error, "%s", optarg);
|
||||
}
|
||||
} else if (spec2 == NULL) {
|
||||
spec2 = fopen(optarg, "r");
|
||||
if (spec2 == NULL)
|
||||
err(1, "%s", optarg);
|
||||
} else
|
||||
if (spec2 == NULL) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(89, error);
|
||||
errc(1, error, "%s", optarg);
|
||||
}
|
||||
} else {
|
||||
RECORD_FAILURE(90, WARN_USAGE);
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
iflag = 1;
|
||||
@ -133,8 +169,10 @@ main(int argc, char *argv[])
|
||||
case 's':
|
||||
sflag = 1;
|
||||
crc_total = (uint32_t)~strtoul(optarg, &p, 0);
|
||||
if (*p)
|
||||
if (*p) {
|
||||
RECORD_FAILURE(91, WARN_USAGE);
|
||||
errx(1, "illegal seed value -- %s", optarg);
|
||||
}
|
||||
break;
|
||||
case 'U':
|
||||
Uflag = 1;
|
||||
@ -152,32 +190,107 @@ main(int argc, char *argv[])
|
||||
case 'X':
|
||||
read_excludes_file(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
mflag = 1;
|
||||
filepath = strdup(optarg);
|
||||
dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
insert_access = insert_mod = insert_birth = insert_change = 0;
|
||||
break;
|
||||
case 'F':
|
||||
timeformat = optarg;
|
||||
break;
|
||||
case 't':
|
||||
timestamp = optarg;
|
||||
tflag = 1;
|
||||
break;
|
||||
case 'E':
|
||||
if (!strcmp(optarg, "-")) {
|
||||
file = stdout;
|
||||
} else {
|
||||
file = fopen(optarg, "w");
|
||||
}
|
||||
if (file == NULL) {
|
||||
warnx("Could not open metrics log file %s", optarg);
|
||||
} else {
|
||||
set_metrics_file(file);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
xflag = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
RECORD_FAILURE(92, WARN_USAGE);
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
// argv += optind;
|
||||
|
||||
if (argc)
|
||||
if (argc) {
|
||||
RECORD_FAILURE(93, WARN_USAGE);
|
||||
usage();
|
||||
}
|
||||
|
||||
if (dir && chdir(dir))
|
||||
err(1, "%s", dir);
|
||||
if (timestamp) {
|
||||
struct tm t = {};
|
||||
char *r = strptime(timestamp, timeformat, &t);
|
||||
if (r && r[0] == '\0') {
|
||||
ts.tv_sec = mktime(&t);
|
||||
if ((ts.tv_sec - time(NULL)) > 30 * SECONDS_IN_A_DAY) {
|
||||
RECORD_FAILURE(94, WARN_TIME);
|
||||
errx(1, "Time is more then 30 days in the future");
|
||||
} else if (ts.tv_sec < 0) {
|
||||
RECORD_FAILURE(95, WARN_TIME);
|
||||
errx(1, "Time is too far in the past");
|
||||
}
|
||||
} else {
|
||||
RECORD_FAILURE(96, WARN_TIME);
|
||||
errx(1,"Cannot parse timestamp '%s' using format \"%s\"\n", timestamp, timeformat);
|
||||
}
|
||||
}
|
||||
|
||||
if ((cflag || sflag) && !getwd(fullpath))
|
||||
if (dir && chdir(dir)) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(97, error);
|
||||
errc(1, error, "%s", dir);
|
||||
}
|
||||
|
||||
if ((cflag || sflag) && !getwd(fullpath)) {
|
||||
RECORD_FAILURE(98, errno);
|
||||
errx(1, "%s", fullpath);
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
set_metric_path(dir);
|
||||
}
|
||||
|
||||
if (cflag) {
|
||||
cwalk();
|
||||
exit(0);
|
||||
}
|
||||
if (spec2 != NULL)
|
||||
if (spec2 != NULL) {
|
||||
status = mtree_specspec(spec1, spec2);
|
||||
else
|
||||
if (Uflag & (status == MISMATCHEXIT)) {
|
||||
status = 0;
|
||||
} else {
|
||||
RECORD_FAILURE(99, status);
|
||||
}
|
||||
} else {
|
||||
status = mtree_verifyspec(spec1);
|
||||
if (Uflag & (status == MISMATCHEXIT))
|
||||
status = 0;
|
||||
if (Uflag & (status == MISMATCHEXIT)) {
|
||||
status = 0;
|
||||
} else if (status) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -185,7 +298,63 @@ static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mtree [-LPUcdeinqruxw] [-f spec] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n"
|
||||
"usage: mtree [-LPUScdeinqruxw] [-f spec] [-K key] [-k key] [-p path] [-s seed] [-m xml dictionary] [-t timestamp]\n"
|
||||
"\t[-X excludes]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -30,6 +30,10 @@
|
||||
* $FreeBSD: src/usr.sbin/mtree/mtree.h,v 1.7 2005/03/29 11:44:17 tobez Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MTREE_H_
|
||||
#define _MTREE_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -60,8 +64,10 @@ typedef struct _node {
|
||||
struct timespec st_ctimespec; /* metadata modification time */
|
||||
struct timespec st_ptimespec; /* time added to parent folder */
|
||||
char *xattrsdigest; /* digest of extended attributes */
|
||||
u_quad_t xdstream_priv_id; /* private id of the xattr data stream */
|
||||
ino_t st_ino; /* inode */
|
||||
char *acldigest; /* digest of access control list */
|
||||
u_quad_t sibling_id; /* sibling id */
|
||||
|
||||
#define F_CKSUM 0x00000001 /* check sum */
|
||||
#define F_DONE 0x00000002 /* directory done */
|
||||
@ -92,6 +98,7 @@ typedef struct _node {
|
||||
#define F_XATTRS 0x02000000 /* digest of extended attributes */
|
||||
#define F_INODE 0x04000000 /* inode */
|
||||
#define F_ACL 0x08000000 /* digest of access control list */
|
||||
#define F_SIBLINGID 0x10000000 /* sibling id */
|
||||
u_int flags; /* items set */
|
||||
|
||||
#define F_BLOCK 0x001 /* block special */
|
||||
@ -109,3 +116,5 @@ typedef struct _node {
|
||||
#define RP(p) \
|
||||
((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
|
||||
(p)->fts_path + 2 : (p)->fts_path)
|
||||
|
||||
#endif /* _MTREE_H_ */
|
||||
|
180
mtree/spec.c
180
mtree/spec.c
@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez E
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
@ -74,8 +75,10 @@ mtree_readspec(FILE *fi)
|
||||
continue;
|
||||
|
||||
/* Find end of line. */
|
||||
if ((p = index(buf, '\n')) == NULL)
|
||||
if ((p = index(buf, '\n')) == NULL) {
|
||||
RECORD_FAILURE(21, ERANGE);
|
||||
errx(1, "line %d too long", lineno);
|
||||
}
|
||||
|
||||
/* See if next line is continuation line. */
|
||||
if (p[-1] == '\\') {
|
||||
@ -102,8 +105,10 @@ mtree_readspec(FILE *fi)
|
||||
}
|
||||
|
||||
/* Grab file name, "$", "set", or "unset". */
|
||||
if ((p = strtok(p, "\n\t ")) == NULL)
|
||||
if ((p = strtok(p, "\n\t ")) == NULL) {
|
||||
RECORD_FAILURE(22, EINVAL);
|
||||
errx(1, "line %d: missing field", lineno);
|
||||
}
|
||||
|
||||
if (p[0] == '/')
|
||||
switch(p[1]) {
|
||||
@ -119,9 +124,11 @@ mtree_readspec(FILE *fi)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index(p, '/'))
|
||||
if (index(p, '/')) {
|
||||
RECORD_FAILURE(23, EINVAL);
|
||||
errx(1, "line %d: slash character in file name",
|
||||
lineno);
|
||||
}
|
||||
|
||||
if (!strcmp(p, "..")) {
|
||||
/* Don't go up, if haven't gone down. */
|
||||
@ -135,17 +142,22 @@ mtree_readspec(FILE *fi)
|
||||
last->flags |= F_DONE;
|
||||
continue;
|
||||
|
||||
noparent: errx(1, "line %d: no parent node", lineno);
|
||||
noparent: RECORD_FAILURE(24, EINVAL);
|
||||
errx(1, "line %d: no parent node", lineno);
|
||||
}
|
||||
|
||||
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
|
||||
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) {
|
||||
RECORD_FAILURE(25, ENOMEM);
|
||||
errx(1, "calloc");
|
||||
}
|
||||
*centry = ginfo;
|
||||
#define MAGIC "?*["
|
||||
if (strpbrk(p, MAGIC))
|
||||
centry->flags |= F_MAGIC;
|
||||
if (strunvis(centry->name, p) == -1)
|
||||
if (strunvis(centry->name, p) == -1) {
|
||||
RECORD_FAILURE(26, EILSEQ);
|
||||
errx(1, "filename %s is ill-encoded", p);
|
||||
}
|
||||
set(NULL, centry);
|
||||
|
||||
if (!root) {
|
||||
@ -166,6 +178,7 @@ noparent: errx(1, "line %d: no parent node", lineno);
|
||||
static void
|
||||
set(char *t, NODE *ip)
|
||||
{
|
||||
int error = 0;
|
||||
int type;
|
||||
char *kw, *val = NULL;
|
||||
struct group *gr;
|
||||
@ -173,93 +186,126 @@ set(char *t, NODE *ip)
|
||||
mode_t *m;
|
||||
int value;
|
||||
char *ep;
|
||||
char *l;
|
||||
|
||||
for (; (kw = strtok(t, "= \t\n")); t = NULL) {
|
||||
ip->flags |= type = parsekey(kw, &value);
|
||||
if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL)
|
||||
if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL) {
|
||||
RECORD_FAILURE(27, EINVAL);
|
||||
errx(1, "line %d: missing value", lineno);
|
||||
}
|
||||
switch(type) {
|
||||
case F_CKSUM:
|
||||
ip->cksum = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(28, EINVAL);
|
||||
errx(1, "line %d: invalid checksum %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_MD5:
|
||||
ip->md5digest = strdup(val);
|
||||
if(!ip->md5digest)
|
||||
if (!ip->md5digest) {
|
||||
RECORD_FAILURE(29, ENOMEM);
|
||||
errx(1, "strdup");
|
||||
}
|
||||
break;
|
||||
case F_SHA1:
|
||||
ip->sha1digest = strdup(val);
|
||||
if(!ip->sha1digest)
|
||||
if (!ip->sha1digest) {
|
||||
RECORD_FAILURE(30, ENOMEM);
|
||||
errx(1, "strdup");
|
||||
}
|
||||
break;
|
||||
case F_SHA256:
|
||||
ip->sha256digest = strdup(val);
|
||||
if(!ip->sha256digest)
|
||||
if (!ip->sha256digest) {
|
||||
RECORD_FAILURE(31, ENOMEM);
|
||||
errx(1, "strdup");
|
||||
}
|
||||
break;
|
||||
case F_RMD160:
|
||||
ip->rmd160digest = strdup(val);
|
||||
if(!ip->rmd160digest)
|
||||
if (!ip->rmd160digest) {
|
||||
RECORD_FAILURE(32, ENOMEM);
|
||||
errx(1, "strdup");
|
||||
}
|
||||
break;
|
||||
case F_FLAGS:
|
||||
if (strcmp("none", val) == 0)
|
||||
if (strcmp("none", val) == 0) {
|
||||
ip->st_flags = 0;
|
||||
else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
|
||||
} else if (strtofflags(&val, &ip->st_flags, NULL) != 0) {
|
||||
RECORD_FAILURE(33, EINVAL);
|
||||
errx(1, "line %d: invalid flag %s",lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_GID:
|
||||
ip->st_gid = (gid_t)strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(34, EINVAL);
|
||||
errx(1, "line %d: invalid gid %s", lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_GNAME:
|
||||
if ((gr = getgrnam(val)) == NULL)
|
||||
if ((gr = getgrnam(val)) == NULL) {
|
||||
RECORD_FAILURE(35, EINVAL);
|
||||
errx(1, "line %d: unknown group %s", lineno, val);
|
||||
}
|
||||
ip->st_gid = gr->gr_gid;
|
||||
break;
|
||||
case F_IGN:
|
||||
/* just set flag bit */
|
||||
break;
|
||||
case F_MODE:
|
||||
if ((m = setmode(val)) == NULL)
|
||||
if ((m = setmode(val)) == NULL) {
|
||||
RECORD_FAILURE(36, EINVAL);
|
||||
errx(1, "line %d: invalid file mode %s",
|
||||
lineno, val);
|
||||
}
|
||||
ip->st_mode = getmode(m, 0);
|
||||
free(m);
|
||||
break;
|
||||
case F_NLINK:
|
||||
ip->st_nlink = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(37, EINVAL);
|
||||
errx(1, "line %d: invalid link count %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_SIZE:
|
||||
ip->st_size = strtoq(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(38, EINVAL);
|
||||
errx(1, "line %d: invalid size %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_SLINK:
|
||||
ip->slink = malloc(strlen(val) + 1);
|
||||
if (ip->slink == NULL)
|
||||
if (ip->slink == NULL) {
|
||||
RECORD_FAILURE(39, ENOMEM);
|
||||
errx(1, "malloc");
|
||||
if (strunvis(ip->slink, val) == -1)
|
||||
}
|
||||
if (strunvis(ip->slink, val) == -1) {
|
||||
RECORD_FAILURE(40, EILSEQ);
|
||||
errx(1, "symlink %s is ill-encoded", val);
|
||||
}
|
||||
break;
|
||||
case F_TIME:
|
||||
ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
|
||||
if (*ep != '.')
|
||||
if (*ep != '.') {
|
||||
RECORD_FAILURE(41, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
val = ep + 1;
|
||||
ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(42, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_TYPE:
|
||||
switch(*val) {
|
||||
@ -290,78 +336,132 @@ set(char *t, NODE *ip)
|
||||
ip->type = F_SOCK;
|
||||
break;
|
||||
default:
|
||||
RECORD_FAILURE(43, EINVAL);
|
||||
errx(1, "line %d: unknown file type %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_UID:
|
||||
ip->st_uid = (uid_t)strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(44, EINVAL);
|
||||
errx(1, "line %d: invalid uid %s", lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_UNAME:
|
||||
if ((pw = getpwnam(val)) == NULL)
|
||||
if ((pw = getpwnam(val)) == NULL) {
|
||||
RECORD_FAILURE(45, EINVAL);
|
||||
errx(1, "line %d: unknown user %s", lineno, val);
|
||||
}
|
||||
ip->st_uid = pw->pw_uid;
|
||||
break;
|
||||
case F_BTIME:
|
||||
ip->st_birthtimespec.tv_sec = strtoul(val, &ep, 10);
|
||||
if (*ep != '.')
|
||||
if (*ep != '.') {
|
||||
RECORD_FAILURE(46, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
val = ep + 1;
|
||||
ip->st_birthtimespec.tv_nsec = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(47, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_ATIME:
|
||||
ip->st_atimespec.tv_sec = strtoul(val, &ep, 10);
|
||||
if (*ep != '.')
|
||||
if (*ep != '.') {
|
||||
RECORD_FAILURE(48, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
val = ep + 1;
|
||||
ip->st_atimespec.tv_nsec = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(49, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_CTIME:
|
||||
ip->st_ctimespec.tv_sec = strtoul(val, &ep, 10);
|
||||
if (*ep != '.')
|
||||
if (*ep != '.') {
|
||||
RECORD_FAILURE(50, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
val = ep + 1;
|
||||
ip->st_ctimespec.tv_nsec = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(51, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_PTIME:
|
||||
ip->st_ptimespec.tv_sec = strtoul(val, &ep, 10);
|
||||
if (*ep != '.')
|
||||
if (*ep != '.') {
|
||||
RECORD_FAILURE(52, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
val = ep + 1;
|
||||
ip->st_ptimespec.tv_nsec = strtoul(val, &ep, 10);
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(53, EINVAL);
|
||||
errx(1, "line %d: invalid time %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_XATTRS:
|
||||
ip->xattrsdigest = strdup(val);
|
||||
if(!ip->xattrsdigest)
|
||||
err(1, "strdup");
|
||||
/*
|
||||
* Note this is nested inside an strtok loop,
|
||||
* strtok_r must be used to preserve the strtok context
|
||||
* of the loop.
|
||||
*/
|
||||
ep = strtok_r(val,".", &l);
|
||||
ip->xattrsdigest = strdup(ep);
|
||||
if (!ip->xattrsdigest) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(54, error);
|
||||
errc(1, error, "strdup");
|
||||
}
|
||||
val = strtok_r(NULL,".", &l);
|
||||
if (val) {
|
||||
ip->xdstream_priv_id = strtoull(val, &ep, 10);
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(55, EINVAL);
|
||||
errx(1, "line %d: invalid private id %s",
|
||||
lineno, val);
|
||||
}
|
||||
} else {
|
||||
ip->xdstream_priv_id = 0;
|
||||
}
|
||||
break;
|
||||
case F_INODE:
|
||||
ip->st_ino = (ino_t)strtoull(val, &ep, 10);
|
||||
if (*ep)
|
||||
errx(1, "line %d: invalid inode %s", lineno, val);
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(56, EINVAL);
|
||||
errx(1, "line %d: invalid inode %s",
|
||||
lineno, val);
|
||||
}
|
||||
break;
|
||||
case F_ACL:
|
||||
ip->acldigest = strdup(val);
|
||||
if(!ip->acldigest)
|
||||
err(1, "strdup");
|
||||
if (!ip->acldigest) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(57, error);
|
||||
errc(1, error, "strdup");
|
||||
}
|
||||
break;
|
||||
case F_SIBLINGID:
|
||||
ip->sibling_id = (quad_t)strtoull(val, &ep, 10);
|
||||
if (*ep) {
|
||||
RECORD_FAILURE(58, EINVAL);
|
||||
errx(1, "line %d: invalid sibling id %s", lineno, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/specspec.c,v 1.6 2005/03/29 11:44:17 tobe
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
@ -98,11 +99,13 @@ shownode(NODE *n, int f, char const *path)
|
||||
if (f & F_PTIME)
|
||||
printf(" ptime=%ld.%09ld", n->st_ptimespec.tv_sec, n->st_ptimespec.tv_nsec);
|
||||
if (f & F_XATTRS)
|
||||
printf(" xattrsdigest=%s", n->xattrsdigest);
|
||||
printf(" xattrsdigest=%s.%llu", n->xattrsdigest, n->xdstream_priv_id);
|
||||
if (f & F_INODE)
|
||||
printf(" inode=%llu", n->st_ino);
|
||||
if (f & F_ACL)
|
||||
printf(" acldigest=%s", n->acldigest);
|
||||
if (f & F_SIBLINGID)
|
||||
printf(" siblingid=%llu", n->sibling_id);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
@ -143,14 +146,17 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
|
||||
return 0;
|
||||
} else if (n1 == NULL) {
|
||||
differs = n2->flags;
|
||||
RECORD_FAILURE(111, WARN_MISMATCH);
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
} else if (n2 == NULL) {
|
||||
differs = n1->flags;
|
||||
RECORD_FAILURE(112, WARN_MISMATCH);
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
} else if (n1->type != n2->type) {
|
||||
differs = 0;
|
||||
RECORD_FAILURE(113, WARN_MISMATCH);
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
}
|
||||
@ -198,8 +204,11 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
|
||||
differs |= F_INODE;
|
||||
if (FS(n1, n2, F_ACL, acldigest))
|
||||
differs |= F_ACL;
|
||||
if (FF(n1, n2, F_SIBLINGID, sibling_id))
|
||||
differs |= F_SIBLINGID;
|
||||
|
||||
if (differs) {
|
||||
RECORD_FAILURE(114, WARN_MISMATCH);
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
}
|
||||
@ -208,7 +217,7 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
|
||||
static int
|
||||
walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
|
||||
{
|
||||
int r, i;
|
||||
int r, i, c;
|
||||
NODE *c1, *c2, *n1, *n2;
|
||||
char *np;
|
||||
|
||||
@ -249,22 +258,49 @@ walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
|
||||
if (c1 == NULL && c2->type == F_DIR) {
|
||||
asprintf(&np, "%s%s/", path, c2->name);
|
||||
i = walk_in_the_forest(c1, c2, np);
|
||||
if (i) {
|
||||
RECORD_FAILURE(115, WARN_MISMATCH);
|
||||
}
|
||||
free(np);
|
||||
i += compare_nodes(c1, c2, path);
|
||||
c = compare_nodes(c1, c2, path);
|
||||
if (c) {
|
||||
RECORD_FAILURE(116, WARN_MISMATCH);
|
||||
}
|
||||
i += c;
|
||||
} else if (c2 == NULL && c1->type == F_DIR) {
|
||||
asprintf(&np, "%s%s/", path, c1->name);
|
||||
i = walk_in_the_forest(c1, c2, np);
|
||||
if (i) {
|
||||
RECORD_FAILURE(117, WARN_MISMATCH);
|
||||
}
|
||||
free(np);
|
||||
i += compare_nodes(c1, c2, path);
|
||||
c = compare_nodes(c1, c2, path);
|
||||
if (c) {
|
||||
RECORD_FAILURE(118, WARN_MISMATCH);
|
||||
}
|
||||
i += c;
|
||||
} else if (c1 == NULL || c2 == NULL) {
|
||||
i = compare_nodes(c1, c2, path);
|
||||
if (i) {
|
||||
RECORD_FAILURE(119, WARN_MISMATCH);
|
||||
}
|
||||
} else if (c1->type == F_DIR && c2->type == F_DIR) {
|
||||
asprintf(&np, "%s%s/", path, c1->name);
|
||||
i = walk_in_the_forest(c1, c2, np);
|
||||
if (i) {
|
||||
RECORD_FAILURE(120, WARN_MISMATCH);
|
||||
}
|
||||
free(np);
|
||||
i += compare_nodes(c1, c2, path);
|
||||
c = compare_nodes(c1, c2, path);
|
||||
if (c) {
|
||||
RECORD_FAILURE(121, WARN_MISMATCH);
|
||||
}
|
||||
i += c;
|
||||
} else {
|
||||
i = compare_nodes(c1, c2, path);
|
||||
if (i) {
|
||||
RECORD_FAILURE(122, WARN_MISMATCH);
|
||||
}
|
||||
}
|
||||
r += i;
|
||||
c1 = n1;
|
||||
@ -283,7 +319,9 @@ mtree_specspec(FILE *fi, FILE *fj)
|
||||
root2 = mtree_readspec(fj);
|
||||
rval = walk_in_the_forest(root1, root2, "");
|
||||
rval += compare_nodes(root1, root2, "");
|
||||
if (rval > 0)
|
||||
if (rval > 0) {
|
||||
RECORD_FAILURE(123, WARN_MISMATCH);
|
||||
return (MISMATCHEXIT);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
143
mtree/verify.c
143
mtree/verify.c
@ -45,33 +45,42 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <removefile.h>
|
||||
#include "metrics.h"
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
static NODE *root;
|
||||
static char path[MAXPATHLEN];
|
||||
|
||||
static int miss(NODE *, char *);
|
||||
static int miss(NODE *, char *, size_t path_length);
|
||||
static int vwalk(void);
|
||||
|
||||
int
|
||||
mtree_verifyspec(FILE *fi)
|
||||
{
|
||||
int rval, mval;
|
||||
size_t path_length = 0;
|
||||
|
||||
root = mtree_readspec(fi);
|
||||
rval = vwalk();
|
||||
mval = miss(root, path);
|
||||
mval = miss(root, path, path_length);
|
||||
|
||||
if (rval != 0)
|
||||
if (rval != 0) {
|
||||
RECORD_FAILURE(60, WARN_MISMATCH);
|
||||
return rval;
|
||||
else
|
||||
} else {
|
||||
if (mval != 0) {
|
||||
RECORD_FAILURE(61, WARN_MISMATCH);
|
||||
}
|
||||
return mval;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vwalk(void)
|
||||
{
|
||||
int error = 0;
|
||||
FTS *t;
|
||||
FTSENT *p;
|
||||
NODE *ep, *level;
|
||||
@ -81,8 +90,11 @@ vwalk(void)
|
||||
|
||||
argv[0] = dot;
|
||||
argv[1] = NULL;
|
||||
if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
|
||||
err(1, "line %d: fts_open", lineno);
|
||||
if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(62, error);
|
||||
errc(1, error, "line %d: fts_open", lineno);
|
||||
}
|
||||
level = root;
|
||||
specdepth = rval = 0;
|
||||
while ((p = fts_read(t))) {
|
||||
@ -96,6 +108,7 @@ vwalk(void)
|
||||
break;
|
||||
case FTS_DP:
|
||||
if (level == NULL) {
|
||||
RECORD_FAILURE(63, EINVAL);
|
||||
errx(1 , "invalid root in vwalk");
|
||||
}
|
||||
if (specdepth > p->fts_level) {
|
||||
@ -122,8 +135,10 @@ vwalk(void)
|
||||
!strcmp(ep->name, p->fts_name)) {
|
||||
ep->flags |= F_VISIT;
|
||||
if ((ep->flags & F_NOCHANGE) == 0 &&
|
||||
compare(ep->name, ep, p))
|
||||
compare(ep->name, ep, p)) {
|
||||
RECORD_FAILURE(64, WARN_MISMATCH);
|
||||
rval = MISMATCHEXIT;
|
||||
}
|
||||
if (ep->flags & F_IGN)
|
||||
(void)fts_set(t, p, FTS_SKIP);
|
||||
else if (ep->child && ep->type == F_DIR &&
|
||||
@ -139,26 +154,61 @@ vwalk(void)
|
||||
extra:
|
||||
if (!eflag) {
|
||||
(void)printf("%s extra", RP(p));
|
||||
|
||||
if (rflag) {
|
||||
if ((S_ISDIR(p->fts_statp->st_mode)
|
||||
? rmdir : unlink)(p->fts_accpath)) {
|
||||
(void)printf(", not removed: %s",
|
||||
strerror(errno));
|
||||
} else
|
||||
(void)printf(", removed");
|
||||
/* rflag implies: delete stuff if "extra" is observed" */
|
||||
if (mflag) {
|
||||
/* -mflag is used for sealing & verification -- use removefile for recursive behavior */
|
||||
removefile_state_t rmstate;
|
||||
rmstate = removefile_state_alloc();
|
||||
if (removefile(p->fts_accpath, rmstate, (REMOVEFILE_RECURSIVE))) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(65, error);
|
||||
errx (1, "\n error deleting item (or descendant) at path %s (%s)", RP(p), strerror(error));
|
||||
}
|
||||
else {
|
||||
/* removefile success */
|
||||
(void) printf(", removed");
|
||||
}
|
||||
removefile_state_free(rmstate);
|
||||
|
||||
}
|
||||
else {
|
||||
/* legacy: use rmdir/unlink if "-m" not specified */
|
||||
int syserr = 0;
|
||||
|
||||
if (S_ISDIR(p->fts_statp->st_mode)){
|
||||
syserr = rmdir(p->fts_accpath);
|
||||
}
|
||||
else {
|
||||
syserr = unlink(p->fts_accpath);
|
||||
}
|
||||
|
||||
/* log failures */
|
||||
if (syserr) {
|
||||
error = errno;
|
||||
RECORD_FAILURE(66, error);
|
||||
(void) printf(", not removed :%s", strerror(error));
|
||||
}
|
||||
}
|
||||
} else if (mflag) {
|
||||
RECORD_FAILURE(68956, WARN_MISMATCH);
|
||||
errx(1, "cannot generate the XML dictionary");
|
||||
}
|
||||
(void)putchar('\n');
|
||||
}
|
||||
(void)fts_set(t, p, FTS_SKIP);
|
||||
}
|
||||
(void)fts_close(t);
|
||||
if (sflag)
|
||||
if (sflag) {
|
||||
RECORD_FAILURE(67, WARN_CHECKSUM);
|
||||
warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
|
||||
}
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static int
|
||||
miss(NODE *p, char *tail)
|
||||
miss(NODE *p, char *tail, size_t path_length)
|
||||
{
|
||||
int create;
|
||||
char *tp;
|
||||
@ -166,10 +216,17 @@ miss(NODE *p, char *tail)
|
||||
int serr;
|
||||
int rval = 0;
|
||||
int rrval = 0;
|
||||
size_t file_name_length = 0;
|
||||
|
||||
for (; p; p = p->next) {
|
||||
if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
|
||||
continue;
|
||||
file_name_length = strnlen(p->name, MAXPATHLEN);
|
||||
path_length += file_name_length;
|
||||
if (path_length >= MAXPATHLEN) {
|
||||
RECORD_FAILURE(61971, ENAMETOOLONG);
|
||||
continue;
|
||||
}
|
||||
(void)strcpy(tail, p->name);
|
||||
if (!(p->flags & F_VISIT)) {
|
||||
/* Don't print missing message if file exists as a
|
||||
@ -180,6 +237,7 @@ miss(NODE *p, char *tail)
|
||||
p->flags |= F_VISIT;
|
||||
} else {
|
||||
(void)printf("%s missing", path);
|
||||
RECORD_FAILURE(68, WARN_MISMATCH);
|
||||
rval = MISMATCHEXIT;
|
||||
}
|
||||
}
|
||||
@ -194,16 +252,19 @@ miss(NODE *p, char *tail)
|
||||
else
|
||||
type = "directory";
|
||||
if (!(p->flags & F_VISIT) && uflag) {
|
||||
if (!(p->flags & (F_UID | F_UNAME)))
|
||||
if (!(p->flags & (F_UID | F_UNAME))) {
|
||||
(void)printf(" (%s not created: user not specified)", type);
|
||||
else if (!(p->flags & (F_GID | F_GNAME)))
|
||||
} else if (!(p->flags & (F_GID | F_GNAME))) {
|
||||
(void)printf(" (%s not created: group not specified)", type);
|
||||
else if (p->type == F_LINK) {
|
||||
if (symlink(p->slink, path))
|
||||
} else if (p->type == F_LINK) {
|
||||
if (symlink(p->slink, path)) {
|
||||
serr = errno;
|
||||
RECORD_FAILURE(69, serr);
|
||||
(void)printf(" (symlink not created: %s)\n",
|
||||
strerror(errno));
|
||||
else
|
||||
strerror(serr));
|
||||
} else {
|
||||
(void)printf(" (created)\n");
|
||||
}
|
||||
if (lchown(path, p->st_uid, p->st_gid) == -1) {
|
||||
serr = errno;
|
||||
if (p->st_uid == (uid_t)-1)
|
||||
@ -215,16 +276,20 @@ miss(NODE *p, char *tail)
|
||||
what = "user";
|
||||
errno = serr;
|
||||
}
|
||||
serr = errno;
|
||||
RECORD_FAILURE(70, serr);
|
||||
(void)printf("%s: %s not modified: %s"
|
||||
"\n", path, what, strerror(errno));
|
||||
"\n", path, what, strerror(serr));
|
||||
}
|
||||
continue;
|
||||
} else if (!(p->flags & F_MODE))
|
||||
} else if (!(p->flags & F_MODE)) {
|
||||
(void)printf(" (directory not created: mode not specified)");
|
||||
else if (mkdir(path, S_IRWXU))
|
||||
} else if (mkdir(path, S_IRWXU)) {
|
||||
serr = errno;
|
||||
RECORD_FAILURE(71, serr);
|
||||
(void)printf(" (directory not created: %s)",
|
||||
strerror(errno));
|
||||
else {
|
||||
strerror(serr));
|
||||
} else {
|
||||
create = 1;
|
||||
(void)printf(" (created)");
|
||||
}
|
||||
@ -234,9 +299,13 @@ miss(NODE *p, char *tail)
|
||||
|
||||
for (tp = tail; *tp; ++tp);
|
||||
*tp = '/';
|
||||
rrval = miss(p->child, tp + 1);
|
||||
if (rrval != 0)
|
||||
++path_length;
|
||||
rrval = miss(p->child, tp + 1, path_length);
|
||||
if (rrval != 0) {
|
||||
RECORD_FAILURE(72, WARN_MISMATCH);
|
||||
rval = rrval;
|
||||
}
|
||||
path_length -= (file_name_length + 1);
|
||||
*tp = '\0';
|
||||
|
||||
if (!create)
|
||||
@ -251,16 +320,24 @@ miss(NODE *p, char *tail)
|
||||
what = "user";
|
||||
errno = serr;
|
||||
}
|
||||
serr = errno;
|
||||
RECORD_FAILURE(73, serr);
|
||||
(void)printf("%s: %s not modified: %s\n",
|
||||
path, what, strerror(errno));
|
||||
path, what, strerror(serr));
|
||||
}
|
||||
if (chmod(path, p->st_mode))
|
||||
if (chmod(path, p->st_mode)) {
|
||||
serr = errno;
|
||||
RECORD_FAILURE(74, serr);
|
||||
(void)printf("%s: permissions not set: %s\n",
|
||||
path, strerror(errno));
|
||||
path, strerror(serr));
|
||||
}
|
||||
if ((p->flags & F_FLAGS) && p->st_flags &&
|
||||
chflags(path, (u_int)p->st_flags))
|
||||
chflags(path, (u_int)p->st_flags)) {
|
||||
serr = errno;
|
||||
RECORD_FAILURE(75, serr);
|
||||
(void)printf("%s: file flags not set: %s\n",
|
||||
path, strerror(errno));
|
||||
path, strerror(serr));
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
@ -34,7 +34,12 @@
|
||||
* $FreeBSD: src/bin/mv/pathnames.h,v 1.6 2002/05/17 11:38:48 jmallett Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MV_PATHNAMES_H_
|
||||
#define _MV_PATHNAMES_H_
|
||||
|
||||
#define _PATH_RM "/bin/rm"
|
||||
#ifdef __APPLE__
|
||||
#define _PATH_CP "/bin/cp"
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#endif /* _MV_PATHNAMES_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)cache.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _CACHE_H_
|
||||
#define _CACHE_H_
|
||||
|
||||
/*
|
||||
* Constants and data structures used to implement group and password file
|
||||
* caches. Traditional passwd/group cache routines perform quite poorly with
|
||||
@ -71,3 +74,5 @@ typedef struct gidc {
|
||||
char name[GNMLEN]; /* gid name */
|
||||
gid_t gid; /* cached gid */
|
||||
} GIDC;
|
||||
|
||||
#endif /* _CACHE_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)cpio.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _CPIO_H_
|
||||
#define _CPIO_H_
|
||||
|
||||
/*
|
||||
* Defines common to all versions of cpio
|
||||
*/
|
||||
@ -148,3 +151,5 @@ typedef struct {
|
||||
#define VCPIO_PAD(x) ((4 - ((x) & 3)) & 3) /* pad to next 4 byte word */
|
||||
#define VCPIO_MASK 0xffffffff /* mask for dev/ino fields */
|
||||
#endif /* _PAX_ */
|
||||
|
||||
#endif /* _CPIO_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)extern.h 8.2 (Berkeley) 4/18/94
|
||||
*/
|
||||
|
||||
#ifndef _PAX_EXTERN_H_
|
||||
#define _PAX_EXTERN_H_
|
||||
|
||||
/*
|
||||
* External references from each source file
|
||||
*/
|
||||
@ -200,9 +203,6 @@ int opt_add(const char *);
|
||||
int bad_opt(void);
|
||||
int pax_format_opt_add(char *);
|
||||
int pax_opt(void);
|
||||
#ifdef DARLING
|
||||
extern
|
||||
#endif
|
||||
char *chdname;
|
||||
|
||||
/*
|
||||
@ -343,3 +343,5 @@ void tty_prnt(const char *, ...);
|
||||
int tty_read(char *, int);
|
||||
void paxwarn(int, const char *, ...);
|
||||
void syswarn(int, int, const char *, ...);
|
||||
|
||||
#endif /* _PAX_EXTERN_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)ftree.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _FTREE_H_
|
||||
#define _FTREE_H_
|
||||
|
||||
/*
|
||||
* Data structure used by the ftree.c routines to store the file args to be
|
||||
* handed to fts(). It keeps a reference count of which args generated a
|
||||
@ -49,3 +52,5 @@ typedef struct ftree {
|
||||
int chflg; /* change directory flag */
|
||||
struct ftree *fow; /* pointer to next entry on list */
|
||||
} FTREE;
|
||||
|
||||
#endif /* _FTREE_H_ */
|
||||
|
@ -216,17 +216,26 @@ ls_tty(ARCHD *arcn)
|
||||
void
|
||||
safe_print(const char *str, FILE *fp)
|
||||
{
|
||||
char visbuf[5];
|
||||
const char *cp;
|
||||
|
||||
/*
|
||||
* if printing to a tty, use vis(3) to print special characters.
|
||||
* if printing to a tty, use strvis(3) to print special characters.
|
||||
*/
|
||||
if (isatty(fileno(fp))) {
|
||||
for (cp = str; *cp; cp++) {
|
||||
(void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
|
||||
(void)fputs(visbuf, fp);
|
||||
/*
|
||||
* The size of visbuf must be four times the number
|
||||
* of bytes encoded from str (plus one for the NUL).
|
||||
*/
|
||||
char *visbuf = (char *) malloc(sizeof(char) * (4 * strlen(str) + 1));
|
||||
if (visbuf == NULL) {
|
||||
paxwarn(1, "Out of memory");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* using strvis(3) instead of vis(3) to account for multibyte
|
||||
* characters
|
||||
*/
|
||||
(void)strvis(visbuf, str, VIS_CSTYLE);
|
||||
(void)fputs(visbuf, fp);
|
||||
free(visbuf);
|
||||
} else {
|
||||
(void)fputs(str, fp);
|
||||
}
|
||||
|
@ -161,10 +161,6 @@ int ford[] = {F_PAX, F_TAR, F_OTAR, F_CPIO, F_SCPIO, F_ACPIO, F_OCPIO, -1 };
|
||||
*/
|
||||
int havechd = 0;
|
||||
|
||||
#ifdef DARLING
|
||||
char* chdname = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* options()
|
||||
* figure out if we are pax, tar or cpio. Call the appropriate options
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)options.h 8.2 (Berkeley) 4/18/94
|
||||
*/
|
||||
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
|
||||
/*
|
||||
* argv[0] names. Used for tar and cpio emulation
|
||||
*/
|
||||
@ -111,3 +114,5 @@
|
||||
#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_ */
|
||||
|
149
pax/pat_rep.c
149
pax/pat_rep.c
@ -74,6 +74,10 @@ static int rep_name(char *, size_t, int *, int);
|
||||
int tty_rename(ARCHD *);
|
||||
static int fix_path(char *, int *, char *, int);
|
||||
static int fn_match(char *, char *, char **);
|
||||
#ifdef _HAVE_REGCOMP_
|
||||
static char* extract_equiv_pat(char *, char **);
|
||||
static int regex_match(char *, char *, char **);
|
||||
#endif
|
||||
static char * range_match(char *, int);
|
||||
static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *);
|
||||
|
||||
@ -495,6 +499,10 @@ fn_match(char *pattern, char *string, char **pend)
|
||||
{
|
||||
char c;
|
||||
char test;
|
||||
#ifdef _HAVE_REGCOMP_
|
||||
char *equiv_pat;
|
||||
char *pat_pend = NULL;
|
||||
#endif
|
||||
|
||||
*pend = NULL;
|
||||
for (;;) {
|
||||
@ -549,10 +557,33 @@ fn_match(char *pattern, char *string, char **pend)
|
||||
/*
|
||||
* range match
|
||||
*/
|
||||
#ifdef _HAVE_REGCOMP_
|
||||
/*
|
||||
* Check for equivalence class and use regex_match to
|
||||
* handle this case. Note pattern should include the
|
||||
* opening bracket '['
|
||||
*/
|
||||
equiv_pat = extract_equiv_pat(pattern-1, &pat_pend);
|
||||
if (equiv_pat) {
|
||||
if (regex_match(equiv_pat, string, &string) == -1) {
|
||||
free (equiv_pat);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
free(equiv_pat);
|
||||
|
||||
/*
|
||||
* Update the pattern string
|
||||
*/
|
||||
pattern = pat_pend;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (((test = *string++) == '\0') ||
|
||||
((pattern = range_match(pattern, test)) == NULL))
|
||||
return (-1);
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
default:
|
||||
if (c != *string++)
|
||||
@ -563,6 +594,124 @@ fn_match(char *pattern, char *string, char **pend)
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
#ifdef _HAVE_REGCOMP_
|
||||
static char*
|
||||
extract_equiv_pat(char *pattern, char **pend)
|
||||
{
|
||||
int pat_len = 2;
|
||||
int found = 0;
|
||||
int is_double_bracket = 0;
|
||||
char* equiv_pat = NULL;
|
||||
|
||||
if (*pattern == '\0' || pattern[1] == '\0' || pattern[2] == '\0')
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* check if the pattern is
|
||||
* "[= =]", "[[= =][= =]]", "[: :]", or "[[: :][: :]]"
|
||||
* note that the full "pattern" string needs to be passed in
|
||||
*/
|
||||
is_double_bracket = (*pattern == '[' && pattern[1] == '[');
|
||||
if (!(*pattern == '[') && !is_double_bracket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pattern ++;
|
||||
|
||||
if (is_double_bracket) {
|
||||
pattern ++;
|
||||
pat_len ++;
|
||||
}
|
||||
|
||||
if (!(*pattern == ':') && !(*pattern == '=')) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pattern ++;
|
||||
|
||||
|
||||
for(; *pattern != '\0'; pat_len++, pattern++) {
|
||||
if (!is_double_bracket) {
|
||||
if ((*pattern == '=' || *pattern == ':')
|
||||
&& pattern[1] == ']') {
|
||||
found = 1;
|
||||
pattern += 2;
|
||||
pat_len += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
if ((*pattern == '=' || *pattern == ':')
|
||||
&& pattern[1] == ']' && pattern[2] == ']') {
|
||||
found = 1;
|
||||
pattern += 3;
|
||||
pat_len += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
equiv_pat = strndup(pattern-pat_len, pat_len);
|
||||
|
||||
if (equiv_pat == NULL) {
|
||||
paxwarn(1, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set pend to the remaining pattern to be matched
|
||||
*/
|
||||
if (pend != NULL) {
|
||||
*pend = pattern;
|
||||
}
|
||||
|
||||
return equiv_pat;
|
||||
}
|
||||
|
||||
static int
|
||||
regex_match(char *pattern, char *string, char **pend)
|
||||
{
|
||||
int res;
|
||||
regex_t preg;
|
||||
regmatch_t pmatch;
|
||||
char rebuf[BUFSIZ];
|
||||
|
||||
if ((res = regcomp(&(preg), pattern, REG_EXTENDED)) != 0) {
|
||||
regerror(res, &(preg), rebuf, sizeof(rebuf));
|
||||
paxwarn(1, "%s while compiling pattern %s", rebuf, pattern);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (regexec(&(preg), string, 1, &(pmatch), 0) != 0) {
|
||||
regfree(&(preg));
|
||||
return(-1);
|
||||
}
|
||||
|
||||
regfree(&(preg));
|
||||
|
||||
/*
|
||||
* starting position of the match must be 0
|
||||
*/
|
||||
if (pmatch.rm_so != 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* set pend to the remaining string to be matched
|
||||
*/
|
||||
if (pend != NULL) {
|
||||
*pend = string + pmatch.rm_eo;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *
|
||||
range_match(char *pattern, int test)
|
||||
{
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)pat_rep.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _PAT_REP_H_
|
||||
#define _PAT_REP_H_
|
||||
|
||||
/*
|
||||
* data structure for storing user supplied replacement strings (-s)
|
||||
*/
|
||||
@ -49,3 +52,5 @@ typedef struct replace {
|
||||
} REPLACE;
|
||||
|
||||
int tty_rename(ARCHD *); /* used for -o invalid=rename recovery */
|
||||
|
||||
#endif /* _PAT_REP_H_ */
|
||||
|
@ -63,6 +63,7 @@ __used static const char rcsid[] = "$OpenBSD: pax.c,v 1.28 2005/08/04 10:02:44 m
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <locale.h>
|
||||
#include "pax.h"
|
||||
#include "extern.h"
|
||||
static int gen_init(void);
|
||||
@ -236,6 +237,10 @@ main(int argc, char **argv)
|
||||
{
|
||||
char *tmpdir;
|
||||
size_t tdlen;
|
||||
#ifdef _HAVE_REGCOMP_
|
||||
setlocale(LC_CTYPE, "");
|
||||
setlocale(LC_COLLATE, "");
|
||||
#endif
|
||||
|
||||
listf = stderr;
|
||||
/*
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)pax.h 8.2 (Berkeley) 4/18/94
|
||||
*/
|
||||
|
||||
#ifndef _PAX_H_
|
||||
#define _PAX_H_
|
||||
|
||||
/*
|
||||
* BSD PAX global data structures and constants.
|
||||
*/
|
||||
@ -246,4 +249,7 @@ typedef struct oplist {
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define _PAX_ 1
|
||||
#define _HAVE_REGCOMP_ 1
|
||||
#define _TFILE_BASE "paxXXXXXXXXXX"
|
||||
|
||||
#endif /* _PAX_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)tar.h 8.2 (Berkeley) 4/18/94
|
||||
*/
|
||||
|
||||
#ifndef _PAX_FORMAT_H_
|
||||
#define _PAX_FORMAT_H_
|
||||
|
||||
/*
|
||||
* defines and data structures common to all tar formats
|
||||
*/
|
||||
@ -151,3 +154,5 @@ typedef struct {
|
||||
char devminor[8]; /* minor device number */
|
||||
char prefix[TPFSZ]; /* linked to name */
|
||||
} HD_USTAR;
|
||||
|
||||
#endif /* _PAX_FORMAT_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)sel_subs.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _SEL_SUBS_H_
|
||||
#define _SEL_SUBS_H_
|
||||
|
||||
/*
|
||||
* data structure for storing uid/grp selects (-U, -G non standard options)
|
||||
*/
|
||||
@ -70,3 +73,5 @@ typedef struct time_rng {
|
||||
#define CMPBOTH (CMPMTME|CMPCTME) /* compare inode and mod time */
|
||||
struct time_rng *fow; /* next pattern */
|
||||
} TIME_RNG;
|
||||
|
||||
#endif /* _SEL_SUBS_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)tables.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _TABLES_H_
|
||||
#define _TABLES_H_
|
||||
|
||||
/*
|
||||
* data structures and constants used by the different databases kept by pax
|
||||
*/
|
||||
@ -168,3 +171,5 @@ typedef struct dirdata {
|
||||
u_int16_t mode; /* file mode to restore */
|
||||
u_int16_t frc_mode; /* do we force mode settings? */
|
||||
} DIRDATA;
|
||||
|
||||
#endif /* _TABLES_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
* @(#)tar.h 8.2 (Berkeley) 4/18/94
|
||||
*/
|
||||
|
||||
#ifndef _TAR_H_
|
||||
#define _TAR_H_
|
||||
|
||||
/*
|
||||
* defines and data structures common to all tar formats
|
||||
*/
|
||||
@ -154,3 +157,5 @@ typedef struct {
|
||||
char devminor[8]; /* minor device number */
|
||||
char prefix[TPFSZ]; /* linked to name */
|
||||
} HD_USTAR;
|
||||
|
||||
#endif /* _TAR_H_ */
|
||||
|
12
rm/rm.c
12
rm/rm.c
@ -286,12 +286,16 @@ rm_tree(argv)
|
||||
case FTS_DP:
|
||||
case FTS_DNR:
|
||||
#if __APPLE__
|
||||
if (p->fts_statp != NULL && (p->fts_statp->st_flags & SF_DATALESS) != 0)
|
||||
rval = unlinkat(AT_FDCWD, p->fts_accpath, AT_REMOVEDIR_DATALESS);
|
||||
else
|
||||
rval = unlinkat(AT_FDCWD, p->fts_accpath, AT_REMOVEDIR_DATALESS);
|
||||
if (rval == -1 && errno == EINVAL) {
|
||||
/*
|
||||
* Kernel rejected AT_REMOVEDIR_DATALESS?
|
||||
* I guess we fall back on the painful
|
||||
* route (but it's better than failing).
|
||||
*/
|
||||
rval = rmdir(p->fts_accpath);
|
||||
}
|
||||
#else
|
||||
|
||||
rval = rmdir(p->fts_accpath);
|
||||
#endif
|
||||
if (rval == 0 || (fflag && errno == ENOENT)) {
|
||||
|
23
tests/cp.sh
Normal file
23
tests/cp.sh
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Regression test for 69452380
|
||||
function regression_69452380()
|
||||
{
|
||||
echo "Verifying that cp -p preserves symlink's attributes, rather than the attributes of the symlink's target."
|
||||
test_dir=`mktemp -d /tmp/69452380_src_XXXX`
|
||||
touch ${test_dir}/target
|
||||
mkdir ${test_dir}/link_dir
|
||||
# Create symlink (must use relative path for the failure to occur)
|
||||
cd ${test_dir}/link_dir
|
||||
ln -s ../target link
|
||||
# cp (with attribute preservation) the test dir containing both the
|
||||
# target and the link (in a subdirectory) to a new dir.
|
||||
# Prior to 69452380, this failed because we followed the symlink to
|
||||
# try and preserve attributes for a non-existing file, instead of
|
||||
# preserving the attributes of the symlink itself.
|
||||
cp -R -P -p ${test_dir} /tmp/69452380_tgt_${RANDOM}
|
||||
}
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
regression_69452380
|
@ -8,6 +8,42 @@
|
||||
<true/>
|
||||
<key>Tests</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Command</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>cp.sh</string>
|
||||
</array>
|
||||
<key>AsRoot</key>
|
||||
<false/>
|
||||
<key>TestName</key>
|
||||
<string>cp</string>
|
||||
<key>WhenToRun</key>
|
||||
<array>
|
||||
<string>PRESUBMISSION</string>
|
||||
<string>NIGHTLY</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/AppleInternal/Tests/file_cmds</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Command</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>touch.sh</string>
|
||||
</array>
|
||||
<key>AsRoot</key>
|
||||
<false/>
|
||||
<key>TestName</key>
|
||||
<string>touch</string>
|
||||
<key>WhenToRun</key>
|
||||
<array>
|
||||
<string>PRESUBMISSION</string>
|
||||
<string>NIGHTLY</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/AppleInternal/Tests/file_cmds</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Command</key>
|
||||
<array>
|
||||
|
14
tests/touch.sh
Normal file
14
tests/touch.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
file_name=`mktemp /tmp/XXXXXX`
|
||||
file_ctime=`/usr/bin/stat -f%c ${file_name}`
|
||||
|
||||
/usr/bin/touch $file_name
|
||||
file_mtime=`/usr/bin/stat -f%m ${file_name}`
|
||||
|
||||
if [ "$file_ctime" -gt "$file_mtime" ]; then
|
||||
echo "file's mod time ($file_mtime) should be later than the file's creation time ($file_ctime)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
@ -48,6 +48,7 @@ __used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/attr.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
@ -59,10 +60,15 @@ __used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct {
|
||||
struct timespec mtime;
|
||||
struct timespec atime;
|
||||
} set_ts;
|
||||
|
||||
int rw(char *, struct stat *, int);
|
||||
void stime_arg1(char *, struct timeval *);
|
||||
void stime_arg2(char *, int, struct timeval *);
|
||||
void stime_file(char *, struct timeval *);
|
||||
void stime_arg1(char *, set_ts *);
|
||||
void stime_arg2(char *, int, set_ts *);
|
||||
void stime_file(char *, set_ts *);
|
||||
int timeoffset(char *);
|
||||
void usage(char *);
|
||||
|
||||
@ -70,19 +76,24 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct stat sb;
|
||||
struct timeval tv[2];
|
||||
int (*stat_f)(const char *, struct stat *);
|
||||
int (*utimes_f)(const char *, const struct timeval *);
|
||||
int Aflag, aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset;
|
||||
char *p;
|
||||
char *myname;
|
||||
struct attrlist ts_req = {
|
||||
.bitmapcount = ATTR_BIT_MAP_COUNT,
|
||||
.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME,
|
||||
};
|
||||
set_ts ts_struct = {};
|
||||
|
||||
myname = basename(argv[0]);
|
||||
Aflag = aflag = cflag = fflag = mflag = timeset = 0;
|
||||
stat_f = stat;
|
||||
utimes_f = utimes;
|
||||
if (gettimeofday(&tv[0], NULL))
|
||||
err(1, "gettimeofday");
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts_struct.mtime))
|
||||
err(1, "clock_gettime");
|
||||
ts_struct.atime = ts_struct.mtime;
|
||||
|
||||
while ((ch = getopt(argc, argv, "A:acfhmr:t:")) != -1)
|
||||
switch(ch) {
|
||||
@ -108,11 +119,11 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
case 'r':
|
||||
timeset = 1;
|
||||
stime_file(optarg, tv);
|
||||
stime_file(optarg, &ts_struct);
|
||||
break;
|
||||
case 't':
|
||||
timeset = 1;
|
||||
stime_arg1(optarg, tv);
|
||||
stime_arg1(optarg, &ts_struct);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
@ -132,9 +143,9 @@ main(int argc, char *argv[])
|
||||
* that time once and for all here.
|
||||
*/
|
||||
if (aflag)
|
||||
tv[0].tv_sec += Aflag;
|
||||
ts_struct.atime.tv_sec += Aflag;
|
||||
if (mflag)
|
||||
tv[1].tv_sec += Aflag;
|
||||
ts_struct.mtime.tv_sec += Aflag;
|
||||
Aflag = 0; /* done our job */
|
||||
}
|
||||
} else {
|
||||
@ -148,11 +159,9 @@ main(int argc, char *argv[])
|
||||
len = p - argv[0];
|
||||
if (*p == '\0' && (len == 8 || len == 10)) {
|
||||
timeset = 1;
|
||||
stime_arg2(*argv++, len == 10, tv);
|
||||
stime_arg2(*argv++, len == 10, &ts_struct);
|
||||
}
|
||||
}
|
||||
/* Both times default to the same. */
|
||||
tv[1] = tv[0];
|
||||
}
|
||||
|
||||
if (*argv == NULL)
|
||||
@ -187,9 +196,9 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (!aflag)
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
|
||||
ts_struct.atime = sb.st_atimespec;
|
||||
if (!mflag)
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
|
||||
ts_struct.mtime = sb.st_mtimespec;
|
||||
|
||||
/*
|
||||
* We're adjusting the times based on the file times, not a
|
||||
@ -197,17 +206,17 @@ main(int argc, char *argv[])
|
||||
*/
|
||||
if (Aflag) {
|
||||
if (aflag) {
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
|
||||
tv[0].tv_sec += Aflag;
|
||||
ts_struct.atime = sb.st_atimespec;
|
||||
ts_struct.atime.tv_sec += Aflag;
|
||||
}
|
||||
if (mflag) {
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
|
||||
tv[1].tv_sec += Aflag;
|
||||
ts_struct.mtime = sb.st_mtimespec;
|
||||
ts_struct.mtime.tv_sec += Aflag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try utimes(2). */
|
||||
if (!utimes_f(*argv, tv))
|
||||
/* Try setattrlist(2). */
|
||||
if (!setattrlist(*argv, &ts_req, &ts_struct, sizeof(ts_struct), 0))
|
||||
continue;
|
||||
|
||||
/* If the user specified a time, nothing else we can do. */
|
||||
@ -241,14 +250,14 @@ main(int argc, char *argv[])
|
||||
#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
|
||||
|
||||
void
|
||||
stime_arg1(char *arg, struct timeval *tvp)
|
||||
stime_arg1(char *arg, set_ts *tsp)
|
||||
{
|
||||
time_t now;
|
||||
struct tm *t;
|
||||
int yearset;
|
||||
char *p;
|
||||
/* Start with the current time. */
|
||||
now = tvp[0].tv_sec;
|
||||
now = tsp->atime.tv_sec;
|
||||
if ((t = localtime(&now)) == NULL)
|
||||
err(1, "localtime");
|
||||
/* [[CC]YY]MMDDhhmm[.SS] */
|
||||
@ -293,21 +302,21 @@ stime_arg1(char *arg, struct timeval *tvp)
|
||||
}
|
||||
|
||||
t->tm_isdst = -1; /* Figure out DST. */
|
||||
tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
|
||||
if (tvp[0].tv_sec == -1)
|
||||
tsp->atime.tv_sec = tsp->mtime.tv_sec = mktime(t);
|
||||
if (tsp->atime.tv_sec == -1)
|
||||
terr: errx(1,
|
||||
"out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
|
||||
|
||||
tvp[0].tv_usec = tvp[1].tv_usec = 0;
|
||||
tsp->atime.tv_nsec = tsp->mtime.tv_nsec = 0;
|
||||
}
|
||||
|
||||
void
|
||||
stime_arg2(char *arg, int year, struct timeval *tvp)
|
||||
stime_arg2(char *arg, int year, set_ts *tsp)
|
||||
{
|
||||
time_t now;
|
||||
struct tm *t;
|
||||
/* Start with the current time. */
|
||||
now = tvp[0].tv_sec;
|
||||
now = tsp->atime.tv_sec;
|
||||
if ((t = localtime(&now)) == NULL)
|
||||
err(1, "localtime");
|
||||
|
||||
@ -323,12 +332,12 @@ stime_arg2(char *arg, int year, struct timeval *tvp)
|
||||
}
|
||||
|
||||
t->tm_isdst = -1; /* Figure out DST. */
|
||||
tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
|
||||
if (tvp[0].tv_sec == -1)
|
||||
tsp->atime.tv_sec = tsp->mtime.tv_sec = mktime(t);
|
||||
if (tsp->atime.tv_sec == -1)
|
||||
errx(1,
|
||||
"out of range or illegal time specification: MMDDhhmm[yy]");
|
||||
|
||||
tvp[0].tv_usec = tvp[1].tv_usec = 0;
|
||||
tsp->atime.tv_nsec = tsp->mtime.tv_nsec = 0;
|
||||
}
|
||||
|
||||
/* Calculate a time offset in seconds, given an arg of the format [-]HHMMSS. */
|
||||
@ -362,14 +371,14 @@ timeoffset(char *arg)
|
||||
}
|
||||
|
||||
void
|
||||
stime_file(char *fname, struct timeval *tvp)
|
||||
stime_file(char *fname, set_ts *ts_struct)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat(fname, &sb))
|
||||
err(1, "%s", fname);
|
||||
TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atimespec);
|
||||
TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtimespec);
|
||||
ts_struct->atime = sb.st_atimespec;
|
||||
ts_struct->mtime = sb.st_mtimespec;
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user