X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/d6c9c3319b191d196c323174c0dc11c834ae9e75..9793bbb3646cbaa816d074dc925a4f4f7d40089f:/flist.c diff --git a/flist.c b/flist.c index 489d92c1..cac390b4 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,46 @@ 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, FLOG, fname, is_dir) < 0) { + errno = ENOENT; + return 1; + } + return 0; +} + +static inline int path_is_daemon_excluded(char *path, int ignore_filename) +{ + if (daemon_filter_list.head && path) { + char *slash = path; + + while ((slash = strchr(slash+1, '/')) != NULL) { + int ret; + *slash = '\0'; + ret = check_filter(&daemon_filter_list, FLOG, path, 1); + *slash = '/'; + if (ret < 0) { + errno = ENOENT; + return 1; + } + } + + if (!ignore_filename + && check_filter(&daemon_filter_list, FLOG, path, 1) < 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,13 +288,12 @@ 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; if (filter_list.head - && check_filter(&filter_list, fname, is_dir) < 0) + && check_filter(&filter_list, FINFO, fname, is_dir) < 0) return 1; return 0; } @@ -342,7 +377,7 @@ int push_pathname(const char *dir, int len) return 1; } -static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ndx) +static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) { static time_t modtime; static mode_t mode; @@ -355,40 +390,10 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ static gid_t gid; static const char *user_name, *group_name; static char lastname[MAXPATHLEN]; - char fname[MAXPATHLEN]; int first_hlink_ndx = -1; int l1, l2; int xflags; -#ifdef ICONV_OPTION - if (ic_send != (iconv_t)-1) { - xbuf outbuf, inbuf; - - INIT_CONST_XBUF(outbuf, fname); - - if (file->dirname) { - INIT_XBUF_STRLEN(inbuf, (char*)file->dirname); - outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */ - if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) - goto convert_error; - outbuf.size += 2; - outbuf.buf[outbuf.len++] = '/'; - } - - INIT_XBUF_STRLEN(inbuf, (char*)file->basename); - if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { - convert_error: - io_error |= IOERR_GENERAL; - rprintf(FINFO, - "[%s] cannot convert filename: %s (%s)\n", - who_am_i(), f_name(file, fname), strerror(errno)); - return; - } - outbuf.buf[outbuf.len] = '\0'; - } else -#endif - f_name(file, fname); - /* Initialize starting value of xflags. */ if (protocol_version >= 30 && S_ISDIR(file->mode)) { dir_count++; @@ -675,10 +680,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist, } #endif - clean_fname(thisname, 0); + if (*thisname) + 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; @@ -854,7 +860,6 @@ static struct file_struct *recv_file_entry(struct file_list *flist, bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len); - bp += basename_len; #ifdef SUPPORT_HARD_LINKS if (xflags & XMIT_HLINKED) @@ -919,6 +924,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #ifdef SUPPORT_LINKS if (linkname_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); @@ -930,7 +936,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 @@ -1021,7 +1027,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. */ @@ -1177,7 +1183,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; #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && flist && flist->prev) { @@ -1216,7 +1221,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, #ifdef SUPPORT_LINKS if (linkname_len) - memcpy(bp, linkname, linkname_len); + memcpy(bp + basename_len, linkname, linkname_len); #endif if (always_checksum && am_sender && S_ISREG(st.st_mode)) @@ -1265,13 +1270,10 @@ void unmake_file(struct file_struct *file) } static struct file_struct *send_file_name(int f, struct file_list *flist, - char *fname, STRUCT_STAT *stp, + const char *fname, STRUCT_STAT *stp, int flags, int filter_level) { struct file_struct *file; -#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS - stat_x sx; -#endif file = make_file(fname, flist, stp, flags, filter_level); if (!file) @@ -1280,28 +1282,59 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (chmod_modes && !S_ISLNK(file->mode)) file->mode = tweak_mode(file->mode, chmod_modes); + if (f >= 0) { + char fbuf[MAXPATHLEN]; +#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS + stat_x sx; +#endif + +#ifdef ICONV_OPTION + if (ic_send != (iconv_t)-1) { + xbuf outbuf, inbuf; + + INIT_CONST_XBUF(outbuf, fbuf); + + if (file->dirname) { + INIT_XBUF_STRLEN(inbuf, (char*)file->dirname); + outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */ + if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) + goto convert_error; + outbuf.size += 2; + outbuf.buf[outbuf.len++] = '/'; + } + + INIT_XBUF_STRLEN(inbuf, (char*)file->basename); + if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { + convert_error: + io_error |= IOERR_GENERAL; + rprintf(FINFO, + "[%s] cannot convert filename: %s (%s)\n", + who_am_i(), f_name(file, fbuf), strerror(errno)); + return NULL; + } + outbuf.buf[outbuf.len] = '\0'; + } else +#endif + f_name(file, fbuf); + #ifdef SUPPORT_ACLS - if (preserve_acls && !S_ISLNK(file->mode) && f >= 0) { - sx.st.st_mode = file->mode; - sx.acc_acl = sx.def_acl = NULL; - if (get_acl(fname, &sx) < 0) - return NULL; - } + 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) + return NULL; + } #endif #ifdef SUPPORT_XATTRS - if (preserve_xattrs && f >= 0) { - sx.xattr = NULL; - if (get_xattr(fname, &sx) < 0) - return NULL; - } + if (preserve_xattrs) { + sx.xattr = NULL; + if (get_xattr(fname, &sx) < 0) + return NULL; + } #endif - maybe_emit_filelist_progress(flist->used + flist_count_offset); + send_file_entry(f, fbuf, file, flist->used, flist->ndx_start); - flist_expand(flist, 1); - flist->files[flist->used++] = file; - if (f >= 0) { - send_file_entry(f, file, flist->used - 1, flist->ndx_start); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { send_acl(&sx, f); @@ -1315,6 +1348,12 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, } #endif } + + maybe_emit_filelist_progress(flist->used + flist_count_offset); + + flist_expand(flist, 1); + flist->files[flist->used++] = file; + return file; } @@ -1787,6 +1826,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()) @@ -1828,13 +1868,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); @@ -1884,8 +1924,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++; @@ -1893,8 +1935,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] == '/') { @@ -1930,6 +1979,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) 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)) continue; lastdir = pathname; @@ -1940,7 +1995,9 @@ 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) + || (relative_paths && path_is_daemon_excluded(fbuf, 1))) { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "link_stat %s failed", full_fname(fbuf)); @@ -1987,15 +2044,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);