X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/95a44066da8ffc6c37f2c05f2225ae9f2dcf4caf..a0f29ed824ff6fdae0d49826bf6bd810e3bca88a:/flist.c diff --git a/flist.c b/flist.c index 688117c9..dc06f05f 100644 --- a/flist.c +++ b/flist.c @@ -115,6 +115,7 @@ static char tmp_sum[MAX_DIGEST_LEN]; static char empty_sum[MAX_DIGEST_LEN]; static int flist_count_offset; /* for --delete --progress */ static int dir_count = 0; +static int high_hlink_ndx; static void clean_flist(struct file_list *flist, int strip_root); static void output_flist(struct file_list *flist); @@ -467,7 +468,8 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino); first_hlink_ndx = (int32)(long)np->data - 1; if (first_hlink_ndx < 0) { - np->data = (void*)(long)(ndx + first_ndx + 1); + high_hlink_ndx = ndx + first_ndx; + np->data = (void*)(long)(high_hlink_ndx + 1); xflags |= XMIT_HLINK_FIRST; } xflags |= XMIT_HLINKED; @@ -941,9 +943,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && xflags & XMIT_HLINKED) { if (protocol_version >= 30) { - F_HL_GNUM(file) = xflags & XMIT_HLINK_FIRST - ? flist->ndx_start + flist->used - : first_hlink_ndx; + if (xflags & XMIT_HLINK_FIRST) { + high_hlink_ndx = flist->ndx_start + flist->used; + F_HL_GNUM(file) = high_hlink_ndx; + } else + F_HL_GNUM(file) = first_hlink_ndx; } else { static int32 cnt = 0; struct ht_int64_node *np; @@ -1551,6 +1555,7 @@ void send_extra_file_list(int f, int at_least) while (future_cnt < at_least) { struct file_struct *file = dir_flist->sorted[send_dir_ndx]; int dir_ndx, dstart = dir_count; + const char *pathname = F_PATHNAME(file); int32 *dp; flist = flist_new(0, "send_extra_file_list"); @@ -1575,7 +1580,8 @@ void send_extra_file_list(int f, int at_least) && dir_flist->sorted[dir_ndx]->flags & FLAG_DUPLICATE) { send_dir_ndx = dir_ndx; file = dir_flist->sorted[dir_ndx]; - send1extra(f, file, flist); + if (F_PATHNAME(file) != pathname) + send1extra(f, file, flist); dp = F_DIR_NODE_P(file); } @@ -1791,16 +1797,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) dirlen = dir ? strlen(dir) : 0; if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) { if (!push_pathname(dir ? strdup(dir) : NULL, dirlen)) - goto push_error; + continue; lastdir = pathname; lastdir_len = pathname_len; - } else if (!push_pathname(lastdir, lastdir_len)) { - push_error: - io_error |= IOERR_GENERAL; - rsyserr(FERROR, errno, "push_dir %s failed in %s", - full_fname(dir), curr_dir); + } else if (!push_pathname(lastdir, lastdir_len)) continue; - } if (fn != fbuf) memmove(fbuf, fn, len + 1); @@ -2205,6 +2206,8 @@ struct file_list *flist_new(int flags, char *msg) flist->file_pool = first_flist->file_pool; flist->ndx_start = first_flist->prev->ndx_end + 2; + if (flist->ndx_start <= high_hlink_ndx) + flist->ndx_start = high_hlink_ndx + 1; flist->prev = first_flist->prev; flist->prev->next = first_flist->prev = flist; @@ -2303,19 +2306,20 @@ static void clean_flist(struct file_list *flist, int strip_root) int keep, drop; /* If one is a dir and the other is not, we want to * keep the dir because it might have contents in the - * list. */ + * list. Otherwise keep the first one. */ if (S_ISDIR(file->mode)) { struct file_struct *fp = flist->sorted[j]; - if (!S_ISDIR(fp->mode)) + if (!S_ISDIR(fp->mode) || !(fp->flags & FLAG_XFER_DIR)) keep = i, drop = j; - else + else { + if (am_sender) + file->flags |= FLAG_DUPLICATE; keep = j, drop = i; + } } else keep = j, drop = i; - if (am_sender) - flist->sorted[drop]->flags |= FLAG_DUPLICATE; - else { + if (!am_sender) { if (verbose > 1) { rprintf(FINFO, "removing duplicate name %s from file list (%d)\n",