X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/b39f79296a4cea240c659cb7d264035198aa6d44..6694ead8b8bc8ce69fbe98fd68659eaff4aa8bfd:/flist.c diff --git a/flist.c b/flist.c index 2af7e88b..0b3ebab0 100644 --- a/flist.c +++ b/flist.c @@ -81,6 +81,7 @@ extern struct chmod_mode_struct *chmod_modes; extern struct filter_list_struct filter_list; extern struct filter_list_struct daemon_filter_list; +extern struct filter_struct *last_hit_filter; #ifdef ICONV_OPTION extern int filesfrom_convert; @@ -274,7 +275,8 @@ static inline int path_is_daemon_excluded(char *path, int ignore_filename) /* 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. */ + * filter_level is set to either SERVER_FILTERS or ALL_FILTERS. + * "last_hit_filter" will be set to the operative filter, or NULL if none. */ static int is_excluded(const char *fname, int is_dir, int filter_level) { #if 0 /* This currently never happens, so avoid a useless compare. */ @@ -283,6 +285,8 @@ static int is_excluded(const char *fname, int is_dir, int filter_level) #endif if (is_daemon_excluded(fname, is_dir)) return 1; + /* Don't leave a daemon include in last_hit_filter. */ + last_hit_filter = NULL; if (filter_level != ALL_FILTERS) return 0; if (filter_list.head @@ -1142,7 +1146,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } else if (readlink_stat(thisname, &st, linkname) != 0) { int save_errno = errno; /* See if file is excluded before reporting an error. */ - if (filter_level != NO_FILTERS + if (filter_level != NO_FILTERS && filter_level != ALL_FILTERS_NO_EXCLUDE && (is_excluded(thisname, 0, filter_level) || is_excluded(thisname, 1, filter_level))) { if (ignore_perishable && save_errno != ENOENT) @@ -1187,6 +1191,12 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (filter_level == NO_FILTERS) goto skip_filters; + if (filter_level == ALL_FILTERS_NO_EXCLUDE) { + /* Call only for the side effect of setting last_hit_filter to + * any operative include filter, which might affect attributes. */ + is_excluded(thisname, S_ISDIR(st.st_mode) != 0, ALL_FILTERS); + goto skip_filters; + } if (S_ISDIR(st.st_mode)) { if (!xfer_dirs) { @@ -1377,12 +1387,23 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, int flags, int filter_level) { struct file_struct *file; + BOOL can_tweak_mode; file = make_file(fname, flist, stp, flags, filter_level); if (!file) return NULL; - if (chmod_modes && !S_ISLNK(file->mode) && file->mode) + can_tweak_mode = !S_ISLNK(file->mode) && file->mode; + if ((filter_level == ALL_FILTERS || filter_level == ALL_FILTERS_NO_EXCLUDE) + && last_hit_filter) { + if ((last_hit_filter->flags & MATCHFLG_CHMOD) && can_tweak_mode) + file->mode = tweak_mode(file->mode, last_hit_filter->chmod->modes); + if ((last_hit_filter->flags & MATCHFLG_FORCE_OWNER) && uid_ndx) + F_OWNER(file) = last_hit_filter->force_uid; + if ((last_hit_filter->flags & MATCHFLG_FORCE_GROUP) && gid_ndx) + F_GROUP(file) = last_hit_filter->force_gid; + } + if (chmod_modes && can_tweak_mode) file->mode = tweak_mode(file->mode, chmod_modes); if (f >= 0) { @@ -2239,7 +2260,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) struct file_struct *file; file = send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags, - NO_FILTERS); + ALL_FILTERS_NO_EXCLUDE); if (!file) continue; if (inc_recurse) { @@ -2253,7 +2274,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) } else send_if_directory(f, flist, file, fbuf, len, flags); } else - send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS); + send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS_NO_EXCLUDE); } gettimeofday(&end_tv, NULL);