Verify changing WebDAV hash metadata without rejecting unchanged files

This commit is contained in:
admin committed 2026-10-26 12:27:01 +01:00
1 parent 7e94915442
commit 8245571f15
4 files changed
+43 -5

No files matched your search

+24 -2
View File
@@ -145,6 +145,28 @@ class Runner:
raise BackupError(f'Independent staging hash mismatch: {name}')
log('Independent local size/hash verification passed')
def validate_final_inventory(self, before, after):
if before == after:
return
atomic_json(self.state / 'changed-inventory.json', after)
# WebDAV checksum properties can appear/disappear without a file changing.
# Changes to actual paths, sizes or modification times still require a new run.
metadata = lambda values: {name: (item['size'], item['mtime']) for name, item in values.items()}
if metadata(before) != metadata(after):
raise BackupError('Cloud changed during sync/verification (paths, sizes or modification times); retry with a stable inventory')
changed = {name: after[name] for name in before if before[name]['hashes'] != after[name]['hashes']}
self.verify_local_hashes(changed)
missing = [name for name, item in changed.items() if item['size'] and not any(
key.lower().replace('-', '') in ('sha1', 'md5') for key in item['hashes'])]
if missing:
flags = []
if not any('\n' in name or '\r' in name for name in missing):
file_list = self.state / 'changed-hash-files.txt'
file_list.write_text('\n'.join(sorted(missing)) + '\n')
flags = ['--files-from-raw', str(file_list)]
self.cloud('check', self.remote, str(self.stage), '--download', *flags)
log(f'Checksum metadata changed on {len(changed)} files; current contents independently verified')
@staticmethod
def totals(manifest):
return len(manifest), sum(x['size'] for x in manifest.values())
@@ -273,6 +295,7 @@ class Runner:
baseline = self.baseline()
self.phase = 'cloud inventory'
before = self.manifest()
atomic_json(self.state / 'source-inventory.json', before)
count, size = self.guard_source(before, baseline)
self.staging_preflight(before)
self.phase = 'cloud sync'
@@ -298,8 +321,7 @@ class Runner:
'--files-from-raw', str(file_list))
self.verify_local_hashes(before)
after = self.manifest()
if before != after:
raise BackupError('Cloud changed during sync/verification; retry with a stable inventory')
self.validate_final_inventory(before, after)
atomic_json(self.state / 'verified-inventory.json', after)
self.nas()
self.phase = 'borg create'