$QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1
$QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2
$QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
+echo "Check resulting qcow2 header extensions:"
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
echo
echo "=== Bitmap preservation not possible to non-qcow2 ==="
$QEMU_IMG bitmap --remove --image-opts \
driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp
$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific
+echo "Check resulting qcow2 header extensions:"
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
echo
echo "=== Check bitmap contents ==="
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 1048576/1048576 bytes at offset 2097152
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Check resulting qcow2 header extensions:
+Header extension:
+magic 0xe2792aca (Backing format)
+length 5
+data 'qcow2'
+
+Header extension:
+magic 0x6803f857 (Feature table)
+length 336
+data <binary>
+
+Header extension:
+magic 0x23852875 (Bitmaps)
+length 24
+nb_bitmaps 2
+reserved32 0
+bitmap_directory_size 0x40
+bitmap_directory_offset 0x510000
+
=== Bitmap preservation not possible to non-qcow2 ===
granularity: 65536
refcount bits: 16
corrupt: false
+Check resulting qcow2 header extensions:
+Header extension:
+magic 0x6803f857 (Feature table)
+length 336
+data <binary>
+
+Header extension:
+magic 0x23852875 (Bitmaps)
+length 24
+nb_bitmaps 3
+reserved32 0
+bitmap_directory_size 0x60
+bitmap_directory_offset 0x520000
+
=== Check bitmap contents ===
print('{:<25} {}'.format(f[2], value_str))
+class Qcow2BitmapExt(Qcow2Struct):
+
+ fields = (
+ ('u32', '{}', 'nb_bitmaps'),
+ ('u32', '{}', 'reserved32'),
+ ('u64', '{:#x}', 'bitmap_directory_size'),
+ ('u64', '{:#x}', 'bitmap_directory_offset')
+ )
+
+
+QCOW2_EXT_MAGIC_BITMAPS = 0x23852875
+
+
class QcowHeaderExtension(Qcow2Struct):
class Magic(Enum):
0xe2792aca: 'Backing format',
0x6803f857: 'Feature table',
0x0537be77: 'Crypto header',
- 0x23852875: 'Bitmaps',
+ QCOW2_EXT_MAGIC_BITMAPS: 'Bitmaps',
0x44415441: 'Data file'
}
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.
+ somehow. Note also, that we probably want to parse different
+ extensions. Should they be subclasses of this class, or how to do it
+ better? Should it be something like QAPI union with discriminator field
+ (magic here). 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.data = fd.read(padded)
assert self.data is not None
- def dump(self):
- data = self.data[:self.length]
- if all(c in string.printable.encode('ascii') for c in data):
- data = f"'{ data.decode('ascii') }'"
+ if self.magic == QCOW2_EXT_MAGIC_BITMAPS:
+ self.obj = Qcow2BitmapExt(data=self.data)
else:
- data = '<binary>'
+ self.obj = None
+ def dump(self):
super().dump()
- print(f'{"data":<25} {data}')
+
+ if self.obj is None:
+ data = self.data[:self.length]
+ if all(c in string.printable.encode('ascii') for c in data):
+ data = f"'{ data.decode('ascii') }'"
+ else:
+ data = '<binary>'
+ print(f'{"data":<25} {data}')
+ else:
+ self.obj.dump()
@classmethod
def create(cls, magic, data):