28
#include "shallow.h"
29
#include "tree.h"
30
#include "hook.h"
31
+#include "object-file-convert.h"
32
33
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
34
1101
"gpgsig-sha256",
1102
};
1103
1103
-int sign_with_header(struct strbuf *buf, const char *keyid)
1104
+static int add_commit_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo)
1105
{
1105
- struct strbuf sig = STRBUF_INIT;
1106
int inspos, copypos;
1107
const char *eoh;
1108
- const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
1108
+ const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algo)];
1109
int gpg_sig_header_len = strlen(gpg_sig_header);
1110
1111
/* find the end of the header */
1115
else
1116
inspos = eoh - buf->buf + 1;
1117
1118
- if (!keyid || !*keyid)
1119
- keyid = get_signing_key();
1120
- if (sign_buffer(buf, &sig, keyid)) {
1121
- strbuf_release(&sig);
1122
- return -1;
1123
- }
1124
-
1125
- for (copypos = 0; sig.buf[copypos]; ) {
1126
- const char *bol = sig.buf + copypos;
1118
+ for (copypos = 0; sig->buf[copypos]; ) {
1119
+ const char *bol = sig->buf + copypos;
1120
const char *eol = strchrnul(bol, '\n');
1121
int len = (eol - bol) + !!*eol;
1122
1129
inspos += len;
1130
copypos += len;
1131
}
1139
- strbuf_release(&sig);
1132
return 0;
1133
}
1134
1143
-
1135
+static int sign_commit_to_strbuf(struct strbuf *sig, struct strbuf *buf, const char *keyid)
1136
+{
1137
+ if (!keyid || !*keyid)
1138
+ keyid = get_signing_key();
1139
+ if (sign_buffer(buf, sig, keyid))
1140
+ return -1;
1141
+ return 0;
1142
+}
1143
1144
int parse_signed_commit(const struct commit *commit,
1145
struct strbuf *payload, struct strbuf *signature,
1598
"You may want to amend it after fixing the message, or set the config\n"
1599
"variable i18n.commitEncoding to the encoding your project uses.\n");
1600
1602
-int commit_tree_extended(const char *msg, size_t msg_len,
1603
- const struct object_id *tree,
1604
- struct commit_list *parents, struct object_id *ret,
1605
- const char *author, const char *committer,
1606
- const char *sign_commit,
1607
- struct commit_extra_header *extra)
1601
+static void write_commit_tree(struct strbuf *buffer, const char *msg, size_t msg_len,
1602
+ const struct object_id *tree,
1603
+ const struct object_id *parents, size_t parents_len,
1604
+ const char *author, const char *committer,
1605
+ struct commit_extra_header *extra)
1606
{
1609
- int result;
1607
int encoding_is_utf8;
1611
- struct strbuf buffer;
1612
-
1613
- assert_oid_type(tree, OBJ_TREE);
1614
-
1615
- if (memchr(msg, '\0', msg_len))
1616
- return error("a NUL byte in commit log message not allowed.");
1608
+ size_t i;
1609
1610
/* Not having i18n.commitencoding is the same as having utf-8 */
1611
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
1612
1621
- strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
1622
- strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
1613
+ strbuf_grow(buffer, 8192); /* should avoid reallocs for the headers */
1614
+ strbuf_addf(buffer, "tree %s\n", oid_to_hex(tree));
1615
1616
/*
1617
* NOTE! This ordering means that the same exact tree merged with a
1618
* different order of parents will be a _different_ changeset even
1619
* if everything else stays the same.
1620
*/
1629
- while (parents) {
1630
- struct commit *parent = pop_commit(&parents);
1631
- strbuf_addf(&buffer, "parent %s\n",
1632
- oid_to_hex(&parent->object.oid));
1633
- }
1621
+ for (i = 0; i < parents_len; i++)
1622
+ strbuf_addf(buffer, "parent %s\n", oid_to_hex(&parents[i]));
1623
1624
/* Person/date information */
1625
if (!author)
1626
author = git_author_info(IDENT_STRICT);
1638
- strbuf_addf(&buffer, "author %s\n", author);
1627
+ strbuf_addf(buffer, "author %s\n", author);
1628
if (!committer)
1629
committer = git_committer_info(IDENT_STRICT);
1641
- strbuf_addf(&buffer, "committer %s\n", committer);
1630
+ strbuf_addf(buffer, "committer %s\n", committer);
1631
if (!encoding_is_utf8)
1643
- strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
1632
+ strbuf_addf(buffer, "encoding %s\n", git_commit_encoding);
1633
1634
while (extra) {
1646
- add_extra_header(&buffer, extra);
1635
+ add_extra_header(buffer, extra);
1636
extra = extra->next;
1637
}
1649
- strbuf_addch(&buffer, '\n');
1638
+ strbuf_addch(buffer, '\n');
1639
1640
/* And add the comment */
1652
- strbuf_add(&buffer, msg, msg_len);
1641
+ strbuf_add(buffer, msg, msg_len);
1642
+}
1643
1654
- /* And check the encoding */
1655
- if (encoding_is_utf8 && !verify_utf8(&buffer))
1656
- fprintf(stderr, _(commit_utf8_warn));
1644
+int commit_tree_extended(const char *msg, size_t msg_len,
1645
+ const struct object_id *tree,
1646
+ struct commit_list *parents, struct object_id *ret,
1647
+ const char *author, const char *committer,
1648
+ const char *sign_commit,
1649
+ struct commit_extra_header *extra)
1650
+{
1651
+ struct repository *r = the_repository;
1652
+ int result = 0;
1653
+ int encoding_is_utf8;
1654
+ struct strbuf buffer = STRBUF_INIT, compat_buffer = STRBUF_INIT;
1655
+ struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
1656
+ struct object_id *parent_buf = NULL, *compat_oid = NULL;
1657
+ struct object_id compat_oid_buf;
1658
+ size_t i, nparents;
1659
+
1660
+ /* Not having i18n.commitencoding is the same as having utf-8 */
1661
+ encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
1662
+
1663
+ assert_oid_type(tree, OBJ_TREE);
1664
+
1665
+ if (memchr(msg, '\0', msg_len))
1666
+ return error("a NUL byte in commit log message not allowed.");
1667
1658
- if (sign_commit && sign_with_header(&buffer, sign_commit)) {
1668
+ nparents = commit_list_count(parents);
1669
+ CALLOC_ARRAY(parent_buf, nparents);
1670
+ i = 0;
1671
+ while (parents) {
1672
+ struct commit *parent = pop_commit(&parents);
1673
+ oidcpy(&parent_buf[i++], &parent->object.oid);
1674
+ }
1675
+
1676
+ write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra);
1677
+ if (sign_commit && sign_commit_to_strbuf(&sig, &buffer, sign_commit)) {
1678
result = -1;
1679
goto out;
1680
}
1681
+ if (r->compat_hash_algo) {
1682
+ struct object_id mapped_tree;
1683
+ struct object_id *mapped_parents;
1684
+
1685
+ CALLOC_ARRAY(mapped_parents, nparents);
1686
+
1687
+ if (repo_oid_to_algop(r, tree, r->compat_hash_algo, &mapped_tree)) {
1688
+ result = -1;
1689
+ free(mapped_parents);
1690
+ goto out;
1691
+ }
1692
+ for (i = 0; i < nparents; i++)
1693
+ if (repo_oid_to_algop(r, &parent_buf[i], r->compat_hash_algo, &mapped_parents[i])) {
1694
+ result = -1;
1695
+ free(mapped_parents);
1696
+ goto out;
1697
+ }
1698
+ write_commit_tree(&compat_buffer, msg, msg_len, &mapped_tree,
1699
+ mapped_parents, nparents, author, committer, extra);
1700
+ free(mapped_parents);
1701
+
1702
+ if (sign_commit && sign_commit_to_strbuf(&compat_sig, &compat_buffer, sign_commit)) {
1703
+ result = -1;
1704
+ goto out;
1705
+ }
1706
+ }
1707
+
1708
+ if (sign_commit) {
1709
+ struct sig_pairs {
1710
+ struct strbuf *sig;
1711
+ const struct git_hash_algo *algo;
1712
+ } bufs [2] = {
1713
+ { &compat_sig, r->compat_hash_algo },
1714
+ { &sig, r->hash_algo },
1715
+ };
1716
+ int i;
1717
+
1718
+ /*
1719
+ * We write algorithms in the order they were implemented in
1720
+ * Git to produce a stable hash when multiple algorithms are
1721
+ * used.
1722
+ */
1723
+ if (r->compat_hash_algo && hash_algo_by_ptr(bufs[0].algo) > hash_algo_by_ptr(bufs[1].algo))
1724
+ SWAP(bufs[0], bufs[1]);
1725
+
1726
+ /*
1727
+ * We traverse each algorithm in order, and apply the signature
1728
+ * to each buffer.
1729
+ */
1730
+ for (i = 0; i < ARRAY_SIZE(bufs); i++) {
1731
+ if (!bufs[i].algo)
1732
+ continue;
1733
+ add_commit_signature(&buffer, bufs[i].sig, bufs[i].algo);
1734
+ if (r->compat_hash_algo)
1735
+ add_commit_signature(&compat_buffer, bufs[i].sig, bufs[i].algo);
1736
+ }
1737
+ }
1738
1663
- result = write_object_file(buffer.buf, buffer.len, OBJ_COMMIT, ret);
1739
+ /* And check the encoding. */
1740
+ if (encoding_is_utf8 && (!verify_utf8(&buffer) || !verify_utf8(&compat_buffer)))
1741
+ fprintf(stderr, _(commit_utf8_warn));
1742
+
1743
+ if (r->compat_hash_algo) {
1744
+ hash_object_file(r->compat_hash_algo, compat_buffer.buf, compat_buffer.len,
1745
+ OBJ_COMMIT, &compat_oid_buf);
1746
+ compat_oid = &compat_oid_buf;
1747
+ }
1748
+
1749
+ result = write_object_file_flags(buffer.buf, buffer.len, OBJ_COMMIT,
1750
+ ret, compat_oid, 0);
1751
out:
1752
+ free(parent_buf);
1753
strbuf_release(&buffer);
1754
+ strbuf_release(&compat_buffer);
1755
+ strbuf_release(&sig);
1756
+ strbuf_release(&compat_sig);
1757
return result;
1758
}
1759