Annotation of embedaddon/rsync/xattrs.c, revision 1.1.1.4

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.
1.1.1.4 ! misho       6:  * Copyright (C) 2006-2020 Wayne Davison
1.1       misho       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"
1.1.1.2   misho      24: #include "inums.h"
1.1       misho      25: #include "lib/sysxattrs.h"
                     26: 
                     27: #ifdef SUPPORT_XATTRS
                     28: 
                     29: extern int dry_run;
                     30: extern int am_root;
                     31: extern int am_sender;
                     32: extern int am_generator;
                     33: extern int read_only;
                     34: extern int list_only;
                     35: extern int preserve_xattrs;
1.1.1.4 ! misho      36: extern int preserve_hfs_compression;
1.1       misho      37: extern int preserve_links;
                     38: extern int preserve_devices;
                     39: extern int preserve_specials;
1.1.1.4 ! misho      40: extern int checksum_type;
1.1       misho      41: extern int checksum_seed;
1.1.1.4 ! misho      42: extern int flist_csum_len;
        !            43: extern int saw_xattr_filter;
1.1       misho      44: 
                     45: #define RSYNC_XAL_INITIAL 5
                     46: #define RSYNC_XAL_LIST_INITIAL 100
                     47: 
1.1.1.4 ! misho      48: #define GXD_NO_MISSING_ERROR (1<<0)
        !            49: #define GXD_OMIT_COMPRESSED (1<<1)
        !            50: #define GXD_FILE_IS_COMPRESSED (1<<2)
        !            51: 
1.1       misho      52: #define MAX_FULL_DATUM 32
                     53: 
1.1.1.4 ! misho      54: #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0)
1.1       misho      55: 
                     56: #define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len)
                     57: 
                     58: #define XSTATE_ABBREV  1
                     59: #define XSTATE_DONE    2
                     60: #define XSTATE_TODO    3
                     61: 
                     62: #define USER_PREFIX "user."
                     63: #define UPRE_LEN ((int)sizeof USER_PREFIX - 1)
                     64: #define SYSTEM_PREFIX "system."
                     65: #define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1)
                     66: 
                     67: #ifdef HAVE_LINUX_XATTRS
1.1.1.4 ! misho      68: #define MIGHT_NEED_RPRE (am_root <= 0)
1.1       misho      69: #define RSYNC_PREFIX USER_PREFIX "rsync."
                     70: #else
                     71: #define MIGHT_NEED_RPRE am_root
                     72: #define RSYNC_PREFIX "rsync."
                     73: #endif
                     74: #define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
                     75: 
                     76: #define XSTAT_SUFFIX "stat"
                     77: #define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
                     78: #define XACC_ACL_SUFFIX "aacl"
                     79: #define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
                     80: #define XDEF_ACL_SUFFIX "dacl"
                     81: #define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
1.1.1.4 ! misho      82: #define MD4_SUFFIX "md4"
        !            83: #define MD4_ATTR RSYNC_PREFIX "%" MD4_SUFFIX
        !            84: #define MD5_SUFFIX "md5"
        !            85: #define MD5_ATTR RSYNC_PREFIX "%" MD5_SUFFIX
        !            86: 
        !            87: #define APPLE_PREFIX "com.apple."
        !            88: #define APLPRE_LEN ((int)sizeof APPLE_PREFIX - 1)
        !            89: #define DECMPFS_SUFFIX "decmpfs"
        !            90: #define RESOURCEFORK_SUFFIX "ResourceFork"
        !            91: 
        !            92: #define UNREAD_DATA ((char *)1)
        !            93: 
        !            94: #if MAX_DIGEST_LEN < SIZEOF_TIME_T
        !            95: #error MAX_DIGEST_LEN is too small to hold an mtime
        !            96: #endif
1.1       misho      97: 
                     98: typedef struct {
                     99:        char *datum, *name;
                    100:        size_t datum_len, name_len;
                    101:        int num;
                    102: } rsync_xa;
                    103: 
1.1.1.4 ! misho     104: struct _rsync_xa_list;
        !           105: 
        !           106: typedef struct _rsync_xa_list_ref {
        !           107:        struct _rsync_xa_list_ref *next;
        !           108:        int ndx;
        !           109: } rsync_xa_list_ref;
        !           110: 
        !           111: typedef struct _rsync_xa_list {
        !           112:        int ndx;
        !           113:        int64 key;
        !           114:        item_list xa_items;
        !           115: } rsync_xa_list;
        !           116: 
1.1       misho     117: static size_t namebuf_len = 0;
                    118: static char *namebuf = NULL;
                    119: 
1.1.1.4 ! misho     120: static const rsync_xa_list empty_xa_list = {
        !           121:        .xa_items = EMPTY_ITEM_LIST,
        !           122: };
        !           123: static const item_list empty_xattr = EMPTY_ITEM_LIST;
1.1       misho     124: static item_list rsync_xal_l = EMPTY_ITEM_LIST;
1.1.1.4 ! misho     125: static struct hashtable *rsync_xal_h = NULL;
1.1       misho     126: 
                    127: static size_t prior_xattr_count = (size_t)-1;
                    128: 
                    129: /* ------------------------------------------------------------------------- */
                    130: 
                    131: static void rsync_xal_free(item_list *xalp)
                    132: {
                    133:        size_t i;
                    134:        rsync_xa *rxas = xalp->items;
                    135: 
                    136:        if (!xalp->malloced)
                    137:                return;
                    138: 
                    139:        for (i = 0; i < xalp->count; i++) {
                    140:                free(rxas[i].datum);
                    141:                /*free(rxas[i].name);*/
                    142:        }
                    143:        free(xalp->items);
                    144: }
                    145: 
                    146: void free_xattr(stat_x *sxp)
                    147: {
                    148:        if (!sxp->xattr)
                    149:                return;
                    150:        rsync_xal_free(sxp->xattr);
                    151:        free(sxp->xattr);
                    152:        sxp->xattr = NULL;
                    153: }
                    154: 
                    155: static int rsync_xal_compare_names(const void *x1, const void *x2)
                    156: {
                    157:        const rsync_xa *xa1 = x1;
                    158:        const rsync_xa *xa2 = x2;
                    159:        return strcmp(xa1->name, xa2->name);
                    160: }
                    161: 
                    162: static ssize_t get_xattr_names(const char *fname)
                    163: {
                    164:        ssize_t list_len;
1.1.1.2   misho     165:        int64 arg;
1.1       misho     166: 
                    167:        if (!namebuf) {
                    168:                namebuf_len = 1024;
                    169:                namebuf = new_array(char, namebuf_len);
                    170:        }
                    171: 
                    172:        while (1) {
                    173:                /* The length returned includes all the '\0' terminators. */
                    174:                list_len = sys_llistxattr(fname, namebuf, namebuf_len);
                    175:                if (list_len >= 0) {
                    176:                        if ((size_t)list_len <= namebuf_len)
                    177:                                break;
                    178:                } else if (errno == ENOTSUP)
                    179:                        return 0;
                    180:                else if (errno != ERANGE) {
1.1.1.2   misho     181:                        arg = namebuf_len;
1.1       misho     182:                  got_error:
                    183:                        rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho     184:                                "get_xattr_names: llistxattr(%s,%s) failed",
1.1.1.2   misho     185:                                full_fname(fname), big_num(arg));
1.1       misho     186:                        return -1;
                    187:                }
                    188:                list_len = sys_llistxattr(fname, NULL, 0);
                    189:                if (list_len < 0) {
                    190:                        arg = 0;
                    191:                        goto got_error;
                    192:                }
                    193:                if (namebuf_len)
                    194:                        free(namebuf);
                    195:                namebuf_len = list_len + 1024;
                    196:                namebuf = new_array(char, namebuf_len);
                    197:        }
                    198: 
                    199:        return list_len;
                    200: }
                    201: 
                    202: /* On entry, the *len_ptr parameter contains the size of the extra space we
                    203:  * should allocate when we create a buffer for the data.  On exit, it contains
                    204:  * the length of the datum. */
