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 "prio-queue.h" | ||||
| #include "sha1-array.h" | ||||
| #include "oidset.h" | ||||
|  | ||||
| static int transfer_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, | ||||
| 			struct ref **refs, | ||||
| 			struct ref **sought, int nr_sought) | ||||
| { | ||||
| 	struct ref *newlist = NULL; | ||||
| 	struct ref **newtail = &newlist; | ||||
| 	struct ref *unmatched = NULL; | ||||
| 	struct ref *ref, *next; | ||||
| 	struct oidset tip_oids = OIDSET_INIT; | ||||
| 	int i; | ||||
|  | ||||
| 	i = 0; | ||||
|  | @ -631,7 +657,8 @@ static void filter_refs(struct fetch_pack_args *args, | |||
| 			ref->next = NULL; | ||||
| 			newtail = &ref->next; | ||||
| 		} else { | ||||
| 			free(ref); | ||||
| 			ref->next = unmatched; | ||||
| 			unmatched = ref; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | @ -648,7 +675,9 @@ static void filter_refs(struct fetch_pack_args *args, | |||
| 			continue; | ||||
|  | ||||
| 		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; | ||||
| 			*newtail = copy_ref(ref); | ||||
| 			newtail = &(*newtail)->next; | ||||
|  | @ -656,6 +685,13 @@ static void filter_refs(struct fetch_pack_args *args, | |||
| 			ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	oidset_clear(&tip_oids); | ||||
| 	for (ref = unmatched; ref; ref = next) { | ||||
| 		next = ref->next; | ||||
| 		free(ref); | ||||
| 	} | ||||
|  | ||||
| 	*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) | ||||
| ' | ||||
|  | ||||
| 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 () { | ||||
| 	cat >expected <<-EOF && | ||||
| 	Diag: url=$1 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Jonathan Tan
						Jonathan Tan