import type { OpenMode } from './handles/index.ts';
import { MountCore } from '../mount/core.ts';
import { type MountResolver } from './resolver.ts';
import type { BridgeDispatchFn } from './types.ts';
import { type WorkspaceBinding } from './binding.ts';
import type { Context } from '../commands/config.ts';
import { type SetAttrFields } from '../types.ts';
import type { VFSEntry, VFSStat } from './types.ts';
/**
 * Whether a listing row is one the file adapter did not classify.
 *
 * Its size-0 non-directory shape is a placeholder, not an answer: a
 * guest that needs the entry's kind, size or stamp must ask the mount
 * with a stat of its own, which also reports whatever failed. A
 * slash-marked directory and a link carry no mode either, but their
 * kind is known.
 */
export declare function isUnclassified(entry: VFSEntry | VFSStat): boolean;
/**
 * One file a guest holds open: the run's core handle on it, the position
 * its reads and writes move, and what its open asked for. Nothing the guest
 * reads or writes stays here: the core holds it (`RuntimeFiles.open`), so
 * every entry point judges, lands and keeps an open file one way. A stream
 * and a descriptor over one open share this, and with it the position, as
 * POSIX shares an open file description. Mirrors Python's `Descriptor`.
 */
export declare class Descriptor {
    readonly files: RuntimeFiles;
    readonly fd: number;
    readonly mode: OpenMode;
    readonly opened: string;
    readonly directory: boolean;
    readonly inode: string;
    pos: number;
    /**
     * @param files the adapter whose core the handle is on.
     * @param fd the core's handle.
     * @param mode what the open asked for.
     * @param opened the path it was opened at, the name a file object reports.
     * @param directory it names a directory, which it may not read.
     * @param inode where the links on `opened` led as it opened, which names
     *   its inode however the file is renamed or the link changed since.
     */
    constructor(files: RuntimeFiles, fd: number, mode: OpenMode, opened: string, directory?: boolean, inode?: string);
    /** The path its file has now; a rename moves it. */
    get path(): string;
    /** The file's length as the handle holds it, its writes counted. */
    size(): Promise<number>;
    /** Read at an explicit offset without moving the position. */
    pread(offset: number, size: number): Promise<Uint8Array>;
    /**
     * Read from the position, advancing it by what was read; a negative or
     * null size reads to the end, a chunk at a time.
     */
    read(size?: number | null): Promise<Uint8Array>;
    /** Write at an explicit offset without moving the position; an appending handle writes at its end. */
    pwrite(offset: number, data: Uint8Array): Promise<void>;
    /**
     * Write at the position, advancing it past what was written; an appending
     * handle first moves the position to its end, as O_APPEND does, so a
     * write that fails to find the end leaves nothing written.
     */
    write(data: Uint8Array): Promise<void>;
    /**
     * Move the position, POSIX whence numbering; null when the whence is
     * unknown or the target would be negative (the position is then
     * untouched).
     */
    seek(offset: number, whence: number): Promise<number | null>;
    /** Set the file's length: a shrink drops bytes, growth reads zeros. */
    truncate(size: number): Promise<void>;
    /** Land what it wrote, as fsync(2) does. */
    land(): Promise<void>;
    /** Land what it wrote and let the core's handle go. */
    close(): Promise<void>;
}
/**
 * The mount-facing op vocabulary a sandboxed runtime encodes into.
 *
 * One instruction set (read/write/append/stat/readdir/create/truncate/
 * unlink/mkdir/rmdir/rename/symlink/readlink/setattr), one routing
 * table, one place that knows an append may have to become a
 * whole-file write. The last three reach the name plane rather than a
 * backend, which is what lets a guest create a link or stamp a time on
 * a mount whose store has neither. Encoders hold one of these; they
 * never inherit it, because a monty encoder is the binding's own `os`
 * callback and a quickjs encoder is a table of host functions.
 *
 * The surface is async, unlike Python's: a JS guest either suspends at
 * the call (quickjs asyncify) or records the mutation and replays it
 * after the run (pyodide), so nothing here has to block a worker
 * thread the way the Python runtimes do.
 *
 * A file the guest opens is a handle on the run's `MountCore` (`open`,
 * `pread`, `pwrite`, `fstat`, `ftruncate`, `fsync`, `close`), the
 * open-file layer every entry point shares: it holds what the guest read,
 * keeps what it wrote until a close or a sync, lands it in the order the
 * writes were made, and keeps a file whose name went for the handles open
 * on it. The guest's own table keeps only the descriptor number, its
 * position and its flags. A removal, a rename, a truncate and a change of
 * times by path go through the core too, so the files open on that path
 * follow them. Mirrors Python's `RuntimeFiles`.
 */
