refs: pass NULL to resolve_refdup() if hash is not needed
[gitweb.git] / builtin / receive-pack.c
index 9a4c2a7ade4486ba5ef4762c7f10ba158e9b7c4b..65e38a72776c557af3c794c06f4598867a422338 100644 (file)
@@ -1,4 +1,5 @@
 #include "builtin.h"
+#include "config.h"
 #include "lockfile.h"
 #include "pack.h"
 #include "refs.h"
@@ -22,6 +23,7 @@
 #include "fsck.h"
 #include "tmp-objdir.h"
 #include "oidset.h"
+#include "packfile.h"
 
 static const char * const receive_pack_usage[] = {
        N_("git receive-pack <git-dir>"),
@@ -78,7 +80,7 @@ static const char *NONCE_OK = "OK";
 static const char *NONCE_SLOP = "SLOP";
 static const char *nonce_status;
 static long nonce_stamp_slop;
-static unsigned long nonce_stamp_slop_limit;
+static timestamp_t nonce_stamp_slop_limit;
 static struct ref_transaction *transaction;
 
 static enum {
@@ -454,17 +456,17 @@ static void hmac_sha1(unsigned char *out,
        git_SHA1_Final(out, &ctx);
 }
 
-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)
+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
 {
        struct strbuf buf = STRBUF_INIT;
        unsigned char sha1[20];
 
-       strbuf_addf(&buf, "%s:%lu", path, stamp);
+       strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
        hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;
        strbuf_release(&buf);
 
        /* RFC 2104 5. HMAC-SHA1-80 */
-       strbuf_addf(&buf, "%lu-%.*s", stamp, 20, sha1_to_hex(sha1));
+       strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, 20, sha1_to_hex(sha1));
        return strbuf_detach(&buf, NULL);
 }
 
@@ -473,7 +475,8 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)
  * after dropping "_commit" from its name and possibly moving it out
  * of commit.c
  */
