Skip to main content

Module fs_ops

Module fs_ops 

Source
Expand description

The filesystem layer behind the generic fs.* RPCs and the Files pane (“Hangar”): paginated listing, known places, name validation, the mutation safety policy, and the mutations themselves.

Everything here is blocking and is called from spawn_blocking (or the trash thread): on macOS the first access to a protected folder blocks the calling thread while a privacy prompt is on screen (spec §9.1.1 fact 10).

Spec: docs/specs/SPEC_FILE_BROWSER_PANE_2026_10_01.md §6.3, §7, §9.

Modules§

git
fs.git_status: what git says about the entries of a listed folder, for the Files pane’s markers (modified, untracked, ignored…) and its status line (branch, ahead/behind).
host_jobs
Copy and move between this computer and an SSH host, or within one host (spec §6.3 of SPEC_REMOTE_TERMINALS_AND_DURABLE_SESSIONS_2026_10_02.md): the same fs.op as a local copy, with the same progress, cancel and conflict questions (jobs::Jobs::start_host), the host’s side carried by its helper (remote::files).
jobs
Copy and move as background jobs: fs.op.start, fs.op.resolve, fs.op.cancel, with progress published as files:op events.
platform
The OS-specific half of the Files pane’s filesystem layer: path display form, hidden attributes, a rename that never overwrites, a delete that never follows a link, and the commands that open or reveal a path.
remote
Hangar’s file operations on an SSH connection (spec §6.3 of SPEC_REMOTE_TERMINALS_AND_DURABLE_SESSIONS_2026_10_02.md): the same requests and results as a local folder, carried out by the host’s helper (remote::files). Paths there are the host’s POSIX paths; ~ is its home.
trash_worker
Every call into the trash crate runs on one dedicated thread.

Structs§

CursorStore
Open listings by cursor id.
ListCursor
An open listing between pages.
ProtectedPaths
What a mutation must never touch (spec §9, “Security”): a filesystem root, the home folder itself, AgentMux’s own data and installation, the OS’s system folders, and the inside of a macOS app bundle. Nor anything that CONTAINS one of those: deleting C:\Users would delete the home folder too.

Constants§

CURSOR_TTL
A cursor is dropped after this long without a page being asked for. The frontend navigating away simply stops asking, so this is the cancellation (spec §6.3).
DEFAULT_LIST_LIMIT
Page size when the request names none.
MAX_CONSECUTIVE_ENTRY_ERRORS 🔒
Consecutive unreadable directory entries after which a listing gives up, so a directory whose iterator keeps failing ends instead of looping.
MAX_CURSORS 🔒
Open listings held at once. Each holds an OS directory handle, so a burst of abandoned listings is bounded rather than left to the TTL.
MAX_LIST_LIMIT
Largest page a request may ask for.
MAX_NAME_LEN 🔒
Longest name most filesystems accept (NTFS: 255 UTF-16 units; ext4 and APFS: 255 bytes). Checked as UTF-16 units and bytes both.
ROOT_REFUSAL 🔒
WINDOWS_RESERVED 🔒
Device names Windows reserves in every folder, with or without an extension (nul.txt is still the null device). The superscript digits are reserved too.

Statics§

CURSORS
The process-wide cursor store. Process-wide rather than per connection because a window reload reconnects; a cursor id is a random UUID, so one connection can’t guess another’s.

Functions§

build_entry 🔒
One listing row. Never fails: what can’t be read becomes the row’s error, and the page goes on (spec §9: errors are per entry).
classify_folder_error
create
fs.create: a new empty file or folder. Creation itself is the existence check (create_new / create_dir fail if the name is taken), so nothing can be overwritten.
delete_permanently
fs.delete, one path: PERMANENT. A link is unlinked, never followed.
ensure_cursor_sweeper
Start the periodic cursor sweep, once per process. Without it, cursors abandoned after the last fs.list call would keep their directory handles open until the next call.
entry_error_message 🔒
exists_message 🔒
file_name_string 🔒
folder_failure 🔒
The fs.list error for a folder that couldn’t be opened.
home_and_known_places
Home and the known folders, by name only. Nothing here reads or stats a known folder: on macOS that alone can raise a privacy prompt the user didn’t ask for (spec §9.1.5). A folder dirs can’t name is left out.
install_dir_of 🔒
The installation a (canonical) executable belongs to: on macOS the whole bundle, not just Contents/MacOS. The outermost .app, because srv’s real file sits in a nested helper app (AgentMux.app/Contents/Helpers/AgentMux Server.app, scripts/package-macos.sh), and protecting only that would leave the rest of AgentMux.app open to changes.
list_failure 🔒
list_page
One page of fs.list, against the process-wide cursor store.
list_page_in
One page of fs.list. A failure to open the directory is an Ok answer with error set, never an Err (spec §9: a denied folder must never look empty, and must never fail the pane).
lock_store 🔒
The store’s lock, recovered if a panic elsewhere poisoned it: the map is left consistent by every operation on it, and a poisoned lock must not silently end every listing.
missing_or 🔒
open_listing 🔒
Canonicalize and open the directory for a first page.
open_or_reveal
fs.open / fs.reveal: hand an existing path to the OS. Not limited to home (unlike openinshell): opening and revealing change nothing.
path_key 🔒
Comparison key for paths: the display form, case-folded on Windows, whose filesystems are case-insensitive. Component-wise starts_with on these is a correct “is inside” test.
rename
fs.rename: a new name in the same folder. Never overwrites; a case-only rename goes through a temporary name, because on a case-insensitive filesystem the new name already “exists” (it is the file itself) and some filesystems ignore a direct case-only rename (spec §7.4).
rename_case_only 🔒
resolve_entry_path
The path a mutation acts on: the request path with its PARENT canonicalized and its own last component kept as given.
resolve_request_path
A request path as an absolute host path: ~ expanded, an MSYS-style /c/… converted on Windows, NUL refused, relative refused (a relative path would resolve against srv’s own working directory, which means nothing to the user).
restore
fs.restore: put each path back from the Trash. The paths are the original locations. Must run on the trash thread (trash_worker::run). One result per path, in order.
system_roots 🔒
The OS’s own folders (spec §9).
trash
fs.trash, one path. Must run on the trash thread (trash_worker::run).
validate_name_rules
The name rules (spec §7.4), with the Windows-only ones switched by windows so every rule can be tested on any platform. Errors are sentences, shown to the user as they are.
validate_new_name
Validate a new file or folder name with the current platform’s rules.