Improved a length check in parse_merge_name().
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index dce55c7..cac390b 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -235,13 +235,39 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
 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) {
+        && 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. */
@@ -267,7 +293,7 @@ static int is_excluded(const char *fname, int is_dir, int filter_level)
        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;
 }
@@ -351,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;
@@ -364,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++;
@@ -684,7 +680,8 @@ 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, SP_DEFAULT);
@@ -1273,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)
@@ -1288,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);
@@ -1323,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;
 }
 
@@ -1948,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;
@@ -1959,7 +1996,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                        memmove(fbuf, fn, len + 1);
 
                if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
-                || is_daemon_excluded(fbuf, S_ISDIR(st.st_mode) != 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));