Skip to content

Commit

Permalink
_open/_openSync correctly handle non-ENOENT errors
Browse files Browse the repository at this point in the history
`_open`/`_openSync` add the original stack trace on the second throw
Fixed `configure` overwritting per-backend `disableAsyncCache`
  • Loading branch information
james-pre committed May 19, 2024
1 parent 79784e0 commit cf8cbca
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export async function configure(config: MountConfiguration<Backend> | Partial<Co
}

if (isBackendConfig(mountConfig)) {
mountConfig.disableAsyncCache = config.disableAsyncCache || false;
mountConfig.disableAsyncCache ??= config.disableAsyncCache || false;
}

config.mounts[point] = await resolveMountConfig(mountConfig);
Expand Down
37 changes: 24 additions & 13 deletions src/emulation/promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,19 +512,30 @@ async function _open(path: fs.PathLike, _flag: fs.OpenMode, _mode: fs.Mode = 0o6
default:
throw new ErrnoError(Errno.EINVAL, 'Invalid file flag');
}
} catch (e) {
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');
} catch (_) {
const original = _ as ErrnoError;
if(original.code != 'ENOENT') {
throw original;
}
try {
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');
}
} catch (_) {
const ex = _ as ErrnoError;
ex.stack += '\n<original>\n';
ex.stack += (original as Error).stack;
throw ex;
}
}
}
Expand Down
39 changes: 25 additions & 14 deletions src/emulation/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,31 @@ function _openSync(_path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | nul
let stats: Stats;
try {
stats = wrap('statSync', resolveSymlinks, path, cred);
} catch (e) {
// File does not exist.
switch (pathNotExistsAction(flag)) {
case ActionType.CREATE:
// Ensure parent exists.
const parentStats: Stats = wrap('statSync', resolveSymlinks, dirname(path), cred);
if (!parentStats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
}
return wrap('createFileSync', resolveSymlinks, path, flag, mode, cred);
case ActionType.THROW:
throw ErrnoError.With('ENOENT', path, '_open');
default:
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
} catch (_) {
const original = _ as ErrnoError;
if(original.code != 'ENOENT') {
throw original;
}
try {
// File does not exist.
switch (pathNotExistsAction(flag)) {
case ActionType.CREATE:
// Ensure parent exists.
const parentStats: Stats = wrap('statSync', resolveSymlinks, dirname(path), cred);
if (!parentStats.isDirectory()) {
throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
}
return wrap('createFileSync', resolveSymlinks, path, flag, mode, cred);
case ActionType.THROW:
throw ErrnoError.With('ENOENT', path, '_open');
default:
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
}
} catch (_) {
const ex = _ as ErrnoError;
ex.stack += '\n<original>\n'
ex.stack += (original as Error).stack;
throw ex;
}
}
if (!stats.hasAccess(mode, cred)) {
Expand Down
6 changes: 5 additions & 1 deletion tests/port/channel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('FS with MessageChannel', () => {
test('configuration', async () => {
tmpfs = await resolveMountConfig({ backend: InMemory, name: 'tmp' });
attachFS(port2, tmpfs);
await configure({ backend: Port, port: port1 });
await configure({ backend: Port, port: port1, disableAsyncCache: true });
});

test('write', async () => {
Expand All @@ -33,4 +33,8 @@ describe('FS with MessageChannel', () => {
test('read', async () => {
expect(await fs.promises.readFile('/test', 'utf8')).toBe(content);
});

test('readFileSync should throw', () => {
expect(() => fs.readFileSync('/test', 'utf8')).toThrow('ENOTSUP');
});
});

0 comments on commit cf8cbca

Please sign in to comment.