X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/85aecef6c346c6cd76e0108be257a85783cde17d..68207537326987e28d42ad3b2fe53bdb1ebcc781:/flist.c diff --git a/flist.c b/flist.c index 06b75ba9..4415a834 100644 --- a/flist.c +++ b/flist.c @@ -28,7 +28,6 @@ #include "rsync.h" extern int verbose; -extern int dry_run; extern int list_only; extern int am_root; extern int am_server; @@ -43,10 +42,10 @@ extern int recurse; extern int xfer_dirs; extern int filesfrom_fd; extern int one_file_system; +extern int copy_dirlinks; extern int keep_dirlinks; extern int preserve_links; extern int preserve_hard_links; -extern int preserve_perms; extern int preserve_devices; extern int preserve_specials; extern int preserve_uid; @@ -58,7 +57,7 @@ extern int copy_links; extern int copy_unsafe_links; extern int protocol_version; extern int sanitize_paths; -extern int orig_umask; +extern const char *io_write_phase; extern struct stats stats; extern struct file_list *the_file_list; @@ -76,7 +75,6 @@ unsigned int file_struct_len; static char empty_sum[MD4_SUM_LENGTH]; static int flist_count_offset; -static int max_dir_depth = 0; static void clean_flist(struct file_list *flist, int strip_root, int no_dups); static void output_flist(struct file_list *flist); @@ -131,26 +129,26 @@ void show_flist_stats(void) static void list_file_entry(struct file_struct *f) { - char perms[11]; + char permbuf[PERMSTRING_SIZE]; if (!f->basename) { /* this can happen if duplicate names were removed */ return; } - permstring(perms, f->mode); + permstring(permbuf, f->mode); #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(f->mode)) { rprintf(FINFO, "%s %11.0f %s %s -> %s\n", - perms, + permbuf, (double)f->length, timestring(f->modtime), f_name(f, NULL), f->u.link); } else #endif { rprintf(FINFO, "%s %11.0f %s %s\n", - perms, + permbuf, (double)f->length, timestring(f->modtime), f_name(f, NULL)); } @@ -175,7 +173,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf) #ifdef SUPPORT_LINKS if (copy_links) return do_stat(path, buffer); - if (link_stat(path, buffer, 0) < 0) + if (link_stat(path, buffer, copy_dirlinks) < 0) return -1; if (S_ISLNK(buffer->st_mode)) { int l = readlink((char *)path, linkbuf, MAXPATHLEN - 1); @@ -635,8 +633,6 @@ static struct file_struct *receive_file_entry(struct file_list *flist, bp[-1] = '\0'; lastdir_depth = count_dir_elements(lastdir); file->dir.depth = lastdir_depth + 1; - if (lastdir_depth >= max_dir_depth) - max_dir_depth = lastdir_depth + 1; } else if (dirname) { file->dirname = dirname; /* we're reusing lastname */ file->dir.depth = lastdir_depth + 1; @@ -716,12 +712,6 @@ static struct file_struct *receive_file_entry(struct file_list *flist, read_buf(f, sum, checksum_len); } - if (!preserve_perms) { - /* set an appropriate set of permissions based on original - * permissions and umask. This emulates what GNU cp does */ - file->mode &= ~orig_umask; - } - return file; } @@ -1150,7 +1140,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) && (len == 1 || fbuf[len-2] == '/'); } - if (link_stat(fbuf, &st, keep_dirlinks) != 0) { + if (link_stat(fbuf, &st, copy_dirlinks) != 0) { io_error |= IOERR_GENERAL; rsyserr(FERROR, errno, "link_stat %s failed", full_fname(fbuf)); @@ -1265,7 +1255,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (fn != p || (*lp && *lp != '/')) { int save_copy_links = copy_links; int save_xfer_dirs = xfer_dirs; - copy_links = copy_unsafe_links; + copy_links |= copy_unsafe_links; xfer_dirs = 1; while ((slash = strchr(slash+1, '/')) != 0) { *slash = '\0'; @@ -1375,7 +1365,7 @@ struct file_list *recv_file_list(int f) flags |= read_byte(f) << 8; file = receive_file_entry(flist, flags, f); - if (S_ISREG(file->mode)) + if (S_ISREG(file->mode) || S_ISLNK(file->mode)) stats.total_size += file->length; flist->files[flist->count++] = file; @@ -1439,7 +1429,7 @@ static int file_compare(struct file_struct **file1, struct file_struct **file2) int flist_find(struct file_list *flist, struct file_struct *f) { int low = flist->low, high = flist->high; - int ret, mid, mid_up; + int diff, mid, mid_up; while (low <= high) { mid = (low + high) / 2; @@ -1469,18 +1459,18 @@ int flist_find(struct file_list *flist, struct file_struct *f) continue; } } - ret = f_name_cmp(flist->files[mid_up], f); - if (ret == 0) { + diff = f_name_cmp(flist->files[mid_up], f); + if (diff == 0) { if (protocol_version < 29 && S_ISDIR(flist->files[mid_up]->mode) != S_ISDIR(f->mode)) return -1; return mid_up; } - if (ret > 0) - high = mid - 1; - else + if (diff < 0) low = mid_up + 1; + else + high = mid - 1; } return -1; } @@ -1489,16 +1479,15 @@ int flist_find(struct file_list *flist, struct file_struct *f) * Free up any resources a file_struct has allocated * and clear the file. */ -void clear_file(int i, struct file_list *flist) +void clear_file(struct file_struct *file, struct file_list *flist) { - 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. */ + * that we're alone for now since flist_find() will adjust the counts + * it runs into that aren't up-to-date. */ file->length = file->dir.depth = 1; } @@ -1608,7 +1597,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) flist->files[keep]->flags |= flist->files[drop]->flags & (FLAG_TOP_DIR|FLAG_DEL_HERE); - clear_file(drop, flist); + clear_file(flist->files[drop], flist); if (keep == i) { if (flist->low == drop) { @@ -1639,38 +1628,58 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups) } } - if (prune_empty_dirs && no_dups && max_dir_depth) { - int j, cur_depth = 0; - int *maybe_dirs = new_array(int, max_dir_depth); + if (prune_empty_dirs && no_dups) { + int j, prev_depth = 0; - maybe_dirs[0] = -1; + prev_i = 0; /* It's OK that this isn't really true. */ for (i = flist->low; i <= flist->high; i++) { - struct file_struct *file = flist->files[i]; + struct file_struct *fp, *file = flist->files[i]; + /* This temporarily abuses the dir.depth value for a + * directory that is in a chain that might get pruned. + * We restore the old value if it gets a reprieve. */ if (S_ISDIR(file->mode) && file->dir.depth) { - j = cur_depth; - cur_depth = file->dir.depth - 1; - for ( ; j >= cur_depth; j--) { - if (maybe_dirs[j] < 0) - continue; - clear_file(maybe_dirs[j], flist); + /* Dump empty dirs when coming back down. */ + for (j = prev_depth; j >= file->dir.depth; j--) { + fp = flist->files[prev_i]; + if (fp->dir.depth >= 0) + break; + prev_i = -fp->dir.depth-1; + clear_file(fp, flist); } + prev_depth = file->dir.depth; if (is_excluded(f_name(file, fbuf), 1, ALL_FILTERS)) { - for (j = 0; j <= cur_depth; j++) - maybe_dirs[j] = -1; + /* Keep dirs through this dir. */ + for (j = prev_depth-1; ; j--) { + fp = flist->files[prev_i]; + if (fp->dir.depth >= 0) + break; + prev_i = -fp->dir.depth-1; + fp->dir.depth = j; + } } else - maybe_dirs[cur_depth] = i; - } else if (maybe_dirs[cur_depth] >= 0) { - for (j = 0; j <= cur_depth; j++) - maybe_dirs[j] = -1; + file->dir.depth = -prev_i-1; + prev_i = i; + } else { + /* Keep dirs through this non-dir. */ + for (j = prev_depth; ; j--) { + fp = flist->files[prev_i]; + if (fp->dir.depth >= 0) + break; + prev_i = -fp->dir.depth-1; + fp->dir.depth = j; + } } } - for (j = cur_depth; j >= 0; j--) { - if (maybe_dirs[j] < 0) - continue; - clear_file(maybe_dirs[j], flist); + /* Dump empty all remaining empty dirs. */ + while (1) { + struct file_struct *fp = flist->files[prev_i]; + if (fp->dir.depth >= 0) + break; + prev_i = -fp->dir.depth-1; + clear_file(fp, flist); } for (i = flist->low; i <= flist->high; i++) { @@ -1900,6 +1909,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, struct file_list *dirlist; char dirbuf[MAXPATHLEN]; int save_recurse = recurse; + int save_xfer_dirs = xfer_dirs; if (dlen < 0) { dlen = strlcpy(dirbuf, dirname, MAXPATHLEN); @@ -1911,7 +1921,9 @@ struct file_list *get_dirlist(char *dirname, int dlen, dirlist = flist_new(WITHOUT_HLINK, "get_dirlist"); recurse = 0; + xfer_dirs = 1; send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen); + xfer_dirs = save_xfer_dirs; recurse = save_recurse; if (do_progress) flist_count_offset += dirlist->count;