git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
	"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 39/45] parse_pathspec: make sure the prefix part is wildcard-free
Date: Sun,  9 Jun 2013 13:26:12 +0700	[thread overview]
Message-ID: <1370759178-1709-40-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1370759178-1709-1-git-send-email-pclouds@gmail.com>

Prepending prefix to pathspec is a trick to workaround the fact that
commands can be executed in a subdirectory, but all git commands run
at worktree's root. The prefix part should always be treated as
literal string. Make it so.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 cache.h    |  2 ++
 path.c     | 15 ++++++++++++++-
 pathspec.c | 21 +++++++++++++++++----
 pathspec.h |  2 +-
 setup.c    | 24 ++++++++++++++++++++----
 5 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/cache.h b/cache.h
index b3d8b29..276330e 100644
--- a/cache.h
+++ b/cache.h
@@ -408,6 +408,7 @@ extern void setup_work_tree(void);
 extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern char *prefix_path(const char *prefix, int len, const char *path);
+extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
 extern const char *prefix_filename(const char *prefix, int len, const char *path);
 extern int check_filename(const char *prefix, const char *name);
 extern void verify_filename(const char *prefix,
@@ -720,6 +721,7 @@ const char *real_path(const char *path);
 const char *real_path_if_valid(const char *path);
 const char *absolute_path(const char *path);
 const char *relative_path(const char *abs, const char *base);
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
 int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, struct string_list *prefixes);
 char *strip_path_suffix(const char *path, const char *suffix);
diff --git a/path.c b/path.c
index 04ff148..f4b49d6 100644
--- a/path.c
+++ b/path.c
@@ -492,8 +492,14 @@ const char *relative_path(const char *abs, const char *base)
  *
  * Note that this function is purely textual.  It does not follow symlinks,
  * verify the existence of the path, or make any system calls.
+ *
+ * prefix_len != NULL is for a specific case of prefix_pathspec():
+ * assume that src == dst and src[0..prefix_len-1] is already
+ * normalized, any time "../" eats up to the prefix_len part,
+ * prefix_len is reduced. In the end prefix_len is the remaining
+ * prefix that has not been overridden by user pathspec.
  */
-int normalize_path_copy(char *dst, const char *src)
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
 {
 	char *dst0;
 
@@ -568,11 +574,18 @@ int normalize_path_copy(char *dst, const char *src)
 		/* Windows: dst[-1] cannot be backslash anymore */
 		while (dst0 < dst && dst[-1] != '/')
 			dst--;
+		if (prefix_len && *prefix_len > dst - dst0)
+			*prefix_len = dst - dst0;
 	}
 	*dst = '\0';
 	return 0;
 }
 
+int normalize_path_copy(char *dst, const char *src)
+{
+	return normalize_path_copy_len(dst, src, NULL);
+}
+
 /*
  * path = Canonical absolute path
  * prefixes = string_list containing normalized, absolute paths without
diff --git a/pathspec.c b/pathspec.c
index 17f25d6..e2ee268 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -150,10 +150,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 	magic |= short_magic;
 	*p_short_magic = short_magic;
 
-	if (magic & PATHSPEC_FROMTOP)
+	if (magic & PATHSPEC_FROMTOP) {
 		match = xstrdup(copyfrom);
-	else
-		match = prefix_path(prefix, prefixlen, copyfrom);
+		prefixlen = 0;
+	} else {
+		match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
+		if (!match)
+			die(_("%s: '%s' is outside repository"), elt, copyfrom);
+	}
 	*raw = item->match = match;
 	/*
 	 * Prefix the pathspec (keep all magic) and put to
@@ -167,6 +171,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 	} else
 		item->original = elt;
 	item->len = strlen(item->match);
+	item->prefix = prefixlen;
 
 	if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
 	    (item->len >= 1 && item->match[item->len - 1] == '/') &&
@@ -198,13 +203,20 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 
 	if (limit_pathspec_to_literal())
 		item->nowildcard_len = item->len;
-	else
+	else {
 		item->nowildcard_len = simple_length(item->match);
+		if (item->nowildcard_len < prefixlen)
+			item->nowildcard_len = prefixlen;
+	}
 	item->flags = 0;
 	if (item->nowildcard_len < item->len &&
 	    item->match[item->nowildcard_len] == '*' &&
 	    no_wildcard(item->match + item->nowildcard_len + 1))
 		item->flags |= PATHSPEC_ONESTAR;
+
+	/* sanity checks, pathspec matchers assume these are sane */
+	assert(item->nowildcard_len <= item->len &&
+	       item->prefix         <= item->len);
 	return magic;
 }
 
