diff options
Diffstat (limited to 'bfd/pdb.c')
-rw-r--r-- | bfd/pdb.c | 57 |
1 files changed, 48 insertions, 9 deletions
@@ -412,7 +412,8 @@ pdb_allocate_block (uint32_t *num_blocks, uint32_t block_size) static bool pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, - uint32_t block_map_addr, uint32_t * num_blocks) + uint32_t block_map_addr, uint32_t * num_blocks, + uint32_t *stream0_start) { char tmp[sizeof (uint32_t)]; uint32_t block, left, block_map_off; @@ -561,6 +562,9 @@ pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, return false; } + if (arelt == abfd->archive_head && i == 0) + *stream0_start = file_block; + left -= sizeof (uint32_t); /* Read file contents into buffer. */ @@ -617,7 +621,8 @@ pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, } static bool -pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) +pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks, + uint32_t stream0_start) { char *buf; uint32_t num_intervals = (num_blocks + block_size - 1) / block_size; @@ -626,8 +631,6 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) if (!buf) return false; - num_blocks--; /* Superblock not included. */ - for (uint32_t i = 0; i < num_intervals; i++) { if (bfd_seek (abfd, ((i * block_size) + 1) * block_size, SEEK_SET)) @@ -636,8 +639,8 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) return false; } - /* All of our blocks are contiguous, making our free block map simple. - 0 = used, 1 = free. */ + /* All of our blocks are contiguous, making our free block map + relatively simple. 0 = used, 1 = free. */ if (num_blocks >= 8) memset (buf, 0, @@ -650,7 +653,7 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) if (num_blocks % 8) { - buf[off] = (1 << (8 - (num_blocks % 8))) - 1; + buf[off] = 256 - (1 << (num_blocks % 8)); off++; } @@ -658,6 +661,40 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) memset (buf + off, 0xff, block_size - off); } + /* Mark the blocks allocated to stream 0 as free. This is because stream + 0 is intended to be used for the previous MSF directory, to allow + atomic updates. This doesn't apply to us, as we rewrite the whole + file whenever any change is made. */ + + if (i == 0 && abfd->archive_head) + { + bfd *arelt = abfd->archive_head; + uint32_t stream0_blocks = + (bfd_get_size (arelt) + block_size - 1) / block_size; + + if (stream0_start % 8) + { + unsigned int high_bit; + + high_bit = (stream0_start % 8) + stream0_blocks; + if (high_bit > 8) + high_bit = 8; + + buf[stream0_start / 8] |= + (1 << high_bit) - (1 << (stream0_start % 8)); + + stream0_blocks -= high_bit - (stream0_start % 8); + stream0_start += high_bit - (stream0_start % 8); + } + + memset (buf + (stream0_start / 8), 0xff, stream0_blocks / 8); + stream0_start += stream0_blocks / 8; + stream0_blocks %= 8; + + if (stream0_blocks > 0) + buf[stream0_start / 8] |= (1 << stream0_blocks) - 1; + } + if (num_blocks < block_size * 8) num_blocks = 0; else @@ -681,6 +718,7 @@ pdb_write_contents (bfd *abfd) uint32_t num_blocks; uint32_t num_files = 0; uint32_t num_directory_bytes = sizeof (uint32_t); + uint32_t stream0_start = 0; bfd *arelt; if (bfd_write (pdb_magic, sizeof (pdb_magic), abfd) != sizeof (pdb_magic)) @@ -735,10 +773,11 @@ pdb_write_contents (bfd *abfd) return false; if (!pdb_write_directory - (abfd, block_size, num_files, block_map_addr, &num_blocks)) + (abfd, block_size, num_files, block_map_addr, &num_blocks, + &stream0_start)) return false; - if (!pdb_write_bitmap (abfd, block_size, num_blocks)) + if (!pdb_write_bitmap (abfd, block_size, num_blocks, stream0_start)) return false; /* Write num_blocks now we know it. */ |