--- rsync-HEAD-20070724-0412GMT/exclude.c.orig 2007-08-02 17:27:22.000000000 +0930 +++ rsync-HEAD-20070724-0412GMT/exclude.c 2007-08-02 17:27:01.000000000 +0930 @@ -498,17 +498,41 @@ static void *filt_array[MAXPATHLEN/2+1]; if (!dname) { - while (cur_depth >= min_depth) - pop_local_filters(filt_array[cur_depth--]); + while (cur_depth >= min_depth) { + if (filt_array[cur_depth]) { /* check (a) */ + pop_local_filters(filt_array[cur_depth]); + filt_array[cur_depth]=NULL; + } + cur_depth--; + } min_depth = MAXPATHLEN; cur_depth = -1; return; } assert(dir_depth < MAXPATHLEN/2+1); + + while (cur_depth >= dir_depth && cur_depth >= min_depth) { + if (filt_array[cur_depth]) { /* check (b) */ + pop_local_filters(filt_array[cur_depth]); + filt_array[cur_depth]=NULL; + } + cur_depth--; + } + + /* If checks (a) and (b) above were absent, the following invariant + must hold so proper cleanup can be performed in pop_local_filters. + However, this is a dirty fix, since this invariant being violated + implies that local filters in some parent directories of dname/dlen + have been skipped. */ + if(cur_depth >= 0 && dir_depth > cur_depth+1) { + rprintf(FINFO, + "Some local filters may have been skipped -- skipping file deletion\n"); + return; + } + /* assume: cur_depth < 0 || dir_depth <= cur_depth+1 */ + - while (cur_depth >= dir_depth && cur_depth >= min_depth) - pop_local_filters(filt_array[cur_depth--]); cur_depth = dir_depth; if (cur_depth < min_depth) min_depth = cur_depth;