Skip to content

Commit

Permalink
Fixed appendFile/writeFile mode behavior
Browse files Browse the repository at this point in the history
Fixed some ENOENT not having paths
Fixed some tests
  • Loading branch information
james-pre committed Mar 6, 2024
1 parent c0800ca commit d503a46
Show file tree
Hide file tree
Showing 11 changed files with 39 additions and 45 deletions.
4 changes: 2 additions & 2 deletions src/backends/SyncStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ export class SyncStoreFileSystem extends SyncFileSystem {
const ino = this._findINode(tx, dirname(parent), basename(parent), visited);
const dir = this.getDirListing(tx, this.getINode(tx, ino, parent + sep + filename), parent);
if (!(filename in dir)) {
throw new ApiError(ErrorCode.ENOENT, resolve(parent, filename));
throw ApiError.ENOENT(resolve(parent, filename));
}

return dir[filename];
Expand All @@ -455,7 +455,7 @@ export class SyncStoreFileSystem extends SyncFileSystem {
// Find the item in the root node.
const dir = this.getDirListing(tx, this.getINode(tx, rootIno, parent), parent);
if (!(filename in dir)) {
throw new ApiError(ErrorCode.ENOENT, resolve(parent, filename));
throw ApiError.ENOENT(resolve(parent, filename));
}
return dir[filename];
}
Expand Down
12 changes: 6 additions & 6 deletions src/emulation/promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ readFile satisfies BufferToUint8Array<typeof Node.promises.readFile>;
*
* The encoding option is ignored if data is a buffer.
*/
async function _writeFile(fname: string, data: Uint8Array, flag: string, resolveSymlinks: boolean): Promise<void> {
const file = await _open(fname, flag, 0o644, resolveSymlinks);
async function _writeFile(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): Promise<void> {
const file = await _open(fname, flag, mode, resolveSymlinks);
try {
await file.write(data, 0, data.length, 0);
} finally {
Expand Down Expand Up @@ -475,16 +475,16 @@ export async function writeFile(filename: PathLike, data: FileContents, _options
throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? encode(data, options.encoding) : data;
await _writeFile(filename, encodedData, options.flag, true);
await _writeFile(filename, encodedData, options.flag, options.mode, true);
}
writeFile satisfies typeof Node.promises.writeFile;

/**
* Asynchronously append data to a file, creating the file if
* it not yet exists.
*/
async function _appendFile(fname: string, data: Uint8Array, flag: string, resolveSymlinks: boolean): Promise<void> {
const file = await _open(fname, flag, 0o644, resolveSymlinks);
async function _appendFile(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): Promise<void> {
const file = await _open(fname, flag, mode, resolveSymlinks);
try {
await file.write(data, 0, data.length, null);
} finally {
Expand Down Expand Up @@ -516,7 +516,7 @@ export async function appendFile(
throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? encode(data) : data;
await _appendFile(filename, encodedData, options.flag, true);
await _appendFile(filename, encodedData, options.flag, options.mode, true);
}
appendFile satisfies typeof Node.promises.appendFile;

Expand Down
20 changes: 10 additions & 10 deletions src/emulation/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ readFileSync satisfies BufferToUint8Array<typeof Node.readFileSync>;
*
* The encoding option is ignored if data is a buffer.
*/
function _writeFileSync(fname: string, data: Uint8Array, flag: string, resolveSymlinks: boolean): void {
const file = _openSync(fname, flag, 0o644, resolveSymlinks);
function _writeFileSync(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): void {
const file = _openSync(fname, flag, mode, resolveSymlinks);
try {
file.writeSync(data, 0, data.length, 0);
} finally {
Expand All @@ -271,9 +271,9 @@ function _writeFileSync(fname: string, data: Uint8Array, flag: string, resolveSy
* @option options flag Defaults to `'w'`.
*/
export function writeFileSync(filename: string, data: FileContents, options?: Node.WriteFileOptions): void;
export function writeFileSync(filename: string, data: FileContents, encoding?: string): void;
export function writeFileSync(filename: string, data: FileContents, arg3?: Node.WriteFileOptions | string): void {
const options = normalizeOptions(arg3, 'utf8', 'w', 0o644);
export function writeFileSync(filename: string, data: FileContents, encoding?: BufferEncoding): void;
export function writeFileSync(filename: string, data: FileContents, _options?: Node.WriteFileOptions | BufferEncoding): void {
const options = normalizeOptions(_options, 'utf8', 'w', 0o644);
const flag = FileFlag.FromString(options.flag);
if (!flag.isWriteable()) {
throw new ApiError(ErrorCode.EINVAL, 'Flag passed to writeFile must allow for writing.');
Expand All @@ -282,16 +282,16 @@ export function writeFileSync(filename: string, data: FileContents, arg3?: Node.
throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? encode(data) : data;
_writeFileSync(filename, encodedData, options.flag, true);
_writeFileSync(filename, encodedData, options.flag, options.mode, true);
}
writeFileSync satisfies typeof Node.writeFileSync;

/**
* Synchronously append data to a file, creating the file if
* it not yet exists.
*/
function _appendFileSync(fname: string, data: Uint8Array, flag: string, resolveSymlinks: boolean): void {
const file = _openSync(fname, flag, 0o644, resolveSymlinks);
function _appendFileSync(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): void {
const file = _openSync(fname, flag, mode, resolveSymlinks);
try {
file.writeSync(data, 0, data.length, null);
} finally {
Expand Down Expand Up @@ -327,7 +327,7 @@ export function appendFileSync(filename: string, data: FileContents, arg3?: Node
throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
}
const encodedData = typeof data == 'string' ? encode(data) : data;
_appendFileSync(filename, encodedData, options.flag, true);
_appendFileSync(filename, encodedData, options.flag, options.mode, true);
}
appendFileSync satisfies typeof Node.appendFileSync;

Expand Down Expand Up @@ -573,7 +573,7 @@ linkSync satisfies typeof Node.linkSync;
* @param dstpath
* @param type can be either `'dir'` or `'file'` (default is `'file'`)
*/
export function symlinkSync(srcpath: PathLike, dstpath: PathLike, type?: symlink.Type): void {
export function symlinkSync(srcpath: PathLike, dstpath: PathLike, type: symlink.Type = 'file'): void {
if (!['file', 'dir', 'junction'].includes(type)) {
throw new ApiError(ErrorCode.EINVAL, 'Invalid type: ' + type);
}
Expand Down
2 changes: 0 additions & 2 deletions test/tests/error-messages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const expectError = async (fn: (...args) => Promise<unknown>, p: string, ...args
expect(error).toBeDefined();
expect(error.path).toBe(p);
expect(error.message).toContain(p);
return error;
};

const expectSyncError = (fn: (...args) => unknown, p: string, ...args) => {
Expand All @@ -26,7 +25,6 @@ const expectSyncError = (fn: (...args) => unknown, p: string, ...args) => {
expect(error).toBeDefined();
expect(error.path).toBe(p);
expect(error.message).toContain(p);
return error;
};

describe('Error tests', () => {
Expand Down
4 changes: 2 additions & 2 deletions test/tests/open.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ describe('fs file opening', () => {
});

it('should open file with mode "r"', async () => {
const fd = await fs.promises.open(filename, 'r');
const { fd } = await fs.promises.open(filename, 'r');
expect(fd).toBeGreaterThanOrEqual(-Infinity);
});

it('should open file with mode "rs"', async () => {
const fd = await fs.promises.open(filename, 'rs');
const { fd } = await fs.promises.open(filename, 'rs');
expect(fd).toBeGreaterThanOrEqual(-Infinity);
});
});
4 changes: 2 additions & 2 deletions test/tests/read.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('read', () => {
it('should read file asynchronously', async () => {
const fd = await fs.promises.open(filepath, 'r');
const buffer = Buffer.alloc(expected.length);
const bytesRead = await fs.promises.read(fd, buffer, 0, expected.length, 0);
const { bytesRead } = await fs.promises.read(fd, buffer, 0, expected.length, 0);

expect(buffer.toString()).toEqual(expected);
expect(bytesRead).toEqual(expected.length);
Expand Down Expand Up @@ -48,7 +48,7 @@ describe('read buffer', () => {

it('should read file asynchronously', async () => {
const fd = await fs.promises.open(filepath, 'r');
const bytesRead = await fs.promises.read(fd, bufferAsync, 0, expected.length, 0);
const { bytesRead } = await fs.promises.read(fd, bufferAsync, 0, expected.length, 0);

expect(bytesRead).toBe(expected.length);
expect(bufferAsync.toString()).toBe(expected);
Expand Down
2 changes: 1 addition & 1 deletion test/tests/readFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('File Reading', () => {
it('Reading past the end of a file should not be an error', async () => {
const fd = await fs.promises.open('a.js', 'r');
const buffData = Buffer.alloc(10);
const bytesRead = await fs.promises.read(fd, buffData, 0, 10, 10000);
const { bytesRead } = await fs.promises.read(fd, buffData, 0, 10, 10000);
expect(bytesRead).toBe(0);
});
});
Expand Down
16 changes: 8 additions & 8 deletions test/tests/utimes.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ErrorCode } from '../../src/ApiError';
import type { ApiError } from '../../src/ApiError';
import { fs } from '../common';

describe('utimes', () => {
Expand All @@ -15,8 +15,8 @@ describe('utimes', () => {
await fs.promises.utimes(filename, atime, mtime);
expect_ok(filename, atime, mtime);

await fs.promises.utimes('foobarbaz', atime, mtime).catch(err => {
expect(err.code).toEqual(ErrorCode.ENOENT);
await fs.promises.utimes('foobarbaz', atime, mtime).catch((err: ApiError) => {
expect(err.code).toEqual('ENOENT');
});

// don't close this fd
Expand All @@ -25,8 +25,8 @@ describe('utimes', () => {
await fs.promises.futimes(handle, atime, mtime);
expect_ok(handle.fd, atime, mtime);

fs.futimes(-1, atime, mtime, err => {
expect(err.code).toEqual(ErrorCode.EBADF);
fs.futimes(-1, atime, mtime, (err: ApiError) => {
expect(err.code).toEqual('EBADF');
});

fs.utimesSync(filename, atime, mtime);
Expand All @@ -38,19 +38,19 @@ describe('utimes', () => {
fs.futimesSync(handle.fd, atime, mtime);
expect_ok(handle.fd, atime, mtime);
} catch (err) {
expect(err.code).toEqual(ErrorCode.ENOTSUP);
expect(err.code).toEqual('ENOTSUP');
}

try {
fs.utimesSync('foobarbaz', atime, mtime);
} catch (err) {
expect(err.code).toEqual(ErrorCode.ENOENT);
expect(err.code).toEqual('ENOENT');
}

try {
fs.futimesSync(-1, atime, mtime);
} catch (err) {
expect(err.code).toEqual(ErrorCode.EBADF);
expect(err.code).toEqual('EBADF');
}
}

Expand Down
6 changes: 3 additions & 3 deletions test/tests/write.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('fs.write', () => {
const fd = await fs.promises.open(fn, 'w', 0o644);
await fs.promises.write(fd, '', 0, 'utf8');
const written = await fs.promises.write(fd, expected, 0, 'utf8');
expect(written).toBe(Buffer.byteLength(expected));
expect(written.bytesWritten).toBe(expected.length);
await fd.close();

const data = await fs.promises.readFile(fn, 'utf8');
Expand All @@ -19,7 +19,7 @@ describe('fs.write', () => {
const fd2 = await fs.promises.open(fn2, 'w', 0o644);
await fs.promises.write(fd2, '', 0, 'utf8');
const written2 = await fs.promises.write(fd2, expected, 0, 'utf8');
expect(written2).toBe(Buffer.byteLength(expected));
expect(written2.bytesWritten).toBe(Buffer.byteLength(expected));
await fd2.close();

const data2 = await fs.promises.readFile(fn2, 'utf8');
Expand All @@ -36,7 +36,7 @@ describe('fs.write', () => {

const written = await fs.promises.write(fd, expected, 0, expected.length, null);

expect(expected.length).toBe(written);
expect(expected.length).toBe(written.bytesWritten);

await fd.close();

Expand Down
1 change: 0 additions & 1 deletion test/tests/writeFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const s =
'南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、经济现状。\n';

describe('fs.writeFile', () => {

it('should write and read file with specified content', async () => {
const filename = 'test.txt';
await fs.promises.writeFile(filename, s);
Expand Down
13 changes: 5 additions & 8 deletions test/tests/writeFileSync.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import { fs } from '../common';

describe('File Writing with Custom Mode', () => {

it('should write file synchronously with custom mode', async () => {
const file = 'testWriteFileSync.txt';
const mode = 0o755;

fs.writeFileSync(file, '123', { mode: mode });
fs.writeFileSync(file, '123', { mode });

const content = fs.readFileSync(file, { encoding: 'utf8' });
const content = fs.readFileSync(file, 'utf8');
expect(content).toBe('123');

const actual = fs.statSync(file).mode & 0o777;
expect(actual).toBe(mode);
expect(fs.statSync(file).mode & 0o777).toBe(mode);

fs.unlinkSync(file);
});
Expand All @@ -21,12 +18,12 @@ describe('File Writing with Custom Mode', () => {
const file = 'testAppendFileSync.txt';
const mode = 0o755;

fs.appendFileSync(file, 'abc', { mode: mode });
fs.appendFileSync(file, 'abc', { mode });

const content = fs.readFileSync(file, { encoding: 'utf8' });
expect(content).toBe('abc');

expect(fs.statSync(file).mode & mode).toBe(mode);
expect(fs.statSync(file).mode & 0o777).toBe(mode);

fs.unlinkSync(file);
});
Expand Down

0 comments on commit d503a46

Please sign in to comment.