#include "rounding.h"
#include "io.h"
-extern int verbose;
extern int am_root;
extern int am_server;
extern int am_daemon;
extern int am_sender;
extern int am_generator;
extern int inc_recurse;
-extern int do_progress;
extern int always_checksum;
extern int module_id;
extern int ignore_errors;
extern int sanitize_paths;
extern int munge_symlinks;
extern int need_unsorted_flist;
+extern int output_needs_newline;
+extern int sender_keeps_checksum;
extern int unsort_ndx;
extern struct stats stats;
extern char *filesfrom_host;
void init_flist(void)
{
- if (verbose > 4) {
+ if (DEBUG_GTE(FLIST, 4)) {
rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
(int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
}
static int show_filelist_p(void)
{
- return verbose && xfer_dirs && !am_server && !inc_recurse;
+ return INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
}
static void start_filelist_progress(char *kind)
{
rprintf(FCLIENT, "%s ... ", kind);
- if (verbose > 1 || do_progress)
- rprintf(FCLIENT, "\n");
+ output_needs_newline = 1;
rflush(FINFO);
}
static void maybe_emit_filelist_progress(int count)
{
- if (do_progress && show_filelist_p() && (count % 100) == 0)
+ if (INFO_GTE(FLIST, 2) && show_filelist_p() && (count % 100) == 0)
emit_filelist_progress(count);
}
static void finish_filelist_progress(const struct file_list *flist)
{
- if (do_progress) {
+ if (INFO_GTE(FLIST, 2)) {
/* This overwrites the progress line */
rprintf(FINFO, "%d file%sto consider\n",
flist->used, flist->used == 1 ? " " : "s ");
- } else
+ } else {
+ output_needs_newline = 0;
rprintf(FINFO, "done\n");
+ }
}
void show_flist_stats(void)
return -1;
linkbuf[llen] = '\0';
if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
- if (verbose > 1) {
+ if (INFO_GTE(SYMSAFE, 1)) {
rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
path, linkbuf);
}
static inline int path_is_daemon_excluded(char *path, int ignore_filename)
{
- if (daemon_filter_list.head && path) {
+ if (daemon_filter_list.head) {
char *slash = path;
while ((slash = strchr(slash+1, '/')) != NULL) {
static const char *pathname, *orig_dir;
static int pathname_len;
-
/* Make sure flist can hold at least flist->used + extra entries. */
static void flist_expand(struct file_list *flist, int extra)
{
new_ptr = realloc_array(flist->files, struct file_struct *,
flist->malloced);
- if (verbose >= 2 && flist->malloced != FLIST_START) {
- rprintf(FCLIENT, "[%s] expand file_list pointer array to %.0f bytes, did%s move\n",
+ if (DEBUG_GTE(FLIST, 1) && flist->malloced != FLIST_START) {
+ rprintf(FCLIENT, "[%s] expand file_list pointer array to %s bytes, did%s move\n",
who_am_i(),
- (double)sizeof flist->files[0] * flist->malloced,
+ big_num(sizeof flist->files[0] * flist->malloced, 0),
(new_ptr == flist->files) ? " not" : "");
}
flist->pool_boundary = ptr;
}
-int push_pathname(const char *dir, int len)
+/* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's
+ * F_PATHNAME(), or (2) "NULL, dir, dirlen" to chdir() to the supplied dir,
+ * with dir == NULL taken to be the starting directory, and dirlen < 0
+ * indicating that strdup(dir) should be called and then the -dirlen length
+ * value checked to ensure that it is not daemon-excluded. */
+int change_pathname(struct file_struct *file, const char *dir, int dirlen)
{
- if (dir == pathname)
- return 1;
+ if (dirlen < 0) {
+ char *cpy = strdup(dir);
+ if (*cpy != '/')
+ change_dir(orig_dir, CD_SKIP_CHDIR);
+ if (path_is_daemon_excluded(cpy, 0))
+ goto chdir_error;
+ dir = cpy;
+ dirlen = -dirlen;
+ } else {
+ if (file) {
+ if (pathname == F_PATHNAME(file))
+ return 1;
+ dir = F_PATHNAME(file);
+ if (dir)
+ dirlen = strlen(dir);
+ } else if (pathname == dir)
+ return 1;
+ if (dir && *dir != '/')
+ change_dir(orig_dir, CD_SKIP_CHDIR);
+ }
- if (!orig_dir)
- orig_dir = strdup(curr_dir);
+ pathname = dir;
+ pathname_len = dirlen;
- if (pathname && !pop_dir(orig_dir)) {
- rsyserr(FERROR, errno, "pop_dir %s failed",
- full_fname(orig_dir));
- exit_cleanup(RERR_FILESELECT);
- }
+ if (!dir)
+ dir = orig_dir;
- if (dir && !push_dir(dir, 0)) {
+ if (!change_dir(dir, CD_NORMAL)) {
+ chdir_error:
io_error |= IOERR_GENERAL;
- rsyserr(FERROR, errno, "push_dir %s failed in %s",
- full_fname(dir), curr_dir);
+ rsyserr(FERROR, errno, "change_dir %s failed", full_fname(dir));
+ if (dir != orig_dir)
+ change_dir(orig_dir, CD_NORMAL);
+ pathname = NULL;
+ pathname_len = 0;
return 0;
}
- pathname = dir;
- pathname_len = len >= 0 ? len : dir ? (int)strlen(dir) : 0;
-
return 1;
}
static gid_t gid;
static const char *user_name, *group_name;
static char lastname[MAXPATHLEN];
+#ifdef SUPPORT_HARD_LINKS
int first_hlink_ndx = -1;
+#endif
int l1, l2;
int xflags;
np->data = (void*)(long)(first_ndx + ndx + 1);
xflags |= XMIT_HLINK_FIRST;
}
+ if (DEBUG_GTE(HLINK, 1)) {
+ if (first_hlink_ndx >= 0) {
+ rprintf(FINFO, "[%s] #%d hard-links #%d (%sabbrev)\n",
+ who_am_i(), first_ndx + ndx, first_hlink_ndx,
+ first_hlink_ndx >= first_ndx ? "" : "un");
+ } else if (DEBUG_GTE(HLINK, 3)) {
+ rprintf(FINFO, "[%s] dev:inode for #%d is %s:%s\n",
+ who_am_i(), first_ndx + ndx,
+ big_num(tmp_dev, 0), big_num(tmp_ino, 0));
+ }
+ }
} else {
if (tmp_dev == dev) {
if (protocol_version >= 28)
write_byte(f, l2);
write_buf(f, fname + l1, l2);
+#ifdef SUPPORT_HARD_LINKS
if (first_hlink_ndx >= 0) {
write_varint(f, first_hlink_ndx);
if (first_hlink_ndx >= first_ndx)
goto the_end;
}
+#endif
write_varlong30(f, F_LENGTH(file), 3);
if (!(xflags & XMIT_SAME_TIME)) {
write_buf(f, sum, checksum_len);
}
+#ifdef SUPPORT_HARD_LINKS
the_end:
+#endif
strlcpy(lastname, fname, MAXPATHLEN);
if (S_ISREG(mode) || S_ISLNK(mode))
int alloc_len, basename_len, linkname_len;
int extra_len = file_extra_cnt * EXTRA_LEN;
int first_hlink_ndx = -1;
- OFF_T file_length;
+ int64 file_length;
const char *basename;
struct file_struct *file;
alloc_pool_t *pool;
xbuf outbuf, inbuf;
INIT_CONST_XBUF(outbuf, thisname);
- INIT_XBUF(inbuf, lastname, basename_len, -1);
+ INIT_XBUF(inbuf, lastname, basename_len, (size_t)-1);
if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) {
io_error |= IOERR_GENERAL;
first_hlink_ndx, flist->ndx_start + flist->used);
exit_cleanup(RERR_PROTOCOL);
}
+ if (DEBUG_GTE(HLINK, 1)) {
+ rprintf(FINFO, "[%s] #%d hard-links #%d (%sabbrev)\n",
+ who_am_i(), flist->used+flist->ndx_start, first_hlink_ndx,
+ first_hlink_ndx >= flist->ndx_start ? "" : "un");
+ }
if (first_hlink_ndx >= flist->ndx_start) {
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
file_length = F_LENGTH(first);
if (always_checksum && S_ISREG(mode))
extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
+#if SIZEOF_INT64 >= 8
if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
extra_len += EXTRA_LEN;
+#endif
+ if (file_length < 0) {
+ rprintf(FERROR, "Offset underflow: file-length is negative\n");
+ exit_cleanup(RERR_UNSUPPORTED);
+ }
if (inc_recurse && S_ISDIR(mode)) {
if (one_file_system) {
#endif
file->modtime = (time_t)modtime;
file->len32 = (uint32)file_length;
+#if SIZEOF_INT64 >= 8
if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) {
+#if SIZEOF_CAPITAL_OFF_T < 8
+ rprintf(FERROR, "Offset overflow: attempted 64-bit file-length\n");
+ exit_cleanup(RERR_UNSUPPORTED);
+#else
file->flags |= FLAG_LENGTH64;
OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
+#endif
}
+#endif
file->mode = mode;
if (preserve_uid)
F_OWNER(file) = uid;
* and performing extensive checks against global options.
*
* Returns a pointer to the new file struct, or NULL if there was an error
- * or this file should be excluded. */
+ * or this file should be excluded.
+ *
+ * Note: Any error (here or in send_file_name) that results in the omission of
+ * an existent source file from the file list should set
+ * "io_error |= IOERR_GENERAL" to avoid deletion of the file from the
+ * destination if --delete is on. */
struct file_struct *make_file(const char *fname, struct file_list *flist,
STRUCT_STAT *stp, int flags, int filter_level)
{
const char *basename;
alloc_pool_t *pool;
STRUCT_STAT st;
- int excl_ret;
char *bp;
if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) {
+ io_error |= IOERR_GENERAL;
rprintf(FINFO, "skipping overly long name: %s\n", fname);
return NULL;
}
return NULL;
}
- /* backup.c calls us with filter_level set to NO_FILTERS. */
if (filter_level == NO_FILTERS)
goto skip_filters;
if (one_file_system && st.st_dev != filesystem_dev
&& BITS_SETnUNSET(flags, FLAG_CONTENT_DIR, FLAG_TOP_DIR)) {
if (one_file_system > 1) {
- if (verbose > 1) {
+ if (INFO_GTE(MOUNT, 1)) {
rprintf(FINFO,
"[%s] skipping mount-point dir %s\n",
who_am_i(), thisname);
} else
flags &= ~FLAG_CONTENT_DIR;
- if (S_ISDIR(st.st_mode)) {
- if (flags & FLAG_DOTDIR_NAME) {
- /* A "." fname (or "/." fname in relative mode) is
- * never excluded. No other trailing-dotdir names
- * are possible. */
- excl_ret = 0;
- } else
- excl_ret = is_excluded(thisname, 1, filter_level);
- } else
- excl_ret = is_excluded(thisname, 0, filter_level);
- if (excl_ret) {
+ if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) {
if (ignore_perishable)
non_perishable_cnt++;
return NULL;
pool = NULL;
}
- if (verbose > 2) {
+ if (DEBUG_GTE(FLIST, 2)) {
rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
who_am_i(), thisname, filter_level);
}
linkname_len = 0;
#endif
+#if SIZEOF_CAPITAL_OFF_T >= 8
if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode))
extra_len += EXTRA_LEN;
+#endif
+
+ if (always_checksum && am_sender && S_ISREG(st.st_mode)) {
+ file_checksum(thisname, tmp_sum, st.st_size);
+ if (sender_keeps_checksum)
+ extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
+ }
#if EXTRA_ROUNDING > 0
if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
file->flags = flags;
file->modtime = st.st_mtime;
file->len32 = (uint32)st.st_size;
+#if SIZEOF_CAPITAL_OFF_T >= 8
if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) {
file->flags |= FLAG_LENGTH64;
OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
}
+#endif
file->mode = st.st_mode;
if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */
F_OWNER(file) = st.st_uid;
memcpy(bp + basename_len, linkname, linkname_len);
#endif
- if (always_checksum && am_sender && S_ISREG(st.st_mode))
- file_checksum(thisname, tmp_sum, st.st_size);
-
if (am_sender)
F_PATHNAME(file) = pathname;
else if (!pool)
return NULL;
}
+ if (sender_keeps_checksum && S_ISREG(st.st_mode))
+ memcpy(F_SUM(file), tmp_sum, checksum_len);
+
if (unsort_ndx)
F_NDX(file) = dir_count;
if (preserve_acls && !S_ISLNK(file->mode)) {
sx.st.st_mode = file->mode;
sx.acc_acl = sx.def_acl = NULL;
- if (get_acl(fname, &sx) < 0)
+ if (get_acl(fname, &sx) < 0) {
+ io_error |= IOERR_GENERAL;
return NULL;
+ }
}
#endif
#ifdef SUPPORT_XATTRS
if (preserve_xattrs) {
sx.xattr = NULL;
- if (get_xattr(fname, &sx) < 0)
+ if (get_xattr(fname, &sx) < 0) {
+ io_error |= IOERR_GENERAL;
return NULL;
+ }
}
#endif
f_name(file, fbuf);
dlen = strlen(fbuf);
- if (F_PATHNAME(file) != pathname) {
- if (!push_pathname(F_PATHNAME(file), -1))
- exit_cleanup(RERR_FILESELECT);
- }
+ if (!change_pathname(file, NULL, 0))
+ exit_cleanup(RERR_FILESELECT);
change_local_filter_dir(fbuf, dlen, send_dir_depth);
file_total += flist->used;
stats.flist_size += stats.total_written - start_write;
stats.num_files += flist->used;
- if (verbose > 3)
+ if (DEBUG_GTE(FLIST, 3))
output_flist(flist);
if (DIR_FIRST_CHILD(dp) >= 0) {
int64 start_write;
int use_ff_fd = 0;
int disable_buffering;
- int arg_flags, flags = recurse ? FLAG_CONTENT_DIR : 0;
+ int flags = recurse ? FLAG_CONTENT_DIR : 0;
int reading_remotely = filesfrom_host != NULL;
int rl_flags = (reading_remotely ? 0 : RL_DUMP_COMMENTS)
#ifdef ICONV_OPTION
rprintf(FLOG, "building file list\n");
if (show_filelist_p())
start_filelist_progress("building file list");
- else if (inc_recurse && verbose && !am_server)
+ else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
rprintf(FCLIENT, "sending incremental file list\n");
start_write = stats.total_written;
gettimeofday(&start_tv, NULL);
+ if (!orig_dir)
+ orig_dir = strdup(curr_dir);
+
if (relative_paths && protocol_version >= 30)
implied_dirs = 1; /* We send flagged implied dirs */
disable_buffering = io_start_buffering_out(f);
if (filesfrom_fd >= 0) {
- if (argv[0] && !push_dir(argv[0], 0)) {
- rsyserr(FERROR_XFER, errno, "push_dir %s failed in %s",
- full_fname(argv[0]), curr_dir);
+ if (argv[0] && !change_dir(argv[0], CD_NORMAL)) {
+ rsyserr(FERROR_XFER, errno, "change_dir %s failed",
+ full_fname(argv[0]));
exit_cleanup(RERR_FILESELECT);
}
use_ff_fd = 1;
dirlen = dir ? strlen(dir) : 0;
if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) {
- if (path_is_daemon_excluded(dir, 0)) {
- io_error |= IOERR_GENERAL;
- rsyserr(FERROR, errno, "push_dir %s failed in %s",
- full_fname(dir), curr_dir);
- continue;
- }
- if (!push_pathname(dir ? strdup(dir) : NULL, dirlen))
+ if (!change_pathname(NULL, dir, -dirlen))
continue;
lastdir = pathname;
lastdir_len = pathname_len;
- } else if (!push_pathname(lastdir, lastdir_len))
+ } else if (!change_pathname(NULL, lastdir, lastdir_len))
continue;
if (fn != fbuf)
continue;
}
+ /* A dot-dir should not be excluded! */
+ if (name_type != DOTDIR_NAME
+ && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, ALL_FILTERS))
+ continue;
+
if (S_ISDIR(st.st_mode) && !xfer_dirs) {
rprintf(FINFO, "skipping directory %s\n", fbuf);
continue;
if (one_file_system)
filesystem_dev = st.st_dev;
- arg_flags = name_type == DOTDIR_NAME ? FLAG_DOTDIR_NAME : 0;
-
if (recurse || (xfer_dirs && name_type != NORMAL_NAME)) {
struct file_struct *file;
- arg_flags |= FLAG_TOP_DIR | FLAG_CONTENT_DIR;
file = send_file_name(f, flist, fbuf, &st,
- arg_flags | flags, ALL_FILTERS);
+ FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags,
+ NO_FILTERS);
if (!file)
continue;
if (inc_recurse) {
} else
send_if_directory(f, flist, file, fbuf, len, flags);
} else
- send_file_name(f, flist, fbuf, &st, arg_flags | flags, ALL_FILTERS);
+ send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS);
}
gettimeofday(&end_tv, NULL);
stats.flist_size = stats.total_written - start_write;
stats.num_files = flist->used;
- if (verbose > 3)
+ if (DEBUG_GTE(FLIST, 3))
output_flist(flist);
- if (verbose > 2)
+ if (DEBUG_GTE(FLIST, 2))
rprintf(FINFO, "send_file_list done\n");
if (inc_recurse) {
send_dir_depth = 1;
add_dirs_to_tree(-1, flist, dir_count);
- if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0)
+ if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0)
flist->parent_ndx = -1;
flist_done_allocating(flist);
if (send_dir_ndx < 0) {
int dstart, flags;
int64 start_read;
- if (!first_flist)
+ if (!first_flist) {
+ if (show_filelist_p())
+ start_filelist_progress("receiving file list");
+ else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
+ rprintf(FCLIENT, "receiving incremental file list\n");
rprintf(FLOG, "receiving file list\n");
- if (show_filelist_p())
- start_filelist_progress("receiving file list");
- else if (inc_recurse && verbose && !am_server && !first_flist)
- rprintf(FCLIENT, "receiving incremental file list\n");
+ }
start_read = stats.total_read;
maybe_emit_filelist_progress(flist->used);
- if (verbose > 2) {
+ if (DEBUG_GTE(FLIST, 2)) {
rprintf(FINFO, "recv_file_name(%s)\n",
f_name(file, NULL));
}
}
file_total += flist->used;
- if (verbose > 2)
+ if (DEBUG_GTE(FLIST, 2))
rprintf(FINFO, "received %d names\n", flist->used);
if (show_filelist_p())
else
io_error |= read_int(f);
} else if (inc_recurse && flist->ndx_start == 1) {
- if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0)
+ if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0)
flist->parent_ndx = -1;
}
- if (verbose > 3)
+ if (DEBUG_GTE(FLIST, 3))
output_flist(flist);
- if (verbose > 2)
+ if (DEBUG_GTE(FLIST, 2))
rprintf(FINFO, "recv_file_list done\n");
stats.flist_size += stats.total_read - start_read;
NDX_FLIST_OFFSET - dir_flist->used + 1);
exit_cleanup(RERR_PROTOCOL);
}
- if (verbose > 3) {
+ if (DEBUG_GTE(FLIST, 3)) {
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
who_am_i(), ndx);
}
if (flags & FLIST_TEMP) {
if (!(flist->file_pool = pool_create(SMALL_EXTENT, 0,
- out_of_memory, POOL_INTERN)))
+ out_of_memory,
+ POOL_INTERN)))
out_of_memory(msg);
} else {
/* This is a doubly linked list with prev looping back to
* the end of the list, but the last next pointer is NULL. */
if (!first_flist) {
flist->file_pool = pool_create(NORMAL_EXTENT, 0,
- out_of_memory, POOL_INTERN);
+ out_of_memory,
+ POOL_INTERN);
if (!flist->file_pool)
out_of_memory(msg);
keep = j, drop = i;
if (!am_sender) {
- if (verbose > 1) {
+ if (DEBUG_GTE(DUP, 1)) {
rprintf(FINFO,
"removing duplicate name %s from file list (%d)\n",
f_name(file, fbuf), drop + flist->ndx_start);
} else
root = dir = slash = name = trail = "";
rprintf(FINFO,
- "[%s] i=%d %s %s%s%s%s mode=0%o len=%.0f%s%s flags=%x\n",
+ "[%s] i=%d %s %s%s%s%s mode=0%o len=%s%s%s flags=%x\n",
who, i + flist->ndx_start,
root, dir, slash, name, trail,
- (int)file->mode, (double)F_LENGTH(file),
+ (int)file->mode, big_num(F_LENGTH(file), 0),
uidbuf, gidbuf, file->flags);
}
}
send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, 0);
xfer_dirs = save_xfer_dirs;
recurse = save_recurse;
- if (do_progress)
+ if (INFO_GTE(PROGRESS, 1))
flist_count_offset += dirlist->used;
prune_empty_dirs = 0;
flist_sort_and_clean(dirlist, 0);
prune_empty_dirs = save_prune_empty_dirs;
- if (verbose > 3)
+ if (DEBUG_GTE(FLIST, 3))
output_flist(dirlist);
return dirlist;