--- backup.c	9 May 2002 21:44:46 -0000	1.10
+++ backup.c	1 Jul 2003 21:43:09 -0000
@@ -198,7 +198,7 @@
 	if (do_stat (fname, &st)) return 1;
 #endif
 
-	file = make_file(-1, fname, NULL, 1);
+	file = make_file(fname, NULL, NO_EXCLUDES);
 
 	/* the file could have disappeared */
 	if (!file) return 1;
--- clientserver.c	10 May 2003 08:33:08 -0000	1.106
+++ clientserver.c	1 Jul 2003 21:43:10 -0000
@@ -34,6 +34,8 @@
 char *auth_user;
 extern int sanitize_paths;
 extern int filesfrom_fd;
+extern struct exclude_struct **server_exclude_list;
+extern char *exclude_path_prefix;
 
 /**
  * Run a client connected to an rsyncd.  The alternative to this
@@ -78,8 +80,8 @@
 		rprintf(FINFO, "opening tcp connection to %s port %d\n",
 			host, rsync_port);
 	}
-	fd = open_socket_out_wrapped (host, rsync_port, bind_address,
-						default_af_hint);
+	fd = open_socket_out_wrapped(host, rsync_port, bind_address,
+				     default_af_hint);
 	if (fd == -1) {
 		exit_cleanup(RERR_SOCKETIO);
 	}
@@ -240,7 +242,8 @@
 		} else {
 			rprintf(FERROR,"max connections (%d) reached\n",
 				lp_max_connections(i));
-			io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i));
+			io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n",
+				lp_max_connections(i));
 		}
 		return -1;
 	}
@@ -288,17 +291,21 @@
 	/* TODO: Perhaps take a list of gids, and make them into the
 	 * supplementary groups. */
 
+	exclude_path_prefix = use_chroot? "" : lp_path(i);
+
 	p = lp_include_from(i);
-	add_exclude_file(p, 1, 1);
+	add_exclude_file(&server_exclude_list, p, MISSING_FATAL, ADD_INCLUDE);
 
 	p = lp_include(i);
-	add_include_line(p);
+	add_exclude_line(&server_exclude_list, p, ADD_INCLUDE);
 
 	p = lp_exclude_from(i);
-	add_exclude_file(p, 1, 0);
+	add_exclude_file(&server_exclude_list, p, MISSING_FATAL, ADD_EXCLUDE);
 
 	p = lp_exclude(i);
-	add_exclude_line(p);
+	add_exclude_line(&server_exclude_list, p, ADD_EXCLUDE);
+
+	exclude_path_prefix = NULL;
 
 	log_init();
 
--- exclude.c	1 May 2003 19:33:54 -0000	1.51
+++ exclude.c	1 Jul 2003 21:43:10 -0000
@@ -27,15 +27,18 @@
 #include "rsync.h"
 
 extern int verbose;
-extern int delete_mode;
 
-static struct exclude_struct **exclude_list;
+struct exclude_struct **exclude_list;
+struct exclude_struct **local_exclude_list;
+struct exclude_struct **server_exclude_list;
+char *exclude_path_prefix = NULL;
 
 /** Build an exclude structure given a exclude pattern */
 static struct exclude_struct *make_exclude(const char *pattern, int include)
 {
 	struct exclude_struct *ret;
 	char *cp;
+	int pat_len;
 
 	ret = (struct exclude_struct *)malloc(sizeof(*ret));
 	if (!ret) out_of_memory("make_exclude");
@@ -51,9 +54,18 @@
 		ret->include = include;
 	}
 
-	ret->pattern = strdup(pattern);
-
-	if (!ret->pattern) out_of_memory("make_exclude");
+	if (exclude_path_prefix)
+		ret->match_flags |= MATCHFLG_ABS_PATH;
+	if (exclude_path_prefix && *pattern == '/') {
+		ret->pattern = malloc(strlen(exclude_path_prefix)
+				+ strlen(pattern) + 1);
+		if (!ret->pattern) out_of_memory("make_exclude");
+		sprintf(ret->pattern, "%s%s", exclude_path_prefix, pattern);
+	}
+	else {
+		ret->pattern = strdup(pattern);
+		if (!ret->pattern) out_of_memory("make_exclude");
+	}
 
 	if (strpbrk(pattern, "*[?")) {
 		ret->match_flags |= MATCHFLG_WILD;
@@ -71,8 +83,9 @@
 		}
 	}
 
