summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasper Beyer <caspervonb@pm.me>2020-06-20 21:46:10 +0800
committerGitHub <noreply@github.com>2020-06-20 09:46:10 -0400
commit86f92e04c79be81f98e5899638cb6fdb29a4fa64 (patch)
treeb106b4551d9ec2e842beefdb4d0f921e27b03aa1
parentbdf2d26ba1879b2ebeffd4b3a52e23e9254d4f05 (diff)
feat(unstable): add Deno.ftruncate and ftruncateSync (#6243)
-rw-r--r--cli/js/deno_unstable.ts1
-rw-r--r--cli/js/lib.deno.unstable.d.ts39
-rw-r--r--cli/js/ops/fs/truncate.ts8
-rw-r--r--cli/ops/fs.rs47
-rw-r--r--cli/tests/unit/truncate_test.ts44
5 files changed, 139 insertions, 0 deletions
diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts
index 192137e1f..991df9955 100644
--- a/cli/js/deno_unstable.ts
+++ b/cli/js/deno_unstable.ts
@@ -12,6 +12,7 @@ export { applySourceMap, formatDiagnostics } from "./ops/errors.ts";
export { signal, signals, Signal, SignalStream } from "./signals.ts";
export { setRaw } from "./ops/tty.ts";
export { utimeSync, utime } from "./ops/fs/utime.ts";
+export { ftruncateSync, ftruncate } from "./ops/fs/truncate.ts";
export { ShutdownMode, shutdown } from "./net.ts";
export { listen, listenDatagram, connect } from "./net_unstable.ts";
export { startTls } from "./tls.ts";
diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts
index 0a80eb2c6..dd8de2eb6 100644
--- a/cli/js/lib.deno.unstable.d.ts
+++ b/cli/js/lib.deno.unstable.d.ts
@@ -1248,4 +1248,43 @@ declare namespace Deno {
/** **UNSTABLE**: The URL of the file that was originally executed from the command-line. */
export const mainModule: string;
+
+ /** Synchronously truncates or extends the specified file stream, to reach the
+ * specified `len`. If `len` is not specified then the entire file contents
+ * are truncated.
+ *
+ * ```ts
+ * // truncate the entire file
+ * const file = Deno.open("my_file.txt", { read: true, write: true, truncate: true, create: true });
+ * Deno.ftruncateSync(file.rid);
+ *
+ * // truncate part of the file
+ * const file = Deno.open("my_file.txt", { read: true, write: true, create: true });
+ * Deno.write(file.rid, new TextEncoder().encode("Hello World"));
+ * Deno.ftruncateSync(file.rid, 7);
+ * const data = new Uint8Array(32);
+ * Deno.readSync(file.rid, data);
+ * console.log(new TextDecoder().decode(data)); // Hello W
+ * ```
+ */
+ export function ftruncateSync(rid: number, len?: number): void;
+
+ /** Truncates or extends the specified file stream, to reach the specified `len`. If
+ * `len` is not specified then the entire file contents are truncated.
+ *
+ * ```ts
+ * // truncate the entire file
+ * const file = Deno.open("my_file.txt", { read: true, write: true, create: true });
+ * await Deno.ftruncate(file.rid);
+ *
+ * // truncate part of the file
+ * const file = Deno.open("my_file.txt", { read: true, write: true, create: true });
+ * await Deno.write(file.rid, new TextEncoder().encode("Hello World"));
+ * await Deno.ftruncate(file.rid, 7);
+ * const data = new Uint8Array(32);
+ * await Deno.read(file.rid, data);
+ * console.log(new TextDecoder().decode(data)); // Hello W
+ * ```
+ */
+ export function ftruncate(rid: number, len?: number): Promise<void>;
}
diff --git a/cli/js/ops/fs/truncate.ts b/cli/js/ops/fs/truncate.ts
index 861e843f8..2b805e5ac 100644
--- a/cli/js/ops/fs/truncate.ts
+++ b/cli/js/ops/fs/truncate.ts
@@ -13,6 +13,14 @@ function coerceLen(len?: number): number {
return len;
}
+export function ftruncateSync(rid: number, len?: number): void {
+ sendSync("op_ftruncate", { rid, len: coerceLen(len) });
+}
+
+export async function ftruncate(rid: number, len?: number): Promise<void> {
+ await sendAsync("op_ftruncate", { rid, len: coerceLen(len) });
+}
+
export function truncateSync(path: string, len?: number): void {
sendSync("op_truncate", { path, len: coerceLen(len) });
}
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs
index 63b3ad7f5..9ca4b31ae 100644
--- a/cli/ops/fs.rs
+++ b/cli/ops/fs.rs
@@ -36,6 +36,7 @@ pub fn init(i: &mut CoreIsolate, s: &State) {
i.register_op("op_link", s.stateful_json_op(op_link));
i.register_op("op_symlink", s.stateful_json_op(op_symlink));
i.register_op("op_read_link", s.stateful_json_op(op_read_link));
+ i.register_op("op_ftruncate", s.stateful_json_op2(op_ftruncate));
i.register_op("op_truncate", s.stateful_json_op(op_truncate));
i.register_op("op_make_temp_dir", s.stateful_json_op(op_make_temp_dir));
i.register_op("op_make_temp_file", s.stateful_json_op(op_make_temp_file));
@@ -785,6 +786,52 @@ fn op_read_link(
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
+struct FtruncateArgs {
+ promise_id: Option<u64>,
+ rid: i32,
+ len: i32,
+}
+
+fn op_ftruncate(
+ isolate_state: &mut CoreIsolateState,
+ state: &State,
+ args: Value,
+ _zero_copy: &mut [ZeroCopyBuf],
+) -> Result<JsonOp, OpError> {
+ state.check_unstable("Deno.ftruncate");
+ let args: FtruncateArgs = serde_json::from_value(args)?;
+ let rid = args.rid as u32;
+ let len = args.len as u64;
+
+ let resource_table = isolate_state.resource_table.clone();
+ let is_sync = args.promise_id.is_none();
+
+ if is_sync {
+ let mut resource_table = resource_table.borrow_mut();
+ std_file_resource(&mut resource_table, rid, |r| match r {
+ Ok(std_file) => std_file.set_len(len).map_err(OpError::from),
+ Err(_) => Err(OpError::type_error(
+ "cannot truncate this type of resource".to_string(),
+ )),
+ })?;
+ Ok(JsonOp::Sync(json!({})))
+ } else {
+ let fut = async move {
+ let mut resource_table = resource_table.borrow_mut();
+ std_file_resource(&mut resource_table, rid, |r| match r {
+ Ok(std_file) => std_file.set_len(len).map_err(OpError::from),
+ Err(_) => Err(OpError::type_error(
+ "cannot truncate this type of resource".to_string(),
+ )),
+ })?;
+ Ok(json!({}))
+ };
+ Ok(JsonOp::Async(fut.boxed_local()))
+ }
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
struct TruncateArgs {
promise_id: Option<u64>,
path: String,
diff --git a/cli/tests/unit/truncate_test.ts b/cli/tests/unit/truncate_test.ts
index 014815702..82f8f03eb 100644
--- a/cli/tests/unit/truncate_test.ts
+++ b/cli/tests/unit/truncate_test.ts
@@ -3,6 +3,50 @@ import { unitTest, assertEquals, assert } from "./test_util.ts";
unitTest(
{ perms: { read: true, write: true } },
+ function ftruncateSyncSuccess(): void {
+ const filename = Deno.makeTempDirSync() + "/test_ftruncateSync.txt";
+ const file = Deno.openSync(filename, {
+ create: true,
+ read: true,
+ write: true,
+ });
+
+ Deno.ftruncateSync(file.rid, 20);
+ assertEquals(Deno.readFileSync(filename).byteLength, 20);
+ Deno.ftruncateSync(file.rid, 5);
+ assertEquals(Deno.readFileSync(filename).byteLength, 5);
+ Deno.ftruncateSync(file.rid, -5);
+ assertEquals(Deno.readFileSync(filename).byteLength, 0);
+
+ Deno.close(file.rid);
+ Deno.removeSync(filename);
+ }
+);
+
+unitTest(
+ { perms: { read: true, write: true } },
+ async function ftruncateSuccess(): Promise<void> {
+ const filename = Deno.makeTempDirSync() + "/test_ftruncate.txt";
+ const file = await Deno.open(filename, {
+ create: true,
+ read: true,
+ write: true,
+ });
+
+ await Deno.ftruncate(file.rid, 20);
+ assertEquals((await Deno.readFile(filename)).byteLength, 20);
+ await Deno.ftruncate(file.rid, 5);
+ assertEquals((await Deno.readFile(filename)).byteLength, 5);
+ await Deno.ftruncate(file.rid, -5);
+ assertEquals((await Deno.readFile(filename)).byteLength, 0);
+
+ Deno.close(file.rid);
+ await Deno.remove(filename);
+ }
+);
+
+unitTest(
+ { perms: { read: true, write: true } },
function truncateSyncSuccess(): void {
const filename = Deno.makeTempDirSync() + "/test_truncateSync.txt";
Deno.writeFileSync(filename, new Uint8Array(5));