New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@zenfs/core

Package Overview
Dependencies
Maintainers
0
Versions
165
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@zenfs/core - npm Package Compare versions

Comparing version 0.13.0 to 0.14.0

dist/symbol-dispose.d.ts

52

dist/backends/locked.d.ts
import type { Cred } from '../cred.js';
import type { File } from '../file.js';
import type { FileSystem, FileSystemMetadata } from '../filesystem.js';
import type { FileSystemMetadata } from '../filesystem.js';
import { FileSystem } from '../filesystem.js';
import type { Stats } from '../stats.js';
export interface MutexLock extends PromiseWithResolvers<void> {
[Symbol.dispose](): void;
}
/**

@@ -17,4 +21,33 @@ * This class serializes access to an underlying async filesystem.

readonly fs: FS;
private mutex;
constructor(fs: FS);
/**
* The current locks
*/
private locks;
protected addLock(path: string): MutexLock;
/**
* Locks `path` asynchronously.
* If the path is currently locked, waits for it to be unlocked.
* @internal
*/
lock(path: string): Promise<MutexLock>;
/**
* Locks `path` asynchronously.
* If the path is currently locked, an error will be thrown
* @internal
*/
lockSync(path: string): MutexLock;
/**
* Unlocks a path
* @param path The path to lock
* @param noThrow If true, an error will not be thrown if the path is already unlocked
* @returns Whether the path was unlocked
* @internal
*/
unlock(path: string, noThrow?: boolean): boolean;
/**
* Whether `path` is locked
* @internal
*/
isLocked(path: string): boolean;
ready(): Promise<void>;

@@ -45,1 +78,16 @@ metadata(): FileSystemMetadata;

}
export declare const Locked: {
name: string;
options: {
fs: {
type: "object";
required: true;
description: string;
validator(fs: FileSystem): void;
};
};
isAvailable(): true;
create({ fs }: {
fs: FileSystem;
} & Partial<import("./backend.js").SharedConfig>): LockedFS<FileSystem>;
};

@@ -1,3 +0,48 @@

