1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
7 #include "repository.h"
13 #include "gpg-interface.h"
14 #include "object-file-convert.h"
16 int repo_oid_to_algop(struct repository
*repo
, const struct object_id
*src
,
17 const struct git_hash_algo
*to
, struct object_id
*dest
)
20 * If the source algorithm is not set, then we're using the
21 * default hash algorithm for that object.
23 const struct git_hash_algo
*from
=
24 src
->algo
? &hash_algos
[src
->algo
] : repo
->hash_algo
;
31 if (repo_loose_object_map_oid(repo
, src
, to
, dest
)) {
33 * We may have loaded the object map at repo initialization but
34 * another process (perhaps upstream of a pipe from us) may have
35 * written a new object into the map. If the object is missing,
36 * let's reload the map to see if the object has appeared.
38 repo_read_loose_object_map(repo
);
39 if (repo_loose_object_map_oid(repo
, src
, to
, dest
))
45 static int decode_tree_entry_raw(struct object_id
*oid
, const char **path
,
46 size_t *len
, const struct git_hash_algo
*algo
,
47 const char *buf
, unsigned long size
)
50 const unsigned hashsz
= algo
->rawsz
;
52 if (size
< hashsz
+ 3 || buf
[size
- (hashsz
+ 1)]) {
56 *path
= parse_mode(buf
, &mode
);
57 if (!*path
|| !**path
)
59 *len
= strlen(*path
) + 1;
61 oidread(oid
, (const unsigned char *)*path
+ *len
, algo
);
65 static int convert_tree_object(struct strbuf
*out
,
66 const struct git_hash_algo
*from
,
67 const struct git_hash_algo
*to
,
68 const char *buffer
, size_t size
)
70 const char *p
= buffer
, *end
= buffer
+ size
;
73 struct object_id entry_oid
, mapped_oid
;
74 const char *path
= NULL
;
77 if (decode_tree_entry_raw(&entry_oid
, &path
, &pathlen
, from
, p
,
79 return error(_("failed to decode tree entry"));
80 if (repo_oid_to_algop(the_repository
, &entry_oid
, to
, &mapped_oid
))
81 return error(_("failed to map tree entry for %s"), oid_to_hex(&entry_oid
));
82 strbuf_add(out
, p
, path
- p
);
83 strbuf_add(out
, path
, pathlen
);
84 strbuf_add(out
, mapped_oid
.hash
, to
->rawsz
);
85 p
= path
+ pathlen
+ from
->rawsz
;
90 static int convert_tag_object(struct strbuf
*out
,
91 const struct git_hash_algo
*from
,
92 const struct git_hash_algo
*to
,
93 const char *buffer
, size_t size
)
95 struct strbuf payload
= STRBUF_INIT
, oursig
= STRBUF_INIT
, othersig
= STRBUF_INIT
;
96 const int entry_len
= from
->hexsz
+ 7;
98 struct object_id oid
, mapped_oid
;
101 /* Consume the object line */
102 if ((entry_len
>= size
) ||
103 memcmp(buffer
, "object ", 7) || buffer
[entry_len
] != '\n')
104 return error("bogus tag object");
105 if (parse_oid_hex_algop(buffer
+ 7, &oid
, &p
, from
) < 0)
106 return error("bad tag object ID");
107 if (repo_oid_to_algop(the_repository
, &oid
, to
, &mapped_oid
))
108 return error("unable to map tree %s in tag object",
110 size
-= ((p
+ 1) - buffer
);
113 /* Is there a signature for our algorithm? */
114 payload_size
= parse_signed_buffer(buffer
, size
);
115 if (payload_size
!= size
) {
117 strbuf_add(&oursig
, buffer
+ payload_size
, size
- payload_size
);
120 /* Now, is there a signature for the other algorithm? */
121 parse_buffer_signed_by_header(buffer
, payload_size
, &payload
, &othersig
, to
);
123 * Our payload is now in payload and we may have up to two signatrures
124 * in oursig and othersig.
127 /* Add some slop for longer signature header in the new algorithm. */
128 strbuf_grow(out
, (7 + to
->hexsz
+ 1) + size
+ 7);
129 strbuf_addf(out
, "object %s\n", oid_to_hex(&mapped_oid
));
130 strbuf_addbuf(out
, &payload
);
132 add_header_signature(out
, &oursig
, from
);
133 strbuf_addbuf(out
, &othersig
);
135 strbuf_release(&payload
);
136 strbuf_release(&othersig
);
137 strbuf_release(&oursig
);
141 static int convert_commit_object(struct strbuf
*out
,
142 const struct git_hash_algo
*from
,
143 const struct git_hash_algo
*to
,
144 const char *buffer
, size_t size
)
146 const char *tail
= buffer
;
147 const char *bufptr
= buffer
;
148 const int tree_entry_len
= from
->hexsz
+ 5;
149 const int parent_entry_len
= from
->hexsz
+ 7;
150 struct object_id oid
, mapped_oid
;
155 while ((bufptr
< tail
) && (*bufptr
!= '\n')) {
156 eol
= memchr(bufptr
, '\n', tail
- bufptr
);
158 return error(_("bad %s in commit"), "line");
160 if (((bufptr
+ 5) < eol
) && !memcmp(bufptr
, "tree ", 5))
162 if (((bufptr
+ tree_entry_len
) != eol
) ||
163 parse_oid_hex_algop(bufptr
+ 5, &oid
, &p
, from
) ||
165 return error(_("bad %s in commit"), "tree");
167 if (repo_oid_to_algop(the_repository
, &oid
, to
, &mapped_oid
))
168 return error(_("unable to map %s %s in commit object"),
169 "tree", oid_to_hex(&oid
));
170 strbuf_addf(out
, "tree %s\n", oid_to_hex(&mapped_oid
));
172 else if (((bufptr
+ 7) < eol
) && !memcmp(bufptr
, "parent ", 7))
174 if (((bufptr
+ parent_entry_len
) != eol
) ||
175 parse_oid_hex_algop(bufptr
+ 7, &oid
, &p
, from
) ||
177 return error(_("bad %s in commit"), "parent");
179 if (repo_oid_to_algop(the_repository
, &oid
, to
, &mapped_oid
))
180 return error(_("unable to map %s %s in commit object"),
181 "parent", oid_to_hex(&oid
));
183 strbuf_addf(out
, "parent %s\n", oid_to_hex(&mapped_oid
));
185 else if (((bufptr
+ 9) < eol
) && !memcmp(bufptr
, "mergetag ", 9))
187 struct strbuf tag
= STRBUF_INIT
, new_tag
= STRBUF_INIT
;
189 /* Recover the tag object from the mergetag */
190 strbuf_add(&tag
, bufptr
+ 9, (eol
- (bufptr
+ 9)) + 1);
193 while ((bufptr
< tail
) && (*bufptr
== ' ')) {
194 eol
= memchr(bufptr
, '\n', tail
- bufptr
);
196 strbuf_release(&tag
);
197 return error(_("bad %s in commit"), "mergetag continuation");
199 strbuf_add(&tag
, bufptr
+ 1, (eol
- (bufptr
+ 1)) + 1);
203 /* Compute the new tag object */
204 if (convert_tag_object(&new_tag
, from
, to
, tag
.buf
, tag
.len
)) {
205 strbuf_release(&tag
);
206 strbuf_release(&new_tag
);
210 /* Write the new mergetag */
211 strbuf_addstr(out
, "mergetag");
212 strbuf_add_lines(out
, " ", new_tag
.buf
, new_tag
.len
);
213 strbuf_release(&tag
);
214 strbuf_release(&new_tag
);
216 else if (((bufptr
+ 7) < tail
) && !memcmp(bufptr
, "author ", 7))
217 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
218 else if (((bufptr
+ 10) < tail
) && !memcmp(bufptr
, "committer ", 10))
219 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
220 else if (((bufptr
+ 9) < tail
) && !memcmp(bufptr
, "encoding ", 9))
221 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
222 else if (((bufptr
+ 6) < tail
) && !memcmp(bufptr
, "gpgsig", 6))
223 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
225 /* Unknown line fail it might embed an oid */
228 /* Consume any trailing continuation lines */
230 while ((bufptr
< tail
) && (*bufptr
== ' ')) {
231 eol
= memchr(bufptr
, '\n', tail
- bufptr
);
233 return error(_("bad %s in commit"), "continuation");
234 strbuf_add(out
, bufptr
, (eol
- bufptr
) + 1);
239 strbuf_add(out
, bufptr
, tail
- bufptr
);
243 int convert_object_file(struct strbuf
*outbuf
,
244 const struct git_hash_algo
*from
,
245 const struct git_hash_algo
*to
,
246 const void *buf
, size_t len
,
247 enum object_type type
,
252 /* Don't call this function when no conversion is necessary */
253 if ((from
== to
) || (type
== OBJ_BLOB
))
254 BUG("Refusing noop object file conversion");
258 ret
= convert_commit_object(outbuf
, from
, to
, buf
, len
);
261 ret
= convert_tree_object(outbuf
, from
, to
, buf
, len
);
264 ret
= convert_tag_object(outbuf
, from
, to
, buf
, len
);
267 /* Not implemented yet, so fail. */
274 strbuf_release(outbuf
);
277 die(_("Failed to convert object from %s to %s"),
278 from
->name
, to
->name
);