Skip to content

Commit e16c499

Browse files
committed
Adds vhdutils.py
1 parent a848586 commit e16c499

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

vhdutils.py

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Copyright 2014 Cloudbase Solutions Srl
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import ctypes
16+
import os
17+
18+
from ctypes import windll
19+
from ctypes import wintypes
20+
21+
kernel32 = windll.kernel32
22+
virtdisk = windll.virtdisk
23+
24+
25+
class Win32_GUID(ctypes.Structure):
26+
_fields_ = [("Data1", wintypes.DWORD),
27+
("Data2", wintypes.WORD),
28+
("Data3", wintypes.WORD),
29+
("Data4", wintypes.BYTE * 8)]
30+
31+
32+
def get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MSFT():
33+
guid = Win32_GUID()
34+
guid.Data1 = 0xec984aec
35+
guid.Data2 = 0xa0f9
36+
guid.Data3 = 0x47e9
37+
ByteArray8 = wintypes.BYTE * 8
38+
guid.Data4 = ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b)
39+
return guid
40+
41+
42+
class Win32_VIRTUAL_STORAGE_TYPE(ctypes.Structure):
43+
_fields_ = [
44+
('DeviceId', wintypes.DWORD),
45+
('VendorId', Win32_GUID)
46+
]
47+
48+
49+
class Win32_RESIZE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
50+
_fields_ = [
51+
('Version', wintypes.DWORD),
52+
('NewSize', ctypes.c_ulonglong)
53+
]
54+
55+
56+
class Win32_CREATE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
57+
_fields_ = [
58+
('Version', wintypes.DWORD),
59+
('UniqueId', Win32_GUID),
60+
('MaximumSize', ctypes.c_ulonglong),
61+
('BlockSizeInBytes', wintypes.ULONG),
62+
('SectorSizeInBytes', wintypes.ULONG),
63+
('PhysicalSectorSizeInBytes', wintypes.ULONG),
64+
('ParentPath', wintypes.LPCWSTR),
65+
('SourcePath', wintypes.LPCWSTR),
66+
('OpenFlags', wintypes.DWORD),
67+
('ParentVirtualStorageType', Win32_VIRTUAL_STORAGE_TYPE),
68+
('SourceVirtualStorageType', Win32_VIRTUAL_STORAGE_TYPE),
69+
('ResiliencyGuid', Win32_GUID)
70+
]
71+
72+
73+
class VHDUtils(object):
74+
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
75+
VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2
76+
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 3
77+
VIRTUAL_DISK_ACCESS_NONE = 0
78+
VIRTUAL_DISK_ACCESS_ALL = 0x003f0000
79+
VIRTUAL_DISK_ACCESS_CREATE = 0x00100000
80+
OPEN_VIRTUAL_DISK_FLAG_NONE = 0
81+
RESIZE_VIRTUAL_DISK_FLAG_NONE = 0
82+
RESIZE_VIRTUAL_DISK_VERSION_1 = 1
83+
CREATE_VIRTUAL_DISK_VERSION_2 = 2
84+
CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE = 0
85+
CREATE_VIRTUAL_DISK_FLAG_NONE = 0
86+
87+
def __init__(self):
88+
self._ext_device_id_map = {
89+
'vhd': self.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
90+
'vhdx': self.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX}
91+
92+
self._msft_vendor_id = get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MSFT()
93+
94+
def _open(self, device_id, vhd_path):
95+
vst = Win32_VIRTUAL_STORAGE_TYPE()
96+
vst.DeviceId = device_id
97+
vst.VendorId = self._msft_vendor_id
98+
99+
handle = wintypes.HANDLE()
100+
ret_val = virtdisk.OpenVirtualDisk(ctypes.byref(vst),
101+
ctypes.c_wchar_p(vhd_path),
102+
self.VIRTUAL_DISK_ACCESS_ALL,
103+
self.OPEN_VIRTUAL_DISK_FLAG_NONE, 0,
104+
ctypes.byref(handle))
105+
if ret_val:
106+
raise Exception("Opening virtual disk failed with error: %s" %
107+
ret_val)
108+
return handle
109+
110+
def _close(self, handle):
111+
kernel32.CloseHandle(handle)
112+
113+
def _get_device_id_by_path(self, vhd_path):
114+
ext = os.path.splitext(vhd_path)[1][1:].lower()
115+
device_id = self._ext_device_id_map.get(ext)
116+
if not device_id:
117+
raise Exception("Unsupported virtual disk extension: %s" % ext)
118+
return device_id
119+
120+
def resize_vhd(self, vhd_path, new_max_size):
121+
device_id = self._get_device_id_by_path(vhd_path)
122+
handle = self._open(device_id, vhd_path)
123+
try:
124+
params = Win32_RESIZE_VIRTUAL_DISK_PARAMETERS()
125+
params.Version = self.RESIZE_VIRTUAL_DISK_VERSION_1
126+
params.NewSize = new_max_size
127+
128+
ret_val = virtdisk.ResizeVirtualDisk(
129+
handle,
130+
self.RESIZE_VIRTUAL_DISK_FLAG_NONE,
131+
ctypes.byref(params),
132+
None)
133+
if ret_val:
134+
raise Exception("Virtual disk resize failed with "
135+
"error: %s" % ret_val)
136+
finally:
137+
self._close(handle)
138+
139+
def convert_vhd(self, src, dest):
140+
src_device_id = self._get_device_id_by_path(src)
141+
dest_device_id = self._get_device_id_by_path(dest)
142+
143+
vst = Win32_VIRTUAL_STORAGE_TYPE()
144+
vst.DeviceId = dest_device_id
145+
vst.VendorId = self._msft_vendor_id
146+
147+
params = Win32_CREATE_VIRTUAL_DISK_PARAMETERS()
148+
params.Version = self.CREATE_VIRTUAL_DISK_VERSION_2
149+
params.UniqueId = Win32_GUID()
150+
params.MaximumSize = 0
151+
params.BlockSizeInBytes = self.CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE
152+
params.SectorSizeInBytes = 0x200
153+
params.PhysicalSectorSizeInBytes = 0x200
154+
params.ParentPath = None
155+
params.SourcePath = src
156+
params.OpenFlags = self.OPEN_VIRTUAL_DISK_FLAG_NONE
157+
params.ParentVirtualStorageType = Win32_VIRTUAL_STORAGE_TYPE()
158+
params.SourceVirtualStorageType = Win32_VIRTUAL_STORAGE_TYPE()
159+
params.SourceVirtualStorageType.DeviceId = src_device_id
160+
params.SourceVirtualStorageType.VendorId = self._msft_vendor_id
161+
params.ResiliencyGuid = Win32_GUID()
162+
163+
handle = wintypes.HANDLE()
164+
ret_val = virtdisk.CreateVirtualDisk(
165+
ctypes.byref(vst),
166+
ctypes.c_wchar_p(dest),
167+
self.VIRTUAL_DISK_ACCESS_NONE,
168+
None,
169+
self.CREATE_VIRTUAL_DISK_FLAG_NONE,
170+
0,
171+
ctypes.byref(params),
172+
None,
173+
ctypes.byref(handle))
174+
if ret_val:
175+
raise Exception("Virtual disk conversion failed with error: %s" %
176+
ret_val)
177+
self._close(handle)

0 commit comments

Comments
 (0)