From matt at mattmccutchen.net Sat Aug 9 13:18:01 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sat, 09 Aug 2008 16:18:01 -0400 Subject: [Rsync-patches] [PATCH] Improve the readlink_stat error message. In-Reply-To: <1218308562.2567.14.camel@localhost> References: <1218308562.2567.14.camel@localhost> Message-ID: <1218313081.2567.15.camel@localhost> --- flist.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/flist.c b/flist.c index b228aab..5fe4130 100644 --- a/flist.c +++ b/flist.c @@ -1149,7 +1149,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } } else { io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, save_errno, "readlink %s failed", + rsyserr(FERROR_XFER, save_errno, "readlink_stat %s failed", full_fname(thisname)); } return NULL; -- 1.6.0.rc1.14.g8150 -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Sun Aug 10 13:39:13 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sun, 10 Aug 2008 16:39:13 -0400 Subject: [Rsync-patches] rsync 2.6.9 uses a lot of memory; has that changed in rsync 3.0.3 ? In-Reply-To: References: Message-ID: <1218400753.2569.6.camel@localhost> On Mon, 2008-08-04 at 13:22 -0700, Aleksey Tsalolikhin wrote: > I checked the rsync FAQ and it says this issue would require a major > rewrite of rsync, not sure if that entry is up to date or not - 3.0 is > a major rewrite AFAIK. The attached patch updates the memory usage portion of the FAQ for rsync 3.0.0. Matt -------------- next part -------------- A non-text attachment was scrubbed... Name: faq-3.0.0-memory-usage.diff Type: text/x-patch Size: 2890 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Thu Aug 14 10:59:02 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Thu, 14 Aug 2008 13:59:02 -0400 Subject: [Rsync-patches] [PATCH] Add instant-rsyncd to support/ . Message-ID: <1218736742.2498.39.camel@mattlaptop2.local> --- support/instant-rsyncd | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 107 insertions(+), 0 deletions(-) create mode 100755 support/instant-rsyncd diff --git a/support/instant-rsyncd b/support/instant-rsyncd new file mode 100755 index 0000000..dcd8757 --- /dev/null +++ b/support/instant-rsyncd @@ -0,0 +1,107 @@ +#!/bin/bash + +# instant-rsyncd lets you quickly set up and start a simple, unprivileged rsync +# daemon with a single module in the current directory. I've found it +# invaluable for quick testing, and I use it when writing a list of commands +# that people can paste into a terminal to reproduce a daemon-related bug. +# Sysadmins deploying an rsync daemon for the first time may find it helpful as +# a starting point. +# +# Usage: instant-rsyncd MODULE PORT RSYNCD-USERNAME [RSYNC-PATH] +# The script asks for the rsyncd user's password twice on stdin, once to set it +# and once to log in to test the daemon. +# -- Matt McCutchen + +set -e + +dir="$(pwd)" + +if [ "$#" -lt 3 ]; then + echo "I would install an rsync daemon in $dir if you gave me" + echo "a module name, a port, and an rsync username." + exit 1 +fi + +module="$1" +port="$2" +user="$3" +rsync="$4" +if [ ! "$rsync" ]; then + rsync=rsync +fi + +moduledir="${dir%/}/$module" + +echo +echo "I'm about to install an rsync daemon in $dir." +echo "It will listen on port $port for requests giving rsync username $user" +echo "and the password you are about to specify. It will serve a module" +echo "$module corresponding to $moduledir." +echo + +IFS='' read -s -p 'Desired password: ' password + +mkdir "$module" + +cat >rsyncd.conf <"$module".secrets <start <stop <<"EOF" +#!/bin/bash +set -e +cd `dirname $0` +! [ -e rsyncd.pid ] || kill -s SIGTERM $(< rsyncd.pid) +EOF +chmod +x stop + +path="rsync://$user@$(hostname):$port/$module/" + +if ./start; then + sleep .2 + echo + echo "I tried to start the daemon. The log file rsyncd.log says:" + echo + cat rsyncd.log + echo + echo "You can start and stop it with ./start and ./stop respectively." + echo "You can customize the configuration file rsyncd.conf." + echo + echo "Give rsync the following path to access the module:" + echo " $path" + echo + echo "Let's test the daemon now. Enter the password you chose." + echo '$' $rsync --list-only "$path" + $rsync --list-only "$path" + echo + echo "You should see an empty folder; it's $moduledir." +else + echo "Something went wrong. Do you see an error message?" +fi -- 1.6.0.rc3.9.g5ebb -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Thu Aug 14 10:59:14 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Thu, 14 Aug 2008 13:59:14 -0400 Subject: [Rsync-patches] [PATCH] Add support/savetransfer to .gitignore . Message-ID: <1218736754.2498.40.camel@mattlaptop2.local> --- .gitignore | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.gitignore b/.gitignore index b72d312..76693bb 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ config.status /rounding.h /doc/rsync.pdf /doc/rsync.ps +/support/savetransfer /testsuite/chown-fake.test /testsuite/devices-fake.test /patches -- 1.6.0.rc3.9.g5ebb -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Thu Aug 14 12:14:27 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Thu, 14 Aug 2008 15:14:27 -0400 Subject: [Rsync-patches] [PATCH] Improve the exit code 23 message. Message-ID: <1218741267.2498.48.camel@mattlaptop2.local> The new message is a bit long, but I'm hoping it will get users to check the previous error messages before mailing the list / filing a bug: "some files/attrs were not transferred, see previous error message(s)" --- log.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/log.c b/log.c index 609f3a5..672d721 100644 --- a/log.c +++ b/log.c @@ -88,7 +88,7 @@ struct { { RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" }, { RERR_WAITCHILD , "waitpid() failed" }, { RERR_MALLOC , "error allocating core memory buffers" }, - { RERR_PARTIAL , "some files could not be transferred" }, + { RERR_PARTIAL , "some files/attrs were not transferred, see previous error message(s)" }, { RERR_VANISHED , "some files vanished before they could be transferred" }, { RERR_TIMEOUT , "timeout in data send/receive" }, { RERR_CONTIMEOUT , "timeout waiting for daemon connection" }, -- 1.6.0.rc3.9.g5ebb -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Sun Aug 17 08:36:58 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sun, 17 Aug 2008 11:36:58 -0400 Subject: [Rsync-patches] [PATCH] Properly free filters loaded during a parent_dirscan to avoid a crash when they define another per-dir merge file. In-Reply-To: <1217984110.2541.29.camel@localhost> References: <1217984110.2541.29.camel@localhost> Message-ID: <1218987418.2466.4.camel@mattlaptop2.local> --- This patch, which is available in branch wip/perdir-merge of my rsync repository ( http://mattmccutchen.net/rsync/rsync.git/ ), should fix the crash but could use some additional testing. exclude.c | 39 +++++++++++++++++++++++++++++---------- rsync.h | 1 + 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/exclude.c b/exclude.c index 6eb83cb..cf93629 100644 --- a/exclude.c +++ b/exclude.c @@ -40,9 +40,9 @@ extern char curr_dir[MAXPATHLEN]; extern unsigned int curr_dir_len; extern unsigned int module_dirlen; -struct filter_list_struct filter_list = { 0, 0, "" }; -struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" }; -struct filter_list_struct daemon_filter_list = { 0, 0, " [daemon]" }; +struct filter_list_struct filter_list = { 0, 0, 0, "" }; +struct filter_list_struct cvs_filter_list = { 0, 0, 0, " [global CVS]" }; +struct filter_list_struct daemon_filter_list = { 0, 0, 0, " [daemon]" }; /* Need room enough for ":MODS " prefix plus some room to grow. */ #define MAX_RULE_PREFIX (16) @@ -102,9 +102,15 @@ static int mergelist_size = 0; * values (so we can pop back to them later) and set the tail to NULL. */ +static void free_filters(struct filter_struct *head); + static void free_filter(struct filter_struct *ex) { if (ex->match_flags & MATCHFLG_PERDIR_MERGE) { + /* Free the parent_dirscan list to clean up any per-dir + * mergelists it defined. Otherwise pop_local_filters may crash + * trying to restore nonexistent state for those mergelists. */ + free_filters(ex->u.mergelist->parent_dirscan_head); free(ex->u.mergelist->debug_type); free(ex->u.mergelist); mergelist_cnt--; @@ -113,6 +119,15 @@ static void free_filter(struct filter_struct *ex) free(ex); } +static void free_filters(struct filter_struct *head) +{ + while (head) { + struct filter_struct *next = head->next; + free_filter(head); + head = next; + } +} + /* Build a filter structure given a filter pattern. The value in "pat" * is not null-terminated. */ static void add_rule(struct filter_list_struct *listp, const char *pat, @@ -237,7 +252,7 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, if (!(lp = new_array(struct filter_list_struct, 1))) out_of_memory("add_rule"); - lp->head = lp->tail = NULL; + lp->head = lp->tail = lp->parent_dirscan_head = NULL; if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0) out_of_memory("add_rule"); ret->u.mergelist = lp; @@ -269,14 +284,10 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, static void clear_filter_list(struct filter_list_struct *listp) { if (listp->tail) { - struct filter_struct *ent, *next; /* Truncate any inherited items from the local list. */ listp->tail->next = NULL; /* Now free everything that is left. */ - for (ent = listp->head; ent; ent = next) { - next = ent->next; - free_filter(ent); - } + free_filters(listp->head); } listp->head = listp->tail = NULL; @@ -414,12 +425,20 @@ static BOOL setup_merge_file(struct filter_struct *ex, dirbuf_len = y - dirbuf; strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf)); parse_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS); - if (ex->match_flags & MATCHFLG_NO_INHERIT) + if (ex->match_flags & MATCHFLG_NO_INHERIT) { + /* Free the undesired rules to clean up any per-dir + * mergelists they defined. Otherwise pop_local_filters + * may crash trying to restore nonexistent state for + * those mergelists. */ + free_filters(lp->head); lp->head = NULL; + } lp->tail = NULL; strlcpy(y, save, MAXPATHLEN); while ((*x++ = *y++) != '/') {} } + /* Save current head for freeing when the mergelist becomes inactive. */ + lp->parent_dirscan_head = lp->head; parent_dirscan = False; free(pat); return 1; diff --git a/rsync.h b/rsync.h index 320d340..6083c81 100644 --- a/rsync.h +++ b/rsync.h @@ -813,6 +813,7 @@ struct filter_struct { struct filter_list_struct { struct filter_struct *head; struct filter_struct *tail; + struct filter_struct *parent_dirscan_head; char *debug_type; }; -- 1.6.0.rc3.13.gdfe0a -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Sun Aug 17 08:48:27 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sun, 17 Aug 2008 11:48:27 -0400 Subject: [Rsync-patches] parent_dirscan test case In-Reply-To: <1218987418.2466.4.camel@mattlaptop2.local> References: <1217984110.2541.29.camel@localhost> <1218987418.2466.4.camel@mattlaptop2.local> Message-ID: <1218988107.2466.7.camel@mattlaptop2.local> On Sun, 2008-08-17 at 11:37 -0400, Matt McCutchen wrote: > This patch, which is available in branch wip/perdir-merge of my rsync > repository ( http://mattmccutchen.net/rsync/rsync.git/ ), should fix the > crash but could use some additional testing. Attached is a simple test case for both ways the crash can happen (with or without the "n" modifier on the parent-dirscanning per-dir merge rule). Matt -------------- next part -------------- A non-text attachment was scrubbed... Name: parent-dirscan-test.tar.gz Type: application/x-compressed-tar Size: 500 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From matt at mattmccutchen.net Sun Aug 17 14:51:29 2008 From: matt at mattmccutchen.net (Matt McCutchen) Date: Sun, 17 Aug 2008 21:51:29 +0000 Subject: [Rsync-patches] [PATCH] Fix a crash with per-dir merge files, and add asserts and debug output. Message-ID: <1219009889.2466.14.camel@mattlaptop2.local> - Free a mergelist's parent_dirscanned filters the last time it is popped or as soon as the filters are discarded due to the "n" modifier. Aside from not leaking memory, this is needed to clean up any mergelists defined during the parent_dirscan to avoid crashing by trying to restore nonexistent state for them in pop_local_filters. - Make push_local_filters save the current mergelist_cnt, and make pop_local_filters assert that it has the correct number of mergelists before restoring their state. - Assert that mergelists get deactivated in strict LIFO order to catch any glitches as soon as they happen. Free linked lists of filters in reverse order to make that the case. - Add a bunch of mergelist-related debug output (--debug=filter2). --- When I added the two assertions to my previous fixed rsync (in wip/perdir-merge), I discovered that the parent_dirscan filters had to be freed in pop_local_filters rather than in free_filter. Thus, this revised fix supersedes (rather than adds to) the previous one. It is available in branch wip/perdir-merge-2. exclude.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++------------ rsync.h | 1 + 2 files changed, 113 insertions(+), 28 deletions(-) diff --git a/exclude.c b/exclude.c index 6eb83cb..52357aa 100644 --- a/exclude.c +++ b/exclude.c @@ -40,9 +40,9 @@ extern char curr_dir[MAXPATHLEN]; extern unsigned int curr_dir_len; extern unsigned int module_dirlen; -struct filter_list_struct filter_list = { 0, 0, "" }; -struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" }; -struct filter_list_struct daemon_filter_list = { 0, 0, " [daemon]" }; +struct filter_list_struct filter_list = { 0, 0, 0, "" }; +struct filter_list_struct cvs_filter_list = { 0, 0, 0, " [global CVS]" }; +struct filter_list_struct daemon_filter_list = { 0, 0, 0, " [daemon]" }; /* Need room enough for ":MODS " prefix plus some room to grow. */ #define MAX_RULE_PREFIX (16) @@ -102,17 +102,53 @@ static int mergelist_size = 0; * values (so we can pop back to them later) and set the tail to NULL. */ +static void teardown_mergelist(struct filter_struct *ex) +{ + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] deactivating mergelist #%d%s\n", + who_am_i(), mergelist_cnt - 1, + ex->u.mergelist->debug_type); + + /* We should deactivate mergelists in LIFO order. */ + assert(mergelist_cnt > 0); + assert(ex == mergelist_parents[mergelist_cnt - 1]); + + /* The parent_dirscan filters should have been freed. */ + assert(ex->u.mergelist->parent_dirscan_head == NULL); + + free(ex->u.mergelist->debug_type); + free(ex->u.mergelist); + mergelist_cnt--; +} + static void free_filter(struct filter_struct *ex) { - if (ex->match_flags & MATCHFLG_PERDIR_MERGE) { - free(ex->u.mergelist->debug_type); - free(ex->u.mergelist); - mergelist_cnt--; - } + if (ex->match_flags & MATCHFLG_PERDIR_MERGE) + teardown_mergelist(ex); free(ex->pattern); free(ex); } +static void free_filters(struct filter_struct *head) +{ + struct filter_struct *rev_head = NULL; + + /* Reverse the list so we deactivate mergelists in the proper LIFO + * order. */ + while (head) { + struct filter_struct *next = head->next; + head->next = rev_head; + rev_head = head; + head = next; + } + + while (rev_head) { + struct filter_struct *prev = rev_head->next; + free_filter(rev_head); + rev_head = prev; + } +} + /* Build a filter structure given a filter pattern. The value in "pat" * is not null-terminated. */ static void add_rule(struct filter_list_struct *listp, const char *pat, @@ -237,7 +273,7 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, if (!(lp = new_array(struct filter_list_struct, 1))) out_of_memory("add_rule"); - lp->head = lp->tail = NULL; + lp->head = lp->tail = lp->parent_dirscan_head = NULL; if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0) out_of_memory("add_rule"); ret->u.mergelist = lp; @@ -250,6 +286,9 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, if (!mergelist_parents) out_of_memory("add_rule"); } + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] activating mergelist #%d%s\n", + who_am_i(), mergelist_cnt, lp->debug_type); mergelist_parents[mergelist_cnt++] = ret; } else ret->u.slash_cnt = slash_cnt; @@ -269,14 +308,10 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, static void clear_filter_list(struct filter_list_struct *listp) { if (listp->tail) { - struct filter_struct *ent, *next; /* Truncate any inherited items from the local list. */ listp->tail->next = NULL; /* Now free everything that is left. */ - for (ent = listp->head; ent; ent = next) { - next = ent->next; - free_filter(ent); - } + free_filters(listp->head); } listp->head = listp->tail = NULL; @@ -376,7 +411,7 @@ void set_filter_dir(const char *dir, unsigned int dirlen) * parent directory of the first transfer dir. If it does, we scan all the * dirs from that point through the parent dir of the transfer dir looking * for the per-dir merge-file in each one. */ -static BOOL setup_merge_file(struct filter_struct *ex, +static BOOL setup_merge_file(int mergelist_num, struct filter_struct *ex, struct filter_list_struct *lp) { char buf[MAXPATHLEN]; @@ -386,6 +421,9 @@ static BOOL setup_merge_file(struct filter_struct *ex, if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/') return 0; + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] performing parent_dirscan for mergelist #%d%s\n", + who_am_i(), mergelist_num, lp->debug_type); y = strrchr(x, '/'); *y = '\0'; ex->pattern = strdup(y+1); @@ -414,37 +452,59 @@ static BOOL setup_merge_file(struct filter_struct *ex, dirbuf_len = y - dirbuf; strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf)); parse_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS); - if (ex->match_flags & MATCHFLG_NO_INHERIT) + if (ex->match_flags & MATCHFLG_NO_INHERIT) { + /* Free the undesired rules to clean up any per-dir + * mergelists they defined. Otherwise pop_local_filters + * may crash trying to restore nonexistent state for + * those mergelists. */ + free_filters(lp->head); lp->head = NULL; + } lp->tail = NULL; strlcpy(y, save, MAXPATHLEN); while ((*x++ = *y++) != '/') {} } + /* Save current head for freeing when the mergelist becomes inactive. */ + lp->parent_dirscan_head = lp->head; parent_dirscan = False; + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] completed parent_dirscan for mergelist #%d%s\n", + who_am_i(), mergelist_num, lp->debug_type); free(pat); return 1; } +struct local_filter_state { + int mergelist_cnt; + struct filter_list_struct mergelists[0]; +}; + /* Each time rsync changes to a new directory it call this function to * handle all the per-dir merge-files. The "dir" value is the current path * relative to curr_dir (which might not be null-terminated). We copy it * into dirbuf so that we can easily append a file name on the end. */ void *push_local_filters(const char *dir, unsigned int dirlen) { - struct filter_list_struct *ap, *push; + struct local_filter_state *push; int i; set_filter_dir(dir, dirlen); + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] pushing local filters for %s\n", + who_am_i(), dirbuf); if (!mergelist_cnt) + /* No old state to save and no new merge files to push. */ return NULL; - push = new_array(struct filter_list_struct, mergelist_cnt); + push = (struct local_filter_state *) malloc(sizeof (struct local_filter_state) + + mergelist_cnt * sizeof (struct filter_list_struct)); if (!push) out_of_memory("push_local_filters"); - for (i = 0, ap = push; i < mergelist_cnt; i++) { - memcpy(ap++, mergelist_parents[i]->u.mergelist, + push->mergelist_cnt = mergelist_cnt; + for (i = 0; i < mergelist_cnt; i++) { + memcpy(&push->mergelists[i], mergelist_parents[i]->u.mergelist, sizeof (struct filter_list_struct)); } @@ -455,8 +515,8 @@ void *push_local_filters(const char *dir, unsigned int dirlen) struct filter_list_struct *lp = ex->u.mergelist; if (DEBUG_GTE(FILTER, 2)) { - rprintf(FINFO, "[%s] pushing filter list%s\n", - who_am_i(), lp->debug_type); + rprintf(FINFO, "[%s] pushing mergelist #%d%s\n", + who_am_i(), i, lp->debug_type); } lp->tail = NULL; /* Switch any local rules to inherited. */ @@ -465,7 +525,7 @@ void *push_local_filters(const char *dir, unsigned int dirlen) if (ex->match_flags & MATCHFLG_FINISH_SETUP) { ex->match_flags &= ~MATCHFLG_FINISH_SETUP; - if (setup_merge_file(ex, lp)) + if (setup_merge_file(i, ex, lp)) set_filter_dir(dir, dirlen); } @@ -487,26 +547,50 @@ void *push_local_filters(const char *dir, unsigned int dirlen) void pop_local_filters(void *mem) { - struct filter_list_struct *ap, *pop = (struct filter_list_struct*)mem; + struct local_filter_state *pop = (struct local_filter_state *)mem; int i; + int old_mergelist_cnt = pop ? pop->mergelist_cnt : 0; + + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] popping local filters\n", who_am_i()); for (i = mergelist_cnt; i-- > 0; ) { struct filter_struct *ex = mergelist_parents[i]; struct filter_list_struct *lp = ex->u.mergelist; if (DEBUG_GTE(FILTER, 2)) { - rprintf(FINFO, "[%s] popping filter list%s\n", - who_am_i(), lp->debug_type); + rprintf(FINFO, "[%s] popping mergelist #%d%s\n", + who_am_i(), i, lp->debug_type); } clear_filter_list(lp); + + if (i >= old_mergelist_cnt) { + /* This mergelist does not exist in the state to be + * restored. Free its parent_dirscan list to clean up + * any per-dir mergelists defined there so we don't + * crash trying to restore nonexistent state for them + * below. (Counterpart to setup_merge_file call in + * push_local_filters. Must be done here, not in + * free_filter, for LIFO order.) */ + if (DEBUG_GTE(FILTER, 2)) + rprintf(FINFO, "[%s] freeing parent_dirscan filters of mergelist #%d%s\n", + who_am_i(), i, ex->u.mergelist->debug_type); + free_filters(lp->parent_dirscan_head); + lp->parent_dirscan_head = NULL; + } } + /* If we cleaned things up properly, the only still-active mergelists + * should be those with a state to be restored. */ + assert(mergelist_cnt == old_mergelist_cnt); + if (!pop) + /* No state to restore. */ return; - for (i = 0, ap = pop; i < mergelist_cnt; i++) { - memcpy(mergelist_parents[i]->u.mergelist, ap++, + for (i = 0; i < mergelist_cnt; i++) { + memcpy(mergelist_parents[i]->u.mergelist, &pop->mergelists[i], sizeof (struct filter_list_struct)); } diff --git a/rsync.h b/rsync.h index 320d340..6083c81 100644 --- a/rsync.h +++ b/rsync.h @@ -813,6 +813,7 @@ struct filter_struct { struct filter_list_struct { struct filter_struct *head; struct filter_struct *tail; + struct filter_struct *parent_dirscan_head; char *debug_type; }; -- 1.6.0.rc3.14.g83bc8 -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: