platform.SaveFile: truncate_and_unlink temporary

SaveFile is typically used for small files where this is not
necessary. The sole exception is the files cache.
This commit is contained in:
Marian Beermann 2017-06-06 18:03:21 +02:00
parent 95064cd241
commit ed0a5c798f
3 changed files with 14 additions and 10 deletions

View File

@ -1995,6 +1995,12 @@ def secure_erase(path):
os.unlink(path)
def truncate_and_unlink(path):
with open(path, 'r+b') as fd:
fd.truncate()
os.unlink(path)
def popen_with_error_handling(cmd_line: str, log_prefix='', **kwargs):
"""
Handle typical errors raised by subprocess.Popen. Return None if an error occurred,

View File

@ -1,6 +1,8 @@
import errno
import os
from borg.helpers import truncate_and_unlink
"""
platform base module
====================
@ -157,7 +159,7 @@ class SaveFile:
def __enter__(self):
from .. import platform
try:
os.unlink(self.tmppath)
truncate_and_unlink(self.tmppath)
except FileNotFoundError:
pass
self.fd = platform.SyncFile(self.tmppath, self.binary)
@ -167,7 +169,7 @@ class SaveFile:
from .. import platform
self.fd.close()
if exc_type is not None:
os.unlink(self.tmppath)
truncate_and_unlink(self.tmppath)
return
os.replace(self.tmppath, self.path)
platform.sync_dir(os.path.dirname(self.path))

View File

@ -18,7 +18,7 @@ from .helpers import Location
from .helpers import ProgressIndicatorPercent
from .helpers import bin_to_hex
from .helpers import hostname_is_unique
from .helpers import secure_erase
from .helpers import secure_erase, truncate_and_unlink
from .locking import Lock, LockError, LockErrorT
from .logger import create_logger
from .lrucache import LRUCache
@ -1159,9 +1159,7 @@ class LoggedIO:
for segment, filename in self.segment_iterator(reverse=True):
if segment > transaction_id:
# Truncate segment files before unlink(). This can help a full file system recover.
# We can use 'wb', since the segment must exist (just returned by the segment_iterator).
open(filename, 'wb').close()
os.unlink(filename)
truncate_and_unlink(filename)
else:
break
@ -1241,9 +1239,7 @@ class LoggedIO:
# In this instance (cf. cleanup()) we need to use r+b (=O_RDWR|O_BINARY) and
# issue an explicit truncate() to avoid creating a file
# if *segment* did not exist in the first place.
with open(filename, 'r+b') as fd:
fd.truncate()
os.unlink(filename)
truncate_and_unlink(filename)
except FileNotFoundError:
pass
@ -1297,7 +1293,7 @@ class LoggedIO:
if segment in self.fds:
del self.fds[segment]
with open(filename, 'rb') as fd:
# XXX: Rather use mmap.
# XXX: Rather use mmap, this loads the entire segment (up to 500 MB by default) into memory.
data = memoryview(fd.read())
os.rename(filename, filename + '.beforerecover')
logger.info('attempting to recover ' + filename)