import { ErrnoError } from '../error.js';
import { Mutex } from '../mutex.js';
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { Errno, ErrnoError } from '../error.js';
import { FileSystem } from '../filesystem.js';
/**

@@ -16,4 +61,67 @@ * This class serializes access to an underlying async filesystem.

this.fs = fs;
this.mutex = new Mutex();
/**
* The current locks
*/
this.locks = new Map();
}
addLock(path) {
const lock = {
...Promise.withResolvers(),
[Symbol.dispose]: () => {
this.unlock(path);
},
};
this.locks.set(path, lock);
return lock;
}
/**
* Locks `path` asynchronously.
* If the path is currently locked, waits for it to be unlocked.
* @internal
*/
async lock(path) {
if (this.locks.has(path)) {
// Non-null assertion: we already checked locks has path
await this.locks.get(path).promise;
}
return this.addLock(path);
}
/**
* Locks `path` asynchronously.
* If the path is currently locked, an error will be thrown
* @internal
*/
lockSync(path) {
if (this.locks.has(path)) {
// Non-null assertion: we already checked locks has path
throw ErrnoError.With('EBUSY', path, 'lockSync');
}
return this.addLock(path);
}
/**
* Unlocks a path
* @param path The path to lock
* @param noThrow If true, an error will not be thrown if the path is already unlocked
* @returns Whether the path was unlocked
* @internal
*/
unlock(path, noThrow = false) {
if (!this.locks.has(path)) {
if (noThrow) {
return false;
}
throw new ErrnoError(Errno.EPERM, 'Can not unlock an already unlocked path', path);
}
// Non-null assertion: we already checked locks has path
this.locks.get(path).resolve();
this.locks.delete(path);
return true;
}
/**
* Whether `path` is locked
* @internal
*/
isLocked(path) {
return this.locks.has(path);
}
async ready() {

@@ -29,127 +137,352 @@ await this.fs.ready();

async rename(oldPath, newPath, cred) {
await this.mutex.lock(oldPath);
await this.fs.rename(oldPath, newPath, cred);
this.mutex.unlock(oldPath);
const env_1 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_1, await this.lock(oldPath), false);
await this.fs.rename(oldPath, newPath, cred);
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
}
}
renameSync(oldPath, newPath, cred) {
if (this.mutex.isLocked(oldPath)) {
throw ErrnoError.With('EBUSY', oldPath, 'rename');
const env_2 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_2, this.lockSync(oldPath), false);
return this.fs.renameSync(oldPath, newPath, cred);
}
return this.fs.renameSync(oldPath, newPath, cred);
catch (e_2) {
env_2.error = e_2;
env_2.hasError = true;
}
finally {
__disposeResources(env_2);
}
}
async stat(path, cred) {
await this.mutex.lock(path);
const stats = await this.fs.stat(path, cred);
this.mutex.unlock(path);
return stats;
const env_3 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_3, await this.lock(path), false);
return await this.fs.stat(path, cred);
}
catch (e_3) {
env_3.error = e_3;
env_3.hasError = true;
}
finally {
__disposeResources(env_3);
}
}
statSync(path, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'stat');
const env_4 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_4, this.lockSync(path), false);
return this.fs.statSync(path, cred);
}
return this.fs.statSync(path, cred);
catch (e_4) {
env_4.error = e_4;
env_4.hasError = true;
}
finally {
__disposeResources(env_4);
}
}
async openFile(path, flag, cred) {
await this.mutex.lock(path);
const fd = await this.fs.openFile(path, flag, cred);
this.mutex.unlock(path);
return fd;
const env_5 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_5, await this.lock(path), false);
return await this.fs.openFile(path, flag, cred);
}
catch (e_5) {
env_5.error = e_5;
env_5.hasError = true;
}
finally {
__disposeResources(env_5);
}
}
openFileSync(path, flag, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'openFile');
const env_6 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_6, this.lockSync(path), false);
return this.fs.openFileSync(path, flag, cred);
}
return this.fs.openFileSync(path, flag, cred);
catch (e_6) {
env_6.error = e_6;
env_6.hasError = true;
}
finally {
__disposeResources(env_6);
}
}
async createFile(path, flag, mode, cred) {
await this.mutex.lock(path);
const fd = await this.fs.createFile(path, flag, mode, cred);
this.mutex.unlock(path);
return fd;
const env_7 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_7, await this.lock(path), false);
return await this.fs.createFile(path, flag, mode, cred);
}
catch (e_7) {
env_7.error = e_7;
env_7.hasError = true;
}
finally {
__disposeResources(env_7);
}
}
createFileSync(path, flag, mode, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'createFile');
const env_8 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_8, this.lockSync(path), false);
return this.fs.createFileSync(path, flag, mode, cred);
}
return this.fs.createFileSync(path, flag, mode, cred);
catch (e_8) {
env_8.error = e_8;
env_8.hasError = true;
}
finally {
__disposeResources(env_8);
}
}
async unlink(path, cred) {
await this.mutex.lock(path);
await this.fs.unlink(path, cred);
this.mutex.unlock(path);
const env_9 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_9, await this.lock(path), false);
await this.fs.unlink(path, cred);
}
catch (e_9) {
env_9.error = e_9;
env_9.hasError = true;
}
finally {
__disposeResources(env_9);
}
}
unlinkSync(path, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'unlink');
const env_10 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_10, this.lockSync(path), false);
return this.fs.unlinkSync(path, cred);
}
return this.fs.unlinkSync(path, cred);
catch (e_10) {
env_10.error = e_10;
env_10.hasError = true;
}
finally {
__disposeResources(env_10);
}
}
async rmdir(path, cred) {
await this.mutex.lock(path);
await this.fs.rmdir(path, cred);
this.mutex.unlock(path);
const env_11 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_11, await this.lock(path), false);
await this.fs.rmdir(path, cred);
}
catch (e_11) {
env_11.error = e_11;
env_11.hasError = true;
}
finally {
__disposeResources(env_11);
}
}
rmdirSync(path, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'rmdir');
const env_12 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_12, this.lockSync(path), false);
return this.fs.rmdirSync(path, cred);
}
return this.fs.rmdirSync(path, cred);
catch (e_12) {
env_12.error = e_12;
env_12.hasError = true;
}
finally {
__disposeResources(env_12);
}
}
async mkdir(path, mode, cred) {
await this.mutex.lock(path);
await this.fs.mkdir(path, mode, cred);
this.mutex.unlock(path);
const env_13 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_13, await this.lock(path), false);
await this.fs.mkdir(path, mode, cred);
}
catch (e_13) {
env_13.error = e_13;
env_13.hasError = true;
}
finally {
__disposeResources(env_13);
}
}
mkdirSync(path, mode, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'mkdir');
const env_14 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_14, this.lockSync(path), false);
return this.fs.mkdirSync(path, mode, cred);
}
return this.fs.mkdirSync(path, mode, cred);
catch (e_14) {
env_14.error = e_14;
env_14.hasError = true;
}
finally {
__disposeResources(env_14);
}
}
async readdir(path, cred) {
await this.mutex.lock(path);
const files = await this.fs.readdir(path, cred);
this.mutex.unlock(path);
return files;
const env_15 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_15, await this.lock(path), false);
return await this.fs.readdir(path, cred);
}
catch (e_15) {
env_15.error = e_15;
env_15.hasError = true;
}
finally {
__disposeResources(env_15);
}
}
readdirSync(path, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'readdir');
const env_16 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_16, this.lockSync(path), false);
return this.fs.readdirSync(path, cred);
}
return this.fs.readdirSync(path, cred);
catch (e_16) {
env_16.error = e_16;
env_16.hasError = true;
}
finally {
__disposeResources(env_16);
}
}
async exists(path, cred) {
await this.mutex.lock(path);
const exists = await this.fs.exists(path, cred);
this.mutex.unlock(path);
return exists;
const env_17 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_17, await this.lock(path), false);
return await this.fs.exists(path, cred);
}
catch (e_17) {
env_17.error = e_17;
env_17.hasError = true;
}
finally {
__disposeResources(env_17);
}
}
existsSync(path, cred) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'exists');
const env_18 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_18, this.lockSync(path), false);
return this.fs.existsSync(path, cred);
}
return this.fs.existsSync(path, cred);
catch (e_18) {
env_18.error = e_18;
env_18.hasError = true;
}
finally {
__disposeResources(env_18);
}
}
async link(srcpath, dstpath, cred) {
await this.mutex.lock(srcpath);
await this.fs.link(srcpath, dstpath, cred);
this.mutex.unlock(srcpath);
const env_19 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_19, await this.lock(srcpath), false);
await this.fs.link(srcpath, dstpath, cred);
}
catch (e_19) {
env_19.error = e_19;
env_19.hasError = true;
}
finally {
__disposeResources(env_19);
}
}
linkSync(srcpath, dstpath, cred) {
if (this.mutex.isLocked(srcpath)) {
throw ErrnoError.With('EBUSY', srcpath, 'link');
const env_20 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_20, this.lockSync(srcpath), false);
return this.fs.linkSync(srcpath, dstpath, cred);
}
return this.fs.linkSync(srcpath, dstpath, cred);
catch (e_20) {
env_20.error = e_20;
env_20.hasError = true;
}
finally {
__disposeResources(env_20);
}
}
async sync(path, data, stats) {
await this.mutex.lock(path);
await this.fs.sync(path, data, stats);
this.mutex.unlock(path);
const env_21 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_21, await this.lock(path), false);
await this.fs.sync(path, data, stats);
}
catch (e_21) {
env_21.error = e_21;
env_21.hasError = true;
}
finally {
__disposeResources(env_21);
}
}
syncSync(path, data, stats) {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'sync');
const env_22 = { stack: [], error: void 0, hasError: false };
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_22, this.lockSync(path), false);
return this.fs.syncSync(path, data, stats);
}
return this.fs.syncSync(path, data, stats);
catch (e_22) {
env_22.error = e_22;
env_22.hasError = true;
}
finally {
__disposeResources(env_22);
}
}
}
export const Locked = {
name: 'Locked',
options: {
fs: {
type: 'object',
required: true,
description: '',
validator(fs) {
if (!(fs instanceof FileSystem)) {
throw new ErrnoError(Errno.EINVAL, 'fs passed to LockedFS must be a FileSystem');
}
},
},
},
isAvailable() {
return true;
},
create({ fs }) {
return new LockedFS(fs);
},
};

