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

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

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