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