#include "rsync.h"
-extern struct stats stats;
-
extern int verbose;
-extern int do_progress;
+extern int dry_run;
+extern int list_only;
extern int am_root;
extern int am_server;
extern int am_daemon;
extern int am_sender;
+extern int do_progress;
extern int always_checksum;
extern int module_id;
extern int ignore_errors;
extern int copy_unsafe_links;
extern int protocol_version;
extern int sanitize_paths;
-extern int deletion_count;
-extern int max_delete;
extern int orig_umask;
-extern int list_only;
-extern unsigned int curr_dir_len;
-extern char *log_format;
+extern struct stats stats;
+extern struct file_list *the_file_list;
extern char curr_dir[MAXPATHLEN];
extern struct filter_list_struct server_filter_list;
int io_error;
+dev_t filesystem_dev; /* used to implement -x */
static char empty_sum[MD4_SUM_LENGTH];
static unsigned int file_struct_len;
-static struct file_list *received_flist, *sorting_flist;
-static dev_t filesystem_dev; /* used to implement -x */
+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, const char *whose_list);
+static void output_flist(struct file_list *flist);
void init_flist(void)
{
static void send_directory(int f, struct file_list *flist,
- char *fbuf, unsigned int offset);
+ char *fbuf, int len);
static char *flist_dir;
static int flist_dir_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;
file->mode = save_mode;
}
- if (!S_ISDIR(st.st_mode))
+ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
stats.total_size += st.st_size;
return file;
}
-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);
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() calls 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 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 also indicates that local filter
+ * rules should be ignored. */
static void send_directory(int f, struct file_list *flist,
- char *fbuf, unsigned int len)
+ char *fbuf, int len)
{
struct dirent *di;
+ unsigned remainder;
char *p;
DIR *d;
+ int start = flist->count;
if (!(d = opendir(fbuf))) {
io_error |= IOERR_GENERAL;
if (len != 1 || *fbuf != '/')
*p++ = '/';
*p = '\0';
+ remainder = MAXPATHLEN - (p - fbuf);
for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
char *dname = d_name(di);
if (dname[0] == '.' && (dname[1] == '\0'
|| (dname[1] == '.' && dname[2] == '\0')))
continue;
- if (strlcpy(p, dname, MAXPATHLEN - len) < MAXPATHLEN - len) {
- 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",
full_fname(fbuf));
}
}
+
+ fbuf[len] = '\0';
+
if (errno) {
io_error |= IOERR_GENERAL;
- *p = '\0';
rsyserr(FERROR, errno, "readdir(%s)", full_fname(fbuf));
}
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)
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;
xfer_dirs = 1;
while ((slash = strchr(slash+1, '/')) != 0) {
*slash = 0;
- send_file_name(f, flist, fname, 0, 0);
+ send_file_name(f, flist, fname, 0);
*slash = '/';
}
copy_links = save_copy_links;
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;
stats.num_files = flist->count;
if (verbose > 3)
- output_flist(flist, who_am_i());
+ output_flist(flist);
if (verbose > 2)
rprintf(FINFO, "send_file_list done\n");
start_read = stats.total_read;
flist = flist_new(WITH_HLINK, "recv_file_list");
- received_flist = flist;
flist->count = 0;
flist->malloced = 1000;
}
if (verbose > 3)
- output_flist(flist, who_am_i());
+ output_flist(flist);
if (list_only) {
int i;
}
}
-static void output_flist(struct file_list *flist, const char *whose_list)
+
+static void output_flist(struct file_list *flist)
{
char uidbuf[16], gidbuf[16], depthbuf[16];
struct file_struct *file;
+ const char *who = who_am_i();
int i;
for (i = 0; i < flist->count; i++) {
if (!am_sender)
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,
+ who, i, am_sender ? NS(file->dir.root) : depthbuf,
file->dirname ? safe_fname(file->dirname) : "",
file->dirname ? "/" : "", NS(file->basename),
S_ISDIR(file->mode) ? "/" : "", (int)file->mode,
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;
}
-struct file_list *get_dirlist(const char *dirname, int ignore_filter_rules)
+/* Do a non-recursive scan of the named directory, possibly ignoring all
+ * exclude rules except for the daemon's. If "dlen" is >=0, it is the length
+ * of the dirname string, and also indicates that "dirname" is a MAXPATHLEN
+ * buffer (the functions we call will append names onto the end, but the old
+ * dir value will be restored on exit). */
+struct file_list *get_dirlist(char *dirname, int dlen,
+ int ignore_filter_rules)
{
struct file_list *dirlist;
char dirbuf[MAXPATHLEN];
- int dlen;
int save_recurse = recurse;
- dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
- if (dlen >= MAXPATHLEN)
- return NULL;
+ if (dlen < 0) {
+ dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
+ if (dlen >= MAXPATHLEN)
+ return NULL;
+ dirname = dirbuf;
+ }
dirlist = flist_new(WITHOUT_HLINK, "get_dirlist");
+
recurse = 0;
- send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirbuf, dlen);
+ send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen);
recurse = save_recurse;
- return dirlist;
-}
-
-
-/* This function is used to implement per-directory deletion, and
- * is used by 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 on exit). */
-void delete_in_dir(struct file_list *flist, char *fbuf,
- struct file_struct *file)
-{
- static int min_depth = MAXPATHLEN, cur_depth = -1;
- static void *filt_array[MAXPATHLEN/2+1];
- struct file_list *dir_list;
- STRUCT_STAT st;
- int dlen;
-
- if (!flist) {
- while (cur_depth >= min_depth)
- pop_local_filters(filt_array[cur_depth--]);
- min_depth = MAXPATHLEN;
- cur_depth = -1;
- return;
- }
- if (file->dir.depth >= MAXPATHLEN/2+1)
- return; /* Impossible... */
-
- if (max_delete && deletion_count >= max_delete)
- return;
-
- if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
- rprintf(FINFO,
- "IO error encountered -- skipping file deletion\n");
- max_delete = -1; /* avoid duplicating the above warning */
- return;
- }
-
- while (cur_depth >= file->dir.depth && cur_depth >= min_depth)
- pop_local_filters(filt_array[cur_depth--]);
- cur_depth = file->dir.depth;
- if (min_depth > cur_depth)
- min_depth = cur_depth;
- dlen = strlen(fbuf);
- filt_array[cur_depth] = push_local_filters(fbuf, dlen);
-
- if (link_stat(fbuf, &st, keep_dirlinks) < 0)
- return;
-
- if (one_file_system && file->flags & FLAG_TOP_DIR)
- filesystem_dev = st.st_dev;
-
- dir_list = flist_new(WITHOUT_HLINK, "delete_in_dir");
-
- recurse = 0;
- send_directory(-1, dir_list, fbuf, dlen);
- recurse = -1;
- fbuf[dlen] = '\0';
+ clean_flist(dirlist, 0, 0);
if (verbose > 3)
- output_flist(dir_list, "delete");
+ output_flist(dirlist);
- delete_missing(flist, dir_list, fbuf);
-
- flist_free(dir_list);
-}
-
-
-/* If an item in dir_list is not found in full_list, delete it from the
- * filesystem. */
-void delete_missing(struct file_list *full_list, struct file_list *dir_list,
- const char *dirname)
-{
- char fbuf[MAXPATHLEN];
- int i;
-
- if (max_delete && deletion_count >= max_delete)
- return;
-
- if (verbose > 2)
- rprintf(FINFO, "delete_missing(%s)\n", safe_fname(dirname));
-
- for (i = dir_list->count; i--; ) {
- if (!dir_list->files[i]->basename)
- continue;
- if (flist_find(full_list, dir_list->files[i]) < 0) {
- char *fn = f_name_to(dir_list->files[i], fbuf);
- int mode = dir_list->files[i]->mode;
- int dflag = S_ISDIR(mode) ? DEL_FORCE_RECURSE : 0;
- if (delete_file(fn, mode, dflag) < 0)
- break;
- }
- }
+ return dirlist;
}