Implement the "m", "o", "g" include modifiers to tweak the permissions,
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 2af7e88..0b3ebab 100644 (file)
--- 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);