5

dist/backends/overlay.js

@@ -59,2 +59,5 @@ import { FileSystem } from '../filesystem.js';

await this.createParentDirectories(path, cred);
if (!(await this._writable.exists(path, cred))) {
await this._writable.createFile(path, 'w', 0o644, cred);
}
await this._writable.sync(path, data, stats);

@@ -127,3 +130,3 @@ }

try {
return this._writable.stat(path, cred);
return await this._writable.stat(path, cred);
}

@@ -130,0 +133,0 @@ catch (e) {

import type { Ino } from '../../inode.js';
import '../../symbol-dispose.js';
/**

@@ -3,0 +4,0 @@ * Represents a key-value store.

import { ErrnoError } from '../../error.js';
import '../../symbol-dispose.js';
/**

@@ -3,0 +4,0 @@ * A transaction for a store.

@@ -21,2 +21,3 @@ /// <reference types="node" resolution-mode="require"/>

export * as constants from './constants.js';
import '../symbol-dispose.js';
export declare class FileHandle implements promises.FileHandle {

@@ -23,0 +24,0 @@ /**

@@ -0,1 +1,46 @@

var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { Buffer } from 'buffer';

@@ -12,2 +57,3 @@ import { Errno, ErrnoError } from '../error.js';

export * as constants from './constants.js';
import '../symbol-dispose.js';
export class FileHandle {

@@ -357,8 +403,15 @@ constructor(fdOrFile) {

export async function truncate(path, len = 0) {
const handle = await open(path, 'r+');
const env_1 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_1, await open(path, 'r+'), true);
await handle.truncate(len);
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
await handle.close();
const result_1 = __disposeResources(env_1);
if (result_1)
await result_1;
}

@@ -430,9 +483,16 @@ }

export async function readFile(path, _options) {
const options = normalizeOptions(_options, null, 'r', 0o644);
const handle = typeof path == 'object' && 'fd' in path ? path : await open(path, options.flag, options.mode);
const env_2 = { stack: [], error: void 0, hasError: false };
try {
const options = normalizeOptions(_options, null, 'r', 0o644);
const handle = __addDisposableResource(env_2, typeof path == 'object' && 'fd' in path ? path : await open(path, options.flag, options.mode), true);
return await handle.readFile(options);
}
catch (e_2) {
env_2.error = e_2;
env_2.hasError = true;
}
finally {
await handle.close();
const result_2 = __disposeResources(env_2);
if (result_2)
await result_2;
}

@@ -453,5 +513,6 @@ }

export async function writeFile(path, data, _options) {
const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
const handle = path instanceof FileHandle ? path : await open(path.toString(), options.flag, options.mode);
const env_3 = { stack: [], error: void 0, hasError: false };
try {
const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
const handle = __addDisposableResource(env_3, path instanceof FileHandle ? path : await open(path.toString(), options.flag, options.mode), true);
const _data = typeof data == 'string' ? data : data;

@@ -463,4 +524,10 @@ if (typeof _data != 'string' && !(_data instanceof Uint8Array)) {

}
catch (e_3) {
env_3.error = e_3;
env_3.hasError = true;
}
finally {
await handle.close();
const result_3 = __disposeResources(env_3);
if (result_3)
await result_3;
}

@@ -480,17 +547,24 @@ }

export async function appendFile(path, data, _options) {
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
const flag = parseFlag(options.flag);
if (!isAppendable(flag)) {
throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
}
if (typeof data != 'string' && !options.encoding) {
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
const handle = typeof path == 'object' && 'fd' in path ? path : await open(path, options.flag, options.mode);
const env_4 = { stack: [], error: void 0, hasError: false };
try {
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
const flag = parseFlag(options.flag);
if (!isAppendable(flag)) {
throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
}
if (typeof data != 'string' && !options.encoding) {
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
const handle = __addDisposableResource(env_4, typeof path == 'object' && 'fd' in path ? path : await open(path, options.flag, options.mode), true);
await handle.appendFile(encodedData, options);
}
catch (e_4) {
env_4.error = e_4;
env_4.hasError = true;
}
finally {
await handle.close();
const result_4 = __disposeResources(env_4);
if (result_4)
await result_4;
}

@@ -607,4 +681,5 @@ }

export async function readlink(path, options) {
const handle = await _open(normalizePath(path), 'r', 0o644, false);
const env_5 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_5, await _open(normalizePath(path), 'r', 0o644, false), true);
const value = await handle.readFile();

@@ -614,4 +689,10 @@ const encoding = typeof options == 'object' ? options?.encoding : options;

}
catch (e_5) {
env_5.error = e_5;
env_5.hasError = true;
}
finally {
await handle.close();
const result_5 = __disposeResources(env_5);
if (result_5)
await result_5;
}

@@ -628,8 +709,15 @@ }

export async function chown(path, uid, gid) {
const handle = await open(path, 'r+');
const env_6 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_6, await open(path, 'r+'), true);
await handle.chown(uid, gid);
}
catch (e_6) {
env_6.error = e_6;
env_6.hasError = true;
}
finally {
await handle.close();
const result_6 = __disposeResources(env_6);
if (result_6)
await result_6;
}

@@ -645,8 +733,15 @@ }

export async function lchown(path, uid, gid) {
const handle = await _open(path, 'r+', 0o644, false);
const env_7 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_7, await _open(path, 'r+', 0o644, false), true);
await handle.chown(uid, gid);
}
catch (e_7) {
env_7.error = e_7;
env_7.hasError = true;
}
finally {
await handle.close();
const result_7 = __disposeResources(env_7);
if (result_7)
await result_7;
}

@@ -661,8 +756,15 @@ }

export async function chmod(path, mode) {
const handle = await open(path, 'r+');
const env_8 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_8, await open(path, 'r+'), true);
await handle.chmod(mode);
}
catch (e_8) {
env_8.error = e_8;
env_8.hasError = true;
}
finally {
await handle.close();
const result_8 = __disposeResources(env_8);
if (result_8)
await result_8;
}

@@ -677,8 +779,15 @@ }

export async function lchmod(path, mode) {
const handle = await _open(path, 'r+', 0o644, false);
const env_9 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_9, await _open(path, 'r+', 0o644, false), true);
await handle.chmod(mode);
}
catch (e_9) {
env_9.error = e_9;
env_9.hasError = true;
}
finally {
await handle.close();
const result_9 = __disposeResources(env_9);
if (result_9)
await result_9;
}

@@ -694,8 +803,15 @@ }

export async function utimes(path, atime, mtime) {
const handle = await open(path, 'r+');
const env_10 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_10, await open(path, 'r+'), true);
await handle.utimes(atime, mtime);
}
catch (e_10) {
env_10.error = e_10;
env_10.hasError = true;
}
finally {
await handle.close();
const result_10 = __disposeResources(env_10);
if (result_10)
await result_10;
}

@@ -711,8 +827,15 @@ }

export async function lutimes(path, atime, mtime) {
const handle = await _open(path, 'r+', 0o644, false);
const env_11 = { stack: [], error: void 0, hasError: false };
try {
const handle = __addDisposableResource(env_11, await _open(path, 'r+', 0o644, false), true);
await handle.utimes(new Date(atime), new Date(mtime));
}
catch (e_11) {
env_11.error = e_11;
env_11.hasError = true;
}
finally {
await handle.close();
const result_11 = __disposeResources(env_11);
if (result_11)
await result_11;
}

@@ -719,0 +842,0 @@ }

@@ -0,1 +1,46 @@

var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { Buffer } from 'buffer';

@@ -81,8 +126,17 @@ import { Errno, ErrnoError } from '../error.js';

export function truncateSync(path, len = 0) {
const fd = openSync(path, 'r+');
const env_1 = { stack: [], error: void 0, hasError: false };
try {
ftruncateSync(fd, len);
const file = __addDisposableResource(env_1, _openSync(path, 'r+'), false);
len || (len = 0);
if (len < 0) {
throw new ErrnoError(Errno.EINVAL);
}
file.truncateSync(len);
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
closeSync(fd);
__disposeResources(env_1);
}

@@ -165,5 +219,6 @@ }

function _readFileSync(fname, flag, resolveSymlinks) {
// Get file.
const file = _openSync(fname, flag, 0o644, resolveSymlinks);
const env_2 = { stack: [], error: void 0, hasError: false };
try {
// Get file.
const file = __addDisposableResource(env_2, _openSync(fname, flag, 0o644, resolveSymlinks), false);
const stat = file.statSync();

@@ -176,4 +231,8 @@ // Allocate buffer.

}
catch (e_2) {
env_2.error = e_2;
env_2.hasError = true;
}
finally {
file.closeSync();
__disposeResources(env_2);
}

@@ -192,20 +251,25 @@ }

export function writeFileSync(path, data, _options = {}) {
const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
const flag = parseFlag(options.flag);
if (!isWriteable(flag)) {
throw new ErrnoError(Errno.EINVAL, 'Flag passed to writeFile must allow for writing.');
}
if (typeof data != 'string' && !options.encoding) {
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
if (!encodedData) {
throw new ErrnoError(Errno.EINVAL, 'Data not specified');
}
const file = _openSync(typeof path == 'number' ? fd2file(path).path : path.toString(), flag, options.mode, true);
const env_3 = { stack: [], error: void 0, hasError: false };
try {
const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
const flag = parseFlag(options.flag);
if (!isWriteable(flag)) {
throw new ErrnoError(Errno.EINVAL, 'Flag passed to writeFile must allow for writing.');
}
if (typeof data != 'string' && !options.encoding) {
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
if (!encodedData) {
throw new ErrnoError(Errno.EINVAL, 'Data not specified');
}
const file = __addDisposableResource(env_3, _openSync(typeof path == 'number' ? fd2file(path).path : path.toString(), flag, options.mode, true), false);
file.writeSync(encodedData, 0, encodedData.byteLength, 0);
}
catch (e_3) {
env_3.error = e_3;
env_3.hasError = true;
}
finally {
file.closeSync();
__disposeResources(env_3);
}

@@ -226,17 +290,22 @@ }

export function appendFileSync(filename, data, _options = {}) {
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
const flag = parseFlag(options.flag);
if (!isAppendable(flag)) {
throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
}
if (typeof data != 'string' && !options.encoding) {
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
const file = _openSync(typeof filename == 'number' ? fd2file(filename).path : filename.toString(), flag, options.mode, true);
const env_4 = { stack: [], error: void 0, hasError: false };
try {
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
const flag = parseFlag(options.flag);
if (!isAppendable(flag)) {
throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
}
if (typeof data != 'string' && !options.encoding) {
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
const file = __addDisposableResource(env_4, _openSync(typeof filename == 'number' ? fd2file(filename).path : filename.toString(), flag, options.mode, true), false);
file.writeSync(encodedData, 0, encodedData.byteLength);
}
catch (e_4) {
env_4.error = e_4;
env_4.hasError = true;
}
finally {
file.closeSync();
__disposeResources(env_4);
}

@@ -243,0 +312,0 @@ }

@@ -6,2 +6,3 @@ /// <reference types="node" resolution-mode="require"/>

import { Stats, type FileType } from './stats.js';
import './symbol-dispose.js';
declare global {

@@ -8,0 +9,0 @@ interface ArrayBuffer {

@@ -5,2 +5,3 @@ import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT } from './emulation/constants.js';

import { Stats } from './stats.js';
import './symbol-dispose.js';
const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];

@@ -7,0 +8,0 @@ export function parseFlag(flag) {

@@ -0,1 +1,46 @@

var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { rootCred } from './cred.js';

@@ -223,5 +268,6 @@ import { join } from './emulation/path.js';

else {
const asyncFile = await this.openFile(path, parseFlag('r'), rootCred);
const syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred());
const env_1 = { stack: [], error: void 0, hasError: false };
try {
const asyncFile = __addDisposableResource(env_1, await this.openFile(path, parseFlag('r'), rootCred), true);
const syncFile = __addDisposableResource(env_1, this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred()), false);
const buffer = new Uint8Array(stats.size);

@@ -231,5 +277,10 @@ await asyncFile.read(buffer);

}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
await asyncFile.close();
syncFile.closeSync();
const result_1 = __disposeResources(env_1);
if (result_1)
await result_1;
}

@@ -236,0 +287,0 @@ }

@@ -17,3 +17,2 @@ export * from './error.js';

export * from './inode.js';
export * from './mutex.js';
export * from './stats.js';

@@ -20,0 +19,0 @@ export * from './utils.js';

@@ -17,3 +17,2 @@ export * from './error.js';

export * from './inode.js';
export * from './mutex.js';
export * from './stats.js';

@@ -20,0 +19,0 @@ export * from './utils.js';

{
"name": "@zenfs/core",
"version": "0.13.0",
"version": "0.14.0",
"description": "A filesystem, anywhere",

@@ -37,3 +37,3 @@ "main": "dist/index.js",

"engines": {
"node": ">= 18"
"node": ">= 22"
},

@@ -73,5 +73,5 @@ "exports": {

"eslint": "^8.36.0",
"jest": "^29.5.0",
"jest": "^29.7.0",
"prettier": "^3.2.5",
"ts-jest": "^29.1.0",
"ts-jest": "^29.1.5",
"typedoc": "^0.25.13",

@@ -78,0 +78,0 @@ "typedoc-plugin-remove-references": "^0.0.6",

@@ -81,5 +81,5 @@ #!/usr/bin/env node

const stats = statSync(path);
entries.set('/' + relative(resolvedRoot, path), stats);
if (stats.isFile()) {
entries.set('/' + relative(resolvedRoot, path), stats);
if (options.verbose) {

@@ -94,2 +94,3 @@ console.log(`${color('green', 'file')} ${path}`);

}
entries.set('/' + relative(resolvedRoot, path), stats);
if (options.verbose) {

@@ -96,0 +97,0 @@ console.log(`${color('bright_green', ' dir')} ${path}`);

@@ -1,8 +0,13 @@

import { ErrnoError } from '../error.js';
import type { Cred } from '../cred.js';
import { Errno, ErrnoError } from '../error.js';
import type { File } from '../file.js';
import type { FileSystem, FileSystemMetadata } from '../filesystem.js';
import { Mutex } from '../mutex.js';
import type { FileSystemMetadata } from '../filesystem.js';
import { FileSystem } from '../filesystem.js';
import type { Stats } from '../stats.js';
import type { Backend } from './backend.js';
export interface MutexLock extends PromiseWithResolvers<void> {
[Symbol.dispose](): void;
}
/**

@@ -19,6 +24,77 @@ * This class serializes access to an underlying async filesystem.

export class LockedFS<FS extends FileSystem> implements FileSystem {
private mutex: Mutex = new Mutex();
constructor(public readonly fs: FS) {}
/**
* The current locks
*/
private locks: Map<string, MutexLock> = new Map();
protected addLock(path: string): MutexLock {
const lock: MutexLock = {
...Promise.withResolvers(),
[Symbol.dispose]: () => {
this.unlock(path);
},
};
this.locks.set(path, lock);
return lock;
}
/**
* Locks `path` asynchronously.
* If the path is currently locked, waits for it to be unlocked.
* @internal
*/
public async lock(path: string): Promise<MutexLock> {
if (this.locks.has(path)) {
// Non-null assertion: we already checked locks has path
await this.locks.get(path)!.promise;
}
return this.addLock(path);
}
/**
* Locks `path` asynchronously.
* If the path is currently locked, an error will be thrown
* @internal
*/
public lockSync(path: string): MutexLock {
if (this.locks.has(path)) {
// Non-null assertion: we already checked locks has path
throw ErrnoError.With('EBUSY', path, 'lockSync');
}
return this.addLock(path);
}
/**
* Unlocks a path
* @param path The path to lock
* @param noThrow If true, an error will not be thrown if the path is already unlocked
* @returns Whether the path was unlocked
* @internal
*/
public unlock(path: string, noThrow: boolean = false): boolean {
if (!this.locks.has(path)) {
if (noThrow) {
return false;
}
throw new ErrnoError(Errno.EPERM, 'Can not unlock an already unlocked path', path);
}
// Non-null assertion: we already checked locks has path
this.locks.get(path)!.resolve();
this.locks.delete(path);
return true;
}
/**
* Whether `path` is locked
* @internal
*/
public isLocked(path: string): boolean {
return this.locks.has(path);
}
public async ready(): Promise<void> {

@@ -36,11 +112,10 @@ await this.fs.ready();

public async rename(oldPath: string, newPath: string, cred: Cred): Promise<void> {
await this.mutex.lock(oldPath);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(oldPath);
await this.fs.rename(oldPath, newPath, cred);
this.mutex.unlock(oldPath);
}
public renameSync(oldPath: string, newPath: string, cred: Cred): void {
if (this.mutex.isLocked(oldPath)) {
throw ErrnoError.With('EBUSY', oldPath, 'rename');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(oldPath);
return this.fs.renameSync(oldPath, newPath, cred);

@@ -50,12 +125,10 @@ }

public async stat(path: string, cred: Cred): Promise<Stats> {
await this.mutex.lock(path);
const stats = await this.fs.stat(path, cred);
this.mutex.unlock(path);
return stats;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
return await this.fs.stat(path, cred);
}
public statSync(path: string, cred: Cred): Stats {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'stat');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.statSync(path, cred);

@@ -65,12 +138,10 @@ }

public async openFile(path: string, flag: string, cred: Cred): Promise<File> {
await this.mutex.lock(path);
const fd = await this.fs.openFile(path, flag, cred);
this.mutex.unlock(path);
return fd;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
return await this.fs.openFile(path, flag, cred);
}
public openFileSync(path: string, flag: string, cred: Cred): File {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'openFile');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.openFileSync(path, flag, cred);

@@ -80,12 +151,10 @@ }

public async createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File> {
await this.mutex.lock(path);
const fd = await this.fs.createFile(path, flag, mode, cred);
this.mutex.unlock(path);
return fd;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
return await this.fs.createFile(path, flag, mode, cred);
}
public createFileSync(path: string, flag: string, mode: number, cred: Cred): File {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'createFile');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.createFileSync(path, flag, mode, cred);

@@ -95,11 +164,10 @@ }

