Skip to contentSkip to conversation

git archive broken in 1.7.8.1

BUG In review Albert Astals Cid 8 participants 30 messages Jun 15, 2016

lore
Share & tools
lore
#0 lore raw

CC me on answers since i'm not subscribed to the list

Hi, one of our [KDE] anongit servers was updated to 1.7.8.1 and not the syntax

git archive --remote=git://anongit.kde.org/repo.git HEAD:path

does not seem to return a valid tar archive anymore when it did work previously. In fact the man page of my version has that syntax in one of the examples.

Is that a regression or should have never it worked and the current behaviour is the correct one?

Albert

#1 lore raw
Quoted 5 lines · Albert Astals Cid

CC me on answers since i'm not subscribed to the list

Hi, one of our [KDE] anongit servers was updated to 1.7.8.1 and not the syntax

git archive --remote=git://anongit.kde.org/repo.git HEAD:path

This syntax is no longer allowed due to some security tightening. Use the alternate syntax

    git archive --remote=git://anongit.kde.org/repo.git HEAD -- path
Quoted 4 lines

does not seem to return a valid tar archive anymore when it did work previously. In fact the man page of my version has that syntax in one of the examples.

That sounds like a documentation bug.

cmn

#2 lore raw

El Dimarts, 10 de gener de 2012, a les 22:33:44, Carlos Martín Nieto va escriure:

Quoted 6 lines · Albert Astals Cid
Quoted 5 lines

CC me on answers since i'm not subscribed to the list

Hi, one of our [KDE] anongit servers was updated to 1.7.8.1 and not the syntax

Quoted 6 lines
Quoted 1 line

git archive --remote=git://anongit.kde.org/repo.git HEAD:path

This syntax is no longer allowed due to some security tightening. Use the alternate syntax

    git archive --remote=git://anongit.kde.org/repo.git HEAD -- path

Unfortunately this producess a tarball with a different layout, e.g.

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD:doc/en_US
gives me a tarball with the doc/en_US files in the root

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD -- doc/en_US
gives me a tarball with the doc/en_US folders and then the files

Is there a way to keep the old behaviour or do we need to update our scripts?

Thanks for the fast answer!

Albert

Quoted 8 lines
Quoted 4 lines

does not seem to return a valid tar archive anymore when it did work previously. In fact the man page of my version has that syntax in one of the examples.

That sounds like a documentation bug.

cmn

#3 lore raw
Quoted 17 lines · Albert Astals Cid

El Dimarts, 10 de gener de 2012, a les 22:33:44, Carlos Martín Nieto va escriure:

Quoted 6 lines · Albert Astals Cid
Quoted 5 lines

CC me on answers since i'm not subscribed to the list

Hi, one of our [KDE] anongit servers was updated to 1.7.8.1 and not the syntax

Quoted 6 lines
Quoted 1 line

git archive --remote=git://anongit.kde.org/repo.git HEAD:path

This syntax is no longer allowed due to some security tightening. Use the alternate syntax

    git archive --remote=git://anongit.kde.org/repo.git HEAD -- path

Unfortunately this producess a tarball with a different layout, e.g.

Quoted 7 lines

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD:doc/en_US
gives me a tarball with the doc/en_US files in the root

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD -- doc/en_US
gives me a tarball with the doc/en_US folders and then the files

Is there a way to keep the old behaviour or do we need to update our scripts?

