|
@@ -32,7 +32,7 @@ import logging
|
|
|
import os
|
|
|
import subprocess
|
|
|
import tempfile
|
|
|
-from contextlib import contextmanager, suppress
|
|
|
+from contextlib import suppress
|
|
|
|
|
|
import qubes.storage
|
|
|
import qubes.utils
|
|
@@ -224,7 +224,7 @@ class ReflinkVolume(qubes.storage.Volume):
|
|
|
def _commit(self, path_from):
|
|
|
self._add_revision()
|
|
|
self._prune_revisions()
|
|
|
- _fsync_path(path_from)
|
|
|
+ qubes.utils.fsync_path(path_from)
|
|
|
_rename_file(path_from, self._path_clean)
|
|
|
|
|
|
def _add_revision(self):
|
|
@@ -354,32 +354,16 @@ class ReflinkVolume(qubes.storage.Volume):
|
|
|
return 0
|
|
|
|
|
|
|
|
|
-@contextmanager
|
|
|
def _replace_file(dst):
|
|
|
- ''' Yield a tempfile whose name starts with dst, creating the last
|
|
|
- directory component if necessary. If the block does not raise
|
|
|
- an exception, safely rename the tempfile to dst.
|
|
|
- '''
|
|
|
- tmp_dir, prefix = os.path.split(dst + '~')
|
|
|
- _make_dir(tmp_dir)
|
|
|
- tmp = tempfile.NamedTemporaryFile(dir=tmp_dir, prefix=prefix, delete=False)
|
|
|
- try:
|
|
|
- yield tmp
|
|
|
- tmp.flush()
|
|
|
- os.fsync(tmp.fileno())
|
|
|
- tmp.close()
|
|
|
- _rename_file(tmp.name, dst)
|
|
|
- except:
|
|
|
- tmp.close()
|
|
|
- _remove_file(tmp.name)
|
|
|
- raise
|
|
|
-
|
|
|
-def _fsync_path(path):
|
|
|
- fd = os.open(path, os.O_RDONLY) # works for a file or a directory
|
|
|
- try:
|
|
|
- os.fsync(fd)
|
|
|
- finally:
|
|
|
- os.close(fd)
|
|
|
+ _make_dir(os.path.dirname(dst))
|
|
|
+ return qubes.utils.replace_file(
|
|
|
+ dst, permissions=0o600, log_level=logging.INFO)
|
|
|
+
|
|
|
+_rename_file = functools.partial(
|
|
|
+ qubes.utils.rename_file, log_level=logging.INFO)
|
|
|
+
|
|
|
+_remove_file = functools.partial(
|
|
|
+ qubes.utils.remove_file, log_level=logging.INFO)
|
|
|
|
|
|
def _make_dir(path):
|
|
|
''' mkdir path, ignoring FileExistsError; return whether we
|
|
@@ -387,35 +371,20 @@ def _make_dir(path):
|
|
|
'''
|
|
|
with suppress(FileExistsError):
|
|
|
os.mkdir(path)
|
|
|
- _fsync_path(os.path.dirname(path))
|
|
|
+ qubes.utils.fsync_path(os.path.dirname(path))
|
|
|
LOGGER.info('Created directory: %r', path)
|
|
|
return True
|
|
|
return False
|
|
|
|
|
|
-def _remove_file(path):
|
|
|
- with suppress(FileNotFoundError):
|
|
|
- os.remove(path)
|
|
|
- _fsync_path(os.path.dirname(path))
|
|
|
- LOGGER.info('Removed file: %r', path)
|
|
|
-
|
|
|
def _remove_empty_dir(path):
|
|
|
try:
|
|
|
os.rmdir(path)
|
|
|
- _fsync_path(os.path.dirname(path))
|
|
|
+ qubes.utils.fsync_path(os.path.dirname(path))
|
|
|
LOGGER.info('Removed empty directory: %r', path)
|
|
|
except OSError as ex:
|
|
|
if ex.errno not in (errno.ENOENT, errno.ENOTEMPTY):
|
|
|
raise
|
|
|
|
|
|
-def _rename_file(src, dst):
|
|
|
- os.rename(src, dst)
|
|
|
- dst_dir = os.path.dirname(dst)
|
|
|
- src_dir = os.path.dirname(src)
|
|
|
- _fsync_path(dst_dir)
|
|
|
- if src_dir != dst_dir:
|
|
|
- _fsync_path(src_dir)
|
|
|
- LOGGER.info('Renamed file: %r -> %r', src, dst)
|
|
|
-
|
|
|
def _resize_file(path, size):
|
|
|
''' Resize an existing file. '''
|
|
|
with open(path, 'rb+') as file:
|