Re: [PATCH v7 4/9] qcow2_format.py: Dump bitmap directory information

2020-06-15 Thread Vladimir Sementsov-Ogievskiy

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

2020-06-11 Thread Andrey Shinkevich
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 &