diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts index 2327b554d2..e7a0510be8 100644 --- a/cli/js/deno_unstable.ts +++ b/cli/js/deno_unstable.ts @@ -5,7 +5,7 @@ export { umask } from "./ops/fs/umask.ts"; export { linkSync, link } from "./ops/fs/link.ts"; export { fstatSync, fstat } from "./ops/fs/stat.ts"; -export { fsyncSync, fsync } from "./ops/fs/sync.ts"; +export { fdatasyncSync, fdatasync, fsyncSync, fsync } from "./ops/fs/sync.ts"; export { symlinkSync, symlink } from "./ops/fs/symlink.ts"; export { loadavg, osRelease, hostname } from "./ops/os.ts"; export { openPlugin } from "./ops/plugins.ts"; diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts index cc7dea9870..f4a7b27868 100644 --- a/cli/js/lib.deno.unstable.d.ts +++ b/cli/js/lib.deno.unstable.d.ts @@ -1119,6 +1119,28 @@ declare namespace Deno { */ export function ftruncate(rid: number, len?: number): Promise; + /* **UNSTABLE**: New API, yet to be vetted. + * Synchronously flushes any pending data operations of the given file stream to disk. + * ```ts + * const file = Deno.openSync("my_file.txt", { read: true, write: true, create: true }); + * Deno.writeSync(file.rid, new TextEncoder().encode("Hello World")); + * Deno.fdatasyncSync(file.rid); + * console.log(new TextDecoder().decode(Deno.readFileSync("my_file.txt"))); // Hello World + * ``` + */ + export function fdatasyncSync(rid: number): void; + + /** **UNSTABLE**: New API, yet to be vetted. + * Flushes any pending data operations of the given file stream to disk. + * ```ts + * const file = await Deno.open("my_file.txt", { read: true, write: true, create: true }); + * await Deno.write(file.rid, new TextEncoder().encode("Hello World")); + * await Deno.fdatasync(file.rid); + * console.log(new TextDecoder().decode(await Deno.readFile("my_file.txt"))); // Hello World + * ``` + */ + export function fdatasync(rid: number): Promise; + /** **UNSTABLE**: New API, yet to be vetted. * Synchronously flushes any pending data and metadata operations of the given file stream to disk. * ```ts diff --git a/cli/js/ops/fs/sync.ts b/cli/js/ops/fs/sync.ts index 5d5de72423..567aab55b4 100644 --- a/cli/js/ops/fs/sync.ts +++ b/cli/js/ops/fs/sync.ts @@ -1,6 +1,14 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { sendSync, sendAsync } from "../dispatch_json.ts"; +export function fdatasyncSync(rid: number): void { + sendSync("op_fdatasync", { rid }); +} + +export async function fdatasync(rid: number): Promise { + await sendAsync("op_fdatasync", { rid }); +} + export function fsyncSync(rid: number): void { sendSync("op_fsync", { rid }); } diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 7c81006050..2e27beff33 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -22,6 +22,7 @@ use rand::{thread_rng, Rng}; pub fn init(i: &mut CoreIsolate, s: &State) { i.register_op("op_open", s.stateful_json_op2(op_open)); i.register_op("op_seek", s.stateful_json_op2(op_seek)); + i.register_op("op_fdatasync", s.stateful_json_op2(op_fdatasync)); i.register_op("op_fsync", s.stateful_json_op2(op_fsync)); i.register_op("op_fstat", s.stateful_json_op2(op_fstat)); i.register_op("op_umask", s.stateful_json_op(op_umask)); @@ -207,6 +208,50 @@ fn op_seek( } } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct FdatasyncArgs { + promise_id: Option, + rid: i32, +} + +fn op_fdatasync( + isolate_state: &mut CoreIsolateState, + state: &State, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result { + state.check_unstable("Deno.fdatasync"); + let args: FdatasyncArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + + 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.sync_data().map_err(OpError::from), + Err(_) => Err(OpError::type_error( + "cannot sync 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.sync_data().map_err(OpError::from), + Err(_) => Err(OpError::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) + }; + Ok(JsonOp::Async(fut.boxed_local())) + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FsyncArgs { diff --git a/cli/tests/unit/sync_test.ts b/cli/tests/unit/sync_test.ts index 7a489e9519..fd6acd8580 100644 --- a/cli/tests/unit/sync_test.ts +++ b/cli/tests/unit/sync_test.ts @@ -1,6 +1,42 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { unitTest, assertEquals } from "./test_util.ts"; +unitTest( + { perms: { read: true, write: true } }, + function fdatasyncSyncSuccess(): void { + const filename = Deno.makeTempDirSync() + "/test_fdatasyncSync.txt"; + const file = Deno.openSync(filename, { + read: true, + write: true, + create: true, + }); + const data = new Uint8Array(64); + Deno.writeSync(file.rid, data); + Deno.fdatasyncSync(file.rid); + assertEquals(Deno.readFileSync(filename), data); + Deno.close(file.rid); + Deno.removeSync(filename); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function fdatasyncSuccess(): Promise { + const filename = (await Deno.makeTempDir()) + "/test_fdatasync.txt"; + const file = await Deno.open(filename, { + read: true, + write: true, + create: true, + }); + const data = new Uint8Array(64); + await Deno.write(file.rid, data); + await Deno.fdatasync(file.rid); + assertEquals(await Deno.readFile(filename), data); + Deno.close(file.rid); + await Deno.remove(filename); + } +); + unitTest( { perms: { read: true, write: true } }, function fsyncSyncSuccess(): void {