From 2b6b4d539b0aab98b1cbb9d8c639cb12473aae94 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 27 May 1998 11:02:33 +0000 Subject: [PATCH] added support for --include, --include-from and the +/- syntax --- clientserver.c | 2 +- configure.in | 2 +- exclude.c | 309 ++++++++++++++++++++++++++++++------------------- flist.c | 14 +-- lib/compat.c | 18 +++ options.c | 19 ++- rsync.h | 10 ++ zlib/zutil.c | 5 - 8 files changed, 244 insertions(+), 135 deletions(-) diff --git a/clientserver.c b/clientserver.c index 7ce08e6d..63ff4230 100644 --- a/clientserver.c +++ b/clientserver.c @@ -174,7 +174,7 @@ static int rsync_module(int fd, int i) } p = lp_exclude_from(i); - add_exclude_file(p, 1); + add_exclude_file(p, 1, 0); p = lp_exclude(i); add_exclude_line(p); diff --git a/configure.in b/configure.in index f328b9a4..1aa07875 100644 --- a/configure.in +++ b/configure.in @@ -41,7 +41,7 @@ AC_FUNC_MEMCMP AC_FUNC_UTIME_NULL AC_CHECK_FUNCS(mmap munmap waitpid getcwd strdup strerror chown chmod mknod) AC_CHECK_FUNCS(fchmod fstat strchr bcopy bzero readlink link utime utimes) -AC_CHECK_FUNCS(memmove getopt_long lchown setlinebuf vsnprintf setsid glob) +AC_CHECK_FUNCS(memmove getopt_long lchown setlinebuf vsnprintf setsid glob strpbrk) echo $ac_n "checking for working fnmatch... $ac_c" AC_TRY_RUN([#include diff --git a/exclude.c b/exclude.c index 901047eb..577c289b 100644 --- a/exclude.c +++ b/exclude.c @@ -17,160 +17,233 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - a lot of this stuff was derived from GNU tar - */ +/* a lot of this stuff was originally derived from GNU tar, although + it has now changed so much that it is hard to tell :) */ #include "rsync.h" extern int verbose; -static char **exclude_list; +static struct exclude_struct **exclude_list; -static int is_regex(char *str) +/* build an exclude structure given a exclude pattern */ +static struct exclude_struct *make_exclude(char *pattern, int include) { - return strchr(str, '*') || strchr(str, '[') || strchr(str, '?'); -} + struct exclude_struct *ret; + ret = (struct exclude_struct *)malloc(sizeof(*ret)); + if (!ret) out_of_memory("make_exclude"); -static int check_one_exclude(char *name,char *pattern) -{ - char *p; + memset(ret, 0, sizeof(*ret)); + + ret->orig = strdup(pattern); + + if (strncmp(pattern,"- ",2) == 0) { + pattern += 2; + } else if (strncmp(pattern,"+ ",2) == 0) { + ret->include = 1; + pattern += 2; + } else { + ret->include = include; + } + + ret->pattern = strdup(pattern); + + if (!ret->orig || !ret->pattern) out_of_memory("make_exclude"); - if (!strchr(pattern,'/') && (p=strrchr(name,'/'))) - name = p+1; + if (strpbrk(pattern, "*[?")) ret->regular_exp = 1; - if (!name[0]) return 0; + if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') { + ret->pattern[strlen(pattern)-1] = 0; + ret->directory = 1; + } - if (*pattern == '/' && *name != '/') pattern++; + if (!strchr(ret->pattern,'/')) { + ret->local = 1; + } - if (is_regex(pattern)) { - if (fnmatch(pattern, name, 0) == 0) - return 1; - } else { - int l1 = strlen(name); - int l2 = strlen(pattern); - if (l2 <= l1 && - strcmp(name+(l1-l2),pattern) == 0 && - (l1==l2 || name[l1-(l2+1)] == '/')) - return 1; - } + return ret; +} + +static void free_exclude(struct exclude_struct *ex) +{ + free(ex->orig); + free(ex->pattern); + memset(ex,0,sizeof(*ex)); + free(ex); +} - return 0; +static int check_one_exclude(char *name,struct exclude_struct *ex, + STRUCT_STAT *st) +{ + char *p; + int match_start=0; + char *pattern = ex->pattern; + + if (ex->local && (p=strrchr(name,'/'))) + name = p+1; + + if (!name[0]) return 0; + + if (ex->directory && !S_ISDIR(st->st_mode)) return 0; + + if (*pattern == '/' && *name != '/') { + match_start = 1; + pattern++; + } + + if (ex->regular_exp) { + if (fnmatch(ex->pattern, name, 0) == 0) + return 1; + } else { + int l1 = strlen(name); + int l2 = strlen(ex->pattern); + if (l2 <= l1 && + strcmp(name+(l1-l2),ex->pattern) == 0 && + (l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) + return 1; + } + + return 0; } -int check_exclude(char *name,char **local_exclude_list) +int check_exclude(char *name,struct exclude_struct **local_exclude_list, + STRUCT_STAT *st) { - int n; + int n; - if (exclude_list) { - for (n=0; exclude_list[n]; n++) - if (check_one_exclude(name,exclude_list[n])) - return 1; - } + if (exclude_list) { + for (n=0; exclude_list[n]; n++) + if (check_one_exclude(name,exclude_list[n],st)) + return !exclude_list[n]->include; + } - if (local_exclude_list) { - for (n=0; local_exclude_list[n]; n++) - if (check_one_exclude(name,local_exclude_list[n])) - return 1; - } + if (local_exclude_list) { + for (n=0; local_exclude_list[n]; n++) + if (check_one_exclude(name,local_exclude_list[n],st)) + return !local_exclude_list[n]->include; + } - return 0; + return 0; } -void add_exclude_list(char *pattern,char ***list) +void add_exclude_list(char *pattern,struct exclude_struct ***list, int include) { - int len=0; - if (list && *list) - for (; (*list)[len]; len++) ; - - if (strcmp(pattern,"!") == 0) { - if (verbose > 2) - rprintf(FINFO,"clearing exclude list\n"); - while ((len)--) - free((*list)[len]); - free((*list)); - *list = NULL; - return; - } - - if (!*list) { - *list = (char **)malloc(sizeof(char *)*2); - } else { - *list = (char **)realloc(*list,sizeof(char *)*(len+2)); - } - - if (!*list || !((*list)[len] = strdup(pattern))) - out_of_memory("add_exclude"); - - if (verbose > 2) - rprintf(FINFO,"add_exclude(%s)\n",pattern); - - (*list)[len+1] = NULL; + int len=0; + if (list && *list) + for (; (*list)[len]; len++) ; + + if (strcmp(pattern,"!") == 0) { + if (verbose > 2) + rprintf(FINFO,"clearing exclude list\n"); + while ((len)--) { + free_exclude((*list)[len]); + } + free((*list)); + *list = NULL; + return; + } + + if (!*list) { + *list = (struct exclude_struct **)malloc(sizeof(struct exclude_struct *)*2); + } else { + *list = (struct exclude_struct **)realloc(*list,sizeof(struct exclude_struct *)*(len+2)); + } + + if (!*list || !((*list)[len] = make_exclude(pattern, include))) + out_of_memory("add_exclude"); + + if (verbose > 2) + rprintf(FINFO,"add_exclude(%s)\n",pattern); + + (*list)[len+1] = NULL; } -void add_exclude(char *pattern) +void add_exclude(char *pattern, int include) { - add_exclude_list(pattern,&exclude_list); + add_exclude_list(pattern,&exclude_list, include); } -char **make_exclude_list(char *fname,char **list1,int fatal) +struct exclude_struct **make_exclude_list(char *fname, + struct exclude_struct **list1, + int fatal, int include) { - char **list=list1; - FILE *f = fopen(fname,"r"); - char line[MAXPATHLEN]; - if (!f) { - if (fatal) { - rprintf(FERROR,"%s : %s\n",fname,strerror(errno)); - exit_cleanup(1); - } - return list; - } - - while (fgets(line,MAXPATHLEN,f)) { - int l = strlen(line); - if (l && line[l-1] == '\n') l--; - line[l] = 0; - if (line[0]) add_exclude_list(line,&list); - } - fclose(f); - return list; + struct exclude_struct **list=list1; + FILE *f = fopen(fname,"r"); + char line[MAXPATHLEN]; + if (!f) { + if (fatal) { + rprintf(FERROR,"%s : %s\n",fname,strerror(errno)); + exit_cleanup(1); + } + return list; + } + + while (fgets(line,MAXPATHLEN,f)) { + int l = strlen(line); + if (l && line[l-1] == '\n') l--; + line[l] = 0; + if (line[0]) add_exclude_list(line,&list,include); + } + fclose(f); + return list; } -void add_exclude_file(char *fname,int fatal) +void add_exclude_file(char *fname,int fatal,int include) { if (!fname || !*fname) return; - exclude_list = make_exclude_list(fname,exclude_list,fatal); + exclude_list = make_exclude_list(fname,exclude_list,fatal,include); } void send_exclude_list(int f) { - int i; - if (exclude_list) - for (i=0;exclude_list[i];i++) { - int l = strlen(exclude_list[i]); - if (l == 0) continue; - write_int(f,l); - write_buf(f,exclude_list[i],l); - } - write_int(f,0); + int i; + extern int remote_version; + + if (!exclude_list) { + write_int(f,0); + return; + } + + for (i=0;exclude_list[i];i++) { + char *pattern = exclude_list[i]->orig; + int l; + + if (remote_version < 19) { + if (strncmp(pattern,"+ ", 2)==0) { + rprintf(FERROR,"remote rsync does not support include syntax - aborting\n"); + exit_cleanup(1); + } + + if (strncmp(pattern,"- ", 2) == 0) { + pattern += 2; + } + } + + l = strlen(pattern); + if (l == 0) continue; + write_int(f,l); + write_buf(f,pattern,l); + } + + write_int(f,0); } void recv_exclude_list(int f) { - char line[MAXPATHLEN]; - int l; - while ((l=read_int(f))) { - if (l >= MAXPATHLEN) overflow("recv_exclude_list"); - read_sbuf(f,line,l); - add_exclude(line); - } + char line[MAXPATHLEN]; + int l; + while ((l=read_int(f))) { + if (l >= MAXPATHLEN) overflow("recv_exclude_list"); + read_sbuf(f,line,l); + add_exclude(line,0); + } } @@ -181,7 +254,7 @@ void add_exclude_line(char *p) p = strdup(p); if (!p) out_of_memory("add_exclude_line"); for (tok=strtok(p," "); tok; tok=strtok(NULL," ")) - add_exclude(tok); + add_exclude(tok, 0); free(p); } @@ -197,17 +270,17 @@ static char *cvs_ignore_list[] = { void add_cvs_excludes(void) { - char fname[MAXPATHLEN]; - char *p; - int i; + char fname[MAXPATHLEN]; + char *p; + int i; - for (i=0; cvs_ignore_list[i]; i++) - add_exclude(cvs_ignore_list[i]); + for (i=0; cvs_ignore_list[i]; i++) + add_exclude(cvs_ignore_list[i], 0); - if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) { - slprintf(fname,sizeof(fname)-1, "%s/.cvsignore",p); - add_exclude_file(fname,0); - } + if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) { + slprintf(fname,sizeof(fname)-1, "%s/.cvsignore",p); + add_exclude_file(fname,0,0); + } - add_exclude_line(getenv("CVSIGNORE")); + add_exclude_line(getenv("CVSIGNORE")); } diff --git a/flist.c b/flist.c index 5cf30446..7b2c985c 100644 --- a/flist.c +++ b/flist.c @@ -46,7 +46,7 @@ extern int copy_links; extern int remote_version; extern int io_error; -static char **local_exclude_list; +static struct exclude_struct **local_exclude_list; int link_stat(const char *Path, STRUCT_STAT *Buffer) { @@ -67,7 +67,7 @@ int link_stat(const char *Path, STRUCT_STAT *Buffer) */ static int match_file_name(char *fname,STRUCT_STAT *st) { - if (check_exclude(fname,local_exclude_list)) { + if (check_exclude(fname,local_exclude_list,st)) { if (verbose > 2) rprintf(FINFO,"excluding file %s\n",fname); return 0; @@ -493,10 +493,10 @@ static void send_file_name(int f,struct file_list *flist,char *fname, } if (S_ISDIR(file->mode) && recursive) { - char **last_exclude_list = local_exclude_list; - send_directory(f,flist,f_name(file)); - local_exclude_list = last_exclude_list; - return; + struct exclude_struct **last_exclude_list = local_exclude_list; + send_directory(f,flist,f_name(file)); + local_exclude_list = last_exclude_list; + return; } } @@ -535,7 +535,7 @@ static void send_directory(int f,struct file_list *flist,char *dir) if (cvs_exclude) { if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) { strcpy(p,".cvsignore"); - local_exclude_list = make_exclude_list(fname,NULL,0); + local_exclude_list = make_exclude_list(fname,NULL,0,0); } else { io_error = 1; rprintf(FINFO,"cannot cvs-exclude in long-named directory %s\n",fname); diff --git a/lib/compat.c b/lib/compat.c index 3e66cc91..c0cf63b4 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -58,3 +58,21 @@ void *memmove(void *dest, const void *src, size_t n) return dest; } #endif + +#ifndef HAVE_STRPBRK +/* Find the first ocurrence in S of any character in ACCEPT. + derived from glibc +*/ +char *strpbrk(const char *s, const char *accept) +{ + while (*s != '\0') { + const char *a = accept; + while (*a != '\0') { + if (*a++ == *s) return (char *)s; + } + ++s; + } + + return NULL; +} +#endif diff --git a/options.c b/options.c index 11dbcbea..09363abf 100644 --- a/options.c +++ b/options.c @@ -109,6 +109,8 @@ void usage(int F) rprintf(F,"-z, --compress compress file data\n"); rprintf(F," --exclude FILE exclude file FILE\n"); rprintf(F," --exclude-from FILE exclude files listed in FILE\n"); + rprintf(F," --include FILE don't exclude file FILE\n"); + rprintf(F," --include-from FILE don't exclude files listed in FILE\n"); rprintf(F," --suffix SUFFIX override backup suffix\n"); rprintf(F," --version print version number\n"); rprintf(F," --daemon run as a rsync daemon\n"); @@ -122,7 +124,8 @@ void usage(int F) enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE, OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH, - OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT}; + OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT, + OPT_INCLUDE, OPT_INCLUDE_FROM}; static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z"; @@ -135,6 +138,8 @@ static struct option long_options[] = { {"numeric-ids", 0, 0, OPT_NUMERIC_IDS}, {"exclude", 1, 0, OPT_EXCLUDE}, {"exclude-from",1, 0, OPT_EXCLUDE_FROM}, + {"include", 1, 0, OPT_INCLUDE}, + {"include-from",1, 0, OPT_INCLUDE_FROM}, {"rsync-path", 1, 0, OPT_RSYNC_PATH}, {"one-file-system",0, 0, 'x'}, {"ignore-times",0, 0, 'I'}, @@ -213,11 +218,19 @@ void parse_arguments(int argc, char *argv[]) break; case OPT_EXCLUDE: - add_exclude(optarg); + add_exclude(optarg, 0); + break; + + case OPT_INCLUDE: + add_exclude(optarg, 1); break; case OPT_EXCLUDE_FROM: - add_exclude_file(optarg,1); + add_exclude_file(optarg,1, 0); + break; + + case OPT_INCLUDE_FROM: + add_exclude_file(optarg,1, 1); break; case 'h': diff --git a/rsync.h b/rsync.h index 877ce049..c442a281 100644 --- a/rsync.h +++ b/rsync.h @@ -309,6 +309,16 @@ struct map_struct { OFF_T size, p_offset; }; +struct exclude_struct { + char *orig; + char *pattern; + int regular_exp; + int include; + int directory; + int local; +}; + + /* we need this function because of the silly way in which duplicate entries are handled in the file lists - we can't change this without breaking existing versions */ diff --git a/zlib/zutil.c b/zlib/zutil.c index 5a3fe6e0..bb2e3ea8 100644 --- a/zlib/zutil.c +++ b/zlib/zutil.c @@ -200,11 +200,6 @@ void zcfree (voidpf opaque, voidpf ptr) #ifndef MY_ZCALLOC /* Any system without a special alloc function */ -#ifndef STDC -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - voidpf zcalloc (opaque, items, size) voidpf opaque; unsigned items; -- 2.34.1