Moved list-only output from flist.c to generator.c so that it works
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index a5c7ca3..1452d6c 100644 (file)
--- a/flist.c
+++ b/flist.c
  */
 
 #include "rsync.h"
+#include "ifuncs.h"
 #include "rounding.h"
 #include "io.h"
 
 extern int verbose;
-extern int list_only;
 extern int am_root;
 extern int am_server;
 extern int am_daemon;
@@ -171,35 +171,6 @@ void show_flist_stats(void)
        /* Nothing yet */
 }
 
-static void list_file_entry(struct file_struct *f)
-{
-       char permbuf[PERMSTRING_SIZE];
-       double len;
-
-       if (!F_IS_ACTIVE(f)) {
-               /* this can happen if duplicate names were removed */
-               return;
-       }
-
-       permstring(permbuf, f->mode);
-       len = F_LENGTH(f);
-
-       /* TODO: indicate '+' if the entry has an ACL. */
-
-#ifdef SUPPORT_LINKS
-       if (preserve_links && S_ISLNK(f->mode)) {
-               rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
-                       permbuf, len, timestring(f->modtime),
-                       f_name(f, NULL), F_SYMLINK(f));
-       } else
-#endif
-       {
-               rprintf(FINFO, "%s %11.0f %s %s\n",
-                       permbuf, len, timestring(f->modtime),
-                       f_name(f, NULL));
-       }
-}
-
 /* Stat either a symlink or its referent, depending on the settings of
  * copy_links, copy_unsafe_links, etc.  Returns -1 on error, 0 on success.
  *
@@ -1076,16 +1047,19 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
        /* -x only affects directories because we need to avoid recursing
         * into a mount-point directory, not to avoid copying a symlinked
         * file if -L (or similar) was specified. */
-       if (one_file_system && st.st_dev != filesystem_dev
-        && S_ISDIR(st.st_mode)) {
-               if (one_file_system > 1) {
-                       if (verbose > 2) {
-                               rprintf(FINFO, "skipping mount-point dir %s\n",
-                                       thisname);
+       if (one_file_system && S_ISDIR(st.st_mode)) {
+               if (flags & FLAG_TOP_DIR)
+                       filesystem_dev = st.st_dev;
+               else if (st.st_dev != filesystem_dev) {
+                       if (one_file_system > 1) {
+                               if (verbose > 2) {
+                                       rprintf(FINFO, "skipping mount-point dir %s\n",
+                                               thisname);
+                               }
+                               return NULL;
                        }
-                       return NULL;
+                       flags |= FLAG_MOUNT_DIR;
                }
-               flags |= FLAG_MOUNT_DIR;
        }
 
        if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) {
@@ -1110,6 +1084,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
                 && flags & FLAG_DIVERT_DIRS) {
                        /* Room for parent/sibling/next-child info. */
                        extra_len += DIRNODE_EXTRA_CNT * EXTRA_LEN;
+                       if (relative_paths)
+                               extra_len += PTR_EXTRA_CNT * EXTRA_LEN;
                        dir_count++;
                        pool = dir_flist->file_pool;
                } else
@@ -1423,8 +1399,7 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist,
                dir_flist->files[dir_flist->used++] = file;
                dir_cnt--;
 
-               if (!(file->flags & FLAG_XFER_DIR)
-                || file->flags & FLAG_MOUNT_DIR)
+               if (file->flags & FLAG_MOUNT_DIR)
                        continue;
 
                if (dp)
@@ -1512,10 +1487,86 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
        }
 }
 
