>       I like the idea of your rsync-exclude.patch and have thought
> about hacking it in myself. However as you already have done the work
> may I make a small suggestion...... can the name of the exclude file 
> (your .rsync) be specified in the flags.... e.g.
> 
>       rsync --rsync-exclude=.snapshot -axvH /here /there
> 
> In this way different invocations (e.g. system and personal) can exclude
> different files.
> 
> Anthony R Iano-Fletcher        [EMAIL PROTECTED]
>                                http://cbel.cit.nih.gov/~arif
>                                CBEL, CIT, NIH, Bethesda, MD, USA.

A good idea. I have implemented this as 

http://www.math.ualberta.ca/imaging/rlbackup/rsync-exclude-file.patch

Unfortunately, backwards compatibility with the previous syntax

        rsync --rsync-exclude -axvH /here /there

does not appear to be possible, because of deficiencies in the popt
option routines relative to getopt_long: popt doesn't really handle
optional arguments correctly, even with POPT_ARGFLAG_OPTIONAL.

Anyway, below is the new version of the --rsync-exclude patch.
This is a useful and general enough feature that I hope it will be added
to the next release of rsync.

-- John Bowman
University of Alberta

This is a patch to add an --rsync-exclude=FILE option to rsync-2.5.6.
Patterns in FILE are used to recursively exclude/include files in a
directory and all of its subdirectories. For example,

rsync --rsync-exclude=.rsync -vaxH /here /there

will copy all files from /here to /there, excluding any files listed in
a file .rsync from the directory containing this file and all of its
subdirectories. As usual, prefixing a pattern with "+ " forces inclusion
rather than exclusion.

This has advantages over --cvs-exclude for backing up large file systems
since the .cvsignore files only apply to the current directory:
unless the .cvsignore restrictions apply to the entire tree they must be
duplicated in each subdirectory. In any case, the --cvs-exclude option
isn't intended for general system backups (for example, unless the default
list is cleared with "!", it automatically excludes *.a and *.so libraries).

diff -ru rsync-2.5.6/exclude.c rsync-2.5.6J/exclude.c
--- rsync-2.5.6/exclude.c       Sun Jan 26 13:10:23 2003
+++ rsync-2.5.6J/exclude.c      Wed Jan 29 17:16:39 2003
@@ -127,6 +127,7 @@
 
 static void report_exclude_result(char const *name,
                                   struct exclude_struct const *ent,
+                                 char const *type,
                                   STRUCT_STAT const *st)
 {
         /* If a trailing slash is present to match only directories,
@@ -134,10 +135,10 @@
          * case we add it back in here. */
         
         if (verbose >= 2)
-                rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
+                rprintf(FINFO, "%s %s %s because of %s pattern %s%s\n",
                         ent->include ? "including" : "excluding",
                         S_ISDIR(st->st_mode) ? "directory" : "file",
-                        name, ent->pattern,
+                        name, type, ent->pattern,
                         ent->directory ? "/" : "");
 }
 
