git

Форк
0
/
object-file-convert.c 
279 строк · 8.1 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "gettext.h"
5
#include "strbuf.h"
6
#include "hex.h"
7
#include "repository.h"
8
#include "hash.h"
9
#include "hash.h"
10
#include "object.h"
11
#include "loose.h"
12
#include "commit.h"
13
#include "gpg-interface.h"
14
#include "object-file-convert.h"
15

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)
18
{
19
	/*
20
	 * If the source algorithm is not set, then we're using the
21
	 * default hash algorithm for that object.
22
	 */
23
	const struct git_hash_algo *from =
24
		src->algo ? &hash_algos[src->algo] : repo->hash_algo;
25

26
	if (from == to) {
27
		if (src != dest)
28
			oidcpy(dest, src);
29
		return 0;
30
	}
31
	if (repo_loose_object_map_oid(repo, src, to, dest)) {
32
		/*
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.
37
		 */
38
		repo_read_loose_object_map(repo);
39
		if (repo_loose_object_map_oid(repo, src, to, dest))
40
			return -1;
41
	}
42
	return 0;
43
}
44

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)
48
{
49
	uint16_t mode;
50
	const unsigned hashsz = algo->rawsz;
51

52
	if (size < hashsz + 3 || buf[size - (hashsz + 1)]) {
53
		return -1;
54
	}
55

56
	*path = parse_mode(buf, &mode);
57
	if (!*path || !**path)
58
		return -1;
59
	*len = strlen(*path) + 1;
60

61
	oidread(oid, (const unsigned char *)*path + *len, algo);
62
	return 0;
63
}
64

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)
69
{
70
	const char *p = buffer, *end = buffer + size;
71

72
	while (p < end) {
73
		struct object_id entry_oid, mapped_oid;
74
		const char *path = NULL;
75
		size_t pathlen;
76

77
		if (decode_tree_entry_raw(&entry_oid, &path, &pathlen, from, p,
78
					  end - 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;
86
	}
87
	return 0;
88
}
89

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)
94
{
95
	struct strbuf payload = STRBUF_INIT, oursig = STRBUF_INIT, othersig = STRBUF_INIT;
96
	const int entry_len = from->hexsz + 7;
97
	size_t payload_size;
98
	struct object_id oid, mapped_oid;
99
	const char *p;
100

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",
109
			     oid_to_hex(&oid));
110
	size -= ((p + 1) - buffer);
111
	buffer = p + 1;
112

113
	/* Is there a signature for our algorithm? */
114
	payload_size = parse_signed_buffer(buffer, size);
115
	if (payload_size != size) {
116
		/* Yes, there is. */
117
		strbuf_add(&oursig, buffer + payload_size, size - payload_size);
118
	}
119

120
	/* Now, is there a signature for the other algorithm? */
121
	parse_buffer_signed_by_header(buffer, payload_size, &payload, &othersig, to);
122
	/*
123
	 * Our payload is now in payload and we may have up to two signatrures
124
	 * in oursig and othersig.
125
	 */
126

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);
131
	if (oursig.len)
132
		add_header_signature(out, &oursig, from);
133
	strbuf_addbuf(out, &othersig);
134

135
	strbuf_release(&payload);
136
	strbuf_release(&othersig);
137
	strbuf_release(&oursig);
138
	return 0;
139
}
140

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)
145
{
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;
151
	const char *p, *eol;
152

153
	tail += size;
154

155
	while ((bufptr < tail) && (*bufptr != '\n')) {
156
		eol = memchr(bufptr, '\n', tail - bufptr);
157
		if (!eol)
158
			return error(_("bad %s in commit"), "line");
159

160
		if (((bufptr + 5) < eol) && !memcmp(bufptr, "tree ", 5))
161
		{
162
			if (((bufptr + tree_entry_len) != eol) ||
163
			    parse_oid_hex_algop(bufptr + 5, &oid, &p, from) ||
164
			    (p != eol))
165
				return error(_("bad %s in commit"), "tree");
166

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));
171
		}
172
		else if (((bufptr + 7) < eol) && !memcmp(bufptr, "parent ", 7))
173
		{
174
			if (((bufptr + parent_entry_len) != eol) ||
175
			    parse_oid_hex_algop(bufptr + 7, &oid, &p, from) ||
176
			    (p != eol))
177
				return error(_("bad %s in commit"), "parent");
178

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));
182

183
			strbuf_addf(out, "parent %s\n", oid_to_hex(&mapped_oid));
184
		}
185
		else if (((bufptr + 9) < eol) && !memcmp(bufptr, "mergetag ", 9))
186
		{
187
			struct strbuf tag = STRBUF_INIT, new_tag = STRBUF_INIT;
188

189
			/* Recover the tag object from the mergetag */
190
			strbuf_add(&tag, bufptr + 9, (eol - (bufptr + 9)) + 1);
191

192
			bufptr = eol + 1;
193
			while ((bufptr < tail) && (*bufptr == ' ')) {
194
				eol = memchr(bufptr, '\n', tail - bufptr);
195
				if (!eol) {
196
					strbuf_release(&tag);
197
					return error(_("bad %s in commit"), "mergetag continuation");
198
				}
199
				strbuf_add(&tag, bufptr + 1, (eol - (bufptr + 1)) + 1);
200
				bufptr = eol + 1;
201
			}
202

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);
207
				return -1;
208
			}
209

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);
215
		}
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);
224
		else {
225
			/* Unknown line fail it might embed an oid */
226
			return -1;
227
		}
228
		/* Consume any trailing continuation lines */
229
		bufptr = eol + 1;
230
		while ((bufptr < tail) && (*bufptr == ' ')) {
231
			eol = memchr(bufptr, '\n', tail - bufptr);
232
			if (!eol)
233
				return error(_("bad %s in commit"), "continuation");
234
			strbuf_add(out, bufptr, (eol - bufptr) + 1);
235
			bufptr = eol + 1;
236
		}
237
	}
238
	if (bufptr < tail)
239
		strbuf_add(out, bufptr, tail - bufptr);
240
	return 0;
241
}
242

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,
248
			int gentle)
249
{
250
	int ret;
251

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");
255

256
	switch (type) {
257
	case OBJ_COMMIT:
258
		ret = convert_commit_object(outbuf, from, to, buf, len);
259
		break;
260
	case OBJ_TREE:
261
		ret = convert_tree_object(outbuf, from, to, buf, len);
262
		break;
263
	case OBJ_TAG:
264
		ret = convert_tag_object(outbuf, from, to, buf, len);
265
		break;
266
	default:
267
		/* Not implemented yet, so fail. */
268
		ret = -1;
269
		break;
270
	}
271
	if (!ret)
272
		return 0;
273
	if (gentle) {
274
		strbuf_release(outbuf);
275
		return ret;
276
	}
277
	die(_("Failed to convert object from %s to %s"),
278
		from->name, to->name);
279
}
280

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.