-	if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
-		ret->pattern[strlen(pattern)-1] = 0;
+	pat_len = strlen(ret->pattern);
+	if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
+		ret->pattern[pat_len-1] = 0;
 		ret->directory = 1;
 	}
 
@@ -89,8 +102,26 @@
 	free(ex);
 }
 
+
+void free_exclude_list(struct exclude_struct ***listp)
+{
+	struct exclude_struct **list = *listp;
+
+	if (verbose > 2)
+		rprintf(FINFO,"clearing exclude list\n");
+
+	if (!list)
+		return;
+
+	while (*list)
+		free_exclude(*list++);
+
+	free(*listp);
+	*listp = NULL;
+}
+
 static int check_one_exclude(char *name, struct exclude_struct *ex,
-                             STRUCT_STAT *st)
+                             int name_is_dir)
 {
 	char *p;
 	int match_start = 0;
@@ -99,13 +130,22 @@
 	/* If the pattern does not have any slashes AND it does not have
 	 * a "**" (which could match a slash), then we just match the
 	 * name portion of the path. */
-	if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2) &&
-	    (p = strrchr(name,'/')) != NULL)
-		name = p+1;
+	if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
+		if ((p = strrchr(name,'/')) != NULL)
+			name = p+1;
+	}
+	else if ((ex->match_flags & MATCHFLG_ABS_PATH) && *name != '/') {
+		static char full_name[MAXPATHLEN];
+		extern char curr_dir[];
+		int plus = curr_dir[1] == '\0'? 1 : 0;
+		snprintf(full_name, sizeof full_name,
+			 "%s/%s", curr_dir+plus, name);
+		name = full_name;
+	}
 
 	if (!name[0]) return 0;
 
-	if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
+	if (ex->directory && !name_is_dir) return 0;
 
 	if (*pattern == '/') {
 		match_start = 1;
@@ -167,7 +207,7 @@
 
 static void report_exclude_result(char const *name,
                                   struct exclude_struct const *ent,
-                                  STRUCT_STAT const *st)
+                                  int name_is_dir)
 {
 	/* If a trailing slash is present to match only directories,
 	 * then it is stripped out by make_exclude.  So as a special
@@ -176,7 +216,7 @@
 	if (verbose >= 2)
 		rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
 			ent->include ? "including" : "excluding",
-			S_ISDIR(st->st_mode) ? "directory" : "file",
+			name_is_dir ? "directory" : "file",
 			name, ent->pattern,
 			ent->directory ? "/" : "");
 }
@@ -186,33 +226,14 @@
  * Return true if file NAME is defined to be excluded by either
  * LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
  */
-int check_exclude(char *name, struct exclude_struct **local_exclude_list,
-		  STRUCT_STAT *st)
+int check_exclude(struct exclude_struct **list, char *name, int name_is_dir)
 {
-	int n;
 	struct exclude_struct *ent;
 
-	if (name && (name[0] == '.') && !name[1])
-		/* never exclude '.', even if somebody does --exclude '*' */
-		return 0;
-
-	if (exclude_list) {
-		for (n=0; exclude_list[n]; n++) {
-			ent = exclude_list[n];
-			if (check_one_exclude(name, ent, st)) {
-				report_exclude_result(name, ent, st);
-				return !ent->include;
-			}
-		}
-	}
-
-	if (local_exclude_list) {
-		for (n=0; local_exclude_list[n]; n++) {
-			ent = local_exclude_list[n];
-			if (check_one_exclude(name, ent, st)) {
-				report_exclude_result(name, ent, st);
-				return !ent->include;
-			}
+	while ((ent = *list++) != NULL) {
+		if (check_one_exclude(name, ent, name_is_dir)) {
+			report_exclude_result(name, ent, name_is_dir);
+			return !ent->include;
 		}
 	}
 
@@ -220,26 +241,22 @@
 }
 
 
-void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include)
+void add_exclude(struct exclude_struct ***listp, const char *pattern, 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_exclude((*list)[len]);
-		}
-		free((*list));
-		*list = NULL;
-		return;
+	struct exclude_struct **list = *listp;
+	int len = 0;
+
+	if (*pattern == '!' && !pattern[1]) {
+	    free_exclude_list(listp);
+	    return;
 	}
 
-	*list = (struct exclude_struct **)Realloc(*list,sizeof(struct exclude_struct *)*(len+2));
+	if (list)
+		for (; list[len]; len++) {}
+
+	list = *listp = (struct exclude_struct **)Realloc(list,sizeof(struct exclude_struct *)*(len+2));
 
-	if (!*list || !((*list)[len] = make_exclude(pattern, include)))
+	if (!list || !(list[len] = make_exclude(pattern, include)))
 		out_of_memory("add_exclude");
 
 	if (verbose > 2) {
@@ -247,25 +264,22 @@
 			include ? "include" : "exclude");
 	}
 
-	(*list)[len+1] = NULL;
+	list[len+1] = NULL;
 }
 
