qcow2_format: refactor QcowHeaderExtension as a subclass of Qcow2Struct

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>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2020-06-06 11:18:04 +03:00 committed by Eric Blake
parent 0931fcc7be
commit a9e750e1ce

View File

@ -97,16 +97,41 @@ class Qcow2Struct(metaclass=Qcow2StructMeta):
print('{:<25} {}'.format(f[2], value_str)) print('{:<25} {}'.format(f[2], value_str))
class QcowHeaderExtension: class QcowHeaderExtension(Qcow2Struct):
def __init__(self, magic, length, data): fields = (
if length % 8 != 0: ('u32', '{:#x}', 'magic'),
padding = 8 - (length % 8) ('u32', '{}', 'length')
data += b'\0' * padding # length bytes of data follows
# then padding to next multiply of 8
)
self.magic = magic def __init__(self, magic=None, length=None, data=None, fd=None):
self.length = length """
self.data = data 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): def dump(self):
data = self.data[:self.length] data = self.data[:self.length]
@ -115,8 +140,7 @@ class QcowHeaderExtension:
else: else:
data = '<binary>' data = '<binary>'
print(f'{"magic":<25} {self.magic:#x}') super().dump()
print(f'{"length":<25} {self.length}')
print(f'{"data":<25} {data}') print(f'{"data":<25} {data}')
@classmethod @classmethod
@ -182,14 +206,11 @@ class QcowHeader(Qcow2Struct):
end = self.cluster_size end = self.cluster_size
while fd.tell() < end: while fd.tell() < end:
(magic, length) = struct.unpack('>II', fd.read(8)) ext = QcowHeaderExtension(fd=fd)
if magic == 0: if ext.magic == 0:
break break
else: else:
padded = (length + 7) & ~7 self.extensions.append(ext)
data = fd.read(padded)
self.extensions.append(QcowHeaderExtension(magic, length,
data))
def update_extensions(self, fd): def update_extensions(self, fd):