Skip to content

Commit

Permalink
Fixes Hyper-V issue with VHD file format
Browse files Browse the repository at this point in the history
The VHD format cookie signature needs to be checked in the footer
instead of the header as fixed format VHDs don't have a copy of the
footer at the beginning of the file.

Fixes bug: #1233853

Change-Id: Ibe44f0d895cde2edbc03dcd6ecebac24b0936660
  • Loading branch information
alexpilotti committed Oct 9, 2013
1 parent c81369c commit fdc5a57
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 7 deletions.
44 changes: 44 additions & 0 deletions nova/tests/virt/hyperv/test_vhdutils.py
Expand Up @@ -88,3 +88,47 @@ def test_get_internal_vhd_size_by_file_size_unsupported(self):
self.assertRaises(vmutils.HyperVException,
vhdutil._get_internal_vhd_size_by_file_size,
None, root_vhd_size)

def test_get_vhd_format_vhdx(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data=vhdutils.VHDX_SIGNATURE),
create=True) as mock_open:

format = self._vhdutils.get_vhd_format(self._FAKE_VHD_PATH)

self.assertEqual(constants.DISK_FORMAT_VHDX, format)

def test_get_vhd_format_vhd(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data=vhdutils.VHD_SIGNATURE),
create=True) as mock_open:
f = mock_open.return_value
f.tell.return_value = 1024

format = self._vhdutils.get_vhd_format(self._FAKE_VHD_PATH)

self.assertEqual(constants.DISK_FORMAT_VHD, format)

def test_get_vhd_format_invalid_format(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data='invalid'),
create=True) as mock_open:
f = mock_open.return_value
f.tell.return_value = 1024

self.assertRaises(vmutils.HyperVException,
self._vhdutils.get_vhd_format,
self._FAKE_VHD_PATH)

def test_get_vhd_format_zero_length_file(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data=''),
create=True) as mock_open:
f = mock_open.return_value
f.tell.return_value = 0

self.assertRaises(vmutils.HyperVException,
self._vhdutils.get_vhd_format,
self._FAKE_VHD_PATH)

f.seek.assert_called_once_with(0, 2)
33 changes: 26 additions & 7 deletions nova/virt/hyperv/vhdutils.py
Expand Up @@ -15,6 +15,16 @@
# License for the specific language governing permissions and limitations
# under the License.

"""
Utility class for VHD related operations.
Official VHD format specs can be retrieved at:
http://technet.microsoft.com/en-us/library/bb676673.aspx
See "Download the Specifications Without Registering"
Official VHDX format specs can be retrieved at:
http://www.microsoft.com/en-us/download/details.aspx?id=34750
"""
import struct
import sys

Expand All @@ -34,6 +44,9 @@
VHD_FOOTER_SIZE_DYNAMIC = 512
VHD_BLK_SIZE_OFFSET = 544

VHD_SIGNATURE = 'conectix'
VHDX_SIGNATURE = 'vhdxfile'


class VHDUtils(object):

Expand Down Expand Up @@ -179,13 +192,19 @@ def get_vhd_info(self, vhd_path):

def get_vhd_format(self, path):
with open(path, 'rb') as f:
signature = f.read(8)
if signature == 'vhdxfile':
return constants.DISK_FORMAT_VHDX
elif signature == 'conectix':
return constants.DISK_FORMAT_VHD
else:
raise vmutils.HyperVException(_('Unsupported virtual disk format'))
# Read header
if f.read(8) == VHDX_SIGNATURE:
return constants.DISK_FORMAT_VHDX

# Read footer
f.seek(0, 2)
file_size = f.tell()
if file_size >= 512:
f.seek(-512, 2)
if f.read(8) == VHD_SIGNATURE:
return constants.DISK_FORMAT_VHD

raise vmutils.HyperVException(_('Unsupported virtual disk format'))

def get_best_supported_vhd_format(self):
return constants.DISK_FORMAT_VHD

0 comments on commit fdc5a57

Please sign in to comment.