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  }