-static char *find_header(const char *msg, size_t len, const char *key)
+static char *find_header(const char *msg, size_t len, const char *key,
+                        const char **next_line)
 {
        int key_len = strlen(key);
        const char *line = msg;
@@ -486,6 +489,8 @@ static char *find_header(const char *msg, size_t len, const char *key)
                if (line + key_len < eol &&
                    !memcmp(line, key, key_len) && line[key_len] == ' ') {
                        int offset = key_len + 1;
+                       if (next_line)
+                               *next_line = *eol ? eol + 1 : eol;
                        return xmemdupz(line + offset, (eol - line) - offset);
                }
                line = *eol ? eol + 1 : NULL;
@@ -495,8 +500,8 @@ static char *find_header(const char *msg, size_t len, const char *key)
 
 static const char *check_nonce(const char *buf, size_t len)
 {
-       char *nonce = find_header(buf, len, "nonce");
-       unsigned long stamp, ostamp;
+       char *nonce = find_header(buf, len, "nonce", NULL);
+       timestamp_t stamp, ostamp;
        char *bohmac, *expect = NULL;
        const char *retval = NONCE_BAD;
 
@@ -575,6 +580,45 @@ static const char *check_nonce(const char *buf, size_t len)
        return retval;
 }
 
+/*
+ * Return 1 if there is no push_cert or if the push options in push_cert are
+ * the same as those in the argument; 0 otherwise.
+ */
+static int check_cert_push_options(const struct string_list *push_options)
+{
+       const char *buf = push_cert.buf;
+       int len = push_cert.len;
+
+       char *option;
+       const char *next_line;
+       int options_seen = 0;
+
+       int retval = 1;
+
+       if (!len)
+               return 1;
+
+       while ((option = find_header(buf, len, "push-option", &next_line))) {
+               len -= (next_line - buf);
+               buf = next_line;
+               options_seen++;
+               if (options_seen > push_options->nr
+                   || strcmp(option,
+                             push_options->items[options_seen - 1].string)) {
+                       retval = 0;
+                       goto leave;
+               }
+               free(option);
+       }
+
+       if (options_seen != push_options->nr)
+               retval = 0;
+
+leave:
+       free(option);
+       return retval;
+}
+
 static void prepare_push_cert_sha1(struct child_process *proc)
 {
        static int already_done;
@@ -772,7 +816,6 @@ static int run_update_hook(struct command *cmd)
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
        proc.argv = argv;
-       proc.env = tmp_objdir_env(tmp_objdir);
 
        code = start_command(&proc);
        if (code)
@@ -859,7 +902,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
         * not lose these new roots..
         */
        for (i = 0; i < extra.nr; i++)
-               register_shallow(extra.oid[i].hash);
+               register_shallow(&extra.oid[i]);
 
        si->shallow_ref[cmd->index] = 0;
        oid_array_clear(&extra);
@@ -877,9 +920,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
  */
 static int head_has_history(void)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       return !get_sha1("HEAD", sha1);
+       return !get_oid("HEAD", &oid);
 }
 
 static const char *push_to_deploy(unsigned char *sha1,
@@ -987,7 +1030,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 {
        const char *name = cmd->ref_name;
        struct strbuf namespaced_name_buf = STRBUF_INIT;
-       const char *namespaced_name, *ret;
+       static char *namespaced_name;
+       const char *ret;
        struct object_id *old_oid = &cmd->old_oid;
        struct object_id *new_oid = &cmd->new_oid;
 
@@ -998,6 +1042,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
        }
 
        strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+       free(namespaced_name);
        namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
 
        if (is_ref_checked_out(namespaced_name)) {
@@ -1059,8 +1104,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                struct object *old_object, *new_object;
                struct commit *old_commit, *new_commit;
 
-               old_object = parse_object(old_oid->hash);
-               new_object = parse_object(new_oid->hash);
+               old_object = parse_object(old_oid);
+               new_object = parse_object(new_oid);
 
                if (!old_object || !new_object ||
                    old_object->type != OBJ_COMMIT ||
@@ -1083,7 +1128,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 
        if (is_null_oid(new_oid)) {
                struct strbuf err = STRBUF_INIT;
-               if (!parse_object(old_oid->hash)) {
+               if (!parse_object(old_oid)) {
                        old_oid = NULL;
                        if (ref_exists(name)) {
                                rp_warning("Allowing deletion of corrupt ref.");
@@ -1094,7 +1139,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
                if (ref_transaction_delete(transaction,
                                           namespaced_name,
-                                          old_oid->hash,
+                                          old_oid ? old_oid->hash : NULL,
                                           0, "push", &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
@@ -1162,11 +1207,10 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
        const char *dst_name;
        struct string_list_item *item;
        struct command *dst_cmd;
-       unsigned char sha1[GIT_MAX_RAWSZ];
        int flag;
 
        strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
-       dst_name = resolve_ref_unsafe(buf.buf, 0, sha1, &flag);
+       dst_name = resolve_ref_unsafe(buf.buf, 0, NULL, &flag);
        strbuf_release(&buf);
 
        if (!(flag & REF_ISSYMREF))
@@ -1414,7 +1458,6 @@ static void execute_commands(struct command *commands,
 {
        struct check_connected_options opt = CHECK_CONNECTED_INIT;
        struct command *cmd;
-       struct object_id oid;
        struct iterate_data data;
        struct async muxer;
        int err_fd = 0;
@@ -1471,7 +1514,7 @@ static void execute_commands(struct command *commands,
        check_aliased_updates(commands);
 
        free(head_name_to_free);
-       head_name = head_name_to_free = resolve_refdup("HEAD", 0, oid.hash, NULL);
+       head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
 
        if (use_atomic)
                execute_commands_atomic(commands, si);
@@ -1698,12 +1741,12 @@ static const char *unpack(int err_fd, struct shallow_info *si)
                if (status)
                        return "unpack-objects abnormal exit";
        } else {
-               char hostname[256];
+               char hostname[HOST_NAME_MAX + 1];
 
                argv_array_pushl(&child.args, "index-pack", "--stdin", NULL);
                push_header_arg(&child.args, &hdr);
 
-               if (gethostname(hostname, sizeof(hostname)))
+               if (xgethostname(hostname, sizeof(hostname)))
                        xsnprintf(hostname, sizeof(hostname), "localhost");
                argv_array_pushf(&child.args,
                                 "--keep=receive-pack %"PRIuMAX" on %s",
@@ -1762,7 +1805,7 @@ static const char *unpack_with_sideband(struct shallow_info *si)
 static void prepare_shallow_update(struct command *commands,
                                   struct shallow_info *si)
 {
-       int i, j, k, bitmap_size = (si->ref->nr + 31) / 32;
+       int i, j, k, bitmap_size = DIV_ROUND_UP(si->ref->nr, 32);
 
        ALLOC_ARRAY(si->used_shallow, si->shallow->nr);
        assign_shallow_commits_to_refs(si, si->used_shallow, NULL);
@@ -1930,6 +1973,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 
                if (use_push_options)
                        read_push_options(&push_options);
+               if (!check_cert_push_options(&push_options)) {
+                       struct command *cmd;
+                       for (cmd = commands; cmd; cmd = cmd->next)
+                               cmd->error_string = "inconsistent push options";
+               }
 
                prepare_shallow_info(&si, &shallow);
                if (!si.nr_ours && !si.nr_theirs)