X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/b769ad6a3e7ef871ea0aabd5b033018ba6cdbb90..774d1c367bbde80c2d9ce8875048860c8c0b5272:/xattrs.c diff --git a/xattrs.c b/xattrs.c index 61d4f607..552a63b3 100644 --- a/xattrs.c +++ b/xattrs.c @@ -3,7 +3,7 @@ * Written by Jay Fenlason, vaguely based on the ACLs patch. * * Copyright (C) 2004 Red Hat, Inc. - * Copyright (C) 2006, 2007 Wayne Davison + * Copyright (C) 2006-2008 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,9 +62,12 @@ extern int checksum_seed; #endif #define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1) -#define XSTAT_ATTR RSYNC_PREFIX "%stat" -#define XACC_ACL_ATTR RSYNC_PREFIX "%aacl" -#define XDEF_ACL_ATTR RSYNC_PREFIX "%dacl" +#define XSTAT_SUFFIX "stat" +#define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX +#define XACC_ACL_SUFFIX "aacl" +#define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX +#define XDEF_ACL_SUFFIX "dacl" +#define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX typedef struct { char *datum, *name; @@ -111,6 +114,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; if (!namebuf) { namebuf_len = 1024; @@ -119,39 +123,36 @@ static ssize_t get_xattr_names(const char *fname) out_of_memory("get_xattr_names"); } - /* The length returned includes all the '\0' terminators. */ - list_len = sys_llistxattr(fname, namebuf, namebuf_len); - if (list_len > (ssize_t)namebuf_len) { - list_len = -1; - errno = ERANGE; - } - if (list_len >= 0) - return list_len; - if (errno == ENOTSUP) - return 0; - if (errno == ERANGE) { - list_len = sys_llistxattr(fname, NULL, 0); - if (list_len < 0) { + while (1) { + /* The length returned includes all the '\0' terminators. */ + list_len = sys_llistxattr(fname, namebuf, namebuf_len); + if (list_len >= 0) { + if ((size_t)list_len <= namebuf_len) + break; + } else if (errno == ENOTSUP) + return 0; + else if (errno != ERANGE) { + arg = (double)namebuf_len; + got_error: rsyserr(FERROR_XFER, errno, - "get_xattr_names: llistxattr(\"%s\",0) failed", - fname); + "get_xattr_names: llistxattr(\"%s\",%.0f) failed", + fname, arg); return -1; } + list_len = sys_llistxattr(fname, NULL, 0); + if (list_len < 0) { + arg = 0; + goto got_error; + } if (namebuf_len) free(namebuf); namebuf_len = list_len + 1024; namebuf = new_array(char, namebuf_len); if (!namebuf) out_of_memory("get_xattr_names"); - list_len = sys_llistxattr(fname, namebuf, namebuf_len); - if (list_len >= 0) - return list_len; } - rsyserr(FERROR_XFER, errno, - "get_xattr_names: llistxattr(\"%s\",%ld) failed", - fname, (long)namebuf_len); - return -1; + return list_len; } /* On entry, the *len_ptr parameter contains the size of the extra space we @@ -177,8 +178,9 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr if (!datum_len && !extra_len) extra_len = 1; /* request non-zero amount of memory */ - if (datum_len + extra_len < datum_len /* checks for overflow */ - || !(ptr = new_array(char, datum_len + extra_len))) + if (datum_len + extra_len < datum_len) + overflow_exit("get_xattr_data"); + if (!(ptr = new_array(char, datum_len + extra_len))) out_of_memory("get_xattr_data"); if (datum_len) { @@ -233,7 +235,10 @@ static int rsync_xal_get(const char *fname, item_list *xalp) if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) { if ((am_sender && preserve_xattrs < 2) - || (am_root < 0 && strcmp(name, XSTAT_ATTR) == 0)) + || (am_root < 0 + && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0 + || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0 + || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0))) continue; } @@ -255,14 +260,6 @@ static int rsync_xal_get(const char *fname, item_list *xalp) } else name_offset = datum_len; -#ifdef HAVE_LINUX_XATTRS - if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] != '%' - && HAS_PREFIX(name, RSYNC_PREFIX)) { - name += RPRE_LEN; - name_len -= RPRE_LEN; - } -#endif - rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL); rxa->name = ptr + name_offset; memcpy(rxa->name, name, name_len); @@ -354,25 +351,32 @@ int send_xattr(stat_x *sxp, int f) int count = sxp->xattr->count; write_varint(f, count); for (rxa = sxp->xattr->items; count--; rxa++) { + size_t name_len = rxa->name_len; + const char *name = rxa->name; + /* Strip the rsync prefix from disguised namespaces. */ + if (name_len > RPRE_LEN #ifdef HAVE_LINUX_XATTRS - write_varint(f, rxa->name_len); + && am_root < 0 +#endif + && name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) { + name += RPRE_LEN; + name_len -= RPRE_LEN; + } +#ifndef HAVE_LINUX_XATTRS + else { + /* Put everything else in the user namespace. */ + name_len += UPRE_LEN; + } +#endif + write_varint(f, name_len); write_varint(f, rxa->datum_len); - write_buf(f, rxa->name, rxa->name_len); -#else - /* We strip the rsync prefix from disguised namespaces - * and put everything else in the user namespace. */ - if (HAS_PREFIX(rxa->name, RSYNC_PREFIX) - && rxa->name[RPRE_LEN] != '%') { - write_varint(f, rxa->name_len - RPRE_LEN); - write_varint(f, rxa->datum_len); - write_buf(f, rxa->name + RPRE_LEN, rxa->name_len - RPRE_LEN); - } else { - write_varint(f, rxa->name_len + UPRE_LEN); - write_varint(f, rxa->datum_len); +#ifndef HAVE_LINUX_XATTRS + if (name_len > rxa->name_len) { write_buf(f, USER_PREFIX, UPRE_LEN); - write_buf(f, rxa->name, rxa->name_len); + name_len -= UPRE_LEN; } #endif + write_buf(f, name, name_len); if (rxa->datum_len > MAX_FULL_DATUM) write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN); else @@ -554,7 +558,7 @@ int recv_xattr_request(struct file_struct *file, int f_in) rxa->datum_len = read_varint(f_in); if (rxa->name_len + rxa->datum_len < rxa->name_len) - out_of_memory("recv_xattr_request"); /* overflow */ + overflow_exit("recv_xattr_request"); rxa->datum = new_array(char, rxa->datum_len + rxa->name_len); if (!rxa->datum) out_of_memory("recv_xattr_request"); @@ -576,6 +580,11 @@ void receive_xattr(struct file_struct *file, int f) { static item_list temp_xattr = EMPTY_ITEM_LIST; int count, num; +#ifdef HAVE_LINUX_XATTRS + int need_sort = 0; +#else + int need_sort = 1; +#endif int ndx = read_varint(f); if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) { @@ -601,10 +610,9 @@ void receive_xattr(struct file_struct *file, int f) size_t datum_len = read_varint(f); size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len; size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0; - if (dget_len + extra_len < dget_len) - out_of_memory("receive_xattr"); /* overflow */ - if (dget_len + extra_len + name_len < dget_len) - out_of_memory("receive_xattr"); /* overflow */ + if ((dget_len + extra_len < dget_len) + || (dget_len + extra_len + name_len < dget_len)) + overflow_exit("receive_xattr"); ptr = new_array(char, dget_len + extra_len + name_len); if (!ptr) out_of_memory("receive_xattr"); @@ -626,6 +634,7 @@ void receive_xattr(struct file_struct *file, int f) name -= RPRE_LEN; name_len += RPRE_LEN; memcpy(name, RSYNC_PREFIX, RPRE_LEN); + need_sort = 1; } #else /* This OS only has a user namespace, so we either @@ -657,6 +666,9 @@ void receive_xattr(struct file_struct *file, int f) rxa->num = num; } + if (need_sort && count > 1) + qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names); + ndx = rsync_xal_l.count; /* pre-incremented count */ rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */ @@ -686,7 +698,8 @@ 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]; - int name_len, ret = 0; + size_t name_len; + int ret = 0; /* This puts the current name list into the "namebuf" buffer. */ if ((list_len = get_xattr_names(fname)) < 0)