Prior to this patch, we did not emit a free page map to the PDB. Instead, we just wrote 0 bytes for the free page map. Since an a free page map represents a minimum of BlockSize * 8 blocks, this had the effect of saying that every PDB is a minimum of 4096*8*4096 = 134,217,728 bytes. This had undesirable side effects when re-linking our PDB with MSVC, which would output a PDB of slightly above the aforementioned size.
The fix for this is to simply write the actual bits of the FPM to appropriate block, but it is not quite that simple. Since one block of FPM data can only describe the state of 4096*8 = 32,768 blocks, supporting PDBs larger than this requires extra magic. To handle this, blocks of the form {1,2} + k * BlockSize are reserved and should not be allocated to any other type of PDB data. The FPM itself can then be viewed as a stream over the blocks {1 + 4096*0, 1 + 4096*1, 1 + 4096*2, ...} or {2 + 4096*0, 2 + 4096*1, 2 + 4096*2, ...} depending on the value of SuperBlock->FreeBlockMapBlock.
So we need some extra complexity that when allocating blocks from a stream, we check if the MSF file requires growing to vend the requested blocks. If it does, then we look to see if the growth would allocated blocks with the aforementioned indices, and if so we mark them as used in the FPM so that they will not be vended by the block allocator.
But that's not all! Another source of trickiness is in the fact that not all FPM blocks are even used. For example, if a PDB file has 5000 blocks, and SuperBlock->FreeBlockMapBlock == 1 , then blocks 1, 2, 4097, and 4098 are FPM blocks but only block 1 is allocated. And from block 1, only 625 bytes are needed. But blocks 2, 4097, and 4098 still need to be initialized to 0xFF, as do the extraneous bytes of block 1. Getting this to work invisibly while allowing the user of the API to see only those bytes of the FPM that describe actual blocks required some finesse.
Can you refactor this alignTo(X, Y) / Y pattern into a helper like divideRoundUp or divideCeil? The usual way to do that is (X + Y - 1) / Y. alignTo does stuff we don't need.