1.1.1.4 ! misho     205: static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr, int flags)
1.1       misho     206: {
                    207:        size_t datum_len = sys_lgetxattr(fname, name, NULL, 0);
                    208:        size_t extra_len = *len_ptr;
                    209:        char *ptr;
                    210: 
                    211:        *len_ptr = datum_len;
                    212: 
                    213:        if (datum_len == (size_t)-1) {
1.1.1.4 ! misho     214:                if (errno == ENOTSUP || flags & GXD_NO_MISSING_ERROR)
1.1       misho     215:                        return NULL;
                    216:                rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho     217:                        "get_xattr_data: lgetxattr(%s,\"%s\",0) failed",
1.1       misho     218:                        full_fname(fname), name);
                    219:                return NULL;
                    220:        }
                    221: 
1.1.1.4 ! misho     222:        if (flags & GXD_OMIT_COMPRESSED && datum_len > MAX_FULL_DATUM
        !           223:         && HAS_PREFIX(name, APPLE_PREFIX)
        !           224:         && (strcmp(name+APLPRE_LEN, DECMPFS_SUFFIX) == 0
        !           225:          || (flags & GXD_FILE_IS_COMPRESSED && strcmp(name+APLPRE_LEN, RESOURCEFORK_SUFFIX) == 0))) {
        !           226:                /* If we are omitting compress-file-related data, we don't want to
        !           227:                 * actually read this data. */
        !           228:                return UNREAD_DATA;
        !           229:        }
        !           230: 
1.1       misho     231:        if (!datum_len && !extra_len)
                    232:                extra_len = 1; /* request non-zero amount of memory */
1.1.1.4 ! misho     233:        if (SIZE_MAX - datum_len < extra_len)
1.1       misho     234:                overflow_exit("get_xattr_data");
1.1.1.4 ! misho     235:        ptr = new_array(char, datum_len + extra_len);
1.1       misho     236: 
                    237:        if (datum_len) {
                    238:                size_t len = sys_lgetxattr(fname, name, ptr, datum_len);
                    239:                if (len != datum_len) {
                    240:                        if (len == (size_t)-1) {
                    241:                                rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho     242:                                        "get_xattr_data: lgetxattr(%s,\"%s\",%ld) failed",
        !           243:                                        full_fname(fname), name, (long)datum_len);
1.1       misho     244:                        } else {
                    245:                                rprintf(FERROR_XFER,
1.1.1.4 ! misho     246:                                        "get_xattr_data: lgetxattr(%s,\"%s\",%ld) returned %ld\n",
        !           247:                                        full_fname(fname), name,
        !           248:                                        (long)datum_len, (long)len);
1.1       misho     249:                        }
                    250:                        free(ptr);
                    251:                        return NULL;
                    252:                }
                    253:        }
                    254: 
                    255:        return ptr;
                    256: }
                    257: 
1.1.1.4 ! misho     258: static void checksum_xattr_data(char *sum, const char *datum, size_t datum_len, stat_x *sxp)
        !           259: {
        !           260:        if (datum == UNREAD_DATA) {
        !           261:                /* For abbreviated compressed data, we store the file's mtime as the checksum. */
        !           262:                SIVAL(sum, 0, sxp->st.st_mtime);
        !           263: #if SIZEOF_TIME_T > 4
        !           264:                SIVAL(sum, 4, sxp->st.st_mtime >> 32);
        !           265: #if MAX_DIGEST_LEN > 8
        !           266:                memset(sum + 8, 0, MAX_DIGEST_LEN - 8);
        !           267: #endif
        !           268: #else
        !           269: #if MAX_DIGEST_LEN > 4
        !           270:                memset(sum + 4, 0, MAX_DIGEST_LEN - 4);
        !           271: #endif
        !           272: #endif
        !           273:        } else {
        !           274:                sum_init(-1, checksum_seed);
        !           275:                sum_update(datum, datum_len);
        !           276:                sum_end(sum);
        !           277:        }
        !           278: }
        !           279: 
        !           280: $$$ERROR$$$ the old patch needs reworking since rsync_xal_get() has totally changed!
        !           281: 
        !           282: static int rsync_xal_get(const char *fname, stat_x *sxp)
1.1       misho     283: {
                    284:        ssize_t list_len, name_len;
                    285:        size_t datum_len, name_offset;
                    286:        char *name, *ptr;
                    287: #ifdef HAVE_LINUX_XATTRS
1.1.1.2   misho     288:        int user_only = am_sender ? 0 : !am_root;
1.1       misho     289: #endif
                    290:        rsync_xa *rxa;
1.1.1.4 ! misho     291:        int count, flags;
        !           292:        item_list *xalp = sxp->xattr;
1.1       misho     293: 
                    294:        /* This puts the name list into the "namebuf" buffer. */
                    295:        if ((list_len = get_xattr_names(fname)) < 0)
                    296:                return -1;
                    297: 
                    298:        for (name = namebuf; list_len > 0; name += name_len) {
                    299:                name_len = strlen(name) + 1;
                    300:                list_len -= name_len;
                    301: 
1.1.1.4 ! misho     302:                if (saw_xattr_filter) {
        !           303:                        if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
        !           304:                                continue;
        !           305:                }
1.1       misho     306: #ifdef HAVE_LINUX_XATTRS
1.1.1.4 ! misho     307:                /* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
        !           308:                else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
1.1       misho     309:                        continue;
                    310: #endif
                    311: 
                    312:                /* No rsync.%FOO attributes are copied w/o 2 -X options. */
1.1.1.4 ! misho     313:                if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
1.1       misho     314:                        if ((am_sender && preserve_xattrs < 2)
                    315:                         || (am_root < 0
                    316:                          && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
                    317:                           || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
1.1.1.4 ! misho     318:                           || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0
        !           319:                           || strcmp(name+RPRE_LEN+1, MD4_SUFFIX) == 0
        !           320:                           || strcmp(name+RPRE_LEN+1, MD5_SUFFIX) == 0)))
1.1       misho     321:                                continue;
                    322:                }
                    323: 
                    324:                datum_len = name_len; /* Pass extra size to get_xattr_data() */
1.1.1.4 ! misho     325:                flags = GXD_OMIT_COMPRESSED;
        !           326:                if (preserve_hfs_compression && sxp->st.st_flags & UF_COMPRESSED)
        !           327:                        flags |= GXD_FILE_IS_COMPRESSED;
        !           328:                if (!(ptr = get_xattr_data(fname, name, &datum_len, flags)))
