import type { SetAttrFields } from '../../../types.ts'; import type { MutationJournal } from './journal.ts'; import type { MirageFsSeed } from './seed.ts'; import type { ErrnoCodes, FSHost, FSNode, FSType, SetAttr } from './types.ts'; /** * The metadata a `setattr` actually changes, or null when it changes * none of it. * * Emscripten hands this callback more than a guest's chmod and utime: * a stamp arrives beside a resize and beside a mode, and a write that * moved no field would still journal an op. Sending one costs a * dispatch and, worse, splits two writes the journal would otherwise * coalesce. Comparing against the node costs one read. * * The one case comparing cannot catch is a create, whose finalizing * chmod does lower a real mode; `MirageFs.fresh` is what suppresses * that one. * * `ctime` is never included: no POSIX call sets it directly, so a mount * has nothing to write it to. `size` is not metadata here either, it is * the resize branch's bytes. * * Args: * node: the node as it stands before the write. * attr: the fields Emscripten passed, times as epoch ms. */ export declare function changedAttrs(node: FSNode, attr: SetAttr): SetAttrFields | null; /** * An Emscripten filesystem backed by a mirage mount. * * This is the pyodide runtime's interception layer. Mounting it at a mount * prefix puts mirage below the guest's syscall boundary, where every * spelling of an operation (`open`, `os.open`, `pathlib`, `shutil`'s * fd-relative walk) arrives as the same callback. Nothing is patched * inside the interpreter. * * Callbacks are synchronous because Emscripten's are, so they never reach * the mounts inline: reads are served from the tree `seed` filled before * the run, and writes are recorded on the mutation journal for the runtime * to replay after it. That is the same contract the guest had before, and * the reason it needs no JSPI. * * The node table lives in `NodeTree` and the flush decision in * `planFlush`; what is left here is one method per Emscripten callback, * plus the errno translation only this layer performs. */ export declare class MirageFs { readonly type: FSType; private readonly host; private readonly errno; private readonly journal; private readonly tree; private readonly mountOf; private readonly prefix; private fresh; /** * Args: * host: the Emscripten FS namespace (`pyodide.FS`). * errno: Emscripten's errno table (`pyodide.ERRNO_CODES`). * journal: the write-ahead log guest mutations are recorded on. * prefix: the mount prefix this filesystem serves. * mountOf: the mirage mount owning a path (`RuntimeVFS.mountOf`). * One mountpoint serves every mirage mount nested under its * prefix, so this is the only boundary fact left to check ops * against; Emscripten's own cross-mount checks cannot see it. */ constructor(host: FSHost, errno: ErrnoCodes, journal: MutationJournal, prefix: string, mountOf: (path: string) => string | null); /** * Populate the tree. Must run after `FS.mount`; see `NodeTree.seed`. * * Args: * seed: tree collected from the mounts before the run. */ seed(seed: MirageFsSeed): void; private getattr; private setattr; private lookup; private mknod; private rename; private unlink; private rmdir; private readdir; /** * Create a symlink node and record it for the mounts. * * A link is namespace state, which is exactly why this can be served: * the op reaches the node table rather than a backend, so a link lands * on an s3 or notion mount whose store has no such thing. The target * is stored as typed and never resolved here. * * Args: * parent: directory the link is created in. * name: the link's own name. * target: what it points at, verbatim. */ private symlink; /** * The target of a symlink node. * * Args: * node: the node to read. */ private readlink; private streamOpen; private streamClose; private streamRead; private streamWrite; private llseek; } //# sourceMappingURL=vfs.d.ts.map