github.com/Microsoft/azure-vhd-utils@v0.0.0-20230613175315-7c30a3748a1b/vhdcore/header/parentlocator/factory.go (about)

     1  package parentlocator
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/Microsoft/azure-vhd-utils/vhdcore/reader"
     6  )
     7  
     8  // Factory type is used to create ParentLocator instance by reading one entry
     9  // in vhd header's parent-hard-disk-locator-info collection section.
    10  //
    11  type Factory struct {
    12  	vhdReader     *reader.VhdReader
    13  	locatorOffset int64
    14  }
    15  
    16  // NewFactory creates a new instance of Factory, which can be used to create ParentLocator instance
    17  // by reading one entry from the vhd header's parent-hard-disk-locator-info collection,
    18  // locatorOffset is the offset of the entry to read, vhdReader is the reader to be used to read the entry.
    19  //
    20  func NewFactory(vhdReader *reader.VhdReader, locatorOffset int64) *Factory {
    21  	return &Factory{vhdReader: vhdReader, locatorOffset: locatorOffset}
    22  }
    23  
    24  // Create creates a ParentLocator instance by reading one entry in vhd header's parent-hard-disk-locator-info
    25  // collection section of the disk. This function return error if any error occurs while reading or parsing
    26  // the parent locators table fields.
    27  //
    28  func (f *Factory) Create() (*ParentLocator, error) {
    29  	locator := &ParentLocator{}
    30  	var err error
    31  	errDone := func() (*ParentLocator, error) {
    32  		return nil, err
    33  	}
    34  
    35  	locator.PlatformCode, err = f.readPlatformCode()
    36  	if err != nil {
    37  		return errDone()
    38  	}
    39  
    40  	locator.PlatformDataSpace, err = f.readPlatformDataSpace()
    41  	if err != nil {
    42  		return errDone()
    43  	}
    44  
    45  	locator.PlatformDataLength, err = f.readPlatformDataLength()
    46  	if err != nil {
    47  		return errDone()
    48  	}
    49  
    50  	locator.Reserved, err = f.readReserved()
    51  	if err != nil {
    52  		return errDone()
    53  	}
    54  
    55  	locator.PlatformDataOffset, err = f.readPlatformDataOffset()
    56  	if err != nil {
    57  		return errDone()
    58  	}
    59  
    60  	fileLocator := make([]byte, locator.PlatformDataLength)
    61  	_, err = f.vhdReader.ReadBytes(locator.PlatformDataOffset, fileLocator)
    62  	if err != nil {
    63  		err = NewParseError("ParentLocator", fmt.Errorf("Unable to resolve file locator: %v", err))
    64  		return errDone()
    65  	}
    66  
    67  	locator.SetPlatformSpecificFileLocator(fileLocator)
    68  	return locator, nil
    69  }
    70  
    71  // readPlatformCode reads the field that stores the platform-specific format used to encode the
    72  // file locator in parent-hard-disk-locator-info
    73  // This function return error if no or fewer bytes could be read. The value is stored as 4 byte
    74  // value starting at offset 0 relative to the beginning of this parent-hard-disk-locator. This value
    75  // is stored in big-endian format.
    76  //
    77  func (f *Factory) readPlatformCode() (PlatformCode, error) {
    78  	value, err := f.vhdReader.ReadInt32(f.locatorOffset + 0)
    79  	if err != nil {
    80  		return PlatformCodeNone, NewParseError("PlatformCode", err)
    81  	}
    82  	return PlatformCode(value), nil
    83  }
    84  
    85  // readPlatformDataSpace reads the field that stores the number of 512-byte sectors needed to store
    86  // the parent hard disk file locator.  This function return error if no or fewer bytes could be read.
    87  // The value is stored as 4 byte value starting at offset 4 relative to the beginning parent-hard-disk-locator-info.
    88  // This value is stored in big-endian format.
    89  //
    90  func (f *Factory) readPlatformDataSpace() (int32, error) {
    91  	value, err := f.vhdReader.ReadInt32(f.locatorOffset + 4)
    92  	if err != nil {
    93  		return -1, NewParseError("PlatformDataSpace", err)
    94  	}
    95  	return value, nil
    96  }
    97  
    98  // readPlatformDataLength reads the field that stores the actual length of the parent hard disk
    99  // locator in bytes. This function return error if no or fewer bytes could be read. The value is stored
   100  // as 4 byte value starting at offset 8 relative to the beginning parent-hard-disk-locator-info. This value
   101  // is stored in big-endian format.
   102  //
   103  func (f *Factory) readPlatformDataLength() (int32, error) {
   104  	value, err := f.vhdReader.ReadInt32(f.locatorOffset + 8)
   105  	if err != nil {
   106  		return -1, NewParseError("PlatformDataLength", err)
   107  	}
   108  	return value, nil
   109  }
   110  
   111  // readReserved reads the reserved field value which is currently set to 0.
   112  // This function return error if no or fewer bytes could be read. The value is stored as 4 byte
   113  // value starting at offset 12 relative to the beginning parent-hard-disk-locator-info.
   114  // This value is stored in big-endian format.
   115  //
   116  func (f *Factory) readReserved() (int32, error) {
   117  	value, err := f.vhdReader.ReadInt32(f.locatorOffset + 12)
   118  	if err != nil {
   119  		return -1, NewParseError("Reserved", err)
   120  	}
   121  	return value, nil
   122  }
   123  
   124  // readPlatformDataOffset reads the field that stores the absolute file offset in bytes where the platform
   125  // specific file locator data is stored. Call to this function is panic if no or fewer bytes could be read.
   126  // The value is stored as 4 byte value starting at offset 16 relative to the beginning parent-hard-disk-locator-info.
   127  // This value is stored in big-endian format.
   128  //
   129  func (f *Factory) readPlatformDataOffset() (int64, error) {
   130  	value, err := f.vhdReader.ReadInt64(f.locatorOffset + 16)
   131  	if err != nil {
   132  		return -1, NewParseError("PlatformDataOffset", err)
   133  	}
   134  	return value, nil
   135  }