. -p .excl2
. .excl3
*.o
+ /foobar
Then the file ".excl2" will also be read in from the current dir and all
its subdirs (due to the -p option). The file ".excl3" would just be
-read in from the current dir (because it was not specified with the -p
-option).
+read in from the current dir. The exclusion of "foobar" will only
+happen in that .excl file's directory because the rule is anchored (so
+that's how you can make rules local instead of inherited).
..wayne..
log_init();
--- orig/exclude.c 2004-08-05 23:16:37
-+++ exclude.c 2004-08-09 18:36:18
++++ exclude.c 2004-08-10 04:51:05
@@ -27,16 +27,75 @@
#include "rsync.h"
out_of_memory("make_exclude");
if (ex_len)
- memcpy(ret->pattern, exclude_path_prefix, ex_len);
-+ strlcpy(ret->pattern, dirbuf + module_dirlen, ex_len + 1);
++ memcpy(ret->pattern, dirbuf + module_dirlen, ex_len);
strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
pat_len += ex_len;
struct exclude_list_struct {
--- orig/rsync.yo 2004-08-03 15:34:32
-+++ rsync.yo 2004-08-09 03:10:29
++++ rsync.yo 2004-08-10 04:49:06
@@ -335,6 +335,7 @@ verb(
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude patterns listed in FILE
-0 --from0 all file lists are delimited by nulls
--version print version number
--daemon run as an rsync daemon
-@@ -1086,6 +1087,11 @@ itemize(
+@@ -979,15 +980,22 @@ The exclude and include patterns specifi
+ selection of which files to transfer and which files to skip.
+
+ Rsync builds an ordered list of include/exclude options as specified on
+-the command line. Rsync checks each file and directory
+-name against each exclude/include pattern in turn. The first matching
++the command line.
++It can also be told to check for include/exclude options in each
++directory that rsync visits during the transfer (see the section on
++MERGED EXCLUDE FILES for the details on these per-directory exclude
++files).
++
++As the list of files/directories to transfer is built, rsync checks each
++name against every exclude/include pattern in turn. The first matching
+ pattern is acted on. If it is an exclude pattern, then that file is
+ skipped. If it is an include pattern then that filename is not
+ skipped. If no matching include/exclude pattern is found then the
+ filename is not skipped.
+
+-The filenames matched against the exclude/include patterns are relative
+-to the "root of the transfer". If you think of the transfer as a
++The global include/exclude rules are anchored at the "root of the
++transfer" (as opposed to per-directory rules, which are anchored at
++the current directory). If you think of the transfer as a
+ subtree of names that are being sent from sender to receiver, the root
+ is where the tree starts to be duplicated in the destination directory.
+ This root governs where patterns that start with a / match (see below).
+@@ -996,7 +1004,7 @@ Because the matching is relative to the
+ trailing slash on a source path or changing your use of the --relative
+ option affects the path you need to use in your matching (in addition to
+ changing how much of the file tree is duplicated on the destination
+-system). The following examples demonstrate this.
++host). The following examples demonstrate this.
+
+ Let's say that we want to match two source files, one with an absolute
+ path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz".
+@@ -1043,23 +1051,29 @@ because rsync did not descend through th
+ hierarchy.
+
+ Note also that the --include and --exclude options take one pattern
+-each. To add multiple patterns use the --include-from and
+---exclude-from options or multiple --include and --exclude options.
++each. To add multiple patterns use the --include-from and --exclude-from
++options or multiple --include and --exclude options. See also the
++section on MERGED EXCLUDE FILES for how to merge-files together and
++specify local rules within a hierarchy of files.
+
+-The patterns can take several forms. The rules are:
++The include/exclude patterns can take several forms. The rules are:
+
+ itemize(
+
+- it() if the pattern starts with a / then it is matched against the
+- start of the filename, otherwise it is matched against the end of
+- the filename.
+- This is the equivalent of a leading ^ in regular expressions.
+- Thus "/foo" would match a file called "foo" at the transfer-root
+- (see above for how this is different from the filesystem-root).
+- On the other hand, "foo" would match any file called "foo"
++ it() if the pattern starts with a / then it is anchored to a
++ particular spot in the hierarchy of files, otherwise it is matched
++ against the end of the pathname. This is similar to a leading ^ in
++ regular expressions.
++ Thus "/foo" would match a file called "foo" at either the "root of the
++ transfer" (for a global rule) or in the current directory (for a
++ per-directory rule).
++ An unqualified "foo" would match any file or directory named "foo"
+ anywhere in the tree because the algorithm is applied recursively from
++ the
+ top down; it behaves as if each path component gets a turn at being the
+- end of the file name.
++ end of the file name. Even the unanchored "sub/foo" would match at
++ any point in the hierarchy where a "foo" was found within a directory
++ named "sub".
+
+ it() if the pattern ends with a / then it will only match a
+ directory, not a file, link, or device.
+@@ -1072,22 +1086,31 @@ itemize(
+ single asterisk pattern "*" will stop at slashes.
+
+ it() if the pattern contains a / (not counting a trailing /) or a "**"
+- then it is matched against the full filename, including any leading
+- directory. If the pattern doesn't contain a / or a "**", then it is
++ then it is matched against the full pathname, including any leading
++ directories. If the pattern doesn't contain a / or a "**", then it is
+ matched only against the final component of the filename. Again,
+ remember that the algorithm is applied recursively so "full filename" can
+ actually be any portion of a path below the starting directory.
+
+ it() if the pattern starts with "+ " (a plus followed by a space)
+ then it is always considered an include pattern, even if specified as
+- part of an exclude option. The prefix is discarded before matching.
++ part of an exclude option. (The prefix is discarded before matching.)
+
+ it() if the pattern starts with "- " (a minus followed by a space)
then it is always considered an exclude pattern, even if specified as
- part of an include option. The prefix is discarded before matching.
-
+- part of an include option. The prefix is discarded before matching.
++ part of an include option. (The prefix is discarded before matching.)
++
+ it() if the pattern starts with ". " (a dot followed by a space) then its
-+ pattern is taken to be a merge file that is read in to supplement the
-+ current rules. See the section on MERGING EXCLUDE FILES for more
++ pattern is taken to be a merge-file that is read in to supplement the
++ current rules. See the section on MERGED EXCLUDE FILES for more
+ information.
-+
+
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,104 @@ itemize(
- it would be excluded by the "*")
++ The "current" list is either the global list of rules (which are
++ specified via options) or a set of per-directory rules (which are
++ inherited in their own sub-list, so a subdirectory can use this to
++ clear out the parent's rules).
)
-+manpagesection(MERGING EXCLUDE FILES)
+ The +/- rules are most useful in a list that was read from a file, allowing
+@@ -1134,10 +1157,109 @@ itemize(
+ it() --include "*/" --include "*.c" --exclude "*" would include all
+ directories and C source files
+ it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
+- only foo/bar.c (the foo/ directory must be explicitly included or
+- it would be excluded by the "*")
++ only the foo directory and foo/bar.c (the foo directory must be
++ explicitly included or it would be excluded by the "*")
++)
++
++manpagesection(MERGED EXCLUDE FILES)
+
+You can merge whole files into an exclude file by specifying a rule that
+starts with a ". " (a dot followed by a space) and putting a filename in
-+place of the pattern. The filename may be preceded by one or more options:
++place of the pattern. There are two kinds of merged exclude files --
++single-instance and per-directory. You select which one you want by
++optionally including an option prior to the merge-file name:
+
+startdit()
+
+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. (Without this option rsync just merges the rules into
-+the parent file.)
-+
-+Rules are inherited in all subdirectories of the directory where the
-+per-dir merge file was found. Each subdirectory's rules are prefixed to
-+the inherited rules from a parent directory, which gives the newest rules a
-+higher priority than the inherited rules. If you don't want a rule to be
-+inherited, anchor it with a leading slash. Anchored rules in a
-+per-directory merge file are relative to the current directory, so a rule
-+"/foo" would only exclude the file "foo" in the current directory.
-+
-+Note also that you can eliminate all the inherited rules for a directory
-+and its subdirectories by putting the list-clearing token (!) at the start
-+of a per-directory file. This only clears the rules in the current
-+sub-list, not all the rules.
++when the file exists.
++
++Per-directory rules are inherited in all subdirectories of the directory
++where the merge-file was found. Each subdirectory's rules are prefixed
++to the inherited rules from the parent directories, which gives the
++newest rules a higher priority than the inherited rules. If you don't
++want a rule to be inherited, anchor it with a leading slash. Anchored
++rules in a per-directory merge-file are relative to the current
++directory, so a rule "/foo" would only exclude the file "foo" in the
++directory where the per-dir exclude file was found.
+
+dit(bf(--)) End the scanning of options. Useful if you want to specify a
+filename that begins with a dash.
+ . -p .excl
+ + *.[ch]
+ *.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. 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 (e.g. no comments, no "!", etc.).
-+
-+Additionally, you can affect where the --cvs-exclude (-C) option's
-+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
-+)
++an exclude statement was used to specify them. Rules read in from the
++.global_excludes file are anchored just like all other global rules
++(only per-directory rules that are read in once the transfer begins get
++the current-dir anchoring).
+
-+will merge all the per-directory .cvsignore rules at the start of your list
-+rather than at the end. This allows their dir-specific rules to supersede
-+your rules instead of being subservient to them. (The global rules taken
-+from the $HOME/.cvsignore file and from $CVSIGNORE are not repositioned by
-+this.)
-+
-+If a per-directory merge file is specified with a path that is a parent
++If a per-directory merge-file is specified with a path that is a parent
+directory of the first transfer directory, rsync will scan all the parent
+dirs from that starting point to the transfer directory for the indicated
+per-directory file. For instance, the -E option is an abbreviation for
+)
+
+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 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).
++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.)
+
+Some examples of this pre-scanning for per-directory files:
+
+ rsync -av --exclude='. -p .rsync-excludes' /src/path/ /dest/dir
+)
+
-+The first two commands above will look for .rsync-excludes in "/" and
++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".
++and its subdirectories. The last command avoids the parent-dir scan
++and only looks for the ".rsync-excludes" files in each directory that is
++a part of the transfer.
++
++Finally, note 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), patterns are split on whitespace, the rules are never
++inherited, and no special characters are honored (e.g. no comments, no "!",
++etc.).
++
++Additionally, you can affect where the --cvs-exclude (-C) option's
++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:
++
++verb(
++ rsync -avC --exclude='. -p .cvsignore' --exclude-from=foo a/ b
++)
++
++The above will merge all the per-directory .cvsignore rules at the start of
++your list rather than at the end. This allows their dir-specific rules to
++supersede your rules instead of being subservient to them. (The global
++rules taken from the $HOME/.cvsignore file and from $CVSIGNORE are not
++repositioned by this.)
+
manpagesection(BATCH MODE)
+
# The script would have aborted on error, so getting here means we've won.
exit 0
---- orig/util.c 2004-08-07 20:57:02
-+++ util.c 2004-08-09 18:28:59
+--- orig/util.c 2004-08-09 21:07:10
++++ util.c 2004-08-09 21:07:25
@@ -524,7 +524,7 @@ static void glob_expand_one(char *s, cha
s = ".";