Not as far as I know. However, the commit that hardened the input (ee27ca4a781844: archive: don't let remote clients get unreachable commits, 2011-11-17) does state that HEAD:doc/en_US should be valid, so it looks like it's actually a regression. As it's bedtime in my timezone, I'm blaming Peff and I'll look into this if it hasn't been fixed by the time I get to the office tomorrow.

Quoted 11 lines

Thanks for the fast answer!

Albert

Quoted 6 lines
Quoted 4 lines

does not seem to return a valid tar archive anymore when it did work previously. In fact the man page of my version has that syntax in one of the examples.

That sounds like a documentation bug.

Notice that the syntax is for the local case, not for --remote.

cmn

#4 lore raw
Quoted 8 lines · Carlos Martín Nieto
Quoted 8 lines

Unfortunately this producess a tarball with a different layout, e.g.

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD:doc/en_US
gives me a tarball with the doc/en_US files in the root

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD -- doc/en_US
gives me a tarball with the doc/en_US folders and then the files

Quoted 8 lines
Quoted 1 line

Is there a way to keep the old behaviour or do we need to update our scripts?

Not as far as I know. However, the commit that hardened the input (ee27ca4a781844: archive: don't let remote clients get unreachable commits, 2011-11-17) does state that HEAD:doc/en_US should be valid, so it looks like it's actually a regression. As it's bedtime in my timezone, I'm blaming Peff and I'll look into this if it hasn't been fixed by the time I get to the office tomorrow.

It is definitely my fault. According to ee27ca4a, sub-trees were an unfortunate casualty of the tightening. However, I did have some patches that moved towards allowing things like that safely (basically the rev parser needs to pass more context back to the caller).

It's evening here and I'm doing family stuff, but I'll take a look either late tonight or tomorrow morning.

-Peff

#5 lore raw

PATCH 1/1 archive: re-allow HEAD:Documentation on a remote invocation

The tightening done in (ee27ca4a: archive: don't let remote clients get unreachable commits, 2011-11-17) went too far and disallowed HEAD:Documentation as it would try to find "HEAD:Documentation" as a ref.

Only DWIM the "HEAD" part to see if it exists as a ref. Once we're sure that we've been given a valid ref, we follow the normal code path. This still disallows attempts to access commits which are not branch tips.

---

AFAICT this should still be safe. Using HEAD^:Documentation or <sha1>:Documentation still complains that HEAD^ and <sha1> aren't refs.

 archive.c |   19 +++++++++++++------
 1 files changed, 13 insertions(+), 6 deletions(-)
archive.c +13 -6
index 164bbd0..4735bfb 100644
@@ -260,14 +260,21 @@ static void parse_treeish_arg(const char **argv,
 	/* Remotes are only allowed to fetch actual refs */
 	if (remote) {
 		char *ref = NULL;
-		if (!dwim_ref(name, strlen(name), sha1, &ref))
-			die("no such ref: %s", name);
+		const char *refname, *colon = NULL;
+
+		colon = strchr(name, ':');
+		if (colon)
+			refname = xstrndup(name, colon - name);
+		else
+			refname = name;
+
+		if (!dwim_ref(refname, strlen(refname), sha1, &ref))
+			die("no such ref: %s", refname);
 		free(ref);
 	}
-	else {
-		if (get_sha1(name, sha1))
-			die("Not a valid object name");
-	}
+
+	if (get_sha1(name, sha1))
+		die("Not a valid object name");
 
 	commit = lookup_commit_reference_gently(sha1, 1);
 	if (commit) {
Signature · 1 line
1.7.8.352.g876a6f
#6 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

Quoted 9 lines · Carlos Martín Nieto

The tightening done in (ee27ca4a: archive: don't let remote clients get unreachable commits, 2011-11-17) went too far and disallowed HEAD:Documentation as it would try to find "HEAD:Documentation" as a ref.

Only DWIM the "HEAD" part to see if it exists as a ref. Once we're sure that we've been given a valid ref, we follow the normal code path. This still disallows attempts to access commits which are not branch tips.

I'd rather not do this kind of ad-hoc parsing of sha1s in the archive code, and instead let the regular resolution process tell us more about what it did, so we can make a policy decision at the upper level.

Patches to follow:

[1/2]: get_sha1_with_context: report features used in resolution [2/2]: archive: loosen restrictions on remote object lookup

Quoted 3 lines

AFAICT this should still be safe. Using HEAD^:Documentation or <sha1>:Documentation still complains that HEAD^ and <sha1> aren't refs.

My patches enable things like HEAD^, but disallow a raw sha1. The only way to safely allow a raw sha1 is to check its connectivity from the tips, which can be somewhat expensive (you have to traverse every tree of every commit in the worst case).

-Peff

#7 lore raw

PATCH 1/2 get_sha1_with_context: report features used in resolution

Most callers generally treat get_sha1 as a black box, giving it a string from the user and expecting to get a sha1 in return. The get_sha1_with_context function gives callers more information about what happened while resolving the object name so they can make better decisions about how to use the result. We currently use this only to provide information about the path entry used to find a blob.

We don't currently provide any information about the resolution rules that were used to reach the final object. Some callers may want these in order to enforce a policy that a particular subset of the lookup rules are used (e.g., when serving remote requests).

This patch adds a set of bit-fields that document the use of particular features during an object lookup.

---
The diffstat looks a little scary, but it is mostly just the internal get_sha1 functions learning to pass the object_context around.

 cache.h     |    7 +++++
 sha1_name.c |   73 +++++++++++++++++++++++++++++++++++++---------------------
 2 files changed, 53 insertions(+), 27 deletions(-)
cache.h +7 -0
index 10afd71..ac25a37 100644
@@ -809,6 +809,13 @@ struct object_context {
 	unsigned char tree[20];
 	char path[PATH_MAX];
 	unsigned mode;
+	unsigned used_ref:1,
+		 used_reflog:1,
+		 used_index:1,
+		 used_nth_checkout:1,
+		 used_describe_name:1,
+		 used_oneline:1,
+		 used_raw_hex:1;
 };
 
 extern int get_sha1(const char *str, unsigned char *sha1);
sha1_name.c +46 -27

239 lines not on this page · raw message

Signature · 1 line
1.7.9.rc0.33.gd3c17
#8 lore raw

Re: [PATCH 1/2] get_sha1_with_context: report features used in resolution

Quoted 14 lines · Jeff King

Most callers generally treat get_sha1 as a black box, giving it a string from the user and expecting to get a sha1 in return. The get_sha1_with_context function gives callers more information about what happened while resolving the object name so they can make better decisions about how to use the result. We currently use this only to provide information about the path entry used to find a blob.

We don't currently provide any information about the resolution rules that were used to reach the final object. Some callers may want these in order to enforce a policy that a particular subset of the lookup rules are used (e.g., when serving remote requests).

Quoted 7 lines

This patch adds a set of bit-fields that document the use of particular features during an object lookup.

---
The diffstat looks a little scary, but it is mostly just the internal get_sha1 functions learning to pass the object_context around.

Hmm, shouldn't this also cover peel_to_type()? That would have made it also apply to the maintenance track.

#9 lore raw

Re: [PATCH 1/2] get_sha1_with_context: report features used in resolution

Quoted 19 lines · Junio C Hamano
Quoted 17 lines · Jeff King

Most callers generally treat get_sha1 as a black box, giving it a string from the user and expecting to get a sha1 in return. The get_sha1_with_context function gives callers more information about what happened while resolving the object name so they can make better decisions about how to use the result. We currently use this only to provide information about the path entry used to find a blob.

We don't currently provide any information about the resolution rules that were used to reach the final object. Some callers may want these in order to enforce a policy that a particular subset of the lookup rules are used (e.g., when serving remote requests).

This patch adds a set of bit-fields that document the use of particular features during an object lookup.

Quoted 7 lines
Quoted 4 lines

---
The diffstat looks a little scary, but it is mostly just the internal get_sha1 functions learning to pass the object_context around.

Hmm, shouldn't this also cover peel_to_type()? That would have made it also apply to the maintenance track.

I don't see how peel_to_type is relevant. As far as get_sha1 is concerned, the interesting thing is actually calling peel_onion. It does get the context passed to it in my patch, but I didn't bother marking that the peel feature was used (because it wasn't relevant to the policy I wanted to implement in the follow-on patch).

But we could pretty easily mark the use of the peel feature, too.

I'm not sure what you mean about the maintenance track, though. AFAICT, we don't separately call peel_to_type, but just potentially use it as part of get_sha1_with_context. Am I missing something?

-Peff

#10 lore raw

PATCH 2/2 archive: loosen restrictions on remote object lookup

In reply to Jeff King

Initially, "git upload-archive" would feed the tree specification from the remote side directly into get_sha1, giving the remote user the full power of the object name resolver. This was convenient, but it also meant that remote users could fetch disconnected trees by their sha1s, which violates the long-standing behavior of upload-pack not to make such objects available.

Later, commit ee27ca4 tightened this to use dwim_ref instead of get_sha1 for the remote case, allowing only the use of actual refs. Unfortunately, this broke some existing use cases, like fetching sub-trees with "$ref:subdir".

This patch loosens the restrictions to re-enable those use cases. It does this by using get_sha1_with_context for the object lookup, and checking that only allowable features were used.

---
 archive.c                     |   34 ++++++++++++++-------
 t/t5002-archive-resolution.sh |   66 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 11 deletions(-)
 create mode 100755 t/t5002-archive-resolution.sh
archive.c +23 -11
index 164bbd0..a031bde 100644
@@ -246,6 +246,25 @@ static void parse_pathspec_arg(const char **pathspec,
 	}
 }
 
+static int check_object_context(int remote, const struct object_context *oc)
+{
+	/* For local requests, allow anything */
+	if (!remote)
+		return 1;
+	/*
+	 * Otherwise, require that we accessed the object through a ref,
+	 * but not have used any of the advanced features like looking in
+	 * the reflog.
+	 */
+	return oc->used_ref &&
+	       !oc->used_reflog &&
+	       !oc->used_index &&
+	       !oc->used_nth_checkout &&
+	       !oc->used_describe_name &&
+	       !oc->used_oneline &&
+	       !oc->used_raw_hex;
+}
+
 static void parse_treeish_arg(const char **argv,
 		struct archiver_args *ar_args, const char *prefix,
 		int remote)
@@ -256,18 +275,11 @@ static void parse_treeish_arg(const char **argv,
 	struct tree *tree;
 	const struct commit *commit;
 	unsigned char sha1[20];
+	struct object_context oc;
 
-	/* Remotes are only allowed to fetch actual refs */
-	if (remote) {
-		char *ref = NULL;
-		if (!dwim_ref(name, strlen(name), sha1, &ref))
-			die("no such ref: %s", name);
-		free(ref);
-	}
-	else {
-		if (get_sha1(name, sha1))
-			die("Not a valid object name");
-	}
+	if (get_sha1_with_context(name, sha1, &oc) ||
+	    !check_object_context(remote, &oc))
+		die("Not a valid object name");
 
 	commit = lookup_commit_reference_gently(sha1, 1);
 	if (commit) {
t/t5002-archive-resolution.sh new file +66 -0

66 lines not on this page · raw message

Signature · 1 line
1.7.9.rc0.33.gd3c17
#11 lore raw

Re: [PATCH 2/2] archive: loosen restrictions on remote object lookup

So, did this patch make it anywhere? We could really use it.

Here's the use case. The original ee27ca4 patch broke our build system when the git server was upgraded to Debian Wheezy last night. The builder fetches source from the repo in two pieces using git archive, and we need to make sure both pieces are from the same commit. So we get a sha1 hash with git ls-remote, and use it with git archive --remote. This, of course, breaks with the 'no such ref' error.

At the very least, the documentation is wrong when it talks about passing a commit ID to git archive: maintainers must surely agree that the documentation and the actual behavior ought to match.

Personally, I'd like to see this patch adopted.

Thanks for listening,
Ian

#12 lore raw

Re: [PATCH 2/2] archive: loosen restrictions on remote object lookup

Quoted 8 lines · Ian Harvey

So, did this patch make it anywhere? We could really use it.

Here's the use case. The original ee27ca4 patch broke our build system when the git server was upgraded to Debian Wheezy last night. The builder fetches source from the repo in two pieces using git archive, and we need to make sure both pieces are from the same commit. So we get a sha1 hash with git ls-remote, and use it with git archive --remote. This, of course, breaks with the 'no such ref' error.

The patch you are responding to[1] would not help there, either. It does not allow raw sha1s. The only way to do that would be:

1. Add an option to the server to allow arbitrary sha1s, even if they are not reachable from the ref tips. This is an easy fix, but requires server admins to cooperate (and they may or may not want to lose the "you can only access reachable things policy".

2. Actually do a reachability check. Doing a full object check to allow fetching an arbitrary tree by sha1 is probably prohibitively expensive[2], but we could allow the form "<commit>[:<path>]", check that "<commit>" is reachable, and then allow arbitrary paths within it.

Quoted 3 lines

At the very least, the documentation is wrong when it talks about passing a commit ID to git archive: maintainers must surely agree that the documentation and the actual behavior ought to match.

I am not sure which documentation you mean. The part about "commit ID" in the current manpage is drawing the distinction between something that resolves to a commit versus something that resolves to a tree. Either is available both locally and remotely. I think the use of the phrase "commit ID" is questionable there, as it really means "something that resolves to a commit", not "a sha1 commit ID". We used to use the phrase "commit-ish" to refer to that, but I think it has fallen out of favor as being too jargon-y.

The documentation does not mention at all the restrictions placed on refs using "--remote", and it probably should.

-Peff

[1] http://article.gmane.org/gmane.comp.version-control.git/188387

[2] If we had a reachability bitmap cache, calculating arbitrary object reachability would actually be pretty cheap. But the bitmap feature for core git is not yet ready for prime-time, so I think we should not depend on it yet.

#13 lore raw

cover real reachability checks for upload-archive

Quoted 5 lines · Jeff King

2. Actually do a reachability check. Doing a full object check to allow fetching an arbitrary tree by sha1 is probably prohibitively expensive[2], but we could allow the form "<commit>[:<path>]", check that "<commit>" is reachable, and then allow arbitrary paths within it.

Thinking on this more, the full reachability check is no worse than what a clone has to do to fetch the full repository. Here's a series that does the full check. I'm not entirely happy with the performance, though; details are in patch 3.

I think I'd be tempted to just go the more limiting "commit is reachable" route, instead, which would solve your case (and most sane cases).

[1/4]: clear parsed flag when we free tree buffers
[2/4]: upload-archive: restrict remote objects with reachability check [3/4]: list-objects: optimize "revs->blob_objects = 0" case [4/4]: archive: ignore blob objects when checking reachability

-Peff

#14 lore raw

PATCH 1/4 clear parsed flag when we free tree buffers

Many code paths will free a tree object's buffer and set it to NULL after finishing with it in order to keep memory usage down during a traversal. However, out of 8 sites that do this, only one actually unsets the "parsed" flag back. Those sites that don't are setting a trap for later users of the tree object; even after calling parse_tree, the buffer will remain NULL, causing potential segfaults.

It is not known whether this is triggerable in the current code. Most commands do not do an in-memory traversal followed by actually using the objects again. However, it does not hurt to be safe for future callers.

In most cases, we can abstract this out to a "free_tree_buffer" helper. However, there are two exceptions:

1. The fsck code relies on the parsed flag to know that we were able to parse the object at one point. We can switch this to using a flag in the "flags" field.

2. The index-pack code sets the buffer to NULL but does not free it (it is freed by a caller). We should still unset the parsed flag here, but we cannot use our helper, as we do not want to free the buffer.

---
This shouldn't have any behavior change, but I'd worry a bit that I missed some case in builtin/fsck.c where the new HAS_OBJ flag would need set.

 builtin/fsck.c       | 17 ++++++++---------
 builtin/index-pack.c |  1 +
 builtin/reflog.c     |  3 +--
 http-push.c          |  3 +--
 list-objects.c       |  3 +--
 reachable.c          |  3 +--
 revision.c           |  3 +--
 tree.c               |  8 ++++++++
 tree.h               |  1 +
 walker.c             |  5 +----
 10 files changed, 24 insertions(+), 23 deletions(-)
builtin/fsck.c +8 -9
index bb9a2cd..579fdcc 100644
@@ -16,6 +16,7 @@
 
 #define REACHABLE 0x0001
 #define SEEN      0x0002
+#define HAS_OBJ   0x0004
 
 static int show_root;
 static int show_tags;
@@ -101,7 +102,7 @@ static int mark_object(struct object *obj, int type, void *data)
 	if (obj->flags & REACHABLE)
 		return 0;
 	obj->flags |= REACHABLE;
-	if (!obj->parsed) {
+	if (!(obj->flags & HAS_OBJ)) {
 		if (parent && !has_sha1_file(obj->sha1)) {
 			printf("broken link from %7s %s\n",
 				 typename(parent->type), sha1_to_hex(parent->sha1));
@@ -127,16 +128,13 @@ static int traverse_one_object(struct object *obj)
 	struct tree *tree = NULL;
 
 	if (obj->type == OBJ_TREE) {
-		obj->parsed = 0;
 		tree = (struct tree *)obj;
 		if (parse_tree(tree) < 0)
 			return 1; /* error already displayed */
 	}
 	result = fsck_walk(obj, mark_object, obj);
-	if (tree) {
-		free(tree->buffer);
-		tree->buffer = NULL;
-	}
+	if (tree)
+		free_tree_buffer(tree);
 	return result;
 }
 
@@ -178,7 +176,7 @@ static void check_reachable_object(struct object *obj)
 	 * except if it was in a pack-file and we didn't
 	 * do a full fsck
 	 */
-	if (!obj->parsed) {
+	if (!(obj->flags & HAS_OBJ)) {
 		if (has_sha1_pack(obj->sha1))
 			return; /* it is in pack - forget about it */
 		printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
@@ -306,8 +304,7 @@ static int fsck_obj(struct object *obj)
 	if (obj->type == OBJ_TREE) {
 		struct tree *item = (struct tree *) obj;
 
-		free(item->buffer);
-		item->buffer = NULL;
+		free_tree_buffer(item);
 	}
 
 	if (obj->type == OBJ_COMMIT) {
@@ -340,6 +337,7 @@ static int fsck_sha1(const unsigned char *sha1)
 		return error("%s: object corrupt or missing",
 			     sha1_to_hex(sha1));
 	}
+	obj->flags |= HAS_OBJ;
 	return fsck_obj(obj);
 }
 
@@ -352,6 +350,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
 		errors_found |= ERROR_OBJECT;
 		return error("%s: object corrupt or missing", sha1_to_hex(sha1));
 	}
+	obj->flags = HAS_OBJ;
 	return fsck_obj(obj);
 }
 
builtin/index-pack.c +1 -0
index 79dfe47..20cf284 100644
@@ -765,6 +765,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
 			if (obj->type == OBJ_TREE) {
 				struct tree *item = (struct tree *) obj;
 				item->buffer = NULL;
+				obj->parsed = 0;
 			}
 			if (obj->type == OBJ_COMMIT) {
 				struct commit *commit = (struct commit *) obj;
builtin/reflog.c +1 -2
index 54184b3..ba27f7c 100644
@@ -94,8 +94,7 @@ static int tree_is_complete(const unsigned char *sha1)
 			complete = 0;
 		}
 	}
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 
 	if (complete)
 		tree->object.flags |= SEEN;
http-push.c +1 -2
index 395a8cf..c13b441 100644
@@ -1330,8 +1330,7 @@ static struct object_list **process_tree(struct tree *tree,
 			break;
 		}
 
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 	return p;
 }
 
list-objects.c +1 -2
index 3dd4a96..c8c3463 100644
@@ -123,8 +123,7 @@ static void process_tree(struct rev_info *revs,
 				     cb_data);
 	}
 	strbuf_setlen(base, baselen);
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 }
 
 static void mark_edge_parents_uninteresting(struct commit *commit,
reachable.c +1 -2
index e7e6a1e..654a8c5 100644
@@ -80,8 +80,7 @@ static void process_tree(struct tree *tree,
 		else
 			process_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);
 	}
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 }
 
 static void process_tag(struct tag *tag, struct object_array *p,
revision.c +1 -2
index 518cd08..eb988ee 100644
@@ -135,8 +135,7 @@ void mark_tree_uninteresting(struct tree *tree)
 	 * We don't care about the tree any more
 	 * after it has been marked uninteresting.
 	 */
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 }
 
 void mark_parents_uninteresting(struct commit *commit)
tree.c +8 -0
index 62fed63..1cbf60e 100644
@@ -225,6 +225,14 @@ int parse_tree(struct tree *item)
 	return parse_tree_buffer(item, buffer, size);
 }
 
+void free_tree_buffer(struct tree *tree)
+{
+	free(tree->buffer);
+	tree->buffer = NULL;
+	tree->size = 0;
+	tree->object.parsed = 0;
+}
+
 struct tree *parse_tree_indirect(const unsigned char *sha1)
 {
 	struct object *obj = parse_object(sha1);
tree.h +1 -0
index 69bcb5e..601ab9c 100644
@@ -16,6 +16,7 @@ int parse_tree(struct tree *tree);
 int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
 
 int parse_tree(struct tree *tree);
+void free_tree_buffer(struct tree *tree);
 
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const unsigned char *sha1);
walker.c +1 -4
index be389dc..633596e 100644
@@ -56,10 +56,7 @@ static int process_tree(struct walker *walker, struct tree *tree)
 		if (!obj || process(walker, obj))
 			return -1;
 	}
-	free(tree->buffer);
-	tree->buffer = NULL;
-	tree->size = 0;
-	tree->object.parsed = 0;
+	free_tree_buffer(tree);
 	return 0;
 }
 
Signature · 1 line
1.8.3.rc2.14.g7eee6b3
#15 lore raw

Re: [PATCH 1/4] clear parsed flag when we free tree buffers

Quoted 26 lines · Jeff King

Many code paths will free a tree object's buffer and set it to NULL after finishing with it in order to keep memory usage down during a traversal. However, out of 8 sites that do this, only one actually unsets the "parsed" flag back. Those sites that don't are setting a trap for later users of the tree object; even after calling parse_tree, the buffer will remain NULL, causing potential segfaults.

It is not known whether this is triggerable in the current code. Most commands do not do an in-memory traversal followed by actually using the objects again. However, it does not hurt to be safe for future callers.

In most cases, we can abstract this out to a "free_tree_buffer" helper. However, there are two exceptions:

1. The fsck code relies on the parsed flag to know that we were able to parse the object at one point. We can switch this to using a flag in the "flags" field.

2. The index-pack code sets the buffer to NULL but does not free it (it is freed by a caller). We should still unset the parsed flag here, but we cannot use our helper, as we do not want to free the buffer.

Quoted 5 lines

---
This shouldn't have any behavior change, but I'd worry a bit that I missed some case in builtin/fsck.c where the new HAS_OBJ flag would need set.

check-unreachable-object?

I am wondering if you can use SEEN which is already there, or at least set HAS_OBJ at the same place where SEEN is set.

The overall structure of fsck is:

* we scan objects we see in the object store; they are marked with SEEN to avoid duplicated work in fsck_obj() and this scanning does not have anything to do with connectivity; then

* we traverse connectivity graph from the starting points (refs, index, etc.).

and this obj->parsed check is used in the latter phase, so...

An unrelated tangent.

I suspect that 271b8d25b25 made a copy&paste error to "broken link" message in builtin/fsck.c while looking at this patch, by the way. The "lookup_object() to compute the first parameter given to the callback in fsck_walk() returned NULL" case has two "from"; the latter should be "to" (and I think in the longer term the function signature of the callback needs to be enhanced to let us tell what object name we found in "parent" that failed to give us an object).

Quoted 215 lines
 builtin/fsck.c       | 17 ++++++++---------
 builtin/index-pack.c |  1 +
 builtin/reflog.c     |  3 +--
 http-push.c          |  3 +--
 list-objects.c       |  3 +--
 reachable.c          |  3 +--
 revision.c           |  3 +--
 tree.c               |  8 ++++++++
 tree.h               |  1 +
 walker.c             |  5 +----
 10 files changed, 24 insertions(+), 23 deletions(-)
builtin/fsck.c +8 -9
index bb9a2cd..579fdcc 100644
@@ -16,6 +16,7 @@
 
 #define REACHABLE 0x0001
 #define SEEN      0x0002
+#define HAS_OBJ   0x0004
 
 static int show_root;
 static int show_tags;
@@ -101,7 +102,7 @@ static int mark_object(struct object *obj, int type, void *data)
 	if (obj->flags & REACHABLE)
 		return 0;
 	obj->flags |= REACHABLE;
-	if (!obj->parsed) {
+	if (!(obj->flags & HAS_OBJ)) {
 		if (parent && !has_sha1_file(obj->sha1)) {
 			printf("broken link from %7s %s\n",
 				 typename(parent->type), sha1_to_hex(parent->sha1));
@@ -127,16 +128,13 @@ static int traverse_one_object(struct object *obj)
 	struct tree *tree = NULL;
 
 	if (obj->type == OBJ_TREE) {
-		obj->parsed = 0;
 		tree = (struct tree *)obj;
 		if (parse_tree(tree) < 0)
 			return 1; /* error already displayed */
 	}
 	result = fsck_walk(obj, mark_object, obj);
-	if (tree) {
-		free(tree->buffer);
-		tree->buffer = NULL;
-	}
+	if (tree)
+		free_tree_buffer(tree);
 	return result;
 }
 
@@ -178,7 +176,7 @@ static void check_reachable_object(struct object *obj)
 	 * except if it was in a pack-file and we didn't
 	 * do a full fsck
 	 */
-	if (!obj->parsed) {
+	if (!(obj->flags & HAS_OBJ)) {
 		if (has_sha1_pack(obj->sha1))
 			return; /* it is in pack - forget about it */
 		printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
@@ -306,8 +304,7 @@ static int fsck_obj(struct object *obj)
 	if (obj->type == OBJ_TREE) {
 		struct tree *item = (struct tree *) obj;
 
-		free(item->buffer);
-		item->buffer = NULL;
+		free_tree_buffer(item);
 	}
 
 	if (obj->type == OBJ_COMMIT) {
@@ -340,6 +337,7 @@ static int fsck_sha1(const unsigned char *sha1)
 		return error("%s: object corrupt or missing",
 			     sha1_to_hex(sha1));
 	}
+	obj->flags |= HAS_OBJ;
 	return fsck_obj(obj);
 }
 
@@ -352,6 +350,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
 		errors_found |= ERROR_OBJECT;
 		return error("%s: object corrupt or missing", sha1_to_hex(sha1));
 	}
+	obj->flags = HAS_OBJ;
 	return fsck_obj(obj);
 }
 
builtin/index-pack.c +1 -0
index 79dfe47..20cf284 100644
@@ -765,6 +765,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
 			if (obj->type == OBJ_TREE) {
 				struct tree *item = (struct tree *) obj;
 				item->buffer = NULL;
+				obj->parsed = 0;
 			}
 			if (obj->type == OBJ_COMMIT) {
 				struct commit *commit = (struct commit *) obj;
builtin/reflog.c +1 -2
index 54184b3..ba27f7c 100644
@@ -94,8 +94,7 @@ static int tree_is_complete(const unsigned char *sha1)
 			complete = 0;
 		}
 	}
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 
 	if (complete)
 		tree->object.flags |= SEEN;
http-push.c +1 -2
index 395a8cf..c13b441 100644
@@ -1330,8 +1330,7 @@ static struct object_list **process_tree(struct tree *tree,
 			break;
 		}
 
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 	return p;
 }
 
list-objects.c +1 -2
index 3dd4a96..c8c3463 100644
@@ -123,8 +123,7 @@ static void process_tree(struct rev_info *revs,
 				     cb_data);
 	}
 	strbuf_setlen(base, baselen);
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 }
 
 static void mark_edge_parents_uninteresting(struct commit *commit,
reachable.c +1 -2
index e7e6a1e..654a8c5 100644
@@ -80,8 +80,7 @@ static void process_tree(struct tree *tree,
 		else
 			process_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);
 	}
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 }
 
 static void process_tag(struct tag *tag, struct object_array *p,
revision.c +1 -2
index 518cd08..eb988ee 100644
@@ -135,8 +135,7 @@ void mark_tree_uninteresting(struct tree *tree)
 	 * We don't care about the tree any more
 	 * after it has been marked uninteresting.
 	 */
-	free(tree->buffer);
-	tree->buffer = NULL;
+	free_tree_buffer(tree);
 }
 
 void mark_parents_uninteresting(struct commit *commit)
