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

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

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