fetch-pack: always allow fetching of literal SHA1s
fetch-pack, when fetching a literal SHA-1 from a server that is not configured with uploadpack.allowtipsha1inwant (or similar), always returns an error message of the form "Server does not allow request for unadvertised object %s". However, it is sometimes the case that such object is advertised. This situation would occur, for example, if a user or a script was provided a SHA-1 instead of a branch or tag name for fetching, and wanted to invoke "git fetch" or "git fetch-pack" using that SHA-1. Teach fetch-pack to also check the SHA-1s of the refs in the received ref advertisement if a literal SHA-1 was given by the user. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									b06d364310
								
							
						
					
					
						commit
						fdb69d33c4
					
				
							
								
								
									
										40
									
								
								fetch-pack.c
								
								
								
								
							
							
						
						
									
										40
									
								
								fetch-pack.c
								
								
								
								
							|  | @ -15,6 +15,7 @@ | ||||||
| #include "version.h" | #include "version.h" | ||||||
| #include "prio-queue.h" | #include "prio-queue.h" | ||||||
| #include "sha1-array.h" | #include "sha1-array.h" | ||||||
|  | #include "oidset.h" | ||||||
|  |  | ||||||
| static int transfer_unpack_limit = -1; | static int transfer_unpack_limit = -1; | ||||||
| static int fetch_unpack_limit = -1; | static int fetch_unpack_limit = -1; | ||||||
|  | @ -592,13 +593,38 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void add_refs_to_oidset(struct oidset *oids, struct ref *refs) | ||||||
|  | { | ||||||
|  | 	for (; refs; refs = refs->next) | ||||||
|  | 		oidset_insert(oids, &refs->old_oid); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int tip_oids_contain(struct oidset *tip_oids, | ||||||
|  | 			    struct ref *unmatched, struct ref *newlist, | ||||||
|  | 			    const struct object_id *id) | ||||||
|  | { | ||||||
|  | 	/* | ||||||
|  | 	 * Note that this only looks at the ref lists the first time it's | ||||||
|  | 	 * called. This works out in filter_refs() because even though it may | ||||||
|  | 	 * add to "newlist" between calls, the additions will always be for | ||||||
|  | 	 * oids that are already in the set. | ||||||
|  | 	 */ | ||||||
|  | 	if (!tip_oids->map.tablesize) { | ||||||
|  | 		add_refs_to_oidset(tip_oids, unmatched); | ||||||
|  | 		add_refs_to_oidset(tip_oids, newlist); | ||||||
|  | 	} | ||||||
|  | 	return oidset_contains(tip_oids, id); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void filter_refs(struct fetch_pack_args *args, | static void filter_refs(struct fetch_pack_args *args, | ||||||
| 			struct ref **refs, | 			struct ref **refs, | ||||||
| 			struct ref **sought, int nr_sought) | 			struct ref **sought, int nr_sought) | ||||||
| { | { | ||||||
| 	struct ref *newlist = NULL; | 	struct ref *newlist = NULL; | ||||||
| 	struct ref **newtail = &newlist; | 	struct ref **newtail = &newlist; | ||||||
|  | 	struct ref *unmatched = NULL; | ||||||
| 	struct ref *ref, *next; | 	struct ref *ref, *next; | ||||||
|  | 	struct oidset tip_oids = OIDSET_INIT; | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
| 	i = 0; | 	i = 0; | ||||||
|  | @ -631,7 +657,8 @@ static void filter_refs(struct fetch_pack_args *args, | ||||||
| 			ref->next = NULL; | 			ref->next = NULL; | ||||||
| 			newtail = &ref->next; | 			newtail = &ref->next; | ||||||
| 		} else { | 		} else { | ||||||
| 			free(ref); | 			ref->next = unmatched; | ||||||
|  | 			unmatched = ref; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -648,7 +675,9 @@ static void filter_refs(struct fetch_pack_args *args, | ||||||
| 			continue; | 			continue; | ||||||
|  |  | ||||||
| 		if ((allow_unadvertised_object_request & | 		if ((allow_unadvertised_object_request & | ||||||
| 		    (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) { | 		     (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) || | ||||||
|  | 		    tip_oids_contain(&tip_oids, unmatched, newlist, | ||||||
|  | 				     &ref->old_oid)) { | ||||||
| 			ref->match_status = REF_MATCHED; | 			ref->match_status = REF_MATCHED; | ||||||
| 			*newtail = copy_ref(ref); | 			*newtail = copy_ref(ref); | ||||||
| 			newtail = &(*newtail)->next; | 			newtail = &(*newtail)->next; | ||||||
|  | @ -656,6 +685,13 @@ static void filter_refs(struct fetch_pack_args *args, | ||||||
| 			ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; | 			ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	oidset_clear(&tip_oids); | ||||||
|  | 	for (ref = unmatched; ref; ref = next) { | ||||||
|  | 		next = ref->next; | ||||||
|  | 		free(ref); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	*refs = newlist; | 	*refs = newlist; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -547,6 +547,41 @@ test_expect_success 'fetch-pack can fetch a raw sha1' ' | ||||||
| 	git fetch-pack hidden $(git -C hidden rev-parse refs/hidden/one) | 	git fetch-pack hidden $(git -C hidden rev-parse refs/hidden/one) | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'fetch-pack can fetch a raw sha1 that is advertised as a ref' ' | ||||||
|  | 	rm -rf server client && | ||||||
|  | 	git init server && | ||||||
|  | 	test_commit -C server 1 && | ||||||
|  |  | ||||||
|  | 	git init client && | ||||||
|  | 	git -C client fetch-pack ../server \ | ||||||
|  | 		$(git -C server rev-parse refs/heads/master) | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'fetch-pack can fetch a raw sha1 overlapping a named ref' ' | ||||||
|  | 	rm -rf server client && | ||||||
|  | 	git init server && | ||||||
|  | 	test_commit -C server 1 && | ||||||
|  | 	test_commit -C server 2 && | ||||||
|  |  | ||||||
|  | 	git init client && | ||||||
|  | 	git -C client fetch-pack ../server \ | ||||||
|  | 		$(git -C server rev-parse refs/tags/1) refs/tags/1 | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'fetch-pack cannot fetch a raw sha1 that is not advertised as a ref' ' | ||||||
|  | 	rm -rf server && | ||||||
|  |  | ||||||
|  | 	git init server && | ||||||
|  | 	test_commit -C server 5 && | ||||||
|  | 	git -C server tag -d 5 && | ||||||
|  | 	test_commit -C server 6 && | ||||||
|  |  | ||||||
|  | 	git init client && | ||||||
|  | 	test_must_fail git -C client fetch-pack ../server \ | ||||||
|  | 		$(git -C server rev-parse refs/heads/master^) 2>err && | ||||||
|  | 	test_i18ngrep "Server does not allow request for unadvertised object" err | ||||||
|  | ' | ||||||
|  |  | ||||||
| check_prot_path () { | check_prot_path () { | ||||||
| 	cat >expected <<-EOF && | 	cat >expected <<-EOF && | ||||||
| 	Diag: url=$1 | 	Diag: url=$1 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jonathan Tan
						Jonathan Tan