From cbbe50db7691cd9d7d261ebc5c5ffec55f93127d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 18 Jan 2013 15:48:49 -0800 Subject: upload-pack: share more code We mark the objects pointed at our refs with "OUR_REF" flag in two functions (mark_our_ref() and send_ref()), but we can just use the former as a helper for the latter. Update the way mark_our_ref() prepares in-core object to use lookup_unknown_object() to delay reading the actual object data, just like we did in 435c833 (upload-pack: use peel_ref for ref advertisements, 2012-10-04). Signed-off-by: Junio C Hamano --- upload-pack.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index 95d83135ae..3dd220d685 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -722,15 +722,28 @@ static void receive_needs(void) free(shallows.objects); } +static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +{ + struct object *o = lookup_unknown_object(sha1); + if (!o) + die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); + if (!(o->flags & OUR_REF)) { + o->flags |= OUR_REF; + nr_our_refs++; + } + return 0; +} + static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" " include-tag multi_ack_detailed"; - struct object *o = lookup_unknown_object(sha1); const char *refname_nons = strip_namespace(refname); unsigned char peeled[20]; + mark_our_ref(refname, sha1, flag, cb_data); + if (capabilities) packet_write(1, "%s %s%c%s%s agent=%s\n", sha1_to_hex(sha1), refname_nons, @@ -740,27 +753,11 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo else packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons); capabilities = NULL; - if (!(o->flags & OUR_REF)) { - o->flags |= OUR_REF; - nr_our_refs++; - } if (!peel_ref(refname, peeled)) packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons); return 0; } -static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) -{ - struct object *o = parse_object(sha1); - if (!o) - die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); - if (!(o->flags & OUR_REF)) { - o->flags |= OUR_REF; - nr_our_refs++; - } - return 0; -} - static void upload_pack(void) { if (advertise_refs || !stateless_rpc) { -- cgit v1.2.1 From 3f1da57fffdcfb48bd8b85da347f310b955245d7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 28 Jan 2013 20:45:43 -0800 Subject: upload-pack: simplify request validation Long time ago, we used to punt on a large (read: asking for more than 256 refs) fetch request and instead sent a full pack, because we couldn't fit many refs on the command line of rev-list we run internally to enumerate the objects to be sent. To fix this, 565ebbf (upload-pack: tighten request validation., 2005-10-24), added a check to count the number of refs in the request and matched with the number of refs we advertised, and changed the invocation of rev-list to pass "--all" to it, still keeping us under the command line argument limit. However, these days we feed the list of objects requested and the list of objects the other end is known to have via standard input, so there is no longer a valid reason to special case a full clone request. Remove the code associated with "create_full_pack" to simplify the logic. Signed-off-by: Junio C Hamano --- upload-pack.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index 3dd220d685..3a26a7bc0d 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -28,7 +28,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; -static int multi_ack, nr_our_refs; +static int multi_ack; static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; @@ -139,7 +139,6 @@ static void create_pack_file(void) { struct async rev_list; struct child_process pack_objects; - int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); char data[8193], progress[128]; char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; @@ -151,9 +150,7 @@ static void create_pack_file(void) argv[arg++] = "pack-objects"; if (!shallow_nr) { argv[arg++] = "--revs"; - if (create_full_pack) - argv[arg++] = "--all"; - else if (use_thin_pack) + if (use_thin_pack) argv[arg++] = "--thin"; } @@ -185,15 +182,15 @@ static void create_pack_file(void) } else { FILE *pipe_fd = xfdopen(pack_objects.in, "w"); - if (!create_full_pack) { - int i; - for (i = 0; i < want_obj.nr; i++) - fprintf(pipe_fd, "%s\n", sha1_to_hex(want_obj.objects[i].item->sha1)); - fprintf(pipe_fd, "--not\n"); - for (i = 0; i < have_obj.nr; i++) - fprintf(pipe_fd, "%s\n", sha1_to_hex(have_obj.objects[i].item->sha1)); - } + int i; + for (i = 0; i < want_obj.nr; i++) + fprintf(pipe_fd, "%s\n", + sha1_to_hex(want_obj.objects[i].item->sha1)); + fprintf(pipe_fd, "--not\n"); + for (i = 0; i < have_obj.nr; i++) + fprintf(pipe_fd, "%s\n", + sha1_to_hex(have_obj.objects[i].item->sha1)); fprintf(pipe_fd, "\n"); fflush(pipe_fd); fclose(pipe_fd); @@ -727,10 +724,7 @@ static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag struct object *o = lookup_unknown_object(sha1); if (!o) die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); - if (!(o->flags & OUR_REF)) { - o->flags |= OUR_REF; - nr_our_refs++; - } + o->flags |= OUR_REF; return 0; } -- cgit v1.2.1 From daebaa78137d59693a808c1f0bdec0ecb40fc12e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 18 Jan 2013 16:08:30 -0800 Subject: upload/receive-pack: allow hiding ref hierarchies A repository may have refs that are only used for its internal bookkeeping purposes that should not be exposed to the others that come over the network. Teach upload-pack to omit some refs from its initial advertisement by paying attention to the uploadpack.hiderefs multi-valued configuration variable. Do the same to receive-pack via the receive.hiderefs variable. As a convenient short-hand, allow using transfer.hiderefs to set the value to both of these variables. Any ref that is under the hierarchies listed on the value of these variable is excluded from responses to requests made by "ls-remote", "fetch", etc. (for upload-pack) and "push" (for receive-pack). Because these hidden refs do not count as OUR_REF, an attempt to fetch objects at the tip of them will be rejected, and because these refs do not get advertised, "git push :" will not see local branches that have the same name as them as "matching" ones to be sent. An attempt to update/delete these hidden refs with an explicit refspec, e.g. "git push origin :refs/hidden/22", is rejected. This is not a new restriction. To the pusher, it would appear that there is no such ref, so its push request will conclude with "Now that I sent you all the data, it is time for you to update the refs. I saw that the ref did not exist when I started pushing, and I want the result to point at this commit". The receiving end will apply the compare-and-swap rule to this request and rejects the push with "Well, your update request conflicts with somebody else; I see there is such a ref.", which is the right thing to do. Otherwise a push to a hidden ref will always be "the last one wins", which is not a good default. Signed-off-by: Junio C Hamano --- upload-pack.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'upload-pack.c') diff --git a/upload-pack.c b/upload-pack.c index 3a26a7bc0d..dec0237793 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -12,6 +12,7 @@ #include "run-command.h" #include "sigchain.h" #include "version.h" +#include "string-list.h" static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=] "; @@ -719,9 +720,13 @@ static void receive_needs(void) free(shallows.objects); } +/* return non-zero if the ref is hidden, otherwise 0 */ static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct object *o = lookup_unknown_object(sha1); + + if (ref_is_hidden(refname)) + return 1; if (!o) die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); o->flags |= OUR_REF; @@ -736,7 +741,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo const char *refname_nons = strip_namespace(refname); unsigned char peeled[20]; - mark_our_ref(refname, sha1, flag, cb_data); + if (mark_our_ref(refname, sha1, flag, cb_data)) + return 0; if (capabilities) packet_write(1, "%s %s%c%s%s agent=%s\n", @@ -773,6 +779,11 @@ static void upload_pack(void) } } +static int upload_pack_config(const char *var, const char *value, void *unused) +{ + return parse_hide_refs_config(var, value, "uploadpack"); +} + int main(int argc, char **argv) { char *dir; @@ -824,6 +835,7 @@ int main(int argc, char **argv) die("'%s' does not appear to be a git repository", dir); if (is_repository_shallow()) die("attempt to fetch/clone from a shallow repository"); + git_config(upload_pack_config, NULL); if (getenv("GIT_DEBUG_SEND_PACK")) debug_fd = atoi(getenv("GIT_DEBUG_SEND_PACK")); upload_pack(); -- cgit v1.2.1