-void add_exclude(const char *pattern, int include)
-{
-	add_exclude_list(pattern,&exclude_list, include);
-}
 
-struct exclude_struct **make_exclude_list(const char *fname,
-					  struct exclude_struct **list1,
-					  int fatal, int include)
+void add_exclude_file(struct exclude_struct ***listp, const char *fname,
+		      int fatal, int include)
 {
-	struct exclude_struct **list=list1;
 	int fd;
 	char line[MAXPATHLEN];
 	char *eob = line + MAXPATHLEN - 1;
 	extern int eol_nulls;
 
-	if (strcmp(fname, "-") != 0)
+	if (!fname || !*fname)
+		return;
+
+	if (*fname != '-' || fname[1])
 		fd = open(fname, O_RDONLY|O_BINARY);
 	else
 		fd = 0;
@@ -277,7 +291,7 @@
 				fname);
 			exit_cleanup(RERR_FILEIO);
 		}
-		return list;
+		return;
 	}
 
 	while (1) {
@@ -299,21 +313,12 @@
 			/* Skip lines starting with semicolon or pound.
 			 * It probably wouldn't cause any harm to not skip
 			 * them but there's no need to save them. */
-			add_exclude_list(line,&list,include);
+			add_exclude(listp, line, include);
 		}
 		if (cnt <= 0)
 			break;
 	}
 	close(fd);
-	return list;
-}
-
-
-void add_exclude_file(const char *fname, int fatal, int include)
-{
-	if (!fname || !*fname) return;
-
-	exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
 }
 
 
@@ -327,9 +332,8 @@
 	 *
 	 * FIXME: This pattern shows up in the output of
 	 * report_exclude_result(), which is not ideal. */
-	if (list_only && !recurse) {
-		add_exclude("/*/*", 0);
-	}
+	if (list_only && !recurse)
+		add_exclude(&exclude_list, "/*/*", ADD_EXCLUDE);
 
 	if (!exclude_list) {
 		write_int(f,0);
@@ -370,7 +374,7 @@
 	while ((l=read_int(f))) {
 		if (l >= MAXPATHLEN) overflow("recv_exclude_list");
 		read_sbuf(f,line,l);
-		add_exclude(line,0);
+		add_exclude(&exclude_list, line, ADD_EXCLUDE);
 	}
 }
 
@@ -423,25 +427,15 @@
 }
 
 
-void add_exclude_line(char *p)
+void add_exclude_line(struct exclude_struct ***listp,
+		      const char *line, int include)
 {
-	char *tok;
-	if (!p || !*p) return;
-	p = strdup(p);
+	char *tok, *p;
+	if (!line || !*line) return;
+	p = strdup(line);
 	if (!p) out_of_memory("add_exclude_line");
 	for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
-		add_exclude(tok, 0);
-	free(p);
-}
-
-void add_include_line(char *p)
-{
-	char *tok;
-	if (!p || !*p) return;
-	p = strdup(p);
-	if (!p) out_of_memory("add_include_line");
-	for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
-		add_exclude(tok, 1);
+		add_exclude(listp, tok, include);
 	free(p);
 }
 
