Skip to content

Commit

Permalink
feat(std/node): add writeBuffer of internal binding fs module (#888)
Browse files Browse the repository at this point in the history
  • Loading branch information
kt3k authored Jul 6, 2021
1 parent 30a9669 commit fa2b0d6
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
8 changes: 8 additions & 0 deletions node/internal_binding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
The modules in this directory implement (simulate) C++ bindings inplemented in
src/ directory of Node.js

These bindings are created in the node.js source code by using
`NODE_MODULE_CONTEXT_AWARE_INTERNAL`.

See:
https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/src/README.md
74 changes: 74 additions & 0 deletions node/internal_binding/fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
import { assert } from "../../testing/asserts.ts";
// This module implements functions in https://github.com/nodejs/node/blob/master/src/node_file.cc

/**
* Write to the given file from the given buffer asynchronously.
*
* Implements async part of WriteBuffer in src/node_file.cc
* See: https://github.com/nodejs/node/blob/e9ed113/src/node_file.cc#L1818
*
* @param fs file descriptor
* @param buffer the data to write
* @param offset where in the buffer to start from
* @param length how much to write
* @param position if integer, position to write at in the file. if null, write from the current position
* @param callback callback function
*/
export function writeBuffer(
_fd: number,
_buffer: Uint8Array,
_offset: number,
_length: number,
_position: number | null,
_callback?: (err: Error, n: number) => void,
): void {
throw new Error("unimplemented!");
}

/**
* Write to the given file from the given buffer synchronously.
*
* Implements sync part of WriteBuffer in src/node_file.cc
* See: https://github.com/nodejs/node/blob/e9ed113/src/node_file.cc#L1818
*
* @param fs file descriptor
* @param buffer the data to write
* @param offset where in the buffer to start from
* @param length how much to write
* @param position if integer, position to write at in the file. if null, write from the current position
* @param context context object for passing error number
*/
export function writeBufferSync(
fd: number,
buffer: Uint8Array,
offset: number,
length: number,
position: number | null,
ctx: { errno?: number },
) {
assert(offset >= 0, "offset should be greater or equal to 0");
assert(
offset + length <= buffer.byteLength,
`buffer doesn't have enough data: byteLength = ${buffer.byteLength}, offset + length = ${offset +
length}`,
);
if (position) {
Deno.seekSync(fd, position, Deno.SeekMode.Current);
}
const subarray = buffer.subarray(offset, offset + length);
try {
return Deno.writeSync(fd, subarray);
} catch (e) {
ctx.errno = extractOsErrorNumberFromErrorMessage(e);
return 0;
}
}

function extractOsErrorNumberFromErrorMessage(e: Error): number {
const match = e.message.match(/\(os error (\d+)\)/);
if (match) {
return +match[1];
}
return 255; // Unknown error
}
56 changes: 56 additions & 0 deletions node/internal_binding/fs_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
import { writeBufferSync } from "./fs.ts";
import { assertEquals } from "../../testing/asserts.ts";

Deno.test("[node/internal_binding/fs] writeBufferSync", async () => {
const tempfile = await Deno.makeTempFile();
await Deno.writeTextFile(tempfile, "01234567890123456789");

const file = await Deno.open(tempfile, { write: true });
await Deno.seek(file.rid, 5, Deno.SeekMode.Start);

try {
const ctx: { errno?: number } = {};
const bytesWritten = writeBufferSync(
file.rid,
new Uint8Array([65, 66, 67, 68, 69] /* abcde */),
1,
3,
5,
ctx,
);

assertEquals(await Deno.readTextFile(tempfile), "0123456789BCD3456789");
assertEquals(bytesWritten, 3);
assertEquals(typeof ctx.errno, "undefined");
} finally {
Deno.close(file.rid);
await Deno.remove(tempfile);
}
});
Deno.test("[node/internal_binding/fs] writeBufferSync", async () => {
const tempfile = await Deno.makeTempFile();
await Deno.writeTextFile(tempfile, "01234567890123456789");
const file = await Deno.open(tempfile, { read: true, write: false });

try {
const ctx: { errno?: number } = {};
const bytesWritten = writeBufferSync(
file.rid,
new Uint8Array([65, 66, 67, 68, 69] /* abcde */),
1,
3,
5,
ctx,
);
assertEquals(bytesWritten, 0);
if (Deno.build.os === "windows") {
assertEquals(ctx.errno, 5); // Access is denied
} else {
assertEquals(ctx.errno, 9); // Bad file descriptor
}
} finally {
Deno.close(file.rid);
await Deno.remove(tempfile);
}
});

0 comments on commit fa2b0d6

Please sign in to comment.