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

     1  package vhdfile
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"github.com/Microsoft/azure-vhd-utils/vhdcore/bat"
     8  	"github.com/Microsoft/azure-vhd-utils/vhdcore/footer"
     9  	"github.com/Microsoft/azure-vhd-utils/vhdcore/header"
    10  	"github.com/Microsoft/azure-vhd-utils/vhdcore/reader"
    11  )
    12  
    13  // FileFactory is a type to create VhdFile representing VHD in the local machine
    14  //
    15  type FileFactory struct {
    16  	vhdDir               string       // Path to the directory holding VHD file
    17  	fd                   *os.File     // File descriptor of the VHD file
    18  	parentVhdFileFactory *FileFactory // Reference to the parent VhdFileFactory if this VHD file is parent of a dynamic VHD
    19  	childVhdFileFactory  *FileFactory // Reference to the child VhdFileFactory if this VHD file has dynamic VHD child
    20  }
    21  
    22  // Create creates a new VhdFile representing a VHD in the local machine located at vhdPath
    23  //
    24  func (f *FileFactory) Create(vhdPath string) (*VhdFile, error) {
    25  	var err error
    26  	if f.fd, err = os.Open(vhdPath); err != nil {
    27  		f.Dispose(err)
    28  		return nil, err
    29  	}
    30  
    31  	f.vhdDir = filepath.Dir(vhdPath)
    32  	fStat, _ := f.fd.Stat()
    33  	file, err := f.CreateFromReaderAtReader(f.fd, fStat.Size())
    34  	if err != nil {
    35  		f.Dispose(err)
    36  		return nil, err
    37  	}
    38  
    39  	return file, nil
    40  }
    41  
    42  // CreateFromReaderAtReader creates a new VhdFile from a reader.ReadAtReader, which is a reader associated
    43  // with a VHD in the local machine. The parameter size is the size of the VHD in bytes
    44  //
    45  func (f *FileFactory) CreateFromReaderAtReader(r reader.ReadAtReader, size int64) (*VhdFile, error) {
    46  	vhdReader := reader.NewVhdReader(r, size)
    47  	vhdFooter, err := (footer.NewFactory(vhdReader)).Create()
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	vhdFile := VhdFile{
    53  		Footer:    vhdFooter,
    54  		VhdReader: vhdReader,
    55  	}
    56  
    57  	if vhdFooter.DiskType == footer.DiskTypeFixed {
    58  		return &vhdFile, nil
    59  	}
    60  
    61  	// Disk is an expanding type (Dynamic or differencing)
    62  	vhdHeader, err := (header.NewFactory(vhdReader, vhdFooter.HeaderOffset)).Create()
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	vhdFile.Header = vhdHeader
    67  
    68  	vhdBlockAllocationTable, err := (bat.NewBlockAllocationFactory(vhdReader, vhdHeader)).Create()
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	vhdFile.BlockAllocationTable = vhdBlockAllocationTable
    73  
    74  	if vhdFooter.DiskType == footer.DiskTypeDynamic {
    75  		return &vhdFile, nil
    76  	}
    77  
    78  	var parentPath string
    79  	if f.vhdDir == "." || f.vhdDir == string(os.PathSeparator) {
    80  		parentPath = vhdHeader.ParentPath
    81  	} else {
    82  		parentPath = filepath.Join(parentPath, vhdHeader.ParentLocators.GetRelativeParentPath())
    83  	}
    84  
    85  	// Insert a node in the doubly linked list of VhdFileFactory chain.
    86  	f.parentVhdFileFactory = &FileFactory{childVhdFileFactory: f}
    87  	// Set differencing disk parent VhdFile
    88  	vhdFile.Parent, err = f.parentVhdFileFactory.Create(parentPath)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	return &vhdFile, nil
    94  }
    95  
    96  // Dispose disposes this instance of VhdFileFactory and VhdFileFactory instances of parent and child
    97  // VHDs
    98  //
    99  func (f *FileFactory) Dispose(err error) {
   100  	if f.fd != nil {
   101  		f.fd.Close()
   102  		f.fd = nil
   103  	}
   104  
   105  	if f.parentVhdFileFactory != nil {
   106  		f.parentVhdFileFactory.disposeUp(err)
   107  	}
   108  
   109  	if f.childVhdFileFactory != nil {
   110  		f.childVhdFileFactory.disposeDown(err)
   111  	}
   112  }
   113  
   114  // Dispose disposes this instance of VhdFileFactory and VhdFileFactory instances of all ancestor VHDs
   115  //
   116  func (f *FileFactory) disposeUp(err error) {
   117  	if f.fd != nil {
   118  		f.fd.Close()
   119  		f.fd = nil
   120  	}
   121  
   122  	if f.parentVhdFileFactory != nil {
   123  		f.parentVhdFileFactory.disposeUp(err)
   124  	}
   125  }
   126  
   127  // Dispose disposes this instance of VhdFileFactory and VhdFileFactory instances of all descendant VHDs
   128  //
   129  func (f *FileFactory) disposeDown(err error) {
   130  	if f.fd != nil {
   131  		f.fd.Close()
   132  		f.fd = nil
   133  	}
   134  
   135  	if f.childVhdFileFactory != nil {
   136  		f.childVhdFileFactory.disposeDown(err)
   137  	}
   138  }