tree.c +8 -0
index 62fed63..1cbf60e 100644
@@ -225,6 +225,14 @@ int parse_tree(struct tree *item)
 	return parse_tree_buffer(item, buffer, size);
 }
 
+void free_tree_buffer(struct tree *tree)
+{
+	free(tree->buffer);
+	tree->buffer = NULL;
+	tree->size = 0;
+	tree->object.parsed = 0;
+}
+
 struct tree *parse_tree_indirect(const unsigned char *sha1)
 {
 	struct object *obj = parse_object(sha1);
tree.h +1 -0
index 69bcb5e..601ab9c 100644
@@ -16,6 +16,7 @@ int parse_tree(struct tree *tree);
 int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
 
 int parse_tree(struct tree *tree);
+void free_tree_buffer(struct tree *tree);
 
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const unsigned char *sha1);
walker.c +1 -4
index be389dc..633596e 100644
@@ -56,10 +56,7 @@ static int process_tree(struct walker *walker, struct tree *tree)
 		if (!obj || process(walker, obj))
 			return -1;
 	}
-	free(tree->buffer);
-	tree->buffer = NULL;
-	tree->size = 0;
-	tree->object.parsed = 0;
+	free_tree_buffer(tree);
 	return 0;
 }
#16 lore raw

PATCH 2/4 upload-archive: restrict remote objects with reachability check

