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

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.2 ! misho       6:  * Copyright (C) 2006-2013 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;
                    311:        }
                    312: 
                    313:        if (rsync_xal_get(fname, sxp->xattr) < 0) {
                    314:                free_xattr(sxp);
                    315:                return -1;
                    316:        }
                    317:        return 0;
                    318: }
                    319: 
                    320: int copy_xattrs(const char *source, const char *dest)
                    321: {
                    322:        ssize_t list_len, name_len;
                    323:        size_t datum_len;
                    324:        char *name, *ptr;
                    325: #ifdef HAVE_LINUX_XATTRS
1.1.1.2 ! misho     326:        int user_only = am_sender ? 0 : am_root <= 0;
1.1       misho     327: #endif
                    328: 
                    329:        /* This puts the name list into the "namebuf" buffer. */
                    330:        if ((list_len = get_xattr_names(source)) < 0)
                    331:                return -1;
                    332: 
                    333:        for (name = namebuf; list_len > 0; name += name_len) {
                    334:                name_len = strlen(name) + 1;
                    335:                list_len -= name_len;
                    336: 
                    337: #ifdef HAVE_LINUX_XATTRS
                    338:                /* We always ignore the system namespace, and non-root
                    339:                 * ignores everything but the user namespace. */
                    340:                if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
                    341:                              : HAS_PREFIX(name, SYSTEM_PREFIX))
                    342:                        continue;
                    343: #endif
                    344: 
                    345:                datum_len = 0;
                    346:                if (!(ptr = get_xattr_data(source, name, &datum_len, 0)))
                    347:                        return -1;
                    348:                if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) {
                    349:                        int save_errno = errno ? errno : EINVAL;
                    350:                        rsyserr(FERROR_XFER, errno,
                    351:                                "copy_xattrs: lsetxattr(\"%s\",\"%s\") failed",
                    352:                                full_fname(dest), name);
                    353:                        errno = save_errno;
                    354:                        return -1;
                    355:                }
                    356:                free(ptr);
                    357:        }
                    358: 
                    359:        return 0;
                    360: }
                    361: 
                    362: static int find_matching_xattr(item_list *xalp)
                    363: {
                    364:        size_t i, j;
                    365:        item_list *lst = rsync_xal_l.items;
                    366: 
                    367:        for (i = 0; i < rsync_xal_l.count; i++) {
                    368:                rsync_xa *rxas1 = lst[i].items;
                    369:                rsync_xa *rxas2 = xalp->items;
                    370: 
                    371:                /* Wrong number of elements? */
                    372:                if (lst[i].count != xalp->count)
                    373:                        continue;
                    374:                /* any elements different? */
                    375:                for (j = 0; j < xalp->count; j++) {
                    376:                        if (rxas1[j].name_len != rxas2[j].name_len
                    377:                         || rxas1[j].datum_len != rxas2[j].datum_len
                    378:                         || strcmp(rxas1[j].name, rxas2[j].name))
                    379:                                break;
                    380:                        if (rxas1[j].datum_len > MAX_FULL_DATUM) {
                    381:                                if (memcmp(rxas1[j].datum + 1,
                    382:                                           rxas2[j].datum + 1,
                    383:                                           MAX_DIGEST_LEN) != 0)
                    384:                                        break;
                    385:                        } else {
                    386:                                if (memcmp(rxas1[j].datum, rxas2[j].datum,
                    387:                                           rxas2[j].datum_len))
                    388:                                        break;
                    389:                        }
                    390:                }
                    391:                /* no differences found.  This is The One! */
                    392:                if (j == xalp->count)
                    393:                        return i;
                    394:        }
                    395: 
                    396:        return -1;
                    397: }
                    398: 
                    399: /* Store *xalp on the end of rsync_xal_l */
                    400: static void rsync_xal_store(item_list *xalp)
                    401: {
                    402:        item_list *new_lst = EXPAND_ITEM_LIST(&rsync_xal_l, item_list, RSYNC_XAL_LIST_INITIAL);
                    403:        /* Since the following call starts a new list, we know it will hold the
                    404:         * entire initial-count, not just enough space for one new item. */
                    405:        *new_lst = empty_xattr;
                    406:        (void)EXPAND_ITEM_LIST(new_lst, rsync_xa, xalp->count);
                    407:        memcpy(new_lst->items, xalp->items, xalp->count * sizeof (rsync_xa));
                    408:        new_lst->count = xalp->count;
                    409:        xalp->count = 0;
                    410: }
                    411: 
                    412: /* Send the make_xattr()-generated xattr list for this flist entry. */
                    413: int send_xattr(int f, stat_x *sxp)
                    414: {
                    415:        int ndx = find_matching_xattr(sxp->xattr);
                    416: 
                    417:        /* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
                    418:        write_varint(f, ndx + 1);
                    419: 
                    420:        if (ndx < 0) {
                    421:                rsync_xa *rxa;
                    422:                int count = sxp->xattr->count;
                    423:                write_varint(f, count);
                    424:                for (rxa = sxp->xattr->items; count--; rxa++) {
                    425:                        size_t name_len = rxa->name_len;
                    426:                        const char *name = rxa->name;
                    427:                        /* Strip the rsync prefix from disguised namespaces. */
                    428:                        if (name_len > RPRE_LEN
                    429: #ifdef HAVE_LINUX_XATTRS
                    430:                         && am_root < 0
                    431: #endif
                    432:                         && name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
                    433:                                name += RPRE_LEN;
                    434:                                name_len -= RPRE_LEN;
                    435:                        }
                    436: #ifndef HAVE_LINUX_XATTRS
                    437:                        else {
                    438:                                /* Put everything else in the user namespace. */
                    439:                                name_len += UPRE_LEN;
                    440:                        }
                    441: #endif
                    442:                        write_varint(f, name_len);
                    443:                        write_varint(f, rxa->datum_len);
                    444: #ifndef HAVE_LINUX_XATTRS
                    445:                        if (name_len > rxa->name_len) {
                    446:                                write_buf(f, USER_PREFIX, UPRE_LEN);
                    447:                                name_len -= UPRE_LEN;
                    448:                        }
                    449: #endif
                    450:                        write_buf(f, name, name_len);
                    451:                        if (rxa->datum_len > MAX_FULL_DATUM)
                    452:                                write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
                    453:                        else
                    454:                                write_buf(f, rxa->datum, rxa->datum_len);
                    455:                }
                    456:                ndx = rsync_xal_l.count; /* pre-incremented count */
                    457:                rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
                    458:        }
                    459: 
                    460:        return ndx;
                    461: }
                    462: 
                    463: /* Return a flag indicating if we need to change a file's xattrs.  If
                    464:  * "find_all" is specified, also mark any abbreviated xattrs that we
                    465:  * need so that send_xattr_request() can tell the sender about them. */
                    466: int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
                    467: {
                    468:        item_list *lst = rsync_xal_l.items;
                    469:        rsync_xa *snd_rxa, *rec_rxa;
                    470:        int snd_cnt, rec_cnt;
                    471:        int cmp, same, xattrs_equal = 1;
                    472: 
                    473:        if (sxp && XATTR_READY(*sxp)) {
                    474:                rec_rxa = sxp->xattr->items;
                    475:                rec_cnt = sxp->xattr->count;
                    476:        } else {
                    477:                rec_rxa = NULL;
                    478:                rec_cnt = 0;
                    479:        }
                    480: 
                    481:        if (F_XATTR(file) >= 0)
                    482:                lst += F_XATTR(file);
                    483:        else
                    484:                lst = &empty_xattr;
                    485: 
                    486:        snd_rxa = lst->items;
                    487:        snd_cnt = lst->count;
                    488: 
                    489:        /* If the count of the sender's xattrs is different from our
                    490:         * (receiver's) xattrs, the lists are not the same. */
                    491:        if (snd_cnt != rec_cnt) {
                    492:                if (!find_all)
                    493:                        return 1;
                    494:                xattrs_equal = 0;
                    495:        }
                    496: 
                    497:        while (snd_cnt) {
                    498:                cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
                    499:                if (cmp > 0)
                    500:                        same = 0;
                    501:                else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
                    502:                        same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
                    503:                            && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
                    504:                                      MAX_DIGEST_LEN) == 0;
                    505:                        /* Flag unrequested items that we need. */
                    506:                        if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
                    507:                                snd_rxa->datum[0] = XSTATE_TODO;
                    508:                } else {
                    509:                        same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
                    510:                            && memcmp(snd_rxa->datum, rec_rxa->datum,
                    511:                                      snd_rxa->datum_len) == 0;
                    512:                }
                    513:                if (!same) {
                    514:                        if (!find_all)
                    515:                                return 1;
                    516:                        xattrs_equal = 0;
                    517:                }
                    518: 
                    519:                if (cmp <= 0) {
                    520:                        snd_rxa++;
                    521:                        snd_cnt--;
                    522:                }
                    523:                if (cmp >= 0) {
                    524:                        rec_rxa++;
                    525:                        rec_cnt--;
                    526:                }
                    527:        }
                    528: 
                    529:        if (rec_cnt)
                    530:                xattrs_equal = 0;
                    531: 
                    532:        return !xattrs_equal;
                    533: }
                    534: 
                    535: /* When called by the generator (with a NULL fname), this tells the sender
                    536:  * all the abbreviated xattr values we need.  When called by the sender
                    537:  * (with a non-NULL fname), we send all the extra xattr data it needs.
                    538:  * The generator may also call with f_out < 0 to just change all the
                    539:  * XSTATE_ABBREV states into XSTATE_DONE. */
                    540: void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
                    541: {
                    542:        item_list *lst = rsync_xal_l.items;
                    543:        int cnt, prior_req = 0;
                    544:        rsync_xa *rxa;
                    545: 
                    546:        lst += F_XATTR(file);
                    547:        for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) {
                    548:                if (rxa->datum_len <= MAX_FULL_DATUM)
                    549:                        continue;
                    550:                switch (rxa->datum[0]) {
                    551:                case XSTATE_ABBREV:
                    552:                        /* Items left abbreviated matched the sender's checksum, so
                    553:                         * the receiver will cache the local data for future use. */
                    554:                        if (am_generator)
                    555:                                rxa->datum[0] = XSTATE_DONE;
                    556:                        continue;
                    557:                case XSTATE_TODO:
                    558:                        assert(f_out >= 0);
                    559:                        break;
                    560:                default:
                    561:                        continue;
                    562:                }
                    563: 
                    564:                /* Flag that we handled this abbreviated item. */
                    565:                rxa->datum[0] = XSTATE_DONE;
                    566: 
                    567:                write_varint(f_out, rxa->num - prior_req);
                    568:                prior_req = rxa->num;
                    569: 
                    570:                if (fname) {
                    571:                        size_t len = 0;
                    572:                        char *ptr;
                    573: 
                    574:                        /* Re-read the long datum. */
                    575:                        if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) {
                    576:                                rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname);
                    577:                                write_varint(f_out, 0);
                    578:                                continue;
                    579:                        }
                    580: 
                    581:                        write_varint(f_out, len); /* length might have changed! */
                    582:                        write_buf(f_out, ptr, len);
                    583:                        free(ptr);
                    584:                }
                    585:        }
                    586: 
                    587:        if (f_out >= 0)
                    588:                write_byte(f_out, 0); /* end the list */
                    589: }
                    590: 
                    591: /* When called by the sender, read the request from the generator and mark
                    592:  * any needed xattrs with a flag that lets us know they need to be sent to
                    593:  * the receiver.  When called by the receiver, reads the sent data and
                    594:  * stores it in place of its checksum. */
                    595: int recv_xattr_request(struct file_struct *file, int f_in)
                    596: {
                    597:        item_list *lst = rsync_xal_l.items;
                    598:        char *old_datum, *name;
                    599:        rsync_xa *rxa;
                    600:        int rel_pos, cnt, num, got_xattr_data = 0;
                    601: 
                    602:        if (F_XATTR(file) < 0) {
                    603:                rprintf(FERROR, "recv_xattr_request: internal data error!\n");
                    604:                exit_cleanup(RERR_PROTOCOL);
                    605:        }
                    606:        lst += F_XATTR(file);
                    607: 
                    608:        cnt = lst->count;
                    609:        rxa = lst->items;
                    610:        num = 0;
                    611:        while ((rel_pos = read_varint(f_in)) != 0) {
                    612:                num += rel_pos;
                    613:                while (cnt && rxa->num < num) {
                    614:                    rxa++;
                    615:                    cnt--;
                    616:                }
                    617:                if (!cnt || rxa->num != num) {
                    618:                        rprintf(FERROR, "[%s] could not find xattr #%d for %s\n",
                    619:                                who_am_i(), num, f_name(file, NULL));
                    620:                        exit_cleanup(RERR_PROTOCOL);
                    621:                }
                    622:                if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) {
                    623:                        rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n",
                    624:                                who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len);
                    625:                        exit_cleanup(RERR_PROTOCOL);
                    626:                }
                    627: 
                    628:                if (am_sender) {
                    629:                        rxa->datum[0] = XSTATE_TODO;
                    630:                        continue;
                    631:                }
                    632: 
                    633:                old_datum = rxa->datum;
                    634:                rxa->datum_len = read_varint(f_in);
                    635: 
                    636:                if (rxa->name_len + rxa->datum_len < rxa->name_len)
                    637:                        overflow_exit("recv_xattr_request");
                    638:                rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
                    639:                if (!rxa->datum)
                    640:                        out_of_memory("recv_xattr_request");
                    641:                name = rxa->datum + rxa->datum_len;
                    642:                memcpy(name, rxa->name, rxa->name_len);
                    643:                rxa->name = name;
                    644:                free(old_datum);
                    645:                read_buf(f_in, rxa->datum, rxa->datum_len);
                    646:                got_xattr_data = 1;
                    647:        }
                    648: 
                    649:        return got_xattr_data;
                    650: }
                    651: 
                    652: /* ------------------------------------------------------------------------- */
                    653: 
                    654: /* receive and build the rsync_xattr_lists */
                    655: void receive_xattr(int f, struct file_struct *file)
                    656: {
                    657:        static item_list temp_xattr = EMPTY_ITEM_LIST;
                    658:        int count, num;
                    659: #ifdef HAVE_LINUX_XATTRS
                    660:        int need_sort = 0;
                    661: #else
                    662:        int need_sort = 1;
                    663: #endif
                    664:        int ndx = read_varint(f);
                    665: 
                    666:        if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
                    667:                rprintf(FERROR, "receive_xattr: xa index %d out of"
                    668:                        " range for %s\n", ndx, f_name(file, NULL));
1.1.1.2 ! misho     669:                exit_cleanup(RERR_STREAMIO);
1.1       misho     670:        }
                    671: 
                    672:        if (ndx != 0) {
                    673:                F_XATTR(file) = ndx - 1;
                    674:                return;
                    675:        }
                    676: 
                    677:        if ((count = read_varint(f)) != 0) {
                    678:                (void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
                    679:                temp_xattr.count = 0;
                    680:        }
                    681: 
                    682:        for (num = 1; num <= count; num++) {
                    683:                char *ptr, *name;
                    684:                rsync_xa *rxa;
                    685:                size_t name_len = read_varint(f);
                    686:                size_t datum_len = read_varint(f);
                    687:                size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
                    688:                size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
                    689:                if ((dget_len + extra_len < dget_len)
                    690:                 || (dget_len + extra_len + name_len < dget_len))
                    691:                        overflow_exit("receive_xattr");
                    692:                ptr = new_array(char, dget_len + extra_len + name_len);
                    693:                if (!ptr)
                    694:                        out_of_memory("receive_xattr");
                    695:                name = ptr + dget_len + extra_len;
                    696:                read_buf(f, name, name_len);
                    697:                if (dget_len == datum_len)
                    698:                        read_buf(f, ptr, dget_len);
                    699:                else {
                    700:                        *ptr = XSTATE_ABBREV;
                    701:                        read_buf(f, ptr + 1, MAX_DIGEST_LEN);
                    702:                }
                    703: #ifdef HAVE_LINUX_XATTRS
                    704:                /* Non-root can only save the user namespace. */
                    705:                if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
                    706:                        if (!am_root) {
                    707:                                free(ptr);
                    708:                                continue;
                    709:                        }
                    710:                        name -= RPRE_LEN;
                    711:                        name_len += RPRE_LEN;
                    712:                        memcpy(name, RSYNC_PREFIX, RPRE_LEN);
                    713:                        need_sort = 1;
                    714:                }
                    715: #else
                    716:                /* This OS only has a user namespace, so we either
                    717:                 * strip the user prefix, or we put a non-user
                    718:                 * namespace inside our rsync hierarchy. */
                    719:                if (HAS_PREFIX(name, USER_PREFIX)) {
                    720:                        name += UPRE_LEN;
                    721:                        name_len -= UPRE_LEN;
                    722:                } else if (am_root) {
                    723:                        name -= RPRE_LEN;
                    724:                        name_len += RPRE_LEN;
                    725:                        memcpy(name, RSYNC_PREFIX, RPRE_LEN);
                    726:                } else {
                    727:                        free(ptr);
                    728:                        continue;
                    729:                }
                    730: #endif
                    731:                /* No rsync.%FOO attributes are copied w/o 2 -X options. */
                    732:                if (preserve_xattrs < 2 && name_len > RPRE_LEN
                    733:                 && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
                    734:                        free(ptr);
                    735:                        continue;
                    736:                }
                    737:                rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1);
                    738:                rxa->name = name;
                    739:                rxa->datum = ptr;
                    740:                rxa->name_len = name_len;
                    741:                rxa->datum_len = datum_len;
                    742:                rxa->num = num;
                    743:        }
                    744: 
                    745:        if (need_sort && count > 1)
                    746:                qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
                    747: 
                    748:        ndx = rsync_xal_l.count; /* pre-incremented count */
                    749:        rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */
                    750: 
                    751:        F_XATTR(file) = ndx;
                    752: }
                    753: 
                    754: /* Turn the xattr data in stat_x into cached xattr data, setting the index
                    755:  * values in the file struct. */
                    756: void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
                    757: {
                    758:        int ndx;
                    759: 
                    760:        if (!sxp->xattr)
                    761:                return;
                    762: 
                    763:        if (prior_xattr_count == (size_t)-1)
                    764:                prior_xattr_count = rsync_xal_l.count;
                    765:        ndx = find_matching_xattr(sxp->xattr);
                    766:        if (ndx < 0)
                    767:                rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
                    768: 
                    769:        F_XATTR(file) = ndx;
                    770: }
                    771: 
                    772: void uncache_tmp_xattrs(void)
                    773: {
                    774:        if (prior_xattr_count != (size_t)-1) {
                    775:                item_list *xattr_item = rsync_xal_l.items;
                    776:                item_list *xattr_start = xattr_item + prior_xattr_count;
                    777:                xattr_item += rsync_xal_l.count;
                    778:                rsync_xal_l.count = prior_xattr_count;
                    779:                while (xattr_item-- > xattr_start)
                    780:                        rsync_xal_free(xattr_item);
                    781:                prior_xattr_count = (size_t)-1;
                    782:        }
                    783: }
                    784: 
                    785: static int rsync_xal_set(const char *fname, item_list *xalp,
                    786:                         const char *fnamecmp, stat_x *sxp)
                    787: {
                    788:        rsync_xa *rxas = xalp->items;
                    789:        ssize_t list_len;
                    790:        size_t i, len;
                    791:        char *name, *ptr, sum[MAX_DIGEST_LEN];
                    792: #ifdef HAVE_LINUX_XATTRS
                    793:        int user_only = am_root <= 0;
                    794: #endif
                    795:        size_t name_len;
                    796:        int ret = 0;
                    797: 
                    798:        /* This puts the current name list into the "namebuf" buffer. */
                    799:        if ((list_len = get_xattr_names(fname)) < 0)
                    800:                return -1;
                    801: 
                    802:        for (i = 0; i < xalp->count; i++) {
                    803:                name = rxas[i].name;
                    804: 
                    805:                if (XATTR_ABBREV(rxas[i])) {
                    806:                        /* See if the fnamecmp version is identical. */
                    807:                        len = name_len = rxas[i].name_len;
                    808:                        if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) {
                    809:                          still_abbrev:
                    810:                                if (am_generator)
                    811:                                        continue;
                    812:                                rprintf(FERROR, "Missing abbreviated xattr value, %s, for %s\n",
                    813:                                        rxas[i].name, full_fname(fname));
                    814:                                ret = -1;
                    815:                                continue;
                    816:                        }
                    817:                        if (len != rxas[i].datum_len) {
                    818:                                free(ptr);
                    819:                                goto still_abbrev;
                    820:                        }
                    821: 
                    822:                        sum_init(checksum_seed);
                    823:                        sum_update(ptr, len);
                    824:                        sum_end(sum);
                    825:                        if (memcmp(sum, rxas[i].datum + 1, MAX_DIGEST_LEN) != 0) {
                    826:                                free(ptr);
                    827:                                goto still_abbrev;
                    828:                        }
                    829: 
                    830:                        if (fname == fnamecmp)
                    831:                                ; /* Value is already set when identical */
                    832:                        else if (sys_lsetxattr(fname, name, ptr, len) < 0) {
                    833:                                rsyserr(FERROR_XFER, errno,
                    834:                                        "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
                    835:                                        full_fname(fname), name);
                    836:                                ret = -1;
                    837:                        } else /* make sure caller sets mtime */
                    838:                                sxp->st.st_mtime = (time_t)-1;
                    839: 
                    840:                        if (am_generator) { /* generator items stay abbreviated */
                    841:                                free(ptr);
                    842:                                continue;
                    843:                        }
                    844: 
                    845:                        memcpy(ptr + len, name, name_len);
                    846:                        free(rxas[i].datum);
                    847: 
                    848:                        rxas[i].name = name = ptr + len;
                    849:                        rxas[i].datum = ptr;
                    850:                        continue;
                    851:                }
                    852: 
                    853:                if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) {
                    854:                        rsyserr(FERROR_XFER, errno,
                    855:                                "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
                    856:                                full_fname(fname), name);
                    857:                        ret = -1;
                    858:                } else /* make sure caller sets mtime */
                    859:                        sxp->st.st_mtime = (time_t)-1;
                    860:        }
                    861: 
                    862:        /* Remove any extraneous names. */
                    863:        for (name = namebuf; list_len > 0; name += name_len) {
                    864:                name_len = strlen(name) + 1;
                    865:                list_len -= name_len;
                    866: 
                    867: #ifdef HAVE_LINUX_XATTRS
                    868:                /* We always ignore the system namespace, and non-root
                    869:                 * ignores everything but the user namespace. */
                    870:                if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
                    871:                              : HAS_PREFIX(name, SYSTEM_PREFIX))
                    872:                        continue;
                    873: #endif
                    874:                if (am_root < 0 && name_len > RPRE_LEN
                    875:                 && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
                    876:                        continue;
                    877: 
                    878:                for (i = 0; i < xalp->count; i++) {
                    879:                        if (strcmp(name, rxas[i].name) == 0)
                    880:                                break;
                    881:                }
                    882:                if (i == xalp->count) {
                    883:                        if (sys_lremovexattr(fname, name) < 0) {
                    884:                                rsyserr(FERROR_XFER, errno,
                    885:                                        "rsync_xal_set: lremovexattr(\"%s\",\"%s\") failed",
                    886:                                        full_fname(fname), name);
                    887:                                ret = -1;
                    888:                        } else /* make sure caller sets mtime */
                    889:                                sxp->st.st_mtime = (time_t)-1;
                    890:                }
                    891:        }
                    892: 
                    893:        return ret;
                    894: }
                    895: 
                    896: /* Set extended attributes on indicated filename. */
                    897: int set_xattr(const char *fname, const struct file_struct *file,
                    898:              const char *fnamecmp, stat_x *sxp)
                    899: {
                    900:        int ndx;
                    901:        item_list *lst = rsync_xal_l.items;
                    902: 
                    903:        if (dry_run)
                    904:                return 1; /* FIXME: --dry-run needs to compute this value */
                    905: 
                    906:        if (read_only || list_only) {
                    907:                errno = EROFS;
                    908:                return -1;
                    909:        }
                    910: 
                    911: #ifdef NO_SPECIAL_XATTRS
                    912:        if (IS_SPECIAL(sxp->st.st_mode)) {
                    913:                errno = ENOTSUP;
                    914:                return -1;
                    915:        }
                    916: #endif
                    917: #ifdef NO_DEVICE_XATTRS
                    918:        if (IS_DEVICE(sxp->st.st_mode)) {
                    919:                errno = ENOTSUP;
                    920:                return -1;
                    921:        }
                    922: #endif
                    923: #ifdef NO_SYMLINK_XATTRS
                    924:        if (S_ISLNK(sxp->st.st_mode)) {
                    925:                errno = ENOTSUP;
                    926:                return -1;
                    927:        }
                    928: #endif
                    929: 
                    930:        ndx = F_XATTR(file);
                    931:        return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp);
                    932: }
                    933: 
                    934: #ifdef SUPPORT_ACLS
                    935: char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)
                    936: {
                    937:        const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
                    938:        *len_p = 0; /* no extra data alloc needed from get_xattr_data() */
                    939:        return get_xattr_data(fname, name, len_p, 1);
                    940: }
                    941: 
                    942: int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len)
                    943: {
                    944:        const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
                    945:        if (sys_lsetxattr(fname, name, buf, buf_len) < 0) {
                    946:                rsyserr(FERROR_XFER, errno,
                    947:                        "set_xattr_acl: lsetxattr(\"%s\",\"%s\") failed",
                    948:                        full_fname(fname), name);
                    949:                return -1;
                    950:        }
                    951:        return 0;
                    952: }
                    953: 
                    954: int del_def_xattr_acl(const char *fname)
                    955: {
                    956:        return sys_lremovexattr(fname, XDEF_ACL_ATTR);
                    957: }
                    958: #endif
                    959: 
                    960: int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
                    961: {
                    962:        int mode, rdev_major, rdev_minor, uid, gid, len;
                    963:        char buf[256];
                    964: 
                    965:        if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
                    966:                return -1;
                    967: 
                    968:        if (xst)
                    969:                *xst = *fst;
                    970:        else
                    971:                xst = fst;
                    972:        if (fname) {
                    973:                fd = -1;
                    974:                len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
                    975:        } else {
                    976:                fname = "fd";
                    977:                len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
                    978:        }
                    979:        if (len >= (int)sizeof buf) {
                    980:                len = -1;
                    981:                errno = ERANGE;
                    982:        }
                    983:        if (len < 0) {
                    984:                if (errno == ENOTSUP || errno == ENOATTR)
                    985:                        return -1;
                    986:                if (errno == EPERM && S_ISLNK(fst->st_mode)) {
                    987:                        xst->st_uid = 0;
                    988:                        xst->st_gid = 0;
                    989:                        return 0;
                    990:                }
                    991:                rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
                    992:                        XSTAT_ATTR, full_fname(fname));
                    993:                return -1;
                    994:        }
                    995:        buf[len] = '\0';
                    996: 
                    997:        if (sscanf(buf, "%o %d,%d %d:%d",
                    998:                   &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
                    999:                rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
                   1000:                        XSTAT_ATTR, full_fname(fname), buf);
                   1001:                exit_cleanup(RERR_FILEIO);
                   1002:        }
                   1003: 
                   1004:        xst->st_mode = from_wire_mode(mode);
                   1005:        xst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
                   1006:        xst->st_uid = uid;
                   1007:        xst->st_gid = gid;
                   1008: 
                   1009:        return 0;
                   1010: }
                   1011: 
                   1012: int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
                   1013: {
                   1014:        STRUCT_STAT fst, xst;
                   1015:        dev_t rdev;
                   1016:        mode_t mode, fmode;
                   1017: 
                   1018:        if (dry_run)
                   1019:                return 0;
                   1020: 
                   1021:        if (read_only || list_only) {
                   1022:                rsyserr(FERROR_XFER, EROFS, "failed to write xattr %s for %s",
                   1023:                        XSTAT_ATTR, full_fname(fname));
                   1024:                return -1;
                   1025:        }
                   1026: 
                   1027:        if (x_lstat(fname, &fst, &xst) < 0) {
                   1028:                rsyserr(FERROR_XFER, errno, "failed to re-stat %s",
                   1029:                        full_fname(fname));
                   1030:                return -1;
                   1031:        }
                   1032: 
                   1033:        fst.st_mode &= (_S_IFMT | CHMOD_BITS);
                   1034:        fmode = new_mode & (_S_IFMT | CHMOD_BITS);
                   1035: 
                   1036:        if (IS_DEVICE(fmode)) {
                   1037:                uint32 *devp = F_RDEV_P(file);
                   1038:                rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
                   1039:        } else
                   1040:                rdev = 0;
                   1041: 
                   1042:        /* Dump the special permissions and enable full owner access. */
                   1043:        mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
                   1044:             | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
                   1045:        if (fst.st_mode != mode)
                   1046:                do_chmod(fname, mode);
                   1047:        if (!IS_DEVICE(fst.st_mode))
                   1048:                fst.st_rdev = 0; /* just in case */
                   1049: 
                   1050:        if (mode == fmode && fst.st_rdev == rdev
                   1051:         && fst.st_uid == F_OWNER(file) && fst.st_gid == F_GROUP(file)) {
                   1052:                /* xst.st_mode will be 0 if there's no current stat xattr */
                   1053:                if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
                   1054:                        rsyserr(FERROR_XFER, errno,
                   1055:                                "delete of stat xattr failed for %s",
                   1056:                                full_fname(fname));
                   1057:                        return -1;
                   1058:                }
                   1059:                return 0;
                   1060:        }
                   1061: 
                   1062:        if (xst.st_mode != fmode || xst.st_rdev != rdev
                   1063:         || xst.st_uid != F_OWNER(file) || xst.st_gid != F_GROUP(file)) {
                   1064:                char buf[256];
                   1065:                int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
                   1066:                        to_wire_mode(fmode),
                   1067:                        (int)major(rdev), (int)minor(rdev),
                   1068:                        F_OWNER(file), F_GROUP(file));
                   1069:                if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
                   1070:                        if (errno == EPERM && S_ISLNK(fst.st_mode))
                   1071:                                return 0;
                   1072:                        rsyserr(FERROR_XFER, errno,
                   1073:                                "failed to write xattr %s for %s",
                   1074:                                XSTAT_ATTR, full_fname(fname));
                   1075:                        return -1;
                   1076:                }
                   1077:        }
                   1078: 
                   1079:        return 0;
                   1080: }
                   1081: 
                   1082: int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1083: {
                   1084:        int ret = do_stat(fname, fst);
                   1085:        if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
                   1086:                xst->st_mode = 0;
                   1087:        return ret;
                   1088: }
                   1089: 
                   1090: int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1091: {
                   1092:        int ret = do_lstat(fname, fst);
                   1093:        if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
                   1094:                xst->st_mode = 0;
                   1095:        return ret;
                   1096: }
                   1097: 
                   1098: int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
                   1099: {
                   1100:        int ret = do_fstat(fd, fst);
                   1101:        if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst)
                   1102:                xst->st_mode = 0;
                   1103:        return ret;
                   1104: }
                   1105: 
                   1106: #endif /* SUPPORT_XATTRS */

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