summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorztplz <mysticzt@gmail.com>2018-10-01 03:06:20 +0800
committerRyan Dahl <ry@tinyclouds.org>2018-09-30 15:06:20 -0400
commit062b22fe569fffc0f52ec36de99e5048e4d42703 (patch)
treefb436c7163b414ea08a2050f4284fe87362f484c
parentf51903f7736e3969ba0003c074d80950aca74f70 (diff)
Add deno.truncate (#805)
-rw-r--r--BUILD.gn1
-rw-r--r--js/deno.ts1
-rw-r--r--js/truncate.ts42
-rw-r--r--js/truncate_test.ts73
-rw-r--r--js/unit_tests.ts1
-rw-r--r--src/handlers.rs23
-rw-r--r--src/msg.fbs6
7 files changed, 147 insertions, 0 deletions
diff --git a/BUILD.gn b/BUILD.gn
index e573b7504..285d6ee13 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -96,6 +96,7 @@ ts_sources = [
"js/text_encoding.ts",
"js/timers.ts",
"js/trace.ts",
+ "js/truncate.ts",
"js/types.ts",
"js/util.ts",
"js/v8_source_maps.ts",
diff --git a/js/deno.ts b/js/deno.ts
index 44fba6164..cd290bfa3 100644
--- a/js/deno.ts
+++ b/js/deno.ts
@@ -17,5 +17,6 @@ export { ErrorKind, DenoError } from "./errors";
export { libdeno } from "./libdeno";
export { arch, platform } from "./platform";
export { trace } from "./trace";
+export { truncateSync, truncate } from "./truncate";
export { setGlobalTimeout } from "./timers";
export const args: string[] = [];
diff --git a/js/truncate.ts b/js/truncate.ts
new file mode 100644
index 000000000..7b6e2f8e9
--- /dev/null
+++ b/js/truncate.ts
@@ -0,0 +1,42 @@
+// Copyright 2018 the Deno authors. All rights reserved. MIT license.
+import * as fbs from "gen/msg_generated";
+import { flatbuffers } from "flatbuffers";
+import * as dispatch from "./dispatch";
+
+/**
+ * Truncates or extends the specified file synchronously,
+ * updating the size of this file to become size.
+ *
+ * import { truncateSync } from "deno";
+ *
+ * truncateSync("hello.txt", 10);
+ */
+export function truncateSync(name: string, len?: number): void {
+ dispatch.sendSync(...req(name, len));
+}
+
+/**
+ * Truncates or extends the specified file,
+ * updating the size of this file to become size.
+ *
+ * import { truncate } from "deno";
+ *
+ * await truncate("hello.txt", 10);
+ */
+export async function truncate(name: string, len?: number): Promise<void> {
+ await dispatch.sendAsync(...req(name, len));
+}
+
+function req(
+ name: string,
+ len?: number
+): [flatbuffers.Builder, fbs.Any, flatbuffers.Offset] {
+ const builder = new flatbuffers.Builder();
+ const name_ = builder.createString(name);
+ len = len && len > 0 ? Math.floor(len) : 0;
+ fbs.Truncate.startTruncate(builder);
+ fbs.Truncate.addName(builder, name_);
+ fbs.Truncate.addLen(builder, len);
+ const msg = fbs.Truncate.endTruncate(builder);
+ return [builder, fbs.Any.Truncate, msg];
+}
diff --git a/js/truncate_test.ts b/js/truncate_test.ts
new file mode 100644
index 000000000..4b9cae445
--- /dev/null
+++ b/js/truncate_test.ts
@@ -0,0 +1,73 @@
+// Copyright 2018 the Deno authors. All rights reserved. MIT license.
+import { testPerm, assertEqual } from "./test_util.ts";
+import * as deno from "deno";
+
+function readDataSync(name: string): string {
+ const data = deno.readFileSync(name);
+ const decoder = new TextDecoder("utf-8");
+ const text = decoder.decode(data);
+ return text;
+}
+
+async function readData(name: string): Promise<string> {
+ const data = await deno.readFile(name);
+ const decoder = new TextDecoder("utf-8");
+ const text = decoder.decode(data);
+ return text;
+}
+
+testPerm({ write: true }, function truncateSyncSuccess() {
+ const enc = new TextEncoder();
+ const d = enc.encode("Hello");
+ const filename = deno.makeTempDirSync() + "/test_truncateSync.txt";
+ deno.writeFileSync(filename, d);
+ deno.truncateSync(filename, 20);
+ let data = readDataSync(filename);
+ assertEqual(data.length, 20);
+ deno.truncateSync(filename, 5);
+ data = readDataSync(filename);
+ assertEqual(data.length, 5);
+ deno.truncateSync(filename, -5);
+ data = readDataSync(filename);
+ assertEqual(data.length, 0);
+ deno.removeSync(filename);
+});
+
+testPerm({ write: true }, async function truncateSuccess() {
+ const enc = new TextEncoder();
+ const d = enc.encode("Hello");
+ const filename = deno.makeTempDirSync() + "/test_truncate.txt";
+ await deno.writeFile(filename, d);
+ await deno.truncate(filename, 20);
+ let data = await readData(filename);
+ assertEqual(data.length, 20);
+ await deno.truncate(filename, 5);
+ data = await readData(filename);
+ assertEqual(data.length, 5);
+ await deno.truncate(filename, -5);
+ data = await readData(filename);
+ assertEqual(data.length, 0);
+ await deno.remove(filename);
+});
+
+testPerm({ write: false }, function truncateSyncPerm() {
+ let err;
+ try {
+ deno.mkdirSync("/test_truncateSyncPermission.txt");
+ } catch (e) {
+ err = e;
+ }
+ assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
+ assertEqual(err.name, "PermissionDenied");
+});
+
+testPerm({ write: false }, async function truncatePerm() {
+ let err;
+ try {
+ await deno.mkdir("/test_truncatePermission.txt");
+ } catch (e) {
+ err = e;
+ }
+ assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
+ assertEqual(err.name, "PermissionDenied");
+});
diff --git a/js/unit_tests.ts b/js/unit_tests.ts
index 3a1fdd9d1..2eea6c17b 100644
--- a/js/unit_tests.ts
+++ b/js/unit_tests.ts
@@ -19,5 +19,6 @@ import "./symlink_test.ts";
import "./platform_test.ts";
import "./text_encoding_test.ts";
import "./trace_test.ts";
+import "./truncate_test.ts";
import "./v8_source_maps_test.ts";
import "../website/app_test.js";
diff --git a/src/handlers.rs b/src/handlers.rs
index b1ef67d94..c615f5669 100644
--- a/src/handlers.rs
+++ b/src/handlers.rs
@@ -77,6 +77,7 @@ pub fn msg_from_js(
msg::Any::Symlink => handle_symlink,
msg::Any::SetEnv => handle_set_env,
msg::Any::Stat => handle_stat,
+ msg::Any::Truncate => handle_truncate,
msg::Any::WriteFile => handle_write_file,
msg::Any::Exit => handle_exit,
_ => panic!(format!(
@@ -977,3 +978,25 @@ fn handle_read_link(
))
})
}
+
+fn handle_truncate(
+ state: Arc<IsolateState>,
+ base: &msg::Base,
+ data: &'static mut [u8],
+) -> Box<Op> {
+ assert_eq!(data.len(), 0);
+
+ if !state.flags.allow_write {
+ return odd_future(permission_denied());
+ }
+
+ let msg = base.msg_as_truncate().unwrap();
+ let filename = String::from(msg.name().unwrap());
+ let len = msg.len();
+ blocking!(base.sync(), || {
+ debug!("handle_truncate {} {}", filename, len);
+ let f = fs::OpenOptions::new().write(true).open(&filename)?;
+ f.set_len(len as u64)?;
+ Ok(empty_buf())
+ })
+}
diff --git a/src/msg.fbs b/src/msg.fbs
index 7f42cd637..6b2e920e8 100644
--- a/src/msg.fbs
+++ b/src/msg.fbs
@@ -27,6 +27,7 @@ union Any {
Stat,
StatRes,
SetEnv,
+ Truncate,
Open,
OpenRes,
Read,
@@ -247,6 +248,11 @@ table StatRes {
has_mode: bool; // false on windows
}
+table Truncate {
+ name: string;
+ len: uint;
+}
+
table WriteFileSync {
filename: string;
data: [ubyte];