@@ -147,6 +148,7 @@
  * LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
  */
 int check_exclude(char *name, struct exclude_struct **local_exclude_list,
+                 struct exclude_struct **recur_local_exclude_list,
                  STRUCT_STAT *st)
 {
        int n;
@@ -156,21 +158,37 @@
                /* never exclude '.', even if somebody does --exclude '*' */
                return 0;
 
-       if (exclude_list) {
-               for (n=0; exclude_list[n]; n++) {
-                        ent = exclude_list[n];
+       /* Precedence: use the most local and most recent matching pattern,
+          in this order: FILE, .cvsignore, --exclude */
+       
+       if (recur_local_exclude_list) {
+               for (n=0; recur_local_exclude_list[n]; n++) ;
+               for (n--; n >= 0; n--) {
+                        ent = recur_local_exclude_list[n];
                        if (check_one_exclude(name, ent, st)) {
-                                report_exclude_result(name, ent, st);
+                                report_exclude_result(name, ent, "rsync", st);
                                return !ent->include;
                         }
                 }
        }
 
        if (local_exclude_list) {
-               for (n=0; local_exclude_list[n]; n++) {
+               for (n=0; local_exclude_list[n]; n++) ;
+               for (n--; n >= 0; n--) {
                         ent = local_exclude_list[n];
                        if (check_one_exclude(name, ent, st)) {
-                                report_exclude_result(name, ent, st);
+                                report_exclude_result(name, ent, "cvsignore", st);
+                               return !ent->include;
+                        }
+                }
+       }
+
+       if (exclude_list) {
+               for (n=0; exclude_list[n]; n++) ;
+               for (n--; n >= 0; n--) {
+                        ent = exclude_list[n];
+                       if (check_one_exclude(name, ent, st)) {
+                                report_exclude_result(name, ent, "global", st);
                                return !ent->include;
                         }
                 }
diff -ru rsync-2.5.6/flist.c rsync-2.5.6J/flist.c
--- rsync-2.5.6/flist.c Sat Jan 18 11:00:23 2003
+++ rsync-2.5.6J/flist.c        Thu Feb 13 09:59:40 2003
@@ -39,6 +39,7 @@
 extern int always_checksum;
 
 extern int cvs_exclude;
+extern const char *rsync_exclude;
 
 extern int recurse;
 
@@ -62,6 +63,7 @@
 extern int write_batch;
 
 static struct exclude_struct **local_exclude_list;
+static struct exclude_struct **recur_local_exclude_list;
 
 static struct file_struct null_file;
 
@@ -258,7 +260,8 @@
        if ((f == -1) && delete_excluded) {
                return 0;
        }
-       if (check_exclude(fname, local_exclude_list, st)) {
+       if (check_exclude(fname, local_exclude_list, 
+                         recur_local_exclude_list, st)) {
                return 1;
        }
        return 0;
@@ -773,7 +776,32 @@
        return file;
 }
 
+static struct exclude_struct **copy_exclude_list(struct exclude_struct **from) {
+       struct exclude_struct **to;
+       int i;
+       int len=0;
+       int size;
+       
+       if (!from) return NULL;
+       
+       for (; from[len]; len++) ;
+       size=sizeof(struct exclude_struct *)*(len+1);
+       to = (struct exclude_struct **) malloc(size);
+       if (!to) out_of_memory("copy_exclude_list");
+
+       size=sizeof(struct exclude_struct);
+       for (i=0; i < len; i++) {
+               struct exclude_struct *p;
+               p=to[i]=(struct exclude_struct *) malloc(size);
+               if (!p) out_of_memory("copy_exclude_list");
+               *p=*from[i];
+               p->pattern=strdup(from[i]->pattern);
+               if (!p->pattern) out_of_memory("copy_exclude_list");
+       }
+       to[len]=NULL;
 
+       return to;
+}
 
 void send_file_name(int f, struct file_list *flist, char *fname,
                    int recursive, unsigned base_flags)
@@ -800,8 +828,11 @@
        if (S_ISDIR(file->mode) && recursive) {
                struct exclude_struct **last_exclude_list =
                    local_exclude_list;
+               struct exclude_struct **recur_last_exclude_list =
+                   recur_local_exclude_list;
                send_directory(f, flist, f_name(file));
                local_exclude_list = last_exclude_list;
+               recur_local_exclude_list = recur_last_exclude_list;
                return;
        }
 }
@@ -840,6 +871,7 @@
        p = fname + strlen(fname);
 
        local_exclude_list = NULL;
+       recur_local_exclude_list = copy_exclude_list(recur_local_exclude_list);
 
        if (cvs_exclude) {
                if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN - 1) {
@@ -854,6 +886,19 @@
                }
        }
 
+       if (rsync_exclude) {
+               if (strlen(fname) + strlen(rsync_exclude) <= MAXPATHLEN - 1) {
+                       strcpy(p, rsync_exclude);
+                       recur_local_exclude_list =
+                           make_exclude_list(fname, recur_local_exclude_list, 0, 0);
+               } else {
+                       io_error = 1;
+                       rprintf(FINFO,
+                               "cannot cvs-exclude in long-named directory %s\n",
+                               fname);
+               }
+       }
+
        for (di = readdir(d); di; di = readdir(d)) {
                char *dname = d_name(di);
                if (strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0)
@@ -866,6 +911,10 @@
                add_exclude_list("!", &local_exclude_list, 0);
        }
 
+       if (recur_local_exclude_list) {
+               add_exclude_list("!", &recur_local_exclude_list, 0);
+       }
+
        closedir(d);
 }
 
@@ -887,6 +936,8 @@
        if (show_filelist_p() && f != -1)
                start_filelist_progress("building file list");
 
+       recur_local_exclude_list = NULL;
+       
        start_write = stats.total_written;
 
        flist = flist_new();
diff -ru rsync-2.5.6/options.c rsync-2.5.6J/options.c
--- rsync-2.5.6/options.c       Mon Jan 27 20:11:57 2003
+++ rsync-2.5.6J/options.c      Thu Feb 13 11:13:01 2003
@@ -45,6 +45,7 @@
 int preserve_times = 0;
 int update_only = 0;
 int cvs_exclude = 0;
+const char *rsync_exclude = NULL;
 int dry_run=0;
 int local_server=0;
 int ignore_times=0;
@@ -84,7 +85,6 @@
 int modify_window=0;
 int blocking_io=-1;
 
-
 /** Network address family. **/
 #ifdef INET6
 int default_af_hint = 0;       /* Any protocol */
@@ -233,6 +233,7 @@
   rprintf(F," -e, --rsh=COMMAND           specify the remote shell\n");
   rprintf(F,"     --rsync-path=PATH       specify path to rsync on the remote 
machine\n");
   rprintf(F," -C, --cvs-exclude           auto ignore files in the same way CVS 
does\n");
+  rprintf(F,"     --rsync-exclude=FILE    recursively exclude files listed in 
+FILE\n");
   rprintf(F,"     --existing              only update files that already exist\n");
   rprintf(F,"     --ignore-existing       ignore files that already exist on the 
receiving side\n");
   rprintf(F,"     --delete                delete files that don't exist on the 
sending side\n");
@@ -320,6 +321,7 @@
   {"dry-run",         'n', POPT_ARG_NONE,   &dry_run , 0, 0, 0 },
   {"sparse",          'S', POPT_ARG_NONE,   &sparse_files , 0, 0, 0 },
   {"cvs-exclude",     'C', POPT_ARG_NONE,   &cvs_exclude , 0, 0, 0 },
+  {"rsync-exclude",    0,  POPT_ARG_STRING, &rsync_exclude , 0, 0, 0 },
   {"update",          'u', POPT_ARG_NONE,   &update_only , 0, 0, 0 },
   {"links",           'l', POPT_ARG_NONE,   &preserve_links , 0, 0, 0 },
   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links , 0, 0, 0 },
diff -ru rsync-2.5.6/proto.h rsync-2.5.6J/proto.h
--- rsync-2.5.6/proto.h Sun Jan 26 20:35:09 2003
+++ rsync-2.5.6J/proto.h        Wed Jan 29 17:16:39 2003
@@ -58,6 +58,7 @@
 void setup_protocol(int f_out,int f_in);
 int claim_connection(char *fname,int max_connections);
 int check_exclude(char *name, struct exclude_struct **local_exclude_list,
+                 struct exclude_struct **recur_local_exclude_list,
                  STRUCT_STAT *st);
 void add_exclude_list(const char *pattern, struct exclude_struct ***list, int 
include);
 void add_exclude(const char *pattern, int include);
diff -ru rsync-2.5.6/rsync.yo rsync-2.5.6J/rsync.yo
--- rsync-2.5.6/rsync.yo        Mon Jan 27 20:11:57 2003
+++ rsync-2.5.6J/rsync.yo       Thu Feb 13 11:57:07 2003
@@ -311,6 +311,7 @@
  -e, --rsh=COMMAND           specify the remote shell to use
      --rsync-path=PATH       specify path to rsync on the remote machine
  -C, --cvs-exclude           auto ignore files in the same way CVS does
+     --rsync-exclude=FILE    recursively exclude files listed in FILE
      --existing              only update files that already exist
      --ignore-existing       ignore files that already exist on the receiving side
      --delete                delete files that don't exist on the sending side
@@ -654,6 +655,12 @@
 .cvsignore file and matches one of the patterns listed therein.  See
 the bf(cvs(1)) manual for more information.
 
+dit(bf(--rsync-exclude=FILE)) Patterns in FILE are excluded from the file
+lists associated with the current directory and all of its subdirectories.
+Prefixing the file name with "+ " will force inclusion of the file.
+If there are multiplying matching patterns, the most local and most recent
+matching pattern will be used, in this order: FILE, .cvsignore, --exclude.
+
 dit(bf(--csum-length=LENGTH)) By default the primary checksum used in
 rsync is a very strong 16 byte MD4 checksum. In most cases you will
 find that a truncated version of this checksum is quite efficient, and




-- 
To unsubscribe or change options: http://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.tuxedo.org/~esr/faqs/smart-questions.html

Reply via email to