1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) 1996 by Paul Mackerras
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* a lot of this stuff was originally derived from GNU tar, although
22 it has now changed so much that it is hard to tell :) */
24 /* include/exclude cluestick added by Martin Pool <mbp@samba.org> */
29 extern int delete_mode
;
31 static struct exclude_struct
**exclude_list
;
33 /* build an exclude structure given a exclude pattern */
34 static struct exclude_struct
*make_exclude(const char *pattern
, int include
)
36 struct exclude_struct
*ret
;
38 ret
= (struct exclude_struct
*)malloc(sizeof(*ret
));
39 if (!ret
) out_of_memory("make_exclude");
41 memset(ret
, 0, sizeof(*ret
));
43 if (strncmp(pattern
,"- ",2) == 0) {
45 } else if (strncmp(pattern
,"+ ",2) == 0) {
49 ret
->include
= include
;
52 ret
->pattern
= strdup(pattern
);
54 if (!ret
->pattern
) out_of_memory("make_exclude");
56 if (strpbrk(pattern
, "*[?")) {
58 ret
->fnmatch_flags
= FNM_PATHNAME
;
59 if (strstr(pattern
, "**")) {
63 if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME
)==0) {
64 rprintf(FERROR
,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
67 ret
->fnmatch_flags
= 0;
71 if (strlen(pattern
) > 1 && pattern
[strlen(pattern
)-1] == '/') {
72 ret
->pattern
[strlen(pattern
)-1] = 0;
76 if (!strchr(ret
->pattern
,'/')) {
83 static void free_exclude(struct exclude_struct
*ex
)
86 memset(ex
,0,sizeof(*ex
));
90 static int check_one_exclude(char *name
, struct exclude_struct
*ex
,
95 char *pattern
= ex
->pattern
;
97 if (ex
->local
&& (p
=strrchr(name
,'/')))
100 if (!name
[0]) return 0;
102 if (ex
->directory
&& !S_ISDIR(st
->st_mode
)) return 0;
104 if (*pattern
== '/' && *name
!= '/') {
109 if (ex
->regular_exp
) {
110 if (fnmatch(pattern
, name
, ex
->fnmatch_flags
) == 0) {
114 int l1
= strlen(name
);
115 int l2
= strlen(pattern
);
117 strcmp(name
+(l1
-l2
),pattern
) == 0 &&
118 (l1
==l2
|| (!match_start
&& name
[l1
-(l2
+1)] == '/'))) {
127 static void report_exclude_result(char const *name
,
128 struct exclude_struct
const *ent
,
129 STRUCT_STAT
const *st
)
131 /* If a trailing slash is present to match only directories,
132 * then it is stripped out by make_exclude. So as a special
133 * case we add it back in here. */
136 rprintf(FINFO
, "%s %s %s because of pattern %s%s\n",
137 ent
->include
? "including" : "excluding",
138 S_ISDIR(st
->st_mode
) ? "directory" : "file",
140 ent
->directory
? "/" : "");
145 * Return true if file NAME is defined to be excluded by either
146 * LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
148 int check_exclude(char *name
, struct exclude_struct
**local_exclude_list
,
152 struct exclude_struct
*ent
;
154 if (name
&& (name
[0] == '.') && !name
[1])
155 /* never exclude '.', even if somebody does --exclude '*' */
159 for (n
=0; exclude_list
[n
]; n
++) {
160 ent
= exclude_list
[n
];
161 if (check_one_exclude(name
, ent
, st
)) {
162 report_exclude_result(name
, ent
, st
);
163 return !ent
->include
;
168 if (local_exclude_list
) {
169 for (n
=0; local_exclude_list
[n
]; n
++) {
170 ent
= local_exclude_list
[n
];
171 if (check_one_exclude(name
, ent
, st
)) {
172 report_exclude_result(name
, ent
, st
);
173 return !ent
->include
;
182 void add_exclude_list(const char *pattern
, struct exclude_struct
***list
, int include
)
186 for (; (*list
)[len
]; len
++) ;
188 if (strcmp(pattern
,"!") == 0) {
190 rprintf(FINFO
,"clearing exclude list\n");
192 free_exclude((*list
)[len
]);
199 *list
= (struct exclude_struct
**)Realloc(*list
,sizeof(struct exclude_struct
*)*(len
+2));
201 if (!*list
|| !((*list
)[len
] = make_exclude(pattern
, include
)))
202 out_of_memory("add_exclude");
205 rprintf(FINFO
,"add_exclude(%s)\n",pattern
);
207 (*list
)[len
+1] = NULL
;
210 void add_exclude(const char *pattern
, int include
)
212 add_exclude_list(pattern
,&exclude_list
, include
);
215 struct exclude_struct
**make_exclude_list(const char *fname
,
216 struct exclude_struct
**list1
,
217 int fatal
, int include
)
219 struct exclude_struct
**list
=list1
;
220 FILE *f
= fopen(fname
,"r");
221 char line
[MAXPATHLEN
];
224 rsyserr(FERROR
, errno
,
225 "failed to open %s file %s",
226 include
? "include" : "exclude",
228 exit_cleanup(RERR_FILEIO
);
233 while (fgets(line
,MAXPATHLEN
,f
)) {
234 int l
= strlen(line
);
235 if (l
&& line
[l
-1] == '\n') l
--;
237 if (line
[0] && (line
[0] != ';') && (line
[0] != '#')) {
238 /* Skip lines starting with semicolon or pound.
239 It probably wouldn't cause any harm to not skip
240 them but there's no need to save them. */
241 add_exclude_list(line
,&list
,include
);
249 void add_exclude_file(const char *fname
, int fatal
, int include
)
251 if (!fname
|| !*fname
) return;
253 exclude_list
= make_exclude_list(fname
,exclude_list
,fatal
,include
);
257 void send_exclude_list(int f
)
260 extern int remote_version
;
261 extern int list_only
, recurse
;
263 /* this is a complete hack - blame Rusty */
264 if (list_only
&& !recurse
) {
265 add_exclude("/*/*", 0);
273 for (i
=0;exclude_list
[i
];i
++) {
275 char pattern
[MAXPATHLEN
];
277 strlcpy(pattern
,exclude_list
[i
]->pattern
,sizeof(pattern
));
278 if (exclude_list
[i
]->directory
) strlcat(pattern
,"/", sizeof(pattern
));
281 if (l
== 0) continue;
282 if (exclude_list
[i
]->include
) {
283 if (remote_version
< 19) {
284 rprintf(FERROR
,"remote rsync does not support include syntax - aborting\n");
285 exit_cleanup(RERR_UNSUPPORTED
);
292 write_buf(f
,pattern
,l
);
299 void recv_exclude_list(int f
)
301 char line
[MAXPATHLEN
];
303 while ((l
=read_int(f
))) {
304 if (l
>= MAXPATHLEN
) overflow("recv_exclude_list");
310 /* Get the next include/exclude arg from the string. It works in a similar way
311 ** to strtok - initially an arg is sent over, from then on NULL. This
312 ** routine takes into account any +/- in the strings and does not
313 ** consider the space following it as a delimeter.
315 char *get_exclude_tok(char *p
)
330 /* Skip over any initial spaces */
334 /* Are we at the end of the string? */
336 /* remember the beginning of the token */
339 /* Is this a '+' or '-' followed by a space (not whitespace)? */
340 if ((*s
=='+' || *s
=='-') && *(s
+1)==' ')
343 /* Skip to the next space or the end of the string */
344 while(!isspace(*s
) && *s
!='\0')
350 /* Have we reached the end of the string? */
359 void add_exclude_line(char *p
)
362 if (!p
|| !*p
) return;
364 if (!p
) out_of_memory("add_exclude_line");
365 for (tok
=get_exclude_tok(p
); tok
; tok
=get_exclude_tok(NULL
))
370 void add_include_line(char *p
)
373 if (!p
|| !*p
) return;
375 if (!p
) out_of_memory("add_include_line");
376 for (tok
=get_exclude_tok(p
); tok
; tok
=get_exclude_tok(NULL
))
382 static char *cvs_ignore_list
[] = {
383 "RCS","SCCS","CVS","CVS.adm","RCSLOG","cvslog.*",
384 "tags","TAGS",".make.state",".nse_depinfo",
385 "*~", "#*", ".#*", ",*", "*.old", "*.bak", "*.BAK", "*.orig",
386 "*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
391 void add_cvs_excludes(void)
393 char fname
[MAXPATHLEN
];
397 for (i
=0; cvs_ignore_list
[i
]; i
++)
398 add_exclude(cvs_ignore_list
[i
], 0);
400 if ((p
=getenv("HOME")) && strlen(p
) < (MAXPATHLEN
-12)) {
401 snprintf(fname
,sizeof(fname
), "%s/.cvsignore",p
);
402 add_exclude_file(fname
,0,0);
405 add_exclude_line(getenv("CVSIGNORE"));