diff options
-rw-r--r-- | js/deno.ts | 2 | ||||
-rw-r--r-- | js/os.ts | 25 | ||||
-rw-r--r-- | js/unit_tests.ts | 30 | ||||
-rw-r--r-- | src/fs.rs | 6 | ||||
-rw-r--r-- | src/handlers.rs | 30 | ||||
-rwxr-xr-x | tools/test.py | 2 |
6 files changed, 89 insertions, 6 deletions
diff --git a/js/deno.ts b/js/deno.ts index 060b2d526..ff9939b1b 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -1,4 +1,4 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. // Public deno module. -export { exit, readFileSync } from "./os"; +export { exit, readFileSync, writeFileSync } from "./os"; export { libdeno } from "./globals"; @@ -121,15 +121,32 @@ export function readFileSync(filename: string): Uint8Array { export function writeFileSync( filename: string, data: Uint8Array, - perm: number + perm = 0o666 ): void { - util.notImplemented(); - /* - pubInternal("os", { + /* Ideally we could write: + const res = send({ command: fbs.Command.WRITE_FILE_SYNC, writeFileSyncFilename: filename, writeFileSyncData: data, writeFileSyncPerm: perm }); */ + const builder = new flatbuffers.Builder(); + const filename_ = builder.createString(filename); + const dataOffset = fbs.WriteFileSync.createDataVector(builder, data); + fbs.WriteFileSync.startWriteFileSync(builder); + fbs.WriteFileSync.addFilename(builder, filename_); + fbs.WriteFileSync.addData(builder, dataOffset); + fbs.WriteFileSync.addPerm(builder, perm); + const msg = fbs.WriteFileSync.endWriteFileSync(builder); + fbs.Base.startBase(builder); + fbs.Base.addMsg(builder, msg); + fbs.Base.addMsgType(builder, fbs.Any.WriteFileSync); + builder.finish(fbs.Base.endBase(builder)); + const resBuf = libdeno.send(builder.asUint8Array()); + if (resBuf != null) { + const bb = new flatbuffers.ByteBuffer(new Uint8Array(resBuf!)); + const baseRes = fbs.Base.getRootAsBase(bb); + maybeThrowError(baseRes); + } } diff --git a/js/unit_tests.ts b/js/unit_tests.ts index f203444fa..6eebf8860 100644 --- a/js/unit_tests.ts +++ b/js/unit_tests.ts @@ -5,6 +5,7 @@ import { test, assert, assertEqual } from "./testing/testing.ts"; import { readFileSync } from "deno"; +import * as deno from "deno"; import "./compiler_test.ts"; @@ -109,6 +110,35 @@ test(function tests_readFileSync_NotFound() { }); */ +/* TODO(ry) Add this once we can create a tmpDir to write the file into. +test(function writeFileSyncSuccess() { + const enc = new TextEncoder(); + const dataWritten = enc.encode("Hello"); + const filename = "TEMPDIR/test.txt"; + deno.writeFileSync(filename, dataWritten, 0o666); + const dataRead = readFileSync(filename); + assertEqual(dataRead, dataWritten); +}); +*/ + +// For this test to pass we need --allow-write permission. +// Otherwise it will fail with deno.PermissionDenied instead of deno.NotFound. +test(function writeFileSyncFail() { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = "/baddir/test.txt"; + // The following should fail because /baddir doesn't exist (hopefully). + let caughtError = false; + try { + deno.writeFileSync(filename, data); + } catch (e) { + caughtError = true; + // TODO assertEqual(e, deno.NotFound); + assertEqual(e.name, "deno.NotFound"); + } + assert(caughtError); +}); + test(async function tests_fetch() { const response = await fetch("http://localhost:4545/package.json"); const json = await response.json(); @@ -1,6 +1,7 @@ use std; use std::fs::File; use std::io::Read; +use std::io::Write; use std::path::Path; pub fn read_file_sync(path: &Path) -> std::io::Result<Vec<u8>> { @@ -17,6 +18,11 @@ pub fn read_file_sync_string(path: &Path) -> std::io::Result<String> { .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err)) } +pub fn write_file_sync(path: &Path, content: &[u8]) -> std::io::Result<()> { + let mut f = File::create(path)?; + f.write_all(content) +} + pub fn mkdir(path: &Path) -> std::io::Result<()> { debug!("mkdir -p {}", path.display()); assert!(path.has_root(), "non-has_root not yet implemented"); diff --git a/src/handlers.rs b/src/handlers.rs index 853fbbc77..1b8a59173 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -70,6 +70,14 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) { let filename = msg.filename().unwrap(); handle_read_file_sync(d, &mut builder, filename) } + msg::Any::WriteFileSync => { + // TODO base.msg_as_WriteFileSync(); + let msg = msg::WriteFileSync::init_from_table(base.msg().unwrap()); + let filename = msg.filename().unwrap(); + let data = msg.data().unwrap(); + let perm = msg.perm(); + handle_write_file_sync(d, &mut builder, filename, data, perm) + } _ => panic!(format!( "Unhandled message {}", msg::enum_name_any(msg_type) @@ -413,6 +421,28 @@ fn handle_read_file_sync( )) } +fn handle_write_file_sync( + d: *const DenoC, + builder: &mut FlatBufferBuilder, + filename: &str, + data: &[u8], + perm: u32, +) -> HandlerResult { + debug!("handle_write_file_sync {}", filename); + let deno = from_c(d); + if deno.flags.allow_write { + // TODO(ry) Use perm. + fs::write_file_sync(Path::new(filename), data)?; + Ok(null_buf()) + } else { + let err = std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + "allow_write is off.", + ); + Err(err.into()) + } +} + // TODO(ry) Use Deno instead of DenoC as first arg. fn remove_timer(d: *const DenoC, timer_id: u32) { let deno = from_c(d); diff --git a/tools/test.py b/tools/test.py index 75886874e..12582f83f 100755 --- a/tools/test.py +++ b/tools/test.py @@ -41,7 +41,7 @@ def main(argv): deno_exe = os.path.join(build_dir, "deno" + executable_suffix) check_exists(deno_exe) - run([deno_exe, "js/unit_tests.ts"]) + run([deno_exe, "js/unit_tests.ts", "--allow-write"]) check_exists(deno_exe) check_output_test(deno_exe) |