@@ -284,6 +296,7 @@ void parse_pathspec(struct pathspec *pathspec,
 		item->match = prefix;
 		item->original = prefix;
 		item->nowildcard_len = item->len = strlen(prefix);
+		item->prefix = item->len;
 		raw[0] = prefix;
 		raw[1] = NULL;
 		pathspec->nr = 1;
diff --git a/pathspec.h b/pathspec.h
index 16bbb7b..bbcfa74 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -21,7 +21,7 @@ struct pathspec {
 		const char *match;
 		const char *original;
 		unsigned magic;
-		int len;
+		int len, prefix;
 		int nowildcard_len;
 		int flags;
 	} *items;
diff --git a/setup.c b/setup.c
index d1ece5d..ff4499e 100644
--- a/setup.c
+++ b/setup.c
@@ -5,7 +5,19 @@
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 
-static char *prefix_path_gently(const char *prefix, int len, const char *path)
+/*
+ * Normalize "path", prepending the "prefix" for relative paths. If
+ * remaining_prefix is not NULL, return the actual prefix still
+ * remains in the path. For example, prefix = sub1/sub2/ and path is
+ *
+ *  foo          -> sub1/sub2/foo  (full prefix)
+ *  ../foo       -> sub1/foo       (remaining prefix is sub1/)
+ *  ../../bar    -> bar            (no remaining prefix)
+ *  ../../sub1/sub2/foo -> sub1/sub2/foo (but no remaining prefix)
+ *  `pwd`/../bar -> sub1/bar       (no remaining prefix)
+ */
+char *prefix_path_gently(const char *prefix, int len,
+			 int *remaining_prefix, const char *path)
 {
 	const char *orig = path;
 	char *sanitized;
@@ -13,13 +25,17 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)
 		const char *temp = real_path(path);
 		sanitized = xmalloc(len + strlen(temp) + 1);
 		strcpy(sanitized, temp);
+		if (remaining_prefix)
+			*remaining_prefix = 0;
 	} else {
 		sanitized = xmalloc(len + strlen(path) + 1);
 		if (len)
 			memcpy(sanitized, prefix, len);
 		strcpy(sanitized + len, path);
+		if (remaining_prefix)
+			*remaining_prefix = len;
 	}
-	if (normalize_path_copy(sanitized, sanitized))
+	if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
 		goto error_out;
 	if (is_absolute_path(orig)) {
 		size_t root_len, len, total;
@@ -44,7 +60,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)
 
 char *prefix_path(const char *prefix, int len, const char *path)
 {
-	char *r = prefix_path_gently(prefix, len, path);
+	char *r = prefix_path_gently(prefix, len, NULL, path);
 	if (!r)
 		die("'%s' is outside repository", path);
 	return r;
@@ -53,7 +69,7 @@ char *prefix_path(const char *prefix, int len, const char *path)
 int path_inside_repo(const char *prefix, const char *path)
 {
 	int len = prefix ? strlen(prefix) : 0;
-	char *r = prefix_path_gently(prefix, len, path);
+	char *r = prefix_path_gently(prefix, len, NULL, path);
 	if (r) {
 		free(r);
 		return 1;
-- 
1.8.2.83.gc99314b

  parent reply	other threads:[~2013-06-09  6:29 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-09  6:25 [PATCH 00/45] "struct pathspec" conversion and :(glob) Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 01/45] clean: remove unused variable "seen" Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 02/45] Move struct pathspec and related functions to pathspec.[ch] Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 03/45] pathspec: i18n-ize error strings in pathspec parsing code Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 04/45] pathspec: add copy_pathspec Nguyễn Thái Ngọc Duy
