CAUTION: this patch has been recently reworked, and needs more testing!
-TODO:
-
- - When an xattr value is long enough to be checksummed and is not changed,
- we need to have the receiver get the unchanged value from the receiving
- side instead of requesting that it be sent from the sender.
-
--- old/Makefile.in
+++ new/Makefile.in
@@ -28,13 +28,13 @@ VERSION=@VERSION@
if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
continue;
#ifdef SUPPORT_ACLS
-@@ -143,6 +147,13 @@ static int make_bak_dir(char *fullpath)
+@@ -143,7 +147,14 @@ static int make_bak_dir(char *fullpath)
free_acl(&sx);
}
#endif
+- set_file_attrs(fullpath, file, NULL, 0);
+#ifdef SUPPORT_XATTRS
+ if (preserve_xattrs) {
+ get_xattr(rel, &sx);
+ free_xattr(&sx);
+ }
+#endif
- set_file_attrs(fullpath, file, NULL, 0);
++ set_file_attrs(fullpath, file, NULL, NULL, 0);
free(file);
}
+ }
@@ -194,6 +205,9 @@ static int keep_backup(const char *fname
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
/* Check to see if this is a device file, or link */
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
+@@ -288,7 +309,7 @@ static int keep_backup(const char *fname
+ robust_unlink(fname); /* Just in case... */
+ }
+ }
+- set_file_attrs(buf, file, NULL, 0);
++ set_file_attrs(buf, file, NULL, fname, 0);
+ unmake_file(file);
+
+ if (verbose > 1) {
+--- old/cleanup.c
++++ new/cleanup.c
+@@ -142,7 +142,7 @@ NORETURN void _exit_cleanup(int code, co
+ flush_write_file(cleanup_fd_w);
+ close(cleanup_fd_w);
+ }
+- finish_transfer(cleanup_new_fname, fname, NULL,
++ finish_transfer(cleanup_new_fname, fname, NULL, NULL,
+ cleanup_file, 0, !partial_dir);
+ }
+
--- old/compat.c
+++ new/compat.c
@@ -43,6 +43,7 @@ extern int protocol_version;
} else if (ndx >= 0) {
enum logcode code = logfile_format_has_i ? FINFO : FCLIENT;
log_item(code, file, &stats, iflags, xname);
+@@ -881,7 +902,7 @@ static int try_dests_reg(struct file_str
+ }
+ if (itemizing)
+ itemize(fname, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
+- set_file_attrs(fname, file, NULL, 0);
++ set_file_attrs(fname, file, NULL, NULL, 0);
+ if (maybe_ATTRS_REPORT
+ && ((!itemizing && verbose && match_level == 2)
+ || (verbose > 1 && match_level == 3))) {
@@ -1112,6 +1133,9 @@ static void recv_generator(char *fname,
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
if (dry_run > 1) {
if (fuzzy_dirlist) {
flist_free(fuzzy_dirlist);
+@@ -1224,7 +1248,7 @@ static void recv_generator(char *fname,
+ goto cleanup;
+ }
+ }
+- if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, 0)
++ if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
+ && verbose && code != FNONE && f_out != -1)
+ rprintf(code, "%s/\n", fname);
+ if (real_ret != 0 && one_file_system)
+@@ -1280,7 +1304,7 @@ static void recv_generator(char *fname,
+ /* The link is pointing to the right place. */
+ if (itemizing)
+ itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
+- set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
++ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_IS_HLINKED(file))
+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
+@@ -1317,7 +1341,7 @@ static void recv_generator(char *fname,
+ rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
+ full_fname(fname), sl);
+ } else {
+- set_file_attrs(fname, file, NULL, 0);
++ set_file_attrs(fname, file, NULL, NULL, 0);
+ if (itemizing) {
+ itemize(fname, file, ndx, statret, &sx,
+ ITEM_LOCAL_CHANGE, 0, NULL);
+@@ -1359,7 +1383,7 @@ static void recv_generator(char *fname,
+ /* The device or special file is identical. */
+ if (itemizing)
+ itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
+- set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
++ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_IS_HLINKED(file))
+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
+@@ -1399,7 +1423,7 @@ static void recv_generator(char *fname,
+ rsyserr(FERROR, errno, "mknod %s failed",
+ full_fname(fname));
+ } else {
+- set_file_attrs(fname, file, NULL, 0);
++ set_file_attrs(fname, file, NULL, NULL, 0);
+ if (itemizing) {
+ itemize(fname, file, ndx, statret, &sx,
+ ITEM_LOCAL_CHANGE, 0, NULL);
+@@ -1531,7 +1555,7 @@ static void recv_generator(char *fname,
+ }
+ if (itemizing)
+ itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
+- set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
++ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_IS_HLINKED(file))
+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
@@ -1636,6 +1660,10 @@ static void recv_generator(char *fname,
if (preserve_acls)
free_acl(&real_sx);
}
if (!do_xfers) {
+@@ -1657,7 +1685,7 @@ static void recv_generator(char *fname,
+
+ if (f_copy >= 0) {
+ close(f_copy);
+- set_file_attrs(backupptr, back_file, NULL, 0);
++ set_file_attrs(backupptr, back_file, NULL, NULL, 0);
+ if (verbose > 1) {
+ rprintf(FINFO, "backed up %s to %s\n",
+ fname, backupptr);
@@ -1672,6 +1700,10 @@ static void recv_generator(char *fname,
if (preserve_acls)
free_acl(&sx);
maybe_log_item(file, iflags, itemizing, xname);
+#ifdef SUPPORT_XATTRS
+ if (iflags & ITEM_REPORT_XATTR && !dry_run)
-+ set_file_attrs(fname, file, NULL, 0);
++ set_file_attrs(fname, file, NULL, fname, 0);
+#endif
continue;
}
if (phase == 2) {
+@@ -655,15 +665,15 @@ int recv_files(int f_in, char *local_nam
+ temp_copy_name = NULL;
+ else
+ temp_copy_name = partialptr;
+- finish_transfer(fname, fnametmp, temp_copy_name,
+- file, recv_ok, 1);
++ finish_transfer(fname, fnametmp, fnamecmp,
++ temp_copy_name, file, recv_ok, 1);
+ if (fnamecmp == partialptr) {
+ do_unlink(partialptr);
+ handle_partial_dir(partialptr, PDIR_DELETE);
+ }
+ } else if (keep_partial && partialptr
+ && handle_partial_dir(partialptr, PDIR_CREATE)) {
+- finish_transfer(partialptr, fnametmp, NULL,
++ finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
+ file, recv_ok, !partial_dir);
+ if (delay_updates && recv_ok) {
+ bitbag_set_bit(delayed_bits, ndx);
--- old/rsync.c
+++ new/rsync.c
@@ -32,6 +32,7 @@
}
*iflag_ptr = iflags;
+@@ -228,8 +222,8 @@ mode_t dest_mode(mode_t flist_mode, mode
+ return new_mode;
+ }
+
+-int set_file_attrs(char *fname, struct file_struct *file, statx *sxp,
+- int flags)
++int set_file_attrs(const char *fname, struct file_struct *file, statx *sxp,
++ const char *fnamecmp, int flags)
+ {
+ int updated = 0;
+ statx sx2;
@@ -247,6 +241,9 @@ int set_file_attrs(char *fname, struct f
#ifdef SUPPORT_ACLS
sx2.acc_acl = sx2.def_acl = NULL;
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
+#ifdef SUPPORT_XATTRS
-+ if (preserve_xattrs && !am_generator)
-+ set_xattr(fname, file, sxp);
++ if (preserve_xattrs && fnamecmp)
++ set_xattr(fname, file, fnamecmp);
+#endif
#ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator
- free_acl(&sx2);
+ if (preserve_acls)
+ free_acl(&sx2);
- #endif
++#endif
+#ifdef SUPPORT_XATTRS
+ if (preserve_xattrs)
+ free_xattr(&sx2);
-+#endif
+ #endif
+ }
return updated;
}
+@@ -378,7 +385,8 @@ RETSIGTYPE sig_int(UNUSED(int val))
+ * attributes (e.g. permissions, ownership, etc.). If partialptr is not
+ * NULL and the robust_rename() call is forced to copy the temp file, we
+ * stage the file into the partial-dir and then rename it into place. */
+-void finish_transfer(char *fname, char *fnametmp, char *partialptr,
++void finish_transfer(const char *fname, const char *fnametmp,
++ const char *fnamecmp, const char *partialptr,
+ struct file_struct *file, int ok_to_set_time,
+ int overwriting_basis)
+ {
+@@ -395,7 +403,7 @@ void finish_transfer(char *fname, char *
+ return;
+
+ /* Change permissions before putting the file into place. */
+- set_file_attrs(fnametmp, file, NULL,
++ set_file_attrs(fnametmp, file, NULL, fnamecmp,
+ ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
+
+ /* move tmp file over real file */
+@@ -419,7 +427,7 @@ void finish_transfer(char *fname, char *
+ fnametmp = partialptr ? partialptr : fname;
+
+ do_set_file_attrs:
+- set_file_attrs(fnametmp, file, NULL,
++ set_file_attrs(fnametmp, file, NULL, fnamecmp,
+ ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
+
+ if (partialptr) {
--- old/rsync.h
+++ new/rsync.h
@@ -569,6 +569,7 @@ extern int file_extra_cnt;
+exit 0
--- old/xattrs.c
+++ new/xattrs.c
-@@ -0,0 +1,688 @@
+@@ -0,0 +1,713 @@
+/*
+ * Extended Attribute support for rsync.
+ * Written by Jay Fenlason, vaguely based on the ACLs patch.
+ && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
+ MAX_DIGEST_LEN) == 0;
+ /* Flag unrequested items that we need. */
-+ if (/*!same &&*/ find_all && snd_rxa->datum[0] == 0)
++ if (!same && find_all && snd_rxa->datum[0] == 0)
+ snd_rxa->datum[0] = 1;
+ } else {
+ same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
+ F_XATTR(file) = ndx;
+}
+
-+static int rsync_xal_set(const char *fname, item_list *xalp)
++static int rsync_xal_set(const char *fname, item_list *xalp, const char *fnamecmp)
+{
+ rsync_xa *rxas = xalp->items;
+ ssize_t list_len;
+
+ for (i = 0; i < xalp->count; i++) {
+ if ((size_t)(rxas[i].name - rxas[i].datum) < rxas[i].datum_len) {
-+ rprintf(FERROR, "Abbreviated xattr value, %s, not received for %s\n",
-+ rxas[i].name, full_fname(fname));
-+ exit_cleanup(RERR_STREAMIO);
++ size_t len = rxas[i].name_len;
++ char *ptr;
++
++ /* See if fnamecmp version is identical. */
++ if ((ptr = get_xattr_data(fnamecmp, rxas[i].name, &len)) != NULL
++ && len == rxas[i].datum_len) {
++ char sum[MAX_DIGEST_LEN];
++ sum_init(checksum_seed);
++ sum_update(ptr, len);
++ sum_end(sum);
++ if (memcmp(sum, rxas[i].datum + 1, MAX_DIGEST_LEN) == 0) {
++ char *name = ptr + len;
++ memcpy(name, rxas[i].name, rxas[i].name_len);
++ rxas[i].name = name;
++ free(rxas[i].datum);
++ rxas[i].datum = ptr;
++ } else
++ len = 0;
++ } else
++ len = 0;
++ if (!len) {
++ rprintf(FERROR, "Missing abbreviated xattr value, %s, for %s\n",
++ rxas[i].name, full_fname(fname));
++ ret = -1;
++ continue;
++ }
++ if (fname == fnamecmp) /* value is already set */
++ continue;
+ }
+ status = sys_lsetxattr(fname, rxas[i].name, rxas[i].datum, rxas[i].datum_len);
+ if (status < 0) {
+}
+
+/* Set extended attributes on indicated filename. */
-+int set_xattr(const char *fname, const struct file_struct *file, UNUSED(statx *sxp))
++int set_xattr(const char *fname, const struct file_struct *file, const char *fnamecmp)
+{
+ int ndx;
+ item_list *lst = rsync_xal_l.items;
+ }
+
+ ndx = F_XATTR(file);
-+ return rsync_xal_set(fname, lst + ndx);
++ return rsync_xal_set(fname, lst + ndx, fnamecmp);
+}
+
+#endif /* SUPPORT_XATTRS */