@matheusbsbs / matheus-bagliano / commits / 493b7a08d8
Fork 0

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>

Clemens Buchacher committed Sep 5, 2009 at 14:31 UTC 493b7a08d80535def6756b281873e4e0937ba6c2
3 files changed +29 -27
builtin-grep.c
+11 -27
@@ -11,6 +11,7 @@
11 #include "tree-walk.h"
12 #include "builtin.h"
13 #include "grep.h"
14 +#include "quote.h"
15
16 #ifndef NO_EXTERNAL_GREP
17 #ifdef __unix__
@@ -114,8 +115,8 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char
115 unsigned long size;
116 char *data;
117 enum object_type type;
117 - char *to_free = NULL;
118 int hit;
119 + struct strbuf pathbuf = STRBUF_INIT;
120
121 data = read_sha1_file(sha1, &type, &size);
122 if (!data) {
@@ -123,26 +124,13 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char
124 return 0;
125 }
126 if (opt->relative && opt->prefix_length) {
126 - static char name_buf[PATH_MAX];
127 - char *cp;
128 - int name_len = strlen(name) - opt->prefix_length + 1;
129 -
130 - if (!tree_name_len)
131 - name += opt->prefix_length;
132 - else {
133 - if (ARRAY_SIZE(name_buf) <= name_len)
134 - cp = to_free = xmalloc(name_len);
135 - else
136 - cp = name_buf;
137 - memcpy(cp, name, tree_name_len);
138 - strcpy(cp + tree_name_len,
139 - name + tree_name_len + opt->prefix_length);
140 - name = cp;
141 - }
127 + quote_path_relative(name + tree_name_len, -1, &pathbuf, opt->prefix);
128 + strbuf_insert(&pathbuf, 0, name, tree_name_len);
129 + name = pathbuf.buf;
130 }
131 hit = grep_buffer(opt, name, data, size);
132 + strbuf_release(&pathbuf);
133 free(data);
145 - free(to_free);
134 return hit;
135 }
136
@@ -152,6 +140,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
140 int i;
141 char *data;
142 size_t sz;
143 + struct strbuf buf = STRBUF_INIT;
144
145 if (lstat(filename, &st) < 0) {
146 err_ret:
@@ -176,8 +165,9 @@ static int grep_file(struct grep_opt *opt, const char *filename)
165 }
166 close(i);
167 if (opt->relative && opt->prefix_length)
179 - filename += opt->prefix_length;
168 + filename = quote_path_relative(filename, -1, &buf, opt->prefix);
169 i = grep_buffer(opt, filename, data, sz);
170 + strbuf_release(&buf);
171 free(data);
172 return i;
173 }
@@ -582,6 +572,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
572 int i;
573
574 memset(&opt, 0, sizeof(opt));
575 + opt.prefix = prefix;
576 opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
577 opt.relative = 1;
578 opt.pathname = 1;
@@ -857,15 +848,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
848 verify_filename(prefix, argv[j]);
849 }
850
860 - if (i < argc) {
851 + if (i < argc)
852 paths = get_pathspec(prefix, argv + i);
862 - if (opt.prefix_length && opt.relative) {
863 - /* Make sure we do not get outside of paths */
864 - for (i = 0; paths[i]; i++)
865 - if (strncmp(prefix, paths[i], opt.prefix_length))
866 - die("git grep: cannot generate relative filenames containing '..'");
867 - }
868 - }
853 else if (prefix) {
854 paths = xcalloc(2, sizeof(const char *));
855 paths[0] = prefix;
grep.h
+1
@@ -59,6 +59,7 @@ struct grep_opt {
59 struct grep_pat *pattern_list;
60 struct grep_pat **pattern_tail;
61 struct grep_expr *pattern_expression;
62 + const char *prefix;
63 int prefix_length;
64 regex_t regexp;
65 unsigned linenum:1;
t/t7002-grep.sh
+17
@@ -212,4 +212,21 @@ test_expect_success 'grep with CE_VALID file' '
212 git checkout t/t
213 '
214
215 +test_expect_success 'grep from a subdirectory to search wider area (1)' '
216 + mkdir -p s &&
217 + (
218 + cd s && git grep "x x x" ..
219 + )
220 +'
221 +
222 +test_expect_success 'grep from a subdirectory to search wider area (2)' '
223 + mkdir -p s &&
224 + (
225 + cd s || exit 1
226 + ( git grep xxyyzz .. >out ; echo $? >status )
227 + ! test -s out &&
228 + test 1 = $(cat status)
229 + )
230 +'
231 +
232 test_done