public async unlink(path: string, cred: Cred): Promise<void> {
await this.mutex.lock(path);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
await this.fs.unlink(path, cred);
this.mutex.unlock(path);
}
public unlinkSync(path: string, cred: Cred): void {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'unlink');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.unlinkSync(path, cred);

@@ -109,11 +177,10 @@ }

public async rmdir(path: string, cred: Cred): Promise<void> {
await this.mutex.lock(path);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
await this.fs.rmdir(path, cred);
this.mutex.unlock(path);
}
public rmdirSync(path: string, cred: Cred): void {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'rmdir');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.rmdirSync(path, cred);

@@ -123,11 +190,10 @@ }

public async mkdir(path: string, mode: number, cred: Cred): Promise<void> {
await this.mutex.lock(path);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
await this.fs.mkdir(path, mode, cred);
this.mutex.unlock(path);
}
public mkdirSync(path: string, mode: number, cred: Cred): void {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'mkdir');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.mkdirSync(path, mode, cred);

@@ -137,12 +203,10 @@ }

public async readdir(path: string, cred: Cred): Promise<string[]> {
await this.mutex.lock(path);
const files = await this.fs.readdir(path, cred);
this.mutex.unlock(path);
return files;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
return await this.fs.readdir(path, cred);
}
public readdirSync(path: string, cred: Cred): string[] {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'readdir');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.readdirSync(path, cred);

