Switching to GPL 3.
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 8d4ec1d..87dbf41 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -7,7 +7,7 @@
  * Copyright (C) 2002-2007 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
+ * it under the terms of the GNU General Public License version 3 as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ * with this program; if not, visit the http://fsf.org website.
  */
 
 #include "rsync.h"
@@ -50,8 +49,8 @@ extern int preserve_links;
 extern int preserve_hard_links;
 extern int preserve_devices;
 extern int preserve_specials;
-extern int preserve_uid;
-extern int preserve_gid;
+extern int uid_ndx;
+extern int gid_ndx;
 extern int relative_paths;
 extern int implied_dirs;
 extern int file_extra_cnt;
@@ -308,6 +307,15 @@ static void flist_expand(struct file_list *flist, int extra)
                out_of_memory("flist_expand");
 }
 
+static void flist_done_allocating(struct file_list *flist)
+{
+       void *ptr = pool_boundary(flist->file_pool, 8*1024);
+       if (flist->pool_boundary == ptr)
+               flist->pool_boundary = NULL; /* list didn't use any pool memory */
+       else
+               flist->pool_boundary = ptr;
+}
+
 int push_pathname(const char *dir, int len)
 {
        if (dir == pathname)
@@ -405,24 +413,24 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
                }
        } else if (protocol_version < 28)
                rdev = MAKEDEV(0, 0);
