Annotation of embedaddon/rsync/hlink.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Routines to support hard-linking.
        !             3:  *
        !             4:  * Copyright (C) 1996 Andrew Tridgell
        !             5:  * Copyright (C) 1996 Paul Mackerras
        !             6:  * Copyright (C) 2002 Martin Pool <mbp@samba.org>
        !             7:  * Copyright (C) 2004-2009 Wayne Davison
        !             8:  *
        !             9:  * This program is free software; you can redistribute it and/or modify
        !            10:  * it under the terms of the GNU General Public License as published by
        !            11:  * the Free Software Foundation; either version 3 of the License, or
        !            12:  * (at your option) any later version.
        !            13:  *
        !            14:  * This program is distributed in the hope that it will be useful,
        !            15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            17:  * GNU General Public License for more details.
        !            18:  *
        !            19:  * You should have received a copy of the GNU General Public License along
        !            20:  * with this program; if not, visit the http://fsf.org website.
        !            21:  */
        !            22: 
        !            23: #include "rsync.h"
        !            24: 
        !            25: extern int verbose;
        !            26: extern int dry_run;
        !            27: extern int list_only;
        !            28: extern int am_sender;
        !            29: extern int inc_recurse;
        !            30: extern int do_xfers;
        !            31: extern int link_dest;
        !            32: extern int preserve_acls;
        !            33: extern int preserve_xattrs;
        !            34: extern int make_backups;
        !            35: extern int protocol_version;
        !            36: extern int remove_source_files;
        !            37: extern int stdout_format_has_i;
        !            38: extern int maybe_ATTRS_REPORT;
        !            39: extern int unsort_ndx;
        !            40: extern char *basis_dir[MAX_BASIS_DIRS+1];
        !            41: extern struct file_list *cur_flist;
        !            42: 
        !            43: #ifdef SUPPORT_HARD_LINKS
        !            44: 
        !            45: /* Starting with protocol 30, we use a simple hashtable on the sending side
        !            46:  * for hashing the st_dev and st_ino info.  The receiving side gets told
        !            47:  * (via flags and a "group index") which items are hard-linked together, so
        !            48:  * we can avoid the pool of dev+inode data.  For incremental recursion mode,
        !            49:  * the receiver will use a ndx hash to remember old pathnames. */
        !            50: 
        !            51: static struct hashtable *dev_tbl;
        !            52: 
        !            53: static struct hashtable *prior_hlinks;
        !            54: 
        !            55: static struct file_list *hlink_flist;
        !            56: 
        !            57: void init_hard_links(void)
        !            58: {
        !            59:        if (am_sender || protocol_version < 30)
        !            60:                dev_tbl = hashtable_create(16, 1);
        !            61:        else if (inc_recurse)
        !            62:                prior_hlinks = hashtable_create(1024, 0);
        !            63: }
        !            64: 
        !            65: struct ht_int64_node *idev_find(int64 dev, int64 ino)
        !            66: {
        !            67:        static struct ht_int64_node *dev_node = NULL;
        !            68:        struct hashtable *tbl;
        !            69: 
        !            70:        /* Note that some OSes have a dev == 0, so increment to avoid storing a 0. */
        !            71:        if (!dev_node || dev_node->key != dev+1) {
        !            72:                /* We keep a separate hash table of inodes for every device. */
        !            73:                dev_node = hashtable_find(dev_tbl, dev+1, 1);
        !            74:                if (!(tbl = dev_node->data))
        !            75:                        tbl = dev_node->data = hashtable_create(512, 1);
        !            76:        } else
        !            77:                tbl = dev_node->data;
        !            78: 
        !            79:        return hashtable_find(tbl, ino, 1);
        !            80: }
        !            81: 
        !            82: void idev_destroy(void)
        !            83: {
        !            84:        int i;
        !            85: 
        !            86:        for (i = 0; i < dev_tbl->size; i++) {
        !            87:                struct ht_int32_node *node = HT_NODE(dev_tbl, dev_tbl->nodes, i);
        !            88:                if (node->data)
        !            89:                        hashtable_destroy(node->data);
        !            90:        }
        !            91: 
        !            92:        hashtable_destroy(dev_tbl);
        !            93: }
        !            94: 
        !            95: static int hlink_compare_gnum(int *int1, int *int2)
        !            96: {
        !            97:        struct file_struct *f1 = hlink_flist->sorted[*int1];
        !            98:        struct file_struct *f2 = hlink_flist->sorted[*int2];
        !            99:        int32 gnum1 = F_HL_GNUM(f1);
        !           100:        int32 gnum2 = F_HL_GNUM(f2);
        !           101: 
        !           102:        if (gnum1 != gnum2)
        !           103:                return gnum1 > gnum2 ? 1 : -1;
        !           104: 
        !           105:        return *int1 > *int2 ? 1 : -1;
        !           106: }
        !           107: 
        !           108: static void match_gnums(int32 *ndx_list, int ndx_count)
        !           109: {
        !           110:        int32 from, prev;
        !           111:        struct file_struct *file, *file_next;
        !           112:        struct ht_int32_node *node = NULL;
        !           113:        int32 gnum, gnum_next;
        !           114: 
        !           115:        qsort(ndx_list, ndx_count, sizeof ndx_list[0],
        !           116:             (int (*)()) hlink_compare_gnum);
        !           117: 
        !           118:        for (from = 0; from < ndx_count; from++) {
        !           119:                file = hlink_flist->sorted[ndx_list[from]];
        !           120:                gnum = F_HL_GNUM(file);
        !           121:                if (inc_recurse) {
        !           122:                        node = hashtable_find(prior_hlinks, gnum, 1);
        !           123:                        if (!node->data) {
        !           124:                                if (!(node->data = new_array0(char, 5)))
        !           125:                                        out_of_memory("match_gnums");
        !           126:                                assert(gnum >= hlink_flist->ndx_start);
        !           127:                                file->flags |= FLAG_HLINK_FIRST;
        !           128:                                prev = -1;
        !           129:                        } else if (CVAL(node->data, 0) == 0) {
        !           130:                                struct file_list *flist;
        !           131:                                prev = IVAL(node->data, 1);
        !           132:                                flist = flist_for_ndx(prev, NULL);
        !           133:                                if (flist)
        !           134:                                        flist->files[prev - flist->ndx_start]->flags &= ~FLAG_HLINK_LAST;
        !           135:                                else {
        !           136:                                        /* We skipped all prior files in this
        !           137:                                         * group, so mark this as a "first". */
        !           138:                                        file->flags |= FLAG_HLINK_FIRST;
        !           139:                                        prev = -1;
        !           140:                                }
        !           141:                        } else
        !           142:                                prev = -1;
        !           143:                } else {
        !           144:                        file->flags |= FLAG_HLINK_FIRST;
        !           145:                        prev = -1;
        !           146:                }
        !           147:                for ( ; from < ndx_count-1; file = file_next, gnum = gnum_next, from++) { /*SHARED ITERATOR*/
        !           148:                        file_next = hlink_flist->sorted[ndx_list[from+1]];
        !           149:                        gnum_next = F_HL_GNUM(file_next);
        !           150:                        if (gnum != gnum_next)
        !           151:                                break;
        !           152:                        F_HL_PREV(file) = prev;
        !           153:                        /* The linked list uses over-the-wire ndx values. */
        !           154:                        if (unsort_ndx)
        !           155:                                prev = F_NDX(file);
        !           156:                        else
        !           157:                                prev = ndx_list[from] + hlink_flist->ndx_start;
        !           158:                }
        !           159:                if (prev < 0 && !inc_recurse) {
        !           160:                        /* Disable hard-link bit and set DONE so that
        !           161:                         * HLINK_BUMP()-dependent values are unaffected. */
        !           162:                        file->flags &= ~(FLAG_HLINKED | FLAG_HLINK_FIRST);
        !           163:                        file->flags |= FLAG_HLINK_DONE;
        !           164:                        continue;
        !           165:                }
        !           166: 
        !           167:                file->flags |= FLAG_HLINK_LAST;
        !           168:                F_HL_PREV(file) = prev;
        !           169:                if (inc_recurse && CVAL(node->data, 0) == 0) {
        !           170:                        if (unsort_ndx)
        !           171:                                prev = F_NDX(file);
        !           172:                        else
        !           173:                                prev = ndx_list[from] + hlink_flist->ndx_start;
        !           174:                        SIVAL(node->data, 1, prev);
        !           175:                }
        !           176:        }
        !           177: }
        !           178: 
        !           179: /* Analyze the hard-links in the file-list by creating a list of all the
        !           180:  * items that have hlink data, sorting them, and matching up identical
        !           181:  * values into clusters.  These will be a single linked list from last
        !           182:  * to first when we're done. */
        !           183: void match_hard_links(struct file_list *flist)
        !           184: {
        !           185:        if (!list_only && flist->used) {
        !           186:                int i, ndx_count = 0;
        !           187:                int32 *ndx_list;
        !           188: 
        !           189:                if (!(ndx_list = new_array(int32, flist->used)))
        !           190:                        out_of_memory("match_hard_links");
        !           191: 
        !           192:                for (i = 0; i < flist->used; i++) {
        !           193:                        if (F_IS_HLINKED(flist->sorted[i]))
        !           194:                                ndx_list[ndx_count++] = i;
        !           195:                }
        !           196: 
        !           197:                hlink_flist = flist;
        !           198: 
        !           199:                if (ndx_count)
        !           200:                        match_gnums(ndx_list, ndx_count);
        !           201: 
        !           202:                free(ndx_list);
        !           203:        }
        !           204:        if (protocol_version < 30)
        !           205:                idev_destroy();
        !           206: }
        !           207: 
        !           208: static int maybe_hard_link(struct file_struct *file, int ndx,
        !           209:                           const char *fname, int statret, stat_x *sxp,
        !           210:                           const char *oldname, STRUCT_STAT *old_stp,
        !           211:                           const char *realname, int itemizing, enum logcode code)
        !           212: {
        !           213:        if (statret == 0) {
        !           214:                if (sxp->st.st_dev == old_stp->st_dev
        !           215:                 && sxp->st.st_ino == old_stp->st_ino) {
        !           216:                        if (itemizing) {
        !           217:                                itemize(fname, file, ndx, statret, sxp,
        !           218:                                        ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
        !           219:                                        0, "");
        !           220:                        }
        !           221:                        if (verbose > 1 && maybe_ATTRS_REPORT)
        !           222:                                rprintf(FCLIENT, "%s is uptodate\n", fname);
        !           223:                        file->flags |= FLAG_HLINK_DONE;
        !           224:                        return 0;
        !           225:                }
        !           226:                if (make_backups > 0) {
        !           227:                        if (!make_backup(fname))
        !           228:                                return -1;
        !           229:                } else if (robust_unlink(fname)) {
        !           230:                        rsyserr(FERROR_XFER, errno, "unlink %s failed",
        !           231:                                full_fname(fname));
        !           232:                        return -1;
        !           233:                }
        !           234:        }
        !           235: 
        !           236:        if (hard_link_one(file, fname, oldname, 0)) {
        !           237:                if (itemizing) {
        !           238:                        itemize(fname, file, ndx, statret, sxp,
        !           239:                                ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
        !           240:                                realname);
        !           241:                }
        !           242:                if (code != FNONE && verbose)
        !           243:                        rprintf(code, "%s => %s\n", fname, realname);
        !           244:                return 0;
        !           245:        }
        !           246:        return -1;
        !           247: }
        !           248: 
        !           249: /* Figure out if a prior entry is still there or if we just have a
        !           250:  * cached name for it. */
        !           251: static char *check_prior(struct file_struct *file, int gnum,
        !           252:                         int *prev_ndx_p, struct file_list **flist_p)
        !           253: {
        !           254:        struct file_struct *fp;
        !           255:        struct ht_int32_node *node;
        !           256:        int prev_ndx = F_HL_PREV(file);
        !           257: 
        !           258:        while (1) {
        !           259:                struct file_list *flist;
        !           260:                if (prev_ndx < 0
        !           261:                 || (flist = flist_for_ndx(prev_ndx, NULL)) == NULL)
        !           262:                        break;
        !           263:                fp = flist->files[prev_ndx - flist->ndx_start];
        !           264:                if (!(fp->flags & FLAG_SKIP_HLINK)) {
        !           265:                        *prev_ndx_p = prev_ndx;
        !           266:                        *flist_p = flist;
        !           267:                        return NULL;
        !           268:                }
        !           269:                F_HL_PREV(file) = prev_ndx = F_HL_PREV(fp);
        !           270:        }
        !           271: 
        !           272:        if (inc_recurse
        !           273:         && (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
        !           274:                assert(node->data != NULL);
        !           275:                if (CVAL(node->data, 0) != 0) {
        !           276:                        *prev_ndx_p = -1;
        !           277:                        *flist_p = NULL;
        !           278:                        return node->data;
        !           279:                }
        !           280:                /* The prior file must have been skipped. */
        !           281:                F_HL_PREV(file) = -1;
        !           282:        }
        !           283: 
        !           284:        *prev_ndx_p = -1;
        !           285:        *flist_p = NULL;
        !           286:        return NULL;
        !           287: }
        !           288: 
        !           289: /* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not.  Returns:
        !           290:  * 0 = process the file, 1 = skip the file, -1 = error occurred. */
        !           291: int hard_link_check(struct file_struct *file, int ndx, const char *fname,
        !           292:                    int statret, stat_x *sxp, int itemizing,
        !           293:                    enum logcode code)
        !           294: {
        !           295:        STRUCT_STAT prev_st;
        !           296:        char namebuf[MAXPATHLEN], altbuf[MAXPATHLEN];
        !           297:        char *realname, *prev_name;
        !           298:        struct file_list *flist;
        !           299:        int gnum = inc_recurse ? F_HL_GNUM(file) : -1;
        !           300:        int prev_ndx;
        !           301: 
        !           302:        prev_name = realname = check_prior(file, gnum, &prev_ndx, &flist);
        !           303: 
        !           304:        if (!prev_name) {
        !           305:                struct file_struct *prev_file;
        !           306: 
        !           307:                if (!flist) {
        !           308:                        /* The previous file was skipped, so this one is
        !           309:                         * treated as if it were the first in its group. */
        !           310:                        return 0;
        !           311:                }
        !           312: 
        !           313:                prev_file = flist->files[prev_ndx - flist->ndx_start];
        !           314: 
        !           315:                /* Is the previous link not complete yet? */
        !           316:                if (!(prev_file->flags & FLAG_HLINK_DONE)) {
        !           317:                        /* Is the previous link being transferred? */
        !           318:                        if (prev_file->flags & FLAG_FILE_SENT) {
        !           319:                                /* Add ourselves to the list of files that will
        !           320:                                 * be updated when the transfer completes, and
        !           321:                                 * mark ourself as waiting for the transfer. */
        !           322:                                F_HL_PREV(file) = F_HL_PREV(prev_file);
        !           323:                                F_HL_PREV(prev_file) = ndx;
        !           324:                                file->flags |= FLAG_FILE_SENT;
        !           325:                                cur_flist->in_progress++;
        !           326:                                return 1;
        !           327:                        }
        !           328:                        return 0;
        !           329:                }
        !           330: 
        !           331:                /* There is a finished file to link with! */
        !           332:                if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
        !           333:                        /* The previous previous is FIRST when prev is not. */
        !           334:                        prev_name = realname = check_prior(prev_file, gnum, &prev_ndx, &flist);
        !           335:                        assert(prev_name != NULL || flist != NULL);
        !           336:                        /* Update our previous pointer to point to the FIRST. */
        !           337:                        F_HL_PREV(file) = prev_ndx;
        !           338:                }
        !           339: 
        !           340:                if (!prev_name) {
        !           341:                        int alt_dest;
        !           342: 
        !           343:                        prev_file = flist->files[prev_ndx - flist->ndx_start];
        !           344:                        /* F_HL_PREV() is alt_dest value when DONE && FIRST. */
        !           345:                        alt_dest = F_HL_PREV(prev_file);
        !           346: 
        !           347:                        if (alt_dest >= 0 && dry_run) {
        !           348:                                pathjoin(namebuf, MAXPATHLEN, basis_dir[alt_dest],
        !           349:                                         f_name(prev_file, NULL));
        !           350:                                prev_name = namebuf;
        !           351:                                realname = f_name(prev_file, altbuf);
        !           352:                        } else {
        !           353:                                prev_name = f_name(prev_file, namebuf);
        !           354:                                realname = prev_name;
        !           355:                        }
        !           356:                }
        !           357:        }
        !           358: 
        !           359:        if (link_stat(prev_name, &prev_st, 0) < 0) {
        !           360:                if (!dry_run || errno != ENOENT) {
        !           361:                        rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(prev_name));
        !           362:                        return -1;
        !           363:                }
        !           364:                /* A new hard-link will get a new dev & inode, so approximate
        !           365:                 * those values in dry-run mode by zeroing them. */
        !           366:                memset(&prev_st, 0, sizeof prev_st);
        !           367:        }
        !           368: 
        !           369:        if (statret < 0 && basis_dir[0] != NULL) {
        !           370:                /* If we match an alt-dest item, we don't output this as a change. */
        !           371:                char cmpbuf[MAXPATHLEN];
        !           372:                stat_x alt_sx;
        !           373:                int j = 0;
        !           374: #ifdef SUPPORT_ACLS
        !           375:                alt_sx.acc_acl = alt_sx.def_acl = NULL;
        !           376: #endif
        !           377: #ifdef SUPPORT_XATTRS
        !           378:                alt_sx.xattr = NULL;
        !           379: #endif
        !           380:                do {
        !           381:                        pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
        !           382:                        if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
        !           383:                                continue;
        !           384:                        if (link_dest) {
        !           385:                                if (prev_st.st_dev != alt_sx.st.st_dev
        !           386:                                 || prev_st.st_ino != alt_sx.st.st_ino)
        !           387:                                        continue;
        !           388:                                statret = 1;
        !           389:                                if (stdout_format_has_i == 0
        !           390:                                 || (verbose < 2 && stdout_format_has_i < 2)) {
        !           391:                                        itemizing = 0;
        !           392:                                        code = FNONE;
        !           393:                                        if (verbose > 1 && maybe_ATTRS_REPORT)
        !           394:                                                rprintf(FCLIENT, "%s is uptodate\n", fname);
        !           395:                                }
        !           396:                                break;
        !           397:                        }
        !           398:                        if (!unchanged_file(cmpbuf, file, &alt_sx.st))
        !           399:                                continue;
        !           400:                        statret = 1;
        !           401:                        if (unchanged_attrs(cmpbuf, file, &alt_sx))
        !           402:                                break;
        !           403:                } while (basis_dir[++j] != NULL);
        !           404:                if (statret == 1) {
        !           405:                        sxp->st = alt_sx.st;
        !           406: #ifdef SUPPORT_ACLS
        !           407:                        if (preserve_acls && !S_ISLNK(file->mode)) {
        !           408:                                free_acl(sxp);
        !           409:                                if (!ACL_READY(alt_sx))
        !           410:                                        get_acl(cmpbuf, sxp);
        !           411:                                else {
        !           412:                                        sxp->acc_acl = alt_sx.acc_acl;
        !           413:                                        sxp->def_acl = alt_sx.def_acl;
        !           414:                                        alt_sx.acc_acl = alt_sx.def_acl = NULL;
        !           415:                                }
        !           416:                        }
        !           417: #endif
        !           418: #ifdef SUPPORT_XATTRS
        !           419:                        if (preserve_xattrs) {
        !           420:                                free_xattr(sxp);
        !           421:                                if (!XATTR_READY(alt_sx))
        !           422:                                        get_xattr(cmpbuf, sxp);
        !           423:                                else {
        !           424:                                        sxp->xattr = alt_sx.xattr;
        !           425:                                        alt_sx.xattr = NULL;
        !           426:                                }
        !           427:                        }
        !           428: #endif
        !           429:                } else {
        !           430: #ifdef SUPPORT_ACLS
        !           431:                        if (preserve_acls)
        !           432:                                free_acl(&alt_sx);
        !           433: #endif
        !           434: #ifdef SUPPORT_XATTRS
        !           435:                        if (preserve_xattrs)
        !           436:                                free_xattr(&alt_sx);
        !           437: #endif
        !           438:                }
        !           439:        }
        !           440: 
        !           441:        if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
        !           442:                            realname, itemizing, code) < 0)
        !           443:                return -1;
        !           444: 
        !           445:        if (remove_source_files == 1 && do_xfers)
        !           446:                send_msg_int(MSG_SUCCESS, ndx);
        !           447: 
        !           448:        return 1;
        !           449: }
        !           450: 
        !           451: int hard_link_one(struct file_struct *file, const char *fname,
        !           452:                  const char *oldname, int terse)
        !           453: {
        !           454:        if (do_link(oldname, fname) < 0) {
        !           455:                enum logcode code;
        !           456:                if (terse) {
        !           457:                        if (!verbose)
        !           458:                                return 0;
        !           459:                        code = FINFO;
        !           460:                } else
        !           461:                        code = FERROR_XFER;
        !           462:                rsyserr(code, errno, "link %s => %s failed",
        !           463:                        full_fname(fname), oldname);
        !           464:                return 0;
        !           465:        }
        !           466: 
        !           467:        file->flags |= FLAG_HLINK_DONE;
        !           468: 
        !           469:        return 1;
        !           470: }
        !           471: 
        !           472: void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
        !           473:                      STRUCT_STAT *stp, int itemizing, enum logcode code,
        !           474:                      int alt_dest)
        !           475: {
        !           476:        stat_x prev_sx;
        !           477:        STRUCT_STAT st;
        !           478:        char prev_name[MAXPATHLEN], alt_name[MAXPATHLEN];
        !           479:        const char *our_name;
        !           480:        struct file_list *flist;
        !           481:        int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
        !           482: 
        !           483:        if (stp == NULL && prev_ndx >= 0) {
        !           484:                if (link_stat(fname, &st, 0) < 0) {
        !           485:                        rsyserr(FERROR_XFER, errno, "stat %s failed",
        !           486:                                full_fname(fname));
        !           487:                        return;
        !           488:                }
        !           489:                stp = &st;
        !           490:        }
        !           491: 
        !           492:        /* FIRST combined with DONE means we were the first to get done. */
        !           493:        file->flags |= FLAG_HLINK_FIRST | FLAG_HLINK_DONE;
        !           494:        F_HL_PREV(file) = alt_dest;
        !           495:        if (alt_dest >= 0 && dry_run) {
        !           496:                pathjoin(alt_name, MAXPATHLEN, basis_dir[alt_dest],
        !           497:                         f_name(file, NULL));
        !           498:                our_name = alt_name;
        !           499:        } else
        !           500:                our_name = fname;
        !           501: 
        !           502: #ifdef SUPPORT_ACLS
        !           503:        prev_sx.acc_acl = prev_sx.def_acl = NULL;
        !           504: #endif
        !           505: #ifdef SUPPORT_XATTRS
        !           506:        prev_sx.xattr = NULL;
        !           507: #endif
        !           508: 
        !           509:        while ((ndx = prev_ndx) >= 0) {
        !           510:                int val;
        !           511:                flist = flist_for_ndx(ndx, "finish_hard_link");
        !           512:                file = flist->files[ndx - flist->ndx_start];
        !           513:                file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
        !           514:                prev_ndx = F_HL_PREV(file);
        !           515:                F_HL_PREV(file) = fin_ndx;
        !           516:                prev_statret = link_stat(f_name(file, prev_name), &prev_sx.st, 0);
        !           517:                val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
        !           518:                                      our_name, stp, fname, itemizing, code);
        !           519:                flist->in_progress--;
        !           520: #ifdef SUPPORT_ACLS
        !           521:                if (preserve_acls)
        !           522:                        free_acl(&prev_sx);
        !           523: #endif
        !           524: #ifdef SUPPORT_XATTRS
        !           525:                if (preserve_xattrs)
        !           526:                        free_xattr(&prev_sx);
        !           527: #endif
        !           528:                if (val < 0)
        !           529:                        continue;
        !           530:                if (remove_source_files == 1 && do_xfers)
        !           531:                        send_msg_int(MSG_SUCCESS, ndx);
        !           532:        }
        !           533: 
        !           534:        if (inc_recurse) {
        !           535:                int gnum = F_HL_GNUM(file);
        !           536:                struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
        !           537:                if (node == NULL) {
        !           538:                        rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name));
        !           539:                        exit_cleanup(RERR_MESSAGEIO);
        !           540:                }
        !           541:                if (node->data == NULL) {
        !           542:                        rprintf(FERROR, "Hlink node data for %d is NULL (%s)\n", gnum, f_name(file, prev_name));
        !           543:                        exit_cleanup(RERR_MESSAGEIO);
        !           544:                }
        !           545:                if (CVAL(node->data, 0) != 0) {
        !           546:                        rprintf(FERROR, "Hlink node data for %d already has path=%s (%s)\n",
        !           547:                                gnum, (char*)node->data, f_name(file, prev_name));
        !           548:                        exit_cleanup(RERR_MESSAGEIO);
        !           549:                }
        !           550:                free(node->data);
        !           551:                if (!(node->data = strdup(our_name)))
        !           552:                        out_of_memory("finish_hard_link");
        !           553:        }
        !           554: }
        !           555: 
        !           556: int skip_hard_link(struct file_struct *file, struct file_list **flist_p)
        !           557: {
        !           558:        struct file_list *flist;
        !           559:        int prev_ndx;
        !           560: 
        !           561:        file->flags |= FLAG_SKIP_HLINK;
        !           562:        if (!(file->flags & FLAG_HLINK_LAST))
        !           563:                return -1;
        !           564: 
        !           565:        check_prior(file, F_HL_GNUM(file), &prev_ndx, &flist);
        !           566:        if (prev_ndx >= 0) {
        !           567:                file = flist->files[prev_ndx - flist->ndx_start];
        !           568:                if (file->flags & (FLAG_HLINK_DONE|FLAG_FILE_SENT))
        !           569:                        return -1;
        !           570:                file->flags |= FLAG_HLINK_LAST;
        !           571:                *flist_p = flist;
        !           572:        }
        !           573: 
        !           574:        return prev_ndx;
        !           575: }
        !           576: #endif

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