extern int am_server;
extern int am_daemon;
extern int am_sender;
-extern int delete_during;
extern int always_checksum;
extern int module_id;
extern int ignore_errors;
static dev_t filesystem_dev; /* used to implement -x */
static int deletion_count = 0; /* used to implement --max-delete */
-static int flist_find(struct file_list *flist, struct file_struct *f);
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static void output_flist(struct file_list *flist, const char *whose_list);
rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
perms,
(double)f->length, timestring(f->modtime),
- f_name(f), f->u.link);
+ safe_fname(f_name(f)), safe_fname(f->u.link));
} else
#endif
{
rprintf(FINFO, "%s %11.0f %s %s\n",
perms,
(double)f->length, timestring(f->modtime),
- f_name(f));
+ safe_fname(f_name(f)));
}
}
if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
if (verbose > 1) {
rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
- path, linkbuf);
+ safe_fname(path), safe_fname(linkbuf));
}
return do_stat(path, buffer);
}
if (l2 >= MAXPATHLEN - l1) {
rprintf(FERROR,
"overflow: flags=0x%x l1=%d l2=%d lastname=%s\n",
- flags, l1, l2, lastname);
+ flags, l1, l2, safe_fname(lastname));
overflow("receive_file_entry");
}
if (strlcpy(thisname, fname, sizeof thisname)
>= sizeof thisname - flist_dir_len) {
- rprintf(FINFO, "skipping overly long name: %s\n", fname);
+ rprintf(FINFO, "skipping overly long name: %s\n",
+ safe_fname(fname));
return NULL;
}
clean_fname(thisname, 0);
goto skip_filters;
if (S_ISDIR(st.st_mode) && !xfer_dirs) {
- rprintf(FINFO, "skipping directory %s\n", thisname);
+ rprintf(FINFO, "skipping directory %s\n", safe_fname(thisname));
return NULL;
}
if (verbose > 2) {
rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
- who_am_i(), thisname, filter_level);
+ who_am_i(), safe_fname(thisname), filter_level);
}
if ((basename = strrchr(thisname, '/')) != NULL) {
if (errno) {
io_error |= IOERR_GENERAL;
*p = '\0';
- rsyserr(FERROR, errno, "readdir(%s)", fbuf);
+ rsyserr(FERROR, errno, "readdir(%s)", full_fname(fbuf));
}
closedir(d);
}
if (S_ISDIR(st.st_mode) && !xfer_dirs) {
- rprintf(FINFO, "skipping directory %s\n", fname);
+ rprintf(FINFO, "skipping directory %s\n",
+ safe_fname(fname));
continue;
}
if (verbose > 2) {
rprintf(FINFO, "recv_file_name(%s)\n",
- f_name(flist->files[i]));
+ safe_fname(f_name(flist->files[i])));
}
}
receive_file_entry(NULL, 0, 0, 0); /* Signal that we're done. */
}
-static int flist_find(struct file_list *flist, struct file_struct *f)
+int flist_find(struct file_list *flist, struct file_struct *f)
{
int low = flist->low, high = flist->high;
int ret, mid, mid_up;
if (verbose > 1 && !am_server) {
rprintf(FINFO,
"removing duplicate name %s from file list %d\n",
- f_name(flist->files[i]), i);
+ safe_fname(f_name(flist->files[i])), i);
}
/* Make sure that if we unduplicate '.', that we don't
* lose track of a user-specified top directory. */
sprintf(depthbuf, "%d", file->dir.depth);
rprintf(FINFO, "[%s] i=%d %s %s%s%s%s mode=0%o len=%.0f%s%s flags=%x\n",
whose_list, i, am_sender ? NS(file->dir.root) : depthbuf,
- file->dirname ? file->dirname : "",
+ file->dirname ? safe_fname(file->dirname) : "",
file->dirname ? "/" : "", NS(file->basename),
S_ISDIR(file->mode) ? "/" : "", (int)file->mode,
(double)file->length, uidbuf, gidbuf, file->flags);
}
-enum fnc_state { fnc_DIR, fnc_SLASH, fnc_BASE };
+enum fnc_state { fnc_DIR, fnc_SLASH, fnc_BASE, fnc_TRAILING };
-/* Compare the names of two file_struct entities, just like strcmp()
- * would do if it were operating on the joined strings. We assume
- * that there are no 0-length strings.
- */
+/* Compare the names of two file_struct entities, similar to how strcmp()
+ * would do if it were operating on the joined strings. The only difference
+ * is that, beginning with protocol_version 29, a directory name will always
+ * sort immediately prior to its contents (previously "foo." would sort in
+ * between directory "foo" and "foo/bar"). We do this by assuming that a dir
+ * has a trailing slash for comparison purposes, but only if we aren't about
+ * to match a file of the same name (because we need all identically named
+ * items to match each other). The dirname component can be an empty string,
+ * but the basename component cannot (and never is in the current codebase).
+ * The basename component may be NULL, in which case it is sorted to the end
+ * of the list (as a removed item). */
int f_name_cmp(struct file_struct *f1, struct file_struct *f2)
{
int dif;
c1 = (uchar*)f1->basename;
break;
case fnc_BASE:
+ state1 = fnc_TRAILING;
+ if (protocol_version >= 29 && S_ISDIR(f1->mode))
+ c1 = (uchar*)"/";
+ break;
+ case fnc_TRAILING:
break;
}
}
c2 = (uchar*)f2->basename;
break;
case fnc_BASE:
- if (!*c1)
+ if (state1 == fnc_TRAILING)
return 0;
+ state2 = fnc_TRAILING;
+ if (protocol_version >= 29 && S_ISDIR(f2->mode))
+ c2 = (uchar*)"/";
+ break;
+ case fnc_TRAILING:
break;
}
}
continue;
mode = dir_list->files[i]->mode;
if ((j = flist_find(full_list, dir_list->files[i])) < 0
- || (delete_during && S_ISDIR(mode)
- && !S_ISDIR(full_list->files[j]->mode))) {
+ || (S_ISDIR(mode) && !S_ISDIR(full_list->files[j]->mode))) {
char *f = f_name(dir_list->files[i]);
if (make_backups && (backup_dir || !is_backup_file(f))
&& !S_ISDIR(mode)) {
rprintf(FINFO, "deleting %s\n",
safe_fname(f));
}
- } else if (S_ISDIR(mode)) {
- int dflag = delete_during ? DEL_FORCE_RECURSE
- : DEL_NO_RECURSE;
- delete_file(f, DEL_DIR | dflag);
- } else {
+ } else if (S_ISDIR(mode))
+ delete_file(f, DEL_DIR | DEL_FORCE_RECURSE);
+ else
delete_file(f, 0);
- }
deletion_count++;
if (max_delete && deletion_count >= max_delete)
break;