github.com/Microsoft/azure-vhd-utils@v0.0.0-20230613175315-7c30a3748a1b/vhdcore/block/differencingDiskBlockFactory.go (about) 1 package block 2 3 import ( 4 "github.com/Microsoft/azure-vhd-utils/vhdcore" 5 "github.com/Microsoft/azure-vhd-utils/vhdcore/block/bitmap" 6 "github.com/Microsoft/azure-vhd-utils/vhdcore/common" 7 ) 8 9 // DifferencingDiskBlockFactory is a type which is used for following purposes 10 // To create a Block instance representing a differencing disk block 11 // To get the number of blocks in the differencing disk 12 // To get the block size of the block in differencing disk 13 // To get a Sector instance representing sector of differencing disk's block 14 // To get the logical footer range of fixed disk generated from the differencing disk and it's parents. 15 // 16 type DifferencingDiskBlockFactory struct { 17 params *FactoryParams 18 bitmapFactory *bitmap.Factory 19 sectorFactory *SectorFactory 20 blockDataReader DataReader 21 cachedBlock *Block 22 } 23 24 // NewDifferencingDiskBlockFactory creates a DifferencingDiskBlockFactory instance which can be used to 25 // create a Block objects representing differential disk block of a size specified in header BlockSize 26 // field parameter vhdFile represents the differencing disk. 27 // 28 func NewDifferencingDiskBlockFactory(params *FactoryParams) *DifferencingDiskBlockFactory { 29 blockFactory := &DifferencingDiskBlockFactory{params: params} 30 31 blockFactory.bitmapFactory = bitmap.NewFactory(blockFactory.params.VhdReader, 32 blockFactory.params.BlockAllocationTable) 33 34 blockFactory.sectorFactory = NewSectorFactory(blockFactory.params.VhdReader, 35 blockFactory.params.BlockAllocationTable.HasData, 36 blockFactory.params.BlockAllocationTable.GetBlockDataAddress) 37 38 blockFactory.blockDataReader = NewDifferencingDiskBlockReader(blockFactory.params.VhdReader, 39 blockFactory.params.BlockAllocationTable, 40 blockFactory.params.VhdHeader.BlockSize) 41 42 return blockFactory 43 } 44 45 // GetBlockCount returns the number of blocks in the differential disk. 46 // 47 func (f *DifferencingDiskBlockFactory) GetBlockCount() int64 { 48 return int64(f.params.BlockAllocationTable.BATEntriesCount) 49 } 50 51 // GetBlockSize returns the size of the 'data section' of block in bytes in the differential disk. 52 // 53 func (f *DifferencingDiskBlockFactory) GetBlockSize() int64 { 54 return int64(f.params.VhdHeader.BlockSize) 55 } 56 57 // GetFooterRange returns the logical range of the footer when converting this differential vhd to 58 // fixed logical range of footer is the absolute start and end byte offset of the footer. 59 // 60 func (f *DifferencingDiskBlockFactory) GetFooterRange() *common.IndexRange { 61 return common.NewIndexRangeFromLength(f.GetBlockCount()*f.GetBlockSize(), vhdcore.VhdFooterSize) 62 } 63 64 // Create returns an instance of Block which represents a differencing disk block, the parameter blockIndex 65 // identifies the block. If the block to be read is marked as empty in the differencing disk BAT then this 66 // method will query parent disk for the same block. This function return error if the block cannot be created 67 // due to any read error. 68 // 69 func (f *DifferencingDiskBlockFactory) Create(blockIndex uint32) (*Block, error) { 70 if !f.params.BlockAllocationTable.HasData(blockIndex) { 71 if f.cachedBlock == nil || f.cachedBlock.BlockIndex != blockIndex { 72 var err error 73 f.cachedBlock, err = f.params.ParentBlockFactory.Create(blockIndex) 74 if err != nil { 75 return nil, err 76 } 77 } 78 79 return f.cachedBlock, nil 80 } 81 82 if f.cachedBlock == nil || f.cachedBlock.BlockIndex != blockIndex { 83 logicalRange := common.NewIndexRangeFromLength(int64(blockIndex)*f.GetBlockSize(), f.GetBlockSize()) 84 f.cachedBlock = &Block{ 85 BlockIndex: blockIndex, 86 LogicalRange: logicalRange, 87 VhdUniqueID: f.params.VhdFooter.UniqueID, 88 IsEmpty: false, 89 BlockDataReader: f.blockDataReader, 90 } 91 92 var err error 93 f.cachedBlock.BitMap, err = f.bitmapFactory.Create(blockIndex) 94 if err != nil { 95 return nil, err 96 } 97 } 98 99 return f.cachedBlock, nil 100 } 101 102 // GetSector returns an instance of Sector in a differencing disk, parameter block object identifies the block 103 // containing the sector, the parameter sectorIndex identifies the sector in the block. If the sector to be 104 // read is marked as empty in the block's bitmap then this method will query parent disk for the same sector. 105 // This function return error if the sector cannot be created due to any read error or if the requested sector 106 // index is invalid. 107 // 108 func (f *DifferencingDiskBlockFactory) GetSector(block *Block, sectorIndex uint32) (*Sector, error) { 109 blockIndex := block.BlockIndex 110 if block.IsEmpty { 111 return f.sectorFactory.CreateEmptySector(blockIndex, sectorIndex), nil 112 } 113 114 if block.BitMap != nil { 115 s, err := block.BitMap.Get(int32(sectorIndex)) 116 if err != nil { 117 return nil, err 118 } 119 120 if s { 121 return f.sectorFactory.Create(block, sectorIndex) 122 } 123 } 124 125 blockInParentDisk, err := f.params.ParentBlockFactory.Create(blockIndex) 126 if err != nil { 127 return nil, err 128 } 129 130 return f.params.ParentBlockFactory.GetSector(blockInParentDisk, sectorIndex) 131 } 132 133 // GetBitmapFactory returns an instance of BitmapFactory that can be used to create the bitmap of a block 134 // by reading block from differencing disk. 135 // 136 func (f *DifferencingDiskBlockFactory) GetBitmapFactory() *bitmap.Factory { 137 return f.bitmapFactory 138 }