+static char lastpath[MAXPATHLEN] = "";
+static int lastpath_len = 0;
+static struct file_struct *lastpath_struct;
+
+static void send_implied_dirs(int f, struct file_list *flist, char *fname,
+                             char *start, char *limit, int flags, int is_dot_dir)
+{
+       struct file_struct *file;
+       item_list *rel_list;
+       char **ep, *slash;
+       int len, need_new_dir;
+
+       flags &= ~FLAG_XFER_DIR;
+
+       if (inc_recurse) {
+               if (lastpath_struct && F_PATHNAME(lastpath_struct) == pathname
+                && lastpath_len == limit - fname
+                && strncmp(lastpath, fname, lastpath_len) == 0)
+                       need_new_dir = 0;
+               else
+                       need_new_dir = 1;
+       } else
+               need_new_dir = 1;
+
+       if (need_new_dir) {
+               int save_copy_links = copy_links;
+               int save_xfer_dirs = xfer_dirs;
+
+               copy_links = xfer_dirs = 1;
+
+               *limit = '\0';
+
+               for (slash = start; (slash = strchr(slash+1, '/')) != NULL; ) {
+                       *slash = '\0';
+                       send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS);
+                       *slash = '/';
+               }
+
+               file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS);
+               if (inc_recurse) {
+                       if (file && !S_ISDIR(file->mode))
+                               file = NULL;
+                       lastpath_struct = file;
+               }
+
+               strlcpy(lastpath, fname, sizeof lastpath);
+               lastpath_len = limit - fname;
+
+               *limit = '/';
+
+               copy_links = save_copy_links;
+               xfer_dirs = save_xfer_dirs;
+
+               if (!inc_recurse)
+                       return;
+       }
+
+       if (!lastpath_struct)
+               return; /* dir must have vanished */
+
+       len = strlen(limit+1);
+       memcpy(&rel_list, F_DIR_RELS_P(lastpath_struct), sizeof rel_list);
+       if (!rel_list) {
+               if (!(rel_list = new0(item_list)))
+                       out_of_memory("send_implied_dirs");
+               memcpy(F_DIR_RELS_P(lastpath_struct), &rel_list, sizeof rel_list);
+       }
+       ep = EXPAND_ITEM_LIST(rel_list, char *, 32);
+       if (!(*ep = new_array(char, 1 + len + 1)))
+               out_of_memory("send_implied_dirs");
+       **ep = is_dot_dir;
+       strlcpy(*ep + 1, limit+1, len + 1);
+}
+
 static void send1extra(int f, struct file_struct *file, struct file_list *flist)
 {
        char fbuf[MAXPATHLEN];
-       int dlen;
+       item_list *rel_list;
+       int len, dlen, flags = FLAG_DIVERT_DIRS | FLAG_XFER_DIR;
+       size_t j;
 
        f_name(file, fbuf);
        dlen = strlen(fbuf);
@@ -1527,7 +1578,51 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
 
        change_local_filter_dir(fbuf, dlen, send_dir_depth);
 
-       send_directory(f, flist, fbuf, dlen, FLAG_DIVERT_DIRS | FLAG_XFER_DIR);
+       if (file->flags & FLAG_XFER_DIR)
+               send_directory(f, flist, fbuf, dlen, flags);
+
+       if (!relative_paths)
+               return;
+
+       memcpy(&rel_list, F_DIR_RELS_P(file), sizeof rel_list);
+       if (!rel_list)
+               return;
+
+       for (j = 0; j < rel_list->count; j++) {
+               char *slash, *ep = ((char**)rel_list->items)[j];
+               int is_dot_dir = *ep;
+
+               fbuf[dlen] = '/';
+               len = strlcpy(fbuf + dlen + 1, ep+1, sizeof fbuf - dlen - 1);
+               free(ep);
+               if (len >= (int)sizeof fbuf)
+                       continue; /* Impossible... */
+
+               slash = strchr(fbuf+dlen+1, '/');
+               if (slash) {
+                       send_implied_dirs(f, flist, fbuf, fbuf+dlen+1, slash, flags, is_dot_dir);
+                       continue;
+               }
+
+               if (is_dot_dir) {
+                       STRUCT_STAT st;
+                       if (link_stat(fbuf, &st, copy_dirlinks) != 0) {
+                               io_error |= IOERR_GENERAL;
+                               rsyserr(FERROR, errno, "link_stat %s failed",
+                                       full_fname(fbuf));
+                               continue;
+                       }
+                       send_file_name(f, flist, fbuf, &st,
+                           recurse || xfer_dirs ? FLAG_TOP_DIR | flags : flags,
+                           ALL_FILTERS);
+               } else {
+                       send_file_name(f, flist, fbuf, NULL,
+                           recurse ? FLAG_TOP_DIR | flags : flags,
+                           ALL_FILTERS);
+               }
+       }
+
+       free(rel_list);
 }
 
 void send_extra_file_list(int f, int at_least)
