Update Makefile.in so that all targets that use syscall.o now include
[rsync/rsync-patches.git] / filter.diff
index 595e740..ffaf81c 100644 (file)
@@ -33,7 +33,7 @@ that's how you can make rules local instead of inherited).
 ..wayne..
 
 --- orig/clientserver.c        2004-08-02 02:29:16
-+++ clientserver.c     2004-08-09 17:35:56
++++ clientserver.c     2004-08-10 15:44:15
 @@ -48,12 +48,14 @@ extern int no_detach;
  extern int default_af_hint;
  extern char *bind_address;
@@ -44,7 +44,7 @@ that's how you can make rules local instead of inherited).
  
  char *auth_user;
  
-+/* The length of the lp_path() string (when we're not chrooted). */
++/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */
 +unsigned int module_dirlen = 0;
 +
  /**
@@ -88,20 +88,13 @@ that's how you can make rules local instead of inherited).
  
        log_init();
  
---- orig/exclude.c     2004-08-05 23:16:37
-+++ exclude.c  2004-08-10 04:51:05
-@@ -27,16 +27,75 @@
- #include "rsync.h"
- extern int verbose;
-+extern int am_sender;
+--- orig/exclude.c     2004-08-10 18:17:01
++++ exclude.c  2004-08-13 07:40:08
+@@ -30,13 +30,69 @@ extern int verbose;
  extern int eol_nulls;
  extern int list_only;
  extern int recurse;
 +extern int io_error;
-+extern int module_id;
-+extern int delete_mode;
-+extern int delete_excluded;
 +extern int sanitize_paths;
  
  extern char curr_dir[];
@@ -124,6 +117,7 @@ that's how you can make rules local instead of inherited).
 + * of this path prefix.  The path is always absolute. */
 +static char dirbuf[MAXPATHLEN+1];
 +static unsigned int dirbuf_len = 0;
++static int dirbuf_depth;
 +
 +/* This is True when we're scanning parent dirs for per-dir merge-files. */
 +static BOOL parent_dirscan = False;
@@ -168,7 +162,7 @@ that's how you can make rules local instead of inherited).
  
  /** Build an exclude structure given an exclude pattern. */
  static void make_exclude(struct exclude_list_struct *listp, const char *pat,
-@@ -46,23 +105,50 @@ static void make_exclude(struct exclude_
+@@ -46,23 +102,50 @@ static void make_exclude(struct exclude_
        const char *cp;
        unsigned int ex_len;
  
@@ -225,7 +219,7 @@ that's how you can make rules local instead of inherited).
        strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
        pat_len += ex_len;
  
-@@ -81,14 +167,40 @@ static void make_exclude(struct exclude_
+@@ -81,14 +164,40 @@ static void make_exclude(struct exclude_
                mflags |= MATCHFLG_DIRECTORY;
        }
  
@@ -270,7 +264,7 @@ that's how you can make rules local instead of inherited).
                listp->tail->next = ret;
                listp->tail = ret;
        }
-@@ -96,22 +208,265 @@ static void make_exclude(struct exclude_
+@@ -96,22 +205,267 @@ static void make_exclude(struct exclude_
  
  static void free_exclude(struct exclude_struct *ex)
  {
@@ -340,14 +334,14 @@ that's how you can make rules local instead of inherited).
 +                      strlcpy(to, merge_file, *len_ptr + 1);
 +                      merge_file = to;
 +              }
-+              if (!sanitize_path(fn, merge_file, r, dirbuf + module_dirlen)) {
++              if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
 +                      rprintf(FERROR, "merge-file name overflows: %s\n",
 +                              merge_file);
 +                      return NULL;
 +              }
 +      } else {
 +              strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN);
-+              clean_fname(fn);
++              clean_fname(fn, 1);
 +      }
 +      
 +      fn_len = strlen(fn);
@@ -360,7 +354,7 @@ that's how you can make rules local instead of inherited).
 +      }
 +      memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
 +      memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1);
-+      fn_len = clean_fname(buf);
++      fn_len = clean_fname(buf, 1);
 +
 +    done:
 +      if (len_ptr)
@@ -376,18 +370,20 @@ that's how you can make rules local instead of inherited).
 +              memcpy(dirbuf, curr_dir, curr_dir_len);
 +              dirbuf[curr_dir_len] = '/';
 +              len = curr_dir_len + 1;
-+              if (dirlen >= MAXPATHLEN - len)
-+                      dirlen = MAXPATHLEN - len - 1;
++              if (len + dirlen >= MAXPATHLEN)
++                      dirlen = 0;
 +      } else
 +              len = 0;
 +      memcpy(dirbuf + len, dir, dirlen);
 +      dirbuf[dirlen + len] = '\0';
