Re: Do "git add" as a builtin

4 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: Do "git add" as a builtin

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:42:26

Junio C Hamano [off-list ref] writes:
Linus Torvalds [off-list ref] writes:
quoted
On Wed, 17 May 2006, Junio C Hamano wrote:
quoted
By "not seeing the point", do you mean you do not agree with
what bba319b5 and 45e48120 tried to do to help users?
Naah, I just didn't see why, and didn't bother to go exploring.

How about this patch on top of the previous one?
Well, not good as-is.  This makes it barf on this sequence:
...
Ouch, things are worse than I thought...

	$ mkdir foo
        $ date >bar
        $ git-add foo/../bar
	$ git ls-files
        foo/../bar

Huh?

Re: Do "git add" as a builtin

From: Linus Torvalds <torvalds@osdl.org>
Date: 2016-06-15 22:42:26


On Thu, 18 May 2006, Junio C Hamano wrote:
Ouch, things are worse than I thought...

	$ mkdir foo
        $ date >bar
        $ git-add foo/../bar
	$ git ls-files
        foo/../bar

Huh?
"git-update-index" does a "verify_path()" which I missed, so the new 
builtin add doesn't do it.

We could do it either in the "add_cache_entry()" function (which would be 
safest, because then by _definition_ you couldn't make this mistake 
again), or we could do it in the caller.

This patch does it in the caller, just to match the old "git add" (which 
would just say "Ignoring path ..." and not do anything).

But if people are ok with changing it from a "print a warning and ignore" 
into an _error_, we could just move it into "add_cache_entry()".

The real _meat_ of this patch is really just that first hunk to 
"builtin-add.c" - all the rest is just making that "verify_path()" 
function available in the git library.

		Linus
