]> git.ipfire.org Git - thirdparty/git.git/blobdiff - commit.c
Merge branch 'ab/detox-gettext-tests'
[thirdparty/git.git] / commit.c
index fe1fa3dc41fe787883752671e5954b75616fe9ac..6ccd774841c6939eb977696ac6f30c04dd514ce3 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -14,7 +14,7 @@
 #include "mergesort.h"
 #include "commit-slab.h"
 #include "prio-queue.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
 #include "wt-status.h"
 #include "advice.h"
 #include "refs.h"
@@ -105,23 +105,23 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail)
        return parse_timestamp(dateptr, NULL, 10);
 }
 
-static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
+static const struct object_id *commit_graft_oid_access(size_t index, const void *table)
 {
-       struct commit_graft **commit_graft_table = table;
-       return commit_graft_table[index]->oid.hash;
+       const struct commit_graft * const *commit_graft_table = table;
+       return &commit_graft_table[index]->oid;
 }
 
-int commit_graft_pos(struct repository *r, const unsigned char *sha1)
+int commit_graft_pos(struct repository *r, const struct object_id *oid)
 {
-       return sha1_pos(sha1, r->parsed_objects->grafts,
-                       r->parsed_objects->grafts_nr,
-                       commit_graft_sha1_access);
+       return oid_pos(oid, r->parsed_objects->grafts,
+                      r->parsed_objects->grafts_nr,
+                      commit_graft_oid_access);
 }
 
 int register_commit_graft(struct repository *r, struct commit_graft *graft,
                          int ignore_dups)
 {
-       int pos = commit_graft_pos(r, graft->oid.hash);
+       int pos = commit_graft_pos(r, &graft->oid);
 
        if (0 <= pos) {
                if (ignore_dups)
@@ -232,7 +232,7 @@ struct commit_graft *lookup_commit_graft(struct repository *r, const struct obje
 {
        int pos;
        prepare_commit_graft(r);
-       pos = commit_graft_pos(r, oid->hash);
+       pos = commit_graft_pos(r, oid);
        if (pos < 0)
                return NULL;
        return r->parsed_objects->grafts[pos];
@@ -544,6 +544,17 @@ struct commit_list *commit_list_insert(struct commit *item, struct commit_list *
        return new_list;
 }
 
+int commit_list_contains(struct commit *item, struct commit_list *list)
+{
+       while (list) {
+               if (list->item == item)
+                       return 1;
+               list = list->next;
+       }
+
+       return 0;
+}
+
 unsigned commit_list_count(const struct commit_list *l)
 {
        unsigned c = 0;
@@ -563,6 +574,17 @@ struct commit_list *copy_commit_list(struct commit_list *list)
        return head;
 }
 
+struct commit_list *reverse_commit_list(struct commit_list *list)
+{
+       struct commit_list *next = NULL, *current, *backup;
+       for (current = list; current; current = backup) {
+               backup = current->next;
+               current->next = next;
+               next = current;
+       }
+       return next;
+}
+
 void free_commit_list(struct commit_list *list)
 {
        while (list)
@@ -731,8 +753,8 @@ int compare_commits_by_author_date(const void *a_, const void *b_,
 int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
 {
        const struct commit *a = a_, *b = b_;
-       const uint32_t generation_a = commit_graph_generation(a),
-                      generation_b = commit_graph_generation(b);
+       const timestamp_t generation_a = commit_graph_generation(a),
+                         generation_b = commit_graph_generation(b);
 
        /* newer commits first */
        if (generation_a < generation_b)
@@ -973,7 +995,7 @@ static const char *gpg_sig_headers[] = {
        "gpgsig-sha256",
 };
 
-static int do_sign_commit(struct strbuf *buf, const char *keyid)
+int sign_with_header(struct strbuf *buf, const char *keyid)
 {
        struct strbuf sig = STRBUF_INIT;
        int inspos, copypos;
@@ -1013,21 +1035,32 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
        return 0;
 }
 
+
+
 int parse_signed_commit(const struct commit *commit,
-                       struct strbuf *payload, struct strbuf *signature)
+                       struct strbuf *payload, struct strbuf *signature,
+                       const struct git_hash_algo *algop)
 {
-
        unsigned long size;
        const char *buffer = get_commit_buffer(commit, &size);
-       int in_signature, saw_signature = -1;
-       const char *line, *tail;
-       const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
-       int gpg_sig_header_len = strlen(gpg_sig_header);
+       int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
+
+       unuse_commit_buffer(commit, buffer);
+       return ret;
+}
+
+int parse_buffer_signed_by_header(const char *buffer,
+                                 unsigned long size,
+                                 struct strbuf *payload,
+                                 struct strbuf *signature,
+                                 const struct git_hash_algo *algop)
+{
+       int in_signature = 0, saw_signature = 0, other_signature = 0;
+       const char *line, *tail, *p;
+       const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algop)];
 
        line = buffer;
        tail = buffer + size;
-       in_signature = 0;
-       saw_signature = 0;
        while (line < tail) {
                const char *sig = NULL;
                const char *next = memchr(line, '\n', tail - line);
@@ -1035,9 +1068,15 @@ int parse_signed_commit(const struct commit *commit,
                next = next ? next + 1 : tail;
                if (in_signature && line[0] == ' ')
                        sig = line + 1;
-               else if (starts_with(line, gpg_sig_header) &&
-                        line[gpg_sig_header_len] == ' ')
-                       sig = line + gpg_sig_header_len + 1;
+               else if (skip_prefix(line, gpg_sig_header, &p) &&
+                        *p == ' ') {
+                       sig = line + strlen(gpg_sig_header) + 1;
+                       other_signature = 0;
+               }
+               else if (starts_with(line, "gpgsig"))
+                       other_signature = 1;
+               else if (other_signature && line[0] != ' ')
+                       other_signature = 0;
                if (sig) {
                        strbuf_add(signature, sig, next - sig);
                        saw_signature = 1;
@@ -1046,12 +1085,12 @@ int parse_signed_commit(const struct commit *commit,
                        if (*line == '\n')
                                /* dump the whole remainder of the buffer */
                                next = tail;
-                       strbuf_add(payload, line, next - line);
+                       if (!other_signature)
+                               strbuf_add(payload, line, next - line);
                        in_signature = 0;
                }
                line = next;
        }
-       unuse_commit_buffer(commit, buffer);
        return saw_signature;
 }
 
@@ -1060,23 +1099,29 @@ int remove_signature(struct strbuf *buf)
        const char *line = buf->buf;
        const char *tail = buf->buf + buf->len;
        int in_signature = 0;
-       const char *sig_start = NULL;
-       const char *sig_end = NULL;
+       struct sigbuf {
+               const char *start;
+               const char *end;
+       } sigs[2], *sigp = &sigs[0];
+       int i;
+       const char *orig_buf = buf->buf;
+
+       memset(sigs, 0, sizeof(sigs));
 
        while (line < tail) {
                const char *next = memchr(line, '\n', tail - line);
                next = next ? next + 1 : tail;
 
                if (in_signature && line[0] == ' ')
-                       sig_end = next;
+                       sigp->end = next;
                else if (starts_with(line, "gpgsig")) {
                        int i;
                        for (i = 1; i < GIT_HASH_NALGOS; i++) {
                                const char *p;
                                if (skip_prefix(line, gpg_sig_headers[i], &p) &&
                                    *p == ' ') {
-                                       sig_start = line;
-                                       sig_end = next;
+                                       sigp->start = line;
+                                       sigp->end = next;
                                        in_signature = 1;
                                }
                        }
@@ -1084,15 +1129,18 @@ int remove_signature(struct strbuf *buf)
                        if (*line == '\n')
                                /* dump the whole remainder of the buffer */
                                next = tail;
+                       if (in_signature && sigp - sigs != ARRAY_SIZE(sigs))
+                               sigp++;
                        in_signature = 0;
                }
                line = next;
        }
 
-       if (sig_start)
-               strbuf_remove(buf, sig_start - buf->buf, sig_end - sig_start);
+       for (i = ARRAY_SIZE(sigs) - 1; i >= 0; i--)
+               if (sigs[i].start)
+                       strbuf_remove(buf, sigs[i].start - orig_buf, sigs[i].end - sigs[i].start);
 
-       return sig_start != NULL;
+       return sigs[0].start != NULL;
 }
 
 static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
@@ -1100,8 +1148,10 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
        struct merge_remote_desc *desc;
        struct commit_extra_header *mergetag;
        char *buf;
-       unsigned long size, len;
+       unsigned long size;
        enum object_type type;
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
 
        desc = merge_remote_util(parent);
        if (!desc || !desc->obj)
@@ -1109,8 +1159,7 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
        buf = read_object_file(&desc->obj->oid, &type, &size);
        if (!buf || type != OBJ_TAG)
                goto free_return;
-       len = parse_signature(buf, size);
-       if (size == len)
+       if (!parse_signature(buf, size, &payload, &signature))
                goto free_return;
        /*
         * We could verify this signature and either omit the tag when
@@ -1129,6 +1178,8 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
 
        **tail = mergetag;
        *tail = &mergetag->next;
+       strbuf_release(&payload);
+       strbuf_release(&signature);
        return;
 
 free_return:
@@ -1143,7 +1194,7 @@ int check_commit_signature(const struct commit *commit, struct signature_check *
 
        sigc->result = 'N';
 
-       if (parse_signed_commit(commit, &payload, &signature) <= 0)
+       if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
                goto out;
        ret = check_signature(payload.buf, payload.len, signature.buf,
                signature.len, sigc);
@@ -1493,7 +1544,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
        if (encoding_is_utf8 && !verify_utf8(&buffer))
                fprintf(stderr, _(commit_utf8_warn));
 
-       if (sign_commit && do_sign_commit(&buffer, sign_commit)) {
+       if (sign_commit && sign_with_header(&buffer, sign_commit)) {
                result = -1;
                goto out;
        }