Fix FAT dashcam file deletion
Co-authored-by: Copilot <[email protected]>
This commit is contained in:
@@ -845,8 +845,16 @@ Phase 15 shared list component:
|
|||||||
regression behavior, and cleanup-failure reporting against temporary filesystem fixtures.
|
regression behavior, and cleanup-failure reporting against temporary filesystem fixtures.
|
||||||
Deployed to the Pi; the live API correctly returned no storage devices while ignoring the
|
Deployed to the Pi; the live API correctly returned no storage devices while ignoring the
|
||||||
attached PL2303 OBD adapter, and the responsive browser UI passed no-device and mocked populated
|
attached PL2303 OBD adapter, and the responsive browser UI passed no-device and mocked populated
|
||||||
list/sort/confirmation/delete tests. Actual deletion from the physical dashcam remains a
|
list/sort/confirmation/delete tests.
|
||||||
hardware verification item for the next time it is connected in USB storage mode.
|
- **Real-hardware deletion verification (2026-08-09)**: connected the 29.7GB FAT dashcam and listed
|
||||||
|
all 87 original videos (29,615,111,758 bytes) through the live API. The first controlled delete
|
||||||
|
exposed that FAT files were root-owned despite the read-write remount, so unprivileged
|
||||||
|
`os.remove()` failed; added a privileged `sudo rm -- <validated-path>` fallback only after the
|
||||||
|
existing extension, realpath, and mount-boundary checks pass. Created and deleted a tiny
|
||||||
|
disposable `YARIS_OBD_DELETE_TEST.MP4` twice through the real API. Both cycles returned exactly
|
||||||
|
to the original 87-file count and byte total, left every real video untouched, unmounted
|
||||||
|
`/mnt/dashcam`, and kept the service active. Bulk delete uses the same validated per-file removal
|
||||||
|
path but was not run against the real card because it would intentionally erase all footage.
|
||||||
|
|
||||||
### Phase 17: Local imported-video browser + player — 🚧 PLANNED
|
### Phase 17: Local imported-video browser + player — 🚧 PLANNED
|
||||||
Same file-browser treatment for videos already imported to the Pi's own disk
|
Same file-browser treatment for videos already imported to the Pi's own disk
|
||||||
|
|||||||
+19
-1
@@ -292,6 +292,24 @@ def _safe_video_path(source_folder, relative_path):
|
|||||||
return target_real
|
return target_real
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_video_file(path):
|
||||||
|
try:
|
||||||
|
os.remove(path)
|
||||||
|
return
|
||||||
|
except PermissionError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
["sudo", "rm", "--", path],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
raise OSError(e.stderr.strip() or f"Failed to delete {path}") from e
|
||||||
|
|
||||||
|
|
||||||
def delete_dashcam_files(relative_path=None, delete_all=False, mount_point=DEFAULT_MOUNT_POINT):
|
def delete_dashcam_files(relative_path=None, delete_all=False, mount_point=DEFAULT_MOUNT_POINT):
|
||||||
"""Delete one or all dashcam videos, restoring read-only state afterward."""
|
"""Delete one or all dashcam videos, restoring read-only state afterward."""
|
||||||
if not delete_all and relative_path is None:
|
if not delete_all and relative_path is None:
|
||||||
@@ -336,7 +354,7 @@ def delete_dashcam_files(relative_path=None, delete_all=False, mount_point=DEFAU
|
|||||||
for _abs_path, rel_path in targets:
|
for _abs_path, rel_path in targets:
|
||||||
try:
|
try:
|
||||||
safe_path = _safe_video_path(source, rel_path)
|
safe_path = _safe_video_path(source, rel_path)
|
||||||
os.remove(safe_path)
|
_remove_video_file(safe_path)
|
||||||
deleted.append(rel_path)
|
deleted.append(rel_path)
|
||||||
except (OSError, ValueError) as e:
|
except (OSError, ValueError) as e:
|
||||||
errors.append(f"{rel_path}: {e}")
|
errors.append(f"{rel_path}: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user