1.1       misho     329:                        return -1;
                    330: 
                    331:                if (datum_len > MAX_FULL_DATUM) {
                    332:                        /* For large datums, we store a flag and a checksum. */
1.1.1.4 ! misho     333:                        char *datum = ptr;
1.1       misho     334:                        name_offset = 1 + MAX_DIGEST_LEN;
1.1.1.4 ! misho     335:                        sum_init(-1, checksum_seed);
1.1       misho     336:                        sum_update(ptr, datum_len);
                    337:                        free(ptr);
                    338: 
1.1.1.4 ! misho     339:                        ptr = new_array(char, name_offset + name_len);
1.1       misho     340:                        *ptr = XSTATE_ABBREV;
1.1.1.4 ! misho     341:                        checksum_xattr_data(ptr+1, datum, datum_len, sxp);
        !           342:                        if (datum != UNREAD_DATA)
        !           343:                                free(datum);
1.1       misho     344:                } else
                    345:                        name_offset = datum_len;
                    346: 
                    347:                rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
                    348:                rxa->name = ptr + name_offset;
                    349:                memcpy(rxa->name, name, name_len);
                    350:                rxa->datum = ptr;
                    351:                rxa->name_len = name_len;
                    352:                rxa->datum_len = datum_len;
                    353:        }
                    354:        count = xalp->count;
                    355:        rxa = xalp->items;
                    356:        if (count > 1)
                    357:                qsort(rxa, count, sizeof (rsync_xa), rsync_xal_compare_names);
                    358:        for (rxa += count-1; count; count--, rxa--)
                    359:                rxa->num = count;
                    360:        return 0;
                    361: }
                    362: 
                    363: /* Read the xattr(s) for this filename. */
                    364: int get_xattr(const char *fname, stat_x *sxp)
                    365: {
                    366:        sxp->xattr = new(item_list);
                    367:        *sxp->xattr = empty_xattr;
                    368: 
                    369:        if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
                    370:                /* Everyone supports this. */
                    371:        } else if (S_ISLNK(sxp->st.st_mode)) {
                    372: #ifndef NO_SYMLINK_XATTRS
                    373:                if (!preserve_links)
                    374: #endif
                    375:                        return 0;
                    376:        } else if (IS_SPECIAL(sxp->st.st_mode)) {
                    377: #ifndef NO_SPECIAL_XATTRS
                    378:                if (!preserve_specials)
                    379: #endif
                    380:                        return 0;
                    381:        } else if (IS_DEVICE(sxp->st.st_mode)) {
                    382: #ifndef NO_DEVICE_XATTRS
                    383:                if (!preserve_devices)
                    384: #endif
                    385:                        return 0;
1.1.1.3   misho     386:        } else if (IS_MISSING_FILE(sxp->st))
                    387:                return 0;
1.1       misho     388: 
1.1.1.4 ! misho     389:        if (rsync_xal_get(fname, sxp) < 0) {
1.1       misho     390:                free_xattr(sxp);
                    391:                return -1;
                    392:        }
                    393:        return 0;
                    394: }
                    395: 
                    396: int copy_xattrs(const char *source, const char *dest)
                    397: {
                    398:        ssize_t list_len, name_len;
                    399:        size_t datum_len;
                    400:        char *name, *ptr;
                    401: #ifdef HAVE_LINUX_XATTRS
1.1.1.2   misho     402:        int user_only = am_sender ? 0 : am_root <= 0;
1.1       misho     403: #endif
                    404: 
                    405:        /* This puts the name list into the "namebuf" buffer. */
                    406:        if ((list_len = get_xattr_names(source)) < 0)
                    407:                return -1;
                    408: 
                    409:        for (name = namebuf; list_len > 0; name += name_len) {
                    410:                name_len = strlen(name) + 1;
                    411:                list_len -= name_len;
                    412: 
1.1.1.4 ! misho     413:                if (saw_xattr_filter) {
        !           414:                        if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
        !           415:                                continue;
        !           416:                }
1.1       misho     417: #ifdef HAVE_LINUX_XATTRS
1.1.1.4 ! misho     418:                /* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
        !           419:                else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
1.1       misho     420:                        continue;
                    421: #endif
                    422: 
                    423:                datum_len = 0;
                    424:                if (!(ptr = get_xattr_data(source, name, &datum_len, 0)))
                    425:                        return -1;
1.1.1.4 ! misho     426:                if (ptr == UNREAD_DATA)
        !           427:                        continue; /* XXX Is this right? */
1.1       misho     428:                if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) {
                    429:                        int save_errno = errno ? errno : EINVAL;
                    430:                        rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho     431:                                "copy_xattrs: lsetxattr(%s,\"%s\") failed",
1.1       misho     432:                                full_fname(dest), name);
                    433:                        errno = save_errno;
                    434:                        return -1;
                    435:                }
                    436:                free(ptr);
                    437:        }
                    438: 
                    439:        return 0;
                    440: }
                    441: 
1.1.1.4 ! misho     442: static int64 xattr_lookup_hash(const item_list *xalp)
1.1       misho     443: {
1.1.1.4 ! misho     444:        const rsync_xa *rxas = xalp->items;
        !           445:        size_t i;
        !           446:        int64 key = hashlittle(&xalp->count, sizeof xalp->count);
1.1       misho     447: 
1.1.1.4 ! misho     448:        for (i = 0; i < xalp->count; i++) {
        !           449:                key += hashlittle(rxas[i].name, rxas[i].name_len);
        !           450:                if (rxas[i].datum_len > MAX_FULL_DATUM)
        !           451:                        key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN);
        !           452:                else
        !           453:                        key += hashlittle(rxas[i].datum, rxas[i].datum_len);
        !           454:        }
        !           455: 
        !           456:        if (key == 0) {
        !           457:                /* This is very unlikely, but we should never
        !           458:                 * return 0 as hashtable_find() doesn't like it. */
        !           459:                return 1;
        !           460:        }
        !           461: 
        !           462:        return key;
        !           463: }
        !           464: 
        !           465: static int find_matching_xattr(const item_list *xalp)
        !           466: {
        !           467:        const struct ht_int64_node *node;
        !           468:        const rsync_xa_list_ref *ref;
        !           469:        int64 key;
        !           470: 
        !           471:        if (rsync_xal_h == NULL)
        !           472:                return -1;
        !           473: 
        !           474:        key = xattr_lookup_hash(xalp);
        !           475: 
        !           476:        node = hashtable_find(rsync_xal_h, key, NULL);
        !           477:        if (node == NULL)
        !           478:                return -1;
        !           479: 
        !           480:        if (node->data == NULL)
        !           481:                return -1;
        !           482: 
        !           483:        for (ref = node->data; ref != NULL; ref = ref->next) {
        !           484:                const rsync_xa_list *ptr = rsync_xal_l.items;
        !           485:                const rsync_xa *rxas1;
        !           486:                const rsync_xa *rxas2 = xalp->items;
        !           487:                size_t j;
        !           488: 
        !           489:                ptr += ref->ndx;
        !           490:                rxas1 = ptr->xa_items.items;
1.1       misho     491: 
                    492:                /* Wrong number of elements? */
1.1.1.4 ! misho     493:                if (ptr->xa_items.count != xalp->count)
1.1       misho     494:                        continue;
                    495:                /* any elements different? */
                    496:                for (j = 0; j < xalp->count; j++) {
                    497:                        if (rxas1[j].name_len != rxas2[j].name_len
                    498:                         || rxas1[j].datum_len != rxas2[j].datum_len
                    499:                         || strcmp(rxas1[j].name, rxas2[j].name))
                    500:                                break;
                    501:                        if (rxas1[j].datum_len > MAX_FULL_DATUM) {
                    502:                                if (memcmp(rxas1[j].datum + 1,
                    503:                                           rxas2[j].datum + 1,
                    504:                                           MAX_DIGEST_LEN) != 0)
                    505:                                        break;
                    506:                        } else {
                    507:                                if (memcmp(rxas1[j].datum, rxas2[j].datum,
                    508:                                           rxas2[j].datum_len))
                    509:                                        break;
                    510:                        }
                    511:                }
                    512:                /* no differences found.  This is The One! */
                    513:                if (j == xalp->count)
1.1.1.4 ! misho     514:                        return ref->ndx;
1.1       misho     515:        }
                    516: 
                    517:        return -1;
1.1.1.4 ! misho     518: #endif
1.1       misho     519: }
                    520: 
                    521: /* Store *xalp on the end of rsync_xal_l */
