fix(files): preserve SQLite locks during previews
Co-Authored-By: Hermes Agent / OpenAI Codex / gpt-6-sol <noreply@agents.invalid> (cherry picked from commit 60d879c125177cd4cacdbc840f16c2e048b4199c)
This commit is contained in:
@@ -230,7 +230,15 @@ def offline_file_access(path: Path | str, *, what: str = "read"):
|
||||
:func:`has_live_connection` and *then* doing raw I/O is a check/use race (a connection opened
|
||||
in between loses its POSIX locks to the raw ``close()``). Held only for the raw I/O."""
|
||||
with _live_lock:
|
||||
if _key(path) in _live_connections:
|
||||
key = _key(path)
|
||||
# SQLite locks the main file and its WAL shared-memory sidecar. A raw
|
||||
# close of either inode cancels this process's POSIX locks, while the
|
||||
# connection registry is keyed by the main database path.
|
||||
live = key in _live_connections or any(
|
||||
key.endswith(suffix) and key[:-len(suffix)] in _live_connections
|
||||
for suffix in ("-wal", "-shm")
|
||||
)
|
||||
if live:
|
||||
raise LiveConnectionError(
|
||||
f"Refusing to {what} {path}: a connection to it is still open "
|
||||
"in this process, and raw file access would cancel that "
|
||||
|
||||
@@ -176,11 +176,16 @@ def _fs_regular_file(path: Path) -> tuple[Path, os.stat_result]:
|
||||
|
||||
def _fs_read_bytes(target: Path, limit: Optional[int] = None) -> bytes:
|
||||
"""Read (a prefix of) ``target``; 403/400 on failure."""
|
||||
from hermes_cli.sqlite_safe_read import LiveConnectionError, offline_file_access
|
||||
try:
|
||||
if limit is None:
|
||||
return target.read_bytes()
|
||||
with target.open("rb") as handle:
|
||||
return handle.read(limit)
|
||||
# Keep admission through close; a raw close cancels this process's SQLite locks.
|
||||
with offline_file_access(target, what="preview file"):
|
||||
if limit is None:
|
||||
return target.read_bytes()
|
||||
with target.open("rb") as handle:
|
||||
return handle.read(limit)
|
||||
except LiveConnectionError as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
except PermissionError:
|
||||
raise HTTPException(status_code=403, detail="File is not readable")
|
||||
except OSError as exc:
|
||||
|
||||
Reference in New Issue
Block a user