Re: [PATCH v7 4/9] qcow2_format.py: Dump bitmap directory information
12.06.2020 03:04, Andrey Shinkevich wrote: Read and dump entries from the bitmap directory of QCOW2 image. It extends the output in the test case #291. Header extension: magic 0x23852875 (Bitmaps) ... Bitmap name bitmap-1 flag auto table size8 (bytes) bitmap_table_offset 0x9 bitmap_table_size 1 flags 0 type 1 granularity_bits 16 name_size 8 extra_data_size 0 Suggested-by: Kevin Wolf Signed-off-by: Andrey Shinkevich Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Hmm I don't remember me gave it.. --- tests/qemu-iotests/291.out | 52 ++ tests/qemu-iotests/qcow2_format.py | 75 ++ 2 files changed, 127 insertions(+) diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out index ccfcdc5..d847419 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/291.out @@ -33,6 +33,27 @@ reserved320 bitmap_directory_size 0x40 bitmap_directory_offset 0x51 +Bitmap name b1 +table size8 (bytes) +bitmap_table_offset 0x4e +bitmap_table_size 1 +flags 0 +type 1 +granularity_bits 19 +name_size 2 +extra_data_size 0 + +Bitmap name b2 +flag auto +table size8 (bytes) +bitmap_table_offset 0x50 +bitmap_table_size 1 +flags 2 both having flags and flag in the output looks strange. If you want good human look of flags field, you should implement a special formatter-class for it, like Flags64. Maybe, something like this: flags 0x3 (in_use auto) +type 1 +granularity_bits 16 +name_size 2 +extra_data_size 0 + === Bitmap preservation not possible to non-qcow2 === @@ -98,6 +119,37 @@ reserved320 bitmap_directory_size 0x60 bitmap_directory_offset 0x52 +Bitmap name b1 +table size8 (bytes) +bitmap_table_offset 0x47 +bitmap_table_size 1 +flags 0 +type 1 +granularity_bits 19 +name_size 2 +extra_data_size 0 + +Bitmap name b2 +flag auto +table size8 (bytes) +bitmap_table_offset 0x49 +bitmap_table_size 1 +flags 2 +type 1 +granularity_bits 16 +name_size 2 +extra_data_size 0 + +Bitmap name b0 +table size8 (bytes) +bitmap_table_offset 0x51 +bitmap_table_size 1 +flags 0 +type 1 +granularity_bits 16 +name_size 2 +extra_data_size 0 + === Check bitmap contents === diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index d4f..90eff92 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -103,6 +103,10 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): print('{:<25} {}'.format(f[2], value_str)) +# seek relative to the current position in the file +FROM_CURRENT = 1 Firstly, I though that it's a global variable to control class behavior. Only than I understood that you just decided to use a named constant instead of just 1... So, I'd prefer to use just 1. + + class Qcow2BitmapExt(Qcow2Struct): fields = ( @@ -112,6 +116,73 @@ class Qcow2BitmapExt(Qcow2Struct): ('u64', '{:#x}', 'bitmap_directory_offset') ) +def read_bitmap_directory(self, fd): +self.bitmaps = [] +fd.seek(self.bitmap_directory_offset) +buf_size = struct.calcsize(Qcow2BitmapDirEntry.fmt) + +for n in range(self.nb_bitmaps): +buf = fd.read(buf_size) +dir_entry = Qcow2BitmapDirEntry(data=buf) Base class of Qcow2BitmapDirEntry can load from fd. We should definitely utilize this possibility, instead of writing it again. +fd.seek(dir_entry.extra_data_size, FROM_CURRENT) +bitmap_name = fd.read(dir_entry.name_size) +dir_entry.name = bitmap_name.decode('ascii') You should initialize object in its constructor, not by hand here. Actually, the code here should look like this: self.bitmap_directory = [Qcow2BitmapDirEntry(fd) for _ in range(self.nb_bitmaps)] OK, you may leave a loop, and even calculating of final alignment here, but real fields should be read and initialized in Qcow2BitmapDirEntry constructor +self.bitmaps.append(dir_entry) +entry_raw_size = dir_entry.bitmap_dir_entry_raw_size() +shift =
[PATCH v7 4/9] qcow2_format.py: Dump bitmap directory information
Read and dump entries from the bitmap directory of QCOW2 image. It extends the output in the test case #291. Header extension: magic 0x23852875 (Bitmaps) ... Bitmap name bitmap-1 flag auto table size8 (bytes) bitmap_table_offset 0x9 bitmap_table_size 1 flags 0 type 1 granularity_bits 16 name_size 8 extra_data_size 0 Suggested-by: Kevin Wolf Signed-off-by: Andrey Shinkevich Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy --- tests/qemu-iotests/291.out | 52 ++ tests/qemu-iotests/qcow2_format.py | 75 ++ 2 files changed, 127 insertions(+) diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out index ccfcdc5..d847419 100644 --- a/tests/qemu-iotests/291.out +++ b/tests/qemu-iotests/291.out @@ -33,6 +33,27 @@ reserved320 bitmap_directory_size 0x40 bitmap_directory_offset 0x51 +Bitmap name b1 +table size8 (bytes) +bitmap_table_offset 0x4e +bitmap_table_size 1 +flags 0 +type 1 +granularity_bits 19 +name_size 2 +extra_data_size 0 + +Bitmap name b2 +flag auto +table size8 (bytes) +bitmap_table_offset 0x50 +bitmap_table_size 1 +flags 2 +type 1 +granularity_bits 16 +name_size 2 +extra_data_size 0 + === Bitmap preservation not possible to non-qcow2 === @@ -98,6 +119,37 @@ reserved320 bitmap_directory_size 0x60 bitmap_directory_offset 0x52 +Bitmap name b1 +table size8 (bytes) +bitmap_table_offset 0x47 +bitmap_table_size 1 +flags 0 +type 1 +granularity_bits 19 +name_size 2 +extra_data_size 0 + +Bitmap name b2 +flag auto +table size8 (bytes) +bitmap_table_offset 0x49 +bitmap_table_size 1 +flags 2 +type 1 +granularity_bits 16 +name_size 2 +extra_data_size 0 + +Bitmap name b0 +table size8 (bytes) +bitmap_table_offset 0x51 +bitmap_table_size 1 +flags 0 +type 1 +granularity_bits 16 +name_size 2 +extra_data_size 0 + === Check bitmap contents === diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index d4f..90eff92 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -103,6 +103,10 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): print('{:<25} {}'.format(f[2], value_str)) +# seek relative to the current position in the file +FROM_CURRENT = 1 + + class Qcow2BitmapExt(Qcow2Struct): fields = ( @@ -112,6 +116,73 @@ class Qcow2BitmapExt(Qcow2Struct): ('u64', '{:#x}', 'bitmap_directory_offset') ) +def read_bitmap_directory(self, fd): +self.bitmaps = [] +fd.seek(self.bitmap_directory_offset) +buf_size = struct.calcsize(Qcow2BitmapDirEntry.fmt) + +for n in range(self.nb_bitmaps): +buf = fd.read(buf_size) +dir_entry = Qcow2BitmapDirEntry(data=buf) +fd.seek(dir_entry.extra_data_size, FROM_CURRENT) +bitmap_name = fd.read(dir_entry.name_size) +dir_entry.name = bitmap_name.decode('ascii') +self.bitmaps.append(dir_entry) +entry_raw_size = dir_entry.bitmap_dir_entry_raw_size() +shift = ((entry_raw_size + 7) & ~7) - entry_raw_size +fd.seek(shift, FROM_CURRENT) + +def load(self, fd): +self.read_bitmap_directory(fd) + +def dump(self): +super().dump() +for bm in self.bitmaps: +bm.dump_bitmap_dir_entry() + + +BME_FLAG_IN_USE = 1 << 0 +BME_FLAG_AUTO = 1 << 1 + + +class Qcow2BitmapDirEntry(Qcow2Struct): + +name = '' + +fields = ( +('u64', '{:#x}', 'bitmap_table_offset'), +('u32', '{}','bitmap_table_size'), +('u32', '{}','flags'), +('u8', '{}','type'), +('u8', '{}','granularity_bits'), +('u16', '{}','name_size'), +('u32', '{}','extra_data_size') +) + +def __init__(self, data): +super().__init__(data=data) + +self.bitmap_table_bytes = self.bitmap_table_size \ +* struct.calcsize('Q') + +self.bitmap_flags = [] +if (self.flags & BME_FLAG_IN_USE): +self.bitmap_flags.append("in-use") +if (self.flags &