Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@zenfs/core

Package Overview
Dependencies
Maintainers
0
Versions
156
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 1.1.6 to 1.2.0

dist/emulation/cache.d.ts

3

dist/backends/file_index.js

@@ -154,5 +154,2 @@ /* Note: this file is named file_index.ts because Typescript has special behavior regarding index.ts which can't be disabled. */

}
if (!stats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'readdir');
}
const content = JSON.parse(decodeUTF8(stats.fileData));

@@ -159,0 +156,0 @@ if (!Array.isArray(content)) {

@@ -317,6 +317,2 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {

this.checkInitialized();
const dirStats = await this.stat(path);
if (!dirStats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'readdir');
}
// Readdir in both, check delete log on RO file system's listing, merge, return.

@@ -345,6 +341,2 @@ const contents = [];

this.checkInitialized();
const dirStats = this.statSync(path);
if (!dirStats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'readdir');
}
// Readdir in both, check delete log on RO file system's listing, merge, return.

@@ -351,0 +343,0 @@ let contents = [];

@@ -583,12 +583,8 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {

async getDirListing(tx, inode, path) {
if (!inode.toStats().isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'getDirListing');
}
const data = await tx.get(inode.ino);
/*
Occurs when data is undefined,or corresponds to something other than a directory listing.
The latter should never occur unless the file system is corrupted.
*/
if (!data) {
/*
Occurs when data is undefined, or corresponds to something other
than a directory listing. The latter should never occur unless
the file system is corrupted.
*/
throw ErrnoError.With('ENOENT', path, 'getDirListing');

@@ -602,5 +598,2 @@ }

getDirListingSync(tx, inode, p) {
if (!inode.toStats().isDirectory()) {
throw ErrnoError.With('ENOTDIR', p, 'getDirListing');
}
const data = tx.getSync(inode.ino);

@@ -763,5 +756,2 @@ if (!data) {

}
if (isDir && !fileNode.toStats().isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'remove');
}
await tx.set(parentNode.ino, encodeDirListing(listing));

@@ -807,5 +797,2 @@ if (--fileNode.nlink < 1) {

}
if (isDir && !fileNode.toStats().isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'remove');
}
// Update directory listing.

@@ -812,0 +799,0 @@ tx.setSync(parentNode.ino, encodeDirListing(listing));

@@ -41,2 +41,16 @@ import type { Backend, BackendConfiguration, FilesystemOf, SharedConfig } from './backends/backend.js';

addDevices: boolean;
/**
* If true, enables caching stats for certain operations.
* This should reduce the number of stat calls performed.
* @default false
* @experimental
*/
cacheStats: boolean;
/**
* If true, disables *all* permissions checking.
* This can increase performance
* @default false
* @experimental
*/
disableAccessChecks: boolean;
}

