..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"
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)
{
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)
+ 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';
+ if (!*fn)
+ fn = "/";
+ if (*fn == '/')
-+ strcpy(buf, fn); /* safe */
++ strlcpy(buf, fn, MAXPATHLEN);
+ else
+ pathjoin(buf, MAXPATHLEN, dirbuf, fn);
+ fn = x + 1;
+
+ 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++) != '/') {}
+ }
+
+ 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)
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. */
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;
}
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. */
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) {
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;
}
} 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) {
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;
}
- 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;
}
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;
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;
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
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 "*")
)
+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.
+
+
+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.
+
+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
+)
+
+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)