Expand ~ and ~user in core.excludesfile, commit.template
These config variables are parsed to substitute ~ and ~user with getpw entries. user_path() refactored into new function expand_user_path(), to allow dynamically allocating the return buffer. Original patch by Karl Chen, modified by Matthieu Moy, and further amended by Junio C Hamano. Signed-off-by: Karl Chen <quarl@quarl.org> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									78d553b7d7
								
							
						
					
					
						commit
						395de250d9
					
				|  | @ -380,7 +380,8 @@ Common unit suffixes of 'k', 'm', or 'g' are supported. | |||
| core.excludesfile:: | ||||
| 	In addition to '.gitignore' (per-directory) and | ||||
| 	'.git/info/exclude', git looks into this file for patterns | ||||
| 	of files which are not meant to be tracked.  See | ||||
| 	of files which are not meant to be tracked.  "~/" and "~user/" | ||||
| 	are expanded to the specified user's home directory.  See | ||||
| 	linkgit:gitignore[5]. | ||||
|  | ||||
| core.editor:: | ||||
|  | @ -666,6 +667,7 @@ color.ui:: | |||
|  | ||||
| commit.template:: | ||||
| 	Specify a file to use as the template for new commit messages. | ||||
| 	"~/" and "~user/" are expanded to the specified user's home directory. | ||||
|  | ||||
| diff.autorefreshindex:: | ||||
| 	When using 'git-diff' to compare with work tree | ||||
|  |  | |||
|  | @ -954,7 +954,7 @@ static int git_commit_config(const char *k, const char *v, void *cb) | |||
| 	struct wt_status *s = cb; | ||||
|  | ||||
| 	if (!strcmp(k, "commit.template")) | ||||
| 		return git_config_string(&template_file, k, v); | ||||
| 		return git_config_pathname(&template_file, k, v); | ||||
|  | ||||
| 	return git_status_config(k, v, s); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										2
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										2
									
								
								cache.h
								
								
								
								
							|  | @ -644,6 +644,7 @@ int set_shared_perm(const char *path, int mode); | |||
