Added a new arg to the make_file() call.
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index a24c117..08ac3c9 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -74,7 +74,6 @@ dev_t filesystem_dev; /* used to implement -x */
 static char empty_sum[MD4_SUM_LENGTH];
 static int flist_count_offset;
 static unsigned int file_struct_len;
-static struct file_list *sorting_flist;
 
 static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
 static void output_flist(struct file_list *flist);
@@ -143,14 +142,14 @@ static void list_file_entry(struct file_struct *f)
                rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
                        perms,
                        (double)f->length, timestring(f->modtime),
-                       safe_fname(f_name(f)), safe_fname(f->u.link));
+                       f_name(f, NULL), f->u.link);
        } else
 #endif
        {
                rprintf(FINFO, "%s %11.0f %s %s\n",
                        perms,
                        (double)f->length, timestring(f->modtime),
-                       safe_fname(f_name(f)));
+                       f_name(f, NULL));
        }
 }
 
@@ -183,7 +182,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
                if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
                        if (verbose > 1) {
                                rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
-                                       safe_fname(path), safe_fname(linkbuf));
+                                       path, linkbuf);
                        }
                        return do_stat(path, buffer);
                }
@@ -336,7 +335,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
 
        io_write_phase = "send_file_entry";
 
-       f_name_to(file, fname);
+       f_name(file, fname);
 
        flags = base_flags;
 
@@ -534,7 +533,7 @@ static struct file_struct *receive_file_entry(struct file_list *flist,
        if (l2 >= MAXPATHLEN - l1) {
                rprintf(FERROR,
                        "overflow: flags=0x%x l1=%d l2=%d lastname=%s\n",
-                       flags, l1, l2, safe_fname(lastname));
+                       flags, l1, l2, lastname);
                overflow_exit("receive_file_entry");
        }
 