1.1.1.4 ! misho     522: static int rsync_xal_store(item_list *xalp)
1.1       misho     523: {
1.1.1.4 ! misho     524:        struct ht_int64_node *node;
        !           525:        int ndx = rsync_xal_l.count; /* pre-incremented count */
        !           526:        rsync_xa_list *new_list = EXPAND_ITEM_LIST(&rsync_xal_l, rsync_xa_list, RSYNC_XAL_LIST_INITIAL);
        !           527:        rsync_xa_list_ref *new_ref;
1.1       misho     528:        /* Since the following call starts a new list, we know it will hold the
                    529:         * entire initial-count, not just enough space for one new item. */
1.1.1.4 ! misho     530:        *new_list = empty_xa_list;
        !           531:        (void)EXPAND_ITEM_LIST(&new_list->xa_items, rsync_xa, xalp->count);
        !           532:        memcpy(new_list->xa_items.items, xalp->items, xalp->count * sizeof (rsync_xa));
        !           533:        new_list->xa_items.count = xalp->count;
1.1       misho     534:        xalp->count = 0;
1.1.1.4 ! misho     535: 
        !           536:        new_list->ndx = ndx;
        !           537:        new_list->key = xattr_lookup_hash(&new_list->xa_items);
        !           538: 
        !           539:        if (rsync_xal_h == NULL)
        !           540:                rsync_xal_h = hashtable_create(512, HT_KEY64);
        !           541:        if (rsync_xal_h == NULL)
        !           542:                out_of_memory("rsync_xal_h hashtable_create()");
        !           543: 
        !           544:        new_ref = new0(rsync_xa_list_ref);
        !           545:        new_ref->ndx = ndx;
        !           546: 
        !           547:        node = hashtable_find(rsync_xal_h, new_list->key, new_ref);
        !           548:        if (node->data != (void*)new_ref) {
        !           549:                rsync_xa_list_ref *ref = node->data;
        !           550: 
        !           551:                while (ref != NULL) {
        !           552:                        if (ref->next != NULL) {
        !           553:                                ref = ref->next;
        !           554:                                continue;
        !           555:                        }
        !           556: 
        !           557:                        ref->next = new_ref;
        !           558:                        break;
        !           559:                }
        !           560:        }
        !           561: 
        !           562:        return ndx;
1.1       misho     563: }
                    564: 
                    565: /* Send the make_xattr()-generated xattr list for this flist entry. */
                    566: int send_xattr(int f, stat_x *sxp)
                    567: {
                    568:        int ndx = find_matching_xattr(sxp->xattr);
                    569: 
                    570:        /* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
                    571:        write_varint(f, ndx + 1);
                    572: 
                    573:        if (ndx < 0) {
                    574:                rsync_xa *rxa;
                    575:                int count = sxp->xattr->count;
                    576:                write_varint(f, count);
                    577:                for (rxa = sxp->xattr->items; count--; rxa++) {
                    578:                        size_t name_len = rxa->name_len;
                    579:                        const char *name = rxa->name;
                    580:                        /* Strip the rsync prefix from disguised namespaces. */
                    581:                        if (name_len > RPRE_LEN
                    582: #ifdef HAVE_LINUX_XATTRS
                    583:                         && am_root < 0
                    584: #endif
                    585:                         && name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
                    586:                                name += RPRE_LEN;
                    587:                                name_len -= RPRE_LEN;
                    588:                        }
                    589: #ifndef HAVE_LINUX_XATTRS
                    590:                        else {
                    591:                                /* Put everything else in the user namespace. */
                    592:                                name_len += UPRE_LEN;
                    593:                        }
                    594: #endif
                    595:                        write_varint(f, name_len);
                    596:                        write_varint(f, rxa->datum_len);
                    597: #ifndef HAVE_LINUX_XATTRS
                    598:                        if (name_len > rxa->name_len) {
                    599:                                write_buf(f, USER_PREFIX, UPRE_LEN);
                    600:                                name_len -= UPRE_LEN;
                    601:                        }
                    602: #endif
                    603:                        write_buf(f, name, name_len);
                    604:                        if (rxa->datum_len > MAX_FULL_DATUM)
                    605:                                write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
                    606:                        else
1.1.1.3   misho     607:                                write_bigbuf(f, rxa->datum, rxa->datum_len);
1.1       misho     608:                }
1.1.1.4 ! misho     609:                ndx = rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
1.1       misho     610:        }
                    611: 
                    612:        return ndx;
                    613: }
                    614: 
                    615: /* Return a flag indicating if we need to change a file's xattrs.  If
                    616:  * "find_all" is specified, also mark any abbreviated xattrs that we
                    617:  * need so that send_xattr_request() can tell the sender about them. */
                    618: int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
                    619: {
1.1.1.4 ! misho     620:        const rsync_xa_list *glst = rsync_xal_l.items;
        !           621:        const item_list *lst;
1.1       misho     622:        rsync_xa *snd_rxa, *rec_rxa;
                    623:        int snd_cnt, rec_cnt;
                    624:        int cmp, same, xattrs_equal = 1;
                    625: 
                    626:        if (sxp && XATTR_READY(*sxp)) {
                    627:                rec_rxa = sxp->xattr->items;
                    628:                rec_cnt = sxp->xattr->count;
                    629:        } else {
                    630:                rec_rxa = NULL;
                    631:                rec_cnt = 0;
                    632:        }
                    633: 
1.1.1.4 ! misho     634:        if (F_XATTR(file) >= 0) {
        !           635:                glst += F_XATTR(file);
        !           636:                lst = &glst->xa_items;
        !           637:        } else
1.1       misho     638:                lst = &empty_xattr;
                    639: 
                    640:        snd_rxa = lst->items;
                    641:        snd_cnt = lst->count;
                    642: 
                    643:        /* If the count of the sender's xattrs is different from our
                    644:         * (receiver's) xattrs, the lists are not the same. */
                    645:        if (snd_cnt != rec_cnt) {
                    646:                if (!find_all)
                    647:                        return 1;
                    648:                xattrs_equal = 0;
                    649:        }
                    650: 
                    651:        while (snd_cnt) {
                    652:                cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
                    653:                if (cmp > 0)
                    654:                        same = 0;
                    655:                else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
                    656:                        same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
                    657:                            && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
                    658:                                      MAX_DIGEST_LEN) == 0;
                    659:                        /* Flag unrequested items that we need. */
                    660:                        if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
                    661:                                snd_rxa->datum[0] = XSTATE_TODO;
                    662:                } else {
                    663:                        same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
                    664:                            && memcmp(snd_rxa->datum, rec_rxa->datum,
                    665:                                      snd_rxa->datum_len) == 0;
                    666:                }
                    667:                if (!same) {
                    668:                        if (!find_all)
                    669:                                return 1;
                    670:                        xattrs_equal = 0;
                    671:                }
                    672: 
                    673:                if (cmp <= 0) {
                    674:                        snd_rxa++;
                    675:                        snd_cnt--;
                    676:                }
                    677:                if (cmp >= 0) {
                    678:                        rec_rxa++;
                    679:                        rec_cnt--;
                    680:                }
                    681:        }
                    682: 
                    683:        if (rec_cnt)
                    684:                xattrs_equal = 0;
                    685: 
                    686:        return !xattrs_equal;
                    687: }
                    688: 
                    689: /* When called by the generator (with a NULL fname), this tells the sender
                    690:  * all the abbreviated xattr values we need.  When called by the sender
                    691:  * (with a non-NULL fname), we send all the extra xattr data it needs.
                    692:  * The generator may also call with f_out < 0 to just change all the
                    693:  * XSTATE_ABBREV states into XSTATE_DONE. */
                    694: void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
                    695: {
1.1.1.4 ! misho     696:        const rsync_xa_list *glst = rsync_xal_l.items;
        !           697:        const item_list *lst;
1.1       misho     698:        int cnt, prior_req = 0;
                    699:        rsync_xa *rxa;
                    700: 
1.1.1.4 ! misho     701:        glst += F_XATTR(file);
        !           702:        lst = &glst->xa_items;
        !           703: 
1.1       misho     704:        for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) {
                    705:                if (rxa->datum_len <= MAX_FULL_DATUM)
                    706:                        continue;
                    707:                switch (rxa->datum[0]) {
                    708:                case XSTATE_ABBREV:
                    709:                        /* Items left abbreviated matched the sender's checksum, so
                    710:                         * the receiver will cache the local data for future use. */
                    711:                        if (am_generator)
                    712:                                rxa->datum[0] = XSTATE_DONE;
                    713:                        continue;
                    714:                case XSTATE_TODO:
                    715:                        assert(f_out >= 0);
                    716:                        break;
                    717:                default:
                    718:                        continue;
                    719:                }
                    720: 
                    721:                /* Flag that we handled this abbreviated item. */
                    722:                rxa->datum[0] = XSTATE_DONE;
                    723: 
                    724:                write_varint(f_out, rxa->num - prior_req);
                    725:                prior_req = rxa->num;
                    726: 
                    727:                if (fname) {
                    728:                        size_t len = 0;
                    729:                        char *ptr;
                    730: 
                    731:                        /* Re-read the long datum. */
                    732:                        if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) {
1.1.1.4 ! misho     733:                                if (errno != ENOTSUP && errno != ENOATTR)
        !           734:                                        rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname);
1.1       misho     735:                                write_varint(f_out, 0);
                    736:                                continue;
                    737:                        }
                    738: 