In reply to Jeff King

When serving a remote request, git-upload-archive tries to restrict access to unreachable objects, which matches the behavior of upload-pack. However, we did so by restricting the requested tree to "<ref>[:<path>]", because it is fast. That covers the common cases, but does not allow requesting items by a specific sha1 (either a tree or a commit sha1).

Instead, let's do the correct-but-slower method of actually walking back from the tips to see if the requested object is reachable. The performance impact of this is roughly:

1. For a recent commit, the speed is about the same (we traverse in reverse chronological order, so we see it almost immediately).

2. For an older commit, even one pointed at directly by a ref (e.g., an old tag), we are slower, because we traverse from the more recent tips. We are bounded in this case by the time to look at all commits (i.e., "time git rev-list --all").

3. When we see "$ref:$path", we typically perform much worse, because our traversal looks at all commits first, followed by all trees.

4. The worst case (which we hit for an unreachable object) is equivalent to "time rev-list --objects --all", which is about the same amount of time pack-objects spends preparing a full clone (which can be in the tens of seconds for a large repository).

The implementation is a fairly straightforward application of the traverse_commit_list function. Using the mark_objects_reachable function would seem more appropriate, but it has no mechanism for looking for a specific object, which lets us end the traversal early in common cases.

---
The slowdown from points (2) and (3) makes me hesitate on this. We can address (2) by checking if the get_sha1 lookup used a refname explicitly, but I'm no sure about (3).

 archive.c                     | 70 +++++++++++++++++++++++++++------
 t/t5005-archive-resolution.sh | 91 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+), 11 deletions(-)
 create mode 100755 t/t5005-archive-resolution.sh
