Explorar el Código

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
Marek Marczykowski-Górecki hace 3 años
padre
commit
ebd0ca7e79
Se han modificado 1 ficheros con 34 adiciones y 15 borrados
  1. 34 15
      qubes/backup.py

+ 34 - 15
qubes/backup.py

@@ -252,12 +252,27 @@ class Backup:
     # pylint: disable=too-many-instance-attributes
     class FileToBackup:
         # 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:
-                size = qubes.storage.file.get_disk_usage(file_path)
+                size = qubes.storage.file.get_disk_usage(file_path_or_func)
 
             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(
                     qubes.config.system_path["qubes_base_dir"]) + '/'
                 abs_file_dir = os.path.dirname(abs_file_path) + '/'
@@ -269,16 +284,17 @@ class Backup:
                 if subdir and not subdir.endswith('/'):
                     subdir += '/'
 
-            #: real path to the file
-            self.path = file_path
+            if name is None:
+                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
             self.size = size
             #: directory in backup archive where file should be placed
             self.subdir = subdir
             #: use this name in the archive (aka rename)
-            self.name = os.path.basename(file_path)
-            if name is not None:
-                self.name = name
+            self.name = name
 
     class VMToBackup:
         # pylint: disable=too-few-public-methods
@@ -370,7 +386,7 @@ class Backup:
                 if not volume.save_on_stop:
                     continue
                 vm_files.append(self.FileToBackup(
-                    volume.export(),
+                    volume.export,
                     subdir,
                     name + '.img',
                     volume.usage))
@@ -610,18 +626,21 @@ class Backup:
                 # Files will be verified before untaring this.
                 # Prefix the path in archive with filename["subdir"] to have it
                 # verified during untar
+                path = file_info.path
+                if callable(path):
+                    path = yield from qubes.utils.coro_maybe(path())
                 tar_cmdline = (["tar", "-Pc", '--sparse',
-                                '-C', os.path.dirname(file_info.path)] +
+                                '-C', os.path.dirname(path)] +
                                (['--dereference'] if
                                file_info.subdir != "dom0-home/" else []) +
                                ['--xform=s:^%s:%s\\0:' % (
-                                   os.path.basename(file_info.path),
+                                   os.path.basename(path),
                                    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 \
-                        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
                     # writer
                     # also use our tar writer when renaming file
@@ -631,7 +650,7 @@ class Backup:
                         '--override-name=%s' % (
                             os.path.join(file_info.subdir, os.path.basename(
                                 file_info.name))),
-                        file_info.path]
+                        path]
                 if self.compressed:
                     tar_cmdline.insert(-2,
                         "--use-compress-program=%s" % self.compression_filter)