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 }