Update Source To file_cmds-321.100.11

This commit is contained in:
Thomas A 2023-01-31 11:21:51 -08:00
parent bfd92c440e
commit 390e64e423
52 changed files with 2015 additions and 356 deletions

View File

@ -31,6 +31,9 @@
* SUCH DAMAGE.
*/
#ifndef _CHMOD_ACL_H_
#define _CHMOD_ACL_H_
#ifdef __APPLE__
#include <pwd.h>
#include <grp.h>
@ -83,3 +86,5 @@ extern int modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
extern int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow);
extern uuid_t *name_to_uuid(char *tok, int nametype);
#endif /* __APPLE__*/
#endif /* _CHMOD_ACL_H_ */

View File

@ -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

View File

@ -34,6 +34,9 @@
* $FreeBSD: src/usr.bin/cksum/extern.h,v 1.6 2003/03/13 23:32:28 robert Exp $
*/
#ifndef _CKSUM_EXTERN_H_
#define _CKSUM_EXTERN_H_
#include <sys/cdefs.h>
__BEGIN_DECLS
@ -45,3 +48,5 @@ int csum1(int, uint32_t *, off_t *);
int csum2(int, uint32_t *, off_t *);
int crc32(int, uint32_t *, off_t *);
__END_DECLS
#endif /* _CKSUM_EXTERN_H_ */

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD: src/usr.bin/compress/compress.c,v 1.23 2010/12/11 08:32:16 j
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/attr.h>
#include <err.h>
#include <errno.h>
@ -382,14 +383,21 @@ err: if (ofp) {
void
setfile(const char *name, struct stat *fs)
{
static struct timeval tv[2];
struct attrlist ts_req = {};
struct {
struct timespec mtime;
struct timespec atime;
} set_ts;
fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
if (utimes(name, tv))
cwarn("utimes: %s", name);
ts_req.bitmapcount = ATTR_BIT_MAP_COUNT;
ts_req.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME;
set_ts.mtime = fs->st_mtimespec;
set_ts.atime = fs->st_atimespec;
if (setattrlist(name, &ts_req, &set_ts, sizeof(set_ts), 0))
cwarn("setattrlist: %s", name);
/*
* Changing the ownership probably won't succeed, unless we're root

View File

@ -30,6 +30,9 @@
* $FreeBSD: src/bin/cp/extern.h,v 1.20 2005/09/05 04:36:08 csjp Exp $
*/
#ifndef _CP_EXTERN_H_
#define _CP_EXTERN_H_
typedef struct {
char *p_end; /* pointer to NULL at end of path */
char *target_end; /* pointer to end of target base */
@ -54,3 +57,5 @@ int preserve_dir_acls(struct stat *, char *, char *);
int preserve_fd_acls(int, int);
void usage(void);
__END_DECLS
#endif /* _CP_EXTERN_H_ */

View File

@ -69,10 +69,22 @@ __FBSDID("$FreeBSD: src/bin/cp/utils.c,v 1.46 2005/09/05 04:36:08 csjp Exp $");
#include "extern.h"
#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y))
/* Memory strategy threshold, in pages: if physmem is larger then this, use a
* large buffer */
#define PHYSPAGES_THRESHOLD (32*1024)
/* Maximum buffer size in bytes - do not allow it to grow larger than this */
#define BUFSIZE_MAX (2*1024*1024)
/* Small (default) buffer size in bytes. It's inefficient for this to be
* smaller than MAXPHYS */
#define BUFSIZE_SMALL (MAXPHYS)
int
copy_file(const FTSENT *entp, int dne)
{
static char buf[MAXBSIZE];
static char *buf = NULL;
static size_t bufsize;
struct stat *fs;
int ch, checkch, from_fd, rval, to_fd;
ssize_t rcount;
@ -258,8 +270,23 @@ copy_file(const FTSENT *entp, int dne)
} else
#endif
{
if (buf == NULL) {
/*
* Note that buf and bufsize are static. If
* malloc() fails, it will fail at the start
* and not copy only some files.
*/
if (sysconf(_SC_PHYS_PAGES) >
PHYSPAGES_THRESHOLD)
bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
else
bufsize = BUFSIZE_SMALL;
buf = malloc(bufsize);
if (buf == NULL)
err(1, "Not enough memory");
}
wtotal = 0;
while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
while ((rcount = read(from_fd, buf, bufsize)) > 0) {
for (bufp = buf, wresid = rcount; ;
bufp += wcount, wresid -= wcount) {
wcount = write(to_fd, bufp, wresid);
@ -382,19 +409,28 @@ copy_special(struct stat *from_stat, int exists)
int
setfile(struct stat *fs, int fd)
{
static struct timeval tv[2];
struct attrlist ts_req = {};
struct stat ts;
int rval, gotstat, islink, fdval;
struct {
struct timespec mtime;
struct timespec atime;
} set_ts;
rval = 0;
fdval = fd != -1;
islink = !fdval && S_ISLNK(fs->st_mode);
fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
unsigned int options = islink ? FSOPT_NOFOLLOW : 0;
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) :

View File

@ -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_ */

View File

@ -38,6 +38,9 @@
* $FreeBSD: src/bin/dd/extern.h,v 1.12 2002/02/02 06:24:12 imp Exp $
*/
#ifndef _DD_EXTERN_H_
#define _DD_EXTERN_H_
#include <sys/cdefs.h>
void block(void);
@ -66,3 +69,5 @@ extern const u_char a2e_32V[], a2e_POSIX[];
extern const u_char e2a_32V[], e2a_POSIX[];
extern const u_char a2ibm_32V[], a2ibm_POSIX[];
extern u_char casetab[];
#endif /* _DD_EXTERN_H_ */

View File

@ -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 = (

View File

@ -33,4 +33,9 @@
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
*/
#ifndef _INSTALL_PATHNAMES_H_
#define _INSTALL_PATHNAMES_H_
#define _PATH_STRIP "/usr/bin/strip"
#endif /* _INSTALL_PATHNAMES_H_ */

26
ln/ln.1
View File

@ -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

View File

@ -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);
}

View File

@ -34,6 +34,9 @@
* $FreeBSD: src/bin/ls/extern.h,v 1.19 2002/05/19 02:51:36 tjr Exp $
*/
#ifndef _LS_EXTERN_H_
#define _LS_EXTERN_H_
int acccmp(const FTSENT *, const FTSENT *);
int revacccmp(const FTSENT *, const FTSENT *);
int modcmp(const FTSENT *, const FTSENT *);
@ -66,3 +69,5 @@ extern char *ansi_coloff;
extern char *attrs_off;
extern char *enter_bold;
#endif
#endif /* _LS_EXTERN_H_ */

13
ls/ls.c
View File

@ -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) {

View File

@ -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_ */

View File

@ -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;
}

View File

@ -1,3 +1,7 @@
#ifndef _COMMON_CRYPTO_H_
#define _COMMON_CRYPTO_H_
#include <CommonCrypto/CommonDigestSPI.h>
#define kNone "none"
@ -9,7 +13,24 @@ extern const int kSHA256NullTerminatedBuffLen;
#define RIPEMD160_File(f, b) Digest_File(kCCDigestRMD160, f, b)
#define SHA256_File(f, b) Digest_File(kCCDigestSHA256, f, b)
typedef struct {
char *digest;
uint64_t xdstream_priv_id;
} xattr_info;
struct attrbuf {
uint32_t info_length;
uint64_t sibling_id;
} __attribute__((aligned, packed));
typedef struct attrbuf attrbuf_t;
char *Digest_File(CCDigestAlg algorithm, const char *filename, char *buf);
char *SHA256_Path_XATTRs(char *path, char *buf);
char *SHA256_Path_ACL(char *path, char *buf);
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_ */

View File

@ -35,6 +35,7 @@ static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $");
#include <CoreFoundation/CoreFoundation.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
@ -63,6 +64,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobe
#include <unistd.h>
#include <vis.h>
#include "metrics.h"
#include "mtree.h"
#include "extern.h"
@ -77,9 +79,79 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobe
tab = "\t"; \
}
extern CFMutableDictionaryRef dict;
// max/min times apfs can store on disk
#define APFS_MAX_TIME 0x7fffffffffffffffLL
#define APFS_MIN_TIME (-0x7fffffffffffffffLL-1)
static uint64_t
timespec_to_apfs_timestamp(struct timespec *ts)
{
int64_t total;
int64_t seconds;
// `tv_nsec' can be > one billion, so we split it into two components:
// seconds and actual nanoseconds
// this allows us to detect overflow on the *total* number of nanoseconds
// e.g. if (MAX_SECONDS+2, -2billion) is passed in, we return MAX_SECONDS
seconds = ((int64_t)ts->tv_nsec / (int64_t)NSEC_PER_SEC);
// compute total nanoseconds, checking for overflow:
// seconds = sec + (ns/10e9)
// total = seconds*10e9 + ns%10e9
if (__builtin_saddll_overflow(ts->tv_sec, seconds, &seconds) ||
__builtin_smulll_overflow(seconds, NSEC_PER_SEC, &total) ||
__builtin_saddll_overflow(((int64_t)ts->tv_nsec % (int64_t)NSEC_PER_SEC), total, &total)) {
// checking the sign of "seconds" tells us whether to cap the value at
// the max or min time
total = (ts->tv_sec > 0) ? APFS_MAX_TIME : APFS_MIN_TIME;
}
return (uint64_t)total;
}
static void
set_key_value_pair(void *in_key, uint64_t *in_val, bool is_string)
{
CFStringRef key;
CFNumberRef val;
if (is_string) {
key = CFStringCreateWithCString(NULL, (const char*)in_key, kCFStringEncodingUTF8);
} else {
key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%llu"), *(uint64_t*)in_key);
}
val = CFNumberCreate(NULL, kCFNumberSInt64Type, in_val);
// we always expect the key to be not present
if (key && val) {
CFDictionaryAddValue(dict, key, val);
} else {
if (key) {
CFRelease(key);
}
if (val) {
CFRelease(val);
}
RECORD_FAILURE(1, EINVAL);
errx(1, "set_key_value_pair: key/value is null");
}
if (key) {
CFRelease(key);
}
if (val) {
CFRelease(val);
}
}
int
compare(char *name __unused, NODE *s, FTSENT *p)
{
int error = 0;
struct timeval tv[2];
uint32_t val;
int fd, label;
@ -92,31 +164,44 @@ compare(char *name __unused, NODE *s, FTSENT *p)
label = 0;
switch(s->type) {
case F_BLOCK:
if (!S_ISBLK(p->fts_statp->st_mode))
if (!S_ISBLK(p->fts_statp->st_mode)) {
RECORD_FAILURE(2, EINVAL);
goto typeerr;
}
break;
case F_CHAR:
if (!S_ISCHR(p->fts_statp->st_mode))
if (!S_ISCHR(p->fts_statp->st_mode)) {
RECORD_FAILURE(3, EINVAL);
goto typeerr;
}
break;
case F_DIR:
if (!S_ISDIR(p->fts_statp->st_mode))
if (!S_ISDIR(p->fts_statp->st_mode)) {
RECORD_FAILURE(4, EINVAL);
goto typeerr;
}
break;
case F_FIFO:
if (!S_ISFIFO(p->fts_statp->st_mode))
if (!S_ISFIFO(p->fts_statp->st_mode)) {
RECORD_FAILURE(5, EINVAL);
goto typeerr;
}
break;
case F_FILE:
if (!S_ISREG(p->fts_statp->st_mode))
if (!S_ISREG(p->fts_statp->st_mode)) {
RECORD_FAILURE(6, EINVAL);
goto typeerr;
}
break;
case F_LINK:
if (!S_ISLNK(p->fts_statp->st_mode))
if (!S_ISLNK(p->fts_statp->st_mode)) {
RECORD_FAILURE(7, EINVAL);
goto typeerr;
}
break;
case F_SOCK:
if (!S_ISSOCK(p->fts_statp->st_mode)) {
RECORD_FAILURE(8, EINVAL);
typeerr: LABEL;
(void)printf("\ttype expected %s found %s\n",
ftype(s->type), inotype(p->fts_statp->st_mode));
@ -129,28 +214,36 @@ typeerr: LABEL;
LABEL;
(void)printf("%suser expected %lu found %lu",
tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
if (uflag)
if (chown(p->fts_accpath, s->st_uid, -1))
if (uflag) {
if (chown(p->fts_accpath, s->st_uid, -1)) {
error = errno;
RECORD_FAILURE(9, error);
(void)printf(" not modified: %s\n",
strerror(errno));
else
strerror(error));
} else {
(void)printf(" modified\n");
else
}
} else {
(void)printf("\n");
}
tab = "\t";
}
if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
LABEL;
(void)printf("%sgid expected %lu found %lu",
tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
if (uflag)
if (chown(p->fts_accpath, -1, s->st_gid))
if (uflag) {
if (chown(p->fts_accpath, -1, s->st_gid)) {
error = errno;
RECORD_FAILURE(10, error);
(void)printf(" not modified: %s\n",
strerror(errno));
else
strerror(error));
} else {
(void)printf(" modified\n");
else
}
} else {
(void)printf("\n");
}
tab = "\t";
}
if (s->flags & F_MODE &&
@ -159,14 +252,18 @@ typeerr: LABEL;
LABEL;
(void)printf("%spermissions expected %#o found %#o",
tab, s->st_mode, p->fts_statp->st_mode & MBITS);
if (uflag)
if (chmod(p->fts_accpath, s->st_mode))
if (uflag) {
if (chmod(p->fts_accpath, s->st_mode)) {
error = errno;
RECORD_FAILURE(11, error);
(void)printf(" not modified: %s\n",
strerror(errno));
else
strerror(error));
} else {
(void)printf(" modified\n");
else
}
} else {
(void)printf("\n");
}
tab = "\t";
}
if (s->flags & F_NLINK && s->type != F_DIR &&
@ -186,35 +283,51 @@ typeerr: LABEL;
if ((s->flags & F_TIME) &&
((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
(s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
LABEL;
(void)printf("%smodification time expected %.24s.%09ld ",
tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
(void)printf("found %.24s.%09ld",
ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
if (uflag) {
tv[0].tv_sec = s->st_mtimespec.tv_sec;
tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
tv[1] = tv[0];
if (utimes(p->fts_accpath, tv))
(void)printf(" not modified: %s\n",
strerror(errno));
else
(void)printf(" modified\n");
} else
(void)printf("\n");
tab = "\t";
if (!mflag) {
LABEL;
(void)printf("%smodification time expected %.24s.%09ld ",
tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
(void)printf("found %.24s.%09ld",
ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
if (uflag) {
tv[0].tv_sec = s->st_mtimespec.tv_sec;
tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
tv[1] = tv[0];
if (utimes(p->fts_accpath, tv)) {
error = errno;
RECORD_FAILURE(12, error);
(void)printf(" not modified: %s\n",
strerror(error));
} else {
(void)printf(" modified\n");
}
} else {
(void)printf("\n");
}
tab = "\t";
}
if (!insert_mod && mflag) {
uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_mtimespec);
char *mod_string = "MODIFICATION";
set_key_value_pair(mod_string, &s_mod_time, true);
insert_mod = 1;
}
}
if (s->flags & F_CKSUM) {
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
LABEL;
error = errno;
RECORD_FAILURE(13, error);
(void)printf("%scksum: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab, p->fts_accpath, strerror(error));
tab = "\t";
} else if (crc(fd, &val, &len)) {
(void)close(fd);
LABEL;
error = errno;
RECORD_FAILURE(14, error);
(void)printf("%scksum: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab, p->fts_accpath, strerror(error));
tab = "\t";
} else {
(void)close(fd);
@ -245,26 +358,37 @@ typeerr: LABEL;
(void)printf(" found \"%s\"", fflags);
free(fflags);
if (uflag)
if (chflags(p->fts_accpath, (u_int)s->st_flags))
if (uflag) {
if (chflags(p->fts_accpath, (u_int)s->st_flags)) {
error = errno;
RECORD_FAILURE(15, error);
(void)printf(" not modified: %s\n",
strerror(errno));
else
strerror(error));
} else {
(void)printf(" modified\n");
else
(void)printf("\n");
}
} else {
(void)printf("\n");
}
tab = "\t";
}
}
#ifdef ENABLE_MD5
if (s->flags & F_MD5) {
char *new_digest, buf[33];
#ifdef __clang__
/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
new_digest = MD5File(p->fts_accpath, buf);
#pragma clang diagnostic pop
#endif
if (!new_digest) {
LABEL;
error = errno;
RECORD_FAILURE(16, error);
printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
strerror(errno));
strerror(error));
tab = "\t";
} else if (strcmp(new_digest, s->md5digest)) {
LABEL;
@ -277,12 +401,19 @@ typeerr: LABEL;
#ifdef ENABLE_SHA1
if (s->flags & F_SHA1) {
char *new_digest, buf[41];
#ifdef __clang__
/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
new_digest = SHA1_File(p->fts_accpath, buf);
#pragma clang diagnostic pop
#endif
if (!new_digest) {
LABEL;
error = errno;
RECORD_FAILURE(17, error);
printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
strerror(errno));
strerror(error));
tab = "\t";
} else if (strcmp(new_digest, s->sha1digest)) {
LABEL;
@ -295,12 +426,19 @@ typeerr: LABEL;
#ifdef ENABLE_RMD160
if (s->flags & F_RMD160) {
char *new_digest, buf[41];
#ifdef __clang__
/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
new_digest = RIPEMD160_File(p->fts_accpath, buf);
#pragma clang diagnostic pop
#endif
if (!new_digest) {
LABEL;
error = errno;
RECORD_FAILURE(18, error);
printf("%sRIPEMD160: %s: %s\n", tab,
p->fts_accpath, strerror(errno));
p->fts_accpath, strerror(error));
tab = "\t";
} else if (strcmp(new_digest, s->rmd160digest)) {
LABEL;
@ -317,8 +455,10 @@ typeerr: LABEL;
new_digest = SHA256_File(p->fts_accpath, buf);
if (!new_digest) {
LABEL;
error = errno;
RECORD_FAILURE(19, error);
printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
strerror(errno));
strerror(error));
tab = "\t";
} else if (strcmp(new_digest, s->sha256digest)) {
LABEL;
@ -338,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);
}

View File

@ -63,6 +63,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/create.c,v 1.37 2005/03/29 11:44:17 tobez
#include <time.h>
#include <unistd.h>
#include <vis.h>
#include "metrics.h"
#include "mtree.h"
#include "extern.h"
@ -79,15 +80,17 @@ static mode_t mode;
static u_long flags = 0xffffffff;
static char *xattrs = kNone;
static char *acl = kNone;
static u_quad_t xdstream_id;
static int dsort(const FTSENT **, const FTSENT **);
static void output(int, int *, const char *, ...) __printflike(3, 4);
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **);
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **, u_quad_t *);
static void statf(int, FTSENT *);
void
cwalk(void)
{
int error = 0;
FTS *t;
FTSENT *p;
time_t cl;
@ -109,8 +112,11 @@ cwalk(void)
argv[0] = dot;
argv[1] = NULL;
if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
err(1, "fts_open()");
if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) {
error = errno;
RECORD_FAILURE(76, error);
errc(1, error, "fts_open()");
}
while ((p = fts_read(t))) {
if (iflag)
indent = p->fts_level * 4;
@ -127,7 +133,7 @@ cwalk(void)
(void)printf("# %s\n", path);
free(path);
}
statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl);
statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl, &xdstream_id);
statf(indent, p);
break;
case FTS_DP:
@ -153,13 +159,16 @@ cwalk(void)
}
}
(void)fts_close(t);
if (sflag && keys & F_CKSUM)
if (sflag && keys & F_CKSUM) {
RECORD_FAILURE(77, WARN_CHECKSUM);
warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
}
}
static void
statf(int indent, FTSENT *p)
{
int error = 0;
struct group *gr;
struct passwd *pw;
uint32_t val;
@ -169,8 +178,10 @@ statf(int indent, FTSENT *p)
char *escaped_name;
escaped_name = calloc(1, p->fts_namelen * 4 + 1);
if (escaped_name == NULL)
if (escaped_name == NULL) {
RECORD_FAILURE(78, ENOMEM);
errx(1, "statf(): calloc() failed");
}
strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB);
if (iflag || S_ISDIR(p->fts_statp->st_mode))
@ -190,15 +201,18 @@ statf(int indent, FTSENT *p)
if (p->fts_statp->st_uid != uid) {
if (keys & F_UNAME) {
pw = getpwuid(p->fts_statp->st_uid);
if (pw != NULL)
if (pw != NULL) {
output(indent, &offset, "uname=%s", pw->pw_name);
else if (wflag)
} else if (wflag) {
RECORD_FAILURE(27448, WARN_UNAME);
warnx("Could not get uname for uid=%u",
p->fts_statp->st_uid);
else
} else {
RECORD_FAILURE(79, EINVAL);
errx(1,
"Could not get uname for uid=%u",
p->fts_statp->st_uid);
}
}
if (keys & F_UID)
output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
@ -206,15 +220,18 @@ statf(int indent, FTSENT *p)
if (p->fts_statp->st_gid != gid) {
if (keys & F_GNAME) {
gr = getgrgid(p->fts_statp->st_gid);
if (gr != NULL)
if (gr != NULL) {
output(indent, &offset, "gname=%s", gr->gr_name);
else if (wflag)
} else if (wflag) {
RECORD_FAILURE(27449, WARN_UNAME);
warnx("Could not get gname for gid=%u",
p->fts_statp->st_gid);
else
} else {
RECORD_FAILURE(80, EINVAL);
errx(1,
"Could not get gname for gid=%u",
p->fts_statp->st_gid);
}
}
if (keys & F_GID)
output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
@ -226,44 +243,79 @@ statf(int indent, FTSENT *p)
if (keys & F_SIZE)
output(indent, &offset, "size=%jd",
(intmax_t)p->fts_statp->st_size);
if (keys & F_TIME)
output(indent, &offset, "time=%ld.%09ld",
(long)p->fts_statp->st_mtimespec.tv_sec,
p->fts_statp->st_mtimespec.tv_nsec);
if (keys & F_TIME) {
if (tflag && !insert_mod) {
output(indent, &offset, "time=%ld.%09ld",
(long)ts.tv_sec, ts.tv_nsec);
insert_mod = 1;
}
if (!tflag) {
output(indent, &offset, "time=%ld.%09ld",
(long)p->fts_statp->st_mtimespec.tv_sec,
p->fts_statp->st_mtimespec.tv_nsec);
}
}
if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
crc(fd, &val, &len))
err(1, "%s", p->fts_accpath);
crc(fd, &val, &len)) {
error = errno;
RECORD_FAILURE(27450, error);
errc(1, error, "%s", p->fts_accpath);
}
(void)close(fd);
output(indent, &offset, "cksum=%lu", (unsigned long)val);
}
#ifdef ENABLE_MD5
if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[33];
#ifdef __clang__
/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
digest = MD5File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
#pragma clang diagnostic pop
#endif
if (!digest) {
error = errno;
RECORD_FAILURE(81, error);
errc(1, error, "%s", p->fts_accpath);
}
output(indent, &offset, "md5digest=%s", digest);
}
#endif /* ENABLE_MD5 */
#ifdef ENABLE_SHA1
if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[41];
#ifdef __clang__
/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
digest = SHA1_File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
#pragma clang diagnostic pop
#endif
if (!digest) {
error = errno;
RECORD_FAILURE(82, error);
errc(1, error, "%s", p->fts_accpath);
}
output(indent, &offset, "sha1digest=%s", digest);
}
#endif /* ENABLE_SHA1 */
#ifdef ENABLE_RMD160
if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[41];
#ifdef __clang__
/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
digest = RIPEMD160_File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
#pragma clang diagnostic pop
#endif
if (!digest) {
error = errno;
RECORD_FAILURE(83, error);
errc(1, error, "%s", p->fts_accpath);
}
output(indent, &offset, "ripemd160digest=%s", digest);
}
#endif /* ENABLE_RMD160 */
@ -272,8 +324,11 @@ statf(int indent, FTSENT *p)
char *digest, buf[kSHA256NullTerminatedBuffLen];
digest = SHA256_File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
if (!digest) {
error = errno;
RECORD_FAILURE(84, error);
errc(1, error, "%s", p->fts_accpath);
}
output(indent, &offset, "sha256digest=%s", digest);
}
#endif /* ENABLE_SHA256 */
@ -290,38 +345,69 @@ statf(int indent, FTSENT *p)
free(fflags);
}
if (keys & F_BTIME) {
output(indent, &offset, "btime=%ld.%09ld",
p->fts_statp->st_birthtimespec.tv_sec,
p->fts_statp->st_birthtimespec.tv_nsec);
if (tflag && !insert_birth) {
output(indent, &offset, "btime=%ld.%09ld",
ts.tv_sec, ts.tv_nsec);
insert_birth = 1;
}
if (!tflag) {
output(indent, &offset, "btime=%ld.%09ld",
p->fts_statp->st_birthtimespec.tv_sec,
p->fts_statp->st_birthtimespec.tv_nsec);
}
}
// only check access time on regular files, as traversing a folder will update its access time
if (keys & F_ATIME && S_ISREG(p->fts_statp->st_mode)) {
output(indent, &offset, "atime=%ld.%09ld",
p->fts_statp->st_atimespec.tv_sec,
p->fts_statp->st_atimespec.tv_nsec);
if (tflag && !insert_access) {
output(indent, &offset, "atime=%ld.%09ld",
ts.tv_sec, ts.tv_nsec);
insert_access = 1;
}
if (!tflag) {
output(indent, &offset, "atime=%ld.%09ld",
p->fts_statp->st_atimespec.tv_sec,
p->fts_statp->st_atimespec.tv_nsec);
}
}
if (keys & F_CTIME) {
output(indent, &offset, "ctime=%ld.%09ld",
p->fts_statp->st_ctimespec.tv_sec,
p->fts_statp->st_ctimespec.tv_nsec);
if (tflag && !insert_change) {
output(indent, &offset, "ctime=%ld.%09ld",
ts.tv_sec, ts.tv_nsec);
insert_change = 1;
}
if (!tflag) {
output(indent, &offset, "ctime=%ld.%09ld",
p->fts_statp->st_ctimespec.tv_sec,
p->fts_statp->st_ctimespec.tv_nsec);
}
}
// date added to parent folder is only supported for files and directories
if (keys & F_PTIME && (S_ISREG(p->fts_statp->st_mode) ||
S_ISDIR(p->fts_statp->st_mode))) {
int supported;
struct timespec ptimespec = ptime(p->fts_accpath, &supported);
if (supported) {
if (tflag && !insert_parent) {
output(indent, &offset, "ptime=%ld.%09ld",
ts.tv_sec, ts.tv_nsec);
insert_parent = 1;
}
if (!tflag && supported) {
output(indent, &offset, "ptime=%ld.%09ld",
ptimespec.tv_sec,
ptimespec.tv_nsec);
}
}
if (keys & F_XATTRS) {
char *digest, buf[kSHA256NullTerminatedBuffLen];
char buf[kSHA256NullTerminatedBuffLen];
xattr_info *ai;
digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
if (digest && (strcmp(digest, xattrs) != 0)) {
output(indent, &offset, "xattrsdigest=%s", digest);
ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
if (ai && ai->digest) {
if ((strcmp(ai->digest, xattrs) != 0) || (ai->xdstream_priv_id != xdstream_id)) {
output(indent, &offset, "xattrsdigest=%s.%llu", ai->digest, ai->xdstream_priv_id);
}
free(ai);
ai = NULL;
}
}
if (keys & F_INODE) {
@ -335,6 +421,11 @@ statf(int indent, FTSENT *p)
output(indent, &offset, "acldigest=%s", digest);
}
}
if (keys & F_SIBLINGID) {
uint64_t sibling_id = get_sibling_id(p->fts_accpath);
sibling_id = (sibling_id != p->fts_statp->st_ino) ? sibling_id : 0;
output(indent, &offset, "siblingid=%llu", sibling_id);
}
(void)putchar('\n');
}
@ -346,8 +437,9 @@ statf(int indent, FTSENT *p)
#define MAXS 16
static int
statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl)
statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl, u_quad_t *xdstream_id)
{
int error = 0;
FTSENT *p;
gid_t sgid;
uid_t suid;
@ -361,14 +453,18 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
u_long saveflags = *pflags;
char *savexattrs = *pxattrs;
char *saveacl = *pacl;
u_quad_t savexdstream_id = *xdstream_id;
u_short maxgid, maxuid, maxmode, maxflags;
u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
char *fflags;
static int first = 1;
if ((p = fts_children(t, 0)) == NULL) {
if (errno)
err(1, "%s", RP(parent));
error = errno;
if (error) {
RECORD_FAILURE(85, error);
errc(1, error, "%s", RP(parent));
}
return (1);
}
@ -434,23 +530,29 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
(void)printf("/set type=file");
if (keys & F_UNAME) {
pw = getpwuid(saveuid);
if (pw != NULL)
if (pw != NULL) {
(void)printf(" uname=%s", pw->pw_name);
else if (wflag)
} else if (wflag) {
RECORD_FAILURE(27451, WARN_UNAME);
warnx( "Could not get uname for uid=%u", saveuid);
else
} else {
RECORD_FAILURE(86, EINVAL);
errx(1, "Could not get uname for uid=%u", saveuid);
}
}
if (keys & F_UID)
(void)printf(" uid=%lu", (u_long)saveuid);
if (keys & F_GNAME) {
gr = getgrgid(savegid);
if (gr != NULL)
if (gr != NULL) {
(void)printf(" gname=%s", gr->gr_name);
else if (wflag)
} else if (wflag) {
RECORD_FAILURE(27452, WARN_UNAME);
warnx("Could not get gname for gid=%u", savegid);
else
} else {
RECORD_FAILURE(87, EINVAL);
errx(1, "Could not get gname for gid=%u", savegid);
}
}
if (keys & F_GID)
(void)printf(" gid=%lu", (u_long)savegid);
@ -464,7 +566,7 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
free(fflags);
}
if (keys & F_XATTRS)
(void)printf(" xattrsdigest=%s", savexattrs);
(void)printf(" xattrsdigest=%s.%llu", savexattrs, savexdstream_id);
if (keys & F_ACL)
(void)printf(" acldigest=%s", saveacl);
(void)printf("\n");
@ -474,6 +576,7 @@ statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *p
*pflags = saveflags;
*pxattrs = savexattrs;
*pacl = saveacl;
*xdstream_id = savexdstream_id;
}
return (0);
}

