github.com/Microsoft/azure-vhd-utils@v0.0.0-20230613175315-7c30a3748a1b/vhdcore/bat/blockAllocationTable.go (about) 1 package bat 2 3 import ( 4 "math" 5 6 "github.com/Microsoft/azure-vhd-utils/vhdcore" 7 ) 8 9 // BlockAllocationTable type represents the Block Allocation Table (BAT) of the disk, BAT served as 10 // index to access the disk's blocks. 11 // A block is a unit of expansion for dynamic and differencing hard disks. All blocks within a given 12 // image must be the same size. 13 // The number of entries in the BAT is the number of blocks needed to store the contents of the disk 14 // when fully expanded. Each entry in this table is the absolute sector offset to a block. Each entry 15 // is four bytes long. if the disk is not fully expanded then, even though BAT has entries reserved 16 // for unexpanded blocks, the corresponding block will not exists. All such unused table entries 17 // are initialized to 0xFFFFFFFF. 18 // A block consists of two sections 'data section' and 'block bitmap section'. The 'BlockSize' field 19 // of the disk header is the size of the 'data section' of the block, it does not include the size of 20 // the 'block bitmap section'. Each bit in the bitmap indicates the state of the corresponding sector 21 // in 'data section', 1 indicates sector contains valid data, 0 indicates the sector have never been 22 // modified. 23 // 24 type BlockAllocationTable struct { 25 BATEntriesCount uint32 26 BAT []uint32 27 blockSize uint32 28 } 29 30 // NewBlockAllocationTable creates an instance of BlockAllocationTable, BAT is the block allocation table, 31 // each entry in this table is the absolute sector offset to a block, blockSize is the size of block's 32 // 'data section' in bytes. 33 // 34 func NewBlockAllocationTable(blockSize uint32, bat []uint32) *BlockAllocationTable { 35 return &BlockAllocationTable{BATEntriesCount: uint32(len(bat)), blockSize: blockSize, BAT: bat} 36 } 37 38 // GetBitmapSizeInBytes returns the size of the 'block bitmap section' that stores the state 39 // of the sectors in block's 'data section'. This means the number of bits in the bitmap is equivalent 40 // to the number of sectors in 'data section', dividing this number by 8 will yield the number of bytes 41 // required to store the bitmap. 42 // As per vhd specification sectors per block must be power of two. The sector length is always 512 bytes. 43 // This means the block size will be power of two as well e.g. 512 * 2^3, 512 * 2^4, 512 * 2^5 etc.. 44 // 45 func (b *BlockAllocationTable) GetBitmapSizeInBytes() int32 { 46 return int32(b.blockSize / uint32(vhdcore.VhdSectorLength) / 8) 47 } 48 49 // GetSectorPaddedBitmapSizeInBytes returns the size of the 'block bitmap section' in bytes which is 50 // padded to a 512-byte sector boundary. The bitmap of a block is always padded to a 512-byte sector 51 // boundary. 52 func (b *BlockAllocationTable) GetSectorPaddedBitmapSizeInBytes() int32 { 53 sectorSizeInBytes := float64(vhdcore.VhdSectorLength) 54 bitmapSizeInBytes := float64(b.GetBitmapSizeInBytes()) 55 return int32(math.Ceil(bitmapSizeInBytes/sectorSizeInBytes) * sectorSizeInBytes) 56 } 57 58 // GetBitmapAddress returns the address of the 'block bitmap section' of a given block. Address is the 59 // absolute byte offset of the 'block bitmap section'. A block consists of 'block bitmap section' and 60 // 'data section' 61 // 62 func (b *BlockAllocationTable) GetBitmapAddress(blockIndex uint32) int64 { 63 return int64(b.BAT[blockIndex]) * vhdcore.VhdSectorLength 64 } 65 66 // GetBlockDataAddress returns the address of the 'data section' of a given block. Address is the absolute 67 // byte offset of the 'data section'. A block consists of 'block bitmap section' and 'data section' 68 // 69 func (b *BlockAllocationTable) GetBlockDataAddress(blockIndex uint32) int64 { 70 return b.GetBitmapAddress(blockIndex) + int64(b.GetSectorPaddedBitmapSizeInBytes()) 71 } 72 73 // HasData returns true if the given block has not yet expanded hence contains no data. 74 // 75 func (b *BlockAllocationTable) HasData(blockIndex uint32) bool { 76 return blockIndex != vhdcore.VhdNoDataInt && b.BAT[blockIndex] != vhdcore.VhdNoDataInt 77 }