@@ -461,12 +455,12 @@
 	int i;
 
 	for (i=0; cvs_ignore_list[i]; i++)
-		add_exclude(cvs_ignore_list[i], 0);
+		add_exclude(&exclude_list, cvs_ignore_list[i], ADD_EXCLUDE);
 
 	if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
 		snprintf(fname,sizeof(fname), "%s/.cvsignore",p);
-		add_exclude_file(fname,0,0);
+		add_exclude_file(&exclude_list,fname,MISSING_OK,ADD_EXCLUDE);
 	}
 
-	add_exclude_line(getenv("CVSIGNORE"));
+	add_exclude_line(&exclude_list, getenv("CVSIGNORE"), ADD_EXCLUDE);
 }
--- flist.c	10 May 2003 00:56:08 -0000	1.136
+++ flist.c	1 Jul 2003 21:43:11 -0000
@@ -64,7 +64,9 @@
 extern int read_batch;
 extern int write_batch;
 
-static struct exclude_struct **local_exclude_list;
+extern struct exclude_struct **exclude_list;
+extern struct exclude_struct **server_exclude_list;
+extern struct exclude_struct **local_exclude_list;
 
 static struct file_struct null_file;
 
@@ -250,20 +252,30 @@
 }
 
 /*
-  This function is used to check if a file should be included/excluded
-  from the list of files based on its name and type etc
+ * This function is used to check if a file should be included/excluded
+ * from the list of files based on its name and type etc.  The value of
+ * exclude_level is set to either SERVER_EXCLUDES or ALL_EXCLUDES.
  */
