mirror of
https://github.com/borgbackup/borg.git
synced 2025-02-20 21:27:32 +00:00
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:
parent
95064cd241
commit
ed0a5c798f
3 changed files with 14 additions and 10 deletions
|
@ -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,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import errno
|
||||
import os
|
||||
|
||||
from borg.helpers import truncate_and_unlink
|
||||
|
||||
"""
|
||||
platform base module
|
||||
====================
|
||||
|
@ -157,7 +159,7 @@ def __init__(self, path, binary=False):
|
|||
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 @@ def __exit__(self, exc_type, exc_val, exc_tb):
|
|||
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))
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
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 @@ def cleanup(self, transaction_id):
|
|||
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 @@ def delete_segment(self, segment):
|
|||
# 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 @@ def recover_segment(self, segment, filename):
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue