Skip to content

Commit

Permalink
Add function to resize a qcow and getVHDInfo equivalent
Browse files Browse the repository at this point in the history
Allow to get parent with QcowInfo header parsing
qcow_util.py: add command info that give virtual size and parent that
gives parent

Signed-off-by: Damien Thenot <damien.thenot@vates.tech>
  • Loading branch information
Nambrok committed Nov 15, 2024
1 parent 88ca7cc commit d381bed
Showing 1 changed file with 90 additions and 3 deletions.
93 changes: 90 additions & 3 deletions scripts/qcow_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@

import struct
import sys
from typing import BinaryIO, Dict, List, NoReturn
from typing import BinaryIO, Dict, List, NoReturn, Any

import errno
import util
from vhdutil import VHDInfo

QEMU_IMG = "/usr/bin/qemu-img"

def ioretry(cmd):
return util.ioretry(lambda: util.pread2(cmd),
errlist = [errno.EIO, errno.EAGAIN])

class QcowInfo:
"""
Expand Down Expand Up @@ -205,7 +214,16 @@ def _is_l2_allocated(entry: int) -> bool:
)

@staticmethod
def _read_qcow2_header(file: BinaryIO) -> Dict[str, int]:
def _read_qcow2_backingfile(file: BinaryIO, backing_file_offset: int , backing_file_size: int) -> str:
if backing_file_offset == 0:
return ""

file.seek(backing_file_offset)
parent_name = file.read(backing_file_size)
return parent_name.decode("UTF-8")

@staticmethod
def _read_qcow2_header(file: BinaryIO) -> Dict[str, Any]:
"""Returns a dict containing some information from QCow2 header.
Args:
Expand Down Expand Up @@ -257,6 +275,8 @@ def _read_qcow2_header(file: BinaryIO) -> Dict[str, int]:
if cluster_bits != 16:
raise ValueError("Only default cluster size of 64K is supported")

parent_name = QcowInfo._read_qcow2_backingfile(file, backing_file_offset, backing_file_size)

return {
"version": version,
"backing_file_offset": backing_file_offset,
Expand All @@ -267,6 +287,7 @@ def _read_qcow2_header(file: BinaryIO) -> Dict[str, int]:
"l1_table_offset": l1_table_offset,
"refcount_table_offset": refcount_table_offset,
"snapshots_offset": snapshots_offset,
"parent": parent_name,
}

def _get_l1_entries(self, file: BinaryIO) -> List[int]:
Expand Down Expand Up @@ -487,6 +508,65 @@ def get_hidden(self) -> bool:
return True


def getSizeVirt(path) -> int:
qcow_info = QcowInfo(path)
return qcow_info.header['virtual_disk_size']

def setSizeVirt(path, new_size) -> None:
cmd = [QEMU_IMG, "resize", path, new_size]
ioretry(cmd)

def setSizeVirtFast(path, size) -> None:
pass

def getSizePhys(path) -> int:
cmd = ["du", "-b", path]
ret = ioretry(cmd)
return ret.split()[0]

def setSizePhys(path, size, debug = True) -> None:
pass

def _get_cluster_to_byte(clusters: int, cluster_bits: int) -> int:
# (1 << cluster_bits) give cluster size in byte
return clusters * (1 << cluster_bits)

def getAllocateSize(path) -> int:
"""
Return allocated blocks in the QCow2 file in byte
"""
qcow_info = QcowInfo(path)
clusters = qcow_info.get_number_of_allocated_clusters()
cluster_bits = qcow_info.header["cluster_bits"]
return _get_cluster_to_byte(clusters, cluster_bits)

def getMaxResizeSize(path) -> int:
return 0

def getVHDInfo(path, extractUuidFunction, includeParent = True) -> VHDInfo:
qcow_info = QcowInfo(path)
uuid = extractUuidFunction(path)
vhdinfo = VHDInfo(uuid)
vhdinfo.path = path
vhdinfo.sizeVirt = qcow_info.header["virtual_disk_size"]
vhdinfo.sizePhys = getSizePhys(path)
vhdinfo.hidden = qcow_info.get_hidden()
vhdinfo.sizeAllocated = _get_cluster_to_byte(qcow_info.get_number_of_allocated_clusters(), qcow_info.header["cluster_bits"])
if includeParent:
parent_path = qcow_info.header["parent"]
if parent_path != "":
vhdinfo.parentPath = parent_path
vhdinfo.parentUuid = extractUuidFunction(parent_path)
vhdinfo.error = 0

return vhdinfo

def qcow_extractUUID(path: str):
return "ffffffff-ffff-ffff-ffff-ffffffffffff"

def print_vhdinfo_debug(vhdinfo: VHDInfo) -> None:
print(f"{vhdinfo.uuid},{vhdinfo.path},{vhdinfo.sizeVirt},{vhdinfo.sizePhys},{vhdinfo.sizeAllocated},{vhdinfo.hidden},{vhdinfo.parentUuid},{vhdinfo.parentPath},{vhdinfo.error}")

def print_help() -> NoReturn:
"""Print help."""
help_msg = """
Expand All @@ -502,7 +582,7 @@ def print_help() -> NoReturn:
Params:
- All command takes a qcow file. Only diff takes a backing file and a qcow.
"""
"""
print(help_msg)
sys.exit(1)

Expand Down Expand Up @@ -544,5 +624,12 @@ def print_help() -> NoReturn:
print("Hidden property is set")
else:
print("Hidden property is not set")
elif command == "info":
print(f"Virtual size: {qcow_info.header['virtual_disk_size']} bytes")
elif command == "parent":
print(f"Parent: {qcow_info.header['parent']}")
elif command == "getVHDInfo":
vhdinfo = getVHDInfo(sys.argv[2], qcow_extractUUID)
print_vhdinfo_debug(vhdinfo)
else:
print_help()

0 comments on commit d381bed

Please sign in to comment.