* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2002-2007 Wayne Davison
+ * Copyright (C) 2002-2008 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
extern int one_file_system;
extern int copy_dirlinks;
extern int keep_dirlinks;
+extern int preserve_uid;
+extern int preserve_gid;
extern int preserve_acls;
extern int preserve_xattrs;
extern int preserve_links;
extern struct chmod_mode_struct *chmod_modes;
extern struct filter_list_struct filter_list;
-extern struct filter_list_struct server_filter_list;
+extern struct filter_list_struct daemon_filter_list;
#ifdef ICONV_OPTION
extern int filesfrom_convert;
#endif
}
+static inline int is_daemon_excluded(const char *fname, int is_dir)
+{
+ if (daemon_filter_list.head
+ && check_filter(&daemon_filter_list, fname, is_dir) < 0) {
+ errno = ENOENT;
+ return 1;
+ }
+ return 0;
+}
+
/* This function is used to check if a file should be included/excluded
* from the list of files based on its name and type etc. The value of
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
-static int is_excluded(char *fname, int is_dir, int filter_level)
+static int is_excluded(const char *fname, int is_dir, int filter_level)
{
#if 0 /* This currently never happens, so avoid a useless compare. */
if (filter_level == NO_FILTERS)
return 0;
}
}
- if (server_filter_list.head
- && check_filter(&server_filter_list, fname, is_dir) < 0)
+ if (is_daemon_excluded(fname, is_dir))
return 1;
if (filter_level != ALL_FILTERS)
return 0;
}
} else if (protocol_version < 28)
rdev = MAKEDEV(0, 0);
- if (uid_ndx) {
+ if (preserve_uid) {
if ((uid_t)F_OWNER(file) == uid && *lastname)
xflags |= XMIT_SAME_UID;
else {
uid = F_OWNER(file);
- if (uid_ndx && !numeric_ids) {
+ if (!numeric_ids) {
user_name = add_uid(uid);
if (inc_recurse && user_name)
xflags |= XMIT_USER_NAME_FOLLOWS;
}
}
}
- if (gid_ndx) {
+ if (preserve_gid) {
if ((gid_t)F_GROUP(file) == gid && *lastname)
xflags |= XMIT_SAME_GID;
else {
gid = F_GROUP(file);
- if (gid_ndx && !numeric_ids) {
+ if (!numeric_ids) {
group_name = add_gid(gid);
if (inc_recurse && group_name)
xflags |= XMIT_GROUP_NAME_FOLLOWS;
}
if (!(xflags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(mode));
- if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
+ if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
if (protocol_version < 30)
write_int(f, uid);
else {
}
}
}
- if (gid_ndx && !(xflags & XMIT_SAME_GID)) {
+ if (preserve_gid && !(xflags & XMIT_SAME_GID)) {
if (protocol_version < 30)
write_int(f, gid);
else {
clean_fname(thisname, 0);
if (sanitize_paths)
- sanitize_path(thisname, thisname, "", 0);
+ sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
if ((basename = strrchr(thisname, '/')) != NULL) {
int len = basename++ - thisname;
file_length = F_LENGTH(first);
modtime = first->modtime;
mode = first->mode;
- if (uid_ndx)
+ if (preserve_uid)
uid = F_OWNER(first);
- if (gid_ndx)
+ if (preserve_gid)
gid = F_GROUP(first);
if ((preserve_devices && IS_DEVICE(mode))
|| (preserve_specials && IS_SPECIAL(mode))) {
if (chmod_modes && !S_ISLNK(mode))
mode = tweak_mode(mode, chmod_modes);
- if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
+ if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
if (protocol_version < 30)
uid = (uid_t)read_int(f);
else {
uid = match_uid(uid);
}
}
- if (gid_ndx && !(xflags & XMIT_SAME_GID)) {
+ if (preserve_gid && !(xflags & XMIT_SAME_GID)) {
if (protocol_version < 30)
gid = (gid_t)read_int(f);
else {
#endif
#ifdef SUPPORT_ACLS
- /* We need one or two index int32s when we're preserving ACLs. */
- if (preserve_acls)
- extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN;
+ /* Directories need an extra int32 for the default ACL. */
+ if (preserve_acls && S_ISDIR(mode))
+ extra_len += EXTRA_LEN;
#endif
if (always_checksum && S_ISREG(mode))
bp += FILE_STRUCT_LEN;
memcpy(bp, basename, basename_len);
- bp += basename_len + linkname_len; /* skip space for symlink too */
#ifdef SUPPORT_HARD_LINKS
if (xflags & XMIT_HLINKED)
OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
}
file->mode = mode;
- if (uid_ndx)
+ if (preserve_uid)
F_OWNER(file) = uid;
- if (gid_ndx) {
+ if (preserve_gid) {
F_GROUP(file) = gid;
file->flags |= gid_flags;
}
#ifdef SUPPORT_LINKS
if (linkname_len) {
- bp = (char*)file->basename + basename_len;
+ bp += basename_len;
if (first_hlink_ndx >= flist->ndx_start) {
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
memcpy(bp, F_SYMLINK(first), linkname_len);
} else {
read_sbuf(f, bp, linkname_len - 1);
if (sanitize_paths)
- sanitize_path(bp, bp, "", lastdir_depth);
+ sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT);
}
}
#endif
}
clean_fname(thisname, 0);
if (sanitize_paths)
- sanitize_path(thisname, thisname, "", 0);
+ sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
if (stp && S_ISDIR(stp->st_mode)) {
st = *stp; /* Needed for "symlink/." with --relative. */
pool = dir_flist->file_pool;
} else
pool = flist->file_pool;
- } else
+ } else {
+#ifdef SUPPORT_ACLS
+ /* Directories need an extra int32 for the default ACL. */
+ if (preserve_acls && S_ISDIR(st.st_mode))
+ extra_len += EXTRA_LEN;
+#endif
pool = NULL;
+ }
if (verbose > 2) {
rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
bp += FILE_STRUCT_LEN;
memcpy(bp, basename, basename_len);
- bp += basename_len + linkname_len; /* skip space for symlink too */
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && flist && flist->prev) {
OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
}
file->mode = st.st_mode;
- if (uid_ndx)
+ if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */
F_OWNER(file) = st.st_uid;
- if (gid_ndx)
+ if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */
F_GROUP(file) = st.st_gid;
if (basename != thisname)
file->dirname = lastdir;
#ifdef SUPPORT_LINKS
- if (linkname_len) {
- bp = (char*)file->basename + basename_len;
- memcpy(bp, linkname, linkname_len);
- }
+ if (linkname_len)
+ 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);
- F_PATHNAME(file) = pathname;
+ if (am_sender)
+ F_PATHNAME(file) = pathname;
+ else if (!pool)
+ F_DEPTH(file) = extra_len / EXTRA_LEN;
/* This code is only used by the receiver when it is building
* a list of files for a delete pass. */
/* Only called for temporary file_struct entries created by make_file(). */
void unmake_file(struct file_struct *file)
{
- int extra_cnt = file_extra_cnt + LEN64_BUMP(file);
-#if EXTRA_ROUNDING > 0
- if (extra_cnt & EXTRA_ROUNDING)
- extra_cnt = (extra_cnt | EXTRA_ROUNDING) + 1;
-#endif
- free(REQ_EXTRA(file, extra_cnt));
+ free(REQ_EXTRA(file, F_DEPTH(file)));
}
static struct file_struct *send_file_name(int f, struct file_list *flist,
| (filesfrom_convert ? RL_CONVERT : 0)
#endif
| (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0);
+ int implied_dot_dir = 0;
rprintf(FLOG, "building file list\n");
if (show_filelist_p())
if (use_ff_fd) {
if (read_line(filesfrom_fd, fbuf, sizeof fbuf, rl_flags) == 0)
break;
- sanitize_path(fbuf, fbuf, "", 0);
+ sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS);
} else {
if (argc-- == 0)
break;
strlcpy(fbuf, *argv++, MAXPATHLEN);
if (sanitize_paths)
- sanitize_path(fbuf, fbuf, "", 0);
+ sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS);
}
len = strlen(fbuf);
*p = '\0';
if (p == fbuf)
dir = "/";
- else
+ else {
dir = fbuf;
+ clean_fname(dir, 0);
+ }
fn = p + 3;
while (*fn == '/')
fn++;
*--fn = '\0'; /* ensure room for '.' */
} else
fn = fbuf;
- len = clean_fname(fn, CFN_KEEP_LEADING_DOT_DIR
- | CFN_KEEP_TRAILING_SLASH
+ /* A leading ./ can be used in relative mode to affect
+ * the dest dir without its name being in the path. */
+ if (*fn == '.' && fn[1] == '/' && !implied_dot_dir) {
+ send_file_name(f, flist, ".", NULL,
+ (flags | FLAG_IMPLIED_DIR) & ~FLAG_CONTENT_DIR,
+ ALL_FILTERS);
+ implied_dot_dir = 1;
+ }
+ len = clean_fname(fn, CFN_KEEP_TRAILING_SLASH
| CFN_DROP_TRAILING_DOT_DIR);
if (len == 1) {
if (fn[0] == '/') {
if (fn != fbuf)
memmove(fbuf, fn, len + 1);
- if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0) {
+ if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
+ || is_daemon_excluded(fbuf, S_ISDIR(st.st_mode) != 0)) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR_XFER, errno, "link_stat %s failed",
full_fname(fbuf));
int top_flags = FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags;
file = send_file_name(f, flist, fbuf, &st,
top_flags, ALL_FILTERS);
+ if (!file)
+ continue;
if (inc_recurse) {
- if (name_type == DOT_NAME && file) {
+ if (name_type == DOT_NAME) {
if (send_dir_depth < 0) {
send_dir_depth = 0;
change_local_filter_dir(fbuf, len, send_dir_depth);
}
send_directory(f, flist, fbuf, len, flags);
}
- } else if (file)
+ } else
send_if_directory(f, flist, file, fbuf, len, flags);
} else
send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS);