28
28
#include "shallow.h"
29
29
#include "tree.h"
30
30
#include "hook.h"
31
+ #include "object-file-convert.h"
31
32
32
33
static struct commit_extra_header * read_commit_extra_header_lines (const char * buf , size_t len , const char * * );
33
34
@@ -1100,12 +1101,11 @@ static const char *gpg_sig_headers[] = {
1100
1101
"gpgsig-sha256" ,
1101
1102
};
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 )
1104
1105
{
1105
- struct strbuf sig = STRBUF_INIT ;
1106
1106
int inspos , copypos ;
1107
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
1109
int gpg_sig_header_len = strlen (gpg_sig_header );
1110
1110
1111
1111
/* find the end of the header */
@@ -1115,15 +1115,8 @@ int sign_with_header(struct strbuf *buf, const char *keyid)
1115
1115
else
1116
1116
inspos = eoh - buf -> buf + 1 ;
1117
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 ;
1127
1120
const char * eol = strchrnul (bol , '\n' );
1128
1121
int len = (eol - bol ) + !!* eol ;
1129
1122
@@ -1136,11 +1129,17 @@ int sign_with_header(struct strbuf *buf, const char *keyid)
1136
1129
inspos += len ;
1137
1130
copypos += len ;
1138
1131
}
1139
- strbuf_release (& sig );
1140
1132
return 0 ;
1141
1133
}
1142
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
+ }
1144
1143
1145
1144
int parse_signed_commit (const struct commit * commit ,
1146
1145
struct strbuf * payload , struct strbuf * signature ,
@@ -1599,70 +1598,162 @@ N_("Warning: commit message did not conform to UTF-8.\n"
1599
1598
"You may want to amend it after fixing the message, or set the config\n"
1600
1599
"variable i18n.commitEncoding to the encoding your project uses.\n" );
1601
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 )
1608
1606
{
1609
- int result ;
1610
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 ;
1617
1609
1618
1610
/* Not having i18n.commitencoding is the same as having utf-8 */
1619
1611
encoding_is_utf8 = is_encoding_utf8 (git_commit_encoding );
1620
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 ));
1623
1615
1624
1616
/*
1625
1617
* NOTE! This ordering means that the same exact tree merged with a
1626
1618
* different order of parents will be a _different_ changeset even
1627
1619
* if everything else stays the same.
1628
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 ]));
1634
1623
1635
1624
/* Person/date information */
1636
1625
if (!author )
1637
1626
author = git_author_info (IDENT_STRICT );
1638
- strbuf_addf (& buffer , "author %s\n" , author );
1627
+ strbuf_addf (buffer , "author %s\n" , author );
1639
1628
if (!committer )
1640
1629
committer = git_committer_info (IDENT_STRICT );
1641
- strbuf_addf (& buffer , "committer %s\n" , committer );
1630
+ strbuf_addf (buffer , "committer %s\n" , committer );
1642
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 );
1644
1633
1645
1634
while (extra ) {
1646
- add_extra_header (& buffer , extra );
1635
+ add_extra_header (buffer , extra );
1647
1636
extra = extra -> next ;
1648
1637
}
1649
- strbuf_addch (& buffer , '\n' );
1638
+ strbuf_addch (buffer , '\n' );
1650
1639
1651
1640
/* And add the comment */
1652
- strbuf_add (& buffer , msg , msg_len );
1641
+ strbuf_add (buffer , msg , msg_len );
1642
+ }
1653
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." );
1657
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 )) {
1659
1678
result = -1 ;
1660
1679
goto out ;
1661
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
+ }
1662
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 );
1664
1751
out :
1752
+ free (parent_buf );
1665
1753
strbuf_release (& buffer );
1754
+ strbuf_release (& compat_buffer );
1755
+ strbuf_release (& sig );
1756
+ strbuf_release (& compat_sig );
1666
1757
return result ;
1667
1758
}
1668
1759
0 commit comments