1.1.1.4 ! misho     739:                        assert(ptr != UNREAD_DATA);
1.1       misho     740:                        write_varint(f_out, len); /* length might have changed! */
1.1.1.3   misho     741:                        write_bigbuf(f_out, ptr, len);
1.1       misho     742:                        free(ptr);
                    743:                }
                    744:        }
                    745: 
                    746:        if (f_out >= 0)
                    747:                write_byte(f_out, 0); /* end the list */
                    748: }
                    749: 
                    750: /* When called by the sender, read the request from the generator and mark
                    751:  * any needed xattrs with a flag that lets us know they need to be sent to
                    752:  * the receiver.  When called by the receiver, reads the sent data and
                    753:  * stores it in place of its checksum. */
                    754: int recv_xattr_request(struct file_struct *file, int f_in)
                    755: {
1.1.1.4 ! misho     756:        const rsync_xa_list *glst = rsync_xal_l.items;
        !           757:        const item_list *lst;
1.1       misho     758:        char *old_datum, *name;
                    759:        rsync_xa *rxa;
                    760:        int rel_pos, cnt, num, got_xattr_data = 0;
                    761: 
                    762:        if (F_XATTR(file) < 0) {
                    763:                rprintf(FERROR, "recv_xattr_request: internal data error!\n");
                    764:                exit_cleanup(RERR_PROTOCOL);
                    765:        }
1.1.1.4 ! misho     766:        glst += F_XATTR(file);
        !           767:        lst = &glst->xa_items;
1.1       misho     768: 
                    769:        cnt = lst->count;
                    770:        rxa = lst->items;
                    771:        num = 0;
                    772:        while ((rel_pos = read_varint(f_in)) != 0) {
                    773:                num += rel_pos;
1.1.1.4 ! misho     774:                if (am_sender) {
        !           775:                        /* The sender-related num values are only in order on the sender.
        !           776:                         * We use that order here to scan forward or backward as needed. */
        !           777:                        if (rel_pos < 0) {
        !           778:                                while (cnt < (int)lst->count && rxa->num > num) {
        !           779:                                        rxa--;
        !           780:                                        cnt++;
        !           781:                                }
        !           782:                        } else {
        !           783:                                while (cnt > 1 && rxa->num < num) {
        !           784:                                        rxa++;
        !           785:                                        cnt--;
        !           786:                                }
        !           787:                        }
        !           788:                } else {
        !           789:                        int j;
        !           790:                        /* The receiving side has no known num order, so we just scan
        !           791:                         * forward (w/wrap) and hope that the next value is near by. */
        !           792:                        for (j = lst->count; j > 1 && rxa->num != num; j--) {
        !           793:                                if (--cnt)
        !           794:                                        rxa++;
        !           795:                                else {
        !           796:                                        cnt = lst->count;
        !           797:                                        rxa = lst->items;
        !           798:                                }
        !           799:                        }
1.1       misho     800:                }
                    801:                if (!cnt || rxa->num != num) {
                    802:                        rprintf(FERROR, "[%s] could not find xattr #%d for %s\n",
                    803:                                who_am_i(), num, f_name(file, NULL));
                    804:                        exit_cleanup(RERR_PROTOCOL);
                    805:                }
                    806:                if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) {
                    807:                        rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n",
                    808:                                who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len);
                    809:                        exit_cleanup(RERR_PROTOCOL);
                    810:                }
                    811: 
                    812:                if (am_sender) {
                    813:                        rxa->datum[0] = XSTATE_TODO;
                    814:                        continue;
                    815:                }
                    816: 
                    817:                old_datum = rxa->datum;
                    818:                rxa->datum_len = read_varint(f_in);
                    819: 
1.1.1.4 ! misho     820:                if (SIZE_MAX - rxa->name_len < rxa->datum_len)
1.1       misho     821:                        overflow_exit("recv_xattr_request");
                    822:                rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
                    823:                name = rxa->datum + rxa->datum_len;
                    824:                memcpy(name, rxa->name, rxa->name_len);
                    825:                rxa->name = name;
                    826:                free(old_datum);
                    827:                read_buf(f_in, rxa->datum, rxa->datum_len);
                    828:                got_xattr_data = 1;
                    829:        }
                    830: 
                    831:        return got_xattr_data;
                    832: }
                    833: 
                    834: /* ------------------------------------------------------------------------- */
                    835: 
                    836: /* receive and build the rsync_xattr_lists */
                    837: void receive_xattr(int f, struct file_struct *file)
                    838: {
                    839:        static item_list temp_xattr = EMPTY_ITEM_LIST;
                    840:        int count, num;
                    841: #ifdef HAVE_LINUX_XATTRS
                    842:        int need_sort = 0;
                    843: #else
                    844:        int need_sort = 1;
                    845: #endif
                    846:        int ndx = read_varint(f);
                    847: 
                    848:        if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
                    849:                rprintf(FERROR, "receive_xattr: xa index %d out of"
                    850:                        " range for %s\n", ndx, f_name(file, NULL));
1.1.1.2   misho     851:                exit_cleanup(RERR_STREAMIO);
1.1       misho     852:        }
                    853: 
                    854:        if (ndx != 0) {
                    855:                F_XATTR(file) = ndx - 1;
                    856:                return;
                    857:        }
                    858: 
                    859:        if ((count = read_varint(f)) != 0) {
                    860:                (void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
                    861:                temp_xattr.count = 0;
                    862:        }
                    863: 
                    864:        for (num = 1; num <= count; num++) {
                    865:                char *ptr, *name;
                    866:                rsync_xa *rxa;
                    867:                size_t name_len = read_varint(f);
                    868:                size_t datum_len = read_varint(f);
                    869:                size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
                    870:                size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
1.1.1.4 ! misho     871:                if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len)
1.1       misho     872:                        overflow_exit("receive_xattr");
                    873:                ptr = new_array(char, dget_len + extra_len + name_len);
                    874:                name = ptr + dget_len + extra_len;
                    875:                read_buf(f, name, name_len);
1.1.1.4 ! misho     876:                if (name_len < 1 || name[name_len-1] != '\0') {
        !           877:                        rprintf(FERROR, "Invalid xattr name received (missing trailing \\0).\n");
        !           878:                        exit_cleanup(RERR_FILEIO);
        !           879:                }
1.1       misho     880:                if (dget_len == datum_len)
                    881:                        read_buf(f, ptr, dget_len);
                    882:                else {
                    883:                        *ptr = XSTATE_ABBREV;
                    884:                        read_buf(f, ptr + 1, MAX_DIGEST_LEN);
                    885:                }
1.1.1.4 ! misho     886: 
        !           887:                if (saw_xattr_filter) {
        !           888:                        if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) {
        !           889:                                free(ptr);
        !           890:                                continue;
        !           891:                        }
        !           892:                }
