Make sure the generator doesn't try to send a negative checksum count to
[rsync/rsync.git] / hlink.c
diff --git a/hlink.c b/hlink.c
index 536b571..1e8adc8 100644 (file)
--- a/hlink.c
+++ b/hlink.c
@@ -37,7 +37,7 @@ extern int stdout_format_has_i;
 extern int maybe_ATTRS_REPORT;
 extern int unsort_ndx;
 extern char *basis_dir[];
-extern struct file_list *cur_flist;
+extern struct file_list *cur_flist, *first_flist;
 
 #ifdef SUPPORT_HARD_LINKS
 
@@ -249,17 +249,13 @@ static char *check_prior(struct file_struct *file, int gnum,
                         int *prev_ndx_p, struct file_list **flist_p)
 {
        struct file_struct *fp;
-       struct file_list *flist;
        struct ht_int32_node *node;
        int prev_ndx = F_HL_PREV(file);
 
        while (1) {
-               if (prev_ndx < 0) {
-                       *prev_ndx_p = prev_ndx;
-                       *flist_p = NULL;
-                       return NULL;
-               }
-               if ((flist = flist_for_ndx(prev_ndx)) == NULL)
+               struct file_list *flist;
+               if (prev_ndx < 0
+                || (flist = flist_for_ndx(prev_ndx)) == NULL)
                        break;
                fp = flist->files[prev_ndx - flist->ndx_start];
                if (!(fp->flags & FLAG_SKIP_HLINK)) {
@@ -270,20 +266,21 @@ static char *check_prior(struct file_struct *file, int gnum,
                F_HL_PREV(file) = prev_ndx = F_HL_PREV(fp);
        }
 
-       node = hashtable_find(prior_hlinks, gnum, 0);
-       assert(node != NULL && node->data);
-
-       if (CVAL(node->data, 0) == 0) {
+       if (inc_recurse
+        && (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
+               assert(node->data != NULL);
+               if (CVAL(node->data, 0) != 0) {
+                       *prev_ndx_p = -1;
+                       *flist_p = NULL;
+                       return node->data;
+               }
                /* The prior file must have been skipped. */
-               F_HL_PREV(file) = prev_ndx = -1;
-               *prev_ndx_p = prev_ndx;
-               *flist_p = NULL;
-               return NULL;
+               F_HL_PREV(file) = -1;
        }
 
-       *prev_ndx_p = prev_ndx;
-       *flist_p = flist;
-       return node->data;
+       *prev_ndx_p = -1;
+       *flist_p = NULL;
+       return NULL;
 }
 
 /* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not.  Returns:
@@ -450,7 +447,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
 {
        stat_x prev_sx;
        STRUCT_STAT st;
-       char alt_name[MAXPATHLEN], *prev_name;
+       char prev_name[MAXPATHLEN], alt_name[MAXPATHLEN];
        const char *our_name;
        struct file_list *flist;
        int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
@@ -481,13 +478,20 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
        while ((ndx = prev_ndx) >= 0) {
                int val;
                flist = flist_for_ndx(ndx);
-               assert(flist != NULL);
+               if (flist == NULL) {
+                       int start1 = first_flist ? first_flist->ndx_start : 0;
+                       int start2 = first_flist ? first_flist->prev->ndx_start : 0;
+                       int used = first_flist ? first_flist->prev->used : 0;
+                       rprintf(FERROR,
+                               "File index not found: %d (%d - %d)\n",
+                               ndx, start1 - 1, start2 + used - 1);
+                       exit_cleanup(RERR_PROTOCOL);
+               }
                file = flist->files[ndx - flist->ndx_start];
                file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
                prev_ndx = F_HL_PREV(file);
                F_HL_PREV(file) = fin_ndx;
-               prev_name = f_name(file, NULL);
-               prev_statret = link_stat(prev_name, &prev_sx.st, 0);
+               prev_statret = link_stat(f_name(file, prev_name), &prev_sx.st, 0);
                val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
                                      our_name, stp, fname, itemizing, code);
                flist->in_progress--;