object-file-convert: convert commit objects when writing

When writing a commit object in a repository with both SHA-1 and SHA-256, we'll need to convert our commit objects so that we can write the hash values for both into the repository. To do so, let's add a function to convert commit objects. Read the commit object and map the tree value and any of the parent values, and copy the rest of the commit through unmodified. Note that we don't need to modify the signature headers, because they are the same under both algorithms. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Oct 1, 2023 at 21:40 UTC 318b023e4a3f5e4f2ecf202aa87db7e5df2c4442
1 file changed +45 -1
object-file-convert.c
+45 -1
@@ -136,6 +136,48 @@ static int convert_tag_object(struct strbuf *out,
136 return 0;
137 }
138
139 +static int convert_commit_object(struct strbuf *out,
140 + const struct git_hash_algo *from,
141 + const struct git_hash_algo *to,
142 + const char *buffer, size_t size)
143 +{
144 + const char *tail = buffer;
145 + const char *bufptr = buffer;
146 + const int tree_entry_len = from->hexsz + 5;
147 + const int parent_entry_len = from->hexsz + 7;
148 + struct object_id oid, mapped_oid;
149 + const char *p;
150 +
151 + tail += size;
152 + if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
153 + bufptr[tree_entry_len] != '\n')
154 + return error("bogus commit object");
155 + if (parse_oid_hex_algop(bufptr + 5, &oid, &p, from) < 0)
156 + return error("bad tree pointer");
157 +
158 + if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
159 + return error("unable to map tree %s in commit object",
160 + oid_to_hex(&oid));
161 + strbuf_addf(out, "tree %s\n", oid_to_hex(&mapped_oid));
162 + bufptr = p + 1;
163 +
164 + while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
165 + if (tail <= bufptr + parent_entry_len + 1 ||
166 + parse_oid_hex_algop(bufptr + 7, &oid, &p, from) ||
167 + *p != '\n')
168 + return error("bad parents in commit");
169 +
170 + if (repo_oid_to_algop(the_repository, &oid, to, &mapped_oid))
171 + return error("unable to map parent %s in commit object",
172 + oid_to_hex(&oid));
173 +
174 + strbuf_addf(out, "parent %s\n", oid_to_hex(&mapped_oid));
175 + bufptr = p + 1;
176 + }
177 + strbuf_add(out, bufptr, tail - bufptr);
178 + return 0;
179 +}
180 +
181 int convert_object_file(struct strbuf *outbuf,
182 const struct git_hash_algo *from,
183 const struct git_hash_algo *to,
@@ -150,13 +192,15 @@ int convert_object_file(struct strbuf *outbuf,
192 BUG("Refusing noop object file conversion");
193
194 switch (type) {
195 + case OBJ_COMMIT:
196 + ret = convert_commit_object(outbuf, from, to, buf, len);
197 + break;
198 case OBJ_TREE:
199 ret = convert_tree_object(outbuf, from, to, buf, len);
200 break;
201 case OBJ_TAG:
202 ret = convert_tag_object(outbuf, from, to, buf, len);
203 break;
159 - case OBJ_COMMIT:
204 default:
205 /* Not implemented yet, so fail. */
206 ret = -1;