1.1       misho     893: #ifdef HAVE_LINUX_XATTRS
                    894:                /* Non-root can only save the user namespace. */
                    895:                if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
1.1.1.4 ! misho     896:                        if (!am_root && !saw_xattr_filter) {
1.1       misho     897:                                free(ptr);
                    898:                                continue;
                    899:                        }
                    900:                        name -= RPRE_LEN;
                    901:                        name_len += RPRE_LEN;
                    902:                        memcpy(name, RSYNC_PREFIX, RPRE_LEN);
                    903:                        need_sort = 1;
                    904:                }
                    905: #else
                    906:                /* This OS only has a user namespace, so we either
                    907:                 * strip the user prefix, or we put a non-user
                    908:                 * namespace inside our rsync hierarchy. */
                    909:                if (HAS_PREFIX(name, USER_PREFIX)) {
                    910:                        name += UPRE_LEN;
                    911:                        name_len -= UPRE_LEN;
                    912:                } else if (am_root) {
                    913:                        name -= RPRE_LEN;
                    914:                        name_len += RPRE_LEN;
                    915:                        memcpy(name, RSYNC_PREFIX, RPRE_LEN);
                    916:                } else {
                    917:                        free(ptr);
                    918:                        continue;
                    919:                }
                    920: #endif
                    921:                /* No rsync.%FOO attributes are copied w/o 2 -X options. */
                    922:                if (preserve_xattrs < 2 && name_len > RPRE_LEN
                    923:                 && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
                    924:                        free(ptr);
                    925:                        continue;
                    926:                }
1.1.1.4 ! misho     927: 
1.1       misho     928:                rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1);
                    929:                rxa->name = name;
                    930:                rxa->datum = ptr;
                    931:                rxa->name_len = name_len;
                    932:                rxa->datum_len = datum_len;
                    933:                rxa->num = num;
                    934:        }
                    935: 
                    936:        if (need_sort && count > 1)
                    937:                qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
                    938: 
1.1.1.4 ! misho     939:        ndx = rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */
1.1       misho     940: 
                    941:        F_XATTR(file) = ndx;
                    942: }
                    943: 
                    944: /* Turn the xattr data in stat_x into cached xattr data, setting the index
                    945:  * values in the file struct. */
                    946: void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
                    947: {
                    948:        int ndx;
                    949: 
                    950:        if (!sxp->xattr)
                    951:                return;
                    952: 
                    953:        if (prior_xattr_count == (size_t)-1)
                    954:                prior_xattr_count = rsync_xal_l.count;
                    955:        ndx = find_matching_xattr(sxp->xattr);
                    956:        if (ndx < 0)
                    957:                rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
                    958: 
                    959:        F_XATTR(file) = ndx;
                    960: }
                    961: 
                    962: void uncache_tmp_xattrs(void)
                    963: {
                    964:        if (prior_xattr_count != (size_t)-1) {
1.1.1.4 ! misho     965:                rsync_xa_list *xa_list_item = rsync_xal_l.items;
        !           966:                rsync_xa_list *xa_list_start = xa_list_item + prior_xattr_count;
        !           967:                xa_list_item += rsync_xal_l.count;
1.1       misho     968:                rsync_xal_l.count = prior_xattr_count;
1.1.1.4 ! misho     969:                while (xa_list_item-- > xa_list_start) {
        !           970:                        struct ht_int64_node *node;
        !           971:                        rsync_xa_list_ref *ref;
        !           972: 
        !           973:                        rsync_xal_free(&xa_list_item->xa_items);
        !           974: 
        !           975:                        if (rsync_xal_h == NULL)
        !           976:                                continue;
        !           977: 
        !           978:                        node = hashtable_find(rsync_xal_h, xa_list_item->key, NULL);
        !           979:                        if (node == NULL)
        !           980:                                continue;
        !           981: 
        !           982:                        if (node->data == NULL)
        !           983:                                continue;
        !           984: 
        !           985:                        ref = node->data;
        !           986:                        if (xa_list_item->ndx == ref->ndx) {
        !           987:                                /* xa_list_item is the first in the list. */
        !           988:                                node->data = ref->next;
        !           989:                                free(ref);
        !           990:                                continue;
        !           991:                        }
        !           992: 
        !           993:                        while (1) {
        !           994:                                rsync_xa_list_ref *next = ref->next;
        !           995:                                if (next == NULL)
        !           996:                                        break;
        !           997:                                if (xa_list_item->ndx == next->ndx) {
        !           998:                                        ref->next = next->next;
        !           999:                                        free(next);
        !          1000:                                        break;
        !          1001:                                }
        !          1002:                                ref = next;
        !          1003:                        }
        !          1004:                }
1.1       misho    1005:                prior_xattr_count = (size_t)-1;
                   1006:        }
                   1007: }
                   1008: 
                   1009: static int rsync_xal_set(const char *fname, item_list *xalp,
                   1010:                         const char *fnamecmp, stat_x *sxp)
                   1011: {
                   1012:        rsync_xa *rxas = xalp->items;
                   1013:        ssize_t list_len;
                   1014:        size_t i, len;
                   1015:        char *name, *ptr, sum[MAX_DIGEST_LEN];
                   1016: #ifdef HAVE_LINUX_XATTRS
                   1017:        int user_only = am_root <= 0;
                   1018: #endif
                   1019:        size_t name_len;
1.1.1.4 ! misho    1020:        int flags, ret = 0;
1.1       misho    1021: 
                   1022:        /* This puts the current name list into the "namebuf" buffer. */
                   1023:        if ((list_len = get_xattr_names(fname)) < 0)
                   1024:                return -1;
                   1025: 
                   1026:        for (i = 0; i < xalp->count; i++) {
                   1027:                name = rxas[i].name;
                   1028: 
                   1029:                if (XATTR_ABBREV(rxas[i])) {
1.1.1.4 ! misho    1030:                        int sum_len;
1.1       misho    1031:                        /* See if the fnamecmp version is identical. */
                   1032:                        len = name_len = rxas[i].name_len;
1.1.1.4 ! misho    1033:                        flags = GXD_OMIT_COMPRESSED | GXD_NO_MISSING_ERROR;
        !          1034:                        if (preserve_hfs_compression && sxp->st.st_flags & UF_COMPRESSED)
        !          1035:                                flags |= GXD_FILE_IS_COMPRESSED;
        !          1036:                        if ((ptr = get_xattr_data(fnamecmp, name, &len, flags)) == NULL) {
1.1       misho    1037:                          still_abbrev:
                   1038:                                if (am_generator)
                   1039:                                        continue;
                   1040:                                rprintf(FERROR, "Missing abbreviated xattr value, %s, for %s\n",
                   1041:                                        rxas[i].name, full_fname(fname));
                   1042:                                ret = -1;
                   1043:                                continue;
                   1044:                        }
1.1.1.4 ! misho    1045:                        if (ptr == UNREAD_DATA)
        !          1046:                                continue; /* XXX Is this right? */
1.1       misho    1047:                        if (len != rxas[i].datum_len) {
                   1048:                                free(ptr);
                   1049:                                goto still_abbrev;
                   1050:                        }
                   1051: 
1.1.1.4 ! misho    1052:                        sum_init(-1, checksum_seed);
1.1       misho    1053:                        sum_update(ptr, len);
1.1.1.4 ! misho    1054:                        sum_len = sum_end(sum);
        !          1055:                        if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) {
1.1       misho    1056:                                free(ptr);
                   1057:                                goto still_abbrev;
                   1058:                        }
                   1059: 
                   1060:                        if (fname == fnamecmp)
                   1061:                                ; /* Value is already set when identical */
                   1062:                        else if (sys_lsetxattr(fname, name, ptr, len) < 0) {
                   1063:                                rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho    1064:                                        "rsync_xal_set: lsetxattr(%s,\"%s\") failed",
1.1       misho    1065:                                        full_fname(fname), name);
                   1066:                                ret = -1;
                   1067:                        } else /* make sure caller sets mtime */
                   1068:                                sxp->st.st_mtime = (time_t)-1;
                   1069: 
                   1070:                        if (am_generator) { /* generator items stay abbreviated */
                   1071:                                free(ptr);
                   1072:                                continue;
                   1073:                        }
                   1074: 
                   1075:                        memcpy(ptr + len, name, name_len);
                   1076:                        free(rxas[i].datum);
                   1077: 
                   1078:                        rxas[i].name = name = ptr + len;
                   1079:                        rxas[i].datum = ptr;
                   1080:                        continue;
                   1081:                }
                   1082: 
                   1083:                if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) {
                   1084:                        rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho    1085:                                "rsync_xal_set: lsetxattr(%s,\"%s\") failed",
1.1       misho    1086:                                full_fname(fname), name);
                   1087:                        ret = -1;
                   1088:                } else /* make sure caller sets mtime */
                   1089:                        sxp->st.st_mtime = (time_t)-1;
                   1090:        }
                   1091: 
                   1092:        /* Remove any extraneous names. */
                   1093:        for (name = namebuf; list_len > 0; name += name_len) {
                   1094:                name_len = strlen(name) + 1;
                   1095:                list_len -= name_len;
                   1096: 
1.1.1.4 ! misho    1097:                if (saw_xattr_filter) {
        !          1098:                        if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
        !          1099:                                continue;
        !          1100:                }
1.1       misho    1101: #ifdef HAVE_LINUX_XATTRS
1.1.1.4 ! misho    1102:                /* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
        !          1103:                else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
1.1       misho    1104:                        continue;
                   1105: #endif
1.1.1.4 ! misho    1106:                if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
1.1       misho    1107:                        continue;
                   1108: 
                   1109:                for (i = 0; i < xalp->count; i++) {
                   1110:                        if (strcmp(name, rxas[i].name) == 0)
                   1111:                                break;
                   1112:                }
                   1113:                if (i == xalp->count) {
                   1114:                        if (sys_lremovexattr(fname, name) < 0) {
                   1115:                                rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho    1116:                                        "rsync_xal_set: lremovexattr(%s,\"%s\") failed",
1.1       misho    1117:                                        full_fname(fname), name);
                   1118:                                ret = -1;
                   1119:                        } else /* make sure caller sets mtime */
                   1120:                                sxp->st.st_mtime = (time_t)-1;
                   1121:                }
                   1122:        }
                   1123: 
