00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "rsync.h"
00028
00029 extern int verbose;
00030 extern int delete_mode;
00031
00032 static struct exclude_struct **exclude_list;
00033
00034
00035 static struct exclude_struct *make_exclude(const char *pattern, int include)
00036 {
00037 struct exclude_struct *ret;
00038
00039 ret = (struct exclude_struct *)malloc(sizeof(*ret));
00040 if (!ret) out_of_memory("make_exclude");
00041
00042 memset(ret, 0, sizeof(*ret));
00043
00044 if (strncmp(pattern,"- ",2) == 0) {
00045 pattern += 2;
00046 } else if (strncmp(pattern,"+ ",2) == 0) {
00047 ret->include = 1;
00048 pattern += 2;
00049 } else {
00050 ret->include = include;
00051 }
00052
00053 ret->pattern = strdup(pattern);
00054
00055 if (!ret->pattern) out_of_memory("make_exclude");
00056
00057 if (strpbrk(pattern, "*[?")) {
00058 ret->regular_exp = 1;
00059 ret->fnmatch_flags = FNM_PATHNAME;
00060 if (strstr(pattern, "**")) {
00061 static int tested;
00062 if (!tested) {
00063 tested = 1;
00064 if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME)==0) {
00065 rprintf(FERROR,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
00066 }
00067 }
00068 ret->fnmatch_flags = 0;
00069 }
00070 }
00071
00072 if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
00073 ret->pattern[strlen(pattern)-1] = 0;
00074 ret->directory = 1;
00075 }
00076
00077 if (!strchr(ret->pattern,'/')) {
00078 ret->local = 1;
00079 }
00080
00081 return ret;
00082 }
00083
00084 static void free_exclude(struct exclude_struct *ex)
00085 {
00086 free(ex->pattern);
00087 memset(ex,0,sizeof(*ex));
00088 free(ex);
00089 }
00090
00091 static int check_one_exclude(char *name, struct exclude_struct *ex,
00092 STRUCT_STAT *st)
00093 {
00094 char *p;
00095 int match_start=0;
00096 char *pattern = ex->pattern;
00097
00098 if (ex->local && (p=strrchr(name,'/')))
00099 name = p+1;
00100
00101 if (!name[0]) return 0;
00102
00103 if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
00104
00105 if (*pattern == '/' && *name != '/') {
00106 match_start = 1;
00107 pattern++;
00108 }
00109
00110 if (ex->regular_exp) {
00111 if (fnmatch(pattern, name, ex->fnmatch_flags) == 0) {
00112 return 1;
00113 }
00114 } else {
00115 int l1 = strlen(name);
00116 int l2 = strlen(pattern);
00117 if (l2 <= l1 &&
00118 strcmp(name+(l1-l2),pattern) == 0 &&
00119 (l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
00120 return 1;
00121 }
00122 }
00123
00124 return 0;
00125 }
00126
00127
00128 static void report_exclude_result(char const *name,
00129 struct exclude_struct const *ent,
00130 STRUCT_STAT const *st)
00131 {
00132
00133
00134
00135
00136 if (verbose >= 2)
00137 rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
00138 ent->include ? "including" : "excluding",
00139 S_ISDIR(st->st_mode) ? "directory" : "file",
00140 name, ent->pattern,
00141 ent->directory ? "/" : "");
00142 }
00143
00144
00145
00146
00147
00148
00149 int check_exclude(char *name, struct exclude_struct **local_exclude_list,
00150 STRUCT_STAT *st)
00151 {
00152 int n;
00153 struct exclude_struct *ent;
00154
00155 if (name && (name[0] == '.') && !name[1])
00156
00157 return 0;
00158
00159 if (exclude_list) {
00160 for (n=0; exclude_list[n]; n++) {
00161 ent = exclude_list[n];
00162 if (check_one_exclude(name, ent, st)) {
00163 report_exclude_result(name, ent, st);
00164 return !ent->include;
00165 }
00166 }
00167 }
00168
00169 if (local_exclude_list) {
00170 for (n=0; local_exclude_list[n]; n++) {
00171 ent = local_exclude_list[n];
00172 if (check_one_exclude(name, ent, st)) {
00173 report_exclude_result(name, ent, st);
00174 return !ent->include;
00175 }
00176 }
00177 }
00178
00179 return 0;
00180 }
00181
00182
00183 void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include)
00184 {
00185 int len=0;
00186 if (list && *list)
00187 for (; (*list)[len]; len++) ;
00188
00189 if (strcmp(pattern,"!") == 0) {
00190 if (verbose > 2)
00191 rprintf(FINFO,"clearing exclude list\n");
00192 while ((len)--) {
00193 free_exclude((*list)[len]);
00194 }
00195 free((*list));
00196 *list = NULL;
00197 return;
00198 }
00199
00200 *list = (struct exclude_struct **)Realloc(*list,sizeof(struct exclude_struct *)*(len+2));
00201
00202 if (!*list || !((*list)[len] = make_exclude(pattern, include)))
00203 out_of_memory("add_exclude");
00204
00205 if (verbose > 2) {
00206 rprintf(FINFO,"add_exclude(%s,%s)\n",pattern,
00207 include ? "include" : "exclude");
00208 }
00209
00210 (*list)[len+1] = NULL;
00211 }
00212
00213 void add_exclude(const char *pattern, int include)
00214 {
00215 add_exclude_list(pattern,&exclude_list, include);
00216 }
00217
00218 struct exclude_struct **make_exclude_list(const char *fname,
00219 struct exclude_struct **list1,
00220 int fatal, int include)
00221 {
00222 struct exclude_struct **list=list1;
00223 FILE *f = fopen(fname,"r");
00224 char line[MAXPATHLEN];
00225 if (!f) {
00226 if (fatal) {
00227 rsyserr(FERROR, errno,
00228 "failed to open %s file %s",
00229 include ? "include" : "exclude",
00230 fname);
00231 exit_cleanup(RERR_FILEIO);
00232 }
00233 return list;
00234 }
00235
00236 while (fgets(line,MAXPATHLEN,f)) {
00237 int l = strlen(line);
00238 if (l && line[l-1] == '\n') l--;
00239 line[l] = 0;
00240 if (line[0] && (line[0] != ';') && (line[0] != '#')) {
00241
00242
00243
00244 add_exclude_list(line,&list,include);
00245 }
00246 }
00247 fclose(f);
00248 return list;
00249 }
00250
00251
00252 void add_exclude_file(const char *fname, int fatal, int include)
00253 {
00254 if (!fname || !*fname) return;
00255
00256 exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
00257 }
00258
00259
00260 void send_exclude_list(int f)
00261 {
00262 int i;
00263 extern int remote_version;
00264 extern int list_only, recurse;
00265
00266
00267
00268
00269
00270 if (list_only && !recurse) {
00271 add_exclude("/*/*", 0);
00272 }
00273
00274 if (!exclude_list) {
00275 write_int(f,0);
00276 return;
00277 }
00278
00279 for (i=0;exclude_list[i];i++) {
00280 int l;
00281 char pattern[MAXPATHLEN];
00282
00283 strlcpy(pattern,exclude_list[i]->pattern,sizeof(pattern));
00284 if (exclude_list[i]->directory) strlcat(pattern,"/", sizeof(pattern));
00285
00286 l = strlen(pattern);
00287 if (l == 0) continue;
00288 if (exclude_list[i]->include) {
00289 if (remote_version < 19) {
00290 rprintf(FERROR,"remote rsync does not support include syntax - aborting\n");
00291 exit_cleanup(RERR_UNSUPPORTED);
00292 }
00293 write_int(f,l+2);
00294 write_buf(f,"+ ",2);
00295 } else {
00296 write_int(f,l);
00297 }
00298 write_buf(f,pattern,l);
00299 }
00300
00301 write_int(f,0);
00302 }
00303
00304
00305 void recv_exclude_list(int f)
00306 {
00307 char line[MAXPATHLEN];
00308 unsigned int l;
00309
00310 while ((l=read_int(f))) {
00311 if (l >= MAXPATHLEN) overflow("recv_exclude_list");
00312 read_sbuf(f,line,l);
00313 add_exclude(line,0);
00314 }
00315 }
00316
00317
00318
00319
00320
00321
00322 char *get_exclude_tok(char *p)
00323 {
00324 static char *s;
00325 static int more;
00326 char *t;
00327
00328 if (p) {
00329 s=p;
00330 if (*p)
00331 more=1;
00332 }
00333
00334 if (!more)
00335 return(NULL);
00336
00337
00338 while (isspace(* (unsigned char *) s))
00339 s++;
00340
00341
00342 if (*s) {
00343
00344 t=s;
00345
00346
00347 if ((*s=='+' || *s=='-') && *(s+1)==' ')
00348 s+=2;
00349
00350
00351 while (!isspace(* (unsigned char *) s) && *s != '\0')
00352 s++;
00353 } else {
00354 t=NULL;
00355 }
00356
00357
00358 if (*s)
00359 *s++='\0';
00360 else
00361 more=0;
00362 return(t);
00363 }
00364
00365
00366 void add_exclude_line(char *p)
00367 {
00368 char *tok;
00369 if (!p || !*p) return;
00370 p = strdup(p);
00371 if (!p) out_of_memory("add_exclude_line");
00372 for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
00373 add_exclude(tok, 0);
00374 free(p);
00375 }
00376
00377 void add_include_line(char *p)
00378 {
00379 char *tok;
00380 if (!p || !*p) return;
00381 p = strdup(p);
00382 if (!p) out_of_memory("add_include_line");
00383 for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
00384 add_exclude(tok, 1);
00385 free(p);
00386 }
00387
00388
00389 static char *cvs_ignore_list[] = {
00390 "RCS","SCCS","CVS","CVS.adm","RCSLOG","cvslog.*",
00391 "tags","TAGS",".make.state",".nse_depinfo",
00392 "*~", "#*", ".#*", ",*", "*.old", "*.bak", "*.BAK", "*.orig",
00393 "*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
00394 "core",NULL};
00395
00396
00397
00398 void add_cvs_excludes(void)
00399 {
00400 char fname[MAXPATHLEN];
00401 char *p;
00402 int i;
00403
00404 for (i=0; cvs_ignore_list[i]; i++)
00405 add_exclude(cvs_ignore_list[i], 0);
00406
00407 if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
00408 snprintf(fname,sizeof(fname), "%s/.cvsignore",p);
00409 add_exclude_file(fname,0,0);
00410 }
00411
00412 add_exclude_line(getenv("CVSIGNORE"));
00413 }