Merge pull request #5329 from ThomasWaldmann/fix-recover-segment-master

check --repair: fix potential data loss (master)
This commit is contained in:
TW 2020-09-08 21:28:02 +02:00 committed by GitHub
commit f928747ff7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 15 additions and 17 deletions

View File

@ -1486,23 +1486,21 @@ class LoggedIO:
logger.info('attempting to recover ' + filename) logger.info('attempting to recover ' + filename)
if segment in self.fds: if segment in self.fds:
del self.fds[segment] del self.fds[segment]
backup_filename = filename + '.beforerecover' if os.path.getsize(filename) < MAGIC_LEN + self.header_fmt.size:
os.rename(filename, backup_filename)
if os.path.getsize(backup_filename) < MAGIC_LEN + self.header_fmt.size:
# this is either a zero-byte file (which would crash mmap() below) or otherwise # this is either a zero-byte file (which would crash mmap() below) or otherwise
# just too small to be a valid non-empty segment file, so do a shortcut here: # just too small to be a valid non-empty segment file, so do a shortcut here:
with open(filename, 'wb') as fd: with SaveFile(filename, binary=True) as fd:
fd.write(MAGIC) fd.write(MAGIC)
return return
with open(backup_filename, 'rb') as backup_fd: with SaveFile(filename, binary=True) as dst_fd:
# note: file must not be 0 size or mmap() will crash. with open(filename, 'rb') as src_fd:
with mmap.mmap(backup_fd.fileno(), 0, access=mmap.ACCESS_READ) as mm: # note: file must not be 0 size or mmap() will crash.
# memoryview context manager is problematic, see https://bugs.python.org/issue35686 with mmap.mmap(src_fd.fileno(), 0, access=mmap.ACCESS_READ) as mm:
data = memoryview(mm) # memoryview context manager is problematic, see https://bugs.python.org/issue35686
d = data data = memoryview(mm)
try: d = data
with open(filename, 'wb') as fd: try:
fd.write(MAGIC) dst_fd.write(MAGIC)
while len(d) >= self.header_fmt.size: while len(d) >= self.header_fmt.size:
crc, size, tag = self.header_fmt.unpack(d[:self.header_fmt.size]) crc, size, tag = self.header_fmt.unpack(d[:self.header_fmt.size])
if size < self.header_fmt.size or size > len(d): if size < self.header_fmt.size or size > len(d):
@ -1511,11 +1509,11 @@ class LoggedIO:
if crc32(d[4:size]) & 0xffffffff != crc: if crc32(d[4:size]) & 0xffffffff != crc:
d = d[1:] d = d[1:]
continue continue
fd.write(d[:size]) dst_fd.write(d[:size])
d = d[size:] d = d[size:]
finally: finally:
del d del d
data.release() data.release()
def read(self, segment, offset, id, read_data=True): def read(self, segment, offset, id, read_data=True):
""" """