export declare class RuntimeFiles {
    readonly bridge: BridgeDispatchFn;
    private readonly resolve;
    private readonly core;
    private readonly signal;
    private readonly live;
    private readonly dispatch;
    private readonly resolver;
    private readonly noAppend;
    /**
     * @param bridge the bridge every op rides, over the run's files; it also
     *   answers the raw calls a guest makes past the typed methods (the
     *   Pyodide worker's xattr and alias checks).
     * @param resolver the workspace mount routing table; the default answers
     *   no mounts, so routing questions answer null.
     * @param resolve where the namespace's links lead a path; null while the
     *   workspace keeps no links.
     * @param core the open-file core the run's files open on; null opens
     *   nothing.
     * @param signal the run's, which stops a core op once it aborts.
     * @param live the signals of the guest calls on the core now, which its
     *   every dispatch checks; a call with none (a run's end landing what it
     *   wrote) passes, however the run ended.
     */
    constructor(bridge: BridgeDispatchFn, resolver?: MountResolver, resolve?: ((path: string) => string) | null, core?: MountCore | null, signal?: AbortSignal | null, live?: AbortSignal[]);
    /**
     * The file adapter every engine builds for one run.
     *
     * Over the run's files (`ctx.vfs`, whose calls are the program's own),
     * the binding's routing table and the namespace's links, each replaying
     * the run's context, which `Runtime.execute` set up, for a guest that
     * calls back from elsewhere. A run with no files rides the binding's
     * guest bridge (`WorkspaceBinding.overBridge`, the Pyodide worker's).
     *
     * @param ctx the run's context.
     * @param binding the runtime's binding; null outside a workspace, which
     *   has no adapter.
     */
    static of(ctx: Context, binding: WorkspaceBinding | null): RuntimeFiles | null;
    /** A live guest view that stops issuing operations once its run is cancelled. */
    withSignal(signal: AbortSignal): RuntimeFiles;
    /**
     * Run one op on the run's open-file core; EBADF when this adapter opens
     * nothing. An op that only lands what the guest already wrote (`lands`)
     * runs however the run ended, as the run's end would land it anyway
     * (`runLanding`), so a cancelled guest call under way beside it stops only
     * itself.
     */
    private onCore;
    /** The path the core's handle `fd` is on now; EBADF for any other number. */
    pathOf(fd: number): string;
    /**
     * Open a file, the open's effect landing before any byte moves
     * (`MountCore.open`), and answer the core's handle for it. `perm` is the
     * mode bits a create gives the file; null takes the mount's default.
     */
    open(path: string, mode: OpenMode, perm?: number | null): Promise<number>;
    /**
     * Read through an open handle: what it holds, judged as a read of its
     * path now, with what it wrote and has not landed laid over.
     */
    pread(fd: number, offset: number, size: number): Promise<Uint8Array>;
    /**
     * Write through an open handle, which keeps the bytes until a close or a
     * sync lands them; one that appends writes at its end.
     */
    pwrite(fd: number, offset: number, data: Uint8Array): Promise<void>;
    /** The row an open handle stats by, the size it holds counted. */
    fstat(fd: number): Promise<VFSStat>;
    /** Whether the name an open handle's file had went, so the file has no link left. */
    unlinked(fd: number): boolean;
    /** Set the length of the file an open handle is on. */
    ftruncate(fd: number, length: number): Promise<void>;
    /** Land what an open handle wrote, as fsync(2) does. */
    fsync(fd: number): Promise<void>;
    /**
     * Land what an open handle wrote and let it go; a landing that fails
     * still lets it go, and is thrown.
     */
    close(fd: number): Promise<void>;
    /**
     * The path an op on `path` lands on once the namespace's links are
     * followed: the final name too when `follow`, else only the directories
     * above it, since a rename or a removal acts on the name itself. One file
     * reads as one path whichever spelling reached it, which is how a removal
     * finds the files open on it. Mirrors Python's RuntimeFiles.walked.
     */
    walked(path: string, follow?: boolean): string;
    /**
     * The workspace mount prefixes, longest first, trailing-slash
     * normalized. Longest first is what makes mountOf's first match the
     * right one when one mount nests inside another.
     */
    prefixes(): string[];
    /**
     * The mount prefix serving `path`, longest match first, or null. The
     * resolver answers in the mount table's own spelling; this surface
     * re-spells to its trailing-slash convention, the form `prefixes`
     * reports.
     */
    mountOf(path: string): string | null;
    /**
     * Whether the workspace answers for `path`.
     *
     * A guest's content calls gate on this: monty and quickjs refuse a
     * path the workspace does not serve, so they read and write only the
     * view. A mount serves what is under it, and a namespace link serves
     * what is reached through it wherever it lives, because the
     * dispatcher follows a link outside every mount the same way. With no
     * mounts wired there is no scoping, and every path routes here.
     */
    serves(path: string): boolean;
    /**
     * A file's bytes, or the range of them a handle asked for. `raw` reads
     * the stored bytes rather than a rendering, which is what an edit that is
     * written back must start from; `direct` reads what the backend holds
     * now, past the file cache. Mirrors Python's `RuntimeFiles.read`.
     */
    read(path: string, options?: {
        offset?: number;
        size?: number;
        raw?: boolean;
        direct?: boolean;
    }): Promise<Uint8Array>;
    write(path: string, bytes: Uint8Array): Promise<void>;
    /**
     * One path's metadata, projected for a guest encoder.
     *
     * @param path guest-absolute virtual path.
     * @param nofollow report a trailing symlink itself rather than its
     *   target (a guest's lstat). The row is then the node table's own,
     *   so it carries the target string's length as the size, the link's
     *   mtime, and whatever a `chown -h` wrote; the dispatcher consumes
     *   the flag and gates that read exactly as it gates `readlink`.
     */
    stat(path: string, nofollow?: boolean): Promise<VFSStat>;
    private mountRow;
    /**
     * The path's row, or null when the mount says it is not there. Only an
     * absence (`ABSENT_PATH`) answers null; anything else throws, since a
     * refusal is not an answer about the path.
     */
    statOrNull(path: string, nofollow?: boolean): Promise<VFSStat | null>;
    /**
     * `path`'s row as a runtime may see it, or null.
     *
     * Structure is open and content is not. A path in the view (`serves`)
     * answers with its mount's own row; any path the workspace lists
     * answers as a directory, so the root above nested mounts and the
     * directories above a link are directories here as they are in a
     * shell, while a withheld surface's files (history, the program view)
     * stay unseen. A file's own row decides that, not its listing: the
     * history mount lists its one file as empty so a traversal never
     * descends into it. 0 is the file adapter's spelling of an unknown mtime.
     */
    viewStat(path: string): Promise<VFSStat | null>;
    /**
     * The directory's unclassified rows, or null when it is not one: the
     * question a guest asks of a path with no row of its own, a directory
     * a mount only implies (the root above a nested mount), so nothing
     * per entry is stat'd. Asked in the directory form, so a prefix store
     * never answers `/s3/f` with the keys of `/s3/foo.txt`.
     */
    listingOrNull(path: string): Promise<VFSEntry[] | null>;
    /**
     * List a directory as resolved entries (Python's `readdir` shape).
     *
     * A backend that slash-marks directories skips the stat; every other
     * entry is classified by its own stat, which is RAM when the readdir
     * filled the index and a backend request when the mount keeps none.
     * At most `LISTING_ENTRY_CONCURRENCY` requests run at once across
     * everything this adapter serves, so a large directory on an unindexed
     * mount does not put every entry's request on the wire together.
     *
     * An entry whose stat fails, for any reason, rides unclassified: a
     * size-0 non-directory with no mode and no stamp, the row that says
     * "not known". One entry never fails the listing, the way a kernel
     * readdir never stats at all. What went wrong is not lost: the
     * guest's own stat or open of that entry asks the mount again and
     * reports it. Only the listing itself failing fails the call. Any
     * failure but a missing path (a dangling link, an entry gone since the
     * listing) also warns on the host, since the row the guest sees is
     * degraded.
     *
     * A row that did stat carries its mode and stamp too, since the
     * struct is already in hand: a guest that places a directory's nodes
     * from one listing (Emscripten does) then needs no second stat per
     * file.
     * The slash-marked and unclassified rows report neither, which is
     * the honest answer for a listing that never learned them.
     *
     * The link mark comes from the name plane, since no backend listing
     * reports a link. One table read per listing, and it only ever marks
     * a name the listing itself returned, so a link the session hides
     * stays hidden: the dispatcher filtered it out of the entries above
     * and an unmatched mark marks nothing. A marked row is the link's
     * own, as a guest's lstat reads it, since the node table answers that
     * stat and no backend is asked.
     *
     * @param path guest-absolute virtual path of the directory.
     * @param classify stat each entry to learn its kind. A guest that
     *   only needs names (monty's listdir, quickjs) passes false and
     *   every row comes back unclassified, one request for the listing
     *   and none per entry, as a POSIX readdir costs.
     */
    readdir(path: string, classify?: boolean): Promise<VFSEntry[]>;
    private classified;
    /** Set `path`'s length: a shrink drops bytes, growth reads zeros. */
    truncate(path: string, length?: number): Promise<void>;
    /**
     * Remove the entry at `path`; a file open on it keeps what it held, as
     * POSIX keeps an open file on its inode.
     */
    unlink(path: string): Promise<void>;
    /**
     * Create a directory; `parents` asks the mount to create missing
     * ancestors too (pathlib's mkdir(parents=True), which the backend op
     * takes as a flag on both hosts).
     */
    mkdir(path: string, parents?: boolean): Promise<void>;
    rmdir(path: string): Promise<void>;
    /**
     * Rename within one mount.
     *
     * Args:
     *   src: guest-absolute source path.
     *   dst: guest-absolute destination path.
     *
     * Throws:
     *   EXDEV: the two ends resolve to different mounts.
     */
    rename(src: string, dst: string): Promise<void>;
    /**
     * Create a namespace symlink at `path` pointing at `target`.
     *
     * A link is namespace state, so no backend stores one and the target
     * is kept verbatim as the guest typed it. The dispatcher answers this
     * op from the node table itself, which is why a runtime can serve
     * `os.symlink` at all: the dispatcher a surface already holds reaches the
     * name plane, not just a mount.
     *
     * Args:
     *   path: guest-absolute path of the link to create.
     *   target: link target, stored as typed.
     */
    symlink(path: string, target: string): Promise<void>;
    /**
     * The target of the symlink at `path`.
     *
     * Throws EINVAL when `path` is not a link, which is what the node
     * table answers and what POSIX readlink says.
     */
    readlink(path: string): Promise<string>;
    /**
     * Write metadata fields, natively where the backend can hold them.
     *
     * The dispatcher reads the whole set and stores in the namespace overlay
     * whatever the backend cannot keep, so a mount with no setattr op
     * still answers: a utime on an s3 or dropbox mount lands in the name
     * plane and stat reports it back. Stored, not enforced; the mount
     * mode is the access control.
     *
     * Args:
     *   path: guest-absolute virtual path.
     *   attrs: the fields to write, unset ones omitted.
     */
    setattr(path: string, attrs: SetAttrFields): Promise<void>;
    /**
     * Extend `path` by `tail`, falling back to a whole-file write.
     *
     * `append` is optional per backend (S3 registers `write` and
     * `rename` without it), so a mount that declines is remembered: the
     * fallback then costs one failed dispatch per mount rather than one
     * per call.
     *
     * The fallback reads the base fresh every time, never a copy from an
     * earlier append: an append lands after whatever the file holds now,
     * so a write another action made between two appends is kept, as
     * O_APPEND keeps it. It reads the stored bytes, not a rendering, since
     * it writes them back. Only a confirmed absence starts from an empty
     * base, since an append may create the file; every other read failure
     * propagates, because writing the tail alone over a file that exists
     * but is momentarily unreadable would replace content this run never
     * saw.
     *
     * Args:
     *   path: guest-absolute virtual path.
     *   tail: only the newly appended bytes.
     */
    append(path: string, tail: Uint8Array): Promise<void>;
    private appendDelta;
}
//# sourceMappingURL=files.d.ts.map