1.1.1.4 ! misho    1124: #ifdef HAVE_OSX_XATTRS
        !          1125:        rsync_xal_free(xalp); /* Free this because we aren't using find_matching_xattr(). */
        !          1126: #endif
        !          1127: 
1.1       misho    1128:        return ret;
                   1129: }
                   1130: 
                   1131: /* Set extended attributes on indicated filename. */
1.1.1.4 ! misho    1132: int set_xattr(const char *fname, const struct file_struct *file, const char *fnamecmp, stat_x *sxp)
1.1       misho    1133: {
1.1.1.4 ! misho    1134:        rsync_xa_list *glst = rsync_xal_l.items;
        !          1135:        item_list *lst;
1.1       misho    1136:        int ndx;
                   1137: 
                   1138:        if (dry_run)
                   1139:                return 1; /* FIXME: --dry-run needs to compute this value */
                   1140: 
                   1141:        if (read_only || list_only) {
                   1142:                errno = EROFS;
                   1143:                return -1;
                   1144:        }
                   1145: 
                   1146: #ifdef NO_SPECIAL_XATTRS
                   1147:        if (IS_SPECIAL(sxp->st.st_mode)) {
                   1148:                errno = ENOTSUP;
                   1149:                return -1;
                   1150:        }
                   1151: #endif
                   1152: #ifdef NO_DEVICE_XATTRS
                   1153:        if (IS_DEVICE(sxp->st.st_mode)) {
                   1154:                errno = ENOTSUP;
                   1155:                return -1;
                   1156:        }
                   1157: #endif
                   1158: #ifdef NO_SYMLINK_XATTRS
                   1159:        if (S_ISLNK(sxp->st.st_mode)) {
                   1160:                errno = ENOTSUP;
                   1161:                return -1;
                   1162:        }
                   1163: #endif
                   1164: 
                   1165:        ndx = F_XATTR(file);
1.1.1.4 ! misho    1166:        glst += ndx;
        !          1167:        lst = &glst->xa_items;
        !          1168:        return rsync_xal_set(fname, lst, fnamecmp, sxp);
1.1       misho    1169: }
                   1170: 
                   1171: #ifdef SUPPORT_ACLS
                   1172: char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)
                   1173: {
                   1174:        const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
                   1175:        *len_p = 0; /* no extra data alloc needed from get_xattr_data() */
1.1.1.4 ! misho    1176:        return get_xattr_data(fname, name, len_p, GXD_NO_MISSING_ERROR);
1.1       misho    1177: }
                   1178: 
                   1179: int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len)
                   1180: {
                   1181:        const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
                   1182:        if (sys_lsetxattr(fname, name, buf, buf_len) < 0) {
                   1183:                rsyserr(FERROR_XFER, errno,
1.1.1.4 ! misho    1184:                        "set_xattr_acl: lsetxattr(%s,\"%s\") failed",
1.1       misho    1185:                        full_fname(fname), name);
                   1186:                return -1;
                   1187:        }
                   1188:        return 0;
                   1189: }
                   1190: 
                   1191: int del_def_xattr_acl(const char *fname)
                   1192: {
                   1193:        return sys_lremovexattr(fname, XDEF_ACL_ATTR);
                   1194: }
                   1195: #endif
                   1196: 
1.1.1.4 ! misho    1197: int get_sum_xattr(const char *fname, STRUCT_STAT *stp, char *sum)
        !          1198: {
        !          1199:        const char *mdattr = checksum_type == 5 ? MD5_ATTR : MD4_ATTR;
        !          1200:        char buf[256];
        !          1201:        uint32 file_length, mtime;
        !          1202:        int len;
        !          1203: 
        !          1204:        len = sys_lgetxattr(fname, mdattr, buf, sizeof buf);
        !          1205:        if (len < 0) {
        !          1206:                if (errno == ENOTSUP || errno == ENOATTR)
        !          1207:                        return 0;
        !          1208:                rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
        !          1209:                        mdattr, full_fname(fname));
        !          1210:                return 0;
        !          1211:        }
        !          1212:        if (len != 4 + 4 + flist_csum_len) {
        !          1213:                rprintf(FERROR, "Corrupt %s xattr attached to %s -- skipping\n",
        !          1214:                        mdattr, full_fname(fname));
        !          1215:                return 0;
        !          1216:        }
        !          1217: 
        !          1218:        file_length = IVAL(buf, 0); /* 32-bit values -- trunctions are OK */
        !          1219:        mtime = IVAL(buf, 4);
        !          1220: 
        !          1221:        if ((uint32)stp->st_size != file_length || (uint32)stp->st_mtime != mtime)
        !          1222:                return 0;
        !          1223: 
        !          1224:        memcpy(sum, buf + 8, flist_csum_len);
        !          1225: 
        !          1226:        return 1;
        !          1227: }
        !          1228: 
