X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/cc12c488aa71e66f4786fd60494d24e81e425868..e9489cd6cb380b30727bd3d074eacc59abca080e:/generator.c diff --git a/generator.c b/generator.c index c06ea0db..27e5b97d 100644 --- a/generator.c +++ b/generator.c @@ -97,7 +97,7 @@ extern char *backup_dir; extern char *backup_suffix; extern int backup_suffix_len; extern struct file_list *cur_flist, *first_flist, *dir_flist; -extern struct filter_list_struct server_filter_list; +extern struct filter_list_struct daemon_filter_list; int ignore_perishable = 0; int non_perishable_cnt = 0; @@ -557,10 +557,13 @@ static void do_delete_pass(void) for (j = 0; j < cur_flist->used; j++) { struct file_struct *file = cur_flist->sorted[j]; - if (!(file->flags & FLAG_CONTENT_DIR)) + f_name(file, fbuf); + + if (!(file->flags & FLAG_CONTENT_DIR)) { + change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file)); continue; + } - f_name(file, fbuf); if (verbose > 1 && file->flags & FLAG_TOP_DIR) rprintf(FINFO, "deleting in %s\n", fbuf); @@ -1213,6 +1216,14 @@ static void list_file_entry(struct file_struct *f) static int phase = 0; static int dflt_perms; +static int implied_dirs_are_missing; +/* Helper for recv_generator's skip_dir and dry_missing_dir tests. */ +static BOOL is_below(struct file_struct *file, struct file_struct *subtree) +{ + return F_DEPTH(file) > F_DEPTH(subtree) + && (!implied_dirs_are_missing || f_name_has_prefix(file, subtree)); +} + /* Acts on the indicated item in cur_flist whose name is fname. If a dir, * make sure it exists, and has the right permissions/timestamp info. For * all other non-regular files (symlinks, etc.) we create them here. For @@ -1227,9 +1238,12 @@ static int dflt_perms; static void recv_generator(char *fname, struct file_struct *file, int ndx, int itemizing, enum logcode code, int f_out) { - static int missing_below = -1; static const char *parent_dirname = ""; - static struct file_struct *missing_dir = NULL; + /* Missing dir not created due to --dry-run; will still be scanned. */ + static struct file_struct *dry_missing_dir = NULL; + /* Missing dir whose contents are skipped altogether due to + * --ignore-non-existing, daemon exclude, or mkdir failure. */ + static struct file_struct *skip_dir = NULL; static struct file_list *fuzzy_dirlist = NULL; static int need_fuzzy_dirlist = 0; struct file_struct *fuzzy_file = NULL; @@ -1241,7 +1255,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, char *fnamecmp, *partialptr, *backupptr = NULL; char fnamecmpbuf[MAXPATHLEN]; uchar fnamecmp_type; - int implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30; int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0; int is_dir = !S_ISDIR(file->mode) ? 0 : inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1 @@ -1258,25 +1271,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, return; } - if (missing_below >= 0) { - if (F_DEPTH(file) <= missing_below - || (implied_dirs_are_missing && !f_name_has_prefix(file, missing_dir))) { - if (dry_run) - dry_run--; - missing_below = -1; - } else if (!dry_run) { + if (skip_dir) { + if (is_below(file, skip_dir)) { if (is_dir) file->flags |= FLAG_MISSING_DIR; #ifdef SUPPORT_HARD_LINKS - if (F_IS_HLINKED(file)) + else if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif return; } + skip_dir = NULL; } - if (server_filter_list.head) { - if (check_filter(&server_filter_list, fname, is_dir) < 0) { + if (daemon_filter_list.head && (*fname != '.' || fname[1])) { + if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) { if (is_dir < 0) return; #ifdef SUPPORT_HARD_LINKS @@ -1298,7 +1307,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, #ifdef SUPPORT_XATTRS sx.xattr = NULL; #endif - if (dry_run > 1) { + if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) { + parent_is_dry_missing: if (fuzzy_dirlist) { flist_free(fuzzy_dirlist); fuzzy_dirlist = NULL; @@ -1308,13 +1318,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, stat_errno = ENOENT; } else { const char *dn = file->dirname ? file->dirname : "."; + dry_missing_dir = NULL; if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) { if (relative_paths && !implied_dirs - && do_stat(dn, &sx.st) < 0 - && create_directory_path(fname) < 0) { - rsyserr(FERROR_XFER, errno, - "recv_generator: mkdir %s failed", - full_fname(dn)); + && do_stat(dn, &sx.st) < 0) { + if (dry_run) + goto parent_is_dry_missing; + if (create_directory_path(fname) < 0) { + rsyserr(FERROR_XFER, errno, + "recv_generator: mkdir %s failed", + full_fname(dn)); + } } if (fuzzy_dirlist) { flist_free(fuzzy_dirlist); @@ -1343,12 +1357,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, if (is_dir) { if (is_dir < 0) return; - if (missing_below < 0) { - if (dry_run) - dry_run++; - missing_below = F_DEPTH(file); - missing_dir = file; - } + skip_dir = file; file->flags |= FLAG_MISSING_DIR; } #ifdef SUPPORT_HARD_LINKS @@ -1404,10 +1413,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto skipping_dir_contents; statret = -1; } - if (dry_run && statret != 0 && missing_below < 0) { - missing_below = F_DEPTH(file); - missing_dir = file; - dry_run++; + if (dry_run && statret != 0) { + if (!dry_missing_dir) + dry_missing_dir = file; + file->flags |= FLAG_MISSING_DIR; } real_ret = statret; real_sx = sx; @@ -1440,8 +1449,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, skipping_dir_contents: rprintf(FERROR, "*** Skipping any contents from this failed directory ***\n"); - missing_below = F_DEPTH(file); - missing_dir = file; + skip_dir = file; file->flags |= FLAG_MISSING_DIR; goto cleanup; } @@ -1474,9 +1482,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, DEV_MINOR(devp) = minor(real_sx.st.st_dev); } } - else if (delete_during && f_out != -1 && !phase && dry_run < 2 - && (file->flags & FLAG_CONTENT_DIR)) - delete_in_dir(fname, file, &real_sx.st.st_dev); + else if (delete_during && f_out != -1 && !phase + && !(file->flags & FLAG_MISSING_DIR)) { + if (file->flags & FLAG_CONTENT_DIR) + delete_in_dir(fname, file, &real_sx.st.st_dev); + else + change_local_filter_dir(fname, strlen(fname), F_DEPTH(file)); + } goto cleanup; } @@ -1729,7 +1741,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } else partialptr = NULL; - if (statret != 0 && fuzzy_dirlist && dry_run <= 1) { + if (statret != 0 && fuzzy_dirlist) { int j = find_fuzzy(file, fuzzy_dirlist); if (j >= 0) { fuzzy_file = fuzzy_dirlist->files[j]; @@ -1856,15 +1868,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, close(fd); goto cleanup; } - if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0 - && (errno != ENOENT || make_bak_dir(backupptr) < 0 - || (f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0)) { - rsyserr(FERROR_XFER, errno, "open %s", - full_fname(backupptr)); - unmake_file(back_file); - back_file = NULL; - close(fd); - goto cleanup; + if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) { + int save_errno = errno ? errno : EINVAL; /* 0 paranoia */ + if (errno == ENOENT && make_bak_dir(backupptr) == 0) { + if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) + save_errno = errno ? errno : save_errno; + else + save_errno = 0; + } + if (save_errno) { + rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(backupptr)); + unmake_file(back_file); + back_file = NULL; + close(fd); + goto cleanup; + } } fnamecmp_type = FNAMECMP_BACKUP; } @@ -1926,9 +1944,16 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, cleanup: if (back_file) { + int save_preserve_xattrs = preserve_xattrs; if (f_copy >= 0) close(f_copy); +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) + copy_xattrs(fname, backupptr); +#endif + preserve_xattrs = 0; set_file_attrs(backupptr, back_file, NULL, NULL, 0); + preserve_xattrs = save_preserve_xattrs; if (verbose > 1) { rprintf(FINFO, "backed up %s to %s\n", fname, backupptr); @@ -2125,6 +2150,7 @@ void generate_files(int f_out, const char *local_name) lull_mod = allowed_lull * 5; symlink_timeset_failed_flags = ITEM_REPORT_TIME | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0); + implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30; if (verbose > 2) rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid()); @@ -2169,16 +2195,18 @@ void generate_files(int f_out, const char *local_name) f_name(fp, fbuf); ndx = cur_flist->ndx_start - 1; recv_generator(fbuf, fp, ndx, itemizing, code, f_out); - if (delete_during && dry_run < 2 && !list_only) { - if (BITS_SETnUNSET(fp->flags, FLAG_CONTENT_DIR, FLAG_MISSING_DIR)) { + if (delete_during && dry_run < 2 && !list_only + && !(fp->flags & FLAG_MISSING_DIR)) { + if (fp->flags & FLAG_CONTENT_DIR) { dev_t dirdev; if (one_file_system) { uint32 *devp = F_DIR_DEV_P(fp); dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); } else dirdev = MAKEDEV(0, 0); - delete_in_dir(f_name(fp, fbuf), fp, &dirdev); - } + delete_in_dir(fbuf, fp, &dirdev); + } else + change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp)); } } for (i = cur_flist->low; i <= cur_flist->high; i++) {