]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/receive-pack.c
Merge branches 'bw/ls-files-sans-the-index' and 'bw/config-h' into bw/repo-object
[thirdparty/git.git] / builtin / receive-pack.c
index 01ae7154e681cd249bdee78507311274fe568628..71c0c768db92378b824951acd6efb7179438017b 100644 (file)
@@ -79,7 +79,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 {
@@ -455,17 +455,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);
 }
 
@@ -474,7 +474,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;
@@ -487,6 +488,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;
@@ -496,8 +499,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;
 
@@ -535,7 +538,7 @@ static const char *check_nonce(const char *buf, size_t len)
                retval = NONCE_BAD;
                goto leave;
        }
-       stamp = strtoul(nonce, &bohmac, 10);
+       stamp = parse_timestamp(nonce, &bohmac, 10);
        if (bohmac == nonce || bohmac[0] != '-') {
                retval = NONCE_BAD;
                goto leave;
@@ -553,7 +556,7 @@ static const char *check_nonce(const char *buf, size_t len)
         * would mean it was issued by another server with its clock
         * skewed in the future.
         */
-       ostamp = strtoul(push_cert_nonce, NULL, 10);
+       ostamp = parse_timestamp(push_cert_nonce, NULL, 10);
        nonce_stamp_slop = (long)ostamp - (long)stamp;
 
        if (nonce_stamp_slop_limit &&
@@ -576,6 +579,45 @@ leave:
        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;
@@ -859,7 +901,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);
@@ -987,7 +1029,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 +1041,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 +1103,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 +1127,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.");
@@ -1930,6 +1974,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)