summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/unit/read_file_test.ts40
-rw-r--r--runtime/js/40_read_file.js73
-rw-r--r--runtime/ops/fs.rs80
3 files changed, 129 insertions, 64 deletions
diff --git a/cli/tests/unit/read_file_test.ts b/cli/tests/unit/read_file_test.ts
index 1f3eea30a..07935b7fb 100644
--- a/cli/tests/unit/read_file_test.ts
+++ b/cli/tests/unit/read_file_test.ts
@@ -1,5 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
-import { writeAllSync } from "../../../test_util/std/io/util.ts";
import {
assert,
assertEquals,
@@ -152,42 +151,3 @@ Deno.test(
assert(data.byteLength > 0);
},
);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function readFileExtendedDuringRead() {
- // Write 128MB file
- const filename = Deno.makeTempDirSync() + "/test.txt";
- const data = new Uint8Array(1024 * 1024 * 128);
- Deno.writeFileSync(filename, data);
- const promise = Deno.readFile(filename);
- queueMicrotask(() => {
- // Append 128MB to file
- const f = Deno.openSync(filename, { append: true });
- writeAllSync(f, data);
- f.close();
- });
- const read = await promise;
- assertEquals(read.byteLength, data.byteLength * 2);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function readFile0LengthExtendedDuringRead() {
- // Write 0 byte file
- const filename = Deno.makeTempDirSync() + "/test.txt";
- const first = new Uint8Array(0);
- const second = new Uint8Array(1024 * 1024 * 128);
- Deno.writeFileSync(filename, first);
- const promise = Deno.readFile(filename);
- queueMicrotask(() => {
- // Append 128MB to file
- const f = Deno.openSync(filename, { append: true });
- writeAllSync(f, second);
- f.close();
- });
- const read = await promise;
- assertEquals(read.byteLength, second.byteLength);
- },
-);
diff --git a/runtime/js/40_read_file.js b/runtime/js/40_read_file.js
index 5862454db..8a52e4f70 100644
--- a/runtime/js/40_read_file.js
+++ b/runtime/js/40_read_file.js
@@ -3,44 +3,69 @@
((window) => {
const core = window.Deno.core;
- const { open, openSync } = window.__bootstrap.files;
- const { readAllSync, readAll, readAllSyncSized, readAllInnerSized } =
- window.__bootstrap.io;
+ const { pathFromURL } = window.__bootstrap.util;
+ const { abortSignal } = window.__bootstrap;
function readFileSync(path) {
- const file = openSync(path);
- try {
- const { size } = file.statSync();
- if (size === 0) {
- return readAllSync(file);
- } else {
- return readAllSyncSized(file, size);
- }
- } finally {
- file.close();
- }
+ return core.opSync("op_readfile_sync", pathFromURL(path));
}
async function readFile(path, options) {
- const file = await open(path);
+ let cancelRid;
+ let abortHandler;
+ if (options?.signal) {
+ options.signal.throwIfAborted();
+ cancelRid = core.opSync("op_cancel_handle");
+ abortHandler = () => core.tryClose(cancelRid);
+ options.signal[abortSignal.add](abortHandler);
+ }
+
try {
- const { size } = await file.stat();
- if (size === 0) {
- return await readAll(file);
- } else {
- return await readAllInnerSized(file, size, options);
- }
+ const read = await core.opAsync(
+ "op_readfile_async",
+ pathFromURL(path),
+ cancelRid,
+ );
+ return read;
} finally {
- file.close();
+ if (options?.signal) {
+ options.signal[abortSignal.remove](abortHandler);
+
+ // always throw the abort error when aborted
+ options.signal.throwIfAborted();
+ }
}
}
function readTextFileSync(path) {
- return core.decode(readFileSync(path));
+ return core.opSync("op_readfile_text_sync", pathFromURL(path));
}
async function readTextFile(path, options) {
- return core.decode(await readFile(path, options));
+ let cancelRid;
+ let abortHandler;
+ if (options?.signal) {
+ options.signal.throwIfAborted();
+ cancelRid = core.opSync("op_cancel_handle");
+ abortHandler = () => core.tryClose(cancelRid);
+ options.signal[abortSignal.add](abortHandler);
+ }
+
+ try {
+ const read = await core.opAsync(
+ "op_readfile_text_async",
+ pathFromURL(path),
+ cancelRid,
+ );
+ return read;
+ } finally {
+ if (options?.signal) {
+ options.signal[abortSignal.remove](abortHandler);
+
+ // always throw the abort error when aborted
+ options.signal.throwIfAborted();
+ }
+ }
}
window.__bootstrap.readFile = {
diff --git a/runtime/ops/fs.rs b/runtime/ops/fs.rs
index ddd7f9ca2..501c2ac5f 100644
--- a/runtime/ops/fs.rs
+++ b/runtime/ops/fs.rs
@@ -95,6 +95,10 @@ pub fn init() -> Extension {
op_futime_async::decl(),
op_utime_sync::decl(),
op_utime_async::decl(),
+ op_readfile_sync::decl(),
+ op_readfile_text_sync::decl(),
+ op_readfile_async::decl(),
+ op_readfile_text_async::decl(),
])
.build()
}
@@ -2008,3 +2012,79 @@ fn op_cwd(state: &mut OpState) -> Result<String, AnyError> {
let path_str = into_string(path.into_os_string())?;
Ok(path_str)
}
+
+#[op]
+fn op_readfile_sync(
+ state: &mut OpState,
+ path: String,
+) -> Result<ZeroCopyBuf, AnyError> {
+ let permissions = state.borrow_mut::<Permissions>();
+ let path = Path::new(&path);
+ permissions.read.check(path)?;
+ Ok(std::fs::read(path)?.into())
+}
+
+#[op]
+fn op_readfile_text_sync(
+ state: &mut OpState,
+ path: String,
+) -> Result<String, AnyError> {
+ let permissions = state.borrow_mut::<Permissions>();
+ let path = Path::new(&path);
+ permissions.read.check(path)?;
+ Ok(std::fs::read_to_string(path)?)
+}
+
+#[op]
+async fn op_readfile_async(
+ state: Rc<RefCell<OpState>>,
+ path: String,
+ cancel_rid: Option<ResourceId>,
+) -> Result<ZeroCopyBuf, AnyError> {
+ {
+ let path = Path::new(&path);
+ let mut state = state.borrow_mut();
+ state.borrow_mut::<Permissions>().read.check(path)?;
+ }
+ let fut = tokio::task::spawn_blocking(move || {
+ let path = Path::new(&path);
+ Ok(std::fs::read(path).map(ZeroCopyBuf::from)?)
+ });
+ if let Some(cancel_rid) = cancel_rid {
+ let cancel_handle = state
+ .borrow_mut()
+ .resource_table
+ .get::<CancelHandle>(cancel_rid);
+ if let Ok(cancel_handle) = cancel_handle {
+ return fut.or_cancel(cancel_handle).await??;
+ }
+ }
+ fut.await?
+}
+
+#[op]
+async fn op_readfile_text_async(
+ state: Rc<RefCell<OpState>>,
+ path: String,
+ cancel_rid: Option<ResourceId>,
+) -> Result<String, AnyError> {
+ {
+ let path = Path::new(&path);
+ let mut state = state.borrow_mut();
+ state.borrow_mut::<Permissions>().read.check(path)?;
+ }
+ let fut = tokio::task::spawn_blocking(move || {
+ let path = Path::new(&path);
+ Ok(String::from_utf8(std::fs::read(path)?)?)
+ });
+ if let Some(cancel_rid) = cancel_rid {
+ let cancel_handle = state
+ .borrow_mut()
+ .resource_table
+ .get::<CancelHandle>(cancel_rid);
+ if let Ok(cancel_handle) = cancel_handle {
+ return fut.or_cancel(cancel_handle).await??;
+ }
+ }
+ fut.await?
+}