43 lines
1.2 KiB
Python
43 lines
1.2 KiB
Python
"""Shared host-side inspection of FDS root filesystems (standard library only)."""
|
|
import hashlib
|
|
import pathlib
|
|
import plistlib
|
|
|
|
|
|
def package_db(root):
|
|
with (root / "var/db/xbps/pkgdb-0.38.plist").open("rb") as stream:
|
|
db = plistlib.load(stream)
|
|
return {name: props for name, props in db.items() if not name.startswith("_")}
|
|
|
|
|
|
def rooted(root, name):
|
|
"""Resolve guest symlinks inside root, including absolute links, never on host."""
|
|
todo = list(pathlib.PurePosixPath(name).parts)
|
|
parts = []
|
|
links = 0
|
|
while todo:
|
|
part = todo.pop(0)
|
|
if part in ("/", "."):
|
|
continue
|
|
if part == "..":
|
|
if parts:
|
|
parts.pop()
|
|
continue
|
|
candidate = root.joinpath(*parts, part)
|
|
if candidate.is_symlink():
|
|
links += 1
|
|
if links > 40:
|
|
raise ValueError(f"Symlink loop: {name}")
|
|
target = candidate.readlink()
|
|
if target.is_absolute():
|
|
parts = []
|
|
todo = list(target.parts) + todo
|
|
else:
|
|
parts.append(part)
|
|
return root.joinpath(*parts)
|
|
|
|
|
|
def digest(path):
|
|
with path.open("rb") as stream:
|
|
return hashlib.file_digest(stream, "sha256").hexdigest()
|