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

📄 util.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 3 页
字号:
		len = strlen(arg);	if (strpbrk(arg, "*?[")) {		struct dirent *di;		DIR *d;		if (!(d = opendir(abpos ? glob.arg_buf : ".")))			return;		while ((di = readdir(d)) != NULL) {			char *dname = d_name(di);			if (dname[0] == '.' && (dname[1] == '\0'			  || (dname[1] == '.' && dname[2] == '\0')))				continue;			if (!wildmatch(arg, dname))				continue;			call_glob_match(dname, strlen(dname), 1,					slash ? arg + len + 1 : NULL,					abpos, fbpos);		}		closedir(d);	} else {		call_glob_match(arg, len, 0,				slash ? arg + len + 1 : NULL,				abpos, fbpos);	}	if (slash)		*slash = '/';}static inline void call_glob_match(const char *name, int len, int from_glob,				   char *arg, int abpos, int fbpos){	char *use_buf;	ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + len + 2);	memcpy(glob.arg_buf + abpos, name, len);	abpos += len;	glob.arg_buf[abpos] = '\0';	if (fbpos >= 0) {		ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, fbpos + len + 2);		memcpy(glob.filt_buf + fbpos, name, len);		fbpos += len;		glob.filt_buf[fbpos] = '\0';		use_buf = glob.filt_buf;	} else		use_buf = glob.arg_buf;	if (from_glob || (arg && len)) {		STRUCT_STAT st;		int is_dir;		if (do_stat(glob.arg_buf, &st) != 0)			return;		is_dir = S_ISDIR(st.st_mode) != 0;		if (arg && !is_dir)			return;		if (daemon_filter_list.head		 && check_filter(&daemon_filter_list, FLOG, use_buf, is_dir) < 0)			return;	}	if (arg) {		glob.arg_buf[abpos++] = '/';		glob.arg_buf[abpos] = '\0';		if (fbpos >= 0) {			glob.filt_buf[fbpos++] = '/';			glob.filt_buf[fbpos] = '\0';		}		glob_match(arg, abpos, fbpos);	} else {		ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);		if (!(glob.argv[glob.argc++] = strdup(glob.arg_buf)))			out_of_memory("glob_match");	}}/* This routine performs wild-card expansion of the pathname in "arg".  Any * daemon-excluded files/dirs will not be matched by the wildcards.  Returns 0 * if a wild-card string is the only returned item (due to matching nothing). */int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p){	int ret, save_argc;	char *s;	if (!arg) {		if (glob.filt_buf)			free(glob.filt_buf);		free(glob.arg_buf);		memset(&glob, 0, sizeof glob);		return -1;	}	if (sanitize_paths)		s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS);	else {		s = strdup(arg);		if (!s)			out_of_memory("glob_expand");		clean_fname(s, CFN_KEEP_DOT_DIRS			     | CFN_KEEP_TRAILING_SLASH			     | CFN_COLLAPSE_DOT_DOT_DIRS);	}	ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);	*glob.arg_buf = '\0';	glob.argc = save_argc = *argc_p;	glob.argv = *argv_p;	glob.maxargs = *maxargs_p;	ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, 100);	glob_match(s, 0, -1);	/* The arg didn't match anything, so add the failed arg to the list. */	if (glob.argc == save_argc) {		ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);		glob.argv[glob.argc++] = s;		ret = 0;	} else {		free(s);		ret = 1;	}	*maxargs_p = glob.maxargs;	*argv_p = glob.argv;	*argc_p = glob.argc;	return ret;}/* This routine is only used in daemon mode. */void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p){	char *p, *s;	char *base = base1;	int base_len = strlen(base);	if (!arg || !*arg)		return;	if (strncmp(arg, base, base_len) == 0)		arg += base_len;	if (!(arg = strdup(arg)))		out_of_memory("glob_expand_module");	if (asprintf(&base," %s/", base1) <= 0)		out_of_memory("glob_expand_module");	base_len++;	for (s = arg; *s; s = p + base_len) {		if ((p = strstr(s, base)) != NULL)			*p = '\0'; /* split it at this point */		glob_expand(s, argv_p, argc_p, maxargs_p);		if (!p)			break;	}	free(arg);	free(base);}/** * Convert a string to lower case **/void strlower(char *s){	while (*s) {		if (isUpper(s))			*s = toLower(s);		s++;	}}/* Join strings p1 & p2 into "dest" with a guaranteed '/' between them.  (If * p1 ends with a '/', no extra '/' is inserted.)  Returns the length of both * strings + 1 (if '/' was inserted), regardless of whether the null-terminated * string fits into destsize. */size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2){	size_t len = strlcpy(dest, p1, destsize);	if (len < destsize - 1) {		if (!len || dest[len-1] != '/')			dest[len++] = '/';		if (len < destsize - 1)			len += strlcpy(dest + len, p2, destsize - len);		else {			dest[len] = '\0';			len += strlen(p2);		}	}	else		len += strlen(p2) + 1; /* Assume we'd insert a '/'. */	return len;}/* Join any number of strings together, putting them in "dest".  The return * value is the length of all the strings, regardless of whether the null- * terminated whole fits in destsize.  Your list of string pointers must end * with a NULL to indicate the end of the list. */size_t stringjoin(char *dest, size_t destsize, ...){	va_list ap;	size_t len, ret = 0;	const char *src;	va_start(ap, destsize);	while (1) {		if (!(src = va_arg(ap, const char *)))			break;		len = strlen(src);		ret += len;		if (destsize > 1) {			if (len >= destsize)				len = destsize - 1;			memcpy(dest, src, len);			destsize -= len;			dest += len;		}	}	*dest = '\0';	va_end(ap);	return ret;}int count_dir_elements(const char *p){	int cnt = 0, new_component = 1;	while (*p) {		if (*p++ == '/')			new_component = (*p != '.' || (p[1] != '/' && p[1] != '\0'));		else if (new_component) {			new_component = 0;			cnt++;		}	}	return cnt;}/* Turns multiple adjacent slashes into a single slash (possible exception: * the preserving of two leading slashes at the start), drops all leading or * interior "." elements unless CFN_KEEP_DOT_DIRS is flagged.  Will also drop * a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is flagged, removes * a trailing slash (perhaps after removing the aforementioned dot) unless * CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements * (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged.  If the * resulting name would be empty, returns ".". */unsigned int clean_fname(char *name, int flags){	char *limit = name - 1, *t = name, *f = name;	int anchored;	if (!name)		return 0;	if ((anchored = *f == '/') != 0) {		*t++ = *f++;#ifdef __CYGWIN__		/* If there are exactly 2 slashes at the start, preserve		 * them.  Would break daemon excludes unless the paths are		 * really treated differently, so used this sparingly. */		if (*f == '/' && f[1] != '/')			*t++ = *f++;#endif	} else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {		*t++ = *f++;		*t++ = *f++;	}	while (*f) {		/* discard extra slashes */		if (*f == '/') {			f++;			continue;		}		if (*f == '.') {			/* discard interior "." dirs */			if (f[1] == '/' && !(flags & CFN_KEEP_DOT_DIRS)) {				f += 2;				continue;			}			if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR)				break;			/* collapse ".." dirs */			if (flags & CFN_COLLAPSE_DOT_DOT_DIRS			 && f[1] == '.' && (f[2] == '/' || !f[2])) {				char *s = t - 1;				if (s == name && anchored) {					f += 2;					continue;				}				while (s > limit && *--s != '/') {}				if (s != t - 1 && (s < name || *s == '/')) {					t = s + 1;					f += 2;					continue;				}				limit = t + 2;			}		}		while (*f && (*t++ = *f++) != '/') {}	}	if (t > name+anchored && t[-1] == '/' && !(flags & CFN_KEEP_TRAILING_SLASH))		t--;	if (t == name)		*t++ = '.';	*t = '\0';	return t - name;}/* Make path appear as if a chroot had occurred.  This handles a leading * "/" (either removing it or expanding it) and any leading or embedded * ".." components that attempt to escape past the module's top dir. * * If dest is NULL, a buffer is allocated to hold the result.  It is legal * to call with the dest and the path (p) pointing to the same buffer, but * rootdir will be ignored to avoid expansion of the string. * * The rootdir string contains a value to use in place of a leading slash. * Specify NULL to get the default of "module_dir". * * The depth var is a count of how many '..'s to allow at the start of the * path. * * We also clean the path in a manner similar to clean_fname() but with a * few differences: * * Turns multiple adjacent slashes into a single slash, gets rid of "." dir * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and * ALWAYS collapses ".." elements (except for those at the start of the * string up to "depth" deep).  If the resulting name would be empty, * change it into a ".". */char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,		    int flags){	char *start, *sanp;	int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);	if (dest != p) {		int plen = strlen(p);		if (*p == '/') {			if (!rootdir)				rootdir = module_dir;			rlen = strlen(rootdir);			depth = 0;			p++;		}		if (dest) {			if (rlen + plen + 1 >= MAXPATHLEN)				return NULL;		} else if (!(dest = new_array(char, rlen + plen + 1)))			out_of_memory("sanitize_path");		if (rlen) {			memcpy(dest, rootdir, rlen);			if (rlen > 1)				dest[rlen++] = '/';		}	}	if (drop_dot_dirs) {		while (*p == '.' && p[1] == '/')			p += 2;	}	start = sanp = dest + rlen;	/* This loop iterates once per filename component in p, pointing at	 * the start of the name (past any prior slash) for each iteration. */	while (*p) {		/* discard leading or extra slashes */		if (*p == '/') {			p++;			continue;		}		if (drop_dot_dirs) {			if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {				/* skip "." component */				p++;				continue;			}		}		if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {			/* ".." component followed by slash or end */			if (depth <= 0 || sanp != start) {				p += 2;				if (sanp != start) {					/* back up sanp one level */					--sanp; /* now pointing at slash */					while (sanp > start && sanp[-1] != '/')						sanp--;				}				continue;			}			/* allow depth levels of .. at the beginning */			depth--;			/* move the virtual beginning to leave the .. alone */			start = sanp + 3;		}		/* copy one component through next slash */		while (*p && (*sanp++ = *p++) != '/') {}	}	if (sanp == dest) {		/* ended up with nothing, so put in "." component */		*sanp++ = '.';	}	*sanp = '\0';	return dest;}/* Like chdir(), but it keeps track of the current directory (in the * global "curr_dir"), and ensures that the path size doesn't overflow. * Also cleans the path using the clean_fname() function. */int change_dir(const char *dir, int set_path_only){	static int initialised;	unsigned int len;	if (!initialised) {		initialised = 1;		if (getcwd(curr_dir, sizeof curr_dir - 1) == NULL) {			rsyserr(FERROR, errno, "getcwd()");			exit_cleanup(RERR_FILESELECT);		}		curr_dir_len = strlen(curr_dir);	}	if (!dir)	/* this call was probably just to initialize */		return 0;	len = strlen(dir);	if (len == 1 && *dir == '.')		return 1;	if (*dir == '/') {		if (len >= sizeof curr_dir) {			errno = ENAMETOOLONG;			return 0;		}		if (!set_path_only && chdir(dir))			return 0;		memcpy(curr_dir, dir, len + 1);	} else {		if (curr_dir_len + 1 + len >= sizeof curr_dir) {			errno = ENAMETOOLONG;			return 0;		}		curr_dir[curr_dir_len] = '/';		memcpy(curr_dir + curr_dir_len + 1, dir, len + 1);		if (!set_path_only && chdir(curr_dir)) {			curr_dir[curr_dir_len] = '\0';			return 0;		}	}	curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS);	if (sanitize_paths) {		if (module_dirlen > curr_dir_len)			module_dirlen = curr_dir_len;		curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);	}	if (verbose >= 5 && !set_path_only)		rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);	return 1;}/* This will make a relative path absolute and clean it up via clean_fname(). * Returns the string, which might be newly allocated, or NULL on error. */char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr){	unsigned int len;	if (*path != '/') { /* Make path absolute. */		int len = strlen(path);		if (curr_dir_len + 1 + len >= sizeof curr_dir)			return NULL;		curr_dir[curr_dir_len] = '/';		memcpy(curr_dir + curr_dir_len + 1, path, len + 1);		if (!(path = strdup(curr_dir)))			out_of_memory("normalize_path");		curr_dir[curr_dir_len] = '\0';	} else if (force_newbuf) {		if (!(path = strdup(path)))			out_of_memory("normalize_path");	}	len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);	if (len_ptr)		*len_ptr = len;	return path;}/** * Return a quoted string with the full pathname of the indicated filename. * The string " (in MODNAME)" may also be appended.  The returned pointer * remains valid until the next time full_fname() is called. **/char *full_fname(const char *fn){	static char *result = NULL;	char *m1, *m2, *m3;	char *p1, *p2;	if (result)		free(result);	if (*fn == '/')		p1 = p2 = "";	else {		p1 = curr_dir + module_dirlen;		for (p2 = p1; *p2 == '/'; p2++) {}		if (*p2)			p2 = "/";	}	if (module_id >= 0) {		m1 = " (in ";		m2 = lp_name(module_id);		m3 = ")";	} else		m1 = m2 = m3 = "";	if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) <= 0)		out_of_memory("full_fname");	return result;}static char partial_fname[MAXPATHLEN];char *partial_dir_fname(const char *fname){	char *t = partial_fname;	int sz = sizeof partial_fname;	const char *fn;	if ((fn = strrchr(fname, '/')) != NULL) {		fn++;		if (*partial_dir != '/') {			int len = fn - fname;			strncpy(t, fname, len); /* safe */			t += len;			sz -= len;		}	} else		fn = fname;	if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)		return NULL;	if (daemon_filter_list.head) {		t = strrchr(partial_fname, '/');		*t = '\0';		if (check_filter(&daemon_filter_list, FLOG, partial_fname, 1) < 0)			return NULL;		*t = '/';		if (check_filter(&daemon_filter_list, FLOG, partial_fname, 0) < 0)			return NULL;	}	return partial_fname;

⌨️ 快捷键说明

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