@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
+#include <sys/xattr.h>
#ifdef __SOLARIS__
#include <sys/mkdev.h>
#endif
@@ -40,7 +41,6 @@
#endif
/* TODO: add hardlink recognition */
-/* TODO: add xattr/acl */
struct excludes {
char *path;
@@ -71,15 +71,16 @@ enum _flags {
FLAG_MTIME,
FLAG_CTIME,
FLAG_DATA,
+ FLAG_XATTRS,
FLAG_OPEN_ERROR,
FLAG_STRUCTURE,
NUM_FLAGS
};
-const char flchar[] = "ugoamcdes";
+const char flchar[] = "ugoamcdxes";
char line[65536];
-int flags[NUM_FLAGS] = {1, 1, 1, 1, 1, 0, 1, 0, 0};
+int flags[NUM_FLAGS] = {1, 1, 1, 1, 1, 0, 1, 1, 0, 0};
char *
getln(char *buf, int size, FILE *fp)
@@ -135,7 +136,7 @@ usage(void)
fprintf(stderr, " -v : verbose mode (debugging only)\n");
fprintf(stderr,
" -r <file> : read checksum or manifest from file\n");
- fprintf(stderr, " -[ugoamcde] : specify which fields to include in checksum calculation.\n");
+ fprintf(stderr, " -[ugoamcdxe]: specify which fields to include in checksum calculation.\n");
fprintf(stderr, " u : include uid\n");
fprintf(stderr, " g : include gid\n");
fprintf(stderr, " o : include mode\n");
@@ -143,9 +144,10 @@ usage(void)
fprintf(stderr, " a : include atime\n");
fprintf(stderr, " c : include ctime\n");
fprintf(stderr, " d : include file data\n");
+ fprintf(stderr, " x : include xattrs\n");
fprintf(stderr, " e : include open errors (aborts otherwise)\n");
fprintf(stderr, " s : include block structure (holes)\n");
- fprintf(stderr, " -[UGOAMCDES]: exclude respective field from calculation\n");
+ fprintf(stderr, " -[UGOAMCDXES]: exclude respective field from calculation\n");
fprintf(stderr, " -n : reset all flags\n");
fprintf(stderr, " -N : set all flags\n");
fprintf(stderr, " -x path : exclude path when building checksum (multiple ok)\n");
@@ -221,6 +223,106 @@ sum_to_string(sum_t *dst)
}
int
+namecmp(const void *aa, const void *bb)
+{
+ char * const *a = aa;
+ char * const *b = bb;
+
+ return strcmp(*a, *b);
+}
+
+int
+sum_xattrs(int fd, sum_t *dst)
+{
+ ssize_t buflen;
+ ssize_t len;
+ char *buf;
+ char *p;
+ char **names = NULL;
+ int num_xattrs = 0;
+ int ret = 0;
+ int i;
+
+ buflen = flistxattr(fd, NULL, 0);
+ if (buflen < 0)
+ return -errno;
+ /* no xattrs exist */
+ if (buflen == 0)
+ return 0;
+
+ buf = malloc(buflen);
+ if (!buf)
+ return -ENOMEM;
+
+ buflen = flistxattr(fd, buf, buflen);
+ if (buflen < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ /*
+ * Keep the list of xattrs sorted, because the order in which they are
+ * listed is filesystem dependent, so we want to get the same checksum
+ * on different filesystems.
+ */
+
+ p = buf;
+ len = buflen;
+ while (len > 0) {
+ int keylen;
+
+ keylen = strlen(p) + 1; /* +1 for NULL terminator */
+ len -= keylen;
+ p += keylen;
+ num_xattrs++;
+ }
+
+ names = malloc(sizeof(char *) * num_xattrs);
+ if (!names) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ p = buf;
+ for (i = 0; i < num_xattrs; i++) {
+ names[i] = p;
+ p += strlen(p) + 1; /* +1 for NULL terminator */
+ }
+
+ qsort(names, num_xattrs, sizeof(char *), namecmp);
+
+ for (i = 0; i < num_xattrs; i++) {
+ len = fgetxattr(fd, names[i], NULL, 0);
+ if (len < 0) {
+ ret = -errno;
+ goto out;
+ }
+ sum_add(dst, names[i], strlen(names[i]));
+ /* no value */
+ if (len == 0)
+ continue;
+ p = malloc(len);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ len = fgetxattr(fd, names[i], p, len);
+ if (len < 0) {
+ ret = -errno;
+ free(p);
+ goto out;
+ }
+ sum_add(dst, p, len);
+ free(p);
+ }
+out:
+ free(buf);
+ free(names);
+
+ return ret;
+}
+
+int
sum_file_data_permissive(int fd, sum_t *dst)
{
int ret;
@@ -401,15 +503,6 @@ malformed:
excess_file(fn);
}
-int
-namecmp(const void *aa, const void *bb)
-{
- char * const *a = aa;
- char * const *b = bb;
-
- return strcmp(*a, *b);
-}
-
void
sum(int dirfd, int level, sum_t *dircs, char *path_prefix, char *path_in)
{
@@ -493,6 +586,28 @@ sum(int dirfd, int level, sum_t *dircs, char *path_prefix, char *path_in)
sum_add_time(&meta, st.st_mtime);
if (flags[FLAG_CTIME])
sum_add_time(&meta, st.st_ctime);
+ if (flags[FLAG_XATTRS] &&
+ (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) {
+ fd = openat(dirfd, namelist[i], 0);
+ if (fd == -1 && flags[FLAG_OPEN_ERROR]) {
+ sum_add_u64(&meta, errno);
+ } else if (fd == -1) {
+ fprintf(stderr, "open failed for %s/%s: %s\n",
+ path_prefix, path, strerror(errno));
+ exit(-1);
+ } else {
+ ret = sum_xattrs(fd, &meta);
+ close(fd);
+ if (ret < 0) {
+ fprintf(stderr,
+ "failed to read xattrs from "
+ "%s/%s: %s\n",
+ path_prefix, path,
+ strerror(-ret));
+ exit(-1);
+ }
+ }
+ }
if (S_ISDIR(st.st_mode)) {
fd = openat(dirfd, namelist[i], 0);
if (fd == -1 && flags[FLAG_OPEN_ERROR]) {