From 41ebea83a1d35b37695006c3eb6cf22e4687d8af Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Fri, 6 Aug 2004 23:01:43 +0000 Subject: [PATCH] - Needed to send the new merge-file options across the socket. - Fixed some problems when running as a daemon. - A few other minor fixes. - Improved the docs. --- filter.diff | 253 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 153 insertions(+), 100 deletions(-) diff --git a/filter.diff b/filter.diff index d5ed382..29d8bb9 100644 --- a/filter.diff +++ b/filter.diff @@ -34,7 +34,7 @@ the -i option). ..wayne.. --- orig/exclude.c 2004-08-05 23:16:37 -+++ exclude.c 2004-08-06 09:01:33 ++++ exclude.c 2004-08-06 22:58:08 @@ -27,17 +27,66 @@ #include "rsync.h" @@ -180,7 +180,7 @@ the -i option). listp->tail->next = ret; listp->tail = ret; } -@@ -96,22 +196,180 @@ static void make_exclude(struct exclude_ +@@ -96,22 +196,244 @@ static void make_exclude(struct exclude_ static void free_exclude(struct exclude_struct *ex) { @@ -214,6 +214,67 @@ the -i option). listp->head = listp->tail = NULL; } ++/* This returns a fully expanded filename for the merge-file name if the ++ * name has any slashes in it, otherwise it returns the original name. */ ++static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr) ++{ ++ static char buf[MAXPATHLEN]; ++ char *fn, tmpbuf[MAXPATHLEN]; ++ unsigned int fn_len, cd_len; ++ ++ cd_len = dirbuf_offset && *dirbuf == '/' ? 0 : curr_dir_len + 1; ++ if (cd_len && *merge_file != '/') { ++ const char *p; ++ if (len_ptr) { ++ for (p = merge_file + *len_ptr; ++ --p > merge_file && *p != '/'; ) {} ++ } else ++ p = strchr(merge_file, '/'); ++ if (!p || p == merge_file) ++ return (char *)merge_file; ++ } ++ ++ fn = *merge_file == '/' ? buf : tmpbuf; ++ if (sanitize_paths) { ++ /* null-terminate the name if it isn't already */ ++ if (len_ptr && merge_file[*len_ptr]) { ++ char *to = fn == buf ? tmpbuf : buf; ++ strlcpy(to, merge_file, *len_ptr + 1); ++ merge_file = to; ++ } ++ dirbuf[dirbuf_offset] = '\0'; ++ if (!sanitize_path(fn, merge_file, dirbuf)) { ++ rprintf(FERROR, "merge filename overflows: %s\n", ++ merge_file); ++ return NULL; ++ } ++ } else { ++ strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN); ++ clean_fname(fn); ++ } ++ ++ if (*fn == '/') ++ return fn; ++ ++ fn_len = strlen(fn); ++ if (cd_len + dirbuf_offset + fn_len >= MAXPATHLEN) { ++ rprintf(FERROR, "merge filename overflows: %s\n", fn); ++ return NULL; ++ } ++ if (cd_len) { ++ memcpy(buf, curr_dir, curr_dir_len); ++ buf[curr_dir_len] = '/'; ++ } ++ if (dirbuf_offset) ++ memcpy(buf + cd_len, dirbuf, dirbuf_offset); ++ memcpy(buf + cd_len + dirbuf_offset, fn, fn_len + 1); ++ fn_len = clean_fname(buf); ++ if (len_ptr) ++ *len_ptr = fn_len; ++ ++ return buf; ++} ++ +static void prep_merge_file(struct exclude_struct *ex, + struct exclude_list_struct *lp, int flags, + char *dir, unsigned int dirlen) @@ -221,13 +282,14 @@ the -i option). + char buf[MAXPATHLEN]; + char *x, *y, *fn = ex->pattern; + -+ if (!(x = strrchr(fn, '/'))) ++ if (!(fn = parse_merge_name(fn, NULL)) || *fn != '/') + return; + ++ x = strrchr(fn, '/'); + *x = '\0'; -+ if (dir[dirlen]) ++ if (dir[dirlen]) /* avoid writing to a read-only string */ + dir[dirlen] = '\0'; -+ pathjoin(dirbuf, MAXPATHLEN, sanitize_paths ? "" : curr_dir, dir); ++ pathjoin(dirbuf, MAXPATHLEN, curr_dir, dir); + if (dirlen == 2 && *dir == '.') { + int len = strlen(dirbuf); + dirbuf[len-2] = '\0'; @@ -235,7 +297,7 @@ the -i option). + if (!*fn) + fn = "/"; + if (*fn == '/') -+ strcpy(buf, fn); /* safe */ ++ strlcpy(buf, fn, MAXPATHLEN); + else + pathjoin(buf, MAXPATHLEN, dirbuf, fn); + fn = x + 1; @@ -249,12 +311,12 @@ the -i option). + + while (*y) { + char save[MAXPATHLEN]; -+ strcpy(save, y); /* safe */ ++ strlcpy(save, y, MAXPATHLEN); + dirbuf_offset = y - dirbuf; + strlcpy(x, fn, MAXPATHLEN - (x - buf)); + lp->tail = NULL; + add_exclude_file(lp, buf, flags); -+ strcpy(y, save); /* safe */ ++ strlcpy(y, save, MAXPATHLEN); + while ((*x++ = *y++) != '/') {} + } + @@ -264,7 +326,9 @@ the -i option). + dirbuf_offset = dirlen; + memcpy(dirbuf, dir, dirbuf_offset); + -+ memmove(ex->pattern, fn, strlen(fn) + 1); ++ x = ex->pattern; ++ ex->pattern = strdup(fn); ++ free(x); +} + +void *push_local_excludes(char *dir, unsigned int dirlen) @@ -367,7 +431,7 @@ the -i option). static int check_one_exclude(char *name, struct exclude_struct *ex, int name_is_dir) { -@@ -122,7 +380,7 @@ static int check_one_exclude(char *name, +@@ -122,7 +444,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. */ @@ -376,7 +440,7 @@ the -i option). if ((p = strrchr(name,'/')) != NULL) name = p+1; } -@@ -133,7 +391,8 @@ static int check_one_exclude(char *name, +@@ -133,7 +455,8 @@ static int check_one_exclude(char *name, name = full_name; } @@ -386,7 +450,7 @@ the -i option). if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir) return 0; -@@ -148,9 +407,9 @@ static int check_one_exclude(char *name, +@@ -148,9 +471,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. */ @@ -398,7 +462,7 @@ the -i option). for (p = name + strlen(name) - 1; p >= name; p--) { if (*p == '/' && !--cnt) break; -@@ -221,6 +480,13 @@ int check_exclude(struct exclude_list_st +@@ -221,6 +544,13 @@ int check_exclude(struct exclude_list_st struct exclude_struct *ent; for (ent = listp->head; ent; ent = ent->next) { @@ -412,7 +476,7 @@ the -i option). if (check_one_exclude(name, ent, name_is_dir)) { report_exclude_result(name, ent, name_is_dir, listp->debug_type); -@@ -253,12 +519,41 @@ static const char *get_exclude_tok(const +@@ -253,12 +583,41 @@ static const char *get_exclude_tok(const p = (const char *)s; } @@ -456,7 +520,7 @@ the -i option). } else if (xflags & XFLG_DEF_INCLUDE) mflags |= MATCHFLG_INCLUDE; -@@ -292,6 +587,7 @@ void add_exclude(struct exclude_list_str +@@ -292,9 +651,15 @@ void add_exclude(struct exclude_list_str cp = pattern; pat_len = 0; while (1) { @@ -464,7 +528,15 @@ the -i option). cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags); if (!pat_len) break; -@@ -306,13 +602,55 @@ void add_exclude(struct exclude_list_str ++ if (pat_len >= MAXPATHLEN) { ++ rprintf(FERROR, "discarding over-long exclude: %s\n", ++ cp); ++ continue; ++ } + + if (mflags & MATCHFLG_CLEAR_LIST) { + if (verbose > 2) { +@@ -306,13 +671,23 @@ void add_exclude(struct exclude_list_str continue; } @@ -475,58 +547,35 @@ the -i option). - who_am_i(), (int)pat_len, cp, listp->debug_type, - mflags & MATCHFLG_INCLUDE ? "in" : "ex"); + if (mflags & MATCHFLG_MERGE_FILE) { -+ char buf1[MAXPATHLEN], buf2[MAXPATHLEN]; -+ unsigned int len = pat_len; -+ const char *fn = cp; -+ if (len >= MAXPATHLEN) { -+ rprintf(FERROR, -+ "merge filename too long: %.*s\n", -+ (int)len, fn); -+ continue; -+ } -+ /* We need a null-terminated version of the filename. */ -+ if (fn[len]) { -+ strlcpy(buf1, fn, len+1); -+ fn = buf1; -+ } -+ if (sanitize_paths) { -+ dirbuf[dirbuf_offset] = '\0'; -+ if (!sanitize_path(buf2, fn, dirbuf)) { -+ rprintf(FERROR, -+ "merge filename too long: %s\n", -+ fn); ++ if (mflags & MATCHFLG_PERDIR_MERGE) { ++ if (dirbuf_offset && *dirbuf == '/') { ++ if (!(cp = parse_merge_name(cp, &pat_len))) ++ continue; ++ make_exclude(listp, cp, pat_len, mflags); + continue; + } -+ len = strlen(fn = buf2); -+ } -+ if (*fn != '/' && dirbuf_offset -+ && (!(mflags & MATCHFLG_PERDIR_MERGE) -+ || *dirbuf == '/')) { -+ len = strlcpy(dirbuf + dirbuf_offset, fn, -+ MAXPATHLEN - dirbuf_offset) -+ + dirbuf_offset; -+ if (len >= MAXPATHLEN) { -+ rprintf(FERROR, -+ "merge filename too long: %s...\n", -+ dirbuf); ++ } else { ++ if (!(cp = parse_merge_name(cp, &pat_len))) + continue; -+ } -+ fn = dirbuf; -+ } -+ if (mflags & MATCHFLG_PERDIR_MERGE) -+ make_exclude(listp, fn, len, mflags); -+ else { -+ add_exclude_file(listp, fn, -+ xflags | XFLG_FATAL_ERRORS); ++ add_exclude_file(listp, cp, xflags | XFLG_FATAL_ERRORS); ++ continue; + } -+ continue; } + + make_exclude(listp, cp, pat_len, mflags); } } -@@ -343,6 +681,11 @@ void add_exclude_file(struct exclude_lis +@@ -321,7 +696,7 @@ void add_exclude_file(struct exclude_lis + int xflags) + { + FILE *fp; +- char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */ ++ char line[MAXPATHLEN+7]; /* Room for prefix chars and trailing slash. */ + char *eob = line + sizeof line - 1; + int word_split = xflags & XFLG_WORD_SPLIT; + +@@ -343,6 +718,11 @@ void add_exclude_file(struct exclude_lis return; } @@ -538,35 +587,30 @@ the -i option). while (1) { char *s = line; int ch, overflow = 0; -@@ -402,7 +745,11 @@ void send_exclude_list(int f) +@@ -402,7 +782,21 @@ void send_exclude_list(int f) if (ent->match_flags & MATCHFLG_INCLUDE) { write_int(f, l + 2); write_buf(f, "+ ", 2); - } else if ((*p == '-' || *p == '+') && p[1] == ' ') { + } else if (ent->match_flags & MATCHFLG_MERGE_FILE) { -+ write_int(f, l + 2); -+ write_buf(f, ". ", 2); ++ char buf[32], *op = buf; ++ *op++ = '.'; ++ *op++ = ' '; ++ if (ent->match_flags & MATCHFLG_PERDIR_MERGE) { ++ *op++ = '-'; ++ *op++ = 'p'; ++ if (ent->match_flags & MATCHFLG_INHERIT) ++ *op++ = 'i'; ++ *op++ = ' '; ++ } ++ write_int(f, l + (op - buf)); ++ write_buf(f, buf, op - buf); + } else if ((*p == '-' || *p == '+' || *p == '.') + && p[1] == ' ') { write_int(f, l + 2); write_buf(f, "- ", 2); } else -@@ -411,6 +758,14 @@ void send_exclude_list(int f) - } - - write_int(f, 0); -+ -+#if 0 -+ /* If we're the receiver and we don't need the excludes, dump them. */ -+ if (!am_sender && (!delete_mode || delete_excluded)) { -+ clear_exclude_list(&exclude_list); -+ mergelist_cnt = 0; -+ } -+#endif - } - - -@@ -443,6 +798,7 @@ void add_cvs_excludes(void) +@@ -443,6 +837,7 @@ void add_cvs_excludes(void) char fname[MAXPATHLEN]; char *p; @@ -575,7 +619,7 @@ the -i option). XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); --- orig/flist.c 2004-08-05 21:57:29 -+++ flist.c 2004-08-06 07:56:11 ++++ flist.c 2004-08-06 20:52:26 @@ -39,10 +39,9 @@ extern int module_id; extern int ignore_errors; extern int numeric_ids; @@ -761,7 +805,7 @@ the -i option). struct exclude_list_struct { --- orig/rsync.yo 2004-08-03 15:34:32 -+++ rsync.yo 2004-08-06 09:32:25 ++++ rsync.yo 2004-08-06 17:05:29 @@ -335,6 +335,7 @@ verb( --include=PATTERN don't exclude files matching PATTERN --include-from=FILE don't exclude patterns listed in FILE @@ -782,7 +826,7 @@ the -i option). it() if the pattern is a single exclamation mark ! then the current include/exclude list is reset, removing all previously defined patterns. ) -@@ -1138,6 +1144,97 @@ itemize( +@@ -1138,6 +1144,106 @@ itemize( it would be excluded by the "*") ) @@ -795,7 +839,7 @@ the -i option). +startdit() + +dit(bf(-i)) All subdirectories of the current directory inherit the rules we -+read in from this file. When applied to a per-directory merge file, the ++read in from this file. Only affects a per-directory merge file. The +rules read in are prefixed to the inherited rules from a parent directory, +which gives the newest rules a higher priority than the inherited rules. + @@ -806,7 +850,8 @@ the -i option). + +dit(bf(-p)) Make the file a per-directory merge-file. Rsync will scan +every directory that it traverses for the named file, merging its contents -+when the file exists. ++when the file exists. Without this option rsync just merges the rules into ++the parent file, giving them the same attributes as the parent. + +dit(bf(--)) End the scanning of options. Useful if you want to specify a +filename that begins with a dash. @@ -818,31 +863,34 @@ the -i option). + +verb( + . /home/user/.global_excludes -+ - *.gz ++ *.gz + . -pi .excl + + *.[ch] -+ - *.o ++ *.o +) + +This will merge the contents of the /home/user/.global_excludes file at the +start of the list and also turns the ".excl" filename into a per-directory -+exclude file whose local contents will be merged into the list in place of -+the .excl line. The rules read in from the .global_excludes file affect -+all the directories because it was read in before the directory scanning -+began (just as if it were an --exclude-from option). The rules read in -+from each directory's .excl file are inherited by that directory's -+subdirectories because the -i option was specified. ++exclude file. The rules read in from the .global_excludes file affect all ++the directories because it is is being merged into an --exclude-from ++option. The rules merged from each directory's .excl file are inherited ++by each directory's subdirectories because the -i option was specified ++(without -i the rules would only affect the directory where they were read ++in). All the merged rules default to being exclude rules because an ++exclude statement was used to specify them. + +Note also that the parsing of any merge-file named ".cvsignore" is always +done in a CVS-compatible manner, even if -C wasn't specified. This means +that its rules are always excludes (even if an include option specified the +file), tokens are split on whitespace, the rules are never inherited, and -+no special characters are honored. ++no special characters are honored (e.g. no comments, no "!", etc.). + +Additionally, you can affect where the --cvs-exclude (-C) option's -+inclusion of a per-directory .cvsignore file gets placed into your rules by -+adding an explicit per-directory merge rule for ".cvsignore". For example, -+specifying this: ++inclusion of the per-directory .cvsignore file gets placed into your rules ++by adding your own explicit per-directory merge rule for ".cvsignore". ++Without this rsync would add its this rule at the end of all your other ++rules (giving it a lower priority than your command-line rules). For ++example, specifying this: + +verb( + rsync -avC --exclude='. -p .cvsignore' --exclude-from=foo a/ b @@ -865,17 +913,22 @@ the -i option). +) + +That exclude tells rsync to scan for the file .rsync-excludes in all -+directories from the root up through the source of the transfer. For -+example: ++directories from the root up through the source of the transfer. For an ++rsync daemon, the root dir is always the module's "path" setting, not the ++root of the filesystem (unless the two are the same). ++ ++Some examples of this pre-scanning for per-directory files: + +verb( + rsync -avE /src/path/ /dest/dir ++ rsync -av --exclude='. -p ../../.rsync-excludes' /src/path/ /dest/dir ++ rsync -av --exclude='. -pi .rsync-excludes' /src/path/ /dest/dir +) + -+For the above command rsync would try to open /.rsync-excludes and -+/src/.rsync-excludes before looking for the file in /src/path. If you -+specify the long version of the option manually and leave off the leading -+slash from "/.rsync-excludes", rsync would start scanning in /src/path. ++The first two commands above will look for .rsync-excludes in "/" and ++"/src" before the normal scan begins looking for the file in "/src/path" ++and its subdirectories. The last command above just starts scanning ++from "/src/path". + manpagesection(BATCH MODE) -- 2.34.1