backup: call volume.export() just before actually extracting it
There are two reasons for this: - call it from a coroutine, allowing export() itself be a coroutine - avoid calling export() when only collecting preliminary backup summary Both needs some more changes in other parts of the codebase to be useful (see next commits). This will be especially useful when export() will need to make some changes (like, create a snapshot, mount something etc). QubesOS/qubes-issues#5935
This commit is contained in:
parent
8b760451a6
commit
ebd0ca7e79
@ -252,12 +252,27 @@ class Backup:
|
|||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
class FileToBackup:
|
class FileToBackup:
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
def __init__(self, file_path, subdir=None, name=None, size=None):
|
def __init__(self, file_path_or_func, subdir=None, name=None, size=None):
|
||||||
|
"""Store a single file to backup
|
||||||
|
|
||||||
|
:param file_path_or_func: path to the file or a function
|
||||||
|
returning one; in case of function, it can be a coroutine;
|
||||||
|
if a function is given, *name*, *subdir* and *size* needs to be
|
||||||
|
given too
|
||||||
|
:param subdir: directory in a backup archive to place file in
|
||||||
|
:param name: name of the file in the backup archive
|
||||||
|
:param size: size
|
||||||
|
"""
|
||||||
|
if callable(file_path_or_func):
|
||||||
|
assert subdir is not None \
|
||||||
|
and name is not None \
|
||||||
|
and size is not None
|
||||||
|
|
||||||
if size is None:
|
if size is None:
|
||||||
size = qubes.storage.file.get_disk_usage(file_path)
|
size = qubes.storage.file.get_disk_usage(file_path_or_func)
|
||||||
|
|
||||||
if subdir is None:
|
if subdir is None:
|
||||||
abs_file_path = os.path.abspath(file_path)
|
abs_file_path = os.path.abspath(file_path_or_func)
|
||||||
abs_base_dir = os.path.abspath(
|
abs_base_dir = os.path.abspath(
|
||||||
qubes.config.system_path["qubes_base_dir"]) + '/'
|
qubes.config.system_path["qubes_base_dir"]) + '/'
|
||||||
abs_file_dir = os.path.dirname(abs_file_path) + '/'
|
abs_file_dir = os.path.dirname(abs_file_path) + '/'
|
||||||
@ -269,16 +284,17 @@ class Backup:
|
|||||||
if subdir and not subdir.endswith('/'):
|
if subdir and not subdir.endswith('/'):
|
||||||
subdir += '/'
|
subdir += '/'
|
||||||
|
|
||||||
#: real path to the file
|
if name is None:
|
||||||
self.path = file_path
|
name = os.path.basename(file_path_or_func)
|
||||||
|
|
||||||
|
#: real path to the file (or callable to get one)
|
||||||
|
self.path = file_path_or_func
|
||||||
#: size of the file
|
#: size of the file
|
||||||
self.size = size
|
self.size = size
|
||||||
#: directory in backup archive where file should be placed
|
#: directory in backup archive where file should be placed
|
||||||
self.subdir = subdir
|
self.subdir = subdir
|
||||||
#: use this name in the archive (aka rename)
|
#: use this name in the archive (aka rename)
|
||||||
self.name = os.path.basename(file_path)
|
self.name = name
|
||||||
if name is not None:
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
class VMToBackup:
|
class VMToBackup:
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
@ -370,7 +386,7 @@ class Backup:
|
|||||||
if not volume.save_on_stop:
|
if not volume.save_on_stop:
|
||||||
continue
|
continue
|
||||||
vm_files.append(self.FileToBackup(
|
vm_files.append(self.FileToBackup(
|
||||||
volume.export(),
|
volume.export,
|
||||||
subdir,
|
subdir,
|
||||||
name + '.img',
|
name + '.img',
|
||||||
volume.usage))
|
volume.usage))
|
||||||
@ -610,18 +626,21 @@ class Backup:
|
|||||||
# Files will be verified before untaring this.
|
# Files will be verified before untaring this.
|
||||||
# Prefix the path in archive with filename["subdir"] to have it
|
# Prefix the path in archive with filename["subdir"] to have it
|
||||||
# verified during untar
|
# verified during untar
|
||||||
|
path = file_info.path
|
||||||
|
if callable(path):
|
||||||
|
path = yield from qubes.utils.coro_maybe(path())
|
||||||
tar_cmdline = (["tar", "-Pc", '--sparse',
|
tar_cmdline = (["tar", "-Pc", '--sparse',
|
||||||
'-C', os.path.dirname(file_info.path)] +
|
'-C', os.path.dirname(path)] +
|
||||||
(['--dereference'] if
|
(['--dereference'] if
|
||||||
file_info.subdir != "dom0-home/" else []) +
|
file_info.subdir != "dom0-home/" else []) +
|
||||||
['--xform=s:^%s:%s\\0:' % (
|
['--xform=s:^%s:%s\\0:' % (
|
||||||
os.path.basename(file_info.path),
|
os.path.basename(path),
|
||||||
file_info.subdir),
|
file_info.subdir),
|
||||||
os.path.basename(file_info.path)
|
os.path.basename(path)
|
||||||
])
|
])
|
||||||
file_stat = os.stat(file_info.path)
|
file_stat = os.stat(path)
|
||||||
if stat.S_ISBLK(file_stat.st_mode) or \
|
if stat.S_ISBLK(file_stat.st_mode) or \
|
||||||
file_info.name != os.path.basename(file_info.path):
|
file_info.name != os.path.basename(path):
|
||||||
# tar doesn't handle content of block device, use our
|
# tar doesn't handle content of block device, use our
|
||||||
# writer
|
# writer
|
||||||
# also use our tar writer when renaming file
|
# also use our tar writer when renaming file
|
||||||
@ -631,7 +650,7 @@ class Backup:
|
|||||||
'--override-name=%s' % (
|
'--override-name=%s' % (
|
||||||
os.path.join(file_info.subdir, os.path.basename(
|
os.path.join(file_info.subdir, os.path.basename(
|
||||||
file_info.name))),
|
file_info.name))),
|
||||||
file_info.path]
|
path]
|
||||||
if self.compressed:
|
if self.compressed:
|
||||||
tar_cmdline.insert(-2,
|
tar_cmdline.insert(-2,
|
||||||
"--use-compress-program=%s" % self.compression_filter)
|
"--use-compress-program=%s" % self.compression_filter)
|
||||||
|
Loading…
Reference in New Issue
Block a user