Skip to content

Commit

Permalink
grep: accept relative paths outside current working directory
Browse files Browse the repository at this point in the history
"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>
  • Loading branch information
Clemens Buchacher authored and Junio C Hamano committed Sep 7, 2009
1 parent 929e37d commit 493b7a0
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 27 deletions.
38 changes: 11 additions & 27 deletions builtin-grep.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "tree-walk.h"
#include "builtin.h"
#include "grep.h"
#include "quote.h"

#ifndef NO_EXTERNAL_GREP
#ifdef __unix__
Expand Down Expand Up @@ -114,35 +115,22 @@ 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) {
error("'%s': unable to read %s", name, sha1_to_hex(sha1));
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;
}

Expand All @@ -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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions grep.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 17 additions & 0 deletions t/t7002-grep.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 493b7a0

Please sign in to comment.