archive.c +59 -11
index d254fa5..4d77624 100644
@@ -5,6 +5,9 @@
 #include "archive.h"
 #include "parse-options.h"
 #include "unpack-trees.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
 
 static char const * const archive_usage[] = {
 	N_("git archive [options] <tree-ish> [<path>...]"),
@@ -241,6 +244,59 @@ static void parse_pathspec_arg(const char **pathspec,
 	}
 }
 
+struct reachable_object_data {
+	struct rev_info revs;
+	struct object *obj;
+};
+
+static void check_object(struct object *obj, const struct name_path *path,
+			 const char *name, void *vdata)
+{
+	struct reachable_object_data *data = vdata;
+	/*
+	 * We found it; the caller will take care of marking it SEEN,
+	 * but we can end the traversal early.
+	 */
+	if (obj == data->obj) {
+		free_commit_list(data->revs.commits);
+		data->revs.commits = NULL;
+
+		free(data->revs.pending.objects);
+		data->revs.pending.nr = 0;
+		data->revs.pending.alloc = 0;
+		data->revs.pending.objects = NULL;
+	}
+}
+
+static void check_commit(struct commit *commit, void *vdata)
+{
+	check_object(&commit->object, NULL, NULL, vdata);
+}
+
+static int object_is_reachable(const unsigned char *sha1)
+{
+	static const char *argv[] = {
+		"rev-list",
+		"--objects",
+		"--all",
+		NULL
+	};
+	struct reachable_object_data data;
+
+	data.obj = parse_object(sha1);
+	if (!data.obj)
+		return 0;
+
+	save_commit_buffer = 0;
+	init_revisions(&data.revs, NULL);
+	setup_revisions(ARRAY_SIZE(argv) - 1, argv, &data.revs, NULL);
+	if (prepare_revision_walk(&data.revs))
+		return 0;
+
+	traverse_commit_list(&data.revs, check_commit, check_object, &data);
+	return data.obj->flags & SEEN;
+}
+
 static void parse_treeish_arg(const char **argv,
 		struct archiver_args *ar_args, const char *prefix,
 		int remote)