-+      dirbuf_len = clean_fname(dirbuf);
++      dirbuf_len = clean_fname(dirbuf, 1);
 +      if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.'
 +          && dirbuf[dirbuf_len-2] == '/')
 +              dirbuf_len -= 2;
 +      dirbuf[dirbuf_len++] = '/';
 +      dirbuf[dirbuf_len] = '\0';
++      if (sanitize_paths)
++              dirbuf_depth = count_dir_elements(dirbuf + module_dirlen);
 +}
 +
 +/* This routine takes a per-dir merge-file entry and finishes its setup.
@@ -415,7 +411,7 @@ that's how you can make rules local instead of inherited).
 +      else
 +              pathjoin(buf, MAXPATHLEN, dirbuf, x);
 +
-+      len = clean_fname(buf);
++      len = clean_fname(buf, 1);
 +      if (len != 1 && len < MAXPATHLEN-1) {
 +              buf[len++] = '/';
 +              buf[len] = '\0';
@@ -542,7 +538,7 @@ that's how you can make rules local instead of inherited).
  static int check_one_exclude(char *name, struct exclude_struct *ex,
                               int name_is_dir)
  {
-@@ -122,18 +477,20 @@ static int check_one_exclude(char *name,
+@@ -125,13 +479,14 @@ 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. */
@@ -551,23 +547,16 @@ that's how you can make rules local instead of inherited).
                if ((p = strrchr(name,'/')) != NULL)
                        name = p+1;
        }
-       else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/') {
-               static char full_name[MAXPATHLEN];
--              int plus = curr_dir[1] == '\0'? 1 : 0;
--              pathjoin(full_name, sizeof full_name, curr_dir+plus, name);
-+              char *cd = curr_dir + module_dirlen;
-+              int plus = cd[1] == '\0'? 1 : 0;
-+              pathjoin(full_name, sizeof full_name, cd+plus, name);
+       else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
+-          && curr_dir[1]) {
+-              pathjoin(full_name, sizeof full_name, curr_dir + 1, name);
++          && curr_dir_len > module_dirlen + 1) {
++              pathjoin(full_name, sizeof full_name,
++                       curr_dir + module_dirlen + 1, name);
                name = full_name;
        }
  
