git

Форк
0
/
chunk-format.c 
214 строк · 4.8 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "chunk-format.h"
5
#include "csum-file.h"
6
#include "gettext.h"
7
#include "hash.h"
8
#include "trace2.h"
9

10
/*
11
 * When writing a chunk-based file format, collect the chunks in
12
 * an array of chunk_info structs. The size stores the _expected_
13
 * amount of data that will be written by write_fn.
14
 */
15
struct chunk_info {
16
	uint32_t id;
17
	uint64_t size;
18
	chunk_write_fn write_fn;
19

20
	const void *start;
21
};
22

23
struct chunkfile {
24
	struct hashfile *f;
25

26
	struct chunk_info *chunks;
27
	size_t chunks_nr;
28
	size_t chunks_alloc;
29
};
30

31
struct chunkfile *init_chunkfile(struct hashfile *f)
32
{
33
	struct chunkfile *cf = xcalloc(1, sizeof(*cf));
34
	cf->f = f;
35
	return cf;
36
}
37

38
void free_chunkfile(struct chunkfile *cf)
39
{
40
	if (!cf)
41
		return;
42
	free(cf->chunks);
43
	free(cf);
44
}
45

46
int get_num_chunks(struct chunkfile *cf)
47
{
48
	return cf->chunks_nr;
49
}
50

51
void add_chunk(struct chunkfile *cf,
52
	       uint32_t id,
53
	       size_t size,
54
	       chunk_write_fn fn)
55
{
56
	ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
57

58
	cf->chunks[cf->chunks_nr].id = id;
59
	cf->chunks[cf->chunks_nr].write_fn = fn;
60
	cf->chunks[cf->chunks_nr].size = size;
61
	cf->chunks_nr++;
62
}
63

64
int write_chunkfile(struct chunkfile *cf, void *data)
65
{
66
	int i, result = 0;
67
	uint64_t cur_offset = hashfile_total(cf->f);
68

69
	trace2_region_enter("chunkfile", "write", the_repository);
70

71
	/* Add the table of contents to the current offset */
72
	cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
73

74
	for (i = 0; i < cf->chunks_nr; i++) {
75
		hashwrite_be32(cf->f, cf->chunks[i].id);
76
		hashwrite_be64(cf->f, cur_offset);
77

78
		cur_offset += cf->chunks[i].size;
79
	}
80

81
	/* Trailing entry marks the end of the chunks */
82
	hashwrite_be32(cf->f, 0);
83
	hashwrite_be64(cf->f, cur_offset);
84

85
	for (i = 0; i < cf->chunks_nr; i++) {
86
		off_t start_offset = hashfile_total(cf->f);
87
		result = cf->chunks[i].write_fn(cf->f, data);
88

89
		if (result)
90
			goto cleanup;
91

92
		if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
93
			BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
94
			    cf->chunks[i].size, cf->chunks[i].id,
95
			    hashfile_total(cf->f) - start_offset);
96
	}
97

98
cleanup:
99
	trace2_region_leave("chunkfile", "write", the_repository);
100
	return result;
101
}
102

103
int read_table_of_contents(struct chunkfile *cf,
104
			   const unsigned char *mfile,
105
			   size_t mfile_size,
106
			   uint64_t toc_offset,
107
			   int toc_length,
108
			   unsigned expected_alignment)
109
{
110
	int i;
111
	uint32_t chunk_id;
112
	const unsigned char *table_of_contents = mfile + toc_offset;
113

114
	ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
115

116
	while (toc_length--) {
117
		uint64_t chunk_offset, next_chunk_offset;
118

119
		chunk_id = get_be32(table_of_contents);
120
		chunk_offset = get_be64(table_of_contents + 4);
121

122
		if (!chunk_id) {
123
			error(_("terminating chunk id appears earlier than expected"));
124
			return 1;
125
		}
126
		if (chunk_offset % expected_alignment != 0) {
127
			error(_("chunk id %"PRIx32" not %d-byte aligned"),
128
			      chunk_id, expected_alignment);
129
			return 1;
130
		}
131

132
		table_of_contents += CHUNK_TOC_ENTRY_SIZE;
133
		next_chunk_offset = get_be64(table_of_contents + 4);
134

135
		if (next_chunk_offset < chunk_offset ||
136
		    next_chunk_offset > mfile_size - the_hash_algo->rawsz) {
137
			error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
138
			      chunk_offset, next_chunk_offset);
139
			return -1;
140
		}
141

142
		for (i = 0; i < cf->chunks_nr; i++) {
143
			if (cf->chunks[i].id == chunk_id) {
144
				error(_("duplicate chunk ID %"PRIx32" found"),
145
					chunk_id);
146
				return -1;
147
			}
148
		}
149

150
		cf->chunks[cf->chunks_nr].id = chunk_id;
151
		cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
152
		cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
153
		cf->chunks_nr++;
154
	}
155

156
	chunk_id = get_be32(table_of_contents);
157
	if (chunk_id) {
158
		error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
159
		return -1;
160
	}
161

162
	return 0;
163
}
164

165
struct pair_chunk_data {
166
	const unsigned char **p;
167
	size_t *size;
168
};
169

170
static int pair_chunk_fn(const unsigned char *chunk_start,
171
			 size_t chunk_size,
172
			 void *data)
173
{
174
	struct pair_chunk_data *pcd = data;
175
	*pcd->p = chunk_start;
176
	*pcd->size = chunk_size;
177
	return 0;
178
}
179

180
int pair_chunk(struct chunkfile *cf,
181
	       uint32_t chunk_id,
182
	       const unsigned char **p,
183
	       size_t *size)
184
{
185
	struct pair_chunk_data pcd = { .p = p, .size = size };
186
	return read_chunk(cf, chunk_id, pair_chunk_fn, &pcd);
187
}
188

189
int read_chunk(struct chunkfile *cf,
190
	       uint32_t chunk_id,
191
	       chunk_read_fn fn,
192
	       void *data)
193
{
194
	int i;
195

196
	for (i = 0; i < cf->chunks_nr; i++) {
197
		if (cf->chunks[i].id == chunk_id)
198
			return fn(cf->chunks[i].start, cf->chunks[i].size, data);
199
	}
200

201
	return CHUNK_NOT_FOUND;
202
}
203

204
uint8_t oid_version(const struct git_hash_algo *algop)
205
{
206
	switch (hash_algo_by_ptr(algop)) {
207
	case GIT_HASH_SHA1:
208
		return 1;
209
	case GIT_HASH_SHA256:
210
		return 2;
211
	default:
212
		die(_("invalid hash version"));
213
	}
214
}
215

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

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

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

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