1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
4 #include "chunk-format.h"
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.
18 chunk_write_fn write_fn
;
26 struct chunk_info
*chunks
;
31 struct chunkfile
*init_chunkfile(struct hashfile
*f
)
33 struct chunkfile
*cf
= xcalloc(1, sizeof(*cf
));
38 void free_chunkfile(struct chunkfile
*cf
)
46 int get_num_chunks(struct chunkfile
*cf
)
51 void add_chunk(struct chunkfile
*cf
,
56 ALLOC_GROW(cf
->chunks
, cf
->chunks_nr
+ 1, cf
->chunks_alloc
);
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
;
64 int write_chunkfile(struct chunkfile
*cf
, void *data
)
67 uint64_t cur_offset
= hashfile_total(cf
->f
);
69 trace2_region_enter("chunkfile", "write", the_repository
);
71 /* Add the table of contents to the current offset */
72 cur_offset
+= (cf
->chunks_nr
+ 1) * CHUNK_TOC_ENTRY_SIZE
;
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
);
78 cur_offset
+= cf
->chunks
[i
].size
;
81 /* Trailing entry marks the end of the chunks */
82 hashwrite_be32(cf
->f
, 0);
83 hashwrite_be64(cf
->f
, cur_offset
);
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
);
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
);
99 trace2_region_leave("chunkfile", "write", the_repository
);
103 int read_table_of_contents(struct chunkfile
*cf
,
104 const unsigned char *mfile
,
108 unsigned expected_alignment
)
112 const unsigned char *table_of_contents
= mfile
+ toc_offset
;
114 ALLOC_GROW(cf
->chunks
, toc_length
, cf
->chunks_alloc
);
116 while (toc_length
--) {
117 uint64_t chunk_offset
, next_chunk_offset
;
119 chunk_id
= get_be32(table_of_contents
);
120 chunk_offset
= get_be64(table_of_contents
+ 4);
123 error(_("terminating chunk id appears earlier than expected"));
126 if (chunk_offset
% expected_alignment
!= 0) {
127 error(_("chunk id %"PRIx32
" not %d-byte aligned"),
128 chunk_id
, expected_alignment
);
132 table_of_contents
+= CHUNK_TOC_ENTRY_SIZE
;
133 next_chunk_offset
= get_be64(table_of_contents
+ 4);
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
);
142 for (i
= 0; i
< cf
->chunks_nr
; i
++) {
143 if (cf
->chunks
[i
].id
== chunk_id
) {
144 error(_("duplicate chunk ID %"PRIx32
" found"),
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
;
156 chunk_id
= get_be32(table_of_contents
);
158 error(_("final chunk has non-zero id %"PRIx32
""), chunk_id
);
165 struct pair_chunk_data
{
166 const unsigned char **p
;
170 static int pair_chunk_fn(const unsigned char *chunk_start
,
174 struct pair_chunk_data
*pcd
= data
;
175 *pcd
->p
= chunk_start
;
176 *pcd
->size
= chunk_size
;
180 int pair_chunk(struct chunkfile
*cf
,
182 const unsigned char **p
,
185 struct pair_chunk_data pcd
= { .p
= p
, .size
= size
};
186 return read_chunk(cf
, chunk_id
, pair_chunk_fn
, &pcd
);
189 int read_chunk(struct chunkfile
*cf
,
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
);
201 return CHUNK_NOT_FOUND
;
204 uint8_t oid_version(const struct git_hash_algo
*algop
)
206 switch (hash_algo_by_ptr(algop
)) {
209 case GIT_HASH_SHA256
:
212 die(_("invalid hash version"));