import { type Files } from '../workspace/files.ts';
import { FileTable, type OpenMode } from '../runtime/handles/index.ts';
import { FileStat } from '../types.ts';
import type { SessionState } from '../workspace/session/session.ts';
import type { MountAttrs, Handle } from './types.ts';
export interface MountCoreOptions {
    rootPrefix?: string;
    /**
     * Bind every op to this session's mount grants. The kernel-tier
     * primitive: bind-mount the tree into a container and the narrowing
     * travels with it. Enforcement happens inside dispatch/Files via the
     * session context, so binding at the op entry point is sufficient.
     */
    session?: SessionState;
    /**
     * Who owns what the mount shows when a row names its owner by name (the
     * kernel wants numbers): the mounting user, which a kernel adapter reads
     * off its process. A guest owns nothing, so it defaults to 0.
     */
    owner?: {
        uid: number;
        gid: number;
    };
}
/**
 * Protocol-neutral mount logic shared by every kernel adapter.
 *
 * Everything here is expressed in POSIX terms (attribute records, ordinary
 * thrown errors) and imports nothing from `@zkochan/fuse-native`, so it is
 * reusable by a non-FUSE adapter and unit-testable without a kernel.
 *
 * The division of labour: this class decides *what* the filesystem
 * contains, an adapter decides *how* to say it to a particular kernel
 * interface. Adapters translate the errors thrown here into their own
 * error codes with `classifyErrno`. Mirrors Python's `MountCore`.
 *
 * Every op goes through `ws.vfs`, which delegates to the dispatcher, so
 * a mount walks the same dispatcher as a shell line (mount modes, policies,
 * cache, invalidation) and every op it runs lands on the `ws.vfs.records`
 * ledger. Reaching `ws.dispatch` from here instead would skip the record;
 * reaching a backend directly would skip the dispatcher.
 */