View File

@ -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';

View File

@ -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_ */

View 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
View 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
View 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_ */

View File

@ -33,6 +33,7 @@ static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
#endif /*not lint */
#endif
#include <sys/cdefs.h>
#include <errno.h>
__FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez Exp $");
#include <sys/types.h>
@ -42,6 +43,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez E
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include "metrics.h"
#include "mtree.h"
#include "extern.h"
#import <sys/attr.h>
@ -84,6 +86,7 @@ static KEY keylist[] = {
#ifdef ENABLE_SHA256
{"sha256digest", F_SHA256, NEEDVALUE},
#endif
{"siblingid", F_SIBLINGID, NEEDVALUE},
{"size", F_SIZE, NEEDVALUE},
{"time", F_TIME, NEEDVALUE},
{"type", F_TYPE, NEEDVALUE},
@ -102,8 +105,10 @@ parsekey(char *name, int *needvaluep)
tmp.name = name;
k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
sizeof(KEY), keycompare);
if (k == NULL)
if (k == NULL) {
RECORD_FAILURE(107, EINVAL);
errx(1, "line %d: unknown keyword %s", lineno, name);
}
if (needvaluep)
*needvaluep = k->flags & NEEDVALUE ? 1 : 0;
@ -119,6 +124,7 @@ keycompare(const void *a, const void *b)
char *
flags_to_string(u_long fflags)
{
int error = 0;
char *string;
string = fflagstostr(fflags);
@ -126,8 +132,11 @@ flags_to_string(u_long fflags)
free(string);
string = strdup("none");
}
if (string == NULL)
err(1, NULL);
if (string == NULL) {
error = errno;
RECORD_FAILURE(108, error);
errc(1, error, NULL);
}
return string;
}
@ -137,8 +146,10 @@ char *
escape_path(char *string)
{
char *escapedPath = calloc(1, strlen(string) * 4 + 1);
if (escapedPath == NULL)
if (escapedPath == NULL) {
RECORD_FAILURE(109, ENOMEM);
errx(1, "escape_path(): calloc() failed");
}
strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
return escapedPath;
@ -154,6 +165,7 @@ struct ptimebuf {
struct timespec
ptime(char *path, int *supported) {
int error = 0;
int ret = 0;
struct ptimebuf buf;
struct attrlist list = {
@ -162,7 +174,9 @@ ptime(char *path, int *supported) {
};
ret = getattrlist(path, &list, &buf, sizeof(buf), FSOPT_NOFOLLOW);
if (ret) {
err(1, "ptime: getattrlist");
error = errno;
RECORD_FAILURE(110, error);
errc(1, error, "ptime: getattrlist");
}
*supported = 0;

View File

@ -148,6 +148,9 @@ This occurs when the directory is a symbolic link.
Remove any files in the file hierarchy that are not described in the
specification.
.\" ==========
.It Fl S
Skip calculating the digest of the extended attributes of the file.
.\" ==========
.It Fl s Ar seed
Display a single checksum to the standard error output that represents all
of the files for which the keyword

View File

@ -41,6 +41,7 @@ static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp $");
#include <CoreFoundation/CoreFoundation.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <err.h>
@ -49,31 +50,58 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "metrics.h"
#include "mtree.h"
#include "extern.h"
#define SECONDS_IN_A_DAY (60 * 60 * 24)
int ftsoptions = FTS_PHYSICAL;
int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag;
int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag, mflag, tflag, 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;
}

View File

@ -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_ */

View File

@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez E
#include <stdint.h>
#include <unistd.h>
#include <vis.h>
#include "metrics.h"
#include "mtree.h"
#include "extern.h"
@ -74,8 +75,10 @@ mtree_readspec(FILE *fi)
continue;
/* Find end of line. */
if ((p = index(buf, '\n')) == NULL)
if ((p = index(buf, '\n')) == NULL) {
RECORD_FAILURE(21, ERANGE);
errx(1, "line %d too long", lineno);
}
/* See if next line is continuation line. */
if (p[-1] == '\\') {
@ -102,8 +105,10 @@ mtree_readspec(FILE *fi)
}
/* Grab file name, "$", "set", or "unset". */
if ((p = strtok(p, "\n\t ")) == NULL)
if ((p = strtok(p, "\n\t ")) == NULL) {
RECORD_FAILURE(22, EINVAL);
errx(1, "line %d: missing field", lineno);
}
if (p[0] == '/')
switch(p[1]) {
@ -119,9 +124,11 @@ mtree_readspec(FILE *fi)
continue;
}
if (index(p, '/'))
if (index(p, '/')) {
RECORD_FAILURE(23, EINVAL);
errx(1, "line %d: slash character in file name",
lineno);
}
if (!strcmp(p, "..")) {
/* Don't go up, if haven't gone down. */
@ -135,17 +142,22 @@ mtree_readspec(FILE *fi)
last->flags |= F_DONE;
continue;
noparent: errx(1, "line %d: no parent node", lineno);
noparent: RECORD_FAILURE(24, EINVAL);
errx(1, "line %d: no parent node", lineno);
}
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) {
RECORD_FAILURE(25, ENOMEM);
errx(1, "calloc");
}
*centry = ginfo;
#define MAGIC "?*["
if (strpbrk(p, MAGIC))
centry->flags |= F_MAGIC;
if (strunvis(centry->name, p) == -1)
if (strunvis(centry->name, p) == -1) {
RECORD_FAILURE(26, EILSEQ);
errx(1, "filename %s is ill-encoded", p);
}
set(NULL, centry);
if (!root) {
@ -166,6 +178,7 @@ noparent: errx(1, "line %d: no parent node", lineno);
static void
set(char *t, NODE *ip)
{
int error = 0;
int type;
char *kw, *val = NULL;
struct group *gr;
@ -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);
}
}
}
}

