git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/2] grep: accept relative paths outside current working directory

From
Clemens Buchacher <drizzd@aon.at>
Date
Sep 5, 2009, 12:31 UTC
Message-ID
<20090905123117.GA3099@darc.dnsalias.org>
In-Reply-To
<7v3a717rgl.fsf@alter.siamese.dyndns.org>
On Sat, Sep 05, 2009 at 12:58:50AM -0700, Junio C Hamano wrote:
> >> If "git add -u ../.." (I mean "the grand parent directory", not "an
> >> unnamed subdirectory") did not work 
I just noticed that this doesn't work with grep. In git.git:

$ cd t $ git grep addremove -- ../ fatal: git grep: cannot generate relative filenames containing '..'

So here's a fix for that. And a configurable solution for add and grep's scope as a follow-up. I did not look at any other commands yet.

Clemens

--o<-- Previously, "git grep" would bark at relative paths pointing outside the current working directory (or subdirectories thereof). We already have quote_path_relative(), which can handle such cases just fine. So use that instead.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---
 builtin-grep.c |   44 ++++++++++++++------------------------------
 grep.h         |    1 +
 2 files changed, 15 insertions(+), 30 deletions(-)
diff --git a/builtin-grep.c b/builtin-grep.c
index ad0e0a5..f6af3d4 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -13,6 +13,7 @@
 #include "parse-options.h"
 #include "userdiff.h"
 #include "grep.h"
+#include "quote.h"
 
 #ifndef NO_EXTERNAL_GREP
 #ifdef __unix__
@@ -152,40 +153,27 @@ static int pathspec_matches(const char **paths, const char *name, int max_depth)
 	return 0;
 }
 
-static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name, int tree_name_len)
+static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *path, int tree_name_len)
 {
 	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));
+		error("'%s': unable to read %s", path, 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(path + tree_name_len, -1, &pathbuf, opt->prefix);
+		strbuf_insert(&pathbuf, 0, path, tree_name_len);
+		path = pathbuf.buf;
 	}
-	hit = grep_buffer(opt, name, data, size);
+	hit = grep_buffer(opt, path, data, size);
+	strbuf_release(&pathbuf);
 	free(data);
-	free(to_free);
 	return hit;
 }
 
@@ -195,6 +183,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:
@@ -219,8 +208,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;
 }
@@ -798,6 +788,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 	};
 
 	memset(&opt, 0, sizeof(opt));
+	opt.prefix = prefix;
 	opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
 	opt.relative = 1;
 	opt.pathname = 1;
@@ -868,15 +859,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;
diff --git a/grep.h b/grep.h
index 28e6b2a..f6eecc6 100644
--- a/grep.h
+++ b/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;
 	int linenum;
-- 
1.6.4.2.264.g79b4f
Previous: Clemens BuchacherNext: Clemens Buchacher
Message 14 of 35 in “[BUG] 'add -u' doesn't work from untracked subdir”
  1. SZEDER GáborSep 2, 2009
  2. Jeff KingSep 2, 2009
  3. Clemens BuchacherSep 4, 2009
  4. Jeff KingSep 5, 2009
  5. Junio C HamanoSep 5, 2009
  6. Jeff KingSep 5, 2009
  7. Junio C HamanoSep 5, 2009
  8. Jeff KingSep 5, 2009
  9. Junio C HamanoSep 5, 2009
  10. Clemens BuchacherSep 6, 2009
  11. Nanako ShiraishiSep 9, 2009
  12. Junio C HamanoSep 10, 2009
  13. Clemens BuchacherSep 10, 2009
  14. 1/2 grep: accept relative paths outside current working directoryClemens Buchacher, Sep 5, 2009
  15. 2/2 add 'scope' config optionClemens Buchacher, Sep 5, 2009
  16. 2/2 add 'scope' config optionClemens Buchacher, Sep 5, 2009
  17. Junio C HamanoSep 6, 2009
  18. grep: fix exit status if external_grep() returns errorClemens Buchacher, Sep 7, 2009
  19. Junio C HamanoSep 7, 2009
  20. Jeff KingSep 5, 2009
  21. Junio C HamanoSep 5, 2009
  22. Clemens BuchacherSep 5, 2009
  23. Junio C HamanoSep 5, 2009
  24. Jakub NarebskiSep 5, 2009
  25. Clemens BuchacherSep 5, 2009
  26. Junio C HamanoSep 5, 2009
  27. Matthieu MoySep 6, 2009
  28. Clemens BuchacherSep 6, 2009
  29. Matthieu MoySep 7, 2009
  30. SZEDER GáborSep 7, 2009
  31. Matthieu MoySep 7, 2009
  32. Nanako ShiraishiSep 7, 2009
  33. Junio C HamanoSep 7, 2009
  34. Clemens BuchacherSep 7, 2009
  35. SZEDER GáborSep 4, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.