@@ -152,12 +216,10 @@ }

public async exists(path: string, cred: Cred): Promise<boolean> {
await this.mutex.lock(path);
const exists = await this.fs.exists(path, cred);
this.mutex.unlock(path);
return exists;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
return await this.fs.exists(path, cred);
}
public existsSync(path: string, cred: Cred): boolean {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'exists');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.existsSync(path, cred);

@@ -167,11 +229,10 @@ }

public async link(srcpath: string, dstpath: string, cred: Cred): Promise<void> {
await this.mutex.lock(srcpath);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(srcpath);
await this.fs.link(srcpath, dstpath, cred);
this.mutex.unlock(srcpath);
}
public linkSync(srcpath: string, dstpath: string, cred: Cred): void {
if (this.mutex.isLocked(srcpath)) {
throw ErrnoError.With('EBUSY', srcpath, 'link');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(srcpath);
return this.fs.linkSync(srcpath, dstpath, cred);

@@ -181,13 +242,34 @@ }

public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
await this.mutex.lock(path);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.lock(path);
await this.fs.sync(path, data, stats);
this.mutex.unlock(path);
}
public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
if (this.mutex.isLocked(path)) {
throw ErrnoError.With('EBUSY', path, 'sync');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = this.lockSync(path);
return this.fs.syncSync(path, data, stats);
}
}
export const Locked = {
name: 'Locked',
options: {
fs: {
type: 'object',
required: true,
description: '',
validator(fs) {
if (!(fs instanceof FileSystem)) {
throw new ErrnoError(Errno.EINVAL, 'fs passed to LockedFS must be a FileSystem');
}
},
},
},
isAvailable() {
return true;
},
create({ fs }) {
return new LockedFS(fs);
},
} satisfies Backend<LockedFS<FileSystem>, { fs: FileSystem }>;