View File

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/mtree/specspec.c,v 1.6 2005/03/29 11:44:17 tobe
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "metrics.h"
#include "mtree.h"
#include "extern.h"
@ -98,11 +99,13 @@ shownode(NODE *n, int f, char const *path)
if (f & F_PTIME)
printf(" ptime=%ld.%09ld", n->st_ptimespec.tv_sec, n->st_ptimespec.tv_nsec);
if (f & F_XATTRS)
printf(" xattrsdigest=%s", n->xattrsdigest);
printf(" xattrsdigest=%s.%llu", n->xattrsdigest, n->xdstream_priv_id);
if (f & F_INODE)
printf(" inode=%llu", n->st_ino);
if (f & F_ACL)
printf(" acldigest=%s", n->acldigest);
if (f & F_SIBLINGID)
printf(" siblingid=%llu", n->sibling_id);
printf("\n");
}
@ -143,14 +146,17 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
return 0;
} else if (n1 == NULL) {
differs = n2->flags;
RECORD_FAILURE(111, WARN_MISMATCH);
mismatch(n1, n2, differs, path);
return (1);
} else if (n2 == NULL) {
differs = n1->flags;
RECORD_FAILURE(112, WARN_MISMATCH);
mismatch(n1, n2, differs, path);
return (1);
} else if (n1->type != n2->type) {
differs = 0;
RECORD_FAILURE(113, WARN_MISMATCH);
mismatch(n1, n2, differs, path);
return (1);
}
@ -198,8 +204,11 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
differs |= F_INODE;
if (FS(n1, n2, F_ACL, acldigest))
differs |= F_ACL;
if (FF(n1, n2, F_SIBLINGID, sibling_id))
differs |= F_SIBLINGID;
if (differs) {
RECORD_FAILURE(114, WARN_MISMATCH);
mismatch(n1, n2, differs, path);
return (1);
}
@ -208,7 +217,7 @@ compare_nodes(NODE *n1, NODE *n2, char const *path)
static int
walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
{
int r, i;
int r, i, c;
NODE *c1, *c2, *n1, *n2;
char *np;
@ -249,22 +258,49 @@ walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
if (c1 == NULL && c2->type == F_DIR) {
asprintf(&np, "%s%s/", path, c2->name);
i = walk_in_the_forest(c1, c2, np);
if (i) {
RECORD_FAILURE(115, WARN_MISMATCH);
}
free(np);
i += compare_nodes(c1, c2, path);
c = compare_nodes(c1, c2, path);
if (c) {
RECORD_FAILURE(116, WARN_MISMATCH);
}
i += c;
} else if (c2 == NULL && c1->type == F_DIR) {
asprintf(&np, "%s%s/", path, c1->name);
i = walk_in_the_forest(c1, c2, np);
if (i) {
RECORD_FAILURE(117, WARN_MISMATCH);
}
free(np);
i += compare_nodes(c1, c2, path);
c = compare_nodes(c1, c2, path);
if (c) {
RECORD_FAILURE(118, WARN_MISMATCH);
}
i += c;
} else if (c1 == NULL || c2 == NULL) {
i = compare_nodes(c1, c2, path);
if (i) {
RECORD_FAILURE(119, WARN_MISMATCH);
}
} else if (c1->type == F_DIR && c2->type == F_DIR) {
asprintf(&np, "%s%s/", path, c1->name);
i = walk_in_the_forest(c1, c2, np);
if (i) {
RECORD_FAILURE(120, WARN_MISMATCH);
}
free(np);
i += compare_nodes(c1, c2, path);
c = compare_nodes(c1, c2, path);
if (c) {
RECORD_FAILURE(121, WARN_MISMATCH);
}
i += c;
} else {
i = compare_nodes(c1, c2, path);
if (i) {
RECORD_FAILURE(122, WARN_MISMATCH);
}
}
r += i;
c1 = n1;
@ -283,7 +319,9 @@ mtree_specspec(FILE *fi, FILE *fj)
root2 = mtree_readspec(fj);
rval = walk_in_the_forest(root1, root2, "");
rval += compare_nodes(root1, root2, "");
if (rval > 0)
if (rval > 0) {
RECORD_FAILURE(123, WARN_MISMATCH);
return (MISMATCHEXIT);
}
return (0);
}

