105
107
/************************************************************************/
110
/* Load the header and some per-layer information. */
107
111
/************************************************************************/
109
void SysBlockMap::Load()
113
void SysBlockMap::PartialLoad()
115
// TODO: this should likely be protected by a mutex.
117
/* -------------------------------------------------------------------- */
118
/* Load the segment contents into a buffer. */
119
/* -------------------------------------------------------------------- */
120
seg_data.SetSize( (int) (data_size - 1024) );
122
ReadFromFile( seg_data.buffer, 0, data_size - 1024 );
124
if( strncmp(seg_data.buffer,"VERSION",7) != 0 )
125
ThrowPCIDSKException( "SysBlockMap::Load() - block map corrupt." );
127
if( seg_data.GetInt( 7, 3 ) != 1 )
128
ThrowPCIDSKException( "SysBlockMap::Load() - unsupported version." );
119
// printf( "<PartialLoad>" );
122
/* -------------------------------------------------------------------- */
123
/* Load the 512 byte count section of the blockmap. */
124
/* -------------------------------------------------------------------- */
125
PCIDSKBuffer count_data;
127
count_data.SetSize( 512 );
128
ReadFromFile( count_data.buffer, 0, 512 );
130
if( strncmp(count_data.buffer,"VERSION",7) != 0 )
131
ThrowPCIDSKException( "SysBlockMap::PartialLoad() - block map corrupt." );
133
if( count_data.GetInt( 7, 3 ) != 1 )
134
ThrowPCIDSKException( "SysBlockMap::PartialLoad() - unsupported version." );
130
136
/* -------------------------------------------------------------------- */
131
137
/* Establish our SysVirtualFile array based on the number of */
132
138
/* images listed in the image list. */
133
139
/* -------------------------------------------------------------------- */
134
int layer_count = seg_data.GetInt( 10, 8 );
136
block_count = seg_data.GetInt( 18, 8 );
137
first_free_block = seg_data.GetInt( 26, 8 );
140
int layer_count = count_data.GetInt( 10, 8 );
139
142
virtual_files.resize( layer_count );
141
block_map_offset = 512;
142
layer_list_offset = block_map_offset + 28 * block_count;
144
block_count = count_data.GetInt( 18, 8 );
145
first_free_block = count_data.GetInt( 26, 8 );
147
/* -------------------------------------------------------------------- */
148
/* Load the layer list definitions. These are fairly small. */
149
/* -------------------------------------------------------------------- */
150
layer_data.SetSize( 24 * layer_count );
151
ReadFromFile( layer_data.buffer,
152
512 + 28 * block_count,
153
layer_data.buffer_size);
155
partial_loaded = true;
160
/************************************************************************/
163
/* Load the blockmap data (can be large) into blockmap_data. */
164
/************************************************************************/
166
void SysBlockMap::FullLoad()
174
// printf( "<FullLoad>" );
177
// TODO: this should likely be protected by a mutex.
179
/* -------------------------------------------------------------------- */
180
/* Load the segment contents into a buffer. */
181
/* -------------------------------------------------------------------- */
182
blockmap_data.SetSize( block_count * 28 );
183
ReadFromFile( blockmap_data.buffer, 512, blockmap_data.buffer_size );
147
188
/************************************************************************/
151
192
void SysBlockMap::Synchronize()
154
if( !loaded || !dirty )
195
if( !full_loaded || !dirty )
157
WriteToFile( seg_data.buffer, 0, seg_data.buffer_size );
198
PCIDSKBuffer init_data(512);
200
init_data.Put( "VERSION 1", 0, 10 );
201
init_data.Put( (int) virtual_files.size(), 10, 8 );
202
init_data.Put( block_count, 18, 8 );
203
init_data.Put( first_free_block, 26, 8 );
204
init_data.Put( "", 34, 512-34 );
206
WriteToFile( init_data.buffer, 0, init_data.buffer_size );
208
WriteToFile( blockmap_data.buffer, 512, blockmap_data.buffer_size );
209
WriteToFile( layer_data.buffer, 512 + blockmap_data.buffer_size,
210
layer_data.buffer_size );
214
269
/* Allocate another set of space. */
215
270
/* -------------------------------------------------------------------- */
216
271
uint64 new_big_blocks = 16;
217
int new_bytes = new_big_blocks * SysVirtualFile::block_size;
272
uint64 new_bytes = new_big_blocks * SysVirtualFile::block_size;
218
273
seg = file->GetSegment( growing_segment );
219
int block_index_in_segment =
220
seg->GetContentSize() / SysVirtualFile::block_size;
274
int block_index_in_segment = (int)
275
(seg->GetContentSize() / SysVirtualFile::block_size);
222
277
seg->WriteToFile( "\0", seg->GetContentSize() + new_bytes - 1, 1 );
224
279
/* -------------------------------------------------------------------- */
225
/* Resize the SysBMDir segment data, growing the block map area. */
280
/* Resize the memory image of the blockmap. */
226
281
/* -------------------------------------------------------------------- */
227
if( block_map_offset + 28 * (block_count + new_big_blocks)
228
+ virtual_files.size() * 24 > (unsigned int) seg_data.buffer_size )
230
block_map_offset + 28 * (block_count + new_big_blocks)
231
+ virtual_files.size() * 24 );
233
// push the layer list on.
234
memmove( seg_data.buffer + layer_list_offset + new_big_blocks*28,
235
seg_data.buffer + layer_list_offset,
236
virtual_files.size() * 24 );
282
if( 28 * (block_count + new_big_blocks)
283
> (unsigned int) blockmap_data.buffer_size )
284
blockmap_data.SetSize( (int) (28 * (block_count + new_big_blocks)) );
238
286
/* -------------------------------------------------------------------- */
239
287
/* Fill in info on the new blocks. */
244
292
block_index < block_count + new_big_blocks;
247
uint64 bi_offset = block_map_offset + block_index * 28;
295
int bi_offset = (int) (block_index * 28);
249
seg_data.Put( growing_segment, bi_offset, 4 );
250
seg_data.Put( block_index_in_segment++, bi_offset+4, 8 );
251
seg_data.Put( -1, bi_offset+12, 8 );
297
blockmap_data.Put( growing_segment, bi_offset, 4 );
298
blockmap_data.Put( block_index_in_segment++, bi_offset+4, 8 );
299
blockmap_data.Put( -1, bi_offset+12, 8 );
253
301
if( block_index == block_count + new_big_blocks - 1 )
254
seg_data.Put( -1, bi_offset+20, 8 );
302
blockmap_data.Put( -1, bi_offset+20, 8 );
256
seg_data.Put( block_index+1, bi_offset+20, 8 );
304
blockmap_data.Put( block_index+1, bi_offset+20, 8 );
259
307
first_free_block = block_count;
260
seg_data.Put( first_free_block, 26, 8 );
262
block_count += new_big_blocks;
263
seg_data.Put( block_count, 18, 8 );
265
layer_list_offset = block_map_offset + 28 * block_count;
309
block_count += (int) new_big_blocks;
292
336
int alloc_block = first_free_block;
294
338
// update first free block to point to the next free block.
295
first_free_block = seg_data.GetInt( block_map_offset+alloc_block*28+20, 8);
296
seg_data.Put( first_free_block, 26, 8 );
339
first_free_block = blockmap_data.GetInt( alloc_block*28+20, 8);
298
341
// mark block as owned by this layer/image.
299
seg_data.Put( image, block_map_offset + alloc_block*28 + 12, 8 );
342
blockmap_data.Put( image, alloc_block*28 + 12, 8 );
301
344
// clear next free block on allocated block - it is the last in the chain
302
seg_data.Put( -1, block_map_offset + alloc_block*28 + 20, 8 );
345
blockmap_data.Put( -1, alloc_block*28 + 20, 8 );
304
347
// point the previous "last block" for this virtual file to this new block
305
348
if( last_block != -1 )
306
seg_data.Put( alloc_block, block_map_offset + last_block*28 + 20, 8 );
349
blockmap_data.Put( alloc_block, last_block*28 + 20, 8 );
308
seg_data.Put( alloc_block, layer_list_offset + image*24 + 4, 8 );
351
layer_data.Put( alloc_block, image*24 + 4, 8 );
312
block_segment_ret = seg_data.GetInt( block_map_offset+alloc_block*28, 4 );
355
block_segment_ret = blockmap_data.GetInt( alloc_block*28, 4 );
313
356
last_block = alloc_block;
315
return seg_data.GetInt( block_map_offset+alloc_block*28+4, 8 );
358
return blockmap_data.GetInt( alloc_block*28+4, 8 );
318
361
/************************************************************************/
333
378
SysVirtualFile *SysBlockMap::GetVirtualFile( int image )
338
383
if( image < 0 || image >= (int) virtual_files.size() )
339
384
ThrowPCIDSKException( "GetImageSysFile(%d): invalid image index",
342
387
if( virtual_files[image] != NULL )
343
388
return virtual_files[image];
345
uint64 vfile_length =
346
seg_data.GetUInt64( layer_list_offset + 24*image + 12, 12 );
348
seg_data.GetInt( layer_list_offset + 24*image + 4, 8 );
390
uint64 vfile_length = layer_data.GetUInt64( 24*image + 12, 12 );
391
int start_block = layer_data.GetInt( 24*image + 4, 8 );
350
393
virtual_files[image] =
351
new SysVirtualFile( dynamic_cast<CPCIDSKFile *>(file), start_block, vfile_length, seg_data,
394
new SysVirtualFile( dynamic_cast<CPCIDSKFile *>(file),
395
start_block, vfile_length,
354
398
return virtual_files[image];
382
425
/* -------------------------------------------------------------------- */
383
426
if( layer_index == virtual_files.size() )
385
seg_data.Put( (int) layer_index+1, 10, 8 );
387
if( layer_list_offset + (virtual_files.size()+1) * 24
388
> (unsigned int) seg_data.buffer_size )
389
seg_data.SetSize( layer_list_offset + (virtual_files.size()+1) * 24 );
391
virtual_files.resize(layer_index+1);
392
virtual_files[layer_index] = NULL;
428
layer_index = virtual_files.size();
429
layer_data.SetSize( (layer_index+1) * 24 );
430
virtual_files.push_back( NULL );
395
433
/* -------------------------------------------------------------------- */
397
435
/* -------------------------------------------------------------------- */
400
seg_data.Put( 2, layer_list_offset + 24*layer_index + 0, 4 );
401
seg_data.Put( -1, layer_list_offset + 24*layer_index + 4, 8 );
402
seg_data.Put( 0, layer_list_offset + 24*layer_index + 12, 12 );
438
layer_data.Put( 2, 24*layer_index + 0, 4 );
439
layer_data.Put( -1, 24*layer_index + 4, 8 );
440
layer_data.Put( 0, 24*layer_index + 12, 12 );
404
442
return layer_index;
460
498
return img_index;
501
/************************************************************************/
502
/* GetNextBlockMapEntry() */
504
/* SysVirtualFile's call this method to find the next block in */
505
/* the blockmap which belongs to them. This allows them to */
506
/* fill their blockmap "as needed" without necessarily forcing */
507
/* a full load of the blockmap. */
508
/************************************************************************/
510
int SysBlockMap::GetNextBlockMapEntry( int bm_index,
512
int &block_in_segment )
515
if( !partial_loaded )
518
/* -------------------------------------------------------------------- */
519
/* If the full blockmap is already loaded, just fetch it from */
520
/* there to avoid extra IO or confusion between what is disk */
521
/* and what is in memory. */
523
/* Otherwise we read from disk and hope the io level buffering */
524
/* is pretty good. */
525
/* -------------------------------------------------------------------- */
530
memcpy( bm_entry, blockmap_data.buffer + bm_index * 28, 28 );
534
ReadFromFile( bm_entry, bm_index * 28 + 512, 28 );
537
/* -------------------------------------------------------------------- */
538
/* Parse the values as efficiently as we can. */
539
/* -------------------------------------------------------------------- */
542
int next_block = atoi( bm_entry+20 );
545
block_in_segment = atoi(bm_entry+4);
548
segment = atoi(bm_entry);