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;
/* 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. */
#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
} 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)
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) {
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) {
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) {
} 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);