View File

@ -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;
}

View File

@ -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_ */

View File

@ -36,6 +36,9 @@
* @(#)cache.h 8.1 (Berkeley) 5/31/93
*/
#ifndef _CACHE_H_
#define _CACHE_H_
/*
* Constants and data structures used to implement group and password file
* caches. Traditional passwd/group cache routines perform quite poorly with
@ -71,3 +74,5 @@ typedef struct gidc {
char name[GNMLEN]; /* gid name */
gid_t gid; /* cached gid */
} GIDC;
#endif /* _CACHE_H_ */

View File

@ -36,6 +36,9 @@
* @(#)cpio.h 8.1 (Berkeley) 5/31/93
*/
#ifndef _CPIO_H_
#define _CPIO_H_
/*
* Defines common to all versions of cpio
*/
@ -148,3 +151,5 @@ typedef struct {
#define VCPIO_PAD(x) ((4 - ((x) & 3)) & 3) /* pad to next 4 byte word */
#define VCPIO_MASK 0xffffffff /* mask for dev/ino fields */
#endif /* _PAX_ */
#endif /* _CPIO_H_ */

View File

@ -36,6 +36,9 @@
* @(#)extern.h 8.2 (Berkeley) 4/18/94
*/
#ifndef _PAX_EXTERN_H_
#define _PAX_EXTERN_H_
/*
* External references from each source file
*/
@ -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_ */

View File

@ -36,6 +36,9 @@
* @(#)ftree.h 8.1 (Berkeley) 5/31/93
*/
#ifndef _FTREE_H_
#define _FTREE_H_
/*
* Data structure used by the ftree.c routines to store the file args to be
* handed to fts(). It keeps a reference count of which args generated a
@ -49,3 +52,5 @@ typedef struct ftree {
int chflg; /* change directory flag */
struct ftree *fow; /* pointer to next entry on list */
} FTREE;
#endif /* _FTREE_H_ */

View File

@ -216,17 +216,26 @@ ls_tty(ARCHD *arcn)
void
safe_print(const char *str, FILE *fp)
{
char visbuf[5];
const char *cp;
/*
* if printing to a tty, use vis(3) to print special characters.
* if printing to a tty, use strvis(3) to print special characters.
*/
if (isatty(fileno(fp))) {
for (cp = str; *cp; cp++) {
(void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
(void)fputs(visbuf, fp);
/*
* The size of visbuf must be four times the number
* of bytes encoded from str (plus one for the NUL).
*/
char *visbuf = (char *) malloc(sizeof(char) * (4 * strlen(str) + 1));
if (visbuf == NULL) {
paxwarn(1, "Out of memory");
return;
}
/*
* using strvis(3) instead of vis(3) to account for multibyte
* characters
*/
(void)strvis(visbuf, str, VIS_CSTYLE);
(void)fputs(visbuf, fp);
free(visbuf);
} else {
(void)fputs(str, fp);
}

View File

@ -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

View File

@ -36,6 +36,9 @@
* @(#)options.h 8.2 (Berkeley) 4/18/94
*/
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
/*
* argv[0] names. Used for tar and cpio emulation
*/
@ -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_ */

View File

@ -74,6 +74,10 @@ static int rep_name(char *, size_t, int *, int);
int tty_rename(ARCHD *);
static int fix_path(char *, int *, char *, int);
static int fn_match(char *, char *, char **);
#ifdef _HAVE_REGCOMP_
static char* extract_equiv_pat(char *, char **);
static int regex_match(char *, char *, char **);
#endif
static char * range_match(char *, int);
static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *);
@ -495,6 +499,10 @@ fn_match(char *pattern, char *string, char **pend)
{
char c;
char test;
#ifdef _HAVE_REGCOMP_
char *equiv_pat;
char *pat_pend = NULL;
#endif
*pend = NULL;
for (;;) {
@ -549,10 +557,33 @@ fn_match(char *pattern, char *string, char **pend)
/*
* range match
*/
#ifdef _HAVE_REGCOMP_
/*
* Check for equivalence class and use regex_match to
* handle this case. Note pattern should include the
* opening bracket '['
*/
equiv_pat = extract_equiv_pat(pattern-1, &pat_pend);
if (equiv_pat) {
if (regex_match(equiv_pat, string, &string) == -1) {
free (equiv_pat);
return (-1);
}
free(equiv_pat);
/*
* Update the pattern string
*/
pattern = pat_pend;
break;
}
#endif
if (((test = *string++) == '\0') ||
((pattern = range_match(pattern, test)) == NULL))
return (-1);
break;
case '\\':
default:
if (c != *string++)
@ -563,6 +594,124 @@ fn_match(char *pattern, char *string, char **pend)
/* NOTREACHED */
}
#ifdef _HAVE_REGCOMP_
static char*
extract_equiv_pat(char *pattern, char **pend)
{
int pat_len = 2;
int found = 0;
int is_double_bracket = 0;
char* equiv_pat = NULL;
if (*pattern == '\0' || pattern[1] == '\0' || pattern[2] == '\0')
return NULL;
/*
* check if the pattern is
* "[= =]", "[[= =][= =]]", "[: :]", or "[[: :][: :]]"
* note that the full "pattern" string needs to be passed in
*/
is_double_bracket = (*pattern == '[' && pattern[1] == '[');
if (!(*pattern == '[') && !is_double_bracket) {
return NULL;
}
pattern ++;
if (is_double_bracket) {
pattern ++;
pat_len ++;
}
if (!(*pattern == ':') && !(*pattern == '=')) {
return NULL;
}
pattern ++;
for(; *pattern != '\0'; pat_len++, pattern++) {
if (!is_double_bracket) {
if ((*pattern == '=' || *pattern == ':')
&& pattern[1] == ']') {
found = 1;
pattern += 2;
pat_len += 2;
break;
}
} else {
if ((*pattern == '=' || *pattern == ':')
&& pattern[1] == ']' && pattern[2] == ']') {
found = 1;
pattern += 3;
pat_len += 3;
break;
}
}
}
if (!found) {
return NULL;
}
equiv_pat = strndup(pattern-pat_len, pat_len);
if (equiv_pat == NULL) {
paxwarn(1, "Out of memory");
return NULL;
}
/*
* set pend to the remaining pattern to be matched
*/
if (pend != NULL) {
*pend = pattern;
}
return equiv_pat;
}
static int
regex_match(char *pattern, char *string, char **pend)
{
int res;
regex_t preg;
regmatch_t pmatch;
char rebuf[BUFSIZ];
if ((res = regcomp(&(preg), pattern, REG_EXTENDED)) != 0) {
regerror(res, &(preg), rebuf, sizeof(rebuf));
paxwarn(1, "%s while compiling pattern %s", rebuf, pattern);
return(-1);
}
if (regexec(&(preg), string, 1, &(pmatch), 0) != 0) {
regfree(&(preg));
return(-1);
}
regfree(&(preg));
/*
* starting position of the match must be 0
*/
if (pmatch.rm_so != 0) {
return(-1);
}
/*
* set pend to the remaining string to be matched
*/
if (pend != NULL) {
*pend = string + pmatch.rm_eo;
}
return(0);
}
#endif
static char *
range_match(char *pattern, int test)
{

View File

@ -36,6 +36,9 @@
* @(#)pat_rep.h 8.1 (Berkeley) 5/31/93
*/
#ifndef _PAT_REP_H_
#define _PAT_REP_H_
/*
* data structure for storing user supplied replacement strings (-s)
*/
@ -49,3 +52,5 @@ typedef struct replace {
} REPLACE;
int tty_rename(ARCHD *); /* used for -o invalid=rename recovery */
#endif /* _PAT_REP_H_ */

View File

@ -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;
/*

View File

@ -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_ */

View File

@ -36,6 +36,9 @@
* @(#)tar.h 8.2 (Berkeley) 4/18/94
*/
#ifndef _PAX_FORMAT_H_
#define _PAX_FORMAT_H_
/*
* defines and data structures common to all tar formats
*/
@ -151,3 +154,5 @@ typedef struct {
char devminor[8]; /* minor device number */
char prefix[TPFSZ]; /* linked to name */
} HD_USTAR;
#endif /* _PAX_FORMAT_H_ */

View File

@ -36,6 +36,9 @@
* @(#)sel_subs.h 8.1 (Berkeley) 5/31/93
*/
#ifndef _SEL_SUBS_H_
#define _SEL_SUBS_H_
/*
* data structure for storing uid/grp selects (-U, -G non standard options)
*/
@ -70,3 +73,5 @@ typedef struct time_rng {
#define CMPBOTH (CMPMTME|CMPCTME) /* compare inode and mod time */
struct time_rng *fow; /* next pattern */
} TIME_RNG;
#endif /* _SEL_SUBS_H_ */

View File

@ -36,6 +36,9 @@
* @(#)tables.h 8.1 (Berkeley) 5/31/93
*/
#ifndef _TABLES_H_
#define _TABLES_H_
/*
* data structures and constants used by the different databases kept by pax
*/
@ -168,3 +171,5 @@ typedef struct dirdata {
u_int16_t mode; /* file mode to restore */
u_int16_t frc_mode; /* do we force mode settings? */
} DIRDATA;
#endif /* _TABLES_H_ */

View File

@ -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
View File

@ -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
View 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

View File

@ -8,6 +8,42 @@
<true/>
<key>Tests</key>
<array>
<dict>
<key>Command</key>
<array>
<string>/bin/sh</string>
<string>cp.sh</string>
</array>
<key>AsRoot</key>
<false/>
<key>TestName</key>
<string>cp</string>
<key>WhenToRun</key>
<array>
<string>PRESUBMISSION</string>
<string>NIGHTLY</string>
</array>
<key>WorkingDirectory</key>
<string>/AppleInternal/Tests/file_cmds</string>
</dict>
<dict>
<key>Command</key>
<array>
<string>/bin/sh</string>
<string>touch.sh</string>
</array>
<key>AsRoot</key>
<false/>
<key>TestName</key>
<string>touch</string>
<key>WhenToRun</key>
<array>
<string>PRESUBMISSION</string>
<string>NIGHTLY</string>
</array>
<key>WorkingDirectory</key>
<string>/AppleInternal/Tests/file_cmds</string>
</dict>
<dict>
<key>Command</key>
<array>

14
tests/touch.sh Normal file
View 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

View File

@ -48,6 +48,7 @@ __used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/attr.h>
#include <err.h>
#include <errno.h>
@ -59,10 +60,15 @@ __used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
#include <time.h>
#include <unistd.h>
typedef struct {
struct timespec mtime;
struct timespec atime;
} set_ts;
int rw(char *, struct stat *, int);
void stime_arg1(char *, struct timeval *);
void stime_arg2(char *, int, struct timeval *);
void stime_file(char *, struct timeval *);
void stime_arg1(char *, set_ts *);
void stime_arg2(char *, int, set_ts *);
void stime_file(char *, set_ts *);
int timeoffset(char *);
void usage(char *);
@ -70,19 +76,24 @@ int
main(int argc, char *argv[])
{
struct stat sb;
struct timeval tv[2];
int (*stat_f)(const char *, struct stat *);
int (*utimes_f)(const char *, const struct timeval *);
int Aflag, aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset;
char *p;
char *myname;
struct attrlist ts_req = {
.bitmapcount = ATTR_BIT_MAP_COUNT,
.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME,
};
set_ts ts_struct = {};
myname = basename(argv[0]);
Aflag = aflag = cflag = fflag = mflag = timeset = 0;
stat_f = stat;
utimes_f = utimes;
if (gettimeofday(&tv[0], NULL))
err(1, "gettimeofday");
if (clock_gettime(CLOCK_REALTIME, &ts_struct.mtime))
err(1, "clock_gettime");
ts_struct.atime = ts_struct.mtime;
while ((ch = getopt(argc, argv, "A:acfhmr:t:")) != -1)
switch(ch) {
@ -108,11 +119,11 @@ main(int argc, char *argv[])
break;
case 'r':
timeset = 1;
stime_file(optarg, tv);
stime_file(optarg, &ts_struct);
break;
case 't':
timeset = 1;
stime_arg1(optarg, tv);
stime_arg1(optarg, &ts_struct);
break;
case '?':
default:
@ -132,9 +143,9 @@ main(int argc, char *argv[])
* that time once and for all here.
*/
if (aflag)
tv[0].tv_sec += Aflag;
ts_struct.atime.tv_sec += Aflag;
if (mflag)
tv[1].tv_sec += Aflag;
ts_struct.mtime.tv_sec += Aflag;
Aflag = 0; /* done our job */
}
} else {
@ -148,11 +159,9 @@ main(int argc, char *argv[])
len = p - argv[0];
if (*p == '\0' && (len == 8 || len == 10)) {
timeset = 1;
stime_arg2(*argv++, len == 10, tv);
stime_arg2(*argv++, len == 10, &ts_struct);
}
}
/* Both times default to the same. */
tv[1] = tv[0];
}
if (*argv == NULL)
@ -187,9 +196,9 @@ main(int argc, char *argv[])
}
if (!aflag)
TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
ts_struct.atime = sb.st_atimespec;
if (!mflag)
TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
ts_struct.mtime = sb.st_mtimespec;
/*
* We're adjusting the times based on the file times, not a
@ -197,17 +206,17 @@ main(int argc, char *argv[])
*/
if (Aflag) {
if (aflag) {
TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
tv[0].tv_sec += Aflag;
ts_struct.atime = sb.st_atimespec;
ts_struct.atime.tv_sec += Aflag;
}
if (mflag) {
TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
tv[1].tv_sec += Aflag;
ts_struct.mtime = sb.st_mtimespec;
ts_struct.mtime.tv_sec += Aflag;
}
}
/* Try utimes(2). */
if (!utimes_f(*argv, tv))
/* Try setattrlist(2). */
if (!setattrlist(*argv, &ts_req, &ts_struct, sizeof(ts_struct), 0))
continue;
/* If the user specified a time, nothing else we can do. */
@ -241,14 +250,14 @@ main(int argc, char *argv[])
#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
void
stime_arg1(char *arg, struct timeval *tvp)
stime_arg1(char *arg, set_ts *tsp)
{
time_t now;
struct tm *t;
int yearset;
char *p;
/* Start with the current time. */
now = tvp[0].tv_sec;
now = tsp->atime.tv_sec;
if ((t = localtime(&now)) == NULL)
err(1, "localtime");
/* [[CC]YY]MMDDhhmm[.SS] */
@ -293,21 +302,21 @@ stime_arg1(char *arg, struct timeval *tvp)
}
t->tm_isdst = -1; /* Figure out DST. */
tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
if (tvp[0].tv_sec == -1)
tsp->atime.tv_sec = tsp->mtime.tv_sec = mktime(t);
if (tsp->atime.tv_sec == -1)
terr: errx(1,
"out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
tvp[0].tv_usec = tvp[1].tv_usec = 0;
tsp->atime.tv_nsec = tsp->mtime.tv_nsec = 0;
}
void
stime_arg2(char *arg, int year, struct timeval *tvp)
stime_arg2(char *arg, int year, set_ts *tsp)
{
time_t now;
struct tm *t;
/* Start with the current time. */
now = tvp[0].tv_sec;
now = tsp->atime.tv_sec;
if ((t = localtime(&now)) == NULL)
err(1, "localtime");
@ -323,12 +332,12 @@ stime_arg2(char *arg, int year, struct timeval *tvp)
}
t->tm_isdst = -1; /* Figure out DST. */
tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
if (tvp[0].tv_sec == -1)
tsp->atime.tv_sec = tsp->mtime.tv_sec = mktime(t);
if (tsp->atime.tv_sec == -1)
errx(1,
"out of range or illegal time specification: MMDDhhmm[yy]");
tvp[0].tv_usec = tvp[1].tv_usec = 0;
tsp->atime.tv_nsec = tsp->mtime.tv_nsec = 0;
}
/* Calculate a time offset in seconds, given an arg of the format [-]HHMMSS. */
@ -362,14 +371,14 @@ timeoffset(char *arg)
}
void
stime_file(char *fname, struct timeval *tvp)
stime_file(char *fname, set_ts *ts_struct)
{
struct stat sb;
if (stat(fname, &sb))
err(1, "%s", fname);
TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atimespec);
TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtimespec);
ts_struct->atime = sb.st_atimespec;
ts_struct->mtime = sb.st_mtimespec;
}
int