--      if (!name[0]) return 0;
-+      if (!name[0])
-+              return 0;
-       if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir)
-               return 0;
-@@ -148,9 +505,9 @@ static int check_one_exclude(char *name,
+@@ -148,9 +503,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. */
@@ -579,7 +568,7 @@ that's how you can make rules local instead of inherited).
                        for (p = name + strlen(name) - 1; p >= name; p--) {
                                if (*p == '/' && !--cnt)
                                        break;
-@@ -221,6 +578,13 @@ int check_exclude(struct exclude_list_st
+@@ -221,6 +576,13 @@ int check_exclude(struct exclude_list_st
        struct exclude_struct *ent;
  
        for (ent = listp->head; ent; ent = ent->next) {
@@ -593,7 +582,7 @@ that's how you can make rules local instead of inherited).
                if (check_one_exclude(name, ent, name_is_dir)) {
                        report_exclude_result(name, ent, name_is_dir,
                                              listp->debug_type);
-@@ -253,11 +617,36 @@ static const char *get_exclude_tok(const
+@@ -253,11 +615,36 @@ static const char *get_exclude_tok(const
                p = (const char *)s;
        }
  
@@ -632,7 +621,7 @@ that's how you can make rules local instead of inherited).
                s += 2;
        } else if (xflags & XFLG_DEF_INCLUDE)
                mflags |= MATCHFLG_INCLUDE;
-@@ -273,6 +662,8 @@ static const char *get_exclude_tok(const
+@@ -273,6 +660,8 @@ static const char *get_exclude_tok(const
  
        if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY))
                mflags |= MATCHFLG_CLEAR_LIST;
@@ -641,7 +630,7 @@ that's how you can make rules local instead of inherited).
  
        *len_ptr = len;
        *flag_ptr = mflags;
-@@ -284,7 +675,7 @@ void add_exclude(struct exclude_list_str
+@@ -284,7 +673,7 @@ void add_exclude(struct exclude_list_str
                 int xflags)
  {
        unsigned int pat_len, mflags;
@@ -650,7 +639,7 @@ that's how you can make rules local instead of inherited).
  
        if (!pattern)
                return;
-@@ -292,9 +683,15 @@ void add_exclude(struct exclude_list_str
+@@ -292,9 +681,15 @@ void add_exclude(struct exclude_list_str
        cp = pattern;
        pat_len = 0;
        while (1) {
@@ -666,7 +655,7 @@ that's how you can make rules local instead of inherited).
  
                if (mflags & MATCHFLG_CLEAR_LIST) {
                        if (verbose > 2) {
-@@ -306,13 +703,24 @@ void add_exclude(struct exclude_list_str
+@@ -306,13 +701,24 @@ void add_exclude(struct exclude_list_str
                        continue;
                }
  
@@ -697,7 +686,7 @@ that's how you can make rules local instead of inherited).
        }
  }
  
-@@ -321,7 +729,7 @@ void add_exclude_file(struct exclude_lis
+@@ -321,7 +727,7 @@ void add_exclude_file(struct exclude_lis
                      int xflags)
  {
        FILE *fp;
@@ -706,7 +695,7 @@ that's how you can make rules local instead of inherited).
        char *eob = line + sizeof line - 1;
        int word_split = xflags & XFLG_WORD_SPLIT;
  
-@@ -342,6 +750,12 @@ void add_exclude_file(struct exclude_lis
+@@ -342,6 +748,12 @@ void add_exclude_file(struct exclude_lis
                }
                return;
        }
@@ -719,7 +708,7 @@ that's how you can make rules local instead of inherited).
  
        while (1) {
                char *s = line;
-@@ -402,7 +816,21 @@ void send_exclude_list(int f)
+@@ -402,7 +814,21 @@ void send_exclude_list(int f)
                if (ent->match_flags & MATCHFLG_INCLUDE) {
                        write_int(f, l + 2);
                        write_buf(f, "+ ", 2);
@@ -742,7 +731,7 @@ that's how you can make rules local instead of inherited).
                        write_int(f, l + 2);
                        write_buf(f, "- ", 2);
                } else
-@@ -443,6 +871,7 @@ void add_cvs_excludes(void)
+@@ -443,6 +869,7 @@ void add_cvs_excludes(void)
        char fname[MAXPATHLEN];
        char *p;
  
@@ -750,9 +739,9 @@ that's how you can make rules local instead of inherited).
        add_exclude(&exclude_list, default_cvsignore,
                    XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
  
---- orig/flist.c       2004-08-05 21:57:29
-+++ flist.c    2004-08-09 18:21:55
-@@ -39,10 +39,9 @@ extern int module_id;
+--- orig/flist.c       2004-09-21 09:40:27
++++ flist.c    2004-08-12 18:59:28
+@@ -40,10 +40,9 @@ extern int module_id;
  extern int ignore_errors;
  extern int numeric_ids;
  
@@ -764,7 +753,7 @@ that's how you can make rules local instead of inherited).
  extern char *files_from;
  extern int filesfrom_fd;
  
-@@ -66,7 +65,6 @@ extern int list_only;
+@@ -67,7 +66,6 @@ extern int list_only;
  
  extern struct exclude_list_struct exclude_list;
  extern struct exclude_list_struct server_exclude_list;
@@ -772,7 +761,7 @@ that's how you can make rules local instead of inherited).
  
  int io_error;
  
-@@ -221,8 +219,6 @@ int link_stat(const char *path, STRUCT_S
+@@ -223,8 +221,6 @@ int link_stat(const char *path, STRUCT_S
   */
  static int check_exclude_file(char *fname, int is_dir, int exclude_level)
  {
@@ -781,7 +770,7 @@ that's how you can make rules local instead of inherited).
  #if 0 /* This currently never happens, so avoid a useless compare. */
        if (exclude_level == NO_EXCLUDES)
                return 0;
-@@ -244,10 +240,7 @@ static int check_exclude_file(char *fnam
+@@ -246,10 +242,7 @@ static int check_exclude_file(char *fnam
        if (exclude_level != ALL_EXCLUDES)
                return 0;
        if (exclude_list.head
@@ -793,34 +782,7 @@ that's how you can make rules local instead of inherited).
                return 1;
        return 0;
  }
-@@ -573,7 +566,7 @@ void receive_file_entry(struct file_stru
-       clean_fname(thisname);
-       if (sanitize_paths)
--              sanitize_path(thisname, thisname, NULL);
-+              sanitize_path(thisname, thisname, "", NULL);
-       if ((basename = strrchr(thisname, '/')) != NULL) {
-               dirname_len = ++basename - thisname; /* counts future '\0' */
-@@ -671,7 +664,7 @@ void receive_file_entry(struct file_stru
-               file->u.link = bp;
-               read_sbuf(f, bp, linkname_len - 1);
-               if (sanitize_paths)
--                      sanitize_path(bp, bp, lastdir);
-+                      sanitize_path(bp, bp, "", lastdir);
-               bp += linkname_len;
-       }
- #endif
-@@ -761,7 +754,7 @@ struct file_struct *make_file(char *fnam
-       }
-       clean_fname(thisname);
-       if (sanitize_paths)
--              sanitize_path(thisname, thisname, NULL);
-+              sanitize_path(thisname, thisname, "", NULL);
-       memset(sum, 0, SUM_LENGTH);
-@@ -954,15 +947,7 @@ void send_file_name(int f, struct file_l
+@@ -978,15 +971,7 @@ void send_file_name(int f, struct file_l
  
        if (recursive && S_ISDIR(file->mode)
            && !(file->flags & FLAG_MOUNT_POINT)) {
@@ -836,7 +798,7 @@ that's how you can make rules local instead of inherited).
        }
  }
  
-@@ -973,6 +958,7 @@ static void send_directory(int f, struct
+@@ -997,6 +982,7 @@ static void send_directory(int f, struct
        struct dirent *di;
        char fname[MAXPATHLEN];
        unsigned int offset;
@@ -844,7 +806,7 @@ that's how you can make rules local instead of inherited).
        char *p;
  
        d = opendir(dir);
-@@ -996,18 +982,7 @@ static void send_directory(int f, struct
+@@ -1020,18 +1006,7 @@ static void send_directory(int f, struct
                offset++;
        }
  
@@ -864,7 +826,7 @@ that's how you can make rules local instead of inherited).
  
        for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
                char *dname = d_name(di);
-@@ -1028,6 +1003,8 @@ static void send_directory(int f, struct
+@@ -1052,6 +1027,8 @@ static void send_directory(int f, struct
                rsyserr(FERROR, errno, "readdir(%s)", dir);
        }
  
@@ -873,7 +835,7 @@ that's how you can make rules local instead of inherited).
        closedir(d);
  }
  
-@@ -1047,6 +1024,7 @@ struct file_list *send_file_list(int f, 
+@@ -1071,6 +1048,7 @@ struct file_list *send_file_list(int f, 
        char *p, *dir, olddir[sizeof curr_dir];
        char lastpath[MAXPATHLEN] = "";
        struct file_list *flist;
@@ -881,7 +843,7 @@ that's how you can make rules local instead of inherited).
        int64 start_write;
        int use_ff_fd = 0;
  
-@@ -1067,6 +1045,10 @@ struct file_list *send_file_list(int f, 
+@@ -1091,6 +1069,10 @@ struct file_list *send_file_list(int f, 
                                exit_cleanup(RERR_FILESELECT);
                        }
                        use_ff_fd = 1;
@@ -892,23 +854,7 @@ that's how you can make rules local instead of inherited).
                }
        }
  
-@@ -1077,13 +1059,13 @@ struct file_list *send_file_list(int f, 
-               if (use_ff_fd) {
-                       if (read_filesfrom_line(filesfrom_fd, fname) == 0)
-                               break;
--                      sanitize_path(fname, fname, NULL);
-+                      sanitize_path(fname, fname, "", NULL);
-               } else {
-                       if (argc-- == 0)
-                               break;
-                       strlcpy(fname, *argv++, MAXPATHLEN);
-                       if (sanitize_paths)
--                              sanitize_path(fname, fname, NULL);
-+                              sanitize_path(fname, fname, "", NULL);
-               }
-               l = strlen(fname);
-@@ -1097,6 +1079,15 @@ struct file_list *send_file_list(int f, 
+@@ -1121,6 +1103,15 @@ struct file_list *send_file_list(int f, 
                        }
                }
  
@@ -924,8 +870,8 @@ that's how you can make rules local instead of inherited).
                if (link_stat(fname, &st, keep_dirlinks) != 0) {
                        if (f != -1) {
                                io_error |= IOERR_GENERAL;
---- orig/options.c     2004-08-05 21:57:29
-+++ options.c  2004-08-09 18:22:26
+--- orig/options.c     2004-09-20 05:10:48
++++ options.c  2004-08-12 18:59:28
 @@ -287,6 +287,7 @@ void usage(enum logcode F)
    rprintf(F,"     --include=PATTERN       don't exclude files matching PATTERN\n");
    rprintf(F,"     --include-from=FILE     don't exclude patterns listed in FILE\n");
@@ -942,7 +888,7 @@ that's how you can make rules local instead of inherited).
    {0,                 'P', POPT_ARG_NONE,   0,              'P', 0, 0 },
    {"config",           0,  POPT_ARG_STRING, &config_file, 0, 0, 0 },
    {"port",             0,  POPT_ARG_INT,    &rsync_port, 0, 0, 0 },
-@@ -589,6 +591,11 @@ int parse_arguments(int *argc, const cha
+@@ -585,6 +587,11 @@ int parse_arguments(int *argc, const cha
                        am_sender = 1;
                        break;
  
@@ -954,30 +900,6 @@ that's how you can make rules local instead of inherited).
                case 'P':
                        do_progress = 1;
                        keep_partial = 1;
-@@ -728,17 +735,17 @@ int parse_arguments(int *argc, const cha
-       if (sanitize_paths) {
-               int i;
-               for (i = *argc; i-- > 0; )
--                      (*argv)[i] = sanitize_path(NULL, (*argv)[i], NULL);
-+                      (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", NULL);
-               if (tmpdir)
--                      tmpdir = sanitize_path(NULL, tmpdir, "");
-+                      tmpdir = sanitize_path(NULL, tmpdir, NULL, NULL);
-               if (partial_dir)
--                      partial_dir = sanitize_path(NULL, partial_dir, "");
-+                      partial_dir = sanitize_path(NULL, partial_dir, NULL, NULL);
-               if (compare_dest)
--                      compare_dest = sanitize_path(NULL, compare_dest, "");
-+                      compare_dest = sanitize_path(NULL, compare_dest, NULL, NULL);
-               if (backup_dir)
--                      backup_dir = sanitize_path(NULL, backup_dir, "");
-+                      backup_dir = sanitize_path(NULL, backup_dir, NULL, NULL);
-               if (files_from)
--                      files_from = sanitize_path(NULL, files_from, "");
-+                      files_from = sanitize_path(NULL, files_from, NULL, NULL);
-       }
-       if (server_exclude_list.head && !am_sender) {
-               struct exclude_list_struct *elp = &server_exclude_list;
 --- orig/rsync.h       2004-08-03 15:41:32
 +++ rsync.h    2004-08-08 06:07:01
 @@ -108,6 +108,7 @@
@@ -1008,9 +930,9 @@ that's how you can make rules local instead of inherited).
  };
  
  struct exclude_list_struct {
---- orig/rsync.yo      2004-08-03 15:34:32
-+++ rsync.yo   2004-08-10 04:49:06
-@@ -335,6 +335,7 @@ verb(
+--- orig/rsync.yo      2004-09-20 05:10:48
++++ rsync.yo   2004-08-13 00:43:31
+@@ -364,6 +364,7 @@ verb(
       --include=PATTERN       don't exclude files matching PATTERN
       --include-from=FILE     don't exclude patterns listed in FILE
       --files-from=FILE       read FILE for list of source-file names
@@ -1018,7 +940,7 @@ that's how you can make rules local instead of inherited).
   -0  --from0                 all file lists are delimited by nulls
       --version               print version number
       --daemon                run as an rsync daemon
-@@ -979,15 +980,22 @@ The exclude and include patterns specifi
+@@ -1025,24 +1026,32 @@ 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
@@ -1039,13 +961,18 @@ that's how you can make rules local instead of inherited).
  
 -The filenames matched against the exclude/include patterns are relative
 -to the "root of the transfer".  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).
 +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 
++the merge-file's directory).  If you think of the transfer as a
++subtree of names that are being sent from sender to receiver, the
++transfer-root is where the tree starts to be duplicated in the
++destination directory.  This root governs where patterns that start
++with a / match (as described in the list on pattern forms below).
+ Because the matching is relative to the transfer-root, changing 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
@@ -1054,16 +981,14 @@ that's how you can make rules local instead of inherited).
  
  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
+@@ -1089,23 +1098,27 @@ 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.
++options or multiple --include and --exclude options.
  
 -The patterns can take several forms. The rules are:
 +The include/exclude patterns can take several forms. The rules are:
@@ -1082,7 +1007,7 @@ that's how you can make rules local instead of inherited).
 +  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
++  transfer" (for a global rule) or in the merge-file's 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
@@ -1095,7 +1020,7 @@ that's how you can make rules local instead of inherited).
  
    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(
+@@ -1118,22 +1131,31 @@ itemize(
    single asterisk pattern "*" will stop at slashes.
  
    it() if the pattern contains a / (not counting a trailing /) or a "**"
@@ -1131,7 +1056,7 @@ that's how you can make rules local instead of inherited).
  )
  
  The +/- rules are most useful in a list that was read from a file, allowing
-@@ -1134,10 +1157,109 @@ itemize(
+@@ -1180,8 +1202,160 @@ itemize(
    it() --include "*/" --include "*.c" --exclude "*" would include all 
    directories and C source files
    it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
@@ -1146,31 +1071,39 @@ that's how you can make rules local instead of inherited).
 +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.  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:
++single-instance and per-directory.  The choice is made via an option
++placed 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.
-+
-+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.
++when the file exists.  These exclude files must exist on the sending side
++because it is the sending side that is being scanned for available files
++to send.  The files may also need to be transferred to the receiving side
++if you want them to affect what files don't get deleted (see PER-DIRECTORY
++EXCLUDES AND DELETE below).
 +
 +dit(bf(--)) End the scanning of options.  Useful if you want to specify a
 +filename that begins with a dash.
 +
 +enddit()
 +
-+Here's an example exclude file (which you'd specify via the normal
-+--exclude-from=FILE option):
++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.  The entire set
++of per-dir rules is grouped together in the spot where the merge-file was
++specified, so it is possible to override per-dir rules via a rule that
++got specified earlier in the list of global rules.
++
++If you don't want a per-dir rule to be inherited, anchor it with a leading
++slash.  Anchored rules in a per-directory merge-file are relative to the
++merge-file's directory, so a rule "/foo" would only exclude the file "foo"
++in the directory where the per-dir exclude file was found.
++
++Here's an example exclude file which you'd specify via the normal
++--exclude-from=FILE option:
 +
 +verb(
 +    . /home/user/.global_excludes
@@ -1178,15 +1111,13 @@ that's how you can make rules local instead of inherited).
 +    . -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.  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).
++.global_excludes file are anchored just like all other global rules.
 +
 +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
@@ -1199,8 +1130,8 @@ that's how you can make rules local instead of inherited).
 +)
 +
 +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.)
++directories from the root down 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:
 +
@@ -1226,7 +1157,7 @@ that's how you can make rules local instead of inherited).
 +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
++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:
 +
@@ -1240,9 +1171,54 @@ that's how you can make rules local instead of inherited).
 +rules taken from the $HOME/.cvsignore file and from $CVSIGNORE are not
 +repositioned by this.)
 +
- manpagesection(BATCH MODE)
++manpagesection(PER-DIRECTORY EXCLUDES AND DELETE)
++
++Without a delete option, per-directory excludes are only relevant on the
++sending side, so you can feel free to exclude the merge files themselves
++without affecting the transfer:
++
++verb(
++  rsync -av --exclude='. -p .excl' --exclude=.excl host:src/dir /dest
++)
++
++However, if you want to do a delete on the receiving side AND you want some
++files to be excluded from being deleted, you'll need to be sure that the
++receiving side knows what files to exclude.  The easiest way is to include
++the per-directory merge files in the transfer and use --delete-after
++because this ensures that the receiving side gets all the same exclude
++rules as the sending side before it tries to delete anything:
++
++verb(
++  rsync -avE --delete-after host:src/dir /dest
++)
++
++However, if you the merge files are not a part of the transfer, you'll need
++to either use a global exclude rule (i.e. specified on the command line),
++or you'll need to maintain your own per-directory merge files on the
++receiving side.  An example of the first is this (assume that the remote
++.ctrl files exclude themselves):
++
++verb(
++  rsync -av --exclude='. -p .ctrl' --exclude-from=/my/extra.rules
++    --delete host:src/dir /dest
++)
++
++In the above example the extra.rules file can affect both sides of the
++transfer, but the rules are subservient to the rules merged from the .ctrl
++files because they were specified after the per-directory merge rule.
++
++In the final example, the remote side is excluding the .rsync-excludes
++files from the transfer, but we want to use our own .rsync-excludes files
++to control what gets deleted on the receiving side.  To do this we must
++specifically exclude the per-directory merge files (so that they don't get
++deleted) and then put rules into the local files to control what else
++should not get deleted.  Like this:
++
++verb(
++  rsync -avE --exclude=.rsync-excludes --delete host:src/dir /dest
+ )
  
- bf(Note:) Batch mode should be considered experimental in this version
+ manpagesection(BATCH MODE)
 --- orig/testsuite/exclude.test        2004-05-29 21:25:45
 +++ testsuite/exclude.test     2004-08-08 06:35:15
 @@ -23,19 +23,47 @@ export HOME CVSIGNORE
@@ -1318,72 +1294,3 @@ that's how you can make rules local instead of inherited).
 +
  # The script would have aborted on error, so getting here means we've won.
  exit 0
---- 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 = ".";
-       if (sanitize_paths)
--              s = sanitize_path(NULL, s, NULL);
-+              s = sanitize_path(NULL, s, "", NULL);
-       else
-               s = strdup(s);
-@@ -706,18 +706,16 @@ unsigned int clean_fname(char *name)
-  * "/" (either removing it or expanding it) and any leading or embedded
-  * ".." components that attempt to escape past the module's top dir.
-  *
-- * If dest is NULL, a buffer is allocated to hold the result.  If dest is
-- * the same buffer as p (the path) OR if reldir is NULL, a leading slash
-- * is dropped instead of being expanded to be the module's top dir.
-+ * If dest is NULL, a buffer is allocated to hold the result.  It is legal
-+ * to call with the dest and the path (p) pointing to the same buffer, but
-+ * rootdir is ignored to avoid expansion of the string.
-+ *
-+ * The rootdir string contains a value to use in place of a leading slash.
-+ * Specify NULL to get the default of lp_path(module_id).
-  *
-  * If reldir is non-NULL (and non-empty), it is a sanitized directory that
-  * the path will be relative to, so allow as many '..'s at the beginning of
-- * the path as there are components in reldir.  This is used for symbolic
-- * link targets.  If reldir is non-null and the path began with "/", to be
-- * completely like a chroot we should add in depth levels of ".." at the
-- * beginning of the path, but that would blow the assumption that the path
-- * doesn't grow and it is not likely to end up being a valid symlink
-- * anyway, so just do the normal removal of the leading "/" instead.
-+ * the path as there are components in reldir.
-  *
-  * While we're at it, remove double slashes and "." components like
-  * clean_fname() does, but DON'T remove a trailing slash because that is
-@@ -725,7 +723,8 @@ unsigned int clean_fname(char *name)
-  *
-  * If the resulting path would be empty, change it into ".".
-  */
--char *sanitize_path(char *dest, const char *p, const char *reldir)
-+char *sanitize_path(char *dest, const char *p, const char *rootdir,
-+                  const char *reldir)
- {
-       char *start, *sanp;
-       int depth = 0;
-@@ -734,8 +733,10 @@ char *sanitize_path(char *dest, const ch
-       if (dest != p) {
-               int plen = strlen(p);
--              if (*p == '/' && reldir) {
--                      rlen = strlen(lp_path(module_id));
-+              if (*p == '/') {
-+                      if (!rootdir)
-+                              rootdir = lp_path(module_id);
-+                      rlen = strlen(rootdir);
-                       reldir = NULL;
-                       p++;
-               }
-@@ -745,7 +746,7 @@ char *sanitize_path(char *dest, const ch
-               } else if (!(dest = new_array(char, rlen + plen + 1)))
-                       out_of_memory("sanitize_path");
-               if (rlen) {
--                      memcpy(dest, lp_path(module_id), rlen);
-+                      memcpy(dest, rootdir, rlen);
-                       if (rlen > 1)
-                               dest[rlen++] = '/';
-               }