-static int check_exclude_file(int f, char *fname, STRUCT_STAT * st)
+static int check_exclude_file(char *fname, int is_dir, int exclude_level)
 {
-	extern int delete_excluded;
-
-	/* f is set to -1 when calculating deletion file list */
-	if ((f == -1) && delete_excluded) {
+#if 0 // This currently never happens, so avoid a useless compare.
+	if (exclude_level == NO_EXCLUDES)
+		return 0;
+#endif
+	if (fname && fname[0] == '.' && !fname[1]) {
+		/* never exclude '.', even if somebody does --exclude '*' */
 		return 0;
 	}
-	if (check_exclude(fname, local_exclude_list, st)) {
+	if (server_exclude_list &&
+	    check_exclude(server_exclude_list, fname, is_dir))
+		return 1;
+	if (exclude_level != ALL_EXCLUDES)
+		return 0;
+	if (exclude_list && check_exclude(exclude_list, fname, is_dir))
+		return 1;
+	if (local_exclude_list &&
+	    check_exclude(local_exclude_list, fname, is_dir))
 		return 1;
-	}
 	return 0;
 }
 
@@ -641,8 +653,8 @@
  * statting directories if we're not recursing, but this is not a very
  * important case.  Some systems may not have d_type.
  **/
-struct file_struct *make_file(int f, char *fname, struct string_area **ap,
-			      int noexcludes)
+struct file_struct *make_file(char *fname, struct string_area **ap,
+			      int exclude_level)
 {
 	struct file_struct *file;
 	STRUCT_STAT st;
@@ -664,12 +676,11 @@
 
 	if (readlink_stat(fname, &st, linkbuf) != 0) {
 		int save_errno = errno;
-		if ((errno == ENOENT) && !noexcludes) {
+		if (errno == ENOENT && exclude_level != NO_EXCLUDES) {
 			/* either symlink pointing nowhere or file that
 			 * was removed during rsync run; see if excluded
 			 * before reporting an error */
-			memset((char *) &st, 0, sizeof(st));
-			if (check_exclude_file(f, fname, &st)) {
+			if (check_exclude_file(fname, 0, exclude_level)) {
 				/* file is excluded anyway, ignore silently */
 				return NULL;
 			}
@@ -680,8 +691,8 @@
 		return NULL;
 	}
 
-	/* we use noexcludes from backup.c */
-	if (noexcludes)
+	/* backup.c calls us with exclude_level set to NO_EXCLUDES. */
+	if (exclude_level == NO_EXCLUDES)
 		goto skip_excludes;
 
 	if (S_ISDIR(st.st_mode) && !recurse && !files_from) {
@@ -694,17 +705,16 @@
 			return NULL;
 	}
 
-	if (check_exclude_file(f, fname, &st))
+	if (check_exclude_file(fname, S_ISDIR(st.st_mode) != 0, exclude_level))
 		return NULL;
 
-
 	if (lp_ignore_nonreadable(module_id) && access(fname, R_OK) != 0)
 		return NULL;
 
       skip_excludes:
 
 	if (verbose > 2)
-		rprintf(FINFO, "make_file(%d,%s)\n", f, fname);
+		rprintf(FINFO, "make_file(%s,*,%d)\n", fname, exclude_level);
 
 	file = (struct file_struct *) malloc(sizeof(*file));
 	if (!file)
@@ -782,8 +792,12 @@
 		    int recursive, unsigned base_flags)
 {
 	struct file_struct *file;
+	extern int delete_excluded;
 
-	file = make_file(f, fname, &flist->string_area, 0);
+	/* f is set to -1 when calculating deletion file list */
+	file = make_file(fname, &flist->string_area,
+			 f == -1 && delete_excluded? SERVER_EXCLUDES
+						   : ALL_EXCLUDES);
 
 	if (!file)
 		return;
@@ -847,8 +861,7 @@
 	if (cvs_exclude) {
 		if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN - 1) {
 			strcpy(p, ".cvsignore");
-			local_exclude_list =
-			    make_exclude_list(fname, NULL, 0, 0);
+			add_exclude_file(&exclude_list,fname,MISSING_OK,ADD_EXCLUDE);
 		} else {
 			io_error = 1;
 			rprintf(FINFO,
@@ -866,18 +879,18 @@
 		send_file_name(f, flist, fname, recurse, 0);
 	}
 
-	if (local_exclude_list) {
-		add_exclude_list("!", &local_exclude_list, 0);
-	}
+	if (local_exclude_list)
+		free_exclude_list(&local_exclude_list); /* Zeros pointer too */
 
 	closedir(d);
 }
 
 
 /**
- *
- * I <b>think</b> f==-1 means that the list should just be built in
- * memory and not transmitted.  But who can tell? -- mbp
+ * The delete_files() function in receiver.c sets f to -1 so that we just
+ * construct the file list in memory without sending it over the wire.  It
+ * also has the side-effect of ignoring user-excludes if delete_excluded
+ * is set (so that the delete list includes user-excluded files).
  **/
 struct file_list *send_file_list(int f, int argc, char *argv[])
 {
--- options.c	2 May 2003 23:36:10 -0000	1.108
+++ options.c	1 Jul 2003 21:43:11 -0000
@@ -21,6 +21,8 @@
 #include "rsync.h"
 #include "popt.h"
 
+extern struct exclude_struct **exclude_list;
+
 int make_backups = 0;
 
 /**
@@ -508,19 +510,23 @@
 			break;
 
 		case OPT_EXCLUDE:
-			add_exclude(poptGetOptArg(pc), 0);
+			add_exclude(&exclude_list, poptGetOptArg(pc),
+				    ADD_EXCLUDE);
 			break;
 
 		case OPT_INCLUDE:
-			add_exclude(poptGetOptArg(pc), 1);
+			add_exclude(&exclude_list, poptGetOptArg(pc),
+				    ADD_INCLUDE);
 			break;
 
 		case OPT_EXCLUDE_FROM:
-			add_exclude_file(poptGetOptArg(pc), 1, 0);
+			add_exclude_file(&exclude_list, poptGetOptArg(pc),
+					 MISSING_FATAL, ADD_EXCLUDE);
 			break;
 
 		case OPT_INCLUDE_FROM:
-			add_exclude_file(poptGetOptArg(pc), 1, 1);
+			add_exclude_file(&exclude_list, poptGetOptArg(pc),
+					 MISSING_FATAL, ADD_INCLUDE);
 			break;
 
 		case 'h':
--- proto.h	10 Apr 2003 01:13:30 -0000	1.157
+++ proto.h	1 Jul 2003 21:43:11 -0000
@@ -56,19 +56,16 @@
 int daemon_main(void);
 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_STAT *st);
-void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include);
-void add_exclude(const char *pattern, int include);
-struct exclude_struct **make_exclude_list(const char *fname,
-					  struct exclude_struct **list1,
-					  int fatal, int include);
-void add_exclude_file(const char *fname, int fatal, int include);
+void free_exclude_list(struct exclude_struct ***listp);
+int check_exclude(struct exclude_struct **list, char *name, int name_is_dir);
+void add_exclude(struct exclude_struct ***listp, const char *pattern, int include);
+void add_exclude_file(struct exclude_struct ***listp, const char *fname,
+		      int fatal, int include);
 void send_exclude_list(int f);
 void recv_exclude_list(int f);
 char *get_exclude_tok(char *p);
-void add_exclude_line(char *p);
-void add_include_line(char *p);
+void add_exclude_line(struct exclude_struct ***listp,
+		      const char *line, int include);
 void add_cvs_excludes(void);
 int sparse_end(int f);
 int write_file(int f,char *buf,size_t len);
@@ -78,8 +75,8 @@
 void show_flist_stats(void);
 int readlink_stat(const char *path, STRUCT_STAT * buffer, char *linkbuf);
 int link_stat(const char *path, STRUCT_STAT * buffer);
-struct file_struct *make_file(int f, char *fname, struct string_area **ap,
-			      int noexcludes);
+struct file_struct *make_file(char *fname, struct string_area **ap,
+			      int exclude_level);
 void send_file_name(int f, struct file_list *flist, char *fname,
 		    int recursive, unsigned base_flags);
 struct file_list *send_file_list(int f, int argc, char *argv[]);
--- rsync.h	1 May 2003 19:33:59 -0000	1.149
+++ rsync.h	1 Jul 2003 21:43:11 -0000
@@ -85,6 +85,16 @@
 
 #define MPLEX_BASE 7
 
+#define NO_EXCLUDES	0
+#define SERVER_EXCLUDES	1
+#define ALL_EXCLUDES	2
+
+#define MISSING_OK    0
+#define MISSING_FATAL 1
+
+#define ADD_INCLUDE 1
+#define ADD_EXCLUDE 0
+
 /* Log values.  I *think* what these mean is: FLOG goes to the server
  * logfile; FERROR and FINFO try to end up on the client, with
  * different levels of filtering. */
@@ -424,6 +434,7 @@
 #define MATCHFLG_WILD		0x0001 /* pattern has '*', '[', and/or '?' */
 #define MATCHFLG_WILD2		0x0002 /* pattern has '**' */
 #define MATCHFLG_WILD2_PREFIX	0x0004 /* pattern starts with '**' */
+#define MATCHFLG_ABS_PATH	0x0008 /* path-match on absolute path */
 struct exclude_struct {
 	char *pattern;
 	int match_flags;
--- t_stub.c	8 Apr 2002 04:12:31 -0000	1.1
+++ t_stub.c	1 Jul 2003 21:43:11 -0000
@@ -27,6 +27,7 @@
  **/
 
 int modify_window = 0;
+struct exclude_struct **server_exclude_list;
 
  void rprintf(enum logcode UNUSED(code), const char *format, ...)
 {
@@ -41,4 +42,11 @@
 	fprintf(stderr, "exit(%d): %s(%d)\n",
 		code, file, line);
 	exit(code);
+}
+
+ int check_exclude(struct exclude_struct **list, char *name, int name_is_dir)
+{
+	/* This function doesn't really get called in a test context, so
+	 * just reference our parameters to avoid compiler warnings. */
+	return 0 && list && name && name_is_dir;
 }
--- util.c	19 Jan 2003 21:37:11 -0000	1.119
+++ util.c	1 Jul 2003 21:43:11 -0000
@@ -345,9 +345,10 @@
 			counter = 1;
 	} while (((rc = access(path, 0)) == 0) && (counter != start));
 
-	if (verbose > 0)
+	if (verbose > 0) {
 		rprintf(FINFO,"renaming %s to %s because of text busy\n",
-					    fname, path);
+			fname, path);
+	}
 
 	/* maybe we should return rename()'s exit status? Nah. */
 	if (do_rename(fname, path) != 0) {
@@ -458,14 +459,31 @@
 	return fcntl(fd,F_SETLK,&lock) == 0;
 }
 
+static int exclude_server_path(char *arg)
+{
+	char *s;
+	extern struct exclude_struct **server_exclude_list;
+
+	if (server_exclude_list) {
+		for (s = arg; (s = strchr(s, '/')) != NULL; ) {
+			*s = '\0';
+			if (check_exclude(server_exclude_list, arg, 1)) {
+				/* We must leave arg truncated! */
+				return 1;
+			}
+			*s++ = '/';
+		}
+	}
+	return 0;
+}
 
 static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
 {
 #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
 	if (!*s) s = ".";
-	argv[*argc] = strdup(s);
+	s = argv[*argc] = strdup(s);
+	exclude_server_path(s);
 	(*argc)++;
-	return;
 #else
 	extern int sanitize_paths;
 	glob_t globbuf;
@@ -473,20 +491,21 @@
 
 	if (!*s) s = ".";
 
-	argv[*argc] = strdup(s);
+	s = argv[*argc] = strdup(s);
 	if (sanitize_paths) {
-		sanitize_path(argv[*argc], NULL);
+		sanitize_path(s, NULL);
 	}
 
 	memset(&globbuf, 0, sizeof(globbuf));
-	glob(argv[*argc], 0, NULL, &globbuf);
+	if (!exclude_server_path(s))
+		glob(s, 0, NULL, &globbuf);
 	if (globbuf.gl_pathc == 0) {
 		(*argc)++;
 		globfree(&globbuf);
 		return;
 	}
 	for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
-		if (i == 0) free(argv[*argc]);
+		if (i == 0) free(s);
 		argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
 		if (!argv[(*argc) + i]) out_of_memory("glob_expand");
 	}
@@ -495,29 +514,31 @@
 #endif
 }
 
+/* This routine is only used in daemon mode. */
 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
 {
 	char *s = argv[*argc];
 	char *p, *q;
 	char *base = base1;
+	int base_len = strlen(base);
 
 	if (!s || !*s) return;
 
-	if (strncmp(s, base, strlen(base)) == 0) {
-		s += strlen(base);
-	}
+	if (strncmp(s, base, base_len) == 0)
+		s += base_len;
 
 	s = strdup(s);
 	if (!s) out_of_memory("glob_expand");
 
 	if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
+	base_len++;
 
 	q = s;
 	while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
 		/* split it at this point */
 		*p = 0;
 		glob_expand_one(q, argv, argc, maxargs);
-		q = p+strlen(base);
+		q = p + base_len;
 	}
 
 	if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
@@ -648,7 +669,7 @@
 		}
 		allowdotdot = 0;
 		if ((*p == '.') && (*(p+1) == '.') &&
-			    ((*(p+2) == '/') || (*(p+2) == '\0'))) {
+		    ((*(p+2) == '/') || (*(p+2) == '\0'))) {
 			/* ".." component followed by slash or end */
 			if ((depth > 0) && (sanp == start)) {
 				/* allow depth levels of .. at the beginning */
@@ -699,7 +720,7 @@
 }
 
 
-static char curr_dir[MAXPATHLEN];
+char curr_dir[MAXPATHLEN];
 
 /**
  * Like chdir() but can be reversed with pop_dir() if @p save is set.
@@ -725,7 +746,7 @@
 
 	if (*dir == '/') {
 		strlcpy(curr_dir, dir, sizeof(curr_dir));
-	} else {
+	} else if (dir[0] != '.' || dir[1] != '\0') {
 		strlcat(curr_dir,"/", sizeof(curr_dir));
 		strlcat(curr_dir,dir, sizeof(curr_dir));
 	}
