grep: accept relative paths outside current working directory
"git grep" would barf at relative paths pointing outside the current working directory (or subdirectories thereof). Use quote_path_relative(), which can handle such cases just fine. [jc: added tests.] Signed-off-by: Clemens Buchacher <drizzd@aon.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									929e37d3df
								
							
						
					
					
						commit
						493b7a08d8
					
				|  | @ -11,6 +11,7 @@ | |||
| #include "tree-walk.h" | ||||
| #include "builtin.h" | ||||
| #include "grep.h" | ||||
| #include "quote.h" | ||||
|  | ||||
| #ifndef NO_EXTERNAL_GREP | ||||
| #ifdef __unix__ | ||||
|  | @ -114,8 +115,8 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char | |||
| 	unsigned long size; | ||||
| 	char *data; | ||||
| 	enum object_type type; | ||||
| 	char *to_free = NULL; | ||||
| 	int hit; | ||||
| 	struct strbuf pathbuf = STRBUF_INIT; | ||||
|  | ||||
| 	data = read_sha1_file(sha1, &type, &size); | ||||
| 	if (!data) { | ||||
|  | @ -123,26 +124,13 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char | |||
| 		return 0; | ||||
| 	} | ||||
| 	if (opt->relative && opt->prefix_length) { | ||||
| 		static char name_buf[PATH_MAX]; | ||||
| 		char *cp; | ||||
| 		int name_len = strlen(name) - opt->prefix_length + 1; | ||||
|  | ||||
| 		if (!tree_name_len) | ||||
| 			name += opt->prefix_length; | ||||
| 		else { | ||||
| 			if (ARRAY_SIZE(name_buf) <= name_len) | ||||
| 				cp = to_free = xmalloc(name_len); | ||||
| 			else | ||||
| 				cp = name_buf; | ||||
| 			memcpy(cp, name, tree_name_len); | ||||
| 			strcpy(cp + tree_name_len, | ||||
| 			       name + tree_name_len + opt->prefix_length); | ||||
| 			name = cp; | ||||
| 		} | ||||
| 		quote_path_relative(name + tree_name_len, -1, &pathbuf, opt->prefix); | ||||
| 		strbuf_insert(&pathbuf, 0, name, tree_name_len); | ||||
| 		name = pathbuf.buf; | ||||
| 	} | ||||
| 	hit = grep_buffer(opt, name, data, size); | ||||
| 	strbuf_release(&pathbuf); | ||||
| 	free(data); | ||||
| 	free(to_free); | ||||
| 	return hit; | ||||
| } | ||||
|  | ||||
|  | @ -152,6 +140,7 @@ static int grep_file(struct grep_opt *opt, const char *filename) | |||
| 	int i; | ||||
| 	char *data; | ||||
| 	size_t sz; | ||||
| 	struct strbuf buf = STRBUF_INIT; | ||||
|  | ||||
| 	if (lstat(filename, &st) < 0) { | ||||
| 	err_ret: | ||||
|  | @ -176,8 +165,9 @@ static int grep_file(struct grep_opt *opt, const char *filename) | |||
| 	} | ||||
| 	close(i); | ||||
| 	if (opt->relative && opt->prefix_length) | ||||
| 		filename += opt->prefix_length; | ||||
| 		filename = quote_path_relative(filename, -1, &buf, opt->prefix); | ||||
| 	i = grep_buffer(opt, filename, data, sz); | ||||
| 	strbuf_release(&buf); | ||||
| 	free(data); | ||||
| 	return i; | ||||
| } | ||||
|  | @ -582,6 +572,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) | |||
| 	int i; | ||||
|  | ||||
| 	memset(&opt, 0, sizeof(opt)); | ||||
| 	opt.prefix = prefix; | ||||
| 	opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; | ||||
| 	opt.relative = 1; | ||||
| 	opt.pathname = 1; | ||||
|  | @ -857,15 +848,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) | |||
| 			verify_filename(prefix, argv[j]); | ||||
| 	} | ||||
|  | ||||
| 	if (i < argc) { | ||||
| 	if (i < argc) | ||||
| 		paths = get_pathspec(prefix, argv + i); | ||||
| 		if (opt.prefix_length && opt.relative) { | ||||
| 			/* Make sure we do not get outside of paths */ | ||||
| 			for (i = 0; paths[i]; i++) | ||||
| 				if (strncmp(prefix, paths[i], opt.prefix_length)) | ||||
| 					die("git grep: cannot generate relative filenames containing '..'"); | ||||
| 		} | ||||
| 	} | ||||
| 	else if (prefix) { | ||||
| 		paths = xcalloc(2, sizeof(const char *)); | ||||
| 		paths[0] = prefix; | ||||
|  |  | |||
							
								
								
									
										1
									
								
								grep.h
								
								
								
								
							
							
						
						
									
										1
									
								
								grep.h
								
								
								
								
							|  | @ -59,6 +59,7 @@ struct grep_opt { | |||
| 	struct grep_pat *pattern_list; | ||||
| 	struct grep_pat **pattern_tail; | ||||
| 	struct grep_expr *pattern_expression; | ||||
| 	const char *prefix; | ||||
| 	int prefix_length; | ||||
| 	regex_t regexp; | ||||
| 	unsigned linenum:1; | ||||
|  |  | |||
|  | @ -212,4 +212,21 @@ test_expect_success 'grep with CE_VALID file' ' | |||
| 	git checkout t/t | ||||
| ' | ||||
|  | ||||
| test_expect_success 'grep from a subdirectory to search wider area (1)' ' | ||||
| 	mkdir -p s && | ||||
| 	( | ||||
| 		cd s && git grep "x x x" .. | ||||
| 	) | ||||
| ' | ||||
|  | ||||
| test_expect_success 'grep from a subdirectory to search wider area (2)' ' | ||||
| 	mkdir -p s && | ||||
| 	( | ||||
| 		cd s || exit 1 | ||||
| 		( git grep xxyyzz .. >out ; echo $? >status ) | ||||
| 		! test -s out && | ||||
| 		test 1 = $(cat status) | ||||
| 	) | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Clemens Buchacher
						Clemens Buchacher