- Needed to send the new merge-file options across the socket.
authorWayne Davison <wayned@samba.org>
Fri, 6 Aug 2004 23:01:43 +0000 (23:01 +0000)
committerWayne Davison <wayned@samba.org>
Fri, 6 Aug 2004 23:01:43 +0000 (23:01 +0000)
- Fixed some problems when running as a daemon.
- A few other minor fixes.
- Improved the docs.

filter.diff

index d5ed382..29d8bb9 100644 (file)
@@ -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)