summaryrefslogtreecommitdiff
path: root/upload-pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'upload-pack.c')
-rw-r--r--upload-pack.c158
1 files changed, 87 insertions, 71 deletions
diff --git a/upload-pack.c b/upload-pack.c
index aa84576500..44d63fba41 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -35,7 +35,11 @@ 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;
-static int allow_tip_sha1_in_want;
+/* Allow specifying sha1 if it is a ref tip. */
+#define ALLOW_TIP_SHA1 01
+/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
+#define ALLOW_REACHABLE_SHA1 02
+static unsigned int allow_unadvertised_object_request;
static int shallow_nr;
static struct object_array have_obj;
static struct object_array want_obj;
@@ -54,27 +58,28 @@ static void reset_timeout(void)
alarm(timeout);
}
-static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
+static void send_client_data(int fd, const char *data, ssize_t sz)
{
- if (use_sideband)
- return send_sideband(1, fd, data, sz, use_sideband);
+ if (use_sideband) {
+ send_sideband(1, fd, data, sz, use_sideband);
+ return;
+ }
if (fd == 3)
/* emergency quit */
fd = 2;
if (fd == 2) {
/* XXX: are we happy to lose stuff here? */
xwrite(fd, data, sz);
- return sz;
+ return;
}
write_or_die(fd, data, sz);
- return sz;
}
static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
{
FILE *fp = cb_data;
if (graft->nr_parent == -1)
- fprintf(fp, "--shallow %s\n", sha1_to_hex(graft->sha1));
+ fprintf(fp, "--shallow %s\n", oid_to_hex(&graft->oid));
return 0;
}
@@ -86,35 +91,32 @@ static void create_pack_file(void)
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[13];
- int i, arg = 0;
+ int i;
FILE *pipe_fd;
if (shallow_nr) {
- argv[arg++] = "--shallow-file";
- argv[arg++] = "";
+ argv_array_push(&pack_objects.args, "--shallow-file");
+ argv_array_push(&pack_objects.args, "");
}
- argv[arg++] = "pack-objects";
- argv[arg++] = "--revs";
+ argv_array_push(&pack_objects.args, "pack-objects");
+ argv_array_push(&pack_objects.args, "--revs");
if (use_thin_pack)
- argv[arg++] = "--thin";
+ argv_array_push(&pack_objects.args, "--thin");
- argv[arg++] = "--stdout";
+ argv_array_push(&pack_objects.args, "--stdout");
if (shallow_nr)
- argv[arg++] = "--shallow";
+ argv_array_push(&pack_objects.args, "--shallow");
if (!no_progress)
- argv[arg++] = "--progress";
+ argv_array_push(&pack_objects.args, "--progress");
if (use_ofs_delta)
- argv[arg++] = "--delta-base-offset";
+ argv_array_push(&pack_objects.args, "--delta-base-offset");
if (use_include_tag)
- argv[arg++] = "--include-tag";
- argv[arg++] = NULL;
+ argv_array_push(&pack_objects.args, "--include-tag");
pack_objects.in = -1;
pack_objects.out = -1;
pack_objects.err = -1;
pack_objects.git_cmd = 1;
- pack_objects.argv = argv;
if (start_command(&pack_objects))
die("git upload-pack: unable to fork git-pack-objects");
@@ -126,14 +128,14 @@ static void create_pack_file(void)
for (i = 0; i < want_obj.nr; i++)
fprintf(pipe_fd, "%s\n",
- sha1_to_hex(want_obj.objects[i].item->sha1));
+ oid_to_hex(&want_obj.objects[i].item->oid));
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));
+ oid_to_hex(&have_obj.objects[i].item->oid));
for (i = 0; i < extra_edge_obj.nr; i++)
fprintf(pipe_fd, "%s\n",
- sha1_to_hex(extra_edge_obj.objects[i].item->sha1));
+ oid_to_hex(&extra_edge_obj.objects[i].item->oid));
fprintf(pipe_fd, "\n");
fflush(pipe_fd);
fclose(pipe_fd);
@@ -173,8 +175,7 @@ static void create_pack_file(void)
if (ret < 0) {
if (errno != EINTR) {
- error("poll failed, resuming: %s",
- strerror(errno));
+ error_errno("poll failed, resuming");
sleep(1);
}
continue;
@@ -229,9 +230,7 @@ static void create_pack_file(void)
}
else
buffered = -1;
- sz = send_client_data(1, data, sz);
- if (sz < 0)
- goto fail;
+ send_client_data(1, data, sz);
}
/*
@@ -258,9 +257,7 @@ static void create_pack_file(void)
/* flush the data */
if (0 <= buffered) {
data[0] = buffered;
- sz = send_client_data(1, data, 1);
- if (sz < 0)
- goto fail;
+ send_client_data(1, data, 1);
fprintf(stderr, "flushed.\n");
}
if (use_sideband)
@@ -312,17 +309,15 @@ static int reachable(struct commit *want)
commit_list_insert_by_date(want, &work);
while (work) {
- struct commit_list *list = work->next;
- struct commit *commit = work->item;
- free(work);
- work = list;
+ struct commit_list *list;
+ struct commit *commit = pop_commit(&work);
if (commit->object.flags & THEY_HAVE) {
want->object.flags |= COMMON_KNOWN;
break;
}
if (!commit->object.parsed)
- parse_object(commit->object.sha1);
+ parse_object(commit->object.oid.hash);
if (commit->object.flags & REACHABLE)
continue;
commit->object.flags |= REACHABLE;
@@ -442,8 +437,9 @@ static int get_common_commits(void)
static int is_our_ref(struct object *o)
{
- return o->flags &
- ((allow_tip_sha1_in_want ? HIDDEN_REF : 0) | OUR_REF);
+ int allow_hidden_ref = (allow_unadvertised_object_request &
+ (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
+ return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);
}
static void check_non_tip(void)
@@ -456,8 +452,12 @@ static void check_non_tip(void)
char namebuf[42]; /* ^ + SHA-1 + LF */
int i;
- /* In the normal in-process case non-tip request can never happen */
- if (!stateless_rpc)
+ /*
+ * In the normal in-process case without
+ * uploadpack.allowReachableSHA1InWant,
+ * non-tip requests can never happen.
+ */
+ if (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))
goto error;
cmd.argv = argv;
@@ -484,7 +484,7 @@ static void check_non_tip(void)
continue;
if (!is_our_ref(o))
continue;
- memcpy(namebuf + 1, sha1_to_hex(o->sha1), 40);
+ memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
if (write_in_full(cmd.in, namebuf, 42) < 0)
goto error;
}
@@ -493,7 +493,7 @@ static void check_non_tip(void)
o = want_obj.objects[i].item;
if (is_our_ref(o))
continue;
- memcpy(namebuf, sha1_to_hex(o->sha1), 40);
+ memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
if (write_in_full(cmd.in, namebuf, 41) < 0)
goto error;
}
@@ -527,7 +527,7 @@ error:
o = want_obj.objects[i].item;
if (!is_our_ref(o))
die("git upload-pack: not our ref %s",
- sha1_to_hex(o->sha1));
+ oid_to_hex(&o->oid));
}
}
@@ -639,8 +639,8 @@ static void receive_needs(void)
struct object *object = &result->item->object;
if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
packet_write(1, "shallow %s",
- sha1_to_hex(object->sha1));
- register_shallow(object->sha1);
+ oid_to_hex(&object->oid));
+ register_shallow(object->oid.hash);
shallow_nr++;
}
result = result->next;
@@ -651,10 +651,10 @@ static void receive_needs(void)
if (object->flags & NOT_SHALLOW) {
struct commit_list *parents;
packet_write(1, "unshallow %s",
- sha1_to_hex(object->sha1));
+ oid_to_hex(&object->oid));
object->flags &= ~CLIENT_SHALLOW;
/* make sure the real parents are parsed */
- unregister_shallow(object->sha1);
+ unregister_shallow(object->oid.hash);
object->parsed = 0;
parse_commit_or_die((struct commit *)object);
parents = ((struct commit *)object)->parents;
@@ -666,14 +666,14 @@ static void receive_needs(void)
add_object_array(object, NULL, &extra_edge_obj);
}
/* make sure commit traversal conforms to client */
- register_shallow(object->sha1);
+ register_shallow(object->oid.hash);
}
packet_flush(1);
} else
if (shallows.nr > 0) {
int i;
for (i = 0; i < shallows.nr; i++)
- register_shallow(shallows.objects[i].item->sha1);
+ register_shallow(shallows.objects[i].item->oid.hash);
}
shallow_nr += shallows.nr;
@@ -681,11 +681,12 @@ static void receive_needs(void)
}
/* return non-zero if the ref is hidden, otherwise 0 */
-static int mark_our_ref(const char *refname, const unsigned char *sha1)
+static int mark_our_ref(const char *refname, const char *refname_full,
+ const struct object_id *oid)
{
- struct object *o = lookup_unknown_object(sha1);
+ struct object *o = lookup_unknown_object(oid->hash);
- if (ref_is_hidden(refname)) {
+ if (ref_is_hidden(refname, refname_full)) {
o->flags |= HIDDEN_REF;
return 1;
}
@@ -693,9 +694,12 @@ static int mark_our_ref(const char *refname, const unsigned char *sha1)
return 0;
}
-static int check_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int check_ref(const char *refname_full, const struct object_id *oid,
+ int flag, void *cb_data)
{
- mark_our_ref(refname, sha1);
+ const char *refname = strip_namespace(refname_full);
+
+ mark_our_ref(refname, refname_full, oid);
return 0;
}
@@ -709,48 +713,52 @@ static void format_symref_info(struct strbuf *buf, struct string_list *symref)
strbuf_addf(buf, " symref=%s:%s", item->string, (char *)item->util);
}
-static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int send_ref(const char *refname, const struct object_id *oid,
+ 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";
const char *refname_nons = strip_namespace(refname);
- unsigned char peeled[20];
+ struct object_id peeled;
- if (mark_our_ref(refname, sha1))
+ if (mark_our_ref(refname_nons, refname, oid))
return 0;
if (capabilities) {
struct strbuf symref_info = STRBUF_INIT;
format_symref_info(&symref_info, cb_data);
- packet_write(1, "%s %s%c%s%s%s%s agent=%s\n",
- sha1_to_hex(sha1), refname_nons,
+ packet_write(1, "%s %s%c%s%s%s%s%s agent=%s\n",
+ oid_to_hex(oid), refname_nons,
0, capabilities,
- allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "",
+ (allow_unadvertised_object_request & ALLOW_TIP_SHA1) ?
+ " allow-tip-sha1-in-want" : "",
+ (allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1) ?
+ " allow-reachable-sha1-in-want" : "",
stateless_rpc ? " no-done" : "",
symref_info.buf,
git_user_agent_sanitized());
strbuf_release(&symref_info);
} else {
- packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
+ packet_write(1, "%s %s\n", oid_to_hex(oid), refname_nons);
}
capabilities = NULL;
- if (!peel_ref(refname, peeled))
- packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons);
+ if (!peel_ref(refname, peeled.hash))
+ packet_write(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
return 0;
}
-static int find_symref(const char *refname, const unsigned char *sha1, int flag,
- void *cb_data)
+static int find_symref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
const char *symref_target;
struct string_list_item *item;
- unsigned char unused[20];
+ struct object_id unused;
if ((flag & REF_ISSYMREF) == 0)
return 0;
- symref_target = resolve_ref_unsafe(refname, 0, unused, &flag);
+ symref_target = resolve_ref_unsafe(refname, 0, unused.hash, &flag);
if (!symref_target || (flag & REF_ISSYMREF) == 0)
die("'%s' is a symref but it is not?", refname);
item = string_list_append(cb_data, refname);
@@ -787,9 +795,17 @@ static void upload_pack(void)
static int upload_pack_config(const char *var, const char *value, void *unused)
{
- if (!strcmp("uploadpack.allowtipsha1inwant", var))
- allow_tip_sha1_in_want = git_config_bool(var, value);
- else if (!strcmp("uploadpack.keepalive", var)) {
+ if (!strcmp("uploadpack.allowtipsha1inwant", var)) {
+ if (git_config_bool(var, value))
+ allow_unadvertised_object_request |= ALLOW_TIP_SHA1;
+ else
+ allow_unadvertised_object_request &= ~ALLOW_TIP_SHA1;
+ } else if (!strcmp("uploadpack.allowreachablesha1inwant", var)) {
+ if (git_config_bool(var, value))
+ allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
+ else
+ allow_unadvertised_object_request &= ~ALLOW_REACHABLE_SHA1;
+ } else if (!strcmp("uploadpack.keepalive", var)) {
keepalive = git_config_int(var, value);
if (!keepalive)
keepalive = -1;