@@ -252,20 +308,12 @@ static void parse_treeish_arg(const char **argv,
 	const struct commit *commit;
 	unsigned char sha1[20];
 
-	/* Remotes are only allowed to fetch actual refs */
-	if (remote) {
-		char *ref = NULL;
-		const char *colon = strchr(name, ':');
-		int refnamelen = colon ? colon - name : strlen(name);
-
-		if (!dwim_ref(name, refnamelen, sha1, &ref))
-			die("no such ref: %.*s", refnamelen, name);
-		free(ref);
-	}
-
 	if (get_sha1(name, sha1))
 		die("Not a valid object name");
 
+	if (remote && !object_is_reachable(sha1))
+		die("Not a valid object name");
+
 	commit = lookup_commit_reference_gently(sha1, 1);
 	if (commit) {
 		commit_sha1 = commit->object.sha1;
t/t5005-archive-resolution.sh new file +91 -0

91 lines not on this page · raw message

Signature · 1 line
1.8.3.rc2.14.g7eee6b3
#17 lore raw

PATCH 3/4 list-objects: optimize "revs->blob_objects = 0" case

In reply to Jeff King

If we are traversing trees during a "--objects" traversal, we may skip blobs if the "blob_objects" field of rev_info is not set. But we do so as the first thing in process_blob(), only after we have actually created the "struct blob" object, incurring a hash lookup. We can optimize out this no-op call completely.

This does not actually affect any current code, as all of the current traversals always set blob_objects when looking at objects, anyway.

---
 list-objects.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
list-objects.c +1 -1
index c8c3463..77e6ec5 100644
@@ -116,7 +116,7 @@ static void process_tree(struct rev_info *revs,
 			process_gitlink(revs, entry.sha1,
 					show, &me, entry.path,
 					cb_data);
-		else
+		else if (revs->blob_objects)
 			process_blob(revs,
 				     lookup_blob(entry.sha1),
 				     show, &me, entry.path,
Signature · 1 line
1.8.3.rc2.14.g7eee6b3
#18 lore raw

PATCH 4/4 archive: ignore blob objects when checking reachability

In reply to Jeff King

We cannot create an archive from a blob object, so we would not expect anyone to provide one to us. And if they do, we will fail anyway just after the reachability check. We can therefore optimize our reachability check to ignore blobs completely, and not even create a "struct blob" for them.

Depending on the repository size and the exact place we find the reachable object in the traversal, this can save 20-25%, a we can avoid many lookups in the object hash.

The downside of this is that a blob provided to a remote archive process will fail with "no such object" rather than "object is not a tree" (we could organize the code to retain the old message, but since we no longer know whether the blob is reachable or not, we would potentially be leaking information about the existence of unreachable objects).

---
 archive.c | 1 +
 1 file changed, 1 insertion(+)
archive.c +1 -0
index 4d77624..98691cd 100644
@@ -290,6 +290,7 @@ static int object_is_reachable(const unsigned char *sha1)
 	save_commit_buffer = 0;
 	init_revisions(&data.revs, NULL);
 	setup_revisions(ARRAY_SIZE(argv) - 1, argv, &data.revs, NULL);
+	data.revs.blob_objects = 0;
 	if (prepare_revision_walk(&data.revs))
 		return 0;
 
Signature · 1 line
1.8.3.rc2.14.g7eee6b3
#19 lore raw

Re: [PATCH 4/4] archive: ignore blob objects when checking reachability

Quoted 10 lines · Jeff King

We cannot create an archive from a blob object, so we would not expect anyone to provide one to us. And if they do, we will fail anyway just after the reachability check. We can therefore optimize our reachability check to ignore blobs completely, and not even create a "struct blob" for them.

Depending on the repository size and the exact place we find the reachable object in the traversal, this can save 20-25%, a we can avoid many lookups in the object hash.

Quoted 6 lines

The downside of this is that a blob provided to a remote archive process will fail with "no such object" rather than "object is not a tree" (we could organize the code to retain the old message, but since we no longer know whether the blob is reachable or not, we would potentially be leaking information about the existence of unreachable objects).

Could we change the error message to "no such tree object" to be non-committal about the reason for the failure?

For a moment I thought that one could get correct error messages while retaining the speed gain in the usual case by doing a quick object lookup, and then

check type of object
if object is missing:
die(there is no such object)
else if object is a blob:
do reachability test including blobs
if object is not reachable:
die(there is no such object)
else
die(object is not a tree)
else
do reachability test excluding blobs
etc

However, even this would leak information about the existence of nonreachable objects to a client measuring time time for the response because the death due to non-reachability would take longer than death due to missing object. So, if one would insist on correct error messages and no information leakage, one could just skip the first "object is missing" optimization (it should be pretty rare anyway!) like so:

check type of object
if object is missing or object is a blob:
/* Force the same delay in either case: */ do reachability test including blobs
if object is missing or object is not reachable:
die(there is no such object)
else
die(object is not a tree)
else
do reachability test excluding blobs etc

I'm not suggesting that the extra effort is worth it; I just wanted to mention the possibility.

Michael

Signature · 3 lines
Michael Haggerty
[email protected]
http://softwareswirl.blogspot.com/
#20 lore raw

Re: [PATCH 4/4] archive: ignore blob objects when checking reachability

In reply to Jeff King
Quoted 9 lines · Jeff King

We cannot create an archive from a blob object, so we would not expect anyone to provide one to us. And if they do, we will fail anyway just after the reachability check. We can therefore optimize our reachability check to ignore blobs completely, and not even create a "struct blob" for them.

Depending on the repository size and the exact place we find the reachable object in the traversal, this can save 20-25%, a we can avoid many lookups in the object hash.

s/a/as/

Quoted 8 lines

The downside of this is that a blob provided to a remote archive process will fail with "no such object" rather than "object is not a tree" (we could organize the code to retain the old message, but since we no longer know whether the blob is reachable or not, we would potentially be leaking information about the existence of unreachable objects).

#21 lore raw

Re: [RFC/PATCH 0/4] real reachability checks for upload-archive

In reply to Jeff King
Quoted 8 lines · Jeff King
Quoted 5 lines · Jeff King

2. Actually do a reachability check. Doing a full object check to allow fetching an arbitrary tree by sha1 is probably prohibitively expensive[2], but we could allow the form "<commit>[:<path>]", check that "<commit>" is reachable, and then allow arbitrary paths within it.

Quoted 4 lines

Thinking on this more, the full reachability check is no worse than what a clone has to do to fetch the full repository. Here's a series that does the full check. I'm not entirely happy with the performance, though; details are in patch 3.

For some repository-servers, it may be OK to enable this by default, but I suspect it would be better to have at least an opt-out server configuration.

Quoted 3 lines

I think I'd be tempted to just go the more limiting "commit is reachable" route, instead, which would solve your case (and most sane cases).

Yes, I think that is a reasonable thing to do. After all, as you noted in 4/4, you cannot ask for a single blob, and not being able to ask for a single tree is not much different.

Quoted 6 lines

[1/4]: clear parsed flag when we free tree buffers
[2/4]: upload-archive: restrict remote objects with reachability check [3/4]: list-objects: optimize "revs->blob_objects = 0" case [4/4]: archive: ignore blob objects when checking reachability

-Peff

#22 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

In reply to Carlos Martín Nieto
Quoted 4 lines · Carlos Martín Nieto

The tightening done in (ee27ca4a: archive: don't let remote clients get unreachable commits, 2011-11-17) went too far and disallowed HEAD:Documentation as it would try to find "HEAD:Documentation" as a ref.

I do not think it went too far. Actually we discussed this exact issue when the topic was cooking, and saw no objections. The commit in question itself advertises this restriction.

Why are we loosening it now? I do not see a compelling reason to do so.

Quoted 10 lines

Only DWIM the "HEAD" part to see if it exists as a ref. Once we're sure that we've been given a valid ref, we follow the normal code path. This still disallows attempts to access commits which are not branch tips.

---
AFAICT this should still be safe. Using HEAD^:Documentation or <sha1>:Documentation still complains that HEAD^ and <sha1> aren't refs.

Having said that, I think I agree this is a safe thing to do, _if_ we want to loosen it.

#23 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

Quoted 10 lines · Junio C Hamano
Quoted 4 lines · Carlos Martín Nieto

The tightening done in (ee27ca4a: archive: don't let remote clients get unreachable commits, 2011-11-17) went too far and disallowed HEAD:Documentation as it would try to find "HEAD:Documentation" as a ref.

I do not think it went too far. Actually we discussed this exact issue when the topic was cooking, and saw no objections. The commit in question itself advertises this restriction.

I think you and I discussed it off list (I originally took this off-list because the original issue did have some security implications). So I don't think people necessarily had a chance to object.

Quoted 1 line

Why are we loosening it now? I do not see a compelling reason to do so.

I see it the opposite way. People are clearly using the "$ref:$path" syntax. So why would we restrict them from doing so? There are no security implications (i.e., they could always just grab $ref and extract $path themselves). In my view, ee27ca4a was over-eager in its restrictions because I wanted it to be simple and close the hole. Now we can take our time adding more code to loosen it.

-Peff

#24 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

Quoted 9 lines · Jeff King
Quoted 7 lines · Junio C Hamano
Quoted 4 lines · Carlos Martín Nieto

The tightening done in (ee27ca4a: archive: don't let remote clients get unreachable commits, 2011-11-17) went too far and disallowed HEAD:Documentation as it would try to find "HEAD:Documentation" as a ref.

Quoted 7 lines
Quoted 3 lines

I do not think it went too far. Actually we discussed this exact issue when the topic was cooking, and saw no objections. The commit in question itself advertises this restriction.

I think you and I discussed it off list (I originally took this off-list because the original issue did have some security implications). So I don't think people necessarily had a chance to object.

Here is the only on-list discussion:

http://article.gmane.org/gmane.comp.version-control.git/186366

Quoted below:

Quoted 9 lines
Quoted 9 lines

* jk/maint-1.6.2-upload-archive (2011-11-21) 1 commit
- archive: don't let remote clients get unreachable commits (this branch is used by jk/maint-upload-archive.)

* jk/maint-upload-archive (2011-11-21) 1 commit
- Merge branch 'jk/maint-1.6.2-upload-archive' into jk/maint-upload-archive
(this branch uses jk/maint-1.6.2-upload-archive.)

Quoted 5 lines
Quoted 1 line

Will merge to 'next' after taking another look.

Thanks. I also have some followup patches to re-loosen to at least trees reachable from refs. Do you want to leave the tightening to the maint track, and then consider the re-loosening for master?

I was planning to first have the really tight version graduate to 'master' and ship it in 1.7.9, while possibly merging that to 1.7.8.X series. If we hear complaints from real users in the meantime before or after such releases, we could apply loosening patch on top of these topics and call them "regression fix", but I have been assuming that nobody would have been using this backdoor for anything that really matters.

So now we have heard a complaint. :)

-Peff

#25 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

In reply to Jeff King
Quoted 6 lines · Jeff King

I see it the opposite way. People are clearly using the "$ref:$path" syntax. So why would we restrict them from doing so? There are no security implications (i.e., they could always just grab $ref and extract $path themselves). In my view, ee27ca4a was over-eager in its restrictions because I wanted it to be simple and close the hole. Now we can take our time adding more code to loosen it.

Ok, so it is more like a partial revert of whatever we did. In that case, I'd take CMN's patch to limit the extent of the changes, as it more closely matches the spirit of the original ee27ca4 (archive: don't let remote clients get unreachable commits, 2011-11-17) that singled out and catered to the need of "archive" command alone. It is already part of the v1.7.8.1 release, so I would prefer a change to be stupid and simple.

#26 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

Quoted 9 lines · Junio C Hamano
Quoted 6 lines · Jeff King

I see it the opposite way. People are clearly using the "$ref:$path" syntax. So why would we restrict them from doing so? There are no security implications (i.e., they could always just grab $ref and extract $path themselves). In my view, ee27ca4a was over-eager in its restrictions because I wanted it to be simple and close the hole. Now we can take our time adding more code to loosen it.

Quoted 6 lines

Ok, so it is more like a partial revert of whatever we did. In that case, I'd take CMN's patch to limit the extent of the changes, as it more closely matches the spirit of the original ee27ca4 (archive: don't let remote clients get unreachable commits, 2011-11-17) that singled out and catered to the need of "archive" command alone. It is already part of the v1.7.8.1 release, so I would prefer a change to be stupid and simple.

For a maint release, I am OK with that. In the long term, I'd rather my patches go onto master (either for 1.7.9 or for later), as I think they are the right way to do it.

-Peff

#27 lore raw

Re: [PATCH] archive: re-allow HEAD:Documentation on a remote invocation

Quoted 3 lines · Jeff King

For a maint release, I am OK with that. In the long term, I'd rather my patches go onto master (either for 1.7.9 or for later), as I think they are the right way to do it.

I would prefer not to use it in 1.7.9, as CMN's patch will make its only immediate user disappear. I think we are in agreement that the change to carry context around is a longer term thing, and when we apply it, the safety we added to "archive" will become simpler.

#28 lore raw
In reply to Albert Astals Cid
Quoted 4 lines · Albert Astals Cid

Unfortunately this producess a tarball with a different layout, e.g.

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD:doc/en_US
gives me a tarball with the doc/en_US files in the root

Meaning the files you have stored in git under doc/en_US are dumped in the root directory of the tar? That does not sound like desired behavior for the feature.

/Allan

Signature · 3 lines
Allan Wind
Life Integrity, LLC
<http://lifeintegrity.com>
#29 lore raw
Quoted 9 lines · Allan Wind
Quoted 4 lines · Albert Astals Cid

Unfortunately this producess a tarball with a different layout, e.g.

git archive --remote=git://anongit.kde.org/kgraphviewer.git HEAD:doc/en_US
gives me a tarball with the doc/en_US files in the root

Meaning the files you have stored in git under doc/en_US are dumped in the root directory of the tar? That does not sound like desired behavior for the feature.

Which feature do you mean? Using HEAD:doc/en_US should be equivalent to running tar cf - . from inside the doc/en_US, as what you're passing is that tree.

Using HEAD -- doc/en_US however means that you want to pack HEAD, but limit it to files that match doc/en_US, so it's working as designed. If you mean that 'HEAD -- doc/en_US' shouldn't give you a tar with those files at the root, then we agree.

cmn