X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/d3d07a5e860f1cde0e234ec7a1aff7111a2c514f..d48810ba5b0b8d09b272092a70da1255c2346ab8:/flist.c diff --git a/flist.c b/flist.c index 665fa19f..dce55c7b 100644 --- a/flist.c +++ b/flist.c @@ -76,7 +76,7 @@ extern char curr_dir[MAXPATHLEN]; 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; @@ -232,10 +232,20 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) #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) @@ -252,8 +262,7 @@ static int is_excluded(char *fname, int is_dir, int filter_level) 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; @@ -678,7 +687,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, 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; @@ -819,9 +828,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #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)) @@ -854,7 +863,6 @@ static struct file_struct *recv_file_entry(struct file_list *flist, 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) @@ -919,7 +927,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #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); @@ -931,7 +939,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, } 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 @@ -1022,7 +1030,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } 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. */ @@ -1123,8 +1131,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, 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", @@ -1172,7 +1186,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, 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) { @@ -1210,16 +1223,17 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, 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. */ @@ -1255,12 +1269,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, /* 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, @@ -1786,6 +1795,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) | (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()) @@ -1827,13 +1837,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) 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); @@ -1883,8 +1893,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) *p = '\0'; if (p == fbuf) dir = "/"; - else + else { dir = fbuf; + clean_fname(dir, 0); + } fn = p + 3; while (*fn == '/') fn++; @@ -1892,8 +1904,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) *--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] == '/') { @@ -1939,7 +1958,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) 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)); @@ -1986,15 +2006,17 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) 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);