⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exclude.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * The filter include/exclude routines. * * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org> * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2008 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, visit the http://fsf.org website. */#include "rsync.h"extern int verbose;extern int am_server;extern int am_sender;extern int eol_nulls;extern int io_error;extern int local_server;extern int prune_empty_dirs;extern int ignore_perishable;extern int delete_mode;extern int delete_excluded;extern int cvs_exclude;extern int sanitize_paths;extern int protocol_version;extern int module_id;extern char curr_dir[];extern unsigned int curr_dir_len;extern unsigned int module_dirlen;struct filter_list_struct filter_list = { 0, 0, "" };struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" };struct filter_list_struct daemon_filter_list = { 0, 0, " [daemon]" };/* Need room enough for ":MODS " prefix plus some room to grow. */#define MAX_RULE_PREFIX (16)#define MODIFIERS_MERGE_FILE "-+Cenw"#define MODIFIERS_INCL_EXCL "/!Crsp"#define MODIFIERS_HIDE_PROTECT "/!p"#define SLASH_WILD3_SUFFIX "/***"/* The dirbuf is set by push_local_filters() to the current subdirectory * relative to curr_dir that is being processed.  The path always has a * trailing slash appended, and the variable dirbuf_len contains the length * of this path prefix.  The path is always absolute. */static char dirbuf[MAXPATHLEN+1];static unsigned int dirbuf_len = 0;static int dirbuf_depth;/* This is True when we're scanning parent dirs for per-dir merge-files. */static BOOL parent_dirscan = False;/* This array contains a list of all the currently active per-dir merge * files.  This makes it easier to save the appropriate values when we * "push" down into each subdirectory. */static struct filter_struct **mergelist_parents;static int mergelist_cnt = 0;static int mergelist_size = 0;/* Each filter_list_struct describes a singly-linked list by keeping track * of both the head and tail pointers.  The list is slightly unusual in that * a parent-dir's content can be appended to the end of the local list in a * special way:  the last item in the local list has its "next" pointer set * to point to the inherited list, but the local list's tail pointer points * at the end of the local list.  Thus, if the local list is empty, the head * will be pointing at the inherited content but the tail will be NULL.  To * help you visualize this, here are the possible list arrangements: * * Completely Empty                     Local Content Only * ==================================   ==================================== * head -> NULL                         head -> Local1 -> Local2 -> NULL * tail -> NULL                         tail -------------^ * * Inherited Content Only               Both Local and Inherited Content * ==================================   ==================================== * head -> Parent1 -> Parent2 -> NULL   head -> L1 -> L2 -> P1 -> P2 -> NULL * tail -> NULL                         tail ---------^ * * This means that anyone wanting to traverse the whole list to use it just * needs to start at the head and use the "next" pointers until it goes * NULL.  To add new local content, we insert the item after the tail item * and update the tail (obviously, if "tail" was NULL, we insert it at the * head).  To clear the local list, WE MUST NOT FREE THE INHERITED CONTENT * because it is shared between the current list and our parent list(s). * The easiest way to handle this is to simply truncate the list after the * tail item and then free the local list from the head.  When inheriting * the list for a new local dir, we just save off the filter_list_struct * values (so we can pop back to them later) and set the tail to NULL. */static void free_filter(struct filter_struct *ex){	if (ex->match_flags & MATCHFLG_PERDIR_MERGE) {		free(ex->u.mergelist->debug_type);		free(ex->u.mergelist);		mergelist_cnt--;	}	free(ex->pattern);	free(ex);}/* Build a filter structure given a filter pattern.  The value in "pat" * is not null-terminated. */static void add_rule(struct filter_list_struct *listp, const char *pat,		     unsigned int pat_len, uint32 mflags, int xflags){	struct filter_struct *ret;	const char *cp;	unsigned int pre_len, suf_len, slash_cnt = 0;	if (verbose > 2) {		rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n",			who_am_i(), get_rule_prefix(mflags, pat, 0, NULL),			(int)pat_len, pat,			(mflags & MATCHFLG_DIRECTORY) ? "/" : "",			listp->debug_type);	}	/* These flags also indicate that we're reading a list that	 * needs to be filtered now, not post-filtered later. */	if (xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH)) {		uint32 mf = mflags & (MATCHFLG_RECEIVER_SIDE|MATCHFLG_SENDER_SIDE);		if (am_sender) {			if (mf == MATCHFLG_RECEIVER_SIDE)				return;		} else {			if (mf == MATCHFLG_SENDER_SIDE)				return;		}	}	if (!(ret = new0(struct filter_struct)))		out_of_memory("add_rule");	if (pat_len > 1 && pat[pat_len-1] == '/') {		pat_len--;		mflags |= MATCHFLG_DIRECTORY;	}	for (cp = pat; cp < pat + pat_len; cp++) {		if (*cp == '/')			slash_cnt++;	}	if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))	 && ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/')	  || (xflags & XFLG_ABS_IF_SLASH && slash_cnt))) {		mflags |= MATCHFLG_ABS_PATH;		if (*pat == '/')			pre_len = dirbuf_len - module_dirlen - 1;		else			pre_len = 0;	} else		pre_len = 0;	/* The daemon wants dir-exclude rules to get an appended "/" + "***". */	if (xflags & XFLG_DIR2WILD3	 && BITS_SETnUNSET(mflags, MATCHFLG_DIRECTORY, MATCHFLG_INCLUDE)) {		mflags &= ~MATCHFLG_DIRECTORY;		suf_len = sizeof SLASH_WILD3_SUFFIX - 1;	} else		suf_len = 0;	if (!(ret->pattern = new_array(char, pre_len + pat_len + suf_len + 1)))		out_of_memory("add_rule");	if (pre_len) {		memcpy(ret->pattern, dirbuf + module_dirlen, pre_len);		for (cp = ret->pattern; cp < ret->pattern + pre_len; cp++) {			if (*cp == '/')				slash_cnt++;		}	}	strlcpy(ret->pattern + pre_len, pat, pat_len + 1);	pat_len += pre_len;	if (suf_len) {		memcpy(ret->pattern + pat_len, SLASH_WILD3_SUFFIX, suf_len+1);		pat_len += suf_len;		slash_cnt++;	}	if (strpbrk(ret->pattern, "*[?")) {		mflags |= MATCHFLG_WILD;		if ((cp = strstr(ret->pattern, "**")) != NULL) {			mflags |= MATCHFLG_WILD2;			/* If the pattern starts with **, note that. */			if (cp == ret->pattern)				mflags |= MATCHFLG_WILD2_PREFIX;			/* If the pattern ends with ***, note that. */			if (pat_len >= 3			 && ret->pattern[pat_len-3] == '*'			 && ret->pattern[pat_len-2] == '*'			 && ret->pattern[pat_len-1] == '*')				mflags |= MATCHFLG_WILD3_SUFFIX;		}	}	if (mflags & MATCHFLG_PERDIR_MERGE) {		struct filter_list_struct *lp;		unsigned int len;		int i;		if ((cp = strrchr(ret->pattern, '/')) != NULL)			cp++;		else			cp = ret->pattern;		/* If the local merge file was already mentioned, don't		 * add it again. */		for (i = 0; i < mergelist_cnt; i++) {			struct filter_struct *ex = mergelist_parents[i];			const char *s = strrchr(ex->pattern, '/');			if (s)				s++;			else				s = ex->pattern;			len = strlen(s);			if (len == pat_len - (cp - ret->pattern)			    && memcmp(s, cp, len) == 0) {				free_filter(ret);				return;			}		}		if (!(lp = new_array(struct filter_list_struct, 1)))			out_of_memory("add_rule");		lp->head = lp->tail = NULL;		if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)			out_of_memory("add_rule");		ret->u.mergelist = lp;		if (mergelist_cnt == mergelist_size) {			mergelist_size += 5;			mergelist_parents = realloc_array(mergelist_parents,						struct filter_struct *,						mergelist_size);			if (!mergelist_parents)				out_of_memory("add_rule");		}		mergelist_parents[mergelist_cnt++] = ret;	} else		ret->u.slash_cnt = slash_cnt;	ret->match_flags = mflags;	if (!listp->tail) {		ret->next = listp->head;		listp->head = listp->tail = ret;	} else {		ret->next = listp->tail->next;		listp->tail->next = ret;		listp->tail = ret;	}}static void clear_filter_list(struct filter_list_struct *listp){	if (listp->tail) {		struct filter_struct *ent, *next;		/* Truncate any inherited items from the local list. */		listp->tail->next = NULL;		/* Now free everything that is left. */		for (ent = listp->head; ent; ent = next) {			next = ent->next;			free_filter(ent);		}	}	listp->head = listp->tail = NULL;}/* This returns an expanded (absolute) filename for the merge-file name if * the name has any slashes in it OR if the parent_dirscan var is True; * otherwise it returns the original merge_file name.  If the len_ptr value * is non-NULL the merge_file name is limited by the referenced length * value and will be updated with the length of the resulting name.  We * always return a name that is null terminated, even if the merge_file * name was not. */static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,			      unsigned int prefix_skip){	static char buf[MAXPATHLEN];	char *fn, tmpbuf[MAXPATHLEN];	unsigned int fn_len;	if (!parent_dirscan && *merge_file != '/') {		/* Return the name unchanged it doesn't have any slashes. */		if (len_ptr) {			const char *p = merge_file + *len_ptr;			while (--p > merge_file && *p != '/') {}			if (p == merge_file) {				strlcpy(buf, merge_file, *len_ptr + 1);				return buf;			}		} else if (strchr(merge_file, '/') == NULL)			return (char *)merge_file;	}	fn = *merge_file == '/' ? buf : tmpbuf;	if (sanitize_paths) {		const char *r = prefix_skip ? "/" : NULL;		/* null-terminate the name if it isn't already */		if (len_ptr && merge_file[*len_ptr]) {			char *to = fn == buf ? tmpbuf : buf;			strlcpy(to, merge_file, *len_ptr + 1);			merge_file = to;		}		if (!sanitize_path(fn, merge_file, r, dirbuf_depth, SP_DEFAULT)) {			rprintf(FERROR, "merge-file name overflows: %s\n",				merge_file);			return NULL;		}		fn_len = strlen(fn);	} else {		strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN);		fn_len = clean_fname(fn, CFN_COLLAPSE_DOT_DOT_DIRS);	}	/* If the name isn't in buf yet, it's wasn't absolute. */	if (fn != buf) {		int d_len = dirbuf_len - prefix_skip;		if (d_len + fn_len >= MAXPATHLEN) {			rprintf(FERROR, "merge-file name overflows: %s\n", fn);			return NULL;		}		memcpy(buf, dirbuf + prefix_skip, d_len);		memcpy(buf + d_len, fn, fn_len + 1);		fn_len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS);	}	if (len_ptr)		*len_ptr = fn_len;	return buf;}/* Sets the dirbuf and dirbuf_len values. */void set_filter_dir(const char *dir, unsigned int dirlen){	unsigned int len;	if (*dir != '/') {		memcpy(dirbuf, curr_dir, curr_dir_len);		dirbuf[curr_dir_len] = '/';		len = curr_dir_len + 1;		if (len + dirlen >= MAXPATHLEN)			dirlen = 0;	} else		len = 0;	memcpy(dirbuf + len, dir, dirlen);	dirbuf[dirlen + len] = '\0';	dirbuf_len = clean_fname(dirbuf, CFN_COLLAPSE_DOT_DOT_DIRS);	if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.'	    && dirbuf[dirbuf_len-2] == '/')		dirbuf_len -= 2;	if (dirbuf_len != 1)		dirbuf[dirbuf_len++] = '/';	dirbuf[dirbuf_len] = '\0';	if (sanitize_paths)		dirbuf_depth = count_dir_elements(dirbuf + module_dirlen);}/* This routine takes a per-dir merge-file entry and finishes its setup. * If the name has a path portion then we check to see if it refers to a * parent directory of the first transfer dir.  If it does, we scan all the * dirs from that point through the parent dir of the transfer dir looking * for the per-dir merge-file in each one. */static BOOL setup_merge_file(struct filter_struct *ex,			     struct filter_list_struct *lp){	char buf[MAXPATHLEN];	char *x, *y, *pat = ex->pattern;	unsigned int len;	if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/')		return 0;	y = strrchr(x, '/');	*y = '\0';	ex->pattern = strdup(y+1);	if (!*x)		x = "/";	if (*x == '/')		strlcpy(buf, x, MAXPATHLEN);	else		pathjoin(buf, MAXPATHLEN, dirbuf, x);	len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS);	if (len != 1 && len < MAXPATHLEN-1) {		buf[len++] = '/';		buf[len] = '\0';	}	/* This ensures that the specified dir is a parent of the transfer. */	for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {}	if (*x)		y += strlen(y); /* nope -- skip the scan */	parent_dirscan = True;	while (*y) {		char save[MAXPATHLEN];		strlcpy(save, y, MAXPATHLEN);		*y = '\0';		dirbuf_len = y - dirbuf;		strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));		parse_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS);		if (ex->match_flags & MATCHFLG_NO_INHERIT)			lp->head = NULL;		lp->tail = NULL;		strlcpy(y, save, MAXPATHLEN);		while ((*x++ = *y++) != '/') {}	}	parent_dirscan = False;	free(pat);	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -