Annotation of embedaddon/rsync/xattrs.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Extended Attribute support for rsync.
! 3: * Written by Jay Fenlason, vaguely based on the ACLs patch.
! 4: *
! 5: * Copyright (C) 2004 Red Hat, Inc.
! 6: * Copyright (C) 2006-2009 Wayne Davison
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify
! 9: * it under the terms of the GNU General Public License as published by
! 10: * the Free Software Foundation; either version 3 of the License, or
! 11: * (at your option) any later version.
! 12: *
! 13: * This program is distributed in the hope that it will be useful,
! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 16: * GNU General Public License for more details.
! 17: *
! 18: * You should have received a copy of the GNU General Public License along
! 19: * with this program; if not, visit the http://fsf.org website.
! 20: */
! 21:
! 22: #include "rsync.h"
! 23: #include "ifuncs.h"
! 24: #include "lib/sysxattrs.h"
! 25:
! 26: #ifdef SUPPORT_XATTRS
! 27:
! 28: extern int dry_run;
! 29: extern int am_root;
! 30: extern int am_sender;
! 31: extern int am_generator;
! 32: extern int read_only;
! 33: extern int list_only;
! 34: extern int preserve_xattrs;
! 35: extern int preserve_links;
! 36: extern int preserve_devices;
! 37: extern int preserve_specials;
! 38: extern int checksum_seed;
! 39:
! 40: #define RSYNC_XAL_INITIAL 5
! 41: #define RSYNC_XAL_LIST_INITIAL 100
! 42:
! 43: #define MAX_FULL_DATUM 32
! 44:
! 45: #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) \
! 46: && strncmp(str, prfx, sizeof (prfx) - 1) == 0)
! 47:
! 48: #define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len)
! 49:
! 50: #define XSTATE_ABBREV 1
! 51: #define XSTATE_DONE 2
! 52: #define XSTATE_TODO 3
! 53:
! 54: #define USER_PREFIX "user."
! 55: #define UPRE_LEN ((int)sizeof USER_PREFIX - 1)
! 56: #define SYSTEM_PREFIX "system."
! 57: #define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1)
! 58:
! 59: #ifdef HAVE_LINUX_XATTRS
! 60: #define MIGHT_NEED_RPRE (am_root < 0)
! 61: #define RSYNC_PREFIX USER_PREFIX "rsync."
! 62: #else
! 63: #define MIGHT_NEED_RPRE am_root
! 64: #define RSYNC_PREFIX "rsync."
! 65: #endif
! 66: #define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
! 67:
! 68: #define XSTAT_SUFFIX "stat"
! 69: #define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
! 70: #define XACC_ACL_SUFFIX "aacl"
! 71: #define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
! 72: #define XDEF_ACL_SUFFIX "dacl"
! 73: #define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
! 74:
! 75: typedef struct {
! 76: char *datum, *name;
! 77: size_t datum_len, name_len;
! 78: int num;
! 79: } rsync_xa;
! 80:
! 81: static size_t namebuf_len = 0;
! 82: static char *namebuf = NULL;
! 83:
! 84: static item_list empty_xattr = EMPTY_ITEM_LIST;
! 85: static item_list rsync_xal_l = EMPTY_ITEM_LIST;
! 86:
! 87: static size_t prior_xattr_count = (size_t)-1;
! 88:
! 89: /* ------------------------------------------------------------------------- */
! 90:
! 91: static void rsync_xal_free(item_list *xalp)
! 92: {
! 93: size_t i;
! 94: rsync_xa *rxas = xalp->items;
! 95:
! 96: if (!xalp->malloced)
! 97: return;
! 98:
! 99: for (i = 0; i < xalp->count; i++) {
! 100: free(rxas[i].datum);
! 101: /*free(rxas[i].name);*/
! 102: }
! 103: free(xalp->items);
! 104: }
! 105:
! 106: void free_xattr(stat_x *sxp)
! 107: {
! 108: if (!sxp->xattr)
! 109: return;
! 110: rsync_xal_free(sxp->xattr);
! 111: free(sxp->xattr);
! 112: sxp->xattr = NULL;
! 113: }
! 114:
! 115: static int rsync_xal_compare_names(const void *x1, const void *x2)
! 116: {
! 117: const rsync_xa *xa1 = x1;
! 118: const rsync_xa *xa2 = x2;
! 119: return strcmp(xa1->name, xa2->name);
! 120: }
! 121:
! 122: static ssize_t get_xattr_names(const char *fname)
! 123: {
! 124: ssize_t list_len;
! 125: double arg;
! 126:
! 127: if (!namebuf) {
! 128: namebuf_len = 1024;
! 129: namebuf = new_array(char, namebuf_len);
! 130: if (!namebuf)
! 131: out_of_memory("get_xattr_names");
! 132: }
! 133:
! 134: while (1) {
! 135: /* The length returned includes all the '\0' terminators. */
! 136: list_len = sys_llistxattr(fname, namebuf, namebuf_len);
! 137: if (list_len >= 0) {
! 138: if ((size_t)list_len <= namebuf_len)
! 139: break;
! 140: } else if (errno == ENOTSUP)
! 141: return 0;
! 142: else if (errno != ERANGE) {
! 143: arg = (double)namebuf_len;
! 144: got_error:
! 145: rsyserr(FERROR_XFER, errno,
! 146: "get_xattr_names: llistxattr(\"%s\",%.0f) failed",
! 147: full_fname(fname), arg);
! 148: return -1;
! 149: }
! 150: list_len = sys_llistxattr(fname, NULL, 0);
! 151: if (list_len < 0) {
! 152: arg = 0;
! 153: goto got_error;
! 154: }
! 155: if (namebuf_len)
! 156: free(namebuf);
! 157: namebuf_len = list_len + 1024;
! 158: namebuf = new_array(char, namebuf_len);
! 159: if (!namebuf)
! 160: out_of_memory("get_xattr_names");
! 161: }
! 162:
! 163: return list_len;
! 164: }
! 165:
! 166: /* On entry, the *len_ptr parameter contains the size of the extra space we
! 167: * should allocate when we create a buffer for the data. On exit, it contains
! 168: * the length of the datum. */
! 169: static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr,
! 170: int no_missing_error)
! 171: {
! 172: size_t datum_len = sys_lgetxattr(fname, name, NULL, 0);
! 173: size_t extra_len = *len_ptr;
! 174: char *ptr;
! 175:
! 176: *len_ptr = datum_len;
! 177:
! 178: if (datum_len == (size_t)-1) {
! 179: if (errno == ENOTSUP || no_missing_error)
! 180: return NULL;
! 181: rsyserr(FERROR_XFER, errno,
! 182: "get_xattr_data: lgetxattr(\"%s\",\"%s\",0) failed",
! 183: full_fname(fname), name);
! 184: return NULL;
! 185: }
! 186:
! 187: if (!datum_len && !extra_len)
! 188: extra_len = 1; /* request non-zero amount of memory */
! 189: if (datum_len + extra_len < datum_len)
! 190: overflow_exit("get_xattr_data");
! 191: if (!(ptr = new_array(char, datum_len + extra_len)))
! 192: out_of_memory("get_xattr_data");
! 193:
! 194: if (datum_len) {
! 195: size_t len = sys_lgetxattr(fname, name, ptr, datum_len);
! 196: if (len != datum_len) {
! 197: if (len == (size_t)-1) {
! 198: rsyserr(FERROR_XFER, errno,
! 199: "get_xattr_data: lgetxattr(\"%s\",\"%s\",%ld)"
! 200: " failed", full_fname(fname), name, (long)datum_len);
! 201: } else {
! 202: rprintf(FERROR_XFER,
! 203: "get_xattr_data: lgetxattr(\"%s\",\"%s\",%ld)"
! 204: " returned %ld\n", full_fname(fname), name,
! 205: (long)datum_len, (long)len);
! 206: }
! 207: free(ptr);
! 208: return NULL;
! 209: }
! 210: }
! 211:
! 212: return ptr;
! 213: }
! 214:
! 215: static int rsync_xal_get(const char *fname, item_list *xalp)
! 216: {
! 217: ssize_t list_len, name_len;
! 218: size_t datum_len, name_offset;
! 219: char *name, *ptr;
! 220: #ifdef HAVE_LINUX_XATTRS
! 221: int user_only = am_sender ? 0 : am_root <= 0;
! 222: #endif
! 223: rsync_xa *rxa;
! 224: int count;
! 225:
! 226: /* This puts the name list into the "namebuf" buffer. */
! 227: if ((list_len = get_xattr_names(fname)) < 0)
! 228: return -1;
! 229:
! 230: for (name = namebuf; list_len > 0; name += name_len) {
! 231: name_len = strlen(name) + 1;
! 232: list_len -= name_len;
! 233:
! 234: #ifdef HAVE_LINUX_XATTRS
! 235: /* We always ignore the system namespace, and non-root
! 236: * ignores everything but the user namespace. */
! 237: if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
! 238: : HAS_PREFIX(name, SYSTEM_PREFIX))
! 239: continue;
! 240: #endif
! 241:
! 242: /* No rsync.%FOO attributes are copied w/o 2 -X options. */
! 243: if (name_len > RPRE_LEN && name[RPRE_LEN] == '%'
! 244: && HAS_PREFIX(name, RSYNC_PREFIX)) {
! 245: if ((am_sender && preserve_xattrs < 2)
! 246: || (am_root < 0
! 247: && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
! 248: || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
! 249: || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
! 250: continue;
! 251: }
! 252:
! 253: datum_len = name_len; /* Pass extra size to get_xattr_data() */
! 254: if (!(ptr = get_xattr_data(fname, name, &datum_len, 0)))
! 255: return -1;
! 256:
! 257: if (datum_len > MAX_FULL_DATUM) {
! 258: /* For large datums, we store a flag and a checksum. */
! 259: name_offset = 1 + MAX_DIGEST_LEN;
! 260: sum_init(checksum_seed);
! 261: sum_update(ptr, datum_len);
! 262: free(ptr);
! 263:
! 264: if (!(ptr = new_array(char, name_offset + name_len)))
! 265: out_of_memory("rsync_xal_get");
! 266: *ptr = XSTATE_ABBREV;
! 267: sum_end(ptr + 1);
! 268: } else
! 269: name_offset = datum_len;
! 270:
! 271: rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
! 272: rxa->name = ptr + name_offset;
! 273: memcpy(rxa->name, name, name_len);
! 274: rxa->datum = ptr;
! 275: rxa->name_len = name_len;
! 276: rxa->datum_len = datum_len;
! 277: }
! 278: count = xalp->count;
! 279: rxa = xalp->items;
! 280: if (count > 1)
! 281: qsort(rxa, count, sizeof (rsync_xa), rsync_xal_compare_names);
! 282: for (rxa += count-1; count; count--, rxa--)
! 283: rxa->num = count;
! 284: return 0;
! 285: }
! 286:
! 287: /* Read the xattr(s) for this filename. */
! 288: int get_xattr(const char *fname, stat_x *sxp)
! 289: {
! 290: sxp->xattr = new(item_list);
! 291: *sxp->xattr = empty_xattr;
! 292:
! 293: if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
! 294: /* Everyone supports this. */
! 295: } else if (S_ISLNK(sxp->st.st_mode)) {
! 296: #ifndef NO_SYMLINK_XATTRS
! 297: if (!preserve_links)
! 298: #endif
! 299: return 0;
! 300: } else if (IS_SPECIAL(sxp->st.st_mode)) {
! 301: #ifndef NO_SPECIAL_XATTRS
! 302: if (!preserve_specials)
! 303: #endif
! 304: return 0;
! 305: } else if (IS_DEVICE(sxp->st.st_mode)) {
! 306: #ifndef NO_DEVICE_XATTRS
! 307: if (!preserve_devices)
! 308: #endif
! 309: return 0;
! 310: }
! 311:
! 312: if (rsync_xal_get(fname, sxp->xattr) < 0) {
! 313: free_xattr(sxp);
! 314: return -1;
! 315: }
! 316: return 0;
! 317: }
! 318:
! 319: int copy_xattrs(const char *source, const char *dest)
! 320: {
! 321: ssize_t list_len, name_len;
! 322: size_t datum_len;
! 323: char *name, *ptr;
! 324: #ifdef HAVE_LINUX_XATTRS
! 325: int user_only = am_root <= 0;
! 326: #endif
! 327:
! 328: /* This puts the name list into the "namebuf" buffer. */
! 329: if ((list_len = get_xattr_names(source)) < 0)
! 330: return -1;
! 331:
! 332: for (name = namebuf; list_len > 0; name += name_len) {
! 333: name_len = strlen(name) + 1;
! 334: list_len -= name_len;
! 335:
! 336: #ifdef HAVE_LINUX_XATTRS
! 337: /* We always ignore the system namespace, and non-root
! 338: * ignores everything but the user namespace. */
! 339: if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
! 340: : HAS_PREFIX(name, SYSTEM_PREFIX))
! 341: continue;
! 342: #endif
! 343:
! 344: datum_len = 0;
! 345: if (!(ptr = get_xattr_data(source, name, &datum_len, 0)))
! 346: return -1;
! 347: if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) {
! 348: int save_errno = errno ? errno : EINVAL;
! 349: rsyserr(FERROR_XFER, errno,
! 350: "copy_xattrs: lsetxattr(\"%s\",\"%s\") failed",
! 351: full_fname(dest), name);
! 352: errno = save_errno;
! 353: return -1;
! 354: }
! 355: free(ptr);
! 356: }
! 357:
! 358: return 0;
! 359: }
! 360:
! 361: static int find_matching_xattr(item_list *xalp)
! 362: {
! 363: size_t i, j;
! 364: item_list *lst = rsync_xal_l.items;
! 365:
! 366: for (i = 0; i < rsync_xal_l.count; i++) {
! 367: rsync_xa *rxas1 = lst[i].items;
! 368: rsync_xa *rxas2 = xalp->items;
! 369:
! 370: /* Wrong number of elements? */
! 371: if (lst[i].count != xalp->count)
! 372: continue;
! 373: /* any elements different? */
! 374: for (j = 0; j < xalp->count; j++) {
! 375: if (rxas1[j].name_len != rxas2[j].name_len
! 376: || rxas1[j].datum_len != rxas2[j].datum_len
! 377: || strcmp(rxas1[j].name, rxas2[j].name))
! 378: break;
! 379: if (rxas1[j].datum_len > MAX_FULL_DATUM) {
! 380: if (memcmp(rxas1[j].datum + 1,
! 381: rxas2[j].datum + 1,
! 382: MAX_DIGEST_LEN) != 0)
! 383: break;
! 384: } else {
! 385: if (memcmp(rxas1[j].datum, rxas2[j].datum,
! 386: rxas2[j].datum_len))
! 387: break;
! 388: }
! 389: }
! 390: /* no differences found. This is The One! */
! 391: if (j == xalp->count)
! 392: return i;
! 393: }
! 394:
! 395: return -1;
! 396: }
! 397:
! 398: /* Store *xalp on the end of rsync_xal_l */
! 399: static void rsync_xal_store(item_list *xalp)
! 400: {
! 401: item_list *new_lst = EXPAND_ITEM_LIST(&rsync_xal_l, item_list, RSYNC_XAL_LIST_INITIAL);
! 402: /* Since the following call starts a new list, we know it will hold the
! 403: * entire initial-count, not just enough space for one new item. */
! 404: *new_lst = empty_xattr;
! 405: (void)EXPAND_ITEM_LIST(new_lst, rsync_xa, xalp->count);
! 406: memcpy(new_lst->items, xalp->items, xalp->count * sizeof (rsync_xa));
! 407: new_lst->count = xalp->count;
! 408: xalp->count = 0;
! 409: }
! 410:
! 411: /* Send the make_xattr()-generated xattr list for this flist entry. */
! 412: int send_xattr(int f, stat_x *sxp)
! 413: {
! 414: int ndx = find_matching_xattr(sxp->xattr);
! 415:
! 416: /* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
! 417: write_varint(f, ndx + 1);
! 418:
! 419: if (ndx < 0) {
! 420: rsync_xa *rxa;
! 421: int count = sxp->xattr->count;
! 422: write_varint(f, count);
! 423: for (rxa = sxp->xattr->items; count--; rxa++) {
! 424: size_t name_len = rxa->name_len;
! 425: const char *name = rxa->name;
! 426: /* Strip the rsync prefix from disguised namespaces. */
! 427: if (name_len > RPRE_LEN
! 428: #ifdef HAVE_LINUX_XATTRS
! 429: && am_root < 0
! 430: #endif
! 431: && name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
! 432: name += RPRE_LEN;
! 433: name_len -= RPRE_LEN;
! 434: }
! 435: #ifndef HAVE_LINUX_XATTRS
! 436: else {
! 437: /* Put everything else in the user namespace. */
! 438: name_len += UPRE_LEN;
! 439: }
! 440: #endif
! 441: write_varint(f, name_len);
! 442: write_varint(f, rxa->datum_len);
! 443: #ifndef HAVE_LINUX_XATTRS
! 444: if (name_len > rxa->name_len) {
! 445: write_buf(f, USER_PREFIX, UPRE_LEN);
! 446: name_len -= UPRE_LEN;
! 447: }
! 448: #endif
! 449: write_buf(f, name, name_len);
! 450: if (rxa->datum_len > MAX_FULL_DATUM)
! 451: write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
! 452: else
! 453: write_buf(f, rxa->datum, rxa->datum_len);
! 454: }
! 455: ndx = rsync_xal_l.count; /* pre-incremented count */
! 456: rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
! 457: }
! 458:
! 459: return ndx;
! 460: }
! 461:
! 462: /* Return a flag indicating if we need to change a file's xattrs. If
! 463: * "find_all" is specified, also mark any abbreviated xattrs that we
! 464: * need so that send_xattr_request() can tell the sender about them. */
! 465: int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
! 466: {
! 467: item_list *lst = rsync_xal_l.items;
! 468: rsync_xa *snd_rxa, *rec_rxa;
! 469: int snd_cnt, rec_cnt;
! 470: int cmp, same, xattrs_equal = 1;
! 471:
! 472: if (sxp && XATTR_READY(*sxp)) {
! 473: rec_rxa = sxp->xattr->items;
! 474: rec_cnt = sxp->xattr->count;
! 475: } else {
! 476: rec_rxa = NULL;
! 477: rec_cnt = 0;
! 478: }
! 479:
! 480: if (F_XATTR(file) >= 0)
! 481: lst += F_XATTR(file);
! 482: else
! 483: lst = &empty_xattr;
! 484:
! 485: snd_rxa = lst->items;
! 486: snd_cnt = lst->count;
! 487:
! 488: /* If the count of the sender's xattrs is different from our
! 489: * (receiver's) xattrs, the lists are not the same. */
! 490: if (snd_cnt != rec_cnt) {
! 491: if (!find_all)
! 492: return 1;
! 493: xattrs_equal = 0;
! 494: }
! 495:
! 496: while (snd_cnt) {
! 497: cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
! 498: if (cmp > 0)
! 499: same = 0;
! 500: else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
! 501: same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
! 502: && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
! 503: MAX_DIGEST_LEN) == 0;
! 504: /* Flag unrequested items that we need. */
! 505: if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
! 506: snd_rxa->datum[0] = XSTATE_TODO;
! 507: } else {
! 508: same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
! 509: && memcmp(snd_rxa->datum, rec_rxa->datum,
! 510: snd_rxa->datum_len) == 0;
! 511: }
! 512: if (!same) {
! 513: if (!find_all)
! 514: return 1;
! 515: xattrs_equal = 0;
! 516: }
! 517:
! 518: if (cmp <= 0) {
! 519: snd_rxa++;
! 520: snd_cnt--;
! 521: }
! 522: if (cmp >= 0) {
! 523: rec_rxa++;
! 524: rec_cnt--;
! 525: }
! 526: }
! 527:
! 528: if (rec_cnt)
! 529: xattrs_equal = 0;
! 530:
! 531: return !xattrs_equal;
! 532: }
! 533:
! 534: /* When called by the generator (with a NULL fname), this tells the sender
! 535: * all the abbreviated xattr values we need. When called by the sender
! 536: * (with a non-NULL fname), we send all the extra xattr data it needs.
! 537: * The generator may also call with f_out < 0 to just change all the
! 538: * XSTATE_ABBREV states into XSTATE_DONE. */
! 539: void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
! 540: {
! 541: item_list *lst = rsync_xal_l.items;
! 542: int cnt, prior_req = 0;
! 543: rsync_xa *rxa;
! 544:
! 545: lst += F_XATTR(file);
! 546: for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) {
! 547: if (rxa->datum_len <= MAX_FULL_DATUM)
! 548: continue;
! 549: switch (rxa->datum[0]) {
! 550: case XSTATE_ABBREV:
! 551: /* Items left abbreviated matched the sender's checksum, so
! 552: * the receiver will cache the local data for future use. */
! 553: if (am_generator)
! 554: rxa->datum[0] = XSTATE_DONE;
! 555: continue;
! 556: case XSTATE_TODO:
! 557: assert(f_out >= 0);
! 558: break;
! 559: default:
! 560: continue;
! 561: }
! 562:
! 563: /* Flag that we handled this abbreviated item. */
! 564: rxa->datum[0] = XSTATE_DONE;
! 565:
! 566: write_varint(f_out, rxa->num - prior_req);
! 567: prior_req = rxa->num;
! 568:
! 569: if (fname) {
! 570: size_t len = 0;
! 571: char *ptr;
! 572:
! 573: /* Re-read the long datum. */
! 574: if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) {
! 575: rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname);
! 576: write_varint(f_out, 0);
! 577: continue;
! 578: }
! 579:
! 580: write_varint(f_out, len); /* length might have changed! */
! 581: write_buf(f_out, ptr, len);
! 582: free(ptr);
! 583: }
! 584: }
! 585:
! 586: if (f_out >= 0)
! 587: write_byte(f_out, 0); /* end the list */
! 588: }
! 589:
! 590: /* When called by the sender, read the request from the generator and mark
! 591: * any needed xattrs with a flag that lets us know they need to be sent to
! 592: * the receiver. When called by the receiver, reads the sent data and
! 593: * stores it in place of its checksum. */
! 594: int recv_xattr_request(struct file_struct *file, int f_in)
! 595: {
! 596: item_list *lst = rsync_xal_l.items;
! 597: char *old_datum, *name;
! 598: rsync_xa *rxa;
! 599: int rel_pos, cnt, num, got_xattr_data = 0;
! 600:
! 601: if (F_XATTR(file) < 0) {
! 602: rprintf(FERROR, "recv_xattr_request: internal data error!\n");
! 603: exit_cleanup(RERR_PROTOCOL);
! 604: }
! 605: lst += F_XATTR(file);
! 606:
! 607: cnt = lst->count;
! 608: rxa = lst->items;
! 609: num = 0;
! 610: while ((rel_pos = read_varint(f_in)) != 0) {
! 611: num += rel_pos;
! 612: while (cnt && rxa->num < num) {
! 613: rxa++;
! 614: cnt--;
! 615: }
! 616: if (!cnt || rxa->num != num) {
! 617: rprintf(FERROR, "[%s] could not find xattr #%d for %s\n",
! 618: who_am_i(), num, f_name(file, NULL));
! 619: exit_cleanup(RERR_PROTOCOL);
! 620: }
! 621: if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) {
! 622: rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n",
! 623: who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len);
! 624: exit_cleanup(RERR_PROTOCOL);
! 625: }
! 626:
! 627: if (am_sender) {
! 628: rxa->datum[0] = XSTATE_TODO;
! 629: continue;
! 630: }
! 631:
! 632: old_datum = rxa->datum;
! 633: rxa->datum_len = read_varint(f_in);
! 634:
! 635: if (rxa->name_len + rxa->datum_len < rxa->name_len)
! 636: overflow_exit("recv_xattr_request");
! 637: rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
! 638: if (!rxa->datum)
! 639: out_of_memory("recv_xattr_request");
! 640: name = rxa->datum + rxa->datum_len;
! 641: memcpy(name, rxa->name, rxa->name_len);
! 642: rxa->name = name;
! 643: free(old_datum);
! 644: read_buf(f_in, rxa->datum, rxa->datum_len);
! 645: got_xattr_data = 1;
! 646: }
! 647:
! 648: return got_xattr_data;
! 649: }
! 650:
! 651: /* ------------------------------------------------------------------------- */
! 652:
! 653: /* receive and build the rsync_xattr_lists */
! 654: void receive_xattr(int f, struct file_struct *file)
! 655: {
! 656: static item_list temp_xattr = EMPTY_ITEM_LIST;
! 657: int count, num;
! 658: #ifdef HAVE_LINUX_XATTRS
! 659: int need_sort = 0;
! 660: #else
! 661: int need_sort = 1;
! 662: #endif
! 663: int ndx = read_varint(f);
! 664:
! 665: if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
! 666: rprintf(FERROR, "receive_xattr: xa index %d out of"
! 667: " range for %s\n", ndx, f_name(file, NULL));
! 668: exit_cleanup(RERR_PROTOCOL);
! 669: }
! 670:
! 671: if (ndx != 0) {
! 672: F_XATTR(file) = ndx - 1;
! 673: return;
! 674: }
! 675:
! 676: if ((count = read_varint(f)) != 0) {
! 677: (void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
! 678: temp_xattr.count = 0;
! 679: }
! 680:
! 681: for (num = 1; num <= count; num++) {
! 682: char *ptr, *name;
! 683: rsync_xa *rxa;
! 684: size_t name_len = read_varint(f);
! 685: size_t datum_len = read_varint(f);
! 686: size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
! 687: size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
! 688: if ((dget_len + extra_len < dget_len)
! 689: || (dget_len + extra_len + name_len < dget_len))
! 690: overflow_exit("receive_xattr");
! 691: ptr = new_array(char, dget_len + extra_len + name_len);
! 692: if (!ptr)
! 693: out_of_memory("receive_xattr");
! 694: name = ptr + dget_len + extra_len;
! 695: read_buf(f, name, name_len);
! 696: if (dget_len == datum_len)
! 697: read_buf(f, ptr, dget_len);
! 698: else {
! 699: *ptr = XSTATE_ABBREV;
! 700: read_buf(f, ptr + 1, MAX_DIGEST_LEN);
! 701: }
! 702: #ifdef HAVE_LINUX_XATTRS
! 703: /* Non-root can only save the user namespace. */
! 704: if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
! 705: if (!am_root) {
! 706: free(ptr);
! 707: continue;
! 708: }
! 709: name -= RPRE_LEN;
! 710: name_len += RPRE_LEN;
! 711: memcpy(name, RSYNC_PREFIX, RPRE_LEN);
! 712: need_sort = 1;
! 713: }
! 714: #else
! 715: /* This OS only has a user namespace, so we either
! 716: * strip the user prefix, or we put a non-user
! 717: * namespace inside our rsync hierarchy. */
! 718: if (HAS_PREFIX(name, USER_PREFIX)) {
! 719: name += UPRE_LEN;
! 720: name_len -= UPRE_LEN;
! 721: } else if (am_root) {
! 722: name -= RPRE_LEN;
! 723: name_len += RPRE_LEN;
! 724: memcpy(name, RSYNC_PREFIX, RPRE_LEN);
! 725: } else {
! 726: free(ptr);
! 727: continue;
! 728: }
! 729: #endif
! 730: /* No rsync.%FOO attributes are copied w/o 2 -X options. */
! 731: if (preserve_xattrs < 2 && name_len > RPRE_LEN
! 732: && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
! 733: free(ptr);
! 734: continue;
! 735: }
! 736: rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1);
! 737: rxa->name = name;
! 738: rxa->datum = ptr;
! 739: rxa->name_len = name_len;
! 740: rxa->datum_len = datum_len;
! 741: rxa->num = num;
! 742: }
! 743:
! 744: if (need_sort && count > 1)
! 745: qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
! 746:
! 747: ndx = rsync_xal_l.count; /* pre-incremented count */
! 748: rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */
! 749:
! 750: F_XATTR(file) = ndx;
! 751: }
! 752:
! 753: /* Turn the xattr data in stat_x into cached xattr data, setting the index
! 754: * values in the file struct. */
! 755: void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
! 756: {
! 757: int ndx;
! 758:
! 759: if (!sxp->xattr)
! 760: return;
! 761:
! 762: if (prior_xattr_count == (size_t)-1)
! 763: prior_xattr_count = rsync_xal_l.count;
! 764: ndx = find_matching_xattr(sxp->xattr);
! 765: if (ndx < 0)
! 766: rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
! 767:
! 768: F_XATTR(file) = ndx;
! 769: }
! 770:
! 771: void uncache_tmp_xattrs(void)
! 772: {
! 773: if (prior_xattr_count != (size_t)-1) {
! 774: item_list *xattr_item = rsync_xal_l.items;
! 775: item_list *xattr_start = xattr_item + prior_xattr_count;
! 776: xattr_item += rsync_xal_l.count;
! 777: rsync_xal_l.count = prior_xattr_count;
! 778: while (xattr_item-- > xattr_start)
! 779: rsync_xal_free(xattr_item);
! 780: prior_xattr_count = (size_t)-1;
! 781: }
! 782: }
! 783:
! 784: static int rsync_xal_set(const char *fname, item_list *xalp,
! 785: const char *fnamecmp, stat_x *sxp)
! 786: {
! 787: rsync_xa *rxas = xalp->items;
! 788: ssize_t list_len;
! 789: size_t i, len;
! 790: char *name, *ptr, sum[MAX_DIGEST_LEN];
! 791: #ifdef HAVE_LINUX_XATTRS
! 792: int user_only = am_root <= 0;
! 793: #endif
! 794: size_t name_len;
! 795: int ret = 0;
! 796:
! 797: /* This puts the current name list into the "namebuf" buffer. */
! 798: if ((list_len = get_xattr_names(fname)) < 0)
! 799: return -1;
! 800:
! 801: for (i = 0; i < xalp->count; i++) {
! 802: name = rxas[i].name;
! 803:
! 804: if (XATTR_ABBREV(rxas[i])) {
! 805: /* See if the fnamecmp version is identical. */
! 806: len = name_len = rxas[i].name_len;
! 807: if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) {
! 808: still_abbrev:
! 809: if (am_generator)
! 810: continue;
! 811: rprintf(FERROR, "Missing abbreviated xattr value, %s, for %s\n",
! 812: rxas[i].name, full_fname(fname));
! 813: ret = -1;
! 814: continue;
! 815: }
! 816: if (len != rxas[i].datum_len) {
! 817: free(ptr);
! 818: goto still_abbrev;
! 819: }
! 820:
! 821: sum_init(checksum_seed);
! 822: sum_update(ptr, len);
! 823: sum_end(sum);
! 824: if (memcmp(sum, rxas[i].datum + 1, MAX_DIGEST_LEN) != 0) {
! 825: free(ptr);
! 826: goto still_abbrev;
! 827: }
! 828:
! 829: if (fname == fnamecmp)
! 830: ; /* Value is already set when identical */
! 831: else if (sys_lsetxattr(fname, name, ptr, len) < 0) {
! 832: rsyserr(FERROR_XFER, errno,
! 833: "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
! 834: full_fname(fname), name);
! 835: ret = -1;
! 836: } else /* make sure caller sets mtime */
! 837: sxp->st.st_mtime = (time_t)-1;
! 838:
! 839: if (am_generator) { /* generator items stay abbreviated */
! 840: free(ptr);
! 841: continue;
! 842: }
! 843:
! 844: memcpy(ptr + len, name, name_len);
! 845: free(rxas[i].datum);
! 846:
! 847: rxas[i].name = name = ptr + len;
! 848: rxas[i].datum = ptr;
! 849: continue;
! 850: }
! 851:
! 852: if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) {
! 853: rsyserr(FERROR_XFER, errno,
! 854: "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
! 855: full_fname(fname), name);
! 856: ret = -1;
! 857: } else /* make sure caller sets mtime */
! 858: sxp->st.st_mtime = (time_t)-1;
! 859: }
! 860:
! 861: /* Remove any extraneous names. */
! 862: for (name = namebuf; list_len > 0; name += name_len) {
! 863: name_len = strlen(name) + 1;
! 864: list_len -= name_len;
! 865:
! 866: #ifdef HAVE_LINUX_XATTRS
! 867: /* We always ignore the system namespace, and non-root
! 868: * ignores everything but the user namespace. */
! 869: if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
! 870: : HAS_PREFIX(name, SYSTEM_PREFIX))
! 871: continue;
! 872: #endif
! 873: if (am_root < 0 && name_len > RPRE_LEN
! 874: && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
! 875: continue;
! 876:
! 877: for (i = 0; i < xalp->count; i++) {
! 878: if (strcmp(name, rxas[i].name) == 0)
! 879: break;
! 880: }
! 881: if (i == xalp->count) {
! 882: if (sys_lremovexattr(fname, name) < 0) {
! 883: rsyserr(FERROR_XFER, errno,
! 884: "rsync_xal_set: lremovexattr(\"%s\",\"%s\") failed",
! 885: full_fname(fname), name);
! 886: ret = -1;
! 887: } else /* make sure caller sets mtime */
! 888: sxp->st.st_mtime = (time_t)-1;
! 889: }
! 890: }
! 891:
! 892: return ret;
! 893: }
! 894:
! 895: /* Set extended attributes on indicated filename. */
! 896: int set_xattr(const char *fname, const struct file_struct *file,
! 897: const char *fnamecmp, stat_x *sxp)
! 898: {
! 899: int ndx;
! 900: item_list *lst = rsync_xal_l.items;
! 901:
! 902: if (dry_run)
! 903: return 1; /* FIXME: --dry-run needs to compute this value */
! 904:
! 905: if (read_only || list_only) {
! 906: errno = EROFS;
! 907: return -1;
! 908: }
! 909:
! 910: #ifdef NO_SPECIAL_XATTRS
! 911: if (IS_SPECIAL(sxp->st.st_mode)) {
! 912: errno = ENOTSUP;
! 913: return -1;
! 914: }
! 915: #endif
! 916: #ifdef NO_DEVICE_XATTRS
! 917: if (IS_DEVICE(sxp->st.st_mode)) {
! 918: errno = ENOTSUP;
! 919: return -1;
! 920: }
! 921: #endif
! 922: #ifdef NO_SYMLINK_XATTRS
! 923: if (S_ISLNK(sxp->st.st_mode)) {
! 924: errno = ENOTSUP;
! 925: return -1;
! 926: }
! 927: #endif
! 928:
! 929: ndx = F_XATTR(file);
! 930: return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp);
! 931: }
! 932:
! 933: #ifdef SUPPORT_ACLS
! 934: char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)
! 935: {
! 936: const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
! 937: *len_p = 0; /* no extra data alloc needed from get_xattr_data() */
! 938: return get_xattr_data(fname, name, len_p, 1);
! 939: }
! 940:
! 941: int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len)
! 942: {
! 943: const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
! 944: if (sys_lsetxattr(fname, name, buf, buf_len) < 0) {
! 945: rsyserr(FERROR_XFER, errno,
! 946: "set_xattr_acl: lsetxattr(\"%s\",\"%s\") failed",
! 947: full_fname(fname), name);
! 948: return -1;
! 949: }
! 950: return 0;
! 951: }
! 952:
! 953: int del_def_xattr_acl(const char *fname)
! 954: {
! 955: return sys_lremovexattr(fname, XDEF_ACL_ATTR);
! 956: }
! 957: #endif
! 958:
! 959: int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
! 960: {
! 961: int mode, rdev_major, rdev_minor, uid, gid, len;
! 962: char buf[256];
! 963:
! 964: if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
! 965: return -1;
! 966:
! 967: if (xst)
! 968: *xst = *fst;
! 969: else
! 970: xst = fst;
! 971: if (fname) {
! 972: fd = -1;
! 973: len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
! 974: } else {
! 975: fname = "fd";
! 976: len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
! 977: }
! 978: if (len >= (int)sizeof buf) {
! 979: len = -1;
! 980: errno = ERANGE;
! 981: }
! 982: if (len < 0) {
! 983: if (errno == ENOTSUP || errno == ENOATTR)
! 984: return -1;
! 985: if (errno == EPERM && S_ISLNK(fst->st_mode)) {
! 986: xst->st_uid = 0;
! 987: xst->st_gid = 0;
! 988: return 0;
! 989: }
! 990: rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
! 991: XSTAT_ATTR, full_fname(fname));
! 992: return -1;
! 993: }
! 994: buf[len] = '\0';
! 995:
! 996: if (sscanf(buf, "%o %d,%d %d:%d",
! 997: &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
! 998: rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
! 999: XSTAT_ATTR, full_fname(fname), buf);
! 1000: exit_cleanup(RERR_FILEIO);
! 1001: }
! 1002:
! 1003: xst->st_mode = from_wire_mode(mode);
! 1004: xst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
! 1005: xst->st_uid = uid;
! 1006: xst->st_gid = gid;
! 1007:
! 1008: return 0;
! 1009: }
! 1010:
! 1011: int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
! 1012: {
! 1013: STRUCT_STAT fst, xst;
! 1014: dev_t rdev;
! 1015: mode_t mode, fmode;
! 1016:
! 1017: if (dry_run)
! 1018: return 0;
! 1019:
! 1020: if (read_only || list_only) {
! 1021: rsyserr(FERROR_XFER, EROFS, "failed to write xattr %s for %s",
! 1022: XSTAT_ATTR, full_fname(fname));
! 1023: return -1;
! 1024: }
! 1025:
! 1026: if (x_lstat(fname, &fst, &xst) < 0) {
! 1027: rsyserr(FERROR_XFER, errno, "failed to re-stat %s",
! 1028: full_fname(fname));
! 1029: return -1;
! 1030: }
! 1031:
! 1032: fst.st_mode &= (_S_IFMT | CHMOD_BITS);
! 1033: fmode = new_mode & (_S_IFMT | CHMOD_BITS);
! 1034:
! 1035: if (IS_DEVICE(fmode)) {
! 1036: uint32 *devp = F_RDEV_P(file);
! 1037: rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
! 1038: } else
! 1039: rdev = 0;
! 1040:
! 1041: /* Dump the special permissions and enable full owner access. */
! 1042: mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
! 1043: | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
! 1044: if (fst.st_mode != mode)
! 1045: do_chmod(fname, mode);
! 1046: if (!IS_DEVICE(fst.st_mode))
! 1047: fst.st_rdev = 0; /* just in case */
! 1048:
! 1049: if (mode == fmode && fst.st_rdev == rdev
! 1050: && fst.st_uid == F_OWNER(file) && fst.st_gid == F_GROUP(file)) {
! 1051: /* xst.st_mode will be 0 if there's no current stat xattr */
! 1052: if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
! 1053: rsyserr(FERROR_XFER, errno,
! 1054: "delete of stat xattr failed for %s",
! 1055: full_fname(fname));
! 1056: return -1;
! 1057: }
! 1058: return 0;
! 1059: }
! 1060:
! 1061: if (xst.st_mode != fmode || xst.st_rdev != rdev
! 1062: || xst.st_uid != F_OWNER(file) || xst.st_gid != F_GROUP(file)) {
! 1063: char buf[256];
! 1064: int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
! 1065: to_wire_mode(fmode),
! 1066: (int)major(rdev), (int)minor(rdev),
! 1067: F_OWNER(file), F_GROUP(file));
! 1068: if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
! 1069: if (errno == EPERM && S_ISLNK(fst.st_mode))
! 1070: return 0;
! 1071: rsyserr(FERROR_XFER, errno,
! 1072: "failed to write xattr %s for %s",
! 1073: XSTAT_ATTR, full_fname(fname));
! 1074: return -1;
! 1075: }
! 1076: }
! 1077:
! 1078: return 0;
! 1079: }
! 1080:
! 1081: int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
! 1082: {
! 1083: int ret = do_stat(fname, fst);
! 1084: if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
! 1085: xst->st_mode = 0;
! 1086: return ret;
! 1087: }
! 1088:
! 1089: int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
! 1090: {
! 1091: int ret = do_lstat(fname, fst);
! 1092: if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
! 1093: xst->st_mode = 0;
! 1094: return ret;
! 1095: }
! 1096:
! 1097: int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
! 1098: {
! 1099: int ret = do_fstat(fd, fst);
! 1100: if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst)
! 1101: xst->st_mode = 0;
! 1102: return ret;
! 1103: }
! 1104:
! 1105: #endif /* SUPPORT_XATTRS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>