char *end = rel + strlen(rel);
char *p = end;
-@@ -183,7 +208,8 @@ static int keep_backup(char *fname)
+@@ -185,7 +210,8 @@ static int keep_backup(char *fname)
if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
return 1; /* the file could have disappeared */
return 0;
/* Check to see if this is a device file, or link */
-@@ -278,3 +304,13 @@ int make_backup(char *fname)
+@@ -280,3 +306,13 @@ int make_backup(char *fname)
return keep_backup(fname);
return make_simple_backup(fname);
}
extern struct file_list *the_file_list;
extern struct filter_list_struct server_filter_list;
-@@ -114,10 +117,14 @@ enum delret {
+@@ -115,10 +118,14 @@ enum delret {
static enum delret delete_dir_contents(char *fname, int flags);
}
/* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
-@@ -153,9 +160,9 @@ static enum delret delete_item(char *fna
+@@ -154,9 +161,9 @@ static enum delret delete_item(char *fbu
if (S_ISDIR(mode)) {
what = "rmdir";
- ok = do_rmdir(fname) == 0;
-- } else if (make_backups && (backup_dir || !is_backup_file(fname))) {
-+ } else if (make_backups && (backup_dir_dels || !is_backup_file(fname))) {
+ ok = do_rmdir(fbuf) == 0;
+- } else if (make_backups && (backup_dir || !is_backup_file(fbuf))) {
++ } else if (make_backups && (backup_dir_dels || !is_backup_file(fbuf))) {
what = "make_backup";
-- ok = make_backup(fname);
-+ ok = safe_delete(fname);
+- ok = make_backup(fbuf);
++ ok = safe_delete(fbuf);
} else {
what = "unlink";
- ok = robust_unlink(fname) == 0;
+ ok = robust_unlink(fbuf) == 0;
--- old/options.c
+++ new/options.c
@@ -138,10 +138,14 @@ int no_detach
rprintf(F," -u, --update skip files that are newer on the receiver\n");
rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n");
rprintf(F," --append append data onto shorter files\n");
-@@ -518,7 +526,9 @@ static struct poptOption long_options[]
+@@ -520,7 +528,9 @@ static struct poptOption long_options[]
{"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 },
{"backup", 'b', POPT_ARG_NONE, &make_backups, 0, 0, 0 },
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
{"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
{"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
{"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
-@@ -1232,6 +1242,8 @@ int parse_arguments(int *argc, const cha
+@@ -1234,6 +1244,8 @@ int parse_arguments(int *argc, const cha
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, NULL);
if (backup_dir)
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, NULL);
}
if (server_filter_list.head && !am_sender) {
struct filter_list_struct *elp = &server_filter_list;
-@@ -1249,6 +1261,14 @@ int parse_arguments(int *argc, const cha
+@@ -1251,6 +1263,14 @@ int parse_arguments(int *argc, const cha
if (check_filter(elp, backup_dir, 1) < 0)
goto options_rejected;
}
}
if (!backup_suffix)
-@@ -1260,6 +1280,16 @@ int parse_arguments(int *argc, const cha
+@@ -1262,6 +1282,16 @@ int parse_arguments(int *argc, const cha
backup_suffix);
return 0;
}
if (backup_dir) {
backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
-@@ -1283,6 +1313,31 @@ int parse_arguments(int *argc, const cha
+@@ -1285,6 +1315,31 @@ int parse_arguments(int *argc, const cha
"P *%s", backup_suffix);
parse_rule(&filter_list, backup_dir_buf, 0, 0);
}
if (make_backups && !backup_dir)
omit_dir_times = 1;
-@@ -1647,6 +1702,10 @@ void server_options(char **args,int *arg
+@@ -1649,6 +1704,10 @@ void server_options(char **args,int *arg
args[ac++] = "--backup-dir";
args[ac++] = backup_dir;
}
/* Only send --suffix if it specifies a non-default value. */
if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
-@@ -1655,7 +1714,13 @@ void server_options(char **args,int *arg
+@@ -1657,7 +1716,13 @@ void server_options(char **args,int *arg
goto oom;
args[ac++] = arg;
}
extern int whole_file;
extern int list_only;
extern int new_root_dir;
-@@ -91,14 +92,17 @@ extern char *backup_dir;
+@@ -91,15 +92,18 @@ extern char *backup_dir;
extern char *backup_suffix;
extern int backup_suffix_len;
extern struct file_list *the_file_list;
static int deletion_count = 0; /* used to implement --max-delete */
+static int unexplored_dirs = 1;
+ static FILE *delete_delay_fp = NULL;
-/* For calling delete_item() and delete_dir_contents(). */
+/* For calling delete_item(), delete_dir_contents(), and delete_in_dir(). */
#define DEL_RECURSE (1<<1) /* recurse */
#define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */
-@@ -120,11 +124,120 @@ static int is_backup_file(char *fn)
+@@ -121,11 +125,120 @@ static int is_backup_file(char *fn)
return k > 0 && strcmp(fn+k, backup_suffix) == 0;
}
/* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
* delete recursively.
*
- * Note that fname must point to a MAXPATHLEN buffer if the mode indicates it's
+ * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
* a directory! (The buffer is used for recursion, but returned unchanged.)
+ *
+ * Also note: --detect-rename may use this routine with DEL_NO_DELETIONS set!
*/
- static enum delret delete_item(char *fname, int mode, char *replace, int flags)
+ static enum delret delete_item(char *fbuf, int mode, char *replace, int flags)
{
-@@ -146,6 +259,8 @@ static enum delret delete_item(char *fna
+@@ -147,6 +260,8 @@ static enum delret delete_item(char *fbu
goto check_ret;
/* OK: try to delete the directory. */
}
if (!replace && max_delete >= 0 && ++deletion_count > max_delete)
return DR_AT_LIMIT;
-@@ -192,6 +307,8 @@ static enum delret delete_item(char *fna
+@@ -193,6 +308,8 @@ static enum delret delete_item(char *fbu
* its contents, otherwise just checks for content. Returns DR_SUCCESS or
* DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
* buffer is used for recursion, but returned unchanged.)
*/
static enum delret delete_dir_contents(char *fname, int flags)
{
-@@ -248,6 +365,8 @@ static enum delret delete_dir_contents(c
+@@ -249,6 +366,8 @@ static enum delret delete_dir_contents(c
if (S_ISDIR(fp->mode)
&& delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
ret = DR_NOT_EMPTY;
if (delete_item(fname, fp->mode, NULL, flags) != DR_SUCCESS)
ret = DR_NOT_EMPTY;
}
-@@ -270,15 +389,19 @@ static enum delret delete_dir_contents(c
+@@ -333,15 +452,19 @@ static void delayed_deletions(char *delb
* all the --delete-WHEN options. Note that the fbuf pointer must point to a
* MAXPATHLEN buffer with the name of the directory in it (the functions we
* call will append names onto the end, but the old dir value will be restored
int dlen, i;
if (!flist) {
-@@ -292,6 +415,8 @@ static void delete_in_dir(struct file_li
+@@ -355,6 +478,8 @@ static void delete_in_dir(struct file_li
if (verbose > 2)
rprintf(FINFO, "delete_in_dir(%s)\n", fbuf);
if (allowed_lull)
maybe_send_keepalive();
-@@ -299,12 +424,14 @@ static void delete_in_dir(struct file_li
+@@ -362,12 +487,14 @@ static void delete_in_dir(struct file_li
return; /* Impossible... */
if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
}
while (cur_depth >= file->dir.depth && cur_depth >= min_depth)
-@@ -315,6 +442,9 @@ static void delete_in_dir(struct file_li
+@@ -378,6 +505,9 @@ static void delete_in_dir(struct file_li
dlen = strlen(fbuf);
filt_array[cur_depth] = push_local_filters(fbuf, dlen);
if (one_file_system) {
if (file->flags & FLAG_TOP_DIR)
filesystem_dev = stp->st_dev;
-@@ -324,6 +454,11 @@ static void delete_in_dir(struct file_li
+@@ -387,6 +517,11 @@ static void delete_in_dir(struct file_li
dirlist = get_dirlist(fbuf, dlen, 0);
/* If an item in dirlist is not found in flist, delete it
* from the filesystem. */
for (i = dirlist->count; i--; ) {
-@@ -336,12 +471,19 @@ static void delete_in_dir(struct file_li
+@@ -399,15 +534,22 @@ static void delete_in_dir(struct file_li
f_name(fp, NULL));
continue;
}
+ }
if (flist_find(flist, fp) < 0) {
f_name(fp, delbuf);
-- delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
+- if (delete_delay_fp)
++ if (delete_delay_fp && !(flags & DEL_NO_DELETIONS))
+ fprintf(delete_delay_fp, "%o %s%c", fp->mode, delbuf, '\0');
+ else
+- delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
- }
-+ delete_item(delbuf, fp->mode, NULL, flags);
++ delete_item(delbuf, fp->mode, NULL, flags);
+ } else if (detect_renamed && S_ISDIR(fp->mode))
+ unexplored_dirs++;
}
flist_free(dirlist);
}
-@@ -371,9 +513,9 @@ static void do_delete_pass(struct file_l
+@@ -437,9 +579,9 @@ static void do_delete_pass(struct file_l
|| !S_ISDIR(st.st_mode))
continue;
if (do_progress && !am_server)
rprintf(FINFO, " \r");
-@@ -902,6 +1044,7 @@ static int try_dests_non(struct file_str
+@@ -968,6 +1110,7 @@ static int try_dests_non(struct file_str
return j;
}
static int phase = 0;
/* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir,
-@@ -1087,8 +1230,12 @@ static void recv_generator(char *fname,
+@@ -1154,8 +1297,12 @@ static void recv_generator(char *fname,
if (real_ret != 0 && one_file_system)
real_st.st_dev = filesystem_dev;
if (delete_during && f_out != -1 && !phase && dry_run < 2
return;
}
-@@ -1340,8 +1487,14 @@ static void recv_generator(char *fname,
+@@ -1407,8 +1554,14 @@ static void recv_generator(char *fname,
&& hard_link_check(file, ndx, fname, statret, &st,
itemizing, code, HL_SKIP))
return;
rsyserr(FERROR, stat_errno, "recv_generator: failed to stat %s",
full_fname(fname));
return;
-@@ -1527,11 +1680,17 @@ void generate_files(int f_out, struct fi
+@@ -1594,13 +1747,19 @@ void generate_files(int f_out, struct fi
(long)getpid(), flist->count);
}
+
if (delete_before && !local_name && flist->count > 0)
do_delete_pass(flist);
+ if (delete_during == 2)
+ start_delete_temp();
do_progress = 0;
- if (append_mode || whole_file < 0)
whole_file = 0;
if (verbose >= 2) {
rprintf(FINFO, "delta-transmission %s\n",
-@@ -1586,7 +1745,23 @@ void generate_files(int f_out, struct fi
+@@ -1655,7 +1814,23 @@ void generate_files(int f_out, struct fi
}
recv_generator(NULL, NULL, 0, 0, 0, code, -1);
if (delete_during)
int numeric_ids = 0;
int allow_8bit_chars = 0;
int force_delete = 0;
-@@ -346,6 +347,7 @@ void usage(enum logcode F)
+@@ -347,6 +348,7 @@ void usage(enum logcode F)
rprintf(F," --modify-window=NUM compare mod-times with reduced accuracy\n");
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n");
rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n");
-@@ -499,6 +501,7 @@ static struct poptOption long_options[]
+@@ -501,6 +503,7 @@ static struct poptOption long_options[]
{"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
{"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
{"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
{"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 0, 0 },
{"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 },
{"compress-level", 0, POPT_ARG_INT, &def_compress_level, 'z', 0, 0 },
-@@ -1362,7 +1365,7 @@ int parse_arguments(int *argc, const cha
+@@ -1360,7 +1363,7 @@ int parse_arguments(int *argc, const cha
inplace = 1;
}
partial_dir = tmp_partialdir;
if (inplace) {
-@@ -1371,6 +1374,7 @@ int parse_arguments(int *argc, const cha
+@@ -1369,6 +1372,7 @@ int parse_arguments(int *argc, const cha
snprintf(err_buf, sizeof err_buf,
"--%s cannot be used with --%s\n",
append_mode ? "append" : "inplace",
delay_updates ? "delay-updates" : "partial-dir");
return 0;
}
-@@ -1674,6 +1678,8 @@ void server_options(char **args,int *arg
+@@ -1679,6 +1683,8 @@ void server_options(char **args,int *arg
args[ac++] = "--super";
if (size_only)
args[ac++] = "--size-only";
if (modify_window_set) {
--- old/rsync.yo
+++ new/rsync.yo
-@@ -363,6 +363,7 @@ to the detailed description below for a
+@@ -364,6 +364,7 @@ to the detailed description below for a
--modify-window=NUM compare mod-times with reduced accuracy
-T, --temp-dir=DIR create temporary files in directory DIR
-y, --fuzzy find similar file for basis if no dest file
--compare-dest=DIR also compare received files relative to DIR
--copy-dest=DIR ... and include copies of unchanged files
--link-dest=DIR hardlink to files in DIR when unchanged
-@@ -1265,6 +1266,15 @@ Note that the use of the bf(--delete) op
+@@ -1272,6 +1273,15 @@ Note that the use of the bf(--delete) op
fuzzy-match files, so either use bf(--delete-after) or specify some
filename exclusions if you need to prevent this.
files against doing transfers (if the files are missing in the destination
--- old/util.c
+++ new/util.c
-@@ -1025,6 +1025,32 @@ int handle_partial_dir(const char *fname
+@@ -1027,6 +1027,32 @@ int handle_partial_dir(const char *fname
return 1;
}
--- old/configure.in
+++ new/configure.in
-@@ -527,7 +527,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strd
+@@ -549,7 +549,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strd
memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
--- old/generator.c
+++ new/generator.c
-@@ -98,6 +98,12 @@ int non_perishable_cnt = 0;
-
+@@ -99,6 +99,12 @@ int non_perishable_cnt = 0;
static int deletion_count = 0; /* used to implement --max-delete */
+ static FILE *delete_delay_fp = NULL;
+#ifdef SUPPORT_FLAGS
+#define FILEFLAGS(ff) ff
/* For calling delete_item() and delete_dir_contents(). */
#define DEL_RECURSE (1<<1) /* recurse */
#define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */
-@@ -113,7 +119,6 @@ enum delret {
+@@ -114,7 +120,6 @@ enum delret {
/* Forward declaration for delete_item(). */
static enum delret delete_dir_contents(char *fname, int flags);
static int is_backup_file(char *fn)
{
int k = strlen(fn) - backup_suffix_len;
-@@ -126,17 +131,20 @@ static int is_backup_file(char *fn)
- * Note that fname must point to a MAXPATHLEN buffer if the mode indicates it's
+@@ -127,17 +132,20 @@ static int is_backup_file(char *fn)
+ * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
* a directory! (The buffer is used for recursion, but returned unchanged.)
*/
--static enum delret delete_item(char *fname, int mode, char *replace, int flags)
-+static enum delret delete_item(char *fname, int mode, uint32 fileflags, char *replace, int flags)
+-static enum delret delete_item(char *fbuf, int mode, char *replace, int flags)
++static enum delret delete_item(char *fbuf, int mode, uint32 fileflags, char *replace, int flags)
{
enum delret ret;
char *what;
if (verbose > 2) {
- rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
-- fname, mode, flags);
+- fbuf, mode, flags);
+ rprintf(FINFO, "delete_item(%s) mode=%o fileflags=%o flags=%d\n",
-+ fname, mode, fileflags, flags);
++ fbuf, mode, fileflags, flags);
}
+#ifdef SUPPORT_FLAGS
-+ make_mutable(fname, mode, fileflags);
++ make_mutable(fbuf, mode, fileflags);
+#endif
if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
ignore_perishable = 1;
/* If DEL_RECURSE is not set, this just reports emptiness. */
-@@ -248,7 +256,7 @@ static enum delret delete_dir_contents(c
+@@ -249,7 +257,7 @@ static enum delret delete_dir_contents(c
if (S_ISDIR(fp->mode)
&& delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
ret = DR_NOT_EMPTY;
ret = DR_NOT_EMPTY;
}
-@@ -338,7 +346,7 @@ static void delete_in_dir(struct file_li
+@@ -401,10 +409,10 @@ static void delete_in_dir(struct file_li
}
if (flist_find(flist, fp) < 0) {
f_name(fp, delbuf);
-- delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
-+ delete_item(delbuf, fp->mode, FILEFLAGS(fp->fileflags), NULL, DEL_RECURSE);
+- if (delete_delay_fp)
++ if (delete_delay_fp) /* XXX need to output fileflags value here too */
+ fprintf(delete_delay_fp, "%o %s%c", fp->mode, delbuf, '\0');
+ else
+- delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
++ delete_item(delbuf, fp->mode, FILEFLAGS(fp->fileflags), NULL, DEL_RECURSE);
}
}
-@@ -1036,7 +1044,7 @@ static void recv_generator(char *fname,
+@@ -1103,7 +1111,7 @@ static void recv_generator(char *fname,
* we need to delete it. If it doesn't exist, then
* (perhaps recursively) create it. */
if (statret == 0 && !S_ISDIR(st.st_mode)) {
return;
statret = -1;
}
-@@ -1130,7 +1138,7 @@ static void recv_generator(char *fname,
+@@ -1197,7 +1205,7 @@ static void recv_generator(char *fname,
}
/* Not the right symlink (or not a symlink), so
* delete it. */
return;
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
-@@ -1201,7 +1209,7 @@ static void recv_generator(char *fname,
+@@ -1268,7 +1276,7 @@ static void recv_generator(char *fname,
goto return_with_success;
return;
}
return;
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
-@@ -1287,7 +1295,7 @@ static void recv_generator(char *fname,
+@@ -1354,7 +1362,7 @@ static void recv_generator(char *fname,
fnamecmp_type = FNAMECMP_FNAME;
if (statret == 0 && !S_ISREG(st.st_mode)) {
rprintf(F," -E, --executability preserve the file's executability\n");
rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n");
rprintf(F," -o, --owner preserve owner (super-user only)\n");
-@@ -424,6 +431,8 @@ static struct poptOption long_options[]
+@@ -425,6 +432,8 @@ static struct poptOption long_options[]
{"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 },
{"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
{"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
{"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 },
{"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
{"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
-@@ -1128,6 +1137,15 @@ int parse_arguments(int *argc, const cha
+@@ -1130,6 +1139,15 @@ int parse_arguments(int *argc, const cha
}
#endif
if (write_batch && read_batch) {
snprintf(err_buf, sizeof err_buf,
"--write-batch and --read-batch can not be used together\n");
-@@ -1581,6 +1599,9 @@ void server_options(char **args,int *arg
+@@ -1584,6 +1602,9 @@ void server_options(char **args,int *arg
if (xfer_dirs && !recurse && delete_mode && am_sender)
args[ac++] = "--no-r";
-E, --executability preserve executability
--chmod=CHMOD affect file and/or directory permissions
-o, --owner preserve owner (super-user only)
-@@ -509,7 +510,9 @@ specified, in which case bf(-r) is not i
+@@ -510,7 +511,9 @@ specified, in which case bf(-r) is not i
Note that bf(-a) bf(does not preserve hardlinks), because
finding multiply-linked files is expensive. You must separately
dit(--no-OPTION) You may turn off one or more implied options by prefixing
the option name with "no-". Not all options may be prefixed with a "no-":
-@@ -804,6 +807,13 @@ quote(itemization(
+@@ -805,6 +808,13 @@ quote(itemization(
If bf(--perms) is enabled, this option is ignored.
transfer. The resulting value is treated as though it was the permissions
--- old/syscall.c
+++ new/syscall.c
-@@ -152,6 +152,15 @@ int do_chmod(const char *path, mode_t mo
+@@ -153,6 +153,15 @@ int do_chmod(const char *path, mode_t mo
}
#endif