X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/9c000f5e7bec6ddd1f488e2e2290fbf946a8de09..a1cc199b34b4bc65cba2dce0cbb04c18f17271ac:/flist.c diff --git a/flist.c b/flist.c index f66a4e20..06b75ba9 100644 --- a/flist.c +++ b/flist.c @@ -53,7 +53,7 @@ extern int preserve_uid; extern int preserve_gid; extern int relative_paths; extern int implied_dirs; -extern int skip_empty_dirs; +extern int prune_empty_dirs; extern int copy_links; extern int copy_unsafe_links; extern int protocol_version; @@ -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. */ + mid_up = mid + flist->files[mid]->dir.depth; + if (!flist->files[mid_up]->basename) { + do { + mid_up += flist->files[mid_up]->dir.depth; + } while (!flist->files[mid_up]->basename); + flist->files[mid]->dir.depth = mid_up - mid; + } + if (mid_up > high) { + /* If there's nothing left above us, set high to + * a non-empty entry below us and continue. */ + high = mid - flist->files[mid]->length; + if (!flist->files[high]->basename) { + do { + high -= flist->files[high]->length; + } while (!flist->files[high]->basename); + flist->files[mid]->length = mid - high; + } + 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; } /* @@ -1519,6 +1547,7 @@ void flist_free(struct file_list *flist) */ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) { + char fbuf[MAXPATHLEN]; int i, prev_i = 0; if (!flist) @@ -1544,20 +1573,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 +1585,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; @@ -1587,7 +1601,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) if (verbose > 1 && !am_server) { rprintf(FINFO, "removing duplicate name %s from file list (%d)\n", - f_name(file, NULL), drop); + f_name(file, fbuf), drop); } /* Make sure we don't lose track of a user-specified * top directory. */ @@ -1610,7 +1624,22 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) } flist->high = no_dups ? prev_i : flist->count - 1; - if (skip_empty_dirs && no_dups && max_dir_depth) { + 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 (prune_empty_dirs && no_dups && max_dir_depth) { int j, cur_depth = 0; int *maybe_dirs = new_array(int, max_dir_depth); @@ -1627,7 +1656,12 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) continue; clear_file(maybe_dirs[j], flist); } - maybe_dirs[cur_depth] = i; + if (is_excluded(f_name(file, fbuf), 1, + ALL_FILTERS)) { + for (j = 0; j <= cur_depth; j++) + maybe_dirs[j] = -1; + } else + maybe_dirs[cur_depth] = i; } else if (maybe_dirs[cur_depth] >= 0) { for (j = 0; j <= cur_depth; j++) maybe_dirs[j] = -1;