summaryrefslogtreecommitdiff
path: root/upload-pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'upload-pack.c')
-rw-r--r--upload-pack.c95
1 files changed, 62 insertions, 33 deletions
diff --git a/upload-pack.c b/upload-pack.c
index 01de944a0a..89e832b64a 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;
@@ -74,19 +78,19 @@ 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;
}
static void create_pack_file(void)
{
- struct child_process pack_objects;
+ struct child_process pack_objects = CHILD_PROCESS_INIT;
char data[8193], progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[12];
+ const char *argv[13];
int i, arg = 0;
FILE *pipe_fd;
@@ -100,6 +104,8 @@ static void create_pack_file(void)
argv[arg++] = "--thin";
argv[arg++] = "--stdout";
+ if (shallow_nr)
+ argv[arg++] = "--shallow";
if (!no_progress)
argv[arg++] = "--progress";
if (use_ofs_delta)
@@ -108,7 +114,6 @@ static void create_pack_file(void)
argv[arg++] = "--include-tag";
argv[arg++] = NULL;
- memset(&pack_objects, 0, sizeof(pack_objects));
pack_objects.in = -1;
pack_objects.out = -1;
pack_objects.err = -1;
@@ -167,7 +172,9 @@ static void create_pack_file(void)
if (!pollsize)
break;
- ret = poll(pfd, pollsize, 1000 * keepalive);
+ ret = poll(pfd, pollsize,
+ keepalive < 0 ? -1 : 1000 * keepalive);
+
if (ret < 0) {
if (errno != EINTR) {
error("poll failed, resuming: %s",
@@ -439,8 +446,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)
@@ -448,13 +456,17 @@ static void check_non_tip(void)
static const char *argv[] = {
"rev-list", "--stdin", NULL,
};
- static struct child_process cmd;
+ static struct child_process cmd = CHILD_PROCESS_INIT;
struct object *o;
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;
@@ -678,20 +690,25 @@ 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, int flag, void *cb_data)
+static int mark_our_ref(const char *refname, 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)) {
o->flags |= HIDDEN_REF;
return 1;
}
- if (!o)
- die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
o->flags |= OUR_REF;
return 0;
}
+static int check_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
+{
+ mark_our_ref(refname, oid);
+ return 0;
+}
+
static void format_symref_info(struct strbuf *buf, struct string_list *symref)
{
struct string_list_item *item;
@@ -702,48 +719,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, flag, NULL))
+ if (mark_our_ref(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, unused, 0, &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);
@@ -764,8 +785,8 @@ static void upload_pack(void)
advertise_shallow_grafts(1);
packet_flush(1);
} else {
- head_ref_namespaced(mark_our_ref, NULL);
- for_each_namespaced_ref(mark_our_ref, NULL);
+ head_ref_namespaced(check_ref, NULL);
+ for_each_namespaced_ref(check_ref, NULL);
}
string_list_clear(&symref, 1);
if (advertise_refs)
@@ -780,9 +801,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;