2013-06-09  7:58   ` Eric Sunshine
2013-06-12 18:07     ` Junio C Hamano
2013-06-09  6:25 ` [PATCH 05/45] Add parse_pathspec() that converts cmdline args to struct pathspec Nguyễn Thái Ngọc Duy
2013-06-10  1:24   ` Eric Sunshine
2013-06-09  6:25 ` [PATCH 06/45] parse_pathspec: save original pathspec for reporting Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 07/45] parse_pathspec: add PATHSPEC_PREFER_{CWD,FULL} Nguyễn Thái Ngọc Duy
2013-06-10  1:29   ` Eric Sunshine
2013-06-09  6:25 ` [PATCH 08/45] Convert some get_pathspec() calls to parse_pathspec() Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 09/45] parse_pathspec: a special flag for max_depth feature Nguyễn Thái Ngọc Duy
2013-06-10  1:34   ` Eric Sunshine
2013-06-09  6:25 ` [PATCH 10/45] parse_pathspec: support stripping submodule trailing slashes Nguyễn Thái Ngọc Duy
2013-06-10  1:36   ` Eric Sunshine
2013-06-09  6:25 ` [PATCH 11/45] parse_pathspec: support stripping/checking submodule paths Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 12/45] parse_pathspec: support prefixing original patterns Nguyễn Thái Ngọc Duy
2013-06-10  1:41   ` Eric Sunshine
2013-06-09  6:25 ` [PATCH 13/45] Guard against new pathspec magic in pathspec matching code Nguyễn Thái Ngọc Duy
2013-06-10  1:53   ` Eric Sunshine
2013-06-09  6:25 ` [PATCH 14/45] clean: convert to use parse_pathspec Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 15/45] commit: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 16/45] status: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 17/45] rerere: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 18/45] checkout: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 19/45] rm: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 20/45] ls-files: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 21/45] archive: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 22/45] check-ignore: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 23/45] add: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 24/45] reset: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 25/45] line-log: " Nguyễn Thái Ngọc Duy
2013-06-09  6:25 ` [PATCH 26/45] Convert read_cache_preload() to take struct pathspec Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 27/45] Convert run_add_interactive to use " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 28/45] Convert unmerge_cache to take " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 29/45] checkout: convert read_tree_some " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 30/45] Convert report_path_error " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 31/45] Convert refresh_index " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 32/45] Convert {read,fill}_directory " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 33/45] Convert add_files_to_cache " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 34/45] Convert common_prefix() to use " Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 35/45] Remove diff_tree_{setup,release}_paths Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 36/45] Remove init_pathspec() in favor of parse_pathspec() Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 37/45] Remove match_pathspec() in favor of match_pathspec_depth() Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 38/45] tree-diff: remove the use of pathspec's raw[] in follow-rename codepath Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` Nguyễn Thái Ngọc Duy [this message]
2013-06-09  6:26 ` [PATCH 40/45] parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 41/45] Kill limit_pathspec_to_literal() as it's only used by parse_pathspec() Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 42/45] pathspec: support :(literal) syntax for noglob pathspec Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 43/45] pathspec: make --literal-pathspecs disable pathspec magic Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 44/45] pathspec: support :(glob) syntax Nguyễn Thái Ngọc Duy
2013-06-09  6:26 ` [PATCH 45/45] Rename field "raw" to "_raw" in struct pathspec Nguyễn Thái Ngọc Duy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1370759178-1709-40-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).