| #define adjust_shared_perm(path) set_shared_perm((path), 0) | ||||
| int safe_create_leading_directories(char *path); | ||||
| int safe_create_leading_directories_const(const char *path); | ||||
| extern char *expand_user_path(const char *path); | ||||
| char *enter_repo(char *path, int strict); | ||||
| static inline int is_absolute_path(const char *path) | ||||
| { | ||||
|  | @ -902,6 +903,7 @@ extern unsigned long git_config_ulong(const char *, const char *); | |||
| extern int git_config_bool_or_int(const char *, const char *, int *); | ||||
| extern int git_config_bool(const char *, const char *); | ||||
| extern int git_config_string(const char **, const char *, const char *); | ||||
| extern int git_config_pathname(const char **, const char *, const char *); | ||||
| extern int git_config_set(const char *, const char *); | ||||
| extern int git_config_set_multivar(const char *, const char *, const char *, int); | ||||
| extern int git_config_rename_section(const char *, const char *); | ||||
|  |  | |||
							
								
								
									
										12
									
								
								config.c
								
								
								
								
							
							
						
						
									
										12
									
								
								config.c
								
								
								
								
							|  | @ -351,6 +351,16 @@ int git_config_string(const char **dest, const char *var, const char *value) | |||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int git_config_pathname(const char **dest, const char *var, const char *value) | ||||
| { | ||||
| 	if (!value) | ||||
| 		return config_error_nonbool(var); | ||||
| 	*dest = expand_user_path(value); | ||||
| 	if (!*dest) | ||||
| 		die("Failed to expand user dir in: '%s'", value); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int git_default_core_config(const char *var, const char *value) | ||||
| { | ||||
| 	/* This needs a better name */ | ||||
|  | @ -474,7 +484,7 @@ static int git_default_core_config(const char *var, const char *value) | |||
| 		return git_config_string(&editor_program, var, value); | ||||
|  | ||||
| 	if (!strcmp(var, "core.excludesfile")) | ||||
| 		return git_config_string(&excludes_file, var, value); | ||||
| 		return git_config_pathname(&excludes_file, var, value); | ||||
|  | ||||
| 	if (!strcmp(var, "core.whitespace")) { | ||||
| 		if (!value) | ||||
|  |  | |||
							
								
								
									
										80
									
								
								path.c
								
								
								
								
							
							
						
						
									
										80
									
								
								path.c
								
								
								
								
							|  | @ -11,6 +11,7 @@ | |||
|  * which is what it's designed for. | ||||
|  */ | ||||
| #include "cache.h" | ||||
| #include "strbuf.h" | ||||
|  | ||||
| static char bad_path[] = "/bad-path/"; | ||||
|  | ||||
|  | @ -207,43 +208,44 @@ int validate_headref(const char *path) | |||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static char *user_path(char *buf, char *path, int sz) | ||||
| static struct passwd *getpw_str(const char *username, size_t len) | ||||
| { | ||||
| 	struct passwd *pw; | ||||
| 	char *slash; | ||||
| 	int len, baselen; | ||||
| 	char *username_z = xmalloc(len + 1); | ||||
| 	memcpy(username_z, username, len); | ||||
| 	username_z[len] = '\0'; | ||||
| 	pw = getpwnam(username_z); | ||||
| 	free(username_z); | ||||
| 	return pw; | ||||
| } | ||||
|  | ||||
| 	if (!path || path[0] != '~') | ||||
| 		return NULL; | ||||
| 	path++; | ||||
| 	slash = strchr(path, '/'); | ||||
| 	if (path[0] == '/' || !path[0]) { | ||||
| 		pw = getpwuid(getuid()); | ||||
| /* | ||||
|  * Return a string with ~ and ~user expanded via getpw*.  If buf != NULL, | ||||
|  * then it is a newly allocated string. Returns NULL on getpw failure or | ||||
|  * if path is NULL. | ||||
|  */ | ||||
| char *expand_user_path(const char *path) | ||||
| { | ||||
| 	struct strbuf user_path = STRBUF_INIT; | ||||
| 	const char *first_slash = strchrnul(path, '/'); | ||||
| 	const char *to_copy = path; | ||||
|  | ||||
| 	if (path == NULL) | ||||
| 		goto return_null; | ||||
| 	if (path[0] == '~') { | ||||
| 		const char *username = path + 1; | ||||
| 		size_t username_len = first_slash - username; | ||||
| 		struct passwd *pw = getpw_str(username, username_len); | ||||
| 		if (!pw) | ||||
| 			goto return_null; | ||||
| 		strbuf_add(&user_path, pw->pw_dir, strlen(pw->pw_dir)); | ||||
| 		to_copy = first_slash; | ||||
| 	} | ||||
| 	else { | ||||
| 		if (slash) { | ||||
| 			*slash = 0; | ||||
| 			pw = getpwnam(path); | ||||
| 			*slash = '/'; | ||||
| 		} | ||||
| 		else | ||||
| 			pw = getpwnam(path); | ||||
| 	} | ||||
| 	if (!pw || !pw->pw_dir || sz <= strlen(pw->pw_dir)) | ||||
| 		return NULL; | ||||
| 	baselen = strlen(pw->pw_dir); | ||||
| 	memcpy(buf, pw->pw_dir, baselen); | ||||
| 	while ((1 < baselen) && (buf[baselen-1] == '/')) { | ||||
| 		buf[baselen-1] = 0; | ||||
| 		baselen--; | ||||
| 	} | ||||
| 	if (slash && slash[1]) { | ||||
| 		len = strlen(slash); | ||||
| 		if (sz <= baselen + len) | ||||
| 			return NULL; | ||||
| 		memcpy(buf + baselen, slash, len + 1); | ||||
| 	} | ||||
| 	return buf; | ||||
| 	strbuf_add(&user_path, to_copy, strlen(to_copy)); | ||||
| 	return strbuf_detach(&user_path, NULL); | ||||
| return_null: | ||||
| 	strbuf_release(&user_path); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  | @ -291,8 +293,18 @@ char *enter_repo(char *path, int strict) | |||
| 		if (PATH_MAX <= len) | ||||
| 			return NULL; | ||||
| 		if (path[0] == '~') { | ||||
| 			if (!user_path(used_path, path, PATH_MAX)) | ||||
| 			char *newpath = expand_user_path(path); | ||||
| 			if (!newpath || (PATH_MAX - 10 < strlen(newpath))) { | ||||
| 				free(newpath); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 			/* | ||||
| 			 * Copy back into the static buffer. A pity | ||||
| 			 * since newpath was not bounded, but other | ||||
| 			 * branches of the if are limited by PATH_MAX | ||||
| 			 * anyway. | ||||
| 			 */ | ||||
| 			strcpy(used_path, newpath); free(newpath); | ||||
| 			strcpy(validated_path, path); | ||||
| 			path = used_path; | ||||
| 		} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Matthieu Moy
						Matthieu Moy