From matt at mattmccutchen.net Sun Nov 2 17:51:35 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sun, 02 Nov 2008 20:51:35 -0500 Subject: [Rsync-patches] [PATCH] The protect filter automatically added with --backup is not perishable In-Reply-To: <1225599783.2688.24.camel@mattlaptop2.local> References: <1225599783.2688.24.camel@mattlaptop2.local> Message-ID: <1225677095.19996.4.camel@mattlaptop2.local> (see f41152d39396f0672a97268739c333537579404a), so remove the inaccurate "p" from the man page. Noticed by Jacob Balazer: http://lists.samba.org/archive/rsync/2008-November/022022.html --- rsync.yo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/rsync.yo b/rsync.yo index 1daff0c..bcf082f 100644 --- a/rsync.yo +++ b/rsync.yo @@ -714,7 +714,7 @@ Note that if you don't specify bf(--backup-dir), (1) the bf(--omit-dir-times) option will be implied, and (2) if bf(--delete) is also in effect (without bf(--delete-excluded)), rsync will add a "protect" filter-rule for the backup suffix to the end of all your existing excludes -(e.g. bf(-f "Pp *~")). This will prevent previously backed-up files from being +(e.g. bf(-f "P *~")). This will prevent previously backed-up files from being deleted. Note that if you are supplying your own filter rules, you may need to manually insert your own exclude/protect rule somewhere higher up in the list so that it has a high enough priority to be effective (e.g., if -- 1.6.0.2.593.g91df From matt at mattmccutchen.net Sun Nov 2 19:22:20 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sun, 02 Nov 2008 22:22:20 -0500 Subject: [Rsync-patches] [PATCH] Make delete_in_dir use a directoryness-insensitive file-list search. In-Reply-To: <1225542578.2688.4.camel@mattlaptop2.local> References: <1225542578.2688.4.camel@mattlaptop2.local> Message-ID: <1225682540.19996.20.camel@mattlaptop2.local> delete_in_dir uses flist_find to determine whether a destination file is matched in the file list and thus shouldn't be deleted. But flist_find is directoryness-sensitive, so rsync prematurely deleted a dir that was to be replaced by a non-dir (or vice versa) during the delete pass. This led to inconsistent itemization and --max-delete counting of such replacements and necessated an ugly hack in make_file for --keep-dirlinks to work at all with --delete. The failure of this hack in incremental recursion mode was noticed by eric casteleijn: http://lists.samba.org/archive/rsync/2008-November/022019.html This patch changes delete_in_dir to use a new flist_find_ignore_dirness function, fixing the inconsistencies, and removes the obsolete chunk of code from make_file. --- This patch, which is in wip/delete-dirness of my repository, seems to fix the problem but needs further testing. I plan to write a test case. Matt flist.c | 41 ++++++++++++++++++++++------------------- generator.c | 5 ++++- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/flist.c b/flist.c index cb667aa..6042b00 100644 --- a/flist.c +++ b/flist.c @@ -1332,25 +1332,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, else if (!pool) F_DEPTH(file) = extra_len / EXTRA_LEN; - /* This code is only used by the receiver when it is building - * a list of files for a delete pass. */ - if (keep_dirlinks && linkname_len && flist) { - STRUCT_STAT st2; - int save_mode = file->mode; - file->mode = S_IFDIR; /* Find a directory with our name. */ - if (flist_find(dir_flist, file) >= 0 - && x_stat(thisname, &st2, NULL) == 0 && S_ISDIR(st2.st_mode)) { - file->modtime = st2.st_mtime; - file->len32 = 0; - file->mode = st2.st_mode; - if (uid_ndx) - F_OWNER(file) = st2.st_uid; - if (gid_ndx) - F_GROUP(file) = st2.st_gid; - } else - file->mode = save_mode; - } - if (basename_len == 0+1) { if (!pool) unmake_file(file); @@ -2533,6 +2514,28 @@ int flist_find(struct file_list *flist, struct file_struct *f) return -1; } +/* Search for an identically-named item in the file list. Differs from + * flist_find in that an item that agrees with "f" in directory-ness is + * preferred but one that does not is still found. */ +int flist_find_ignore_dirness(struct file_list *flist, struct file_struct *f) +{ + mode_t save_mode; + int ndx; + + /* First look for an item that agrees in directory-ness. */ + ndx = flist_find(flist, f); + if (ndx >= 0) + return ndx; + + /* Temporarily flip f->mode to look for an item of opposite + * directory-ness. */ + save_mode = f->mode; + f->mode = S_ISDIR(f->mode) ? S_IFREG : S_IFDIR; + ndx = flist_find(flist, f); + f->mode = save_mode; + return ndx; +} + /* * Free up any resources a file_struct has allocated * and clear the file. diff --git a/generator.c b/generator.c index 6a0d527..1db0fe0 100644 --- a/generator.c +++ b/generator.c @@ -535,7 +535,10 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) f_name(fp, NULL)); continue; } - if (flist_find(cur_flist, fp) < 0) { + /* Here we want to match regardless of file type. Replacement + * of a file with one of another type is handled separately by + * a delete_item call with a DEL_MAKE_ROOM flag. */ + if (flist_find_ignore_dirness(cur_flist, fp) < 0) { int flags = DEL_RECURSE; if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid) flags |= DEL_NO_UID_WRITE; -- 1.6.0.2.593.g91df