1.1       misho    1229: int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1230: {
                   1231:        int mode, rdev_major, rdev_minor, uid, gid, len;
                   1232:        char buf[256];
                   1233: 
                   1234:        if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
                   1235:                return -1;
                   1236: 
                   1237:        if (xst)
                   1238:                *xst = *fst;
                   1239:        else
                   1240:                xst = fst;
                   1241:        if (fname) {
                   1242:                fd = -1;
                   1243:                len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
                   1244:        } else {
                   1245:                fname = "fd";
                   1246:                len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
                   1247:        }
                   1248:        if (len >= (int)sizeof buf) {
                   1249:                len = -1;
                   1250:                errno = ERANGE;
                   1251:        }
                   1252:        if (len < 0) {
                   1253:                if (errno == ENOTSUP || errno == ENOATTR)
                   1254:                        return -1;
                   1255:                if (errno == EPERM && S_ISLNK(fst->st_mode)) {
                   1256:                        xst->st_uid = 0;
                   1257:                        xst->st_gid = 0;
                   1258:                        return 0;
                   1259:                }
                   1260:                rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
                   1261:                        XSTAT_ATTR, full_fname(fname));
                   1262:                return -1;
                   1263:        }
                   1264:        buf[len] = '\0';
                   1265: 
                   1266:        if (sscanf(buf, "%o %d,%d %d:%d",
                   1267:                   &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
                   1268:                rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
                   1269:                        XSTAT_ATTR, full_fname(fname), buf);
                   1270:                exit_cleanup(RERR_FILEIO);
                   1271:        }
                   1272: 
                   1273:        xst->st_mode = from_wire_mode(mode);
                   1274:        xst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
                   1275:        xst->st_uid = uid;
                   1276:        xst->st_gid = gid;
                   1277: 
                   1278:        return 0;
                   1279: }
                   1280: 
                   1281: int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
                   1282: {
                   1283:        STRUCT_STAT fst, xst;
                   1284:        dev_t rdev;
                   1285:        mode_t mode, fmode;
                   1286: 
                   1287:        if (dry_run)
                   1288:                return 0;
                   1289: 
                   1290:        if (read_only || list_only) {
                   1291:                rsyserr(FERROR_XFER, EROFS, "failed to write xattr %s for %s",
                   1292:                        XSTAT_ATTR, full_fname(fname));
                   1293:                return -1;
                   1294:        }
                   1295: 
                   1296:        if (x_lstat(fname, &fst, &xst) < 0) {
                   1297:                rsyserr(FERROR_XFER, errno, "failed to re-stat %s",
                   1298:                        full_fname(fname));
                   1299:                return -1;
                   1300:        }
                   1301: 
                   1302:        fst.st_mode &= (_S_IFMT | CHMOD_BITS);
                   1303:        fmode = new_mode & (_S_IFMT | CHMOD_BITS);
                   1304: 
                   1305:        if (IS_DEVICE(fmode)) {
                   1306:                uint32 *devp = F_RDEV_P(file);
                   1307:                rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
                   1308:        } else
                   1309:                rdev = 0;
                   1310: 
                   1311:        /* Dump the special permissions and enable full owner access. */
                   1312:        mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
                   1313:             | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
                   1314:        if (fst.st_mode != mode)
1.1.1.4 ! misho    1315:                do_chmod(fname, mode, ST_FLAGS(fst));
1.1       misho    1316:        if (!IS_DEVICE(fst.st_mode))
                   1317:                fst.st_rdev = 0; /* just in case */
                   1318: 
                   1319:        if (mode == fmode && fst.st_rdev == rdev
                   1320:         && fst.st_uid == F_OWNER(file) && fst.st_gid == F_GROUP(file)) {
                   1321:                /* xst.st_mode will be 0 if there's no current stat xattr */
                   1322:                if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
                   1323:                        rsyserr(FERROR_XFER, errno,
                   1324:                                "delete of stat xattr failed for %s",
                   1325:                                full_fname(fname));
                   1326:                        return -1;
                   1327:                }
                   1328:                return 0;
                   1329:        }
                   1330: 
                   1331:        if (xst.st_mode != fmode || xst.st_rdev != rdev
                   1332:         || xst.st_uid != F_OWNER(file) || xst.st_gid != F_GROUP(file)) {
                   1333:                char buf[256];
                   1334:                int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
                   1335:                        to_wire_mode(fmode),
                   1336:                        (int)major(rdev), (int)minor(rdev),
                   1337:                        F_OWNER(file), F_GROUP(file));
                   1338:                if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
                   1339:                        if (errno == EPERM && S_ISLNK(fst.st_mode))
                   1340:                                return 0;
                   1341:                        rsyserr(FERROR_XFER, errno,
                   1342:                                "failed to write xattr %s for %s",
                   1343:                                XSTAT_ATTR, full_fname(fname));
                   1344:                        return -1;
                   1345:                }
                   1346:        }
                   1347: 
                   1348:        return 0;
                   1349: }
                   1350: 
1.1.1.4 ! misho    1351: #ifdef SUPPORT_HFS_COMPRESSION
        !          1352: static inline void hfs_compress_tweaks(STRUCT_STAT *fst)
        !          1353: {
        !          1354:        if (fst->st_flags & UF_COMPRESSED) {
        !          1355:                if (preserve_hfs_compression) {
        !          1356:                        /* We're sending the compression xattr, not the decompressed data fork.
        !          1357:                         * Setting rsync's idea of the file size to 0 effectively prevents the
        !          1358:                         * transfer of the data fork. */
        !          1359:                        fst->st_size = 0;
        !          1360:                } else {
        !          1361:                        /* If the sender's filesystem supports compression, then we'll be able
        !          1362:                         * to send the decompressed data fork and the decmpfs xattr will be
        !          1363:                         * hidden (not sent). As such, we need to strip the compression flag. */
        !          1364:                        fst->st_flags &= ~UF_COMPRESSED;
        !          1365:                }
        !          1366:        }
        !          1367: }
        !          1368: #endif
        !          1369: 
1.1       misho    1370: int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1371: {
                   1372:        int ret = do_stat(fname, fst);
                   1373:        if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
                   1374:                xst->st_mode = 0;
1.1.1.4 ! misho    1375: #ifdef SUPPORT_HFS_COMPRESSION
        !          1376:        hfs_compress_tweaks(fst);
        !          1377: #endif
1.1       misho    1378:        return ret;
                   1379: }
                   1380: 
                   1381: int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1382: {
                   1383:        int ret = do_lstat(fname, fst);
                   1384:        if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
                   1385:                xst->st_mode = 0;
1.1.1.4 ! misho    1386: #ifdef SUPPORT_HFS_COMPRESSION
        !          1387:        hfs_compress_tweaks(fst);
        !          1388: #endif
1.1       misho    1389:        return ret;
                   1390: }
                   1391: 
                   1392: int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1393: {
                   1394:        int ret = do_fstat(fd, fst);
                   1395:        if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst)
                   1396:                xst->st_mode = 0;
1.1.1.4 ! misho    1397: #ifdef SUPPORT_HFS_COMPRESSION
        !          1398:        hfs_compress_tweaks(fst);
        !          1399: #endif
1.1       misho    1400:        return ret;
                   1401: }
                   1402: 
                   1403: #endif /* SUPPORT_XATTRS */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>