1 #include "git-compat-util.h"
5 #include "repository.h"
11 #include "gpg-interface.h"
12 #include "object-file-convert.h"
14 int repo_oid_to_algop(struct repository
*repo
, const struct object_id
*src
,
15 const struct git_hash_algo
*to
, struct object_id
*dest
)
18 * If the source algorithm is not set, then we're using the
19 * default hash algorithm for that object.
21 const struct git_hash_algo
*from
=
22 src
->algo
? &hash_algos
[src
->algo
] : repo
->hash_algo
;
29 if (repo_loose_object_map_oid(repo
, src
, to
, dest
)) {
31 * We may have loaded the object map at repo initialization but
32 * another process (perhaps upstream of a pipe from us) may have
33 * written a new object into the map. If the object is missing,
34 * let's reload the map to see if the object has appeared.
36 repo_read_loose_object_map(repo
);
37 if (repo_loose_object_map_oid(repo
, src
, to
, dest
))
43 static int decode_tree_entry_raw(struct object_id
*oid
, const char **path
,
44 size_t *len
, const struct git_hash_algo
*algo
,
45 const char *buf
, unsigned long size
)
48 const unsigned hashsz
= algo
->rawsz
;
50 if (size
< hashsz
+ 3 || buf
[size
- (hashsz
+ 1)]) {
54 *path
= parse_mode(buf
, &mode
);
55 if (!*path
|| !**path
)
57 *len
= strlen(*path
) + 1;
59 oidread_algop(oid
, (const unsigned char *)*path
+ *len
, algo
);
63 static int convert_tree_object(struct strbuf
*out
,
64 const struct git_hash_algo
*from
,
65 const struct git_hash_algo
*to
,
66 const char *buffer
, size_t size
)
68 const char *p
= buffer
, *end
= buffer
+ size
;
71 struct object_id entry_oid
, mapped_oid
;
72 const char *path
= NULL
;
75 if (decode_tree_entry_raw(&entry_oid
, &path
, &pathlen
, from
, p
,
77 return error(_("failed to decode tree entry"));
78 if (repo_oid_to_algop(the_repository
, &entry_oid
, to
, &mapped_oid
))
79 return error(_("failed to map tree entry for %s"), oid_to_hex(&entry_oid
));
80 strbuf_add(out
, p
, path
- p
);
81 strbuf_add(out
, path
, pathlen
);
82 strbuf_add(out
, mapped_oid
.hash
, to
->rawsz
);
83 p
= path
+ pathlen
+ from
->rawsz
;
88 static int convert_tag_object(struct strbuf
*out
,
89 const struct git_hash_algo
*from
,
90 const struct git_hash_algo
*to
,
91 const char *buffer
, size_t size
)
93 struct strbuf payload
= STRBUF_INIT
, oursig
= STRBUF_INIT
, othersig
= STRBUF_INIT
;
94 const int entry_len
= from
->hexsz
+ 7;
96 struct object_id oid
, mapped_oid
;
99 /* Consume the object line */
100 if ((entry_len
>= size
) ||
101 memcmp(buffer
, "object ", 7) || buffer
[entry_len
] != '\n')
102 return error("bogus tag object");
103 if (parse_oid_hex_algop(buffer
+ 7, &oid
, &p
, from
) < 0)
104 return error("bad tag object ID");
105 if (repo_oid_to_algop(the_repository
, &oid
, to
, &mapped_oid
))
106 return error("unable to map tree %s in tag object",
108 size
-= ((p
+ 1) - buffer
);
111 /* Is there a signature for our algorithm? */
112 payload_size
= parse_signed_buffer(buffer
, size
);
113 if (payload_size
!= size
) {
115 strbuf_add(&oursig
, buffer
+ payload_size
, size
- payload_size
);
118 /* Now, is there a signature for the other algorithm? */
119 parse_buffer_signed_by_header(buffer
, payload_size
, &payload
, &othersig
, to
);
121 * Our payload is now in payload and we may have up to two signatrures
122 * in oursig and othersig.
125 /* Add some slop for longer signature header in the new algorithm. */
126 strbuf_grow(out
, (7 + to
->hexsz
+ 1) + size
+ 7);
127 strbuf_addf(out
, "object %s\n", oid_to_hex(&mapped_oid
));
128 strbuf_addbuf(out
, &payload
);
130 add_header_signature(out
, &oursig
, from
);
131 strbuf_addbuf(out
, &othersig
);
133 strbuf_release(&payload
);
134 strbuf_release(&othersig
);
135 strbuf_release(&oursig
);
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
)
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
;
153 while ((bufptr
< tail
) && (*bufptr
!= '\n')) {
154 eol
= memchr(bufptr
, '\n', tail
- bufptr
);
156 return error(_("bad %s in commit"), "line");
158 if (((bufptr
+ 5) < eol
) && !memcmp(bufptr
, "tree ", 5))
160 if (((bufptr
+ tree_entry_len
) != eol
) ||
161 parse_oid_hex_algop(bufptr
+ 5, &oid
, &p
, from
) ||
163 return error(_("bad %s in commit"), "tree");
165 if (repo_oid_to_algop(the_repository
, &oid
, to
, &mapped_oid
))
166 return error(_("unable to map %s %s in commit object"),
167 "tree", oid_to_hex(&oid
));
168 strbuf_addf(out
, "tree %s\n", oid_to_hex(&mapped_oid
));
170 else if (((bufptr
+ 7) < eol
) && !memcmp(bufptr
, "parent ", 7))
172 if (((bufptr
+ parent_entry_len
) != eol
) ||
173 parse_oid_hex_algop(bufptr
+ 7, &oid
, &p
, from
) ||
175 return error(_("bad %s in commit"), "parent");
177 if (repo_oid_to_algop(the_repository
, &oid
, to
, &mapped_oid
))
178 return error(_("unable to map %s %s in commit object"),
179 "parent", oid_to_hex(&oid
));
181 strbuf_addf(out
, "parent %s\n", oid_to_hex(&mapped_oid
));
183 else if (((bufptr
+ 9) < eol
) && !memcmp(bufptr
, "mergetag ", 9))
185 struct strbuf tag
= STRBUF_INIT
, new_tag
= STRBUF_INIT
;
187 /* Recover the tag object from the mergetag */
188 strbuf_add(&tag
, bufptr
+ 9, (eol
- (bufptr
+ 9)) + 1);
191 while ((bufptr
< tail
) && (*bufptr
== ' ')) {
192 eol
= memchr(bufptr
, '\n', tail
- bufptr
);
194 strbuf_release(&tag
);
195 return error(_("bad %s in commit"), "mergetag continuation");
197 strbuf_add(&tag
, bufptr
+ 1, (eol
- (bufptr
+ 1)) + 1);
201 /* Compute the new tag object */
202 if (convert_tag_object(&new_tag
, from
, to
, tag
.buf
, tag
.len
)) {
203 strbuf_release(&tag
);
204 strbuf_release(&new_tag
);
208 /* Write the new mergetag */
209 strbuf_addstr(out
, "mergetag");
210 strbuf_add_lines(out
, " ", new_tag
.buf
, new_tag
.len
);
211 strbuf_release(&tag
);
212 strbuf_release(&new_tag
);
214 else if (((bufptr
+ 7) < tail
) && !memcmp(bufptr
, "author ", 7))
215 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
216 else if (((bufptr
+ 10) < tail
) && !memcmp(bufptr
, "committer ", 10))
217 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
218 else if (((bufptr
+ 9) < tail
) && !memcmp(bufptr
, "encoding ", 9))
219 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
220 else if (((bufptr
+ 6) < tail
) && !memcmp(bufptr
, "gpgsig", 6))
221 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
223 /* Unknown line fail it might embed an oid */
226 /* Consume any trailing continuation lines */
228 while ((bufptr
< tail
) && (*bufptr
== ' ')) {
229 eol
= memchr(bufptr
, '\n', tail
- bufptr
);
231 return error(_("bad %s in commit"), "continuation");
232 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
237 strbuf_add(out
, bufptr
, tail
- bufptr
);
241 int convert_object_file(struct strbuf
*outbuf
,
242 const struct git_hash_algo
*from
,
243 const struct git_hash_algo
*to
,
244 const void *buf
, size_t len
,
245 enum object_type type
,
250 /* Don't call this function when no conversion is necessary */
251 if ((from
== to
) || (type
== OBJ_BLOB
))
252 BUG("Refusing noop object file conversion");
256 ret
= convert_commit_object(outbuf
, from
, to
, buf
, len
);
259 ret
= convert_tree_object(outbuf
, from
, to
, buf
, len
);
262 ret
= convert_tag_object(outbuf
, from
, to
, buf
, len
);
265 /* Not implemented yet, so fail. */
272 strbuf_release(outbuf
);
275 die(_("Failed to convert object from %s to %s"),
276 from
->name
, to
->name
);