fix(files): review round 2, the server — locks the GC and folders read under, the mount check, the old mount name
- GC: the expiry warning marks each file conditionally on the expiry it saw, one commit each (a file deleted meanwhile no longer fails the run; one re-timed keeps its fresh expiry unwarned); eviction counts the disk again when a candidate was freed meanwhile, so it never evicts for space already free. - Folders: a retention change locks the folder and its files, and a finishing file reads the retention under a share lock, so neither misses the other; a folder delete locks the files it takes home (a file moved out meanwhile stays put, one deleted meanwhile no longer fails the delete). - Upload: the folder is checked before the probe and held only once the job names it. - Dedup enqueue locks the cached asset, so a release meanwhile yields a fresh one instead of a 500. - Mount check reads the kernel's mount table instead of comparing devices (the vfs storage driver gave a mounted volume the device of /), and only inside a container; the API also logs a fresh, empty volume in the library's place. - Compose files fall back to DOWNLOAD_HOST_PATH; the upgrade notes cover the from-source pull. - Folder routes call owned_or_404 directly.
This commit is contained in:
@@ -177,15 +177,29 @@ def test_sidecars_keep_the_full_basename_when_the_title_has_a_dot(tmp_path: Path
|
||||
assert "Chan_-_2026-08-12_-_Sonka_Hazilag.nfo" not in names # the old truncated orphan
|
||||
|
||||
|
||||
def _mounts(*points):
|
||||
"""A /proc/self/mountinfo table with these mount points (the fields around them are filler)."""
|
||||
return "\n".join(f"{i} 1 0:{i} / {p} rw - ext4 /dev/x rw" for i, p in enumerate(points, 22))
|
||||
|
||||
|
||||
def test_a_files_root_on_the_containers_own_disk_is_refused(tmp_path):
|
||||
# The image's empty /files, left unmounted by an old compose file: every file would 404 and
|
||||
# every download would go with the container.
|
||||
assert "not a mounted volume" in files_root_problem(
|
||||
str(tmp_path), system_root=str(tmp_path.parent)
|
||||
)
|
||||
root = str(tmp_path)
|
||||
plain = _mounts("/", "/proc", "/etc/hosts")
|
||||
assert "not a mounted volume" in files_root_problem(root, plain, in_container=True)
|
||||
assert "does not exist" in files_root_problem(str(tmp_path / "gone"))
|
||||
# On another filesystem than the container's own, and writable: the volume.
|
||||
assert files_root_problem(str(tmp_path), system_root="/proc") is None
|
||||
# Its own mount, or inside one: the volume — whatever device it reports. On a storage driver that
|
||||
# keeps the container's root on the host's disk (vfs) a volume has the same device as /.
|
||||
assert files_root_problem(root, _mounts("/", root), in_container=True) is None
|
||||
assert files_root_problem(root, _mounts("/", str(tmp_path.parent)), in_container=True) is None
|
||||
# A mount point with a space in it, as the kernel escapes it.
|
||||
spaced = tmp_path / "my files"
|
||||
spaced.mkdir()
|
||||
escaped = str(spaced).replace(" ", "\\040")
|
||||
assert files_root_problem(str(spaced), _mounts("/", escaped), in_container=True) is None
|
||||
# Outside a container a plain directory is a fine root.
|
||||
assert files_root_problem(root, plain, in_container=False) is None
|
||||
|
||||
|
||||
def test_the_old_name_of_the_files_root_still_finds_the_files(monkeypatch):
|
||||
|
||||
Reference in New Issue
Block a user