-       if (preserve_uid) {
+       if (uid_ndx) {
                if ((uid_t)F_OWNER(file) == uid && *lastname)
                        flags |= XMIT_SAME_UID;
                else {
                        uid = F_OWNER(file);
-                       if (preserve_uid && !numeric_ids) {
+                       if (uid_ndx && !numeric_ids) {
                                user_name = add_uid(uid);
                                if (inc_recurse && user_name)
                                        flags |= XMIT_USER_NAME_FOLLOWS;
                        }
                }
        }
-       if (preserve_gid) {
+       if (gid_ndx) {
                if ((gid_t)F_GROUP(file) == gid && *lastname)
                        flags |= XMIT_SAME_GID;
                else {
                        gid = F_GROUP(file);
-                       if (preserve_gid && !numeric_ids) {
+                       if (gid_ndx && !numeric_ids) {
                                group_name = add_gid(gid);
                                if (inc_recurse && group_name)
                                        flags |= XMIT_GROUP_NAME_FOLLOWS;
@@ -504,7 +512,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
        }
        if (!(flags & XMIT_SAME_MODE))
                write_int(f, to_wire_mode(mode));
-       if (preserve_uid && !(flags & XMIT_SAME_UID)) {
+       if (uid_ndx && !(flags & XMIT_SAME_UID)) {
                if (protocol_version < 30)
                        write_int(f, uid);
                else {
@@ -516,7 +524,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
                        }
                }
        }
-       if (preserve_gid && !(flags & XMIT_SAME_GID)) {
+       if (gid_ndx && !(flags & XMIT_SAME_GID)) {
                if (protocol_version < 30)
                        write_int(f, gid);
                else {
@@ -692,9 +700,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                file_length = F_LENGTH(first);
                modtime = first->modtime;
                mode = first->mode;
-               if (preserve_uid)
+               if (uid_ndx)
                        uid = F_OWNER(first);
-               if (preserve_gid)
+               if (gid_ndx)
                        gid = F_GROUP(first);
                if ((preserve_devices && IS_DEVICE(mode))
                 || (preserve_specials && IS_SPECIAL(mode))) {
@@ -730,7 +738,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
        if (chmod_modes && !S_ISLNK(mode))
                mode = tweak_mode(mode, chmod_modes);
 
-       if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
+       if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
                if (protocol_version < 30)
                        uid = (uid_t)read_int(f);
                else {
@@ -741,7 +749,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                                uid = match_uid(uid);
                }
        }
-       if (preserve_gid && !(xflags & XMIT_SAME_GID)) {
+       if (gid_ndx && !(xflags & XMIT_SAME_GID)) {
                if (protocol_version < 30)
                        gid = (gid_t)read_int(f);
                else {
@@ -848,9 +856,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
        }
        file->mode = mode;
-       if (preserve_uid)
+       if (uid_ndx)
                F_OWNER(file) = uid;
-       if (preserve_gid) {
+       if (gid_ndx) {
                F_GROUP(file) = gid;
                file->flags |= gid_flags;
        }
@@ -1169,9 +1177,9 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
                OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
        }
        file->mode = st.st_mode;
-       if (preserve_uid)
+       if (uid_ndx)
                F_OWNER(file) = st.st_uid;
-       if (preserve_gid)
+       if (gid_ndx)
                F_GROUP(file) = st.st_gid;
 
        if (basename != thisname)
@@ -1200,9 +1208,9 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
                        file->modtime = st2.st_mtime;
                        file->len32 = 0;
                        file->mode = st2.st_mode;
-                       if (preserve_uid)
+                       if (uid_ndx)
                                F_OWNER(file) = st2.st_uid;
-                       if (preserve_gid)
+                       if (gid_ndx)
                                F_GROUP(file) = st2.st_gid;
                } else
                        file->mode = save_mode;
@@ -1318,7 +1326,7 @@ static int file_compare(const void *file1, const void *file2)
                          *(struct file_struct **)file2);
 }
 
-/* The guts of a merge sort algorithm.  This was derived from the GNU C
+/* The guts of a merge-sort algorithm.  This was derived from the glibc
  * version, but I (Wayne) changed the merge code to do less copying and
  * to require only half the amount of temporary memory. */
 static void fsort_tmp(struct file_struct **fp, size_t num,
@@ -1562,6 +1570,7 @@ void send_extra_file_list(int f, int at_least)
                clean_flist(flist, 0);
 
                add_dirs_to_tree(send_dir_ndx, flist, dir_count - dstart);
+               flist_done_allocating(flist);
 
                file_total += flist->count;
                future_cnt += flist->count;
@@ -1895,6 +1904,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
 
        if (inc_recurse) {
                add_dirs_to_tree(-1, flist, dir_count);
+               flist_done_allocating(flist);
                if (send_dir_ndx < 0) {
                        write_ndx(f, NDX_FLIST_EOF);
                        flist_eof = 1;
@@ -2001,7 +2011,9 @@ struct file_list *recv_file_list(int f)
                }
        }
 
-       if (!inc_recurse && f >= 0)
+       if (inc_recurse)
+               flist_done_allocating(flist);
+       else if (f >= 0)
                recv_id_list(f, flist);
 
        clean_flist(flist, relative_paths);
@@ -2137,34 +2149,42 @@ struct file_list *flist_new(int flags, char *msg)
 
        memset(flist, 0, sizeof flist[0]);
 
-       if (!(flags & FLIST_TEMP)) {
-               if (first_flist) {
-                       flist->ndx_start = first_flist->prev->ndx_start
-                                        + first_flist->prev->count;
-               }
+       if (flags & FLIST_TEMP) {
+               if (!(flist->file_pool = pool_create(SMALL_EXTENT, 0,
+                                               out_of_memory, POOL_INTERN)))
+                       out_of_memory(msg);
+       } else {
                /* This is a doubly linked list with prev looping back to
                 * the end of the list, but the last next pointer is NULL. */
-               if (!first_flist)
+               if (!first_flist) {
+                       flist->file_pool = pool_create(NORMAL_EXTENT, 0,
+                                               out_of_memory, POOL_INTERN);
+                       if (!flist->file_pool)
+                               out_of_memory(msg);
+
                        first_flist = cur_flist = flist->prev = flist;
-               else {
+               } else {
+                       flist->file_pool = first_flist->file_pool;
+
+                       flist->ndx_start = first_flist->prev->ndx_start
+                                        + first_flist->prev->count;
+
                        flist->prev = first_flist->prev;
                        flist->prev->next = first_flist->prev = flist;
                }
+               flist->pool_boundary = pool_boundary(flist->file_pool, 0);
                flist_cnt++;
        }
 
-       if (!(flist->file_pool = pool_create(FILE_EXTENT, 0, out_of_memory, POOL_INTERN)))
-               out_of_memory(msg);
-
        return flist;
 }
 
 /* Free up all elements in a flist. */
 void flist_free(struct file_list *flist)
 {
-       if (!flist->prev)
-               /* Was FLIST_TEMP dir-list. */
-       else if (flist == flist->prev) {
+       if (!flist->prev) {
+               /* Was FLIST_TEMP dir-list. */
+       else if (flist == flist->prev) {
                first_flist = cur_flist = NULL;
                file_total = 0;
                flist_cnt = 0;
@@ -2183,7 +2203,11 @@ void flist_free(struct file_list *flist)
                flist_cnt--;
        }
 
-       pool_destroy(flist->file_pool);
+       if (!flist->prev || !flist_cnt)
+               pool_destroy(flist->file_pool);
+       else
+               pool_free_old(flist->file_pool, flist->pool_boundary);
+
        if (flist->sorted && flist->sorted != flist->files)
                free(flist->sorted);
        free(flist->files);
@@ -2375,12 +2399,12 @@ static void output_flist(struct file_list *flist)
                who, flist->ndx_start, flist->count, flist->low, flist->high);
        for (i = 0; i < flist->count; i++) {
                file = flist->sorted[i];
-               if ((am_root || am_sender) && preserve_uid) {
+               if ((am_root || am_sender) && uid_ndx) {
                        snprintf(uidbuf, sizeof uidbuf, " uid=%u",
                                 F_OWNER(file));
                } else
                        *uidbuf = '\0';
-               if (preserve_gid) {
+               if (gid_ndx) {
                        static char parens[] = "(\0)\0\0\0";
                        char *pp = parens + (file->flags & FLAG_SKIP_GROUP ? 0 : 3);
                        snprintf(gidbuf, sizeof gidbuf, " gid=%s%u%s",