@@ -89,2 +89,5 @@ import type { FileSystemMetadata } from '../filesystem.js';

await this.createParentDirectories(path, cred);
if (!(await this._writable.exists(path, cred))) {
await this._writable.createFile(path, 'w', 0o644, cred);
}
await this._writable.sync(path, data, stats);

@@ -164,3 +167,3 @@ }

try {
return this._writable.stat(path, cred);
return await this._writable.stat(path, cred);
} catch (e) {

@@ -167,0 +170,0 @@ if (this._deletedFiles.has(path)) {

import { ErrnoError } from '../../error.js';
import type { Ino } from '../../inode.js';
import '../../symbol-dispose.js';

@@ -4,0 +5,0 @@ /**

@@ -21,2 +21,3 @@ import { Buffer } from 'buffer';

export * as constants from './constants.js';
import '../symbol-dispose.js';

@@ -460,8 +461,4 @@ export class FileHandle implements promises.FileHandle {

export async function truncate(path: fs.PathLike, len: number = 0): Promise<void> {
const handle = await open(path, 'r+');
try {
await handle.truncate(len);
} finally {
await handle.close();
}
await using handle = await open(path, 'r+');
await handle.truncate(len);
}

@@ -559,9 +556,4 @@ truncate satisfies typeof promises.truncate;

const options = normalizeOptions(_options, null, 'r', 0o644);
const handle: FileHandle | promises.FileHandle = typeof path == 'object' && 'fd' in path ? path : await open(path as string, options.flag, options.mode);
try {
return await handle.readFile(options);
} finally {
await handle.close();
}
await using handle: FileHandle | promises.FileHandle = typeof path == 'object' && 'fd' in path ? path : await open(path as string, options.flag, options.mode);
return await handle.readFile(options);
}

@@ -587,12 +579,9 @@ readFile satisfies typeof promises.readFile;

const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
const handle = path instanceof FileHandle ? path : await open(path.toString(), options.flag, options.mode);
try {
const _data = typeof data == 'string' ? data : data;
if (typeof _data != 'string' && !(_data instanceof Uint8Array)) {
throw new ErrnoError(Errno.EINVAL, 'Iterables and streams not supported', handle.file.path, 'writeFile');
}
await handle.writeFile(_data, options);
} finally {
await handle.close();
await using handle = path instanceof FileHandle ? path : await open(path.toString(), options.flag, options.mode);
const _data = typeof data == 'string' ? data : data;
if (typeof _data != 'string' && !(_data instanceof Uint8Array)) {
throw new ErrnoError(Errno.EINVAL, 'Iterables and streams not supported', handle.file.path, 'writeFile');
}
await handle.writeFile(_data, options);
}

@@ -625,9 +614,5 @@ writeFile satisfies typeof promises.writeFile;

const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
const handle: FileHandle | promises.FileHandle = typeof path == 'object' && 'fd' in path ? path : await open(path as string, options.flag, options.mode);
await using handle: FileHandle | promises.FileHandle = typeof path == 'object' && 'fd' in path ? path : await open(path as string, options.flag, options.mode);
try {
await handle.appendFile(encodedData, options);
} finally {
await handle.close();
}
await handle.appendFile(encodedData, options);
}

@@ -783,10 +768,6 @@ appendFile satisfies typeof promises.appendFile;

export async function readlink(path: fs.PathLike, options?: fs.BufferEncodingOption | fs.EncodingOption | string | null): Promise<string | Buffer> {
const handle = await _open(normalizePath(path), 'r', 0o644, false);
try {
const value = await handle.readFile();
const encoding = typeof options == 'object' ? options?.encoding : options;
return encoding == 'buffer' ? value : value.toString(encoding! as BufferEncoding);
} finally {
await handle.close();
}
await using handle = await _open(normalizePath(path), 'r', 0o644, false);
const value = await handle.readFile();
const encoding = typeof options == 'object' ? options?.encoding : options;
return encoding == 'buffer' ? value : value.toString(encoding! as BufferEncoding);
}

@@ -804,8 +785,4 @@ readlink satisfies typeof promises.readlink;

export async function chown(path: fs.PathLike, uid: number, gid: number): Promise<void> {
const handle = await open(path, 'r+');
try {
await handle.chown(uid, gid);
} finally {
await handle.close();
}
await using handle = await open(path, 'r+');
await handle.chown(uid, gid);
}

@@ -821,8 +798,4 @@ chown satisfies typeof promises.chown;

export async function lchown(path: fs.PathLike, uid: number, gid: number): Promise<void> {
const handle: FileHandle = await _open(path, 'r+', 0o644, false);
try {
await handle.chown(uid, gid);
} finally {
await handle.close();
}
await using handle: FileHandle = await _open(path, 'r+', 0o644, false);
await handle.chown(uid, gid);
}

@@ -837,8 +810,4 @@ lchown satisfies typeof promises.lchown;

export async function chmod(path: fs.PathLike, mode: fs.Mode): Promise<void> {
const handle = await open(path, 'r+');
try {
await handle.chmod(mode);
} finally {
await handle.close();
}
await using handle = await open(path, 'r+');
await handle.chmod(mode);
}

@@ -853,8 +822,4 @@ chmod satisfies typeof promises.chmod;

export async function lchmod(path: fs.PathLike, mode: fs.Mode): Promise<void> {
const handle: FileHandle = await _open(path, 'r+', 0o644, false);
try {
await handle.chmod(mode);
} finally {
await handle.close();
}
await using handle: FileHandle = await _open(path, 'r+', 0o644, false);
await handle.chmod(mode);
}

@@ -870,8 +835,4 @@ lchmod satisfies typeof promises.lchmod;

export async function utimes(path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date): Promise<void> {
const handle = await open(path, 'r+');
try {
await handle.utimes(atime, mtime);
} finally {
await handle.close();
}
await using handle = await open(path, 'r+');
await handle.utimes(atime, mtime);
}

@@ -887,8 +848,4 @@ utimes satisfies typeof promises.utimes;

export async function lutimes(path: fs.PathLike, atime: fs.TimeLike, mtime: fs.TimeLike): Promise<void> {
const handle: FileHandle = await _open(path, 'r+', 0o644, false);
try {
await handle.utimes(new Date(atime), new Date(mtime));
} finally {
await handle.close();
}
await using handle: FileHandle = await _open(path, 'r+', 0o644, false);
await handle.utimes(new Date(atime), new Date(mtime));
}

@@ -895,0 +852,0 @@ lutimes satisfies typeof promises.lutimes;

@@ -102,8 +102,8 @@ import { Buffer } from 'buffer';

export function truncateSync(path: fs.PathLike, len: number | null = 0): void {
const fd = openSync(path, 'r+');
try {
ftruncateSync(fd, len);
} finally {
closeSync(fd);
using file = _openSync(path, 'r+');
len ||= 0;
if (len < 0) {
throw new ErrnoError(Errno.EINVAL);
}
file.truncateSync(len);
}

@@ -198,13 +198,9 @@ truncateSync satisfies typeof fs.truncateSync;

// Get file.
const file = _openSync(fname, flag, 0o644, resolveSymlinks);
try {
const stat = file.statSync();
// Allocate buffer.
const data = new Uint8Array(stat.size);
file.readSync(data, 0, stat.size, 0);
file.closeSync();
return data;
} finally {
file.closeSync();
}
using file = _openSync(fname, flag, 0o644, resolveSymlinks);
const stat = file.statSync();
// Allocate buffer.
const data = new Uint8Array(stat.size);
file.readSync(data, 0, stat.size, 0);
file.closeSync();
return data;
}

@@ -260,8 +256,4 @@

}
const file = _openSync(typeof path == 'number' ? fd2file(path).path! : path.toString(), flag, options.mode, true);
try {
file.writeSync(encodedData, 0, encodedData.byteLength, 0);
} finally {
file.closeSync();
}
using file = _openSync(typeof path == 'number' ? fd2file(path).path! : path.toString(), flag, options.mode, true);
file.writeSync(encodedData, 0, encodedData.byteLength, 0);
}

@@ -291,8 +283,4 @@ writeFileSync satisfies typeof fs.writeFileSync;

const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
const file = _openSync(typeof filename == 'number' ? fd2file(filename).path! : filename.toString(), flag, options.mode, true);
try {
file.writeSync(encodedData, 0, encodedData.byteLength);
} finally {
file.closeSync();
}
using file = _openSync(typeof filename == 'number' ? fd2file(filename).path! : filename.toString(), flag, options.mode, true);
file.writeSync(encodedData, 0, encodedData.byteLength);
}

@@ -299,0 +287,0 @@ appendFileSync satisfies typeof fs.appendFileSync;

@@ -7,2 +7,3 @@ import type { FileReadResult } from 'node:fs/promises';

import { Stats, type FileType } from './stats.js';
import './symbol-dispose.js';

@@ -9,0 +10,0 @@ /*

@@ -466,12 +466,7 @@ import type { ExtractProperties } from 'utilium';

} else {
const asyncFile = await this.openFile(path, parseFlag('r'), rootCred);
const syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred());
try {
const buffer = new Uint8Array(stats.size);
await asyncFile.read(buffer);
syncFile.writeSync(buffer, 0, stats.size);
} finally {
await asyncFile.close();
syncFile.closeSync();
}
await using asyncFile = await this.openFile(path, parseFlag('r'), rootCred);
using syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred());
const buffer = new Uint8Array(stats.size);
await asyncFile.read(buffer);
syncFile.writeSync(buffer, 0, stats.size);
}

@@ -478,0 +473,0 @@ }

@@ -17,3 +17,2 @@ export * from './error.js';

export * from './inode.js';
export * from './mutex.js';
export * from './stats.js';

@@ -20,0 +19,0 @@ export * from './utils.js';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc