Changed --skip-empty-dirs (-k) to --prune-empty-dirs (-m) and
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index f66a4e2..851e306 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -1443,11 +1443,33 @@ int flist_find(struct file_list *flist, struct file_struct *f)
 
        while (low <= high) {
                mid = (low + high) / 2;
-               for (mid_up = mid; !flist->files[mid_up]->basename; mid_up++) {}
-               if (mid_up <= high)
-                       ret = f_name_cmp(flist->files[mid_up], f);
-               else
-                       ret = 1;
+               if (flist->files[mid]->basename)
+                       mid_up = mid;
+               else {
+                       /* Scan for the next non-empty entry using the cached
+                        * distance values.  If the value isn't fully up-to-
+                        * date, update it. */
+                       while (1) {
+                               mid_up = mid + flist->files[mid]->dir.depth;
+                               if (flist->files[mid_up]->basename)
+                                       break;
+                               flist->files[mid]->dir.depth
+                                       += flist->files[mid_up]->dir.depth;
+                       }
+                       if (mid_up > high) {
+                               /* If there's nothing left above us, set high to
+                                * a non-empty entry below us and continue. */
+                               while (1) {
+                                       high = mid - flist->files[mid]->length;
+                                       if (flist->files[high]->basename)
+                                               break;
+                                       flist->files[mid]->length
+                                               += flist->files[high]->length;
+                               }
+                               continue;
+                       }
+               }
+               ret = f_name_cmp(flist->files[mid_up], f);
                if (ret == 0) {
                        if (protocol_version < 29
                            && S_ISDIR(flist->files[mid_up]->mode)
@@ -1469,9 +1491,15 @@ int flist_find(struct file_list *flist, struct file_struct *f)
  */
 void clear_file(int i, struct file_list *flist)
 {
-       if (flist->hlink_pool && flist->files[i]->link_u.idev)
-               pool_free(flist->hlink_pool, 0, flist->files[i]->link_u.idev);
-       memset(flist->files[i], 0, file_struct_len);
+       struct file_struct *file = flist->files[i];
+       if (flist->hlink_pool && file->link_u.idev)
+               pool_free(flist->hlink_pool, 0, file->link_u.idev);
+       memset(file, 0, file_struct_len);
+       /* In an empty entry, dir.depth is an offset to the next non-empty
+        * entry.  Likewise for length in the opposite direction.  We assume
+        * that we're alone for now since flist_find() will collate adjacent
+        * items for any entries that are encountered during the find. */
+       file->length = file->dir.depth = 1;
 }
 
 /*
@@ -1544,20 +1572,6 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
 
                if (!file->basename)
                        continue;
-
-               if (strip_root && file->dirname) {
-                       /* We need to strip off the leading slashes for
-                        * relative paths, but this must be done _after_
-                        * the sorting phase (above). */
-                       if (*file->dirname == '/') {
-                               char *s = file->dirname + 1;
-                               while (*s == '/') s++;
-                               memmove(file->dirname, s, strlen(s) + 1);
-                       }
-                       if (!*file->dirname)
-                               file->dirname = NULL;
-               }
-
                if (f_name_cmp(file, flist->files[prev_i]) == 0)
                        j = prev_i;
                else if (protocol_version >= 29 && S_ISDIR(file->mode)) {
@@ -1570,7 +1584,6 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
                        file->mode = save_mode;
                } else
                        j = -1;
-
                if (j >= 0) {
                        struct file_struct *fp = flist->files[j];
                        int keep, drop;
@@ -1610,6 +1623,21 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
        }
        flist->high = no_dups ? prev_i : flist->count - 1;
 
+       if (strip_root) {
+               /* We need to strip off the leading slashes for relative
+                * paths, but this must be done _after_ the sorting phase. */
+               for (i = flist->low; i <= flist->high; i++) {
+                       struct file_struct *file = flist->files[i];
+
+                       if (!file->dirname)
+                               continue;
+                       while (*file->dirname == '/')
+                               file->dirname++;
+                       if (!*file->dirname)
+                               file->dirname = NULL;
+               }
+       }
+
        if (skip_empty_dirs && no_dups && max_dir_depth) {
                int j, cur_depth = 0;
                int *maybe_dirs = new_array(int, max_dir_depth);