#include "rsync.h"
extern int verbose;
-extern int dry_run;
extern int list_only;
extern int am_root;
extern int am_server;
extern int xfer_dirs;
extern int filesfrom_fd;
extern int one_file_system;
+extern int copy_dirlinks;
extern int keep_dirlinks;
extern int preserve_links;
extern int preserve_hard_links;
-extern int preserve_perms;
extern int preserve_devices;
extern int preserve_specials;
extern int preserve_uid;
extern int copy_unsafe_links;
extern int protocol_version;
extern int sanitize_paths;
-extern int orig_umask;
+extern const char *io_write_phase;
extern struct stats stats;
extern struct file_list *the_file_list;
static char empty_sum[MD4_SUM_LENGTH];
static int flist_count_offset;
-static int max_dir_depth = 0;
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static void output_flist(struct file_list *flist);
static void list_file_entry(struct file_struct *f)
{
- char perms[11];
+ char permbuf[PERMSTRING_SIZE];
if (!f->basename) {
/* this can happen if duplicate names were removed */
return;
}
- permstring(perms, f->mode);
+ permstring(permbuf, f->mode);
#ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
- perms,
+ permbuf,
(double)f->length, timestring(f->modtime),
f_name(f, NULL), f->u.link);
} else
#endif
{
rprintf(FINFO, "%s %11.0f %s %s\n",
- perms,
+ permbuf,
(double)f->length, timestring(f->modtime),
f_name(f, NULL));
}
#ifdef SUPPORT_LINKS
if (copy_links)
return do_stat(path, buffer);
- if (link_stat(path, buffer, 0) < 0)
+ if (link_stat(path, buffer, copy_dirlinks) < 0)
return -1;
if (S_ISLNK(buffer->st_mode)) {
int l = readlink((char *)path, linkbuf, MAXPATHLEN - 1);
bp[-1] = '\0';
lastdir_depth = count_dir_elements(lastdir);
file->dir.depth = lastdir_depth + 1;
- if (lastdir_depth >= max_dir_depth)
- max_dir_depth = lastdir_depth + 1;
} else if (dirname) {
file->dirname = dirname; /* we're reusing lastname */
file->dir.depth = lastdir_depth + 1;
read_buf(f, sum, checksum_len);
}
- if (!preserve_perms) {
- /* set an appropriate set of permissions based on original
- * permissions and umask. This emulates what GNU cp does */
- file->mode &= ~orig_umask;
- }
-
return file;
}
&& (len == 1 || fbuf[len-2] == '/');
}
- if (link_stat(fbuf, &st, keep_dirlinks) != 0) {
+ if (link_stat(fbuf, &st, copy_dirlinks) != 0) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno, "link_stat %s failed",
full_fname(fbuf));
if (fn != p || (*lp && *lp != '/')) {
int save_copy_links = copy_links;
int save_xfer_dirs = xfer_dirs;
- copy_links = copy_unsafe_links;
+ copy_links |= copy_unsafe_links;
xfer_dirs = 1;
while ((slash = strchr(slash+1, '/')) != 0) {
*slash = '\0';
flags |= read_byte(f) << 8;
file = receive_file_entry(flist, flags, f);
- if (S_ISREG(file->mode))
+ if (S_ISREG(file->mode) || S_ISLNK(file->mode))
stats.total_size += file->length;
flist->files[flist->count++] = file;
int flist_find(struct file_list *flist, struct file_struct *f)
{
int low = flist->low, high = flist->high;
- int ret, mid, mid_up;
+ int diff, mid, mid_up;
while (low <= high) {
mid = (low + high) / 2;
continue;
}
}
- ret = f_name_cmp(flist->files[mid_up], f);
- if (ret == 0) {
+ diff = f_name_cmp(flist->files[mid_up], f);
+ if (diff == 0) {
if (protocol_version < 29
&& S_ISDIR(flist->files[mid_up]->mode)
!= S_ISDIR(f->mode))
return -1;
return mid_up;
}
- if (ret > 0)
- high = mid - 1;
- else
+ if (diff < 0)
low = mid_up + 1;
+ else
+ high = mid - 1;
}
return -1;
}
* Free up any resources a file_struct has allocated
* and clear the file.
*/
-void clear_file(int i, struct file_list *flist)
+void clear_file(struct file_struct *file, struct file_list *flist)
{
- struct file_struct *file = flist->files[i];
if (flist->hlink_pool && file->link_u.idev)
pool_free(flist->hlink_pool, 0, file->link_u.idev);
memset(file, 0, file_struct_len);
/* In an empty entry, dir.depth is an offset to the next non-empty
* entry. Likewise for length in the opposite direction. We assume
- * that we're alone for now since flist_find() will collate adjacent
- * items for any entries that are encountered during the find. */
+ * that we're alone for now since flist_find() will adjust the counts
+ * it runs into that aren't up-to-date. */
file->length = file->dir.depth = 1;
}
flist->files[keep]->flags |= flist->files[drop]->flags
& (FLAG_TOP_DIR|FLAG_DEL_HERE);
- clear_file(drop, flist);
+ clear_file(flist->files[drop], flist);
if (keep == i) {
if (flist->low == drop) {
}
}
- if (prune_empty_dirs && no_dups && max_dir_depth) {
- int j, cur_depth = 0;
- int *maybe_dirs = new_array(int, max_dir_depth);
+ if (prune_empty_dirs && no_dups) {
+ int j, prev_depth = 0;
- maybe_dirs[0] = -1;
+ prev_i = 0; /* It's OK that this isn't really true. */
for (i = flist->low; i <= flist->high; i++) {
- struct file_struct *file = flist->files[i];
+ struct file_struct *fp, *file = flist->files[i];
+ /* This temporarily abuses the dir.depth value for a
+ * directory that is in a chain that might get pruned.
+ * We restore the old value if it gets a reprieve. */
if (S_ISDIR(file->mode) && file->dir.depth) {
- j = cur_depth;
- cur_depth = file->dir.depth - 1;
- for ( ; j >= cur_depth; j--) {
- if (maybe_dirs[j] < 0)
- continue;
- clear_file(maybe_dirs[j], flist);
+ /* Dump empty dirs when coming back down. */
+ for (j = prev_depth; j >= file->dir.depth; j--) {
+ fp = flist->files[prev_i];
+ if (fp->dir.depth >= 0)
+ break;
+ prev_i = -fp->dir.depth-1;
+ clear_file(fp, flist);
}
+ prev_depth = file->dir.depth;
if (is_excluded(f_name(file, fbuf), 1,
ALL_FILTERS)) {
- for (j = 0; j <= cur_depth; j++)
- maybe_dirs[j] = -1;
+ /* Keep dirs through this dir. */
+ for (j = prev_depth-1; ; j--) {
+ fp = flist->files[prev_i];
+ if (fp->dir.depth >= 0)
+ break;
+ prev_i = -fp->dir.depth-1;
+ fp->dir.depth = j;
+ }
} else
- maybe_dirs[cur_depth] = i;
- } else if (maybe_dirs[cur_depth] >= 0) {
- for (j = 0; j <= cur_depth; j++)
- maybe_dirs[j] = -1;
+ file->dir.depth = -prev_i-1;
+ prev_i = i;
+ } else {
+ /* Keep dirs through this non-dir. */
+ for (j = prev_depth; ; j--) {
+ fp = flist->files[prev_i];
+ if (fp->dir.depth >= 0)
+ break;
+ prev_i = -fp->dir.depth-1;
+ fp->dir.depth = j;
+ }
}
}
- for (j = cur_depth; j >= 0; j--) {
- if (maybe_dirs[j] < 0)
- continue;
- clear_file(maybe_dirs[j], flist);
+ /* Dump empty all remaining empty dirs. */
+ while (1) {
+ struct file_struct *fp = flist->files[prev_i];
+ if (fp->dir.depth >= 0)
+ break;
+ prev_i = -fp->dir.depth-1;
+ clear_file(fp, flist);
}
for (i = flist->low; i <= flist->high; i++) {
struct file_list *dirlist;
char dirbuf[MAXPATHLEN];
int save_recurse = recurse;
+ int save_xfer_dirs = xfer_dirs;
if (dlen < 0) {
dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
dirlist = flist_new(WITHOUT_HLINK, "get_dirlist");
recurse = 0;
+ xfer_dirs = 1;
send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen);
+ xfer_dirs = save_xfer_dirs;
recurse = save_recurse;
if (do_progress)
flist_count_offset += dirlist->count;