@@ -752,8 +751,7 @@ struct file_struct *make_file(char *fname, struct file_list *flist,
 
        if (strlcpy(thisname, fname, sizeof thisname)
            >= sizeof thisname - flist_dir_len) {
-               rprintf(FINFO, "skipping overly long name: %s\n",
-                       safe_fname(fname));
+               rprintf(FINFO, "skipping overly long name: %s\n", fname);
                return NULL;
        }
        clean_fname(thisname, 0);
@@ -798,7 +796,7 @@ struct file_struct *make_file(char *fname, struct file_list *flist,
                goto skip_filters;
 
        if (S_ISDIR(st.st_mode) && !xfer_dirs) {
-               rprintf(FINFO, "skipping directory %s\n", safe_fname(thisname));
+               rprintf(FINFO, "skipping directory %s\n", thisname);
                return NULL;
        }
 
@@ -820,11 +818,11 @@ struct file_struct *make_file(char *fname, struct file_list *flist,
                                return NULL;
        }
 
-    skip_filters:
+  skip_filters:
 
        if (verbose > 2) {
                rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
-                       who_am_i(), safe_fname(thisname), filter_level);
+                       who_am_i(), thisname, filter_level);
        }
 
        if ((basename = strrchr(thisname, '/')) != NULL) {
@@ -853,12 +851,11 @@ struct file_struct *make_file(char *fname, struct file_list *flist,
 
        alloc_len = file_struct_len + dirname_len + basename_len
            + linkname_len + sum_len;
-       if (flist) {
-               bp = pool_alloc(flist->file_pool, alloc_len,
-                   "receive_file_entry");
-       } else {
+       if (flist)
+               bp = pool_alloc(flist->file_pool, alloc_len, "make_file");
+       else {
                if (!(bp = new_array(char, alloc_len)))
-                       out_of_memory("receive_file_entry");
+                       out_of_memory("make_file");
        }
 
        file = (struct file_struct *)bp;
@@ -980,7 +977,7 @@ static void send_if_directory(int f, struct file_list *flist,
        char is_dot_dir = fbuf[ol-1] == '.' && (ol == 1 || fbuf[ol-2] == '/');
 
        if (S_ISDIR(file->mode)
-           && !(file->flags & FLAG_MOUNT_POINT) && f_name_to(file, fbuf)) {
+           && !(file->flags & FLAG_MOUNT_POINT) && f_name(file, fbuf)) {
                void *save_filters;
                unsigned int len = strlen(fbuf);
                if (len > 1 && fbuf[len-1] == '/')
@@ -1031,14 +1028,15 @@ static void send_directory(int f, struct file_list *flist,
                if (dname[0] == '.' && (dname[1] == '\0'
                    || (dname[1] == '.' && dname[2] == '\0')))
                        continue;
-               if (strlcpy(p, dname, remainder) < remainder)
-                       send_file_name(f, flist, fbuf, 0);
-               else {
+               if (strlcpy(p, dname, remainder) >= remainder) {
                        io_error |= IOERR_GENERAL;
                        rprintf(FINFO,
                                "cannot send long-named file %s\n",
                                full_fname(fbuf));
+                       continue;
                }
+
+               send_file_name(f, flist, fbuf, 0);
        }
 
        fbuf[len] = '\0';
@@ -1104,7 +1102,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                }
 
                len = strlen(fbuf);
-               if (!len || fbuf[len - 1] == '/') {
+               if (relative_paths) {
+                       /* We clean up fbuf below. */
+                       is_dot_dir = 0;
+               } else if (!len || fbuf[len - 1] == '/') {
                        if (len == 2 && fbuf[0] == '.') {
                                /* Turn "./" into just "." rather than "./." */
                                fbuf[1] = '\0';
@@ -1136,8 +1137,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                }
 
                if (S_ISDIR(st.st_mode) && !xfer_dirs) {
-                       rprintf(FINFO, "skipping directory %s\n",
-                               safe_fname(fbuf));
+                       rprintf(FINFO, "skipping directory %s\n", fbuf);
                        continue;
                }
 
@@ -1156,16 +1156,41 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                                fn = p + 1;
                        } else
                                fn = fbuf;
-               } else if ((p = strstr(fbuf, "/./")) != NULL) {
-                       *p = '\0';
-                       if (p == fbuf)
-                               dir = "/";
-                       else
-                               dir = fbuf;
-                       len -= p - fbuf + 3;
-                       fn = p + 3;
-               } else
-                       fn = fbuf;
+               } else {
+                       if ((p = strstr(fbuf, "/./")) != NULL) {
+                               *p = '\0';
+                               if (p == fbuf)
+                                       dir = "/";
+                               else
+                                       dir = fbuf;
+                               len -= p - fbuf + 3;
+                               fn = p + 3;
+                       } else
+                               fn = fbuf;
+                       /* Get rid of trailing "/" and "/.". */
+                       while (len) {
+                               if (fn[len - 1] == '/')
+                                       len--;
+                               else if (len >= 2 && fn[len - 1] == '.'
+                                                 && fn[len - 2] == '/') {
+                                       if (!(len -= 2) && !dir) {
+                                               len++;
+                                               break;
+                                       }
+                               } else
+                                       break;
+                       }
+                       fn[len] = '\0';
+                       /* Reject a ".." dir in the active part of the path. */
+                       if ((p = strstr(fbuf, "..")) != NULL
+                        && (p[2] == '/' || p[2] == '\0')
+                        && (p == fbuf || p[-1] == '/')) {
+                               rprintf(FERROR,
+                                   "using a \"..\" dir is invalid with --relative: %s\n",
+                                   fbuf);
+                               exit_cleanup(RERR_SYNTAX);
+                       }
+               }
 
                if (!*fn) {
                        len = 1;
@@ -1314,7 +1339,6 @@ struct file_list *recv_file_list(int f)
        if (!flist->files)
                goto oom;
 
-
        while ((flags = read_byte(f)) != 0) {
                struct file_struct *file;
 
@@ -1333,7 +1357,7 @@ struct file_list *recv_file_list(int f)
 
                if (verbose > 2) {
                        rprintf(FINFO, "recv_file_name(%s)\n",
-                               safe_fname(f_name(file)));
+                               f_name(file, NULL));
                }
        }
        receive_file_entry(NULL, 0, 0); /* Signal that we're done. */
@@ -1375,7 +1399,7 @@ struct file_list *recv_file_list(int f)
 
        return flist;
 
-oom:
+  oom:
        out_of_memory("recv_file_list");
        return NULL;            /* not reached */
 }
@@ -1479,10 +1503,8 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
                return;
        }
 
-       sorting_flist = flist;
        qsort(flist->files, flist->count,
            sizeof flist->files[0], (int (*)())file_compare);
-       sorting_flist = NULL;
 
        for (i = no_dups? 0 : flist->count; i < flist->count; i++) {
                if (flist->files[i]->basename) {
@@ -1525,7 +1547,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
                        if (verbose > 1 && !am_server) {
                                rprintf(FINFO,
                                        "removing duplicate name %s from file list (%d)\n",
-                                       safe_fname(f_name(file)), drop);
+                                       f_name(file, NULL), drop);
                        }
                        /* Make sure that if we unduplicate '.', that we don't
                         * lose track of a user-specified top directory. */
@@ -1589,7 +1611,7 @@ static void output_flist(struct file_list *flist)
                        sprintf(depthbuf, "%d", file->dir.depth);
                rprintf(FINFO, "[%s] i=%d %s %s%s%s%s mode=0%o len=%.0f%s%s flags=%x\n",
                        who, i, am_sender ? NS(file->dir.root) : depthbuf,
-                       file->dirname ? safe_fname(file->dirname) : "",
+                       file->dirname ? file->dirname : "",
                        file->dirname ? "/" : "", NS(file->basename),
                        S_ISDIR(file->mode) ? "/" : "", (int)file->mode,
                        (double)file->length, uidbuf, gidbuf, file->flags);
@@ -1743,14 +1765,23 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2)
 }
 
 /* Return a copy of the full filename of a flist entry, using the indicated
- * buffer.  No size-checking is done because we checked the size when creating
- * the file_struct entry.
+ * buffer or one of 5 static buffers if fbuf is NULL.  No size-checking is
+ * done because we checked the size when creating the file_struct entry.
  */
-char *f_name_to(struct file_struct *f, char *fbuf)
+char *f_name(struct file_struct *f, char *fbuf)
 {
        if (!f || !f->basename)
                return NULL;
 
+       if (!fbuf) {
+               static char names[5][MAXPATHLEN];
+               static unsigned int n;
+
+               n = (n + 1) % (sizeof names / sizeof names[0]);
+
+               fbuf = names[n];
+       }
+
        if (f->dirname) {
                int len = strlen(f->dirname);
                memcpy(fbuf, f->dirname, len);
@@ -1758,18 +1789,8 @@ char *f_name_to(struct file_struct *f, char *fbuf)
                strcpy(fbuf + len + 1, f->basename);
        } else
                strcpy(fbuf, f->basename);
-       return fbuf;
-}
 
-/* Like f_name_to(), but we rotate through 5 static buffers of our own. */
-char *f_name(struct file_struct *f)
-{
-       static char names[5][MAXPATHLEN];
-       static unsigned int n;
-
-       n = (n + 1) % (sizeof names / sizeof names[0]);
-
-       return f_name_to(f, names[n]);
+       return fbuf;
 }
 
 /* Do a non-recursive scan of the named directory, possibly ignoring all