From d8af86618ba0f52cf8fccbae695692e8446c9235 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Mon, 17 May 2004 16:35:02 +0000 Subject: [PATCH] Switched the storage for the merge-file lists from a single, reallocated array (which made push/pop easy) to separate, unchanging allocations directly attached to the exclude_struct item. This fixes a problem where a listp pointer to a parent list might get invalidated when a new merge-file list forced the array to grow (and its memory to move). --- filter.diff | 211 +++++++++++++++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 95 deletions(-) diff --git a/filter.diff b/filter.diff index aff9918..b8100bc 100644 --- a/filter.diff +++ b/filter.diff @@ -29,9 +29,9 @@ for the current dir because its name contained a slash. ..wayne.. ---- exclude.c 16 May 2004 14:08:34 -0000 1.79 -+++ exclude.c 16 May 2004 22:04:31 -0000 -@@ -30,14 +30,54 @@ extern int verbose; +--- exclude.c 16 May 2004 23:54:12 -0000 1.80 ++++ exclude.c 17 May 2004 16:16:23 -0000 +@@ -30,13 +30,54 @@ extern int verbose; extern int eol_nulls; extern int list_only; extern int recurse; @@ -40,17 +40,16 @@ for the current dir because its name contained a slash. extern char curr_dir[]; --struct exclude_list_struct exclude_list = { 0, 0, "" }; + struct exclude_list_struct exclude_list = { 0, 0, "" }; -struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " }; --struct exclude_list_struct server_exclude_list = { 0, 0, "server " }; -+struct exclude_list_struct exclude_list = { 0, 0, 0, "" }; -+struct exclude_list_struct server_exclude_list = { 0, 0, 0, "server " }; + struct exclude_list_struct server_exclude_list = { 0, 0, "server " }; char *exclude_path_prefix = NULL; - -+struct exclude_list_root { ++int merge_list_cnt = 0; ++ ++struct mergelist_save { + struct exclude_list_struct *array; -+ int cnt; -+} local_lists; ++ int count; ++}; + +static char dirbuf[MAXPATHLEN]; +static unsigned int dirbuf_offset = 0; @@ -85,11 +84,10 @@ for the current dir because its name contained a slash. + * the list for a new local dir, we just save off the exclude_list_struct + * values (so we can pop back to them later) and set the tail to NULL. + */ -+ + /** Build an exclude structure given an exclude pattern. */ static void make_exclude(struct exclude_list_struct *listp, const char *pat, - unsigned int pat_len, unsigned int mflags) -@@ -46,6 +86,24 @@ static void make_exclude(struct exclude_ +@@ -46,6 +87,24 @@ static void make_exclude(struct exclude_ const char *cp; unsigned int ex_len; @@ -100,7 +98,7 @@ for the current dir because its name contained a slash. + for (ex = listp->head; ex; ex = ex->next) { + if (ex->match_flags & MATCHFLG_MERGE_FILE + && strlen(ex->pattern) == pat_len -+ && strncmp(ex->pattern, pat, pat_len) == 0) ++ && memcmp(ex->pattern, pat, pat_len) == 0) + return; + } + if ((pat_len == 10 || (pat_len > 10 && pat[pat_len-11] == '/')) @@ -114,29 +112,22 @@ for the current dir because its name contained a slash. ret = new(struct exclude_struct); if (!ret) out_of_memory("make_exclude"); -@@ -81,14 +139,35 @@ static void make_exclude(struct exclude_ +@@ -81,14 +140,28 @@ static void make_exclude(struct exclude_ mflags |= MATCHFLG_DIRECTORY; } - for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++) - ret->slash_cnt++; + if (mflags & MATCHFLG_MERGE_FILE) { -+ struct exclude_list_struct *lp = local_lists.array; -+ int ndx = local_lists.cnt++; -+ local_lists.array = realloc_array(local_lists.array, -+ struct exclude_list_struct, local_lists.cnt); -+ if (!local_lists.array) ++ struct exclude_list_struct *lp ++ = new_array(struct exclude_list_struct, 1); ++ if (!lp) + out_of_memory("make_exclude"); -+ /* If "listp" was pointing inside the memory we just -+ * reallocated, update it. */ -+ if (ndx && listp >= lp && listp < lp + ndx) -+ listp = &local_lists.array[listp - lp]; -+ lp = &local_lists.array[ndx]; + lp->head = lp->tail = NULL; -+ lp->parent = ret; + if (asprintf(&lp->debug_type, "per-dir %s ", ret->pattern) < 0) + out_of_memory("make_exclude"); -+ ret->u.array_index = ndx; ++ ret->u.merge_list = lp; ++ merge_list_cnt++; + } else { + for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++) + ret->u.slash_cnt++; @@ -154,12 +145,20 @@ for the current dir because its name contained a slash. listp->tail->next = ret; listp->tail = ret; } -@@ -100,18 +179,90 @@ static void free_exclude(struct exclude_ +@@ -96,22 +169,128 @@ static void make_exclude(struct exclude_ + + static void free_exclude(struct exclude_struct *ex) + { ++ if (ex->match_flags & MATCHFLG_MERGE_FILE) { ++ free(ex->u.merge_list->debug_type); ++ free(ex->u.merge_list); ++ } + free(ex->pattern); free(ex); } --void free_exclude_list(struct exclude_list_struct *listp) -+static void free_exclude_list(struct exclude_list_struct *listp) +-void clear_exclude_list(struct exclude_list_struct *listp) ++static void clear_exclude_list(struct exclude_list_struct *listp) { - struct exclude_struct *ent, *next; - @@ -179,79 +178,109 @@ for the current dir because its name contained a slash. listp->head = listp->tail = NULL; } -+void *push_local_excludes(char *fname, unsigned int offset) ++static struct exclude_list_struct * ++push_merge_files(struct exclude_struct *ent, struct exclude_list_struct *array) +{ -+ int i; -+ struct exclude_list_root *push = new_array(struct exclude_list_root, 1); -+ -+ if (!push) -+ out_of_memory("push_local_excludes"); -+ -+ push->cnt = local_lists.cnt; -+ push->array = new_array(struct exclude_list_struct, local_lists.cnt); -+ if (!push->array) -+ out_of_memory("push_local_excludes"); -+ -+ memcpy(push->array, local_lists.array, -+ sizeof (struct exclude_list_struct) * local_lists.cnt); ++ struct exclude_list_struct *lp; + -+ /* Make it easy to construct the full path for a merge-file that was -+ * specified with a relative path by saving off the current dir. */ -+ memcpy(dirbuf, fname, offset); -+ dirbuf_offset = offset; -+ -+ for (i = 0; i < local_lists.cnt; i++) { -+ struct exclude_list_struct *listp = &local_lists.array[i]; -+ char *file = listp->parent->pattern; ++ for (; ent; ent = ent->next) { + int flags; ++ if (!(ent->match_flags & MATCHFLG_MERGE_FILE)) ++ continue; ++ lp = ent->u.merge_list; + + if (verbose > 2) { + rprintf(FINFO, "[%s] pushing %sexclude list\n", -+ who_am_i(), listp->debug_type); ++ who_am_i(), lp->debug_type); + } -+ if (listp->parent->match_flags & MATCHFLG_CVSIGNORE) { -+ listp->head = NULL; /* Subdirs don't inherit rules. */ ++ ++ memcpy(array++, lp, sizeof (struct exclude_list_struct)); ++ ++ array = push_merge_files(lp->head, array); ++ ++ if (ent->match_flags & MATCHFLG_CVSIGNORE) { ++ lp->head = NULL; /* CVS doesn't inherit rules. */ + flags = XFLG_WORD_SPLIT | XFLG_WORDS_ONLY; + } else { -+ flags = listp->parent->match_flags & MATCHFLG_INCLUDE ++ flags = ent->match_flags & MATCHFLG_INCLUDE + ? XFLG_DEF_INCLUDE : 0; + } -+ listp->tail = NULL; /* Signals no local content. */ -+ if (strlcpy(fname + offset, file, MAXPATHLEN - offset) -+ < MAXPATHLEN - offset) -+ add_exclude_file(listp, fname, flags); ++ lp->tail = NULL; /* Switch any local rules to inherited. */ ++ if (strlcpy(dirbuf + dirbuf_offset, ent->pattern, ++ MAXPATHLEN - dirbuf_offset) < MAXPATHLEN - dirbuf_offset) ++ add_exclude_file(lp, dirbuf, flags); + else { + io_error |= IOERR_GENERAL; + rprintf(FINFO, + "cannot add local excludes in long-named directory %s\n", -+ full_fname(fname)); ++ full_fname(dirbuf)); + } + } + ++ return array; ++} ++ ++void *push_local_excludes(char *fname, unsigned int offset) ++{ ++ struct mergelist_save *push; ++ ++ /* Make it easy to construct the full path for a merge-file that was ++ * specified with a relative path by saving off the current dir. */ ++ memcpy(dirbuf, fname, offset); ++ dirbuf_offset = offset; ++ ++ if (!(push = new_array(struct mergelist_save, 1))) ++ out_of_memory("push_local_excludes"); ++ ++ push->count = merge_list_cnt; ++ push->array = new_array(struct exclude_list_struct, merge_list_cnt); ++ if (!push->array) ++ out_of_memory("push_local_excludes"); ++ ++ push_merge_files(exclude_list.head, push->array); ++ + return (void*)push; +} + -+void pop_local_excludes(void *mem) ++static struct exclude_list_struct * ++pop_merge_files(struct exclude_struct *ent, struct exclude_list_struct *array) +{ -+ int i; ++ struct exclude_list_struct *lp; ++ ++ for (; ent; ent = ent->next) { ++ if (!(ent->match_flags & MATCHFLG_MERGE_FILE)) ++ continue; ++ lp = ent->u.merge_list; + -+ for (i = 0; i < local_lists.cnt; i++) { -+ struct exclude_list_struct *listp = &local_lists.array[i]; + if (verbose > 2) { + rprintf(FINFO, "[%s] popping %sexclude list\n", -+ who_am_i(), listp->debug_type); ++ who_am_i(), lp->debug_type); + } -+ free_exclude_list(listp); ++ ++ clear_exclude_list(lp); ++ memcpy(lp, array++, sizeof (struct exclude_list_struct)); ++ ++ array = pop_merge_files(lp->head, array); + } -+ free(local_lists.array); -+ local_lists = *(struct exclude_list_root*)mem; -+ free(mem); ++ ++ return array; ++} ++ ++void pop_local_excludes(void *mem) ++{ ++ struct mergelist_save *pop = (struct mergelist_save*)mem; ++ ++ pop_merge_files(exclude_list.head, pop->array); ++ merge_list_cnt = pop->count; ++ ++ free(pop->array); ++ free(pop); +} + static int check_one_exclude(char *name, struct exclude_struct *ex, int name_is_dir) { -@@ -122,7 +273,7 @@ static int check_one_exclude(char *name, +@@ -122,7 +301,7 @@ static int check_one_exclude(char *name, /* If the pattern does not have any slashes AND it does not have * a "**" (which could match a slash), then we just match the * name portion of the path. */ @@ -260,7 +289,7 @@ for the current dir because its name contained a slash. if ((p = strrchr(name,'/')) != NULL) name = p+1; } -@@ -148,9 +299,9 @@ static int check_one_exclude(char *name, +@@ -148,9 +327,9 @@ static int check_one_exclude(char *name, if (ex->match_flags & MATCHFLG_WILD) { /* A non-anchored match with an infix slash and no "**" * needs to match the last slash_cnt+1 name elements. */ @@ -272,14 +301,13 @@ for the current dir because its name contained a slash. for (p = name + strlen(name) - 1; p >= name; p--) { if (*p == '/' && !--cnt) break; -@@ -221,6 +372,14 @@ int check_exclude(struct exclude_list_st +@@ -221,6 +400,13 @@ int check_exclude(struct exclude_list_st struct exclude_struct *ent; for (ent = listp->head; ent; ent = ent->next) { + if (ent->match_flags & MATCHFLG_MERGE_FILE) { -+ struct exclude_list_struct *lp -+ = &local_lists.array[ent->u.array_index]; -+ int rc = check_exclude(lp, name, name_is_dir); ++ int rc = check_exclude(ent->u.merge_list, name, ++ name_is_dir); + if (rc) + return rc; + continue; @@ -287,7 +315,7 @@ for the current dir because its name contained a slash. if (check_one_exclude(name, ent, name_is_dir)) { report_exclude_result(name, ent, name_is_dir, listp->debug_type); -@@ -254,11 +413,16 @@ static const char *get_exclude_tok(const +@@ -254,11 +440,16 @@ static const char *get_exclude_tok(const p = (const char *)s; } @@ -306,7 +334,7 @@ for the current dir because its name contained a slash. s += 2; } else if (xflags & XFLG_DEF_INCLUDE) mflags |= MATCHFLG_INCLUDE; -@@ -307,11 +471,42 @@ void add_exclude(struct exclude_list_str +@@ -307,11 +498,42 @@ void add_exclude(struct exclude_list_str continue; } @@ -350,7 +378,7 @@ for the current dir because its name contained a slash. mflags & MATCHFLG_INCLUDE ? "in" : "ex"); } } -@@ -403,7 +598,11 @@ void send_exclude_list(int f) +@@ -403,7 +625,11 @@ void send_exclude_list(int f) if (ent->match_flags & MATCHFLG_INCLUDE) { write_int(f, l + 2); write_buf(f, "+ ", 2); @@ -363,7 +391,7 @@ for the current dir because its name contained a slash. write_int(f, l + 2); write_buf(f, "- ", 2); } else -@@ -444,6 +643,7 @@ void add_cvs_excludes(void) +@@ -444,6 +670,7 @@ void add_cvs_excludes(void) char fname[MAXPATHLEN]; char *p; @@ -371,8 +399,8 @@ for the current dir because its name contained a slash. add_exclude(&exclude_list, default_cvsignore, XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); ---- flist.c 15 May 2004 19:31:10 -0000 1.223 -+++ flist.c 16 May 2004 22:04:31 -0000 +--- flist.c 16 May 2004 23:54:12 -0000 1.224 ++++ flist.c 17 May 2004 16:16:24 -0000 @@ -39,8 +39,6 @@ extern int module_id; extern int ignore_errors; extern int numeric_ids; @@ -422,7 +450,7 @@ for the current dir because its name contained a slash. - rprintf(FINFO, "[%s] popping %sexclude list\n", - who_am_i(), local_exclude_list.debug_type); - } -- free_exclude_list(&local_exclude_list); +- clear_exclude_list(&local_exclude_list); - local_exclude_list = last_list; } } @@ -465,8 +493,8 @@ for the current dir because its name contained a slash. closedir(d); } --- rsync.h 16 May 2004 07:28:24 -0000 1.204 -+++ rsync.h 16 May 2004 22:04:33 -0000 -@@ -496,16 +496,21 @@ struct map_struct { ++++ rsync.h 17 May 2004 16:16:25 -0000 +@@ -496,11 +496,16 @@ struct map_struct { #define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */ #define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */ #define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */ @@ -479,20 +507,13 @@ for the current dir because its name contained a slash. - int slash_cnt; + union { + int slash_cnt; -+ int array_index; ++ struct exclude_list_struct *merge_list; + } u; }; struct exclude_list_struct { -- struct exclude_struct *head; -- struct exclude_struct *tail; -+ struct exclude_struct *head, *tail; -+ struct exclude_struct *parent; - char *debug_type; - }; - --- rsync.yo 7 May 2004 00:18:37 -0000 1.169 -+++ rsync.yo 16 May 2004 22:04:33 -0000 ++++ rsync.yo 17 May 2004 16:16:26 -0000 @@ -1075,6 +1075,72 @@ itemize( it would be excluded by the "*") ) -- 2.34.1