manageiq-smartstate 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +31 -0
- data/.rspec +0 -1
- data/.whitesource +3 -0
- data/Gemfile +1 -1
- data/README.md +1 -2
- data/lib/MiqVm/MiqRhevmVm.rb +1 -0
- data/lib/MiqVm/MiqVm.rb +0 -7
- data/lib/blackbox/VmBlackBox.rb +1 -0
- data/lib/db/MiqBdb/MiqBdb.rb +1 -0
- data/lib/db/MiqBdb/MiqBdbBtree.rb +1 -0
- data/lib/db/MiqBdb/MiqBdbHash.rb +1 -0
- data/lib/db/MiqBdb/MiqBdbPage.rb +1 -0
- data/lib/disk/DiskProbe.rb +2 -1
- data/lib/disk/modules/MiqLargeFile.rb +1 -0
- data/lib/fs/ntfs/attrib_file_name.rb +1 -0
- data/lib/fs/ntfs/attrib_standard_information.rb +1 -0
- data/lib/manageiq/smartstate/version.rb +1 -1
- data/lib/metadata/MIQExtract/MIQExtract.rb +1 -0
- data/lib/metadata/ScanProfile/ScanProfilesBase.rb +1 -0
- data/lib/metadata/VmConfig/GetNativeCfg.rb +1 -0
- data/lib/metadata/VmConfig/VmConfig.rb +1 -0
- data/lib/metadata/VmConfig/ovfConfig.rb +1 -0
- data/lib/metadata/VmConfig/vmcConfig.rb +1 -0
- data/lib/metadata/VmConfig/xmlConfig.rb +1 -6
- data/lib/metadata/linux/LinuxInitProcs.rb +1 -0
- data/lib/metadata/linux/LinuxOSInfo.rb +1 -0
- data/lib/metadata/linux/LinuxPackages.rb +1 -0
- data/lib/metadata/linux/LinuxSystemd.rb +1 -0
- data/lib/metadata/linux/LinuxUsers.rb +1 -0
- data/lib/metadata/linux/MiqConaryPackages.rb +1 -0
- data/lib/metadata/linux/MiqRpmPackages.rb +1 -0
- data/lib/metadata/util/md5deep.rb +1 -0
- data/lib/metadata/util/win32/Win32Accounts.rb +1 -0
- data/lib/metadata/util/win32/Win32EventLog.rb +1 -0
- data/lib/metadata/util/win32/Win32Services.rb +1 -0
- data/lib/metadata/util/win32/Win32Software.rb +1 -0
- data/lib/metadata/util/win32/Win32System.rb +1 -0
- data/lib/metadata/util/win32/fleece_hives.rb +1 -0
- data/lib/metadata/util/win32/ms-registry.rb +1 -0
- data/lib/metadata/util/win32/remote-registry.rb +1 -0
- data/manageiq-smartstate.gemspec +4 -5
- metadata +7 -32
- data/.travis.yml +0 -15
- data/lib/MiqVm/miq_scvmm_vm.rb +0 -39
- data/lib/Scvmm/miq_hyperv_disk.rb +0 -274
- data/lib/Scvmm/miq_scvmm_parse_powershell.rb +0 -75
- data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +0 -135
- data/lib/disk/modules/MSCommon.rb +0 -354
- data/lib/disk/modules/MSVSDiffDisk.rb +0 -85
- data/lib/disk/modules/MSVSDiskProbe.rb +0 -61
- data/lib/disk/modules/MSVSDynamicDisk.rb +0 -36
- data/lib/disk/modules/MSVSFixedDisk.rb +0 -39
- data/lib/disk/modules/VhdxDisk.rb +0 -629
- data/lib/disk/modules/VhdxDiskProbe.rb +0 -46
- data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +0 -41
@@ -1,354 +0,0 @@
|
|
1
|
-
require 'disk/modules/MiqLargeFile'
|
2
|
-
require 'miq_unicode'
|
3
|
-
require 'binary_struct'
|
4
|
-
require 'memory_buffer'
|
5
|
-
require 'Scvmm/miq_hyperv_disk'
|
6
|
-
|
7
|
-
module MSCommon
|
8
|
-
using ManageIQ::UnicodeString
|
9
|
-
|
10
|
-
# NOTE: All values are stored in network byte order.
|
11
|
-
|
12
|
-
FOOTER = BinaryStruct.new([
|
13
|
-
'a8', 'cookie', # Always 'conectix'.
|
14
|
-
'N', 'features', # Should be 2 or 3 (bit 0 is temp disk).
|
15
|
-
'N', 'version', # Major/Minor file format version.
|
16
|
-
'N', 'data_offset_hi', # Offset from beginning of file to next data struct (dyn & diff only, 0xffffffff for fixed).
|
17
|
-
'N', 'data_offset_lo',
|
18
|
-
'N', 'time_stamp', # Create time (sec since Jan 1 2000 12:00 AM in GMT).
|
19
|
-
'a4', 'creator_app', # Virtual PC = 'vpc ', Virtual Server = 'vs '.
|
20
|
-
'N', 'creator_ver', # Major/Minor ver of creator app.
|
21
|
-
'N', 'creator_host', # Creator host: Windows = 0x5769326b ('Wi2k'); Macintosh = 0x4d616320 ('Mac ').
|
22
|
-
'N', 'original_size_hi', # Original size of disk.
|
23
|
-
'N', 'original_size_lo',
|
24
|
-
'N', 'current_size_hi', # Current size of the disk.
|
25
|
-
'N', 'current_size_lo',
|
26
|
-
'N', 'disk_geometry', # CHS (byte sizes 2, 1, 1) values for disk.
|
27
|
-
'N', 'disk_type', # Disk subtype (Fixed, Dynamic or Differencing).
|
28
|
-
'N', 'checksum', # One's compliment of sum of struct minus this field.
|
29
|
-
'a16', 'unique_id', # UUID.
|
30
|
-
'C', 'saved_state', # If 1, system is in 'saved state'.
|
31
|
-
])
|
32
|
-
|
33
|
-
HEADER = BinaryStruct.new([
|
34
|
-
'a8', 'cookie', # Always 'cxsparse'.
|
35
|
-
'Q', 'data_offset', # Unused, should be 0xffffffff.
|
36
|
-
'N', 'table_offset_hi', # Byte offset to the Block Allocation Table.
|
37
|
-
'N', 'table_offset_lo',
|
38
|
-
'N', 'header_ver', # Major/Minor header version.
|
39
|
-
'N', 'max_tbl_ent', # Max entries in the BAT.
|
40
|
-
'N', 'block_size', # Size of data section of a block, default 2M (0x00200000).
|
41
|
-
'N', 'checksum', # One's compliment sum of all fields minus this one.
|
42
|
-
'a16', 'parent_uuid', # Parent disk UUID (for differencing disk only).
|
43
|
-
'N', 'parent_tstamp', # MTime of parent disk (sec since Jan 1 2000 12:00 AM in GMT).
|
44
|
-
'N', 'reserved1', # reserved, should be 0.
|
45
|
-
'a512', 'parent_uname', # Parent disk filename in UNICODE (UTF-16).
|
46
|
-
'a24', 'parent_loc1', # Parent locator entries.
|
47
|
-
'a24', 'parent_loc2',
|
48
|
-
'a24', 'parent_loc3',
|
49
|
-
'a24', 'parent_loc4',
|
50
|
-
'a24', 'parent_loc5',
|
51
|
-
'a24', 'parent_loc6',
|
52
|
-
'a24', 'parent_loc7',
|
53
|
-
'a24', 'parent_loc8',
|
54
|
-
])
|
55
|
-
|
56
|
-
PARENT_LOCATOR = BinaryStruct.new([
|
57
|
-
'a4', 'platform_code', # Platform specific format used for locator.
|
58
|
-
'N', 'data_space', # Number of sectors used to store locator.
|
59
|
-
'N', 'data_length', # Byte length of locator.
|
60
|
-
'N', 'reserved1', # Must be zero.
|
61
|
-
'N', 'data_offset_hi', # Absolute byte offset of locator.
|
62
|
-
'N', 'data_offset_lo',
|
63
|
-
])
|
64
|
-
|
65
|
-
BAE_SIZE = 4
|
66
|
-
SECTOR_LENGTH = 512
|
67
|
-
FOOTER_LENGTH = 512
|
68
|
-
HEADER_LOCATION = 512
|
69
|
-
BLOCK_NOT_ALLOCATED = 0xffffffff
|
70
|
-
SUPPORTED_HEADER_VERSION = 0x00010000
|
71
|
-
|
72
|
-
def self.connect_to_hyperv(ostruct)
|
73
|
-
connection = ostruct.hyperv_connection
|
74
|
-
@network = ostruct.driveType == "Network"
|
75
|
-
hyperv_disk = MiqHyperVDisk.new(connection[:host],
|
76
|
-
connection[:user],
|
77
|
-
connection[:password],
|
78
|
-
connection[:port],
|
79
|
-
@network)
|
80
|
-
hyperv_disk.open(ostruct.fileName)
|
81
|
-
hyperv_disk
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.d_init_common(dInfo, file)
|
85
|
-
@dInfo = dInfo
|
86
|
-
@blockSize = SECTOR_LENGTH
|
87
|
-
@file = file
|
88
|
-
|
89
|
-
# Get file, footer & header, do footer verification.
|
90
|
-
@footer = getFooter(@file, true)
|
91
|
-
@header = getHeader(@footer, true)
|
92
|
-
verifyFooterCopy(@footer)
|
93
|
-
|
94
|
-
# Verify footer copy.
|
95
|
-
|
96
|
-
# Verify format version number (must be 0x00010000).
|
97
|
-
raise "Incompatible header version: 0x#{'%04x' % @header['header_ver']}" if @header['header_ver'] != SUPPORTED_HEADER_VERSION
|
98
|
-
|
99
|
-
# Calc sectors per block, bytes in block sector bitmap & BAT loc.
|
100
|
-
@secPerBlock = @header['block_size'] / @blockSize
|
101
|
-
@blockSectorBitmapByteCount = @secPerBlock / 8
|
102
|
-
if (bd = @blockSectorBitmapByteCount % 512) != 0
|
103
|
-
@blockSectorBitmapByteCount = @blockSectorBitmapByteCount + 512 - bd
|
104
|
-
end
|
105
|
-
@batBase = getHiLo(@header, "table_offset")
|
106
|
-
process_bae
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.d_read_common(pos, len, parent = nil)
|
110
|
-
# Get starting & ending block, sector & byte offset of read.
|
111
|
-
blockStart, sectorStart, byteOffsetStart = blockPos(pos)
|
112
|
-
blockEnd, sectorEnd, byteOffsetEnd = blockPos(pos + len - 1)
|
113
|
-
|
114
|
-
# Loop on blocks (2M entities of storage).
|
115
|
-
buf = ""
|
116
|
-
(blockStart..blockEnd).each do |blockNum|
|
117
|
-
# Loop on sectors (512 byte entities of storage).
|
118
|
-
secStart = (blockNum == blockStart) ? sectorStart : 0
|
119
|
-
secEnd = (blockNum == blockEnd) ? sectorEnd : @secPerBlock - 1
|
120
|
-
(secStart..secEnd).each do |secNum|
|
121
|
-
# If STARTING, need to skip to where data is
|
122
|
-
if (blockStart == blockEnd) && (sectorStart == sectorEnd)
|
123
|
-
byteOffset = byteOffsetStart
|
124
|
-
thisLen = len
|
125
|
-
elsif (blockNum == blockStart) && (secNum == sectorStart)
|
126
|
-
byteOffset = byteOffsetStart
|
127
|
-
thisLen = @blockSize - byteOffset
|
128
|
-
# If ENDING, need to account for short read
|
129
|
-
elsif (blockNum == blockEnd) && (secNum == sectorEnd)
|
130
|
-
byteOffset = 0
|
131
|
-
thisLen = len - buf.length
|
132
|
-
raise "Internal Error: Calculated read more than sector: #{thisLen}" if thisLen > @blockSize
|
133
|
-
# Read ENTIRE Sector in all other cases
|
134
|
-
else
|
135
|
-
byteOffset = 0
|
136
|
-
thisLen = @blockSize
|
137
|
-
end
|
138
|
-
|
139
|
-
# If the allocation status of this sector is 0 return zeros.
|
140
|
-
allocStat = getAllocStatus(blockNum, secNum)
|
141
|
-
if allocStat == false
|
142
|
-
if parent.nil?
|
143
|
-
buf << MemoryBuffer.create(thisLen)
|
144
|
-
else
|
145
|
-
buf << parent.d_read(pos + buf.length, thisLen)
|
146
|
-
end
|
147
|
-
else
|
148
|
-
@file.seek(getAbsSectorLoc(blockNum, secNum) + byteOffset, IO::SEEK_SET)
|
149
|
-
buf << @file.read(thisLen)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
buf
|
154
|
-
end
|
155
|
-
|
156
|
-
def self.d_write_common(pos, buf, len, parent = nil)
|
157
|
-
# Get starting & ending block, sector & byte offset of read.
|
158
|
-
blockStart, sectorStart, byteOffsetStart = blockPos(pos)
|
159
|
-
blockEnd, sectorEnd, byteOffsetEnd = blockPos(pos + len - 1)
|
160
|
-
|
161
|
-
# Loop on blocks (2M entities of storage).
|
162
|
-
bytesWritten = 0
|
163
|
-
(blockStart..blockEnd).each do |blockNum|
|
164
|
-
# Loop on sectors (512 byte entities of storage).
|
165
|
-
secStart = (blockNum == blockStart) ? sectorStart : 0
|
166
|
-
secEnd = (blockNum == blockEnd) ? sectorEnd : @secPerBlock - 1
|
167
|
-
(secStart..secEnd).each do |secNum|
|
168
|
-
# If STARTING, need to skip to where data is
|
169
|
-
if (blockStart == blockEnd) && (sectorStart == sectorEnd)
|
170
|
-
byteOffset = byteOffsetStart
|
171
|
-
thisLen = len
|
172
|
-
elsif (blockNum == blockStart) && (secNum == sectorStart)
|
173
|
-
byteOffset = byteOffsetStart
|
174
|
-
thisLen = @blockSize - byteOffset
|
175
|
-
# If ENDING, need to account for short read
|
176
|
-
elsif (blockNum == blockEnd) && (secNum == sectorEnd)
|
177
|
-
byteOffset = 0
|
178
|
-
thisLen = len - bytesWritten
|
179
|
-
raise "Internal Error: Calculated read more than sector: #{thisLen}" if thisLen > @blockSize
|
180
|
-
# Read ENTIRE Sector in all other cases
|
181
|
-
else
|
182
|
-
byteOffset = 0
|
183
|
-
thisLen = @blockSize
|
184
|
-
end
|
185
|
-
|
186
|
-
# If the allocation status of this sector is 0 then allocate it.
|
187
|
-
allocStat = getAllocStatus(blockNum, secNum)
|
188
|
-
allocSector(blockNum, secNum, pos + bytesWritten, parent) if allocStat == false
|
189
|
-
@file.seek(getAbsSectorLoc(blockNum, secNum) + byteOffset, IO::SEEK_SET)
|
190
|
-
bytesWritten += @file.write(buf[bytesWritten, thisLen], thisLen)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
bytesWritten
|
194
|
-
end
|
195
|
-
|
196
|
-
# Disk size in sectors.
|
197
|
-
def self.d_size_common
|
198
|
-
getHiLo(@footer, "current_size") / @blockSize
|
199
|
-
end
|
200
|
-
|
201
|
-
def self.getHiLo(hash, member)
|
202
|
-
(hash["#{member}_hi"] << 32) + hash["#{member}_lo"]
|
203
|
-
end
|
204
|
-
|
205
|
-
# Needed by diff disk.
|
206
|
-
def self.header
|
207
|
-
@header
|
208
|
-
end
|
209
|
-
|
210
|
-
def self.getFooter(file, skip_check = false)
|
211
|
-
# NOTE: Spec says that if checksum fails use the copy in the header.
|
212
|
-
# If that fails then the disk is corrupt.
|
213
|
-
file.seek(file.size - FOOTER_LENGTH, IO::SEEK_SET)
|
214
|
-
@footerBuf = file.read(FOOTER_LENGTH)
|
215
|
-
footer = FOOTER.decode(@footerBuf)
|
216
|
-
# TODO: Find out why this checksum test is failing. For now don't call getFooter without skip_check set to "true"
|
217
|
-
unless skip_check
|
218
|
-
footerCsum = checksum(@footerBuf, 64)
|
219
|
-
raise "Footer checksum doesn't match: got 0x#{'%04x' % footerCsum}, s/b 0x#{'%04x' % @footer['checksum']}" if footerCsum != footer['checksum']
|
220
|
-
end
|
221
|
-
footer
|
222
|
-
end
|
223
|
-
|
224
|
-
private
|
225
|
-
|
226
|
-
def self.getHeader(footer, skip_check = false)
|
227
|
-
hdrLoc = getHiLo(footer, "data_offset")
|
228
|
-
hdrSiz = HEADER.size
|
229
|
-
puts "VHD Header is mislocated: 0x#{'%04x' % hdrLoc} (s/b 0x0200)" if hdrLoc != HEADER_LOCATION && !skip_check
|
230
|
-
@file.seek(hdrLoc, IO::SEEK_SET)
|
231
|
-
buf = @file.read(hdrSiz)
|
232
|
-
header = HEADER.decode(buf)
|
233
|
-
# TODO: Find out why this checksum test is failing. For now don't call getHeader without skip_check set to "true"
|
234
|
-
unless skip_check
|
235
|
-
headerCsum = checksum(buf, 36)
|
236
|
-
raise "Header checksum doesn't match: got 0x#{'%04x' % headerCsum}, s/b 0x#{'%04x' % @header['checksum']}" if headerCsum != header['checksum']
|
237
|
-
end
|
238
|
-
header
|
239
|
-
end
|
240
|
-
|
241
|
-
def self.verifyFooterCopy(footer)
|
242
|
-
hdrLoc = getHiLo(footer, "data_offset")
|
243
|
-
@file.seek(hdrLoc - FOOTER_LENGTH, IO::SEEK_SET)
|
244
|
-
footer_copy = FOOTER.decode(@file.read(FOOTER_LENGTH))
|
245
|
-
puts "Footer copy does not match header." if footer_copy != @footer
|
246
|
-
end
|
247
|
-
|
248
|
-
def self.blockPos(pos)
|
249
|
-
rawSectorNumber, byteOffset = pos.divmod(@blockSize)
|
250
|
-
blockNumber, secInBlock = rawSectorNumber.divmod(@secPerBlock)
|
251
|
-
return blockNumber, secInBlock, byteOffset
|
252
|
-
end
|
253
|
-
|
254
|
-
def self.process_bae
|
255
|
-
@file.seek(@batBase, IO::SEEK_SET)
|
256
|
-
@bae = []
|
257
|
-
1.step(@header['max_tbl_ent'], 1) do |block_num|
|
258
|
-
@bae << @file.read(BAE_SIZE).unpack('N')[0]
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
def self.getBAE(blockNumber)
|
263
|
-
@bae[blockNumber]
|
264
|
-
end
|
265
|
-
|
266
|
-
def self.putBAE(blockNum, bae)
|
267
|
-
seekBAE(blockNum)
|
268
|
-
@file.write([bae].pack('N'), BAE_SIZE)
|
269
|
-
end
|
270
|
-
|
271
|
-
def self.seekBAE(blockNum)
|
272
|
-
batOffset = blockNum * BAE_SIZE + @batBase
|
273
|
-
@file.seek(batOffset, IO::SEEK_SET)
|
274
|
-
end
|
275
|
-
|
276
|
-
def self.getAllocStatus(blockNum, sectorNum)
|
277
|
-
sectorMask = seekAllocStatus(blockNum, sectorNum)
|
278
|
-
return false if sectorMask == BLOCK_NOT_ALLOCATED
|
279
|
-
sectorBitmap = @file.read(1).unpack('C')[0]
|
280
|
-
sectorBitmap & sectorMask == sectorMask
|
281
|
-
end
|
282
|
-
|
283
|
-
def self.setAllocStatus(blockNum, sectorNum)
|
284
|
-
sectorMask = seekAllocStatus(blockNum, sectorNum)
|
285
|
-
sectorBitmap = @file.read(1).unpack('C')[0]
|
286
|
-
sectorBitmap |= sectorMask
|
287
|
-
@file.seek(-1, IO::SEEK_CUR)
|
288
|
-
@file.write([sectorBitmap].pack('C'), 1)
|
289
|
-
end
|
290
|
-
|
291
|
-
def self.seekAllocStatus(blockNum, sectorNum)
|
292
|
-
sectorByte, bitOffset = sectorNum.divmod(8)
|
293
|
-
bae = getBAE(blockNum)
|
294
|
-
return bae if bae == BLOCK_NOT_ALLOCATED
|
295
|
-
@file.seek(bae * @blockSize + sectorByte, IO::SEEK_SET)
|
296
|
-
0x80 >> bitOffset
|
297
|
-
end
|
298
|
-
|
299
|
-
def self.getAbsSectorLoc(blockNum, sectorNum)
|
300
|
-
getBAE(blockNum) * @blockSize + sectorNum * @blockSize + @blockSectorBitmapByteCount
|
301
|
-
end
|
302
|
-
|
303
|
-
def self.allocSector(blockNum, sectorNum, pos, parent)
|
304
|
-
allocBlock(blockNum) if getBAE(blockNum) == BLOCK_NOT_ALLOCATED
|
305
|
-
if parent.nil?
|
306
|
-
buf = MemoryBuffer.create(@blockSize)
|
307
|
-
else
|
308
|
-
sector = pos.divmod(@blockSize)[0]
|
309
|
-
buf = parent.d_read(sector, @blockSize)
|
310
|
-
end
|
311
|
-
setAllocStatus(blockNum, sectorNum)
|
312
|
-
@file.seek(getAbsSectorLoc(blockNum, sectorNum), IO::SEEK_SET)
|
313
|
-
@file.write(buf, buf.size)
|
314
|
-
end
|
315
|
-
|
316
|
-
def self.allocBlock(blockNum)
|
317
|
-
# Alloc block.
|
318
|
-
pos = @file.size - FOOTER_LENGTH
|
319
|
-
sector = findFreeSector
|
320
|
-
putBAE(blockNum, sector)
|
321
|
-
# Write sector alloc bitmap.
|
322
|
-
bmp = MemoryBuffer.create(@blockSectorBitmapByteCount)
|
323
|
-
@file.seek(sector * @blockSize, IO::SEEK_SET)
|
324
|
-
@file.write(bmp, bmp.size)
|
325
|
-
# Footer has to move. Total size is 2048 + size of data blocks.
|
326
|
-
pos += @secPerBlock * @blockSize
|
327
|
-
@file.seek(pos, IO::SEEK_SET)
|
328
|
-
@file.write(@footerBuf, @footerBuf.size)
|
329
|
-
end
|
330
|
-
|
331
|
-
def self.findFreeSector
|
332
|
-
# Find a free disk sector with which to start a new block.
|
333
|
-
if @freeSector.nil?
|
334
|
-
seekBAE(0); ents = @header['max_tbl_ent']
|
335
|
-
baes = @file.read(ents * BAE_SIZE).unpack("N#{ents}")
|
336
|
-
baes.delete(BLOCK_NOT_ALLOCATED)
|
337
|
-
raise "Disk full." if baes.size == @header['max_tbl_ent']
|
338
|
-
@freeSector = baes.max
|
339
|
-
end
|
340
|
-
@freeSector += @secPerBlock
|
341
|
-
raise "Disk full." if @freeSector > d_size_common / @blockSize
|
342
|
-
@freeSector
|
343
|
-
end
|
344
|
-
|
345
|
-
def self.checksum(buf, skip_offset)
|
346
|
-
csum = 0
|
347
|
-
0.upto(buf.size - 1) do|i|
|
348
|
-
next if i >= skip_offset && i < skip_offset + 4
|
349
|
-
csum += buf[i].to_i
|
350
|
-
end
|
351
|
-
# GRRRRR - convert to actual 32-bits.
|
352
|
-
[~csum].pack('L').unpack('L')[0]
|
353
|
-
end
|
354
|
-
end # module
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# encoding: US-ASCII
|
2
|
-
|
3
|
-
require 'disk/modules/MSCommon'
|
4
|
-
require 'disk/modules/miq_disk_common'
|
5
|
-
|
6
|
-
module MSVSDiffDisk
|
7
|
-
def d_init
|
8
|
-
self.diskType = "MSVS Differencing"
|
9
|
-
self.blockSize = MSCommon::SECTOR_LENGTH
|
10
|
-
fileMode = MiqDiskCommon.file_mode(dInfo)
|
11
|
-
if dInfo.hyperv_connection
|
12
|
-
@hyperv_connection = dInfo.hyperv_connection
|
13
|
-
@ms_disk_file = MSCommon.connect_to_hyperv(dInfo)
|
14
|
-
else
|
15
|
-
@hyperv_connection = nil
|
16
|
-
@ms_disk_file = MiqLargeFile.open(dInfo.fileName, fileMode) unless dInfo.baseOnly
|
17
|
-
end
|
18
|
-
MSCommon.d_init_common(dInfo, @ms_disk_file) unless dInfo.baseOnly
|
19
|
-
|
20
|
-
# Get parent locators.
|
21
|
-
@locators = []
|
22
|
-
1.upto(8) do|idx|
|
23
|
-
@locators << MSCommon::PARENT_LOCATOR.decode(MSCommon.header["parent_loc#{idx}"])
|
24
|
-
next if @locators[idx - 1]['platform_code'] == "\000\000\000\000"
|
25
|
-
locator = @locators[idx - 1]
|
26
|
-
if locator['platform_code'] == "W2ku"
|
27
|
-
getParentPathWin(locator)
|
28
|
-
getParent(locator)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
raise "No compatible parent locator found" if @parent == nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def getBase
|
35
|
-
@parent || self
|
36
|
-
end
|
37
|
-
|
38
|
-
# /////////////////////////////////////////////////////////////////////////
|
39
|
-
# Implementation.
|
40
|
-
|
41
|
-
def d_read(pos, len)
|
42
|
-
MSCommon.d_read_common(pos, len, @parent)
|
43
|
-
end
|
44
|
-
|
45
|
-
def d_write(pos, buf, len)
|
46
|
-
MSCommon.d_write_common(pos, buf, len, @parent)
|
47
|
-
end
|
48
|
-
|
49
|
-
def d_close
|
50
|
-
@parent.close if @parent
|
51
|
-
@ms_disk_file.close
|
52
|
-
end
|
53
|
-
|
54
|
-
def d_size
|
55
|
-
total = 0
|
56
|
-
total = @parent.d_size if @parent
|
57
|
-
total += @ms_disk_file.size
|
58
|
-
total
|
59
|
-
end
|
60
|
-
|
61
|
-
# /////////////////////////////////////////////////////////////////////////
|
62
|
-
# // Helpers.
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def getParent(locator)
|
67
|
-
if locator.key?('fileName')
|
68
|
-
@parent_ostruct = OpenStruct.new
|
69
|
-
@parent_ostruct.fileName = locator['fileName']
|
70
|
-
@parent_ostruct.driveType = dInfo.driveType
|
71
|
-
@parent_ostruct.hyperv_connection = @hyperv_connection unless @hyperv_connection.nil?
|
72
|
-
@parent = MiqDisk.getDisk(@parent_ostruct)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def getParentPathWin(locator)
|
77
|
-
buf = getPathData(locator)
|
78
|
-
locator['fileName'] = buf.UnicodeToUtf8!
|
79
|
-
end
|
80
|
-
|
81
|
-
def getPathData(locator)
|
82
|
-
@ms_disk_file.seek(MSCommon.getHiLo(locator, "data_offset"), IO::SEEK_SET)
|
83
|
-
@ms_disk_file.read(locator['data_length'])
|
84
|
-
end
|
85
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# encoding: US-ASCII
|
2
|
-
|
3
|
-
require 'Scvmm/miq_hyperv_disk'
|
4
|
-
require 'disk/modules/MiqLargeFile'
|
5
|
-
require 'disk/modules/MSCommon'
|
6
|
-
|
7
|
-
module MSVSDiskProbe
|
8
|
-
MS_MAGIC = "conectix"
|
9
|
-
|
10
|
-
TYPE_FIXED = 2
|
11
|
-
TYPE_DYNAMIC = 3
|
12
|
-
TYPE_DIFF = 4
|
13
|
-
|
14
|
-
MOD_FIXED = "MSVSFixedDisk"
|
15
|
-
MOD_DYNAMIC = "MSVSDynamicDisk"
|
16
|
-
MOD_DIFF = "MSVSDiffDisk"
|
17
|
-
|
18
|
-
def self.probe(ostruct)
|
19
|
-
return nil unless ostruct.fileName
|
20
|
-
# If file not VHD then not Microsoft.
|
21
|
-
# Allow ".miq" also.
|
22
|
-
ext = File.extname(ostruct.fileName).downcase
|
23
|
-
return nil if ext != ".vhd" && ext != ".avhd" && ext != ".miq"
|
24
|
-
|
25
|
-
if ostruct.hyperv_connection
|
26
|
-
ms_disk_file = connect_to_hyperv(ostruct)
|
27
|
-
else
|
28
|
-
# Get (assumed) footer.
|
29
|
-
ms_disk_file = MiqLargeFile.open(ostruct.fileName, "rb")
|
30
|
-
end
|
31
|
-
footer = MSCommon.getFooter(ms_disk_file, true)
|
32
|
-
ms_disk_file.close
|
33
|
-
|
34
|
-
# Check for MS disk.
|
35
|
-
return nil if footer['cookie'] != MS_MAGIC
|
36
|
-
|
37
|
-
# Return module name to handle type.
|
38
|
-
case footer['disk_type']
|
39
|
-
when TYPE_FIXED
|
40
|
-
return MOD_FIXED
|
41
|
-
when TYPE_DYNAMIC
|
42
|
-
return MOD_DYNAMIC
|
43
|
-
when TYPE_DIFF
|
44
|
-
return MOD_DIFF
|
45
|
-
else
|
46
|
-
raise "Unsupported MS disk: #{footer['disk_type']}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.connect_to_hyperv(ostruct)
|
51
|
-
connection = ostruct.hyperv_connection
|
52
|
-
network = ostruct.driveType == "Network"
|
53
|
-
hyperv_disk = MiqHyperVDisk.new(connection[:host],
|
54
|
-
connection[:user],
|
55
|
-
connection[:password],
|
56
|
-
connection[:port],
|
57
|
-
network)
|
58
|
-
hyperv_disk.open(ostruct.fileName)
|
59
|
-
hyperv_disk
|
60
|
-
end
|
61
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'disk/modules/MSCommon'
|
2
|
-
require 'disk/modules/miq_disk_common'
|
3
|
-
|
4
|
-
module MSVSDynamicDisk
|
5
|
-
def d_init
|
6
|
-
self.diskType = "MSVS Dynamic"
|
7
|
-
self.blockSize = MSCommon::SECTOR_LENGTH
|
8
|
-
fileMode = MiqDiskCommon.file_mode(dInfo)
|
9
|
-
@ms_disk_file = if dInfo.hyperv_connection
|
10
|
-
MSCommon.connect_to_hyperv(dInfo)
|
11
|
-
else
|
12
|
-
MiqLargeFile.open(dInfo.fileName, fileMode)
|
13
|
-
end
|
14
|
-
MSCommon.d_init_common(dInfo, @ms_disk_file)
|
15
|
-
end
|
16
|
-
|
17
|
-
def getBase
|
18
|
-
self
|
19
|
-
end
|
20
|
-
|
21
|
-
def d_read(pos, len)
|
22
|
-
MSCommon.d_read_common(pos, len)
|
23
|
-
end
|
24
|
-
|
25
|
-
def d_write(pos, buf, len)
|
26
|
-
MSCommon.d_write_common(pos, buf, len)
|
27
|
-
end
|
28
|
-
|
29
|
-
def d_close
|
30
|
-
@ms_disk_file.close
|
31
|
-
end
|
32
|
-
|
33
|
-
def d_size
|
34
|
-
MSCommon.d_size_common
|
35
|
-
end
|
36
|
-
end # module
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'disk/modules/MiqLargeFile'
|
2
|
-
require 'disk/modules/miq_disk_common'
|
3
|
-
|
4
|
-
module MSVSFixedDisk
|
5
|
-
def d_init
|
6
|
-
@diskType = "MSVSFixed"
|
7
|
-
@blockSize = 512
|
8
|
-
|
9
|
-
fileMode = MiqDiskCommon.file_mode
|
10
|
-
|
11
|
-
if dInfo.hyperv_connection
|
12
|
-
@ms_flat_disk_file = MSCommon.connect_to_hyperv(dInfo)
|
13
|
-
else
|
14
|
-
@ms_flat_disk_file = MiqLargeFile.open(dInfo.fileName, fileMode)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def d_read(pos, len)
|
19
|
-
@ms_flat_disk_file.seek(pos, IO::SEEK_SET)
|
20
|
-
@ms_flat_disk_file.read(len)
|
21
|
-
end
|
22
|
-
|
23
|
-
def getBase
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def d_write(pos, buf, len)
|
28
|
-
@ms_flat_disk_file.seek(pos, IO::SEEK_SET)
|
29
|
-
@ms_flat_disk_file.write(buf, len)
|
30
|
-
end
|
31
|
-
|
32
|
-
def d_close
|
33
|
-
@ms_flat_disk_file.close
|
34
|
-
end
|
35
|
-
|
36
|
-
def d_size
|
37
|
-
File.size(dInfo.fileName)
|
38
|
-
end
|
39
|
-
end
|