@@ -1637,7 +1732,6 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        int len, dirlen;
        STRUCT_STAT st;
        char *p, *dir;
-       char lastpath[MAXPATHLEN] = "";
        struct file_list *flist;
        struct timeval start_tv, end_tv;
        int64 start_write;
@@ -1645,8 +1739,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        int flags, disable_buffering;
        int reading_remotely = filesfrom_host != NULL;
        int rl_flags = (reading_remotely ? 0 : RL_DUMP_COMMENTS)
-                    | (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0)
-                    | (filesfrom_convert ? RL_CONVERT : 0);
+#ifdef ICONV_OPTION
+                    | (filesfrom_convert ? RL_CONVERT : 0)
+#endif
+                    | (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0);
 
        rprintf(FLOG, "building file list\n");
        if (show_filelist_p())
@@ -1814,7 +1910,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                        continue;
                }
 
-               if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf) {
+               if (inc_recurse && relative_paths && *fbuf) {
+                       if ((p = strchr(fbuf+1, '/')) != NULL) {
+                               send_implied_dirs(f, flist, fbuf, fbuf, p, flags, is_dot_dir);
+                               continue;
+                       }
+               } else if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf) {
                        /* Send the implied directories at the start of the
                         * source spec, so we get their permissions right. */
                        char *lp = lastpath, *slash = fbuf;
@@ -1826,29 +1927,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                                        slash = fn;
                        }
                        *p = '/';
-                       if (fn != p || (*lp && *lp != '/')) {
-                               int save_copy_links = copy_links;
-                               int save_xfer_dirs = xfer_dirs;
-                               int dir_flags = flags & ~FLAG_XFER_DIR;
-                               copy_links |= copy_unsafe_links;
-                               xfer_dirs = 1;
-                               while ((slash = strchr(slash+1, '/')) != 0) {
-                                       *slash = '\0';
-                                       send_file_name(f, flist, fbuf, NULL,
-                                                      dir_flags, ALL_FILTERS);
-                                       *slash = '/';
-                               }
-                               copy_links = save_copy_links;
-                               xfer_dirs = save_xfer_dirs;
-                               *p = '\0';
-                               strlcpy(lastpath, fbuf, sizeof lastpath);
-                               *p = '/';
-                       }
+                       if (fn != p || (*lp && *lp != '/'))
+                               send_implied_dirs(f, flist, fbuf, slash, p, flags, 0);
                }
 
-               if (one_file_system)
-                       filesystem_dev = st.st_dev;
-
                if (recurse || (xfer_dirs && is_dot_dir)) {
                        struct file_struct *file;
                        int top_flags = FLAG_TOP_DIR | flags;
@@ -2066,12 +2148,6 @@ struct file_list *recv_file_list(int f)
        if (verbose > 3)
                output_flist(flist);
 
-       if (list_only) {
-               int i;
-               for (i = flist->low; i <= flist->high; i++)
-                       list_file_entry(flist->files[i]);
-       }
-
        if (verbose > 2)
                rprintf(FINFO, "recv_file_list done\n");
 
@@ -2180,8 +2256,7 @@ struct file_list *flist_new(int flags, char *msg)
 {
        struct file_list *flist;
 
-       flist = new0(struct file_list);
-       if (!flist)
+       if (!(flist = new0(struct file_list)))
                out_of_memory(msg);
 
        if (flags & FLIST_TEMP) {
@@ -2305,7 +2380,7 @@ static void clean_flist(struct file_list *flist, int strip_root)
                         * list.  Otherwise keep the first one. */
                        if (S_ISDIR(file->mode)) {
                                struct file_struct *fp = flist->sorted[j];
-                               if (!S_ISDIR(fp->mode) || !(fp->flags & FLAG_XFER_DIR))
+                               if (!S_ISDIR(fp->mode))
                                        keep = i, drop = j;
                                else {
                                        if (am_sender)