---
diff --git a/builtin-add.c b/builtin-add.c
index 7083820..0346bb5 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -172,6 +172,11 @@ static int add_file_to_index(const char 
 	if (lstat(path, &st))
 		die("%s: unable to stat (%s)", path, strerror(errno));
 
+	if (!verify_path(path)) {
+		fprintf(stderr, "Ignoring path %s\n", path);
+		return -1;
+	}
+		
 	if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
 		die("%s: can only add regular files or symbolic links", path);
 
diff --git a/cache.h b/cache.h
index b1300cd..f9b7049 100644
--- a/cache.h
+++ b/cache.h
@@ -143,6 +143,7 @@ #define alloc_nr(x) (((x)+16)*3/2)
 /* Initialize and use the cache information */
 extern int read_cache(void);
 extern int write_cache(int newfd, struct cache_entry **cache, int entries);
+extern int verify_path(const char *path);
 extern int cache_name_pos(const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
diff --git a/read-cache.c b/read-cache.c
index ed0da38..6b323dd 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -347,6 +347,70 @@ int ce_path_match(const struct cache_ent
 }
 
 /*
+ * We fundamentally don't like some paths: we don't want
+ * dot or dot-dot anywhere, and for obvious reasons don't
+ * want to recurse into ".git" either.
+ *
+ * Also, we don't want double slashes or slashes at the
+ * end that can make pathnames ambiguous.
+ */
+static int verify_dotfile(const char *rest)
+{
+	/*
+	 * The first character was '.', but that
+	 * has already been discarded, we now test
+	 * the rest.
+	 */
+	switch (*rest) {
+	/* "." is not allowed */
+	case '\0': case '/':
+		return 0;
+
+	/*
+	 * ".git" followed by  NUL or slash is bad. This
+	 * shares the path end test with the ".." case.
+	 */
+	case 'g':
+		if (rest[1] != 'i')
+			break;
+		if (rest[2] != 't')
+			break;
+		rest += 2;
+	/* fallthrough */
+	case '.':
+		if (rest[1] == '\0' || rest[1] == '/')
+			return 0;
+	}
+	return 1;
+}
+
+int verify_path(const char *path)
+{
+	char c;
+
+	goto inside;
+	for (;;) {
+		if (!c)
+			return 1;
+		if (c == '/') {
+inside:
+			c = *path++;
+			switch (c) {
+			default:
+				continue;
+			case '/': case '\0':
+				break;
+			case '.':
+				if (verify_dotfile(path))
+					continue;
+			}
+			return 0;
+		}
+		c = *path++;
+	}
+}
+
+/*
  * Do we have another file that has the beginning components being a
  * proper superset of the name we're trying to add?
  */
diff --git a/update-index.c b/update-index.c
index f6b09a4..69b9a71 100644
--- a/update-index.c
+++ b/update-index.c
@@ -8,6 +8,7 @@ #include "strbuf.h"
 #include "quote.h"
 #include "cache-tree.h"
 #include "tree-walk.h"
+#include "dir.h"
 
 /*
  * Default to not allowing changes to the list of files. The
@@ -245,70 +246,6 @@ static int refresh_cache(int really)
 	return has_errors;
 }
 
-/*
- * We fundamentally don't like some paths: we don't want
- * dot or dot-dot anywhere, and for obvious reasons don't
- * want to recurse into ".git" either.
- *
- * Also, we don't want double slashes or slashes at the
- * end that can make pathnames ambiguous.
- */
-static int verify_dotfile(const char *rest)
-{
-	/*
-	 * The first character was '.', but that
-	 * has already been discarded, we now test
-	 * the rest.
-	 */
-	switch (*rest) {
-	/* "." is not allowed */
-	case '\0': case '/':
-		return 0;
-
-	/*
-	 * ".git" followed by  NUL or slash is bad. This
-	 * shares the path end test with the ".." case.
-	 */
-	case 'g':
-		if (rest[1] != 'i')
-			break;
-		if (rest[2] != 't')
-			break;
-		rest += 2;
-	/* fallthrough */
-	case '.':
-		if (rest[1] == '\0' || rest[1] == '/')
-			return 0;
-	}
-	return 1;
-}
-
-static int verify_path(const char *path)
-{
-	char c;
-
-	goto inside;
-	for (;;) {
-		if (!c)
-			return 1;
-		if (c == '/') {
-inside:
-			c = *path++;
-			switch (c) {
-			default:
-				continue;
-			case '/': case '\0':
-				break;
-			case '.':
-				if (verify_dotfile(path))
-					continue;
-			}
-			return 0;
-		}
-		c = *path++;
-	}
-}
-
 static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
 			 const char *path, int stage)
 {

Re: Do "git add" as a builtin

From: Linus Torvalds <torvalds@osdl.org>
Date: 2016-06-15 22:42:26


On Thu, 18 May 2006, Linus Torvalds wrote:
But if people are ok with changing it from a "print a warning and ignore" 
into an _error_, we could just move it into "add_cache_entry()".
This is the incremental patch to do that instead, if you prefer it.

Putting it into add_cache_entry() definitely has advantages, in that it 
should make it much harder for this bug to happen again - all users will 
now be verified.

With this one, it's now a fatal error to try to add a pathname that cannot 
be added, ie

	[torvalds@g5 git]$ git add .git/config 
	fatal: unable to add .git/config to index

and

	[torvalds@g5 git]$ git add foo/../bar 
	fatal: unable to add foo/../bar to index

instead of the old "Ignoring path xyz" warning that would end up silently 
succeeding on any other paths.

		Linus

---
diff --git a/builtin-add.c b/builtin-add.c
index 0346bb5..ac9ed2d 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -172,11 +172,6 @@ static int add_file_to_index(const char 
 	if (lstat(path, &st))
 		die("%s: unable to stat (%s)", path, strerror(errno));
 
-	if (!verify_path(path)) {
-		fprintf(stderr, "Ignoring path %s\n", path);
-		return -1;
-	}
-		
 	if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
 		die("%s: can only add regular files or symbolic links", path);
 
diff --git a/read-cache.c b/read-cache.c
index 6b323dd..9a272f8 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -551,6 +551,8 @@ int add_cache_entry(struct cache_entry *
 
 	if (!ok_to_add)
 		return -1;
+	if (!verify_path(ce->name))
+		return -1;
 
 	if (!skip_df_check &&
 	    check_file_directory_conflict(ce, pos, ok_to_replace)) {

Re: Do "git add" as a builtin

From: Linus Torvalds <torvalds@osdl.org>
Date: 2016-06-15 22:42:26


On Thu, 18 May 2006, Linus Torvalds wrote:
quoted
But if people are ok with changing it from a "print a warning and ignore" 
into an _error_, we could just move it into "add_cache_entry()".
This is the incremental patch to do that instead, if you prefer it.
Thinking some more about it, I think I personally much prefer this.

Especially as a quick look-through seems to say that there's actually a 
path through git-update-index too that allows a unverified filename to get 
into the index (the new "--unresolve" thing also misses the need to verify 
the path).

Making it a fatal error makes it more obvious that the user did something 
fundamentally wrong. And the safety in doing it in add_cache_entry() just 
makes be happier, particularly in light of the above problem with 
--unresolve.

That still leaves the question of whether we should also drop all the 
"verify_path()" calls in update-index.c, and make it fatal there too. I 
think we probably should.

(At that point we could turn verify_path() back into a static function, 
this time local entirely to read-cache.c, rather than update-index.c)

			Linus
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help