#include "rsync.h"
-extern struct stats stats;
-
extern int verbose;
extern int dry_run;
extern int list_only;
extern int protocol_version;
extern int sanitize_paths;
extern int orig_umask;
+extern struct stats stats;
+extern struct file_list *the_file_list;
extern char curr_dir[MAXPATHLEN];
dev_t filesystem_dev; /* used to implement -x */
static char empty_sum[MD4_SUM_LENGTH];
+static int flist_count_offset;
static unsigned int file_struct_len;
-static struct file_list *received_flist, *sorting_flist;
+static struct file_list *sorting_flist;
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static void output_flist(struct file_list *flist);
}
-static void emit_filelist_progress(const struct file_list *flist)
+static void emit_filelist_progress(int count)
{
- rprintf(FINFO, " %d files...\r", flist->count);
+ rprintf(FINFO, " %d files...\r", count);
}
-static void maybe_emit_filelist_progress(const struct file_list *flist)
+static void maybe_emit_filelist_progress(int count)
{
- if (do_progress && show_filelist_p() && (flist->count % 100) == 0)
- emit_filelist_progress(flist);
+ if (do_progress && show_filelist_p() && (count % 100) == 0)
+ emit_filelist_progress(count);
}
rprintf(FERROR,
"overflow: flags=0x%x l1=%d l2=%d lastname=%s\n",
flags, l1, l2, safe_fname(lastname));
- overflow("receive_file_entry");
+ overflow_exit("receive_file_entry");
}
strlcpy(thisname, lastname, l1 + 1);
if (linkname_len <= 0 || linkname_len > MAXPATHLEN) {
rprintf(FERROR, "overflow: linkname_len=%d\n",
linkname_len - 1);
- overflow("receive_file_entry");
+ overflow_exit("receive_file_entry");
}
}
else
if (flags & XMIT_TOP_DIR) {
in_del_hier = 1;
del_hier_name_len = file->dir.depth == 0 ? 0 : l1 + l2;
+ if (relative_paths && del_hier_name_len > 2
+ && basename_len == 1+1 && *basename == '.')
+ del_hier_name_len -= 2;
file->flags |= FLAG_TOP_DIR | FLAG_DEL_HERE;
} else if (in_del_hier) {
if (!relative_paths || !del_hier_name_len
STRUCT_STAT st2;
int save_mode = file->mode;
file->mode = S_IFDIR; /* find a directory w/our name */
- if (flist_find(received_flist, file) >= 0
+ if (flist_find(the_file_list, file) >= 0
&& do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) {
file->modtime = st2.st_mtime;
file->length = st2.st_size;
}
-void send_file_name(int f, struct file_list *flist, char *fname,
- int recursive, unsigned short base_flags)
+static struct file_struct *send_file_name(int f, struct file_list *flist,
+ char *fname, unsigned short base_flags)
{
struct file_struct *file;
- char fbuf[MAXPATHLEN];
file = make_file(fname, flist, f == -2 ? SERVER_FILTERS : ALL_FILTERS);
if (!file)
- return;
+ return NULL;
- maybe_emit_filelist_progress(flist);
+ maybe_emit_filelist_progress(flist->count + flist_count_offset);
flist_expand(flist);
flist->files[flist->count++] = file;
send_file_entry(file, f, base_flags);
}
+ return file;
+}
+
+static void send_if_directory(int f, struct file_list *flist,
+ struct file_struct *file)
+{
+ char fbuf[MAXPATHLEN];
- if (recursive && S_ISDIR(file->mode)
+ if (S_ISDIR(file->mode)
&& !(file->flags & FLAG_MOUNT_POINT) && f_name_to(file, fbuf)) {
void *save_filters;
unsigned int len = strlen(fbuf);
}
-/* Note that the "recurse" value either contains -1, for infinite recursion, or
- * a number >= 0 indicating how many levels of recursion we will allow. This
- * function is normally called by the sender, but the receiving side also calls
- * it from delete_in_dir() with f set to -1 so that we just construct the file
- * list in memory without sending it over the wire. Also, get_dirlist() might
- * call this with f set to -2, which indicates that local filter rules should
- * be ignored. */
+/* This function is normally called by the sender, but the receiving side also
+ * calls it from get_dirlist() with f set to -1 so that we just construct the
+ * file list in memory without sending it over the wire. Also, get_dirlist()
+ * might call this with f set to -2, which also indicates that local filter
+ * rules should be ignored. */
static void send_directory(int f, struct file_list *flist,
char *fbuf, int len)
{
unsigned remainder;
char *p;
DIR *d;
+ int start = flist->count;
if (!(d = opendir(fbuf))) {
io_error |= IOERR_GENERAL;
if (dname[0] == '.' && (dname[1] == '\0'
|| (dname[1] == '.' && dname[2] == '\0')))
continue;
- if (strlcpy(p, dname, remainder) < remainder) {
- int do_subdirs = recurse >= 1 ? recurse-- : recurse;
- send_file_name(f, flist, fbuf, do_subdirs, 0);
- } else {
+ if (strlcpy(p, dname, remainder) < remainder)
+ send_file_name(f, flist, fbuf, 0);
+ else {
io_error |= IOERR_GENERAL;
rprintf(FINFO,
"cannot send long-named file %s\n",
}
closedir(d);
+
+ if (recurse) {
+ int i, end = flist->count - 1;
+ for (i = start; i <= end; i++)
+ send_if_directory(f, flist, flist->files[i]);
+ }
}
}
while (1) {
+ struct file_struct *file;
char fname2[MAXPATHLEN];
char *fname = fname2;
- int do_subdirs;
+ int is_dot_dir;
if (use_ff_fd) {
if (read_filesfrom_line(filesfrom_fd, fname) == 0)
if (l == 2 && fname[0] == '.') {
/* Turn "./" into just "." rather than "./." */
fname[1] = '\0';
- } else if (l < MAXPATHLEN) {
+ } else {
+ if (l + 1 >= MAXPATHLEN)
+ overflow_exit("send_file_list");
fname[l++] = '.';
fname[l] = '\0';
}
+ is_dot_dir = 1;
+ } else if (l > 1 && fname[l-1] == '.' && fname[l-2] == '.'
+ && (l == 2 || fname[l-3] == '/')) {
+ if (l + 2 >= MAXPATHLEN)
+ overflow_exit("send_file_list");
+ fname[l++] = '/';
+ fname[l++] = '.';
+ fname[l] = '\0';
+ is_dot_dir = 1;
+ } else {
+ is_dot_dir = fname[l-1] == '.'
+ && (l == 1 || fname[l-2] == '/');
}
- if (fname[l-1] == '.' && (l == 1 || fname[l-2] == '/')) {
- if (!recurse && xfer_dirs)
- recurse = 1; /* allow one level */
- } else if (recurse > 0)
- recurse = 0;
if (link_stat(fname, &st, keep_dirlinks) != 0) {
io_error |= IOERR_GENERAL;
if (!relative_paths) {
p = strrchr(fname, '/');
if (p) {
- *p = 0;
+ *p = '\0';
if (p == fname)
dir = "/";
else
fname = p + 1;
}
} else if (implied_dirs && (p=strrchr(fname,'/')) && p != fname) {
- /* this ensures we send the intermediate directories,
- thus getting their permissions right */
+ /* Send the implied directories at the start of the
+ * source spec, so we get their permissions right. */
char *lp = lastpath, *fn = fname, *slash = fname;
- *p = 0;
+ *p = '\0';
/* Skip any initial directories in our path that we
* have in common with lastpath. */
while (*fn && *lp == *fn) {
copy_links = copy_unsafe_links;
xfer_dirs = 1;
while ((slash = strchr(slash+1, '/')) != 0) {
- *slash = 0;
- send_file_name(f, flist, fname, 0, 0);
+ *slash = '\0';
+ send_file_name(f, flist, fname, 0);
*slash = '/';
}
copy_links = save_copy_links;
xfer_dirs = save_xfer_dirs;
- *p = 0;
+ *p = '\0';
strlcpy(lastpath, fname, sizeof lastpath);
*p = '/';
}
if (one_file_system)
filesystem_dev = st.st_dev;
- do_subdirs = recurse >= 1 ? recurse-- : recurse;
- send_file_name(f, flist, fname, do_subdirs, XMIT_TOP_DIR);
+ if ((file = send_file_name(f, flist, fname, XMIT_TOP_DIR))) {
+ if (recurse || (xfer_dirs && is_dot_dir))
+ send_if_directory(f, flist, file);
+ }
if (olddir[0]) {
flist_dir = NULL;
start_read = stats.total_read;
flist = flist_new(WITH_HLINK, "recv_file_list");
- received_flist = flist;
flist->count = 0;
flist->malloced = 1000;
flist->files[flist->count++] = file;
- maybe_emit_filelist_progress(flist);
+ maybe_emit_filelist_progress(flist->count);
if (verbose > 2) {
rprintf(FINFO, "recv_file_name(%s)\n",
{
int i, prev_i = 0;
- if (!flist || flist->count == 0)
+ if (!flist)
+ return;
+ if (flist->count == 0) {
+ flist->high = -1;
return;
+ }
sorting_flist = flist;
qsort(flist->files, flist->count,
}
/* Make sure that if we unduplicate '.', that we don't
* lose track of a user-specified top directory. */
- if (flist->files[drop]->flags & FLAG_TOP_DIR)
- flist->files[keep]->flags |= FLAG_TOP_DIR;
+ flist->files[keep]->flags |= flist->files[drop]->flags
+ & (FLAG_TOP_DIR|FLAG_DEL_HERE);
clear_file(drop, flist);
break;
case s_SLASH:
type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM;
- state1 = s_BASE;
c1 = (uchar*)f1->basename;
+ if (type1 == t_PATH && *c1 == '.' && !c1[1]) {
+ type1 = t_ITEM;
+ state1 = s_TRAILING;
+ c1 = (uchar*)"";
+ } else
+ state1 = s_BASE;
break;
case s_BASE:
state1 = s_TRAILING;
if (!*c2) {
switch (state2) {
case s_DIR:
- if (state1 == s_SLASH && sorting_flist) {
- int j;
- /* Optimize for future comparisons. */
- for (j = 0;
- j < sorting_flist->count;
- j++) {
- struct file_struct *fp
- = sorting_flist->files[j];
- if (fp->dirname == f2->dirname)
- fp->dirname = f1->dirname;
- }
- }
state2 = s_SLASH;
c2 = (uchar*)"/";
break;
case s_SLASH:
type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM;
- state2 = s_BASE;
c2 = (uchar*)f2->basename;
+ if (type2 == t_PATH && *c2 == '.' && !c2[1]) {
+ type2 = t_ITEM;
+ state2 = s_TRAILING;
+ c2 = (uchar*)"";
+ } else
+ state2 = s_BASE;
break;
case s_BASE:
state2 = s_TRAILING;
recurse = 0;
send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen);
recurse = save_recurse;
+ if (do_progress)
+ flist_count_offset += dirlist->count;
clean_flist(dirlist, 0, 0);