X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/774d1c367bbde80c2d9ce8875048860c8c0b5272..5dd14f0c3388f69932d521915e039e32b9e6d970:/xattrs.c diff --git a/xattrs.c b/xattrs.c index 552a63b3..28d147d9 100644 --- a/xattrs.c +++ b/xattrs.c @@ -21,6 +21,7 @@ #include "rsync.h" #include "ifuncs.h" +#include "inums.h" #include "lib/sysxattrs.h" #ifdef SUPPORT_XATTRS @@ -44,9 +45,9 @@ extern int checksum_seed; #define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len) -#define XSTATE_ABBREV 0 -#define XSTATE_DONE 1 -#define XSTATE_TODO 2 +#define XSTATE_ABBREV 1 +#define XSTATE_DONE 2 +#define XSTATE_TODO 3 #define USER_PREFIX "user." #define UPRE_LEN ((int)sizeof USER_PREFIX - 1) @@ -114,7 +115,7 @@ static int rsync_xal_compare_names(const void *x1, const void *x2) static ssize_t get_xattr_names(const char *fname) { ssize_t list_len; - double arg; + int64 arg; if (!namebuf) { namebuf_len = 1024; @@ -132,11 +133,11 @@ static ssize_t get_xattr_names(const char *fname) } else if (errno == ENOTSUP) return 0; else if (errno != ERANGE) { - arg = (double)namebuf_len; + arg = namebuf_len; got_error: rsyserr(FERROR_XFER, errno, - "get_xattr_names: llistxattr(\"%s\",%.0f) failed", - fname, arg); + "get_xattr_names: llistxattr(\"%s\",%s) failed", + fname, big_num(arg)); return -1; } list_len = sys_llistxattr(fname, NULL, 0); @@ -288,6 +289,48 @@ int get_xattr(const char *fname, stat_x *sxp) return 0; } +int copy_xattrs(const char *source, const char *dest) +{ + ssize_t list_len, name_len; + size_t datum_len; + char *name, *ptr; +#ifdef HAVE_LINUX_XATTRS + int user_only = am_sender ? 0 : am_root <= 0; +#endif + + /* This puts the name list into the "namebuf" buffer. */ + if ((list_len = get_xattr_names(source)) < 0) + return -1; + + for (name = namebuf; list_len > 0; name += name_len) { + name_len = strlen(name) + 1; + list_len -= name_len; + +#ifdef HAVE_LINUX_XATTRS + /* We always ignore the system namespace, and non-root + * ignores everything but the user namespace. */ + if (user_only ? !HAS_PREFIX(name, USER_PREFIX) + : HAS_PREFIX(name, SYSTEM_PREFIX)) + continue; +#endif + + datum_len = 0; + if (!(ptr = get_xattr_data(source, name, &datum_len, 0))) + return -1; + if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) { + int save_errno = errno ? errno : EINVAL; + rsyserr(FERROR_XFER, errno, + "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed", + dest, name); + errno = save_errno; + return -1; + } + free(ptr); + } + + return 0; +} + static int find_matching_xattr(item_list *xalp) { size_t i, j; @@ -461,9 +504,11 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all) return !xattrs_equal; } -/* When called by the generator with a NULL fname, this tells the sender - * which abbreviated xattr values we need. When called by the sender - * (with a non-NULL fname), we send all the extra xattr data it needs. */ +/* When called by the generator (with a NULL fname), this tells the sender + * all the abbreviated xattr values we need. When called by the sender + * (with a non-NULL fname), we send all the extra xattr data it needs. + * The generator may also call with f_out < 0 to just change all the + * XSTATE_ABBREV states into XSTATE_DONE. */ void send_xattr_request(const char *fname, struct file_struct *file, int f_out) { item_list *lst = rsync_xal_l.items; @@ -482,6 +527,7 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out) rxa->datum[0] = XSTATE_DONE; continue; case XSTATE_TODO: + assert(f_out >= 0); break; default: continue; @@ -510,7 +556,8 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out) } } - write_byte(f_out, 0); /* end the list */ + if (f_out >= 0) + write_byte(f_out, 0); /* end the list */ } /* When called by the sender, read the request from the generator and mark @@ -544,8 +591,9 @@ int recv_xattr_request(struct file_struct *file, int f_in) who_am_i(), num, f_name(file, NULL)); exit_cleanup(RERR_STREAMIO); } - if (rxa->datum_len <= MAX_FULL_DATUM || rxa->datum[0] != XSTATE_ABBREV) { - rprintf(FERROR, "[%s] internal abbrev error!\n", who_am_i()); + if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) { + rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n", + who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len); exit_cleanup(RERR_STREAMIO); } @@ -698,6 +746,9 @@ static int rsync_xal_set(const char *fname, item_list *xalp, ssize_t list_len; size_t i, len; char *name, *ptr, sum[MAX_DIGEST_LEN]; +#ifdef HAVE_LINUX_XATTRS + int user_only = am_root <= 0; +#endif size_t name_len; int ret = 0; @@ -773,8 +824,8 @@ static int rsync_xal_set(const char *fname, item_list *xalp, #ifdef HAVE_LINUX_XATTRS /* We always ignore the system namespace, and non-root * ignores everything but the user namespace. */ - if (am_root ? HAS_PREFIX(name, SYSTEM_PREFIX) - : !HAS_PREFIX(name, USER_PREFIX)) + if (user_only ? !HAS_PREFIX(name, USER_PREFIX) + : HAS_PREFIX(name, SYSTEM_PREFIX)) continue; #endif if (am_root < 0 && name_len > RPRE_LEN