@@ -43,0 +57,0 @@ /**

import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js';
import { credentials } from './credentials.js';
import { DeviceFS, fullDevice, nullDevice, randomDevice, zeroDevice } from './devices.js';
import * as cache from './emulation/cache.js';
import * as fs from './emulation/index.js';
import { config } from './emulation/shared.js';
import { Errno, ErrnoError } from './error.js';

@@ -69,2 +71,4 @@ import { FileSystem } from './filesystem.js';

Object.assign(credentials, { uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
cache.setEnabled(configuration.cacheStats ?? false);
config.checkAccess = !configuration.disableAccessChecks;
if (configuration.addDevices) {

@@ -71,0 +75,0 @@ const devfs = new DeviceFS();

@@ -257,11 +257,5 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {

async rmdir(path) {
if (this.devices.has(path)) {
throw ErrnoError.With('ENOTDIR', path, 'rmdir');
}
return super.rmdir(path);
}
rmdirSync(path) {
if (this.devices.has(path)) {
throw ErrnoError.With('ENOTDIR', path, 'rmdir');
}
return super.rmdirSync(path);

@@ -282,5 +276,2 @@ }

async readdir(path) {
if (this.devices.has(path)) {
throw ErrnoError.With('ENOTDIR', path, 'readdir');
}
const entries = await super.readdir(path);

@@ -295,5 +286,2 @@ for (const dev of this.devices.keys()) {

readdirSync(path) {
if (this.devices.has(path)) {
throw ErrnoError.With('ENOTDIR', path, 'readdirSync');
}
const entries = super.readdirSync(path);

@@ -300,0 +288,0 @@ for (const dev of this.devices.keys()) {

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

import { Dir, Dirent } from './dir.js';
import { type InternalOptions, type ReaddirOptions } from './shared.js';
import { ReadStream, WriteStream } from './streams.js';

@@ -252,26 +253,20 @@ export * as constants from './constants.js';

* Asynchronous readdir(3) - read a directory.
*
* Note: The order of entries is not guaranteed
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'`.
*/
export declare function readdir(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & {
export declare function readdir(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & ReaddirOptions & {
withFileTypes?: false;
recursive?: boolean;
}) | BufferEncoding | null): Promise<string[]>;
export declare function readdir(path: fs.PathLike, options: fs.BufferEncodingOption & {
export declare function readdir(path: fs.PathLike, options: fs.BufferEncodingOption & ReaddirOptions & {
withFileTypes?: false;
recursive?: boolean;
}): Promise<Buffer[]>;
export declare function readdir(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & {
export declare function readdir(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & ReaddirOptions & {
withFileTypes?: false;
recursive?: boolean;
}) | BufferEncoding | null): Promise<string[] | Buffer[]>;
export declare function readdir(path: fs.PathLike, options: fs.ObjectEncodingOptions & {
export declare function readdir(path: fs.PathLike, options: fs.ObjectEncodingOptions & ReaddirOptions & {
withFileTypes: true;
recursive?: boolean;
}): Promise<Dirent[]>;
export declare function readdir(path: fs.PathLike, options?: {
withFileTypes?: boolean;
recursive?: boolean;
encoding?: BufferEncoding | 'buffer' | null;
} | BufferEncoding | 'buffer' | null): Promise<string[] | Dirent[] | Buffer[]>;
export declare function readdir(path: fs.PathLike, options?: (ReaddirOptions & (fs.ObjectEncodingOptions | fs.BufferEncodingOption)) | BufferEncoding | null): Promise<string[] | Dirent[] | Buffer[]>;
export declare function link(targetPath: fs.PathLike, linkPath: fs.PathLike): Promise<void>;

@@ -316,3 +311,3 @@ /**

*/
export declare function rm(path: fs.PathLike, options?: fs.RmOptions): Promise<void>;
export declare function rm(path: fs.PathLike, options?: fs.RmOptions & InternalOptions): Promise<void>;
/**

@@ -319,0 +314,0 @@ * Asynchronous `mkdtemp`. Creates a unique temporary directory.

@@ -55,6 +55,7 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {

import { decodeUTF8, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
import * as cache from './cache.js';
import * as constants from './constants.js';
import { Dir, Dirent } from './dir.js';
import { dirname, join, parse } from './path.js';
import { _statfs, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
import { _statfs, config, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
import { ReadStream, WriteStream } from './streams.js';

@@ -221,3 +222,3 @@ import { FSWatcher, emitChange } from './watchers.js';

const stats = await this.file.stat();
if (!stats.hasAccess(constants.R_OK)) {
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', this.file.path, 'stat');

@@ -356,3 +357,3 @@ }

const dst = resolveMount(newPath);
if (!(await stat(dirname(oldPath))).hasAccess(constants.W_OK)) {
if (config.checkAccess && !(await stat(dirname(oldPath))).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', oldPath, 'rename');

@@ -395,3 +396,3 @@ }

const stats = await fs.stat(resolved);
if (!stats.hasAccess(constants.R_OK)) {
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', resolved, 'stat');

@@ -440,3 +441,3 @@ }

try {
if (!(await fs.stat(resolved)).hasAccess(constants.W_OK)) {
if (config.checkAccess && !(cache.getStats(path) || (await fs.stat(resolved))).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', resolved, 'unlink');

@@ -468,3 +469,3 @@ }

const parentStats = await fs.stat(dirname(resolved));
if (!parentStats.hasAccess(constants.W_OK)) {
if (config.checkAccess && !parentStats.hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(path), '_open');

@@ -477,3 +478,3 @@ }

}
if (!stats.hasAccess(flagToMode(flag))) {
if (config.checkAccess && !stats.hasAccess(flagToMode(flag))) {
throw ErrnoError.With('EACCES', path, '_open');

@@ -589,7 +590,10 @@ }

export async function rmdir(path) {
path = normalizePath(path);
path = await realpath(path);
const { fs, path: resolved } = resolveMount(path);
try {
if (!(await fs.stat(resolved)).hasAccess(constants.W_OK)) {
const stats = cache.getStats(path) || (await fs.stat(resolved));
if (!stats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
}
if (config.checkAccess && !stats.hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', resolved, 'rmdir');

@@ -608,3 +612,3 @@ }

const mode = normalizeMode(options?.mode, 0o777);
path = await realpath(normalizePath(path));
path = await realpath(path);
const { fs, path: resolved } = resolveMount(path);

@@ -614,3 +618,3 @@ const errorPaths = { [resolved]: path };

if (!options?.recursive) {
if (!(await fs.stat(dirname(resolved))).hasAccess(constants.W_OK)) {
if (config.checkAccess && !(await fs.stat(dirname(resolved))).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(resolved), 'mkdir');

@@ -628,3 +632,3 @@ }

for (const dir of dirs) {
if (!(await fs.stat(dirname(dir))).hasAccess(constants.W_OK)) {
if (config.checkAccess && !(await fs.stat(dirname(dir))).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(dir), 'mkdir');

@@ -644,10 +648,16 @@ }

options = typeof options === 'object' ? options : { encoding: options };
path = await realpath(normalizePath(path));
path = await realpath(path);
const handleError = (e) => {
throw fixError(e, { [resolved]: path });
};
const { fs, path: resolved } = resolveMount(path);
if (!(await fs.stat(resolved)).hasAccess(constants.R_OK)) {
const stats = cache.getStats(path) || (await fs.stat(resolved).catch(handleError));
cache.setStats(path, stats);
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', path, 'readdir');
}
const entries = await fs.readdir(resolved).catch((e) => {
throw fixError(e, { [resolved]: path });
});
if (!stats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', path, 'readdir');
}
const entries = await fs.readdir(resolved).catch(handleError);
for (const point of mounts.keys()) {

@@ -664,13 +674,12 @@ if (point.startsWith(path)) {

const values = [];
for (const entry of entries) {
let stats;
const addEntry = async (entry) => {
let entryStats;
if (options?.recursive || options?.withFileTypes) {
stats = await fs.stat(join(resolved, entry)).catch((error) => {
throw fixError(error, { [resolved]: path });
});
entryStats = cache.getStats(join(path, entry)) || (await fs.stat(join(resolved, entry)).catch(handleError));
cache.setStats(join(path, entry), entryStats);
}
if (options?.withFileTypes) {
values.push(new Dirent(entry, stats));
values.push(new Dirent(entry, entryStats));
}
else if (options?.encoding === 'buffer') {
else if (options?.encoding == 'buffer') {
values.push(Buffer.from(entry));

@@ -681,6 +690,5 @@ }

}
if (!options?.recursive || !stats?.isDirectory()) {
continue;
}
for (const subEntry of await readdir(join(path, entry), options)) {
if (!options?.recursive || !entryStats?.isDirectory())
return;
for (const subEntry of await readdir(join(path, entry), { ...options, _isIndirect: true })) {
if (subEntry instanceof Dirent) {

@@ -698,2 +706,6 @@ subEntry.path = join(entry, subEntry.path);

}
};
await Promise.all(entries.map(addEntry));
if (!options?._isIndirect) {
cache.clearStats();
}

@@ -705,9 +717,3 @@ return values;

targetPath = normalizePath(targetPath);
if (!(await stat(dirname(targetPath))).hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', dirname(targetPath), 'link');
}
linkPath = normalizePath(linkPath);
if (!(await stat(dirname(linkPath))).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(linkPath), 'link');
}
const { fs, path } = resolveMount(targetPath);

@@ -719,3 +725,9 @@ const link = resolveMount(linkPath);

try {
if (!(await fs.stat(path)).hasAccess(constants.W_OK)) {
if (config.checkAccess && !(await fs.stat(dirname(targetPath))).hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', dirname(path), 'link');
}
if (config.checkAccess && !(await stat(dirname(linkPath))).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(linkPath), 'link');
}
if (config.checkAccess && !(await fs.stat(path)).hasAccess(constants.W_OK | constants.R_OK)) {
throw ErrnoError.With('EACCES', path, 'link');

@@ -927,2 +939,4 @@ }

export async function access(path, mode = constants.F_OK) {
if (!config.checkAccess)
return;
const stats = await stat(path);

@@ -940,22 +954,24 @@ if (!stats.hasAccess(mode)) {

path = normalizePath(path);
const stats = await stat(path).catch((error) => {
if (error.code != 'ENOENT' || !options?.force)
throw error;
});
const stats = cache.getStats(path) ||
(await stat(path).catch((error) => {
if (error.code != 'ENOENT' || !options?.force)
throw error;
}));
if (!stats) {
return;
}
cache.setStats(path, stats);
switch (stats.mode & constants.S_IFMT) {
case constants.S_IFDIR:
if (options?.recursive) {
for (const entry of await readdir(path)) {
await rm(join(path, entry), options);
for (const entry of await readdir(path, { _isIndirect: true })) {
await rm(join(path, entry), { ...options, _isIndirect: true });
}
}
await rmdir(path);
return;
break;
case constants.S_IFREG:
case constants.S_IFLNK:
await unlink(path);
return;
break;
case constants.S_IFBLK:

@@ -966,4 +982,8 @@ case constants.S_IFCHR:

default:
cache.clearStats();
throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
}
if (!options?._isIndirect) {
cache.clearStats();
}
}

@@ -1028,14 +1048,17 @@ rm;

switch (srcStats.mode & constants.S_IFMT) {
case constants.S_IFDIR:
case constants.S_IFDIR: {
if (!opts?.recursive) {
throw new ErrnoError(Errno.EISDIR, source + ' is a directory (not copied)', source, 'cp');
}
await mkdir(destination, { recursive: true }); // Ensure the destination directory exists
for (const dirent of await readdir(source, { withFileTypes: true })) {
const [entries] = await Promise.all([readdir(source, { withFileTypes: true }), mkdir(destination, { recursive: true })] // Ensure the destination directory exists
);
const _cp = async (dirent) => {
if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
continue; // Skip if the filter returns false
return; // Skip if the filter returns false
}
await cp(join(source, dirent.name), join(destination, dirent.name), opts);
}
};
await Promise.all(entries.map(_cp));
break;
}
case constants.S_IFREG:

@@ -1042,0 +1065,0 @@ case constants.S_IFLNK:

@@ -46,1 +46,23 @@ import type { BigIntStatsFs, StatsFs } from 'node:fs';

export declare function _statfs<const T extends boolean>(fs: FileSystem, bigint?: T): T extends true ? BigIntStatsFs : StatsFs;
export declare const config: {
/**
* Whether to perform access checks
*/
checkAccess: boolean;
};
/**
* Options used for caching, among other things.
* @internal *UNSTABLE*
*/
export interface InternalOptions {
/**
* If true, then this readdir was called from another function.
* In this case, don't clear the cache when done.
* @internal *UNSTABLE*
*/
_isIndirect?: boolean;
}
export interface ReaddirOptions extends InternalOptions {
withFileTypes?: boolean;
recursive?: boolean;
}

@@ -118,1 +118,7 @@ // Utilities and shared data

}
export const config = {
/**
* Whether to perform access checks
*/
checkAccess: true,
};

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

import { Dir, Dirent } from './dir.js';
import { type InternalOptions, type ReaddirOptions } from './shared.js';
export declare function renameSync(oldPath: fs.PathLike, newPath: fs.PathLike): void;

@@ -114,25 +115,15 @@ /**

export declare function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): string | undefined;
export declare function readdirSync(path: fs.PathLike, options?: {
recursive?: boolean;
encoding?: BufferEncoding | null;
export declare function readdirSync(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & ReaddirOptions & {
withFileTypes?: false;
} | BufferEncoding | null): string[];
export declare function readdirSync(path: fs.PathLike, options: {
recursive?: boolean;
encoding: 'buffer';
}) | BufferEncoding | null): string[];
export declare function readdirSync(path: fs.PathLike, options: fs.BufferEncodingOption & ReaddirOptions & {
withFileTypes?: false;
} | 'buffer'): Buffer[];
export declare function readdirSync(path: fs.PathLike, options: {
recursive?: boolean;
}): Buffer[];
export declare function readdirSync(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & ReaddirOptions & {
withFileTypes?: false;
}) | BufferEncoding | null): string[] | Buffer[];
export declare function readdirSync(path: fs.PathLike, options: fs.ObjectEncodingOptions & ReaddirOptions & {
withFileTypes: true;
}): Dirent[];
export declare function readdirSync(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & {
withFileTypes?: false;
recursive?: boolean;
}) | BufferEncoding | null): string[] | Buffer[];
export declare function readdirSync(path: fs.PathLike, options?: {
withFileTypes?: boolean;
recursive?: boolean;
encoding?: BufferEncoding | 'buffer' | null;
} | BufferEncoding | 'buffer' | null): string[] | Dirent[] | Buffer[];
export declare function readdirSync(path: fs.PathLike, options?: (ReaddirOptions & (fs.ObjectEncodingOptions | fs.BufferEncodingOption)) | BufferEncoding | null): string[] | Dirent[] | Buffer[];
export declare function linkSync(targetPath: fs.PathLike, linkPath: fs.PathLike): void;

@@ -168,3 +159,3 @@ /**

*/
export declare function rmSync(path: fs.PathLike, options?: fs.RmOptions): void;
export declare function rmSync(path: fs.PathLike, options?: fs.RmOptions & InternalOptions): void;
/**

@@ -171,0 +162,0 @@ * Synchronous `mkdtemp`. Creates a unique temporary directory.

@@ -56,4 +56,5 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {

import { dirname, join, parse } from './path.js';
import { _statfs, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
import { _statfs, config, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
import { emitChange } from './watchers.js';
import * as cache from './cache.js';
export function renameSync(oldPath, newPath) {

@@ -64,3 +65,3 @@ oldPath = normalizePath(oldPath);

const newMount = resolveMount(newPath);
if (!statSync(dirname(oldPath)).hasAccess(constants.W_OK)) {
if (config.checkAccess && !statSync(dirname(oldPath)).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', oldPath, 'rename');

@@ -105,3 +106,3 @@ }

const stats = fs.statSync(resolved);
if (!stats.hasAccess(constants.R_OK)) {
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', resolved, 'stat');

@@ -151,3 +152,3 @@ }

try {
if (!fs.statSync(resolved).hasAccess(constants.W_OK)) {
if (config.checkAccess && !(cache.getStats(path) || fs.statSync(resolved)).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', resolved, 'unlink');

@@ -181,3 +182,3 @@ }

const parentStats = fs.statSync(dirname(resolved));
if (!parentStats.hasAccess(constants.W_OK)) {
if (config.checkAccess && !parentStats.hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(path), '_open');

@@ -190,3 +191,3 @@ }

}
if (!stats.hasAccess(mode) || !stats.hasAccess(flagToMode(flag))) {
if (config.checkAccess && (!stats.hasAccess(mode) || !stats.hasAccess(flagToMode(flag)))) {
throw ErrnoError.With('EACCES', path, '_open');

@@ -401,3 +402,7 @@ }

try {
if (!fs.statSync(resolved).hasAccess(constants.W_OK)) {
const stats = cache.getStats(path) || fs.statSync(resolved);
if (!stats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
}
if (config.checkAccess && !stats.hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', resolved, 'rmdir');

@@ -416,3 +421,3 @@ }

const mode = normalizeMode(options?.mode, 0o777);
path = realpathSync(normalizePath(path));
path = realpathSync(path);
const { fs, path: resolved } = resolveMount(path);

@@ -422,3 +427,3 @@ const errorPaths = { [resolved]: path };

if (!options?.recursive) {
if (!fs.statSync(dirname(resolved)).hasAccess(constants.W_OK)) {
if (config.checkAccess && !fs.statSync(dirname(resolved)).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(resolved), 'mkdir');

@@ -434,3 +439,3 @@ }

for (const dir of dirs) {
if (!fs.statSync(dirname(dir)).hasAccess(constants.W_OK)) {
if (config.checkAccess && !fs.statSync(dirname(dir)).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(dir), 'mkdir');

@@ -454,5 +459,10 @@ }

try {
if (!fs.statSync(resolved).hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', path, 'readdir');
const stats = cache.getStats(path) || fs.statSync(resolved);
cache.setStats(path, stats);
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', resolved, 'readdir');
}
if (!stats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', resolved, 'readdir');
}
entries = fs.readdirSync(resolved);

@@ -477,7 +487,8 @@ }

for (const entry of entries) {
const entryStat = fs.statSync(join(resolved, entry));
const entryStat = cache.getStats(join(path, entry)) || fs.statSync(join(resolved, entry));
cache.setStats(join(path, entry), entryStat);
if (options?.withFileTypes) {
values.push(new Dirent(entry, entryStat));
}
else if (options?.encoding === 'buffer') {
else if (options?.encoding == 'buffer') {
values.push(Buffer.from(entry));

@@ -490,3 +501,3 @@ }

continue;
for (const subEntry of readdirSync(join(path, entry), options)) {
for (const subEntry of readdirSync(join(path, entry), { ...options, _isIndirect: true })) {
if (subEntry instanceof Dirent) {

@@ -504,2 +515,5 @@ subEntry.path = join(entry, subEntry.path);

}
if (!options?._isIndirect) {
cache.clearStats();
}
return values;

@@ -511,7 +525,7 @@ }

targetPath = normalizePath(targetPath);
if (!statSync(dirname(targetPath)).hasAccess(constants.R_OK)) {
if (config.checkAccess && !statSync(dirname(targetPath)).hasAccess(constants.R_OK)) {
throw ErrnoError.With('EACCES', dirname(targetPath), 'link');
}
linkPath = normalizePath(linkPath);
if (!statSync(dirname(linkPath)).hasAccess(constants.W_OK)) {
if (config.checkAccess && !statSync(dirname(linkPath)).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', dirname(linkPath), 'link');

@@ -525,3 +539,3 @@ }

try {
if (!fs.statSync(path).hasAccess(constants.W_OK)) {
if (config.checkAccess && !fs.statSync(path).hasAccess(constants.W_OK)) {
throw ErrnoError.With('EACCES', path, 'link');

@@ -627,2 +641,4 @@ }

export function accessSync(path, mode = 0o600) {
if (!config.checkAccess)
return;
if (!statSync(path).hasAccess(mode)) {

@@ -641,3 +657,3 @@ throw new ErrnoError(Errno.EACCES);

try {
stats = statSync(path);
stats = cache.getStats(path) || statSync(path);
}

@@ -651,15 +667,16 @@ catch (error) {

}
cache.setStats(path, stats);
switch (stats.mode & constants.S_IFMT) {
case constants.S_IFDIR:
if (options?.recursive) {
for (const entry of readdirSync(path)) {
rmSync(join(path, entry), options);
for (const entry of readdirSync(path, { _isIndirect: true })) {
rmSync(join(path, entry), { ...options, _isIndirect: true });
}
}
rmdirSync(path);
return;
break;
case constants.S_IFREG:
case constants.S_IFLNK:
unlinkSync(path);
return;
break;
case constants.S_IFBLK:

@@ -670,4 +687,8 @@ case constants.S_IFCHR:

default:
cache.clearStats();
throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
}
if (!options?._isIndirect) {
cache.clearStats();
}
}

@@ -674,0 +695,0 @@ rmSync;

{
"name": "@zenfs/core",
"version": "1.1.6",
"version": "1.2.0",
"description": "A filesystem, anywhere",

@@ -21,2 +21,3 @@ "funding": {

"files": [
"src",
"dist",

@@ -52,3 +53,4 @@ "tests",

"./eslint": "./eslint.shared.js",
"./tests/*": "./tests/*"
"./tests/*": "./tests/*",
"./src/*": "./src/*"
},

@@ -55,0 +57,0 @@ "scripts": {

#!/usr/bin/env node
import { execSync } from 'node:child_process';
import { existsSync } from 'node:fs';
import { join } from 'node:path';

@@ -11,2 +12,4 @@ import { parseArgs } from 'node:util';

verbose: { type: 'boolean', default: false },
test: { type: 'string' },
forceExit: { short: 'f', type: 'boolean', default: false },
},

@@ -24,2 +27,4 @@ allowPositionals: true,

--verbose Output verbose messages
--test Which test to run
--forceExit Whether to use --test-force-exit
`);

@@ -29,6 +34,14 @@ process.exit();

if (options.verbose) console.debug('Forcing tests to exit (--test-force-exit)');
const testsGlob = join(import.meta.dirname, `../tests/fs/${options.test || '*'}.test.ts`);
for (const setupFile of positionals) {
if (options.verbose) console.debug('Running tests for:', setupFile);
process.env.SETUP = setupFile;
execSync('tsx --test --experimental-test-coverage ' + join(import.meta.dirname, '../tests/fs/*.test.ts'), { stdio: 'inherit' });
if (!existsSync(setupFile)) {
console.log('ERROR: Skipping non-existent file:', setupFile);
continue;
}
execSync(['tsx --test --experimental-test-coverage', options.forceExit ? '--test-force-exit' : '', testsGlob, process.env.CMD].join(' '), { stdio: 'inherit' });
}

@@ -70,5 +70,5 @@ import assert from 'node:assert';

const entries = await fs.promises.readdir(testDir, { recursive: true, withFileTypes: true });
assert.equal(entries[0].path, 'file1.txt');
assert.equal(entries[4].path, 'subdir1/file4.txt');
assert.equal(entries[entries.length - 1].path, 'subdir2/file5.txt');
assert(entries.find(entry => entry.path === 'file1.txt'));
assert(entries.find(entry => entry.path === 'subdir1/file4.txt'));
assert(entries.find(entry => entry.path === 'subdir2/file5.txt'));
});

@@ -75,0 +75,0 @@

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