1850a1951SThomas Huth# Utilities for python-based QEMU tests
2850a1951SThomas Huth#
3850a1951SThomas Huth# Copyright 2024 Red Hat, Inc.
4850a1951SThomas Huth#
5850a1951SThomas Huth# Authors:
6850a1951SThomas Huth#  Thomas Huth <thuth@redhat.com>
7850a1951SThomas Huth#
8850a1951SThomas Huth# This work is licensed under the terms of the GNU GPL, version 2 or
9850a1951SThomas Huth# later.  See the COPYING file in the top-level directory.
10850a1951SThomas Huth
11d5674412SThomas Huthimport gzip
12e2e9fd25SThomas Huthimport lzma
13e2e9fd25SThomas Huthimport os
14e2e9fd25SThomas Huthimport shutil
1534917eadSPhilippe Mathieu-Daudéimport subprocess
16850a1951SThomas Huthimport tarfile
17850a1951SThomas Huth
18*f7d6b772SThomas Huth"""
19*f7d6b772SThomas HuthRound up to next power of 2
20*f7d6b772SThomas Huth"""
21*f7d6b772SThomas Huthdef pow2ceil(x):
22*f7d6b772SThomas Huth    return 1 if x == 0 else 2**(x - 1).bit_length()
23*f7d6b772SThomas Huth
24*f7d6b772SThomas Huthdef file_truncate(path, size):
25*f7d6b772SThomas Huth    if size != os.path.getsize(path):
26*f7d6b772SThomas Huth        with open(path, 'ab+') as fd:
27*f7d6b772SThomas Huth            fd.truncate(size)
28*f7d6b772SThomas Huth
29*f7d6b772SThomas Huth"""
30*f7d6b772SThomas HuthExpand file size to next power of 2
31*f7d6b772SThomas Huth"""
32*f7d6b772SThomas Huthdef image_pow2ceil_expand(path):
33*f7d6b772SThomas Huth        size = os.path.getsize(path)
34*f7d6b772SThomas Huth        size_aligned = pow2ceil(size)
35*f7d6b772SThomas Huth        if size != size_aligned:
36*f7d6b772SThomas Huth            with open(path, 'ab+') as fd:
37*f7d6b772SThomas Huth                fd.truncate(size_aligned)
38*f7d6b772SThomas Huth
39850a1951SThomas Huthdef archive_extract(archive, dest_dir, member=None):
40850a1951SThomas Huth    with tarfile.open(archive) as tf:
41850a1951SThomas Huth        if hasattr(tarfile, 'data_filter'):
42850a1951SThomas Huth            tf.extraction_filter = getattr(tarfile, 'data_filter',
43850a1951SThomas Huth                                           (lambda member, path: member))
44850a1951SThomas Huth        if member:
45850a1951SThomas Huth            tf.extract(member=member, path=dest_dir)
46850a1951SThomas Huth        else:
47850a1951SThomas Huth            tf.extractall(path=dest_dir)
48e2e9fd25SThomas Huth
49d5674412SThomas Huthdef gzip_uncompress(gz_path, output_path):
50d5674412SThomas Huth    if os.path.exists(output_path):
51d5674412SThomas Huth        return
52d5674412SThomas Huth    with gzip.open(gz_path, 'rb') as gz_in:
53d5674412SThomas Huth        try:
54d5674412SThomas Huth            with open(output_path, 'wb') as raw_out:
55d5674412SThomas Huth                shutil.copyfileobj(gz_in, raw_out)
56d5674412SThomas Huth        except:
57d5674412SThomas Huth            os.remove(output_path)
58d5674412SThomas Huth            raise
59d5674412SThomas Huth
60e2e9fd25SThomas Huthdef lzma_uncompress(xz_path, output_path):
61e2e9fd25SThomas Huth    if os.path.exists(output_path):
62e2e9fd25SThomas Huth        return
63e2e9fd25SThomas Huth    with lzma.open(xz_path, 'rb') as lzma_in:
64e2e9fd25SThomas Huth        try:
65e2e9fd25SThomas Huth            with open(output_path, 'wb') as raw_out:
66e2e9fd25SThomas Huth                shutil.copyfileobj(lzma_in, raw_out)
67e2e9fd25SThomas Huth        except:
68e2e9fd25SThomas Huth            os.remove(output_path)
69e2e9fd25SThomas Huth            raise
7034917eadSPhilippe Mathieu-Daudé
7134917eadSPhilippe Mathieu-Daudédef cpio_extract(cpio_handle, output_path):
7234917eadSPhilippe Mathieu-Daudé    cwd = os.getcwd()
7334917eadSPhilippe Mathieu-Daudé    os.chdir(output_path)
7434917eadSPhilippe Mathieu-Daudé    subprocess.run(['cpio', '-i'],
7534917eadSPhilippe Mathieu-Daudé                   input=cpio_handle.read(),
7634917eadSPhilippe Mathieu-Daudé                   stderr=subprocess.DEVNULL)
7734917eadSPhilippe Mathieu-Daudé    os.chdir(cwd)
78