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

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

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