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>