Files
dodo/backend/backup/storage.py
T
bboysoul 6c234d7d82
ci / gitleaks (push) Successful in 1m19s
ci / docker (push) Successful in 5m48s
feat: strengthen backup and mobile workflows
2026-09-16 21:12:52 +08:00

53 lines
1.7 KiB
Python

import shutil
from pathlib import Path
def contained_file(root: Path, storage_name: str) -> Path:
root = root.resolve()
candidate = (root / storage_name).resolve()
if candidate.parent != root:
raise ValueError("attachment path escapes storage root")
return candidate
def quarantine_files(root: Path, storage_names: list[str], quarantine: Path) -> list[tuple[Path, Path]]:
moved = []
quarantine.mkdir(parents=True, exist_ok=True)
try:
for name in storage_names:
source = contained_file(root, name)
if source.exists():
target = quarantine / name
target.parent.mkdir(parents=True, exist_ok=True)
source.replace(target)
moved.append((source, target))
return moved
except Exception:
restore_quarantine(moved)
raise
def restore_quarantine(moved: list[tuple[Path, Path]]) -> None:
for original, quarantined in reversed(moved):
if quarantined.exists():
original.parent.mkdir(parents=True, exist_ok=True)
quarantined.replace(original)
def restore_quarantine_dir(root: Path, quarantine: Path) -> None:
if not quarantine.exists():
return
for quarantined in sorted(quarantine.rglob("*")):
if not quarantined.is_file():
continue
relative = quarantined.relative_to(quarantine)
original = contained_file(root, relative.as_posix())
original.parent.mkdir(parents=True, exist_ok=True)
quarantined.replace(original)
shutil.rmtree(quarantine)
def remove_quarantine(path: Path) -> None:
if path.exists():
shutil.rmtree(path)