export declare class MountCore {
    readonly files: Files;
    readonly session: SessionState | null;
    private readonly now;
    private readonly root;
    readonly handles: FileTable<Handle>;
    private static readonly grown;
    private readonly hydrations;
    private readonly hydrationGen;
    private readonly pending;
    private readonly removals;
    private readonly opening;
    private readonly uid;
    private readonly gid;
    private readonly noAppend;
    private removed;
    constructor(files: Files, options?: MountCoreOptions);
    /**
     * Run one op under the bound session's mount grants and profile, as the
     * Python MountCore binds each op: dispatch reads the session from
     * context, so binding at the op entry point is what scopes a kernel or
     * SFTP mount to it. Unbound, an op runs as whatever session is current.
     */
    private op;
    /** Judge retained metadata through the stat policy boundary. */
    private statCached;
    /** Judge retained bytes through the same read boundary as a fetch. */
    private readCached;
    resolve(path: string): string;
    /**
     * The attrs for one stat row, the way a guest's stat reads it. The row
     * carries the namespace overlay (chmod bits, chown ids, a touched mtime),
     * so what a metadata op stored is what the mount shows, and a device
     * keeps its type and numbers. String uid/gid (names) fall back to the
     * mounting user: the kernel wants numbers and there is no user db to map
     * against. A missing stamp falls back to the mount's start time; epoch
     * zero is a real time and lands. `size` replaces the row's, from an open
     * handle or a link's shown target. Mirrors Python's `MountCore.attrs`.
     */
    attrs(s: FileStat, size?: number | null): MountAttrs;
    /**
     * The target to present for a link at a mount path. Relative targets are
     * stored verbatim and returned as-is. Absolute targets name virtual
     * paths, so they are rewritten relative to the link's directory: returned
     * raw, the kernel would resolve them against the host root and escape
     * the mountpoint.
     */
    shownTarget(path: string, target: string): string;
    /**
     * The length of the bytes an open handle on the file holds. A size-unknown
     * file is read whole when it opens, so while a handle is open its length
     * answers a stat by path too (`ls -l` beside a `cat`). Once every handle
     * is released, the dispatcher answers from the workspace cache instead.
     * Mirrors Python's `held_size`.
     */
    heldSize(path: string): number | null;
    /**
     * Read a size-unknown file whole for the handle opening it, through the
     * dispatcher, so a caching mount keeps the bytes for the next open and for
     * a stat once this one closes. Undefined when the read fails: open() stays
     * permissive and the read() that follows surfaces the error. Opens of one
     * view of one file while a read is out share it; `raw` is the stored
     * bytes, for a handle that writes, rather than the rendering. Mirrors
     * Python's `_hydrate`.
     */
    private hydrate;
    /**
     * Run one mutation of a file after every mutation already queued for
     * it, and let the next one wait for it. Serialization is per identity,
     * so a flush through a link and a truncate through its target queue
     * behind each other, and a flush still landing cannot be overtaken by a
     * truncate that would then be undone when the flush completes.
     */
    private mutate;
    /**
     * Run `fn` holding the chain of every key, taken in sorted order so two
     * callers that hold the same pair never wait on each other. Mirrors
     * Python's `_queue_all`.
     */
    private queueAll;
    /**
     * Run `fn`, which removes, replaces or moves the files at `paths`, after
     * the opens of those names already out, with later ones held back until
     * it is done, as the kernel orders an open and an unlink or a rename of
     * one name. `hold` reads the rest for the handles open before; an open
     * that slipped in while that read was out would get a chunked handle onto
     * bytes about to go. Chains of their own, taken before any `pending` one,
     * rather than `pending` itself: an open they wait for may be truncating
     * there.
     */
    private removing;
    /**
     * Run `fn` after every call already queued under `key` in `queues`, and
     * let the next one wait for it, whether it resolves or throws.
     */
    private queue;
    /**
     * Land write runs on the mount, one pwrite each, in order. A pwrite keeps
     * every stored byte the handle did not write, so nothing is read through
     * the dispatcher first: a session that may write a file and not read it writes
     * through FUSE, as through a write-only descriptor. An appending handle's
     * runs land as appends instead, at the end the file has then, so what
     * another writer appended meanwhile stays before them, as O_APPEND keeps
     * it. The runs that landed leave `runs` in one step, so after a failure
     * `runs` holds only what did not land and a retry never replays a run over
     * bytes another writer has since put there. A run that fails still
     * invalidates what the core holds, since the runs before it have landed.
     */
    private applyWrites;
    /**
     * Extend a file by `data` at the end it has now. A mount with no append
     * (S3) takes a write of the whole file, read fresh from the backend
     * rather than from a copy, so a write another action made since stays; a
     * mount that declined once is remembered. Mirrors Python's `_append`.
     */
    private appendTo;
    /** The read options for one view: the stored bytes, else the rendering. */
    private static stored;
    /** The key one view of a file's hydration goes by. */
    private static view;
    /**
     * POSIX attributes for a path. One stat through the dispatcher answers: a
     * link the session cannot see is absent, as it is to the shell, and a
     * visible one reports its own row with its target read through the
     * dispatcher too. `follow` reports a trailing link's target rather than
     * the link (stat rather than lstat).
     */
    getattr(path: string, follow?: boolean, ctx?: Handle | null): Promise<MountAttrs>;
    /**
     * The row a stat of `path` answers, the size an open handle holds and what
     * it wrote and has not landed counted. Mirrors Python's `_row`.
     */
    private row;
    /**
     * Attributes through an open handle: the path's row, with the size the
     * handle holds, what it wrote and has not flushed included.
     */
    fgetattr(path: string, fd: number): Promise<MountAttrs>;
    /**
     * The row a stat of `path` answers, what the handles open on it wrote and
     * have not landed counted, as a guest projects it into its own record.
     * Mirrors Python's `stat`.
     */
    stat(path: string, follow?: boolean): Promise<FileStat>;
    /**
     * The row an open handle stats by: its file's, with the size it holds and
     * what it wrote and has not landed counted, judged as a stat of its path.
     * A guest projects this into its own record. Mirrors Python's `fstat`.
     */
    fstat(fd: number): Promise<FileStat>;
    /** The handle `fd` names; EBADF for any other number. */
    private openHandle;
    /**
     * Where the file a handle holds ends: its bytes, else the length its open
     * saw, and past them what it wrote.
     */
    private static end;
    /**
     * The mount root's attrs: its own row through the dispatcher, so a chmod
     * made on it shows, or a plain directory when nothing answers for it (a
     * workspace with no mount at `/`). Mirrors Python's `root_attrs`.
     */
    rootAttrs(): Promise<MountAttrs>;
    readdir(path: string): Promise<string[]>;
    /**
     * A directory's entries with their attributes, in one pass. The entries
     * are stat'd together rather than one after another, with at most
     * `LISTING_CONCURRENCY` stats out at once across every listing. A stat
     * that fails ends the listing, and the ones not yet sent are not. An
     * entry that vanishes between the listing and its stat is left out, as
     * `ls` leaves out a file deleted mid-listing. `names` are the entries to
     * stat, in the order they are answered; null takes `readdir`'s, `.` and
     * `..` first. Mirrors Python's `listing`.
     */
    listing(path: string, names?: readonly string[] | null, follow?: boolean): Promise<[string, MountAttrs][]>;
    read(path: string, fd: number, pos: number, len: number): Promise<Uint8Array>;
    /**
     * What a read of the file `key` names sees that has not landed: every
     * handle's writes on it, as write(2) is seen by every reader at once.
     * `supersede` keeps them apart, so they lay over the stored bytes in any
     * order; an appending handle's are its own, since they land at the end the
     * file has then, and the reader's own go last. Mirrors Python's
     * `_writes_on`.
     */
    private writesOn;
    /**
     * Buffer a write on its handle, or apply it directly when there is none.
     * An appending handle writes at the end it holds, whatever `pos` says;
     * EBADF through a handle opened only to read.
     */
    write(path: string, fd: number, data: Uint8Array, pos: number): Promise<void>;
    /**
     * Keep a write on its handle, a copy: one that starts inside the last run
     * or right at its end folds into it, so a stream of writes stays one run;
     * any other starts a run of its own, laid over the earlier ones in order,
     * and every 64 of those fold together while none waits in the spool. Past
     * `MEMORY_LIMIT` held in memory, the handle's runs move to its spool, and
     * a stream goes on at the spool's end. A spool append is queued as it is
     * called, ahead of any read of the window it publishes. Mirrors Python's
     * `_buffer`.
     */
    private static buffer;
    /** The buffered writes held in memory, in arrival order. */
    private static held;
    /**
     * Move a handle's runs held in memory to its spool once they hold more
     * than `MEMORY_LIMIT`. Each takes its place in the spool before the spool
     * has its bytes, in one append, so a write or a read meanwhile finds the
     * run where it will be. Mirrors Python's `_spill`.
     */
    private static spill;
    /**
     * `run` with `data` laid at `at`, inside it or right at its end: in place
     * when the run is one this grew and its buffer has the room, else in a
     * buffer twice as long, so a stream copies what it holds only as often as
     * its length doubles, as Python's bytearray grows.
     */
    private static folded;
    /**
     * Cut a new write's range out of what the file's other handles hold:
     * their bytes there are older, and the new write replaces them. No two
     * handles on a file then hold the same bytes, so whichever flush, release
     * or sync lands first, the file ends as its writes were made. Nothing
     * lands here, so a write never waits on one.
     */
    private supersede;
    /** `writes` with the range a newer write took cut out of them. Mirrors Python's `_cut`. */
    private static cut;
    /**
     * Put a failed landing's writes back ahead of those made since, less what
     * other writes took meanwhile, so a retry never lands bytes older than
     * theirs. Mirrors Python's `_put_back`.
     */
    private static putBack;
    /**
     * Create an empty file and return a fresh handle. `mode` is what the
     * creator asked for, umask applied; null takes the mount's default.
     */
    create(path: string, mode?: number | null): Promise<number>;
    /** Create an empty file in the file's turn. */
    private make;
    /** Create a directory, keeping the mode it was asked for. */
    mkdir(path: string, mode?: number | null): Promise<void>;
    /**
     * Store the mode a create asked for, when it is not the one the backend
     * made the entry with (a disk mount applies the daemon's umask), so
     * `open(O_CREAT, 0600)` and `mkdir -m` read back as asked without a
     * write per ordinary create. Mirrors Python's `_keep_mode`.
     */
    private keepMode;
    /** The target of a namespace link, read through the dispatcher; EINVAL when not a link. */
    readlink(path: string): Promise<string>;
    /**
     * Create namespace link `dest -> src` (ln -s src dest; libfuse passes
     * the pointee first). Relative sources are stored verbatim (resolved
     * at follow time, exactly like the shell `ln -s`); absolute sources
     * are mapped into virtual space so a scoped mount stores the path it
     * will later follow.
     */
    symlink(src: string, dest: string): Promise<void>;
    /**
     * Remove the entry at `path`, a link entry like any other.
     *
     * A link routes through the dispatcher rather than straight to the node
     * table: `unlink` is a LINK_ENTRY_OPS member, so the dispatcher answers a
     * link path itself, gated by session grants and admission policies
     * and recorded on the ledger. Writing the table here instead let a
     * session-scoped kernel mount delete a link on a mount its profile
     * hides. Mirrors Python's MountCore.unlink.
     */
    unlink(path: string): Promise<void>;
    /**
     * The one function every mutation of a file's bytes goes through. The
     * open handles on a file are matched by its identity (the mount path with
     * namespace links followed), and this is the only place their bytes are
     * refreshed, so a new mutating op cannot forget one of them and a link
     * alias cannot slip past. A hydration still in flight is outdated so it
     * re-reads instead of handing over what it fetched, and hydrated handles
     * on the file are refreshed in one read through the dispatcher, so fstat
     * and read through any of them, including the handle that wrote, see the
     * new bytes. A removal or rename passes `rehydrate = false`: POSIX keeps
     * an open descriptor on the bytes it had, and the name, not what it
     * points at, is what changed. A refresh that fails is logged
     * and leaves the handles unhydrated rather than failing the committed
     * mutation. Mirrors Python's `_changed`.
     */
    private changed;
    /**
     * Resize the file an open handle is on: through its name, or, on a file
     * whose name went, the bytes its handles hold. EBADF through a handle
     * opened only to read, EINVAL for a negative length. Mirrors Python's
     * `ftruncate`.
     */
    ftruncate(fd: number, length: number): Promise<void>;
    rename(src: string, dst: string): Promise<void>;
    rmdir(path: string): Promise<void>;
    /**
     * The mount path the file `key` names, or `spelled` where it lies outside
     * the mount's root.
     */
    private mountPath;
    /**
     * Where a mount path really points: the mount-resolved path with every
     * namespace link followed, so two handles opened through a link and
     * its target are recognised as the same file.
     */
    identity(path: string, follow?: boolean): string;
    /**
     * Persist a handle's buffered writes. The buffer is detached before the
     * await so a write arriving meanwhile is not lost to the clear, and the
     * runs that did not land are restored ahead of those later writes when
     * persistence fails, so the acknowledged bytes stay for the handle's own
     * flush to retry.
     */
    private settle;
    /** The handles open on the entry at `path` itself. */
    private named;
    /**
     * The handles open on the file `key` names. The handles left on a file
     * whose name went share a key of their own (`detach`), so no path names
     * them.
     */
    private openOn;
    /**
     * Leave the handles open on a name that went on the file it had: they
     * stat by its row from then on, and share a key no path gives, so a write
     * through one reaches the others and nothing that opens the name later.
     */
    private detach;
    /**
     * Land a handle's writes on a file whose name went: on the bytes it holds,
     * which every handle open on that file reads, as writes to an unlinked
     * file stay with it. A handle reading a rendering the stored bytes differ
     * from keeps its own. The writes leave the handle before its spool is read,
     * an empty run at their end in their place, so a write arriving meanwhile
     * stays for the next landing and an append starts past them; the spool
     * stays the handle's, closed once none of its writes wait there. Mirrors
     * Python's `_land_held`.
     */
    private landHeld;
    /**
     * Land what every handle open on `path` wrote, in the file's turn, as a
     * change of its times by path must come after; `follow` says the change
     * follows a link at `path`. Mirrors Python's `land`.
     */
    land(path: string, follow?: boolean): Promise<void>;
    /**
     * Have the handles open on `path` stat it afresh, after a change by path
     * made past the core (a runtime's setattr or whole-file write), so their
     * next fstat agrees with stat; `follow` says the change followed a link
     * at `path`. Mirrors Python's `restat`.
     */
    restat(path: string, follow?: boolean): void;
    /**
     * Drop the stat rows the handles open on `key` keep, and outdate a stat
     * of theirs still out. Mirrors Python's `_restat`.
     */
    private restatKey;
    /** Land the buffered writes of every handle open on `key`. */
    private landBuffered;
    private persistBuffered;
    /**
     * Land a buffer whose writes wait in its spool, each group of writes
     * `writeRuns` would fold into one run as a stream, in order. A group from
     * the file's start that reaches its stored end leaves nothing of what is
     * stored, so it lands as a write of the whole file, which a store with no
     * pwrite (S3) takes in parts rather than reading the file back first; any
     * other lands as one streamed pwrite, and an appending handle's as
     * appends. The groups that landed leave `groups`, as `applyWrites` drops
     * its runs. Mirrors Python's `_land_spooled`.
     */
    private landSpooled;
    /**
     * Whether the stored file at `path` is missing or ends at or before `end`,
     * by a fresh stat, which waits out a write already landing on the path, so
     * an append under way is counted. A stat refused (a policy may allow the
     * write and not it) answers no, so the group lands as a pwrite rather than
     * not at all. Mirrors Python's `_ends_by`.
     */
    private endsBy;
    /** Close a handle's spool once none of its writes wait there. Mirrors Python's `_free_spool`. */
    private static freeSpool;
    truncate(path: string, size: number): Promise<void>;
    statfs(): Record<string, number>;
    /**
     * Store metadata through the dispatcher. The backend keeps what it can and
     * the namespace overlay the rest, so a chmod, chown or `touch -d` through
     * the mount is what `stat` in a shell reads back, on a backend with no
     * permission bits or settable times of its own too. A null field is left
     * as it is. Mirrors Python's `MountCore.setattr`.
     */
    setattr(path: string, mode: number | null, uid?: number | null, gid?: number | null, atime?: Date | null, mtime?: Date | null, follow?: boolean): Promise<void>;
    /**
     * Store an extended attribute through the dispatcher, which keeps
     * it on the path's namespace node: it outlives the mount, moves with a
     * rename, and is the attribute every other surface (the shell's
     * getfattr, a guest's os.getxattr) reads. Tools that set xattrs as a
     * matter of course (rsync -aX, tar --xattrs, cp -p, Finder writing
     * com.apple.*) succeed on a backend with no attribute slot of its own.
     * Mirrors the python MountCore.
     */
    setxattr(path: string, name: string, value: Uint8Array, opts?: {
        create?: boolean;
        replace?: boolean;
    }): Promise<void>;
    /** One attribute, the backend's own facts included; ENODATA when unset. */
    getxattr(path: string, name: string): Promise<Uint8Array>;
    listxattr(path: string): Promise<string[]>;
    removexattr(path: string, name: string): Promise<void>;
    /**
     * Open a path, the open's effect landing before any byte moves. One rule
     * for every entry point, however it spells the open (open(2) flags, SFTP
     * pflags, an fopen mode, preview1 oflags): an exclusive create refuses
     * what exists, a dangling link or a listed directory included; a
     * directory refuses a mode that would write it; a missing path is created
     * when the mode creates and refused when it does not; a truncating mode
     * empties what exists, which CPython's `open('w')` leaves behind even when
     * nothing is written; and a mode that writes is admitted against the
     * file's write rules before its first write. A file an API mount cannot
     * size is then read whole. `perm` is the mode bits a create gives the
     * file, umask applied; null takes the mount's default. Mirrors Python's
     * `MountCore.open`.
     */
    open(path: string, mode?: OpenMode, perm?: number | null): Promise<number>;
    /** The open itself, which a removal of its name waits for. */
    private openPath;
    /** The path's row, or null when the mount says it is not there. */
    private rowOrNull;
    /**
     * Whether a path with no row is a directory the mount only implies (the
     * root above a nested mount), which it lists.
     */
    private listed;
    /**
     * Empty a file an open truncates. A mount with no truncate (hf buckets,
     * databricks volumes) still empties it through an empty create, which is
     * the effect the open asked for.
     */
    private empty;
    /**
     * A removal of `path` still running. One is keyed by the name it takes, so
     * an open through a link meets the link's removal and then its target's.
     */
    private removalOf;
    /**
     * Keep what the handles open on `path` need once it goes, and return the
     * row they stat by from then on. POSIX keeps an open descriptor on the
     * file it had, so an unlink or a rename onto it must not leave a handle
     * reading or stat'ing the file at that name next. A handle holding no
     * bytes yet (never read, or chunked and holding one chunk) gets them all
     * from one read every such handle shares; it runs under `removing` and
     * the file's `pending` chain, so no handle opens on the file and no write
     * lands on it meanwhile. The handles are matched by the
     * entry itself, so removing a link holds nothing: it takes the link,
     * never its target's bytes. A stat or a read that fails (a policy may
     * allow the removal and refuse either) leaves a bare row or the handles
     * as they are, each on its own, rather than refusing a mutation the
     * caller is allowed. Mirrors Python's `MountCore._hold`.
     */
    private hold;
    /**
     * Wait for a flush or truncation of the handle's file still landing, into
     * the queue a rename moved the handle to. Mirrors Python's `_settled`.
     */
    private settled;
    /**
     * Land a handle's buffered writes and let it go. The handle goes even
     * when the landing fails, as close(2) releases its descriptor: no
     * adapter retries a release, so a kept handle would never close. The
     * failure still reaches the caller.
     */
    release(fd: number): Promise<void>;
    flush(_path: string, fd: number): Promise<void>;
    /**
     * Land what every open handle holds, as sync(2) does, for a client whose
     * close(2) returns before it releases the handle (sshfs). A landing that
     * fails is logged, and its bytes stay on the handle for its own flush to
     * retry and report.
     */
    sync(): Promise<void>;
}
//# sourceMappingURL=core.d.ts.map