#include <fcntl.h>
#include <fts.h>
#include <grp.h>
+#ifndef __APPLE__
#ifdef ENABLE_MD5
#include <md5.h>
#endif
#ifdef ENABLE_SHA256
#include <sha256.h>
#endif
+#endif /* !__APPLE__ */
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include "mtree.h"
#include "extern.h"
+#ifdef __APPLE__
+#include "commoncrypto.h"
+#endif /* __APPLE__ */
+
#define INDENTNAMELEN 15
#define MAXLINELEN 80
static uid_t uid;
static mode_t mode;
static u_long flags = 0xffffffff;
+static char *xattrs = kNone;
+static char *acl = kNone;
static int dsort(const FTSENT **, const FTSENT **);
static void output(int, int *, const char *, ...) __printflike(3, 4);
-static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
+static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **);
static void statf(int, FTSENT *);
void
char *argv[2], host[MAXHOSTNAMELEN];
char dot[] = ".";
int indent = 0;
+ char *path;
if (!nflag) {
(void)time(&cl);
case FTS_D:
if (!dflag)
(void)printf("\n");
- if (!nflag)
- (void)printf("# %s\n", p->fts_path);
- statd(t, p, &uid, &gid, &mode, &flags);
+ if (!nflag) {
+ path = escape_path(p->fts_path);
+ (void)printf("# %s\n", path);
+ free(path);
+ }
+ statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl);
statf(indent, p);
break;
case FTS_DP:
- if (!nflag && (p->fts_level > 0))
- (void)printf("%*s# %s\n", indent, "", p->fts_path);
+ if (!nflag && (p->fts_level > 0)) {
+ path = escape_path(p->fts_path);
+ (void)printf("%*s# %s\n", indent, "", path);
+ free(path);
+ }
(void)printf("%*s..\n", indent, "");
if (!dflag)
(void)printf("\n");
output(indent, &offset, "size=%jd",
(intmax_t)p->fts_statp->st_size);
if (keys & F_TIME)
- output(indent, &offset, "time=%ld.%ld",
+ output(indent, &offset, "time=%ld.%09ld",
(long)p->fts_statp->st_mtimespec.tv_sec,
p->fts_statp->st_mtimespec.tv_nsec);
if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
#endif /* ENABLE_RMD160 */
#ifdef ENABLE_SHA256
if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) {
- char *digest, buf[65];
+ char *digest, buf[kSHA256NullTerminatedBuffLen];
digest = SHA256_File(p->fts_accpath, buf);
if (!digest)
}
#endif /* ENABLE_SHA256 */
if (keys & F_SLINK &&
- (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
- output(indent, &offset, "link=%s", rlink(p->fts_accpath));
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+ char visbuf[MAXPATHLEN * 4];
+ char *s = rlink(p->fts_accpath);
+ strvis(visbuf, s, VIS_WHITE | VIS_OCTAL);
+ output(indent, &offset, "link=%s", visbuf);
+ }
if (keys & F_FLAGS && p->fts_statp->st_flags != flags) {
fflags = flags_to_string(p->fts_statp->st_flags);
output(indent, &offset, "flags=%s", fflags);
free(fflags);
}
+ if (keys & F_BTIME) {
+ output(indent, &offset, "btime=%ld.%09ld",
+ p->fts_statp->st_birthtimespec.tv_sec,
+ p->fts_statp->st_birthtimespec.tv_nsec);
+ }
+ // only check access time on regular files, as traversing a folder will update its access time
+ if (keys & F_ATIME && S_ISREG(p->fts_statp->st_mode)) {
+ output(indent, &offset, "atime=%ld.%09ld",
+ p->fts_statp->st_atimespec.tv_sec,
+ p->fts_statp->st_atimespec.tv_nsec);
+ }
+ if (keys & F_CTIME) {
+ output(indent, &offset, "ctime=%ld.%09ld",
+ p->fts_statp->st_ctimespec.tv_sec,
+ p->fts_statp->st_ctimespec.tv_nsec);
+ }
+ // date added to parent folder is only supported for files and directories
+ if (keys & F_PTIME && (S_ISREG(p->fts_statp->st_mode) ||
+ S_ISDIR(p->fts_statp->st_mode))) {
+ int supported;
+ struct timespec ptimespec = ptime(p->fts_accpath, &supported);
+ if (supported) {
+ output(indent, &offset, "ptime=%ld.%09ld",
+ ptimespec.tv_sec,
+ ptimespec.tv_nsec);
+ }
+ }
+ if (keys & F_XATTRS) {
+ char *digest, buf[kSHA256NullTerminatedBuffLen];
+
+ digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
+ if (digest && (strcmp(digest, xattrs) != 0)) {
+ output(indent, &offset, "xattrsdigest=%s", digest);
+ }
+ }
+ if (keys & F_INODE) {
+ output(indent, &offset, "inode=%llu", p->fts_statp->st_ino);
+ }
+ if (keys & F_ACL) {
+ char *digest, buf[kSHA256NullTerminatedBuffLen];
+
+ digest = SHA256_Path_ACL(p->fts_accpath, buf);
+ if (digest && (strcmp(digest, acl) != 0)) {
+ output(indent, &offset, "acldigest=%s", digest);
+ }
+ }
+
(void)putchar('\n');
}
#define MAXS 16
static int
-statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags)
+statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl)
{
FTSENT *p;
gid_t sgid;
uid_t saveuid = *puid;
mode_t savemode = *pmode;
u_long saveflags = *pflags;
+ char *savexattrs = *pxattrs;
+ char *saveacl = *pacl;
u_short maxgid, maxuid, maxmode, maxflags;
u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
char *fflags;
saveuid = suid;
maxuid = u[suid];
}
+
+ /*
+ * XXX
+ * note that we don't count the most common xattr/acl digest
+ * so set will always the default value (none)
+ */
/*
* XXX
(void)printf(" flags=%s", fflags);
free(fflags);
}
+ if (keys & F_XATTRS)
+ (void)printf(" xattrsdigest=%s", savexattrs);
+ if (keys & F_ACL)
+ (void)printf(" acldigest=%s", saveacl);
(void)printf("\n");
*puid = saveuid;
*pgid = savegid;
*pmode = savemode;
*pflags = saveflags;
+ *pxattrs = savexattrs;
+ *pacl = saveacl;
}
return (0);
}