Skip to content

Commit

Permalink
qcow2_format: refactor QcowHeaderExtension as a subclass of Qcow2Struct
Browse files Browse the repository at this point in the history
Only two fields we can parse by generic code, but that is better than
nothing. Keep further refactoring of variable-length fields for another
day.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
Message-Id: <20200606081806.23897-12-vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
  • Loading branch information
Vladimir Sementsov-Ogievskiy authored and ebblake committed Jun 9, 2020
1 parent 0931fcc commit a9e750e
Showing 1 changed file with 37 additions and 16 deletions.
53 changes: 37 additions & 16 deletions tests/qemu-iotests/qcow2_format.py
Expand Up @@ -97,16 +97,41 @@ def dump(self):
print('{:<25} {}'.format(f[2], value_str))


class QcowHeaderExtension:
class QcowHeaderExtension(Qcow2Struct):

def __init__(self, magic, length, data):
if length % 8 != 0:
padding = 8 - (length % 8)
data += b'\0' * padding
fields = (
('u32', '{:#x}', 'magic'),
('u32', '{}', 'length')
# length bytes of data follows
# then padding to next multiply of 8
)

self.magic = magic
self.length = length
self.data = data
def __init__(self, magic=None, length=None, data=None, fd=None):
"""
Support both loading from fd and creation from user data.
For fd-based creation current position in a file will be used to read
the data.
This should be somehow refactored and functionality should be moved to
superclass (to allow creation of any qcow2 struct), but then, fields
of variable length (data here) should be supported in base class
somehow. So, it's a TODO. We'll see how to properly refactor this when
we have more qcow2 structures.
"""
if fd is None:
assert all(v is not None for v in (magic, length, data))
self.magic = magic
self.length = length
if length % 8 != 0:
padding = 8 - (length % 8)
data += b'\0' * padding
self.data = data
else:
assert all(v is None for v in (magic, length, data))
super().__init__(fd=fd)
padded = (self.length + 7) & ~7
self.data = fd.read(padded)
assert self.data is not None

def dump(self):
data = self.data[:self.length]
Expand All @@ -115,8 +140,7 @@ def dump(self):
else:
data = '<binary>'

print(f'{"magic":<25} {self.magic:#x}')
print(f'{"length":<25} {self.length}')
super().dump()
print(f'{"data":<25} {data}')

@classmethod
Expand Down Expand Up @@ -182,14 +206,11 @@ def load_extensions(self, fd):
end = self.cluster_size

while fd.tell() < end:
(magic, length) = struct.unpack('>II', fd.read(8))
if magic == 0:
ext = QcowHeaderExtension(fd=fd)
if ext.magic == 0:
break
else:
padded = (length + 7) & ~7
data = fd.read(padded)
self.extensions.append(QcowHeaderExtension(magic, length,
data))
self.extensions.append(ext)

def update_extensions(self, fd):

Expand Down

0 comments on commit a9e750e

Please sign in to comment.