@zenfs/core
Advanced tools
Comparing version 0.12.2 to 0.12.3
import type { RequiredKeys } from 'utilium'; | ||
import { FileSystem } from '../filesystem.js'; | ||
import type { FileSystem } from '../filesystem.js'; | ||
type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function'; | ||
@@ -4,0 +4,0 @@ /** |
import type { FileSystemMetadata } from '../filesystem.js'; | ||
import { Stats } from '../stats.js'; | ||
import type { Stats } from '../stats.js'; | ||
import { IndexFS } from './index/fs.js'; | ||
@@ -4,0 +4,0 @@ import type { IndexData } from './index/index.js'; |
@@ -5,3 +5,4 @@ import type { Cred } from '../../cred.js'; | ||
import type { Stats } from '../../stats.js'; | ||
import { Index, IndexData } from './index.js'; | ||
import type { IndexData } from './index.js'; | ||
import { Index } from './index.js'; | ||
declare const IndexFS_base: (abstract new (...args: any[]) => { | ||
@@ -23,3 +24,2 @@ metadata(): import("../../filesystem.js").FileSystemMetadata; | ||
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void; | ||
_type?: number | undefined; | ||
ready(): Promise<void>; | ||
@@ -26,0 +26,0 @@ stat(path: string, cred: Cred): Promise<Stats>; |
@@ -1,2 +0,3 @@ | ||
import { Stats, StatsLike } from '../../stats.js'; | ||
import type { StatsLike } from '../../stats.js'; | ||
import { Stats } from '../../stats.js'; | ||
/** | ||
@@ -3,0 +4,0 @@ * An Index in JSON form |
@@ -1,6 +0,7 @@ | ||
import { FileSystem, FileSystemMetadata } from '../filesystem.js'; | ||
import { File } from '../file.js'; | ||
import type { FileSystemMetadata } from '../filesystem.js'; | ||
import { FileSystem } from '../filesystem.js'; | ||
import type { File } from '../file.js'; | ||
import { Stats } from '../stats.js'; | ||
import { LockedFS } from './locked.js'; | ||
import { Cred } from '../cred.js'; | ||
import type { Cred } from '../cred.js'; | ||
/** | ||
@@ -7,0 +8,0 @@ * Configuration options for OverlayFS instances. |
@@ -19,2 +19,3 @@ /// <reference types="node" resolution-mode="require"/> | ||
rpc<const T extends FileMethod & string>(method: T, ...args: Parameters<FileMethods[T]>): Promise<Awaited<ReturnType<FileMethods[T]>>>; | ||
protected _throwNoSync(syscall: string): never; | ||
stat(): Promise<Stats>; | ||
@@ -59,3 +60,2 @@ statSync(): Stats; | ||
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void; | ||
_type?: number | undefined; | ||
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>; | ||
@@ -67,3 +67,6 @@ stat(path: string, cred: Cred): Promise<Stats>; | ||
rmdir(path: string, cred: Cred): Promise<void>; | ||
mkdir(path: string, mode: number, cred: Cred): Promise<void>; | ||
mkdir(path: string, mode: number, cred: Cred): Promise<void>; /** | ||
* Constructs a new PortFS instance that connects with ZenFS running on | ||
* the specified port. | ||
*/ | ||
readdir(path: string, cred: Cred): Promise<string[]>; | ||
@@ -70,0 +73,0 @@ exists(path: string, cred: Cred): Promise<boolean>; |
@@ -23,2 +23,5 @@ import { Errno, ErrnoError } from '../../error.js'; | ||
} | ||
_throwNoSync(syscall) { | ||
throw new ErrnoError(Errno.ENOTSUP, 'Syncrohnous operations not support on PortFile', this.path, syscall); | ||
} | ||
stat() { | ||
@@ -28,3 +31,3 @@ return this.rpc('stat'); | ||
statSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.stat'); | ||
this._throwNoSync('stat'); | ||
} | ||
@@ -35,3 +38,3 @@ truncate(len) { | ||
truncateSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.truncate'); | ||
this._throwNoSync('truncate'); | ||
} | ||
@@ -42,3 +45,3 @@ write(buffer, offset, length, position) { | ||
writeSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.write'); | ||
this._throwNoSync('write'); | ||
} | ||
@@ -50,3 +53,3 @@ async read(buffer, offset, length, position) { | ||
readSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.read'); | ||
this._throwNoSync('read'); | ||
} | ||
@@ -57,3 +60,3 @@ chown(uid, gid) { | ||
chownSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.chown'); | ||
this._throwNoSync('chown'); | ||
} | ||
@@ -64,3 +67,3 @@ chmod(mode) { | ||
chmodSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.chmod'); | ||
this._throwNoSync('chmod'); | ||
} | ||
@@ -71,3 +74,3 @@ utimes(atime, mtime) { | ||
utimesSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.utimes'); | ||
this._throwNoSync('utimes'); | ||
} | ||
@@ -78,3 +81,3 @@ _setType(type) { | ||
_setTypeSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile._setType'); | ||
this._throwNoSync('_setType'); | ||
} | ||
@@ -85,3 +88,3 @@ close() { | ||
closeSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.close'); | ||
this._throwNoSync('close'); | ||
} | ||
@@ -92,3 +95,3 @@ sync() { | ||
syncSync() { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.sync'); | ||
this._throwNoSync('sync'); | ||
} | ||
@@ -95,0 +98,0 @@ } |
@@ -9,3 +9,3 @@ import type { Backend, BackendConfiguration, FilesystemOf } from './backends/backend.js'; | ||
* Retrieve a file system with the given configuration. | ||
* @param config A BackendConfig object. | ||
* @see MountConfiguration | ||
*/ | ||
@@ -12,0 +12,0 @@ export declare function resolveMountConfig<T extends Backend>(config: MountConfiguration<T>, _depth?: number): Promise<FilesystemOf<T>>; |
@@ -11,3 +11,3 @@ import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js'; | ||
* Retrieve a file system with the given configuration. | ||
* @param config A BackendConfig object. | ||
* @see MountConfiguration | ||
*/ | ||
@@ -14,0 +14,0 @@ export async function resolveMountConfig(config, _depth = 0) { |
/** | ||
* Credentials used for various operations. | ||
* Similar to Linux's cred struct. See https://github.com/torvalds/linux/blob/master/include/linux/cred.h | ||
* Similar to Linux's cred struct. | ||
* @see https://github.com/torvalds/linux/blob/master/include/linux/cred.h | ||
*/ | ||
@@ -5,0 +6,0 @@ export interface Cred { |
@@ -9,3 +9,4 @@ /// <reference types="node" resolution-mode="require"/> | ||
import { type Callback } from '../utils.js'; | ||
import { Dirent, type Dir } from './dir.js'; | ||
import type { Dirent } from './dir.js'; | ||
import { type Dir } from './dir.js'; | ||
import * as promises from './promises.js'; | ||
@@ -12,0 +13,0 @@ import { ReadStream, WriteStream } from './streams.js'; |
@@ -15,3 +15,3 @@ /// <reference types="node" resolution-mode="require"/> | ||
import type { Interface as ReadlineInterface } from 'readline'; | ||
import { File } from '../file.js'; | ||
import type { File } from '../file.js'; | ||
import type { FileContents } from '../filesystem.js'; | ||
@@ -18,0 +18,0 @@ import { BigIntStats, type Stats } from '../stats.js'; |
import { Buffer } from 'buffer'; | ||
import { Errno, ErrnoError } from '../error.js'; | ||
import { ActionType, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js'; | ||
import { isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../file.js'; | ||
import { BigIntStats, FileType } from '../stats.js'; | ||
@@ -86,3 +86,3 @@ import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js'; | ||
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : data; | ||
await this.file.write(encodedData, 0, encodedData.length, null); | ||
await this.file.write(encodedData, 0, encodedData.length); | ||
} | ||
@@ -391,36 +391,28 @@ /** | ||
if (!(await fs.exists(path, cred))) { | ||
switch (pathNotExistsAction(flag)) { | ||
case ActionType.CREATE: | ||
// Ensure parent exists. | ||
const parentStats = await fs.stat(dirname(resolved), cred); | ||
if (parentStats && !parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return new FileHandle(await fs.createFile(resolved, flag, mode, cred)); | ||
case ActionType.THROW: | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid file flag'); | ||
if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') { | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
} | ||
// Create the file | ||
const parentStats = await fs.stat(dirname(resolved), cred); | ||
if (parentStats && !parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return new FileHandle(await fs.createFile(resolved, flag, mode, cred)); | ||
} | ||
switch (pathExistsAction(flag)) { | ||
case ActionType.THROW: | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
case ActionType.TRUNCATE: | ||
/* | ||
In a previous implementation, we deleted the file and | ||
re-created it. However, this created a race condition if another | ||
asynchronous request was trying to read the file, as the file | ||
would not exist for a small period of time. | ||
*/ | ||
const file = await fs.openFile(resolved, flag, cred); | ||
await file.truncate(0); | ||
await file.sync(); | ||
return new FileHandle(file); | ||
case ActionType.NOP: | ||
// Must await so thrown errors are caught by the catch below | ||
return new FileHandle(await fs.openFile(resolved, flag, cred)); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid file flag'); | ||
if (isExclusive(flag)) { | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
} | ||
if (!isTruncating(flag)) { | ||
return new FileHandle(await fs.openFile(resolved, flag, cred)); | ||
} | ||
/* | ||
In a previous implementation, we deleted the file and | ||
re-created it. However, this created a race condition if another | ||
asynchronous request was trying to read the file, as the file | ||
would not exist for a small period of time. | ||
*/ | ||
const file = await fs.openFile(resolved, flag, cred); | ||
await file.truncate(0); | ||
await file.sync(); | ||
return new FileHandle(file); | ||
} | ||
@@ -427,0 +419,0 @@ /** |
/// <reference types="node" resolution-mode="require"/> | ||
import type { BigIntStatsFs, StatsFs } from 'node:fs'; | ||
import { Cred } from '../cred.js'; | ||
import type { Cred } from '../cred.js'; | ||
import type { File } from '../file.js'; | ||
import { FileSystem } from '../filesystem.js'; | ||
import type { FileSystem } from '../filesystem.js'; | ||
import { type AbsolutePath } from './path.js'; | ||
@@ -7,0 +7,0 @@ export declare let cred: Cred; |
@@ -6,3 +6,2 @@ // Utilities and shared data | ||
import { size_max } from '../inode.js'; | ||
import { ZenFsType } from '../stats.js'; | ||
import { normalizePath } from '../utils.js'; | ||
@@ -113,3 +112,3 @@ import { resolve } from './path.js'; | ||
return { | ||
type: (bigint ? BigInt : Number)(md.type || ZenFsType), | ||
type: (bigint ? BigInt : Number)(md.type), | ||
bsize: (bigint ? BigInt : Number)(bs), | ||
@@ -116,0 +115,0 @@ ffree: (bigint ? BigInt : Number)(md.freeNodes || size_max), |
@@ -5,3 +5,3 @@ /// <reference types="node" resolution-mode="require"/> | ||
import { Readable, Writable } from 'readable-stream'; | ||
import { Callback } from '../utils.js'; | ||
import type { Callback } from '../utils.js'; | ||
export declare class ReadStream extends Readable implements Node.ReadStream { | ||
@@ -8,0 +8,0 @@ close(callback?: Callback): void; |
@@ -6,3 +6,3 @@ /// <reference types="node" resolution-mode="require"/> | ||
import type * as fs from 'node:fs'; | ||
import { FileContents } from '../filesystem.js'; | ||
import type { FileContents } from '../filesystem.js'; | ||
import { BigIntStats, type Stats } from '../stats.js'; | ||
@@ -9,0 +9,0 @@ import { Dir, Dirent } from './dir.js'; |
import { Buffer } from 'buffer'; | ||
import { Errno, ErrnoError } from '../error.js'; | ||
import { ActionType, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js'; | ||
import { isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../file.js'; | ||
import { BigIntStats, FileType } from '../stats.js'; | ||
@@ -111,15 +111,11 @@ import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js'; | ||
if (!fs.existsSync(resolved, cred)) { | ||
switch (pathNotExistsAction(flag)) { | ||
case ActionType.CREATE: | ||
// Ensure parent exists. | ||
const parentStats = fs.statSync(dirname(resolved), cred); | ||
if (!parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return fs.createFileSync(resolved, flag, mode, cred); | ||
case ActionType.THROW: | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.'); | ||
if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') { | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
} | ||
// Create the file | ||
const parentStats = fs.statSync(dirname(resolved), cred); | ||
if (!parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return fs.createFileSync(resolved, flag, mode, cred); | ||
} | ||
@@ -130,21 +126,17 @@ const stats = fs.statSync(resolved, cred); | ||
} | ||
// File exists. | ||
switch (pathExistsAction(flag)) { | ||
case ActionType.THROW: | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
case ActionType.TRUNCATE: | ||
// Delete file. | ||
fs.unlinkSync(resolved, cred); | ||
/* | ||
Create file. Use the same mode as the old file. | ||
Node itself modifies the ctime when this occurs, so this action | ||
will preserve that behavior if the underlying file system | ||
supports those properties. | ||
*/ | ||
return fs.createFileSync(resolved, flag, stats.mode, cred); | ||
case ActionType.NOP: | ||
return fs.openFileSync(resolved, flag, cred); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.'); | ||
if (isExclusive(flag)) { | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
} | ||
if (!isTruncating(flag)) { | ||
return fs.openFileSync(resolved, flag, cred); | ||
} | ||
// Delete file. | ||
fs.unlinkSync(resolved, cred); | ||
/* | ||
Create file. Use the same mode as the old file. | ||
Node itself modifies the ctime when this occurs, so this action | ||
will preserve that behavior if the underlying file system | ||
supports those properties. | ||
*/ | ||
return fs.createFileSync(resolved, flag, stats.mode, cred); | ||
} | ||
@@ -243,3 +235,3 @@ /** | ||
try { | ||
file.writeSync(encodedData, 0, encodedData.byteLength, null); | ||
file.writeSync(encodedData, 0, encodedData.byteLength); | ||
} | ||
@@ -246,0 +238,0 @@ finally { |
@@ -5,3 +5,3 @@ /// <reference types="node" resolution-mode="require"/> | ||
* needed. | ||
* @url https://en.wikipedia.org/wiki/Errno.h | ||
* @see https://en.wikipedia.org/wiki/Errno.h | ||
*/ | ||
@@ -8,0 +8,0 @@ export declare enum Errno { |
/** | ||
* Standard libc error codes. More will be added to this enum and error strings as they are | ||
* needed. | ||
* @url https://en.wikipedia.org/wiki/Errno.h | ||
* @see https://en.wikipedia.org/wiki/Errno.h | ||
*/ | ||
@@ -6,0 +6,0 @@ export var Errno; |
@@ -23,11 +23,2 @@ /// <reference types="node" resolution-mode="require"/> | ||
} | ||
/** | ||
* @hidden | ||
*/ | ||
export declare enum ActionType { | ||
NOP = 0, | ||
THROW = 1, | ||
TRUNCATE = 2, | ||
CREATE = 3 | ||
} | ||
export declare function parseFlag(flag: string | number): string; | ||
@@ -47,4 +38,2 @@ export declare function flagToString(flag: number): string; | ||
export declare function isExclusive(flag: string): boolean; | ||
export declare function pathExistsAction(flag: string): ActionType; | ||
export declare function pathNotExistsAction(flag: string): ActionType; | ||
export declare abstract class File { | ||
@@ -106,3 +95,3 @@ /** | ||
*/ | ||
abstract write(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): Promise<number>; | ||
abstract write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number>; | ||
/** | ||
@@ -120,3 +109,3 @@ * Write buffer to the file. | ||
*/ | ||
abstract writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): number; | ||
abstract writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number; | ||
/** | ||
@@ -123,0 +112,0 @@ * Read data from the file. |
@@ -1,19 +0,5 @@ | ||
import { ErrnoError, Errno } from './error.js'; | ||
import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT } from './emulation/constants.js'; | ||
import { Errno, ErrnoError } from './error.js'; | ||
import { size_max } from './inode.js'; | ||
import { Stats } from './stats.js'; | ||
/** | ||
* @hidden | ||
*/ | ||
export var ActionType; | ||
(function (ActionType) { | ||
// Indicates that the code should not do anything. | ||
ActionType[ActionType["NOP"] = 0] = "NOP"; | ||
// Indicates that the code should throw an exception. | ||
ActionType[ActionType["THROW"] = 1] = "THROW"; | ||
// Indicates that the code should truncate the file, but only if it is a file. | ||
ActionType[ActionType["TRUNCATE"] = 2] = "TRUNCATE"; | ||
// Indicates that the code should create the file. | ||
ActionType[ActionType["CREATE"] = 3] = "CREATE"; | ||
})(ActionType || (ActionType = {})); | ||
const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+']; | ||
@@ -120,17 +106,2 @@ export function parseFlag(flag) { | ||
} | ||
export function pathExistsAction(flag) { | ||
if (isExclusive(flag)) { | ||
return ActionType.THROW; | ||
} | ||
if (isTruncating(flag)) { | ||
return ActionType.TRUNCATE; | ||
} | ||
return ActionType.NOP; | ||
} | ||
export function pathNotExistsAction(flag) { | ||
if ((isWriteable(flag) || isAppendable(flag)) && flag !== 'r+') { | ||
return ActionType.CREATE; | ||
} | ||
return ActionType.THROW; | ||
} | ||
export class File { | ||
@@ -310,3 +281,3 @@ [Symbol.asyncDispose]() { | ||
*/ | ||
async write(buffer, offset = 0, length = this.stats.size, position = 0) { | ||
async write(buffer, offset = 0, length = this.stats.size, position = this.position) { | ||
const bytesWritten = this.writeSync(buffer, offset, length, position); | ||
@@ -329,5 +300,4 @@ await this.sync(); | ||
*/ | ||
writeSync(buffer, offset = 0, length = this.stats.size, position = 0) { | ||
writeSync(buffer, offset = 0, length = this.stats.size, position = this.position) { | ||
this.dirty = true; | ||
position ?? (position = this.position); | ||
if (!isWriteable(this.flag)) { | ||
@@ -334,0 +304,0 @@ throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.'); |
import { type Cred } from './cred.js'; | ||
import { type File } from './file.js'; | ||
import type { Stats } from './stats.js'; | ||
import { type Stats } from './stats.js'; | ||
export type FileContents = ArrayBufferView | string; | ||
@@ -53,3 +53,3 @@ /** | ||
*/ | ||
type?: number; | ||
type: number; | ||
} | ||
@@ -59,16 +59,8 @@ /** | ||
* | ||
* This class includes some default implementations | ||
* This class includes default implementations for `exists` and `existsSync` | ||
* | ||
* Assume the following about arguments passed to each API method: | ||
* | ||
* - Every path is an absolute path. `.`, `..`, and other items are resolved into an absolute form. | ||
* - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values. | ||
* If you are extending this class, note that every path is an absolute path and all arguments are present. | ||
*/ | ||
export declare abstract class FileSystem { | ||
/** | ||
* Numeric type, used for statfs | ||
* @internal @protected | ||
*/ | ||
_type?: number; | ||
/** | ||
* Get metadata about the current file system | ||
@@ -80,4 +72,3 @@ */ | ||
/** | ||
* Asynchronous rename. No arguments other than a possible exception | ||
* are given to the completion callback. | ||
* Asynchronous rename. | ||
*/ | ||
@@ -98,4 +89,4 @@ abstract rename(oldPath: string, newPath: string, cred: Cred): Promise<void>; | ||
/** | ||
* Opens the file at path p with the given flag. The file must exist. | ||
* @param p The path to open. | ||
* Opens the file at `path` with the given flag. The file must exist. | ||
* @param path The path to open. | ||
* @param flag The flag to use when opening the file. | ||
@@ -105,4 +96,4 @@ */ | ||
/** | ||
* Opens the file at path p with the given flag. The file must exist. | ||
* @param p The path to open. | ||
* Opens the file at `path` with the given flag. The file must exist. | ||
* @param path The path to open. | ||
* @param flag The flag to use when opening the file. | ||
@@ -113,9 +104,7 @@ * @return A File object corresponding to the opened file. | ||
/** | ||
* Create the file at path p with the given mode. Then, open it with the given | ||
* flag. | ||
* Create the file at `path` with the given mode. Then, open it with the given flag. | ||
*/ | ||
abstract createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>; | ||
/** | ||
* Create the file at path p with the given mode. Then, open it with the given | ||
* flag. | ||
* Create the file at `path` with the given mode. Then, open it with the given flag. | ||
*/ | ||
@@ -141,4 +130,3 @@ abstract createFileSync(path: string, flag: string, mode: number, cred: Cred): File; | ||
* Asynchronous `mkdir`. | ||
* @param mode Mode to make the directory using. Can be ignored if | ||
* the filesystem doesn't support permissions. | ||
* @param mode Mode to make the directory using. | ||
*/ | ||
@@ -148,4 +136,3 @@ abstract mkdir(path: string, mode: number, cred: Cred): Promise<void>; | ||
* Synchronous `mkdir`. | ||
* @param mode Mode to make the directory using. Can be ignored if | ||
* the filesystem doesn't support permissions. | ||
* @param mode Mode to make the directory using. | ||
*/ | ||
@@ -155,5 +142,2 @@ abstract mkdirSync(path: string, mode: number, cred: Cred): void; | ||
* Asynchronous `readdir`. Reads the contents of a directory. | ||
* | ||
* The callback gets two arguments `(err, files)` where `files` is an array of | ||
* the names of the files in the directory excluding `'.'` and `'..'`. | ||
*/ | ||
@@ -245,10 +229,8 @@ abstract readdir(path: string, cred: Cred): Promise<string[]>; | ||
* | ||
* Implementing classes must define a protected _sync property for the synchronous file system used as a cache. | ||
* by: | ||
* Implementing classes must define `_sync` for the synchronous file system used as a cache. | ||
* Synchronous methods on an asynchronous FS are implemented by: | ||
* - Performing operations over the in-memory copy, | ||
* while asynchronously pipelining them to the backing store. | ||
* - During loading, the contents of the async file system are eloaded into the synchronous store. | ||
* | ||
* - Performing operations over the in-memory copy, while asynchronously pipelining them | ||
* to the backing store. | ||
* - During application loading, the contents of the async file system can be reloaded into | ||
* the synchronous store, if desired. | ||
* | ||
*/ | ||
@@ -255,0 +237,0 @@ export declare function Async<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => AsyncFS) & T; |
@@ -5,11 +5,9 @@ import { ErrnoError, Errno } from './error.js'; | ||
import { PreloadFile, parseFlag } from './file.js'; | ||
import { ZenFsType } from './stats.js'; | ||
/** | ||
* Structure for a filesystem. All ZenFS backends must extend this. | ||
* | ||
* This class includes some default implementations | ||
* This class includes default implementations for `exists` and `existsSync` | ||
* | ||
* Assume the following about arguments passed to each API method: | ||
* | ||
* - Every path is an absolute path. `.`, `..`, and other items are resolved into an absolute form. | ||
* - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values. | ||
* If you are extending this class, note that every path is an absolute path and all arguments are present. | ||
*/ | ||
@@ -28,3 +26,3 @@ export class FileSystem { | ||
noAsyncCache: false, | ||
type: this._type, | ||
type: ZenFsType, | ||
}; | ||
@@ -104,10 +102,8 @@ } | ||
* | ||
* Implementing classes must define a protected _sync property for the synchronous file system used as a cache. | ||
* by: | ||
* Implementing classes must define `_sync` for the synchronous file system used as a cache. | ||
* Synchronous methods on an asynchronous FS are implemented by: | ||
* - Performing operations over the in-memory copy, | ||
* while asynchronously pipelining them to the backing store. | ||
* - During loading, the contents of the async file system are eloaded into the synchronous store. | ||
* | ||
* - Performing operations over the in-memory copy, while asynchronously pipelining them | ||
* to the backing store. | ||
* - During application loading, the contents of the async file system can be reloaded into | ||
* the synchronous store, if desired. | ||
* | ||
*/ | ||
@@ -114,0 +110,0 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any |
/// <reference types="node" resolution-mode="require"/> | ||
import type * as Node from 'fs'; | ||
import { Cred } from './cred.js'; | ||
import type { Cred } from './cred.js'; | ||
/** | ||
@@ -5,0 +5,0 @@ * Indicates the type of the given file. Applied to 'mode'. |
@@ -5,5 +5,5 @@ /// <reference types="node" resolution-mode="require"/> | ||
import { ErrnoError } from './error.js'; | ||
import { Cred } from './cred.js'; | ||
import type { Cred } from './cred.js'; | ||
import { type AbsolutePath } from './emulation/path.js'; | ||
import { FileSystem } from './filesystem.js'; | ||
import type { FileSystem } from './filesystem.js'; | ||
import type * as fs from 'node:fs'; | ||
@@ -10,0 +10,0 @@ declare global { |
@@ -1,4 +0,4 @@ | ||
Copyright (c) 2023-2024 James P. and other ZenFS contributors. | ||
Copyright (c) James P. and other ZenFS contributors. | ||
Copyright (c) 2013-2023 John Vilk and other BrowserFS contributors. | ||
Copyright (c) Joyent, Inc. and other Node contributors for `test/fixtures/node`. | ||
@@ -22,25 +22,1 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
SOFTWARE. | ||
This license applies to all parts of ZenFS, except for the following items: | ||
- The test fixtures located in `test/fixtures/node`. Their license follows: | ||
""" | ||
Copyright Joyent, Inc. and other Node contributors. All rights reserved. | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to | ||
deal in the Software without restriction, including without limitation the | ||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
sell copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
IN THE SOFTWARE. | ||
""" |
{ | ||
"name": "@zenfs/core", | ||
"version": "0.12.2", | ||
"version": "0.12.3", | ||
"description": "A filesystem in your browser", | ||
@@ -41,3 +41,3 @@ "main": "dist/index.js", | ||
"format:check": "prettier --check .", | ||
"lint": "eslint src tests && tsc -p tsconfig.json --noEmit", | ||
"lint": "tsc -p tsconfig.json --noEmit && eslint src tests", | ||
"test": "npm run build && tsc -p tests/tsconfig.json --noEmit && cross-env NODE_OPTIONS=--experimental-vm-modules npx jest", | ||
@@ -44,0 +44,0 @@ "build": "node scripts/build.js --globalName=ZenFS --entry src/index.ts", |
@@ -7,3 +7,3 @@ # ZenFS | ||
ZenFS is a fork of [BrowserFS](https://github.com/jvilk/BrowserFS). If you are using ZenFS in a research paper, you may want to [cite BrowserFS](https://github.com/jvilk/BrowserFS?tab=readme-ov-file#citing). | ||
ZenFS is a fork of [BrowserFS](https://github.com/jvilk/BrowserFS). If you are using ZenFS in a research paper, you may want to [cite BrowserFS](https://github.com/jvilk/BrowserFS#citing). | ||
@@ -10,0 +10,0 @@ ## Backends |
import type { RequiredKeys } from 'utilium'; | ||
import { ErrnoError, Errno } from '../error.js'; | ||
import { FileSystem } from '../filesystem.js'; | ||
import type { FileSystem } from '../filesystem.js'; | ||
import { levenshtein } from '../utils.js'; | ||
@@ -5,0 +5,0 @@ |
import { Errno, ErrnoError } from '../error.js'; | ||
import type { FileSystemMetadata } from '../filesystem.js'; | ||
import { Stats } from '../stats.js'; | ||
import type { Stats } from '../stats.js'; | ||
import type { Backend } from './backend.js'; | ||
@@ -5,0 +5,0 @@ import { IndexFS } from './index/fs.js'; |
@@ -7,3 +7,4 @@ import type { Cred } from '../../cred.js'; | ||
import { decode } from '../../utils.js'; | ||
import { Index, IndexData } from './index.js'; | ||
import type { IndexData } from './index.js'; | ||
import { Index } from './index.js'; | ||
@@ -10,0 +11,0 @@ export abstract class IndexFS extends Readonly(FileSystem) { |
import { isJSON } from 'utilium'; | ||
import { Errno, ErrnoError } from '../../error.js'; | ||
import { Stats, StatsLike } from '../../stats.js'; | ||
import type { StatsLike } from '../../stats.js'; | ||
import { Stats } from '../../stats.js'; | ||
import { encode } from '../../utils.js'; | ||
@@ -5,0 +6,0 @@ import { basename, dirname } from '../../emulation/path.js'; |
@@ -1,8 +0,11 @@ | ||
import { FileSystem, FileSystemMetadata } from '../filesystem.js'; | ||
import type { FileSystemMetadata } from '../filesystem.js'; | ||
import { FileSystem } from '../filesystem.js'; | ||
import { ErrnoError, Errno } from '../error.js'; | ||
import { File, PreloadFile, parseFlag } from '../file.js'; | ||
import type { File } from '../file.js'; | ||
import { PreloadFile, parseFlag } from '../file.js'; | ||
import { Stats } from '../stats.js'; | ||
import { LockedFS } from './locked.js'; | ||
import { dirname } from '../emulation/path.js'; | ||
import { Cred, rootCred } from '../cred.js'; | ||
import type { Cred } from '../cred.js'; | ||
import { rootCred } from '../cred.js'; | ||
import { decode, encode } from '../utils.js'; | ||
@@ -9,0 +12,0 @@ import type { Backend } from './backend.js'; |
@@ -41,2 +41,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
protected _throwNoSync(syscall: string): never { | ||
throw new ErrnoError(Errno.ENOTSUP, 'Syncrohnous operations not support on PortFile', this.path, syscall); | ||
} | ||
public stat(): Promise<Stats> { | ||
@@ -47,3 +51,3 @@ return this.rpc('stat'); | ||
public statSync(): Stats { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.stat'); | ||
this._throwNoSync('stat'); | ||
} | ||
@@ -56,3 +60,3 @@ | ||
public truncateSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.truncate'); | ||
this._throwNoSync('truncate'); | ||
} | ||
@@ -65,3 +69,3 @@ | ||
public writeSync(): number { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.write'); | ||
this._throwNoSync('write'); | ||
} | ||
@@ -75,3 +79,3 @@ | ||
public readSync(): number { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.read'); | ||
this._throwNoSync('read'); | ||
} | ||
@@ -84,3 +88,3 @@ | ||
public chownSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.chown'); | ||
this._throwNoSync('chown'); | ||
} | ||
@@ -93,3 +97,3 @@ | ||
public chmodSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.chmod'); | ||
this._throwNoSync('chmod'); | ||
} | ||
@@ -102,3 +106,3 @@ | ||
public utimesSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.utimes'); | ||
this._throwNoSync('utimes'); | ||
} | ||
@@ -111,3 +115,3 @@ | ||
public _setTypeSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile._setType'); | ||
this._throwNoSync('_setType'); | ||
} | ||
@@ -120,3 +124,3 @@ | ||
public closeSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.close'); | ||
this._throwNoSync('close'); | ||
} | ||
@@ -129,3 +133,3 @@ | ||
public syncSync(): void { | ||
throw ErrnoError.With('ENOSYS', this.path, 'PortFile.sync'); | ||
this._throwNoSync('sync'); | ||
} | ||
@@ -132,0 +136,0 @@ } |
@@ -21,3 +21,3 @@ import { type Entries } from 'utilium'; | ||
* Retrieve a file system with the given configuration. | ||
* @param config A BackendConfig object. | ||
* @see MountConfiguration | ||
*/ | ||
@@ -24,0 +24,0 @@ export async function resolveMountConfig<T extends Backend>(config: MountConfiguration<T>, _depth = 0): Promise<FilesystemOf<T>> { |
/** | ||
* Credentials used for various operations. | ||
* Similar to Linux's cred struct. See https://github.com/torvalds/linux/blob/master/include/linux/cred.h | ||
* Similar to Linux's cred struct. | ||
* @see https://github.com/torvalds/linux/blob/master/include/linux/cred.h | ||
*/ | ||
@@ -5,0 +6,0 @@ export interface Cred { |
@@ -8,3 +8,4 @@ import { Buffer } from 'buffer'; | ||
import { R_OK } from './constants.js'; | ||
import { Dirent, type Dir } from './dir.js'; | ||
import type { Dirent } from './dir.js'; | ||
import { type Dir } from './dir.js'; | ||
import * as promises from './promises.js'; | ||
@@ -11,0 +12,0 @@ import { fd2file } from './shared.js'; |
@@ -10,3 +10,4 @@ import { Buffer } from 'buffer'; | ||
import { Errno, ErrnoError } from '../error.js'; | ||
import { ActionType, File, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js'; | ||
import type { File } from '../file.js'; | ||
import { isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../file.js'; | ||
import type { FileContents } from '../filesystem.js'; | ||
@@ -114,3 +115,3 @@ import { BigIntStats, FileType, type Stats } from '../stats.js'; | ||
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : data; | ||
await this.file.write(encodedData, 0, encodedData.length, null); | ||
await this.file.write(encodedData, 0, encodedData.length); | ||
} | ||
@@ -497,37 +498,31 @@ | ||
if (!(await fs.exists(path, cred))) { | ||
switch (pathNotExistsAction(flag)) { | ||
case ActionType.CREATE: | ||
// Ensure parent exists. | ||
const parentStats: Stats = await fs.stat(dirname(resolved), cred); | ||
if (parentStats && !parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return new FileHandle(await fs.createFile(resolved, flag, mode, cred)); | ||
case ActionType.THROW: | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid file flag'); | ||
if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') { | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
} | ||
// Create the file | ||
const parentStats: Stats = await fs.stat(dirname(resolved), cred); | ||
if (parentStats && !parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return new FileHandle(await fs.createFile(resolved, flag, mode, cred)); | ||
} | ||
switch (pathExistsAction(flag)) { | ||
case ActionType.THROW: | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
case ActionType.TRUNCATE: | ||
/* | ||
In a previous implementation, we deleted the file and | ||
re-created it. However, this created a race condition if another | ||
asynchronous request was trying to read the file, as the file | ||
would not exist for a small period of time. | ||
*/ | ||
const file: File = await fs.openFile(resolved, flag, cred); | ||
await file.truncate(0); | ||
await file.sync(); | ||
return new FileHandle(file); | ||
case ActionType.NOP: | ||
// Must await so thrown errors are caught by the catch below | ||
return new FileHandle(await fs.openFile(resolved, flag, cred)); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid file flag'); | ||
if (isExclusive(flag)) { | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
} | ||
if (!isTruncating(flag)) { | ||
return new FileHandle(await fs.openFile(resolved, flag, cred)); | ||
} | ||
/* | ||
In a previous implementation, we deleted the file and | ||
re-created it. However, this created a race condition if another | ||
asynchronous request was trying to read the file, as the file | ||
would not exist for a small period of time. | ||
*/ | ||
const file: File = await fs.openFile(resolved, flag, cred); | ||
await file.truncate(0); | ||
await file.sync(); | ||
return new FileHandle(file); | ||
} | ||
@@ -534,0 +529,0 @@ |
@@ -5,8 +5,8 @@ // Utilities and shared data | ||
import { InMemory } from '../backends/memory.js'; | ||
import { Cred, rootCred } from '../cred.js'; | ||
import type { Cred } from '../cred.js'; | ||
import { rootCred } from '../cred.js'; | ||
import { Errno, ErrnoError } from '../error.js'; | ||
import type { File } from '../file.js'; | ||
import { FileSystem } from '../filesystem.js'; | ||
import type { FileSystem } from '../filesystem.js'; | ||
import { size_max } from '../inode.js'; | ||
import { ZenFsType } from '../stats.js'; | ||
import { normalizePath } from '../utils.js'; | ||
@@ -133,3 +133,3 @@ import { resolve, type AbsolutePath } from './path.js'; | ||
return { | ||
type: (bigint ? BigInt : Number)(md.type || ZenFsType), | ||
type: (bigint ? BigInt : Number)(md.type), | ||
bsize: (bigint ? BigInt : Number)(bs), | ||
@@ -136,0 +136,0 @@ ffree: (bigint ? BigInt : Number)(md.freeNodes || size_max), |
import type * as Node from 'fs'; | ||
import { Readable, Writable } from 'readable-stream'; | ||
import { Callback } from '../utils.js'; | ||
import type { Callback } from '../utils.js'; | ||
import { ErrnoError, Errno } from '../error.js'; | ||
@@ -5,0 +5,0 @@ |
import { Buffer } from 'buffer'; | ||
import type * as fs from 'node:fs'; | ||
import { Errno, ErrnoError } from '../error.js'; | ||
import { ActionType, File, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js'; | ||
import { FileContents } from '../filesystem.js'; | ||
import type { File } from '../file.js'; | ||
import { isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../file.js'; | ||
import type { FileContents } from '../filesystem.js'; | ||
import { BigIntStats, FileType, type Stats } from '../stats.js'; | ||
@@ -134,15 +135,11 @@ import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js'; | ||
if (!fs.existsSync(resolved, cred)) { | ||
switch (pathNotExistsAction(flag)) { | ||
case ActionType.CREATE: | ||
// Ensure parent exists. | ||
const parentStats: Stats = fs.statSync(dirname(resolved), cred); | ||
if (!parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return fs.createFileSync(resolved, flag, mode, cred); | ||
case ActionType.THROW: | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.'); | ||
if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') { | ||
throw ErrnoError.With('ENOENT', path, '_open'); | ||
} | ||
// Create the file | ||
const parentStats: Stats = fs.statSync(dirname(resolved), cred); | ||
if (!parentStats.isDirectory()) { | ||
throw ErrnoError.With('ENOTDIR', dirname(path), '_open'); | ||
} | ||
return fs.createFileSync(resolved, flag, mode, cred); | ||
} | ||
@@ -156,21 +153,19 @@ | ||
// File exists. | ||
switch (pathExistsAction(flag)) { | ||
case ActionType.THROW: | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
case ActionType.TRUNCATE: | ||
// Delete file. | ||
fs.unlinkSync(resolved, cred); | ||
/* | ||
Create file. Use the same mode as the old file. | ||
Node itself modifies the ctime when this occurs, so this action | ||
will preserve that behavior if the underlying file system | ||
supports those properties. | ||
*/ | ||
return fs.createFileSync(resolved, flag, stats.mode, cred); | ||
case ActionType.NOP: | ||
return fs.openFileSync(resolved, flag, cred); | ||
default: | ||
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.'); | ||
if (isExclusive(flag)) { | ||
throw ErrnoError.With('EEXIST', path, '_open'); | ||
} | ||
if (!isTruncating(flag)) { | ||
return fs.openFileSync(resolved, flag, cred); | ||
} | ||
// Delete file. | ||
fs.unlinkSync(resolved, cred); | ||
/* | ||
Create file. Use the same mode as the old file. | ||
Node itself modifies the ctime when this occurs, so this action | ||
will preserve that behavior if the underlying file system | ||
supports those properties. | ||
*/ | ||
return fs.createFileSync(resolved, flag, stats.mode, cred); | ||
} | ||
@@ -297,3 +292,3 @@ | ||
try { | ||
file.writeSync(encodedData, 0, encodedData.byteLength, null); | ||
file.writeSync(encodedData, 0, encodedData.byteLength); | ||
} finally { | ||
@@ -300,0 +295,0 @@ file.closeSync(); |
/** | ||
* Standard libc error codes. More will be added to this enum and error strings as they are | ||
* needed. | ||
* @url https://en.wikipedia.org/wiki/Errno.h | ||
* @see https://en.wikipedia.org/wiki/Errno.h | ||
*/ | ||
@@ -6,0 +6,0 @@ export enum Errno { |
import type { FileReadResult } from 'node:fs/promises'; | ||
import { ErrnoError, Errno } from './error.js'; | ||
import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT } from './emulation/constants.js'; | ||
import { Errno, ErrnoError } from './error.js'; | ||
import type { FileSystem } from './filesystem.js'; | ||
@@ -35,16 +35,2 @@ import { size_max } from './inode.js'; | ||
/** | ||
* @hidden | ||
*/ | ||
export enum ActionType { | ||
// Indicates that the code should not do anything. | ||
NOP = 0, | ||
// Indicates that the code should throw an exception. | ||
THROW = 1, | ||
// Indicates that the code should truncate the file, but only if it is a file. | ||
TRUNCATE = 2, | ||
// Indicates that the code should create the file. | ||
CREATE = 3, | ||
} | ||
const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+']; | ||
@@ -162,21 +148,2 @@ | ||
export function pathExistsAction(flag: string): ActionType { | ||
if (isExclusive(flag)) { | ||
return ActionType.THROW; | ||
} | ||
if (isTruncating(flag)) { | ||
return ActionType.TRUNCATE; | ||
} | ||
return ActionType.NOP; | ||
} | ||
export function pathNotExistsAction(flag: string): ActionType { | ||
if ((isWriteable(flag) || isAppendable(flag)) && flag !== 'r+') { | ||
return ActionType.CREATE; | ||
} | ||
return ActionType.THROW; | ||
} | ||
export abstract class File { | ||
@@ -254,3 +221,3 @@ /** | ||
*/ | ||
public abstract write(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): Promise<number>; | ||
public abstract write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number>; | ||
@@ -269,3 +236,3 @@ /** | ||
*/ | ||
public abstract writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): number; | ||
public abstract writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number; | ||
@@ -522,3 +489,3 @@ /** | ||
*/ | ||
public async write(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = 0): Promise<number> { | ||
public async write(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): Promise<number> { | ||
const bytesWritten = this.writeSync(buffer, offset, length, position); | ||
@@ -542,5 +509,4 @@ await this.sync(); | ||
*/ | ||
public writeSync(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = 0): number { | ||
public writeSync(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number { | ||
this.dirty = true; | ||
position ??= this.position; | ||
if (!isWriteable(this.flag)) { | ||
@@ -547,0 +513,0 @@ throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.'); |
@@ -6,3 +6,3 @@ import type { ExtractProperties } from 'utilium'; | ||
import { PreloadFile, parseFlag, type File } from './file.js'; | ||
import type { Stats } from './stats.js'; | ||
import { ZenFsType, type Stats } from './stats.js'; | ||
@@ -68,3 +68,3 @@ export type FileContents = ArrayBufferView | string; | ||
*/ | ||
type?: number; | ||
type: number; | ||
} | ||
@@ -75,17 +75,8 @@ | ||
* | ||
* This class includes some default implementations | ||
* This class includes default implementations for `exists` and `existsSync` | ||
* | ||
* Assume the following about arguments passed to each API method: | ||
* | ||
* - Every path is an absolute path. `.`, `..`, and other items are resolved into an absolute form. | ||
* - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values. | ||
* If you are extending this class, note that every path is an absolute path and all arguments are present. | ||
*/ | ||
export abstract class FileSystem { | ||
/** | ||
* Numeric type, used for statfs | ||
* @internal @protected | ||
*/ | ||
_type?: number; | ||
/** | ||
* Get metadata about the current file system | ||
@@ -101,3 +92,3 @@ */ | ||
noAsyncCache: false, | ||
type: this._type, | ||
type: ZenFsType, | ||
}; | ||
@@ -111,4 +102,3 @@ } | ||
/** | ||
* Asynchronous rename. No arguments other than a possible exception | ||
* are given to the completion callback. | ||
* Asynchronous rename. | ||
*/ | ||
@@ -132,4 +122,4 @@ public abstract rename(oldPath: string, newPath: string, cred: Cred): Promise<void>; | ||
/** | ||
* Opens the file at path p with the given flag. The file must exist. | ||
* @param p The path to open. | ||
* Opens the file at `path` with the given flag. The file must exist. | ||
* @param path The path to open. | ||
* @param flag The flag to use when opening the file. | ||
@@ -140,4 +130,4 @@ */ | ||
/** | ||
* Opens the file at path p with the given flag. The file must exist. | ||
* @param p The path to open. | ||
* Opens the file at `path` with the given flag. The file must exist. | ||
* @param path The path to open. | ||
* @param flag The flag to use when opening the file. | ||
@@ -149,4 +139,3 @@ * @return A File object corresponding to the opened file. | ||
/** | ||
* Create the file at path p with the given mode. Then, open it with the given | ||
* flag. | ||
* Create the file at `path` with the given mode. Then, open it with the given flag. | ||
*/ | ||
@@ -156,4 +145,3 @@ public abstract createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>; | ||
/** | ||
* Create the file at path p with the given mode. Then, open it with the given | ||
* flag. | ||
* Create the file at `path` with the given mode. Then, open it with the given flag. | ||
*/ | ||
@@ -181,4 +169,3 @@ public abstract createFileSync(path: string, flag: string, mode: number, cred: Cred): File; | ||
* Asynchronous `mkdir`. | ||
* @param mode Mode to make the directory using. Can be ignored if | ||
* the filesystem doesn't support permissions. | ||
* @param mode Mode to make the directory using. | ||
*/ | ||
@@ -188,4 +175,3 @@ public abstract mkdir(path: string, mode: number, cred: Cred): Promise<void>; | ||
* Synchronous `mkdir`. | ||
* @param mode Mode to make the directory using. Can be ignored if | ||
* the filesystem doesn't support permissions. | ||
* @param mode Mode to make the directory using. | ||
*/ | ||
@@ -195,5 +181,2 @@ public abstract mkdirSync(path: string, mode: number, cred: Cred): void; | ||
* Asynchronous `readdir`. Reads the contents of a directory. | ||
* | ||
* The callback gets two arguments `(err, files)` where `files` is an array of | ||
* the names of the files in the directory excluding `'.'` and `'..'`. | ||
*/ | ||
@@ -367,10 +350,8 @@ public abstract readdir(path: string, cred: Cred): Promise<string[]>; | ||
* | ||
* Implementing classes must define a protected _sync property for the synchronous file system used as a cache. | ||
* by: | ||
* Implementing classes must define `_sync` for the synchronous file system used as a cache. | ||
* Synchronous methods on an asynchronous FS are implemented by: | ||
* - Performing operations over the in-memory copy, | ||
* while asynchronously pipelining them to the backing store. | ||
* - During loading, the contents of the async file system are eloaded into the synchronous store. | ||
* | ||
* - Performing operations over the in-memory copy, while asynchronously pipelining them | ||
* to the backing store. | ||
* - During application loading, the contents of the async file system can be reloaded into | ||
* the synchronous store, if desired. | ||
* | ||
*/ | ||
@@ -377,0 +358,0 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any |
import type * as Node from 'fs'; | ||
import { Cred } from './cred.js'; | ||
import type { Cred } from './cred.js'; | ||
import { S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRWXG, S_IRWXO, S_IRWXU } from './emulation/constants.js'; | ||
@@ -4,0 +4,0 @@ import { size_max } from './inode.js'; |
import type { OptionalTuple } from 'utilium'; | ||
import { ErrnoError, Errno } from './error.js'; | ||
import { Cred } from './cred.js'; | ||
import type { Cred } from './cred.js'; | ||
import { dirname, resolve, type AbsolutePath } from './emulation/path.js'; | ||
import { FileSystem } from './filesystem.js'; | ||
import type { FileSystem } from './filesystem.js'; | ||
import type * as fs from 'node:fs'; | ||
@@ -7,0 +7,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
1857642
20470