2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* a lot of this stuff was originally derived from GNU tar, although
21 it has now changed so much that it is hard to tell :) */
23 /* include/exclude cluestick added by Martin Pool <mbp@samba.org> */
28 extern int delete_mode
;
30 static struct exclude_struct
**exclude_list
;
32 /* build an exclude structure given a exclude pattern */
33 static struct exclude_struct
*make_exclude(char *pattern
, int include
)
35 struct exclude_struct
*ret
;
37 ret
= (struct exclude_struct
*)malloc(sizeof(*ret
));
38 if (!ret
) out_of_memory("make_exclude");
40 memset(ret
, 0, sizeof(*ret
));
42 if (strncmp(pattern
,"- ",2) == 0) {
44 } else if (strncmp(pattern
,"+ ",2) == 0) {
48 ret
->include
= include
;
51 ret
->pattern
= strdup(pattern
);
53 if (!ret
->pattern
) out_of_memory("make_exclude");
55 if (strpbrk(pattern
, "*[?")) {
57 ret
->fnmatch_flags
= FNM_PATHNAME
;
58 if (strstr(pattern
, "**")) {
62 if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME
)==0) {
63 rprintf(FERROR
,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
66 ret
->fnmatch_flags
= 0;
70 if (strlen(pattern
) > 1 && pattern
[strlen(pattern
)-1] == '/') {
71 ret
->pattern
[strlen(pattern
)-1] = 0;
75 if (!strchr(ret
->pattern
,'/')) {
82 static void free_exclude(struct exclude_struct
*ex
)
85 memset(ex
,0,sizeof(*ex
));
89 static int check_one_exclude(char *name
, struct exclude_struct
*ex
,
94 char *pattern
= ex
->pattern
;
96 if (ex
->local
&& (p
=strrchr(name
,'/')))
99 if (!name
[0]) return 0;
101 if (ex
->directory
&& !S_ISDIR(st
->st_mode
)) return 0;
103 if (*pattern
== '/' && *name
!= '/') {
108 if (ex
->regular_exp
) {
109 if (fnmatch(pattern
, name
, ex
->fnmatch_flags
) == 0) {
113 int l1
= strlen(name
);
114 int l2
= strlen(pattern
);
116 strcmp(name
+(l1
-l2
),pattern
) == 0 &&
117 (l1
==l2
|| (!match_start
&& name
[l1
-(l2
+1)] == '/'))) {
126 static void report_exclude_result(char const *name
,
127 struct exclude_struct
const *ent
,
128 STRUCT_STAT
const *st
)
130 /* If a trailing slash is present to match only directories,
131 * then it is stripped out by make_exclude. So as a special
132 * case we add it back in here. */
135 rprintf(FINFO
, "%s %s %s because of pattern %s%s\n",
136 ent
->include
? "including" : "excluding",
137 S_ISDIR(st
->st_mode
) ? "directory" : "file",
139 ent
->directory
? "/" : "");
144 * Return true if file NAME is defined to be excluded by either
145 * LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
147 int check_exclude(char *name
, struct exclude_struct
**local_exclude_list
,
151 struct exclude_struct
*ent
;
153 if (name
&& (name
[0] == '.') && !name
[1])
154 /* never exclude '.', even if somebody does --exclude '*' */
158 for (n
=0; exclude_list
[n
]; n
++) {
159 ent
= exclude_list
[n
];
160 if (check_one_exclude(name
, ent
, st
)) {
161 report_exclude_result(name
, ent
, st
);
162 return !ent
->include
;
167 if (local_exclude_list
) {
168 for (n
=0; local_exclude_list
[n
]; n
++) {
169 ent
= exclude_list
[n
];
170 if (check_one_exclude(name
, ent
, st
)) {
171 report_exclude_result(name
, ent
, st
);
172 return !ent
->include
;
181 void add_exclude_list(char *pattern
,struct exclude_struct
***list
, int include
)
185 for (; (*list
)[len
]; len
++) ;
187 if (strcmp(pattern
,"!") == 0) {
189 rprintf(FINFO
,"clearing exclude list\n");
191 free_exclude((*list
)[len
]);
198 *list
= (struct exclude_struct
**)Realloc(*list
,sizeof(struct exclude_struct
*)*(len
+2));
200 if (!*list
|| !((*list
)[len
] = make_exclude(pattern
, include
)))
201 out_of_memory("add_exclude");
204 rprintf(FINFO
,"add_exclude(%s)\n",pattern
);
206 (*list
)[len
+1] = NULL
;
209 void add_exclude(char *pattern
, int include
)
211 add_exclude_list(pattern
,&exclude_list
, include
);
214 struct exclude_struct
**make_exclude_list(char *fname
,
215 struct exclude_struct
**list1
,
216 int fatal
, int include
)
218 struct exclude_struct
**list
=list1
;
219 FILE *f
= fopen(fname
,"r");
220 char line
[MAXPATHLEN
];
223 rsyserr(FERROR
, errno
,
224 "failed to open %s file %s",
225 include
? "include" : "exclude",
227 exit_cleanup(RERR_FILEIO
);
232 while (fgets(line
,MAXPATHLEN
,f
)) {
233 int l
= strlen(line
);
234 if (l
&& line
[l
-1] == '\n') l
--;
236 if (line
[0] && (line
[0] != ';') && (line
[0] != '#')) {
237 /* Skip lines starting with semicolon or pound.
238 It probably wouldn't cause any harm to not skip
239 them but there's no need to save them. */
240 add_exclude_list(line
,&list
,include
);
248 void add_exclude_file(char *fname
,int fatal
,int include
)
250 if (!fname
|| !*fname
) return;
252 exclude_list
= make_exclude_list(fname
,exclude_list
,fatal
,include
);
256 void send_exclude_list(int f
)
259 extern int remote_version
;
260 extern int list_only
, recurse
;
262 /* this is a complete hack - blame Rusty */
263 if (list_only
&& !recurse
) {
264 add_exclude("/*/*", 0);
272 for (i
=0;exclude_list
[i
];i
++) {
274 char pattern
[MAXPATHLEN
];
276 strlcpy(pattern
,exclude_list
[i
]->pattern
,sizeof(pattern
));
277 if (exclude_list
[i
]->directory
) strlcat(pattern
,"/", sizeof(pattern
));
280 if (l
== 0) continue;
281 if (exclude_list
[i
]->include
) {
282 if (remote_version
< 19) {
283 rprintf(FERROR
,"remote rsync does not support include syntax - aborting\n");
284 exit_cleanup(RERR_UNSUPPORTED
);
291 write_buf(f
,pattern
,l
);
298 void recv_exclude_list(int f
)
300 char line
[MAXPATHLEN
];
302 while ((l
=read_int(f
))) {
303 if (l
>= MAXPATHLEN
) overflow("recv_exclude_list");
309 /* Get the next include/exclude arg from the string. It works in a similar way
310 ** to strtok - initially an arg is sent over, from then on NULL. This
311 ** routine takes into account any +/- in the strings and does not
312 ** consider the space following it as a delimeter.
314 char *get_exclude_tok(char *p
)
329 /* Skip over any initial spaces */
333 /* Are we at the end of the string? */
335 /* remember the beginning of the token */
338 /* Is this a '+' or '-' followed by a space (not whitespace)? */
339 if ((*s
=='+' || *s
=='-') && *(s
+1)==' ')
342 /* Skip to the next space or the end of the string */
343 while(!isspace(*s
) && *s
!='\0')
349 /* Have we reached the end of the string? */
358 void add_exclude_line(char *p
)
361 if (!p
|| !*p
) return;
363 if (!p
) out_of_memory("add_exclude_line");
364 for (tok
=get_exclude_tok(p
); tok
; tok
=get_exclude_tok(NULL
))
369 void add_include_line(char *p
)
372 if (!p
|| !*p
) return;
374 if (!p
) out_of_memory("add_include_line");
375 for (tok
=get_exclude_tok(p
); tok
; tok
=get_exclude_tok(NULL
))
381 static char *cvs_ignore_list
[] = {
382 "RCS","SCCS","CVS","CVS.adm","RCSLOG","cvslog.*",
383 "tags","TAGS",".make.state",".nse_depinfo",
384 "*~", "#*", ".#*", ",*", "*.old", "*.bak", "*.BAK", "*.orig",
385 "*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
390 void add_cvs_excludes(void)
392 char fname
[MAXPATHLEN
];
396 for (i
=0; cvs_ignore_list
[i
]; i
++)
397 add_exclude(cvs_ignore_list
[i
], 0);
399 if ((p
=getenv("HOME")) && strlen(p
) < (MAXPATHLEN
-12)) {
400 slprintf(fname
,sizeof(fname
), "%s/.cvsignore",p
);
401 add_exclude_file(fname
,0,0);
404 add_exclude_line(getenv("CVSIGNORE"));