Catch all OS errors when removing old local backups

Errors other than a missing directory or denied permission (e.g. read-only filesystem, device busy) ended in a traceback after the backup.
This commit is contained in:
Fuxino
2026-10-21 22:32:50 +02:00
parent db4059ff36
commit ac59969d82
2 changed files with 17 additions and 0 deletions
+3
View File
@@ -405,6 +405,9 @@ class Backup:
except PermissionError: except PermissionError:
logger.error( logger.error(
'Error while removing backup %s. Permission denied', dirs[i]) 'Error while removing backup %s. Permission denied', dirs[i])
except OSError as e:
# E.g. read-only filesystem or device busy
logger.error('Error while removing backup %s. %s', dirs[i], e.strerror or e)
self._removed_count = count self._removed_count = count
+14
View File
@@ -1,5 +1,6 @@
"""Tests for local backups, with real rsync runs and with a fake Popen""" """Tests for local backups, with real rsync runs and with a fake Popen"""
import errno
import io import io
import os import os
from collections.abc import Callable, Iterator from collections.abc import Callable, Iterator
@@ -161,6 +162,19 @@ class TestRsync:
# Nothing to link against, as the old backup was removed first # Nothing to link against, as the old backup was removed first
assert copied(out, backup, src / 'same.txt').stat().st_nlink == 1 assert copied(out, backup, src / 'same.txt').stat().st_nlink == 1
def test_removal_os_error(self, src: Path, out: Path, monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture) -> None:
assert run_backup(out, [str(src)]) == 0
def busy(path: str) -> None:
raise OSError(errno.EBUSY, os.strerror(errno.EBUSY), path)
monkeypatch.setattr(sb, 'rmtree', busy)
assert run_backup(out, [str(src)], keep=0) == 0
assert backups(out) == ['2026-10-14_10-00-00', '2026-10-14_11-00-00']
assert 'Error while removing backup 2026-10-14_10-00-00. Device or resource busy' in caplog.text
def test_stray_files_and_symlinks(self, src: Path, out: Path) -> None: def test_stray_files_and_symlinks(self, src: Path, out: Path) -> None:
assert run_backup(out, [str(src)]) == 0 assert run_backup(out, [str(src)]) == 0