#define NORMAL_NAME 0
#define SLASH_ENDING_NAME 1
-#define DOT_NAME 2
+#define DOTDIR_NAME 2
/* Starting from protocol version 26, we always use 64-bit ino_t and dev_t
* internally, even if this platform does not allow files to have 64-bit inums.
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) {
if (filter_level == NO_FILTERS)
return 0;
#endif
- if (fname) {
- /* never exclude '.', even if somebody does --exclude '*' */
- if (fname[0] == '.' && !fname[1])
- return 0;
- /* Handle the -R version of the '.' dir. */
- if (fname[0] == '/') {
- int len = strlen(fname);
- if (fname[len-1] == '.' && fname[len-2] == '/')
- return 0;
- }
- }
if (is_daemon_excluded(fname, is_dir))
return 1;
if (filter_level != ALL_FILTERS)
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)
{
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;
}
}
} else if (protocol_version < 28)
rdev = MAKEDEV(0, 0);
- if (preserve_uid) {
- if ((uid_t)F_OWNER(file) == uid && *lastname)
- xflags |= XMIT_SAME_UID;
- else {
- uid = F_OWNER(file);
- if (!numeric_ids) {
- user_name = add_uid(uid);
- if (inc_recurse && user_name)
- xflags |= XMIT_USER_NAME_FOLLOWS;
- }
+ if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname))
+ xflags |= XMIT_SAME_UID;
+ else {
+ uid = F_OWNER(file);
+ if (!numeric_ids) {
+ user_name = add_uid(uid);
+ if (inc_recurse && user_name)
+ xflags |= XMIT_USER_NAME_FOLLOWS;
}
}
- if (preserve_gid) {
- if ((gid_t)F_GROUP(file) == gid && *lastname)
- xflags |= XMIT_SAME_GID;
- else {
- gid = F_GROUP(file);
- if (!numeric_ids) {
- group_name = add_gid(gid);
- if (inc_recurse && group_name)
- xflags |= XMIT_GROUP_NAME_FOLLOWS;
- }
+ if (!preserve_gid || ((gid_t)F_GROUP(file) == gid && *lastname))
+ xflags |= XMIT_SAME_GID;
+ else {
+ gid = F_GROUP(file);
+ if (!numeric_ids) {
+ group_name = add_gid(gid);
+ if (inc_recurse && group_name)
+ xflags |= XMIT_GROUP_NAME_FOLLOWS;
}
}
if (file->modtime == modtime)
np->data = (void*)(long)(first_ndx + ndx + 1);
xflags |= XMIT_HLINK_FIRST;
}
- xflags |= XMIT_HLINKED;
} else {
if (tmp_dev == dev) {
if (protocol_version >= 28)
xflags |= XMIT_SAME_DEV_pre30;
} else
dev = tmp_dev;
- xflags |= XMIT_HLINKED;
}
+ xflags |= XMIT_HLINKED;
}
#endif
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;
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)
{
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;
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 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;
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
}
}
-static char lastpath[MAXPATHLEN] = "";
-static int lastpath_len = 0;
-static struct file_struct *lastpath_struct;
-
static void send_implied_dirs(int f, struct file_list *flist, char *fname,
char *start, char *limit, int flags, char name_type)
{
+ static char lastpath[MAXPATHLEN] = "";
+ static int lastpath_len = 0;
+ static struct file_struct *lastpath_struct = NULL;
struct file_struct *file;
item_list *relname_list;
relnamecache **rnpp;
- char *slash;
- int len, need_new_dir;
+ int len, need_new_dir, depth = 0;
struct filter_list_struct save_filter_list = filter_list;
flags = (flags | FLAG_IMPLIED_DIR) & ~(FLAG_TOP_DIR | FLAG_CONTENT_DIR);
need_new_dir = 0;
else
need_new_dir = 1;
- } else
+ } else {
+ char *tp = fname, *lp = lastpath;
+ /* Skip any initial directories in our path that we
+ * have in common with lastpath. */
+ assert(start == fname);
+ for ( ; ; tp++, lp++) {
+ if (tp == limit) {
+ if (*lp == '/' || *lp == '\0')
+ goto done;
+ break;
+ }
+ if (*lp != *tp)
+ break;
+ if (*tp == '/') {
+ start = tp;
+ depth++;
+ }
+ }
need_new_dir = 1;
+ }
if (need_new_dir) {
int save_copy_links = copy_links;
int save_xfer_dirs = xfer_dirs;
+ char *slash;
copy_links = xfer_dirs = 1;
for (slash = start; (slash = strchr(slash+1, '/')) != NULL; ) {
*slash = '\0';
- send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS);
+ file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS);
+ depth++;
+ if (!inc_recurse && file && S_ISDIR(file->mode))
+ change_local_filter_dir(fname, strlen(fname), depth);
*slash = '/';
}
if (file && !S_ISDIR(file->mode))
file = NULL;
lastpath_struct = file;
- }
+ } else if (file && S_ISDIR(file->mode))
+ change_local_filter_dir(fname, strlen(fname), ++depth);
strlcpy(lastpath, fname, sizeof lastpath);
lastpath_len = limit - fname;
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);
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;
fbuf[len++] = '.';
fbuf[len] = '\0';
}
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
} else if (len > 1 && fbuf[len-1] == '.' && fbuf[len-2] == '.'
&& (len == 2 || fbuf[len-3] == '/')) {
if (len + 2 >= MAXPATHLEN)
fbuf[len++] = '/';
fbuf[len++] = '.';
fbuf[len] = '\0';
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
} else if (fbuf[len-1] == '.' && (len == 1 || fbuf[len-2] == '/'))
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
else
name_type = NORMAL_NAME;
if (fn[0] == '/') {
fn = "/.";
len = 2;
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
} else if (fn[0] == '.')
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
} else if (fn[len-1] == '/') {
fn[--len] = '\0';
if (len == 1 && *fn == '.')
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
else
name_type = SLASH_ENDING_NAME;
}
if (!*fn) {
len = 1;
fn = ".";
- name_type = DOT_NAME;
+ name_type = DOTDIR_NAME;
}
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)
memmove(fbuf, fn, len + 1);
if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
- || is_daemon_excluded(fbuf, S_ISDIR(st.st_mode) != 0)
+ || (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode)))
|| (relative_paths && path_is_daemon_excluded(fbuf, 1))) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR_XFER, errno, "link_stat %s failed",
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;
} else if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf) {
/* Send the implied directories at the start of the
* source spec, so we get their permissions right. */
- char *lp = lastpath, *slash = fbuf;
- *p = '\0';
- /* Skip any initial directories in our path that we
- * have in common with lastpath. */
- for (fn = fbuf; *fn && *lp == *fn; lp++, fn++) {
- if (*fn == '/')
- slash = fn;
- }
- *p = '/';
- if (fn != p || (*lp && *lp != '/'))
- send_implied_dirs(f, flist, fbuf, slash, p, flags, 0);
+ send_implied_dirs(f, flist, fbuf, fbuf, p, flags, 0);
}
if (one_file_system)
if (recurse || (xfer_dirs && name_type != NORMAL_NAME)) {
struct file_struct *file;
- int top_flags = FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags;
file = send_file_name(f, flist, fbuf, &st,
- top_flags, ALL_FILTERS);
+ FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags,
+ NO_FILTERS);
if (!file)
continue;
if (inc_recurse) {
- if (name_type == DOT_NAME) {
+ if (name_type == DOTDIR_NAME) {
if (send_dir_depth < 0) {
send_dir_depth = 0;
change_local_filter_dir(fbuf, len, send_dir_depth);
} else
send_if_directory(f, flist, file, fbuf, len, flags);
} else
- send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS);
+ send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS);
}
gettimeofday(&end_tv, NULL);