@@ -13,6 +13,7 @@ struct chunk_info {
1313 chunk_write_fn write_fn ;
1414
1515 const void * start ;
16+ off_t offset ;
1617};
1718
1819struct chunkfile {
@@ -56,38 +57,59 @@ void add_chunk(struct chunkfile *cf,
5657 cf -> chunks_nr ++ ;
5758}
5859
59- int write_chunkfile (struct chunkfile * cf , void * data )
60+ int write_chunkfile (struct chunkfile * cf ,
61+ enum chunkfile_flags flags ,
62+ void * data )
6063{
6164 int i , result = 0 ;
62- uint64_t cur_offset = hashfile_total (cf -> f );
6365
6466 trace2_region_enter ("chunkfile" , "write" , the_repository );
6567
66- /* Add the table of contents to the current offset */
67- cur_offset += (cf -> chunks_nr + 1 ) * CHUNK_TOC_ENTRY_SIZE ;
68+ if (!( flags & CHUNKFILE_TRAILING_TOC )) {
69+ uint64_t cur_offset = hashfile_total (cf -> f ) ;
6870
69- for (i = 0 ; i < cf -> chunks_nr ; i ++ ) {
70- hashwrite_be32 (cf -> f , cf -> chunks [i ].id );
71- hashwrite_be64 (cf -> f , cur_offset );
71+ /* Add the table of contents to the current offset */
72+ cur_offset += (cf -> chunks_nr + 1 ) * CHUNK_TOC_ENTRY_SIZE ;
7273
73- cur_offset += cf -> chunks [i ].size ;
74- }
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+ }
7580
76- /* Trailing entry marks the end of the chunks */
77- hashwrite_be32 (cf -> f , 0 );
78- hashwrite_be64 (cf -> f , cur_offset );
81+ /* Trailing entry marks the end of the chunks */
82+ hashwrite_be32 (cf -> f , 0 );
83+ hashwrite_be64 (cf -> f , cur_offset );
84+ }
7985
8086 for (i = 0 ; i < cf -> chunks_nr ; i ++ ) {
81- off_t start_offset = hashfile_total (cf -> f );
87+ cf -> chunks [ i ]. offset = hashfile_total (cf -> f );
8288 result = cf -> chunks [i ].write_fn (cf -> f , data );
8389
8490 if (result )
8591 goto cleanup ;
8692
87- if (hashfile_total (cf -> f ) - start_offset != cf -> chunks [i ].size )
88- BUG ("expected to write %" PRId64 " bytes to chunk %" PRIx32 ", but wrote %" PRId64 " instead" ,
89- cf -> chunks [i ].size , cf -> chunks [i ].id ,
90- hashfile_total (cf -> f ) - start_offset );
93+ if (!(flags & CHUNKFILE_TRAILING_TOC )) {
94+ if (hashfile_total (cf -> f ) - cf -> chunks [i ].offset != cf -> chunks [i ].size )
95+ BUG ("expected to write %" PRId64 " bytes to chunk %" PRIx32 ", but wrote %" PRId64 " instead" ,
96+ cf -> chunks [i ].size , cf -> chunks [i ].id ,
97+ hashfile_total (cf -> f ) - cf -> chunks [i ].offset );
98+ }
99+
100+ cf -> chunks [i ].size = hashfile_total (cf -> f ) - cf -> chunks [i ].offset ;
101+ }
102+
103+ if (flags & CHUNKFILE_TRAILING_TOC ) {
104+ size_t last_chunk_tail = hashfile_total (cf -> f );
105+ /* First entry marks the end of the chunks */
106+ hashwrite_be32 (cf -> f , 0 );
107+ hashwrite_be64 (cf -> f , last_chunk_tail );
108+
109+ for (i = cf -> chunks_nr - 1 ; i >= 0 ; i -- ) {
110+ hashwrite_be32 (cf -> f , cf -> chunks [i ].id );
111+ hashwrite_be64 (cf -> f , cf -> chunks [i ].offset );
112+ }
91113 }
92114
93115cleanup :
@@ -151,6 +173,59 @@ int read_table_of_contents(struct chunkfile *cf,
151173 return 0 ;
152174}
153175
176+ int read_trailing_table_of_contents (struct chunkfile * cf ,
177+ const unsigned char * mfile ,
178+ size_t mfile_size )
179+ {
180+ int i ;
181+ uint32_t chunk_id ;
182+ const unsigned char * table_of_contents = mfile + mfile_size - the_hash_algo -> rawsz ;
183+
184+ while (1 ) {
185+ uint64_t chunk_offset ;
186+
187+ table_of_contents -= CHUNK_TOC_ENTRY_SIZE ;
188+
189+ chunk_id = get_be32 (table_of_contents );
190+ chunk_offset = get_be64 (table_of_contents + 4 );
191+
192+ /* Calculate the previous chunk size, if it exists. */
193+ if (cf -> chunks_nr ) {
194+ off_t previous_offset = cf -> chunks [cf -> chunks_nr - 1 ].offset ;
195+
196+ if (chunk_offset < previous_offset ||
197+ chunk_offset > table_of_contents - mfile ) {
198+ error (_ ("improper chunk offset(s) %" PRIx64 " and %" PRIx64 "" ),
199+ previous_offset , chunk_offset );
200+ return -1 ;
201+ }
202+
203+ cf -> chunks [cf -> chunks_nr - 1 ].size = chunk_offset - previous_offset ;
204+ }
205+
206+ /* Stop at the null chunk. We only need it for the last size. */
207+ if (!chunk_id )
208+ break ;
209+
210+ for (i = 0 ; i < cf -> chunks_nr ; i ++ ) {
211+ if (cf -> chunks [i ].id == chunk_id ) {
212+ error (_ ("duplicate chunk ID %" PRIx32 " found" ),
213+ chunk_id );
214+ return -1 ;
215+ }
216+ }
217+
218+ ALLOC_GROW (cf -> chunks , cf -> chunks_nr + 1 , cf -> chunks_alloc );
219+
220+ cf -> chunks [cf -> chunks_nr ].id = chunk_id ;
221+ cf -> chunks [cf -> chunks_nr ].start = mfile + chunk_offset ;
222+ cf -> chunks [cf -> chunks_nr ].offset = chunk_offset ;
223+ cf -> chunks_nr ++ ;
224+ }
225+
226+ return 0 ;
227+ }
228+
154229static int pair_chunk_fn (const unsigned char * chunk_start ,
155230 size_t chunk_size ,
156231 void * data )
0 commit comments