summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-05-04 14:28:42 -0400
committerGitHub <noreply@github.com>2023-05-04 14:28:42 -0400
commit5270c43e412cc636cd9923182169d166d181f78a (patch)
tree640c90a70f7dd7bc91f5e942e1eaa5a7914ae46b
parent4b645676d62fd595ecac47e24be1b83a3ba636c6 (diff)
refactor(ext/fs): boxed deno_fs::FileSystem (#18945)
1. Boxed `File` and `FileSystem` to allow more easily passing this through the CLI code (as shown within this pr). 2. `StdFileResource` is now `FileResource`. `FileResource` now contains an `Rc<dyn File>`.
-rw-r--r--Cargo.lock3
-rw-r--r--Cargo.toml1
-rw-r--r--cli/build.rs9
-rw-r--r--cli/factory.rs4
-rw-r--r--cli/standalone/mod.rs2
-rw-r--r--cli/worker.rs36
-rw-r--r--core/resources.rs7
-rw-r--r--ext/fs/Cargo.toml4
-rw-r--r--ext/fs/interface.rs164
-rw-r--r--ext/fs/lib.rs135
-rw-r--r--ext/fs/ops.rs454
-rw-r--r--ext/fs/std_fs.rs411
-rw-r--r--ext/io/Cargo.toml3
-rw-r--r--ext/io/fs.rs330
-rw-r--r--ext/io/lib.rs623
-rw-r--r--runtime/build.rs6
-rw-r--r--runtime/ops/process.rs6
-rw-r--r--runtime/ops/tty.rs125
-rw-r--r--runtime/web_worker.rs5
-rw-r--r--runtime/worker.rs6
20 files changed, 1133 insertions, 1201 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 73b0f3f0d..ad816c9a2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1059,7 +1059,10 @@ dependencies = [
name = "deno_io"
version = "0.13.0"
dependencies = [
+ "async-trait",
"deno_core",
+ "filetime",
+ "fs3",
"nix",
"once_cell",
"tokio",
diff --git a/Cargo.toml b/Cargo.toml
index f7f6d553b..4ffac7e79 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -92,6 +92,7 @@ dlopen = "0.1.8"
encoding_rs = "=0.8.31"
ecb = "=0.1.1"
fastwebsockets = "=0.3.1"
+filetime = "0.2.16"
flate2 = "=1.0.24"
fs3 = "0.5.0"
futures = "0.3.21"
diff --git a/cli/build.rs b/cli/build.rs
index 21f8c229a..6cedb53ce 100644
--- a/cli/build.rs
+++ b/cli/build.rs
@@ -9,7 +9,6 @@ use deno_core::Extension;
use deno_core::ExtensionFileSource;
use deno_core::ExtensionFileSourceCode;
use deno_runtime::deno_cache::SqliteBackedCache;
-use deno_runtime::deno_fs::StdFs;
use deno_runtime::deno_kv::sqlite::SqliteDbHandler;
use deno_runtime::permissions::PermissionsContainer;
use deno_runtime::*;
@@ -361,11 +360,11 @@ fn create_cli_snapshot(snapshot_path: PathBuf) {
deno_napi::deno_napi::init_ops::<PermissionsContainer>(),
deno_http::deno_http::init_ops(),
deno_io::deno_io::init_ops(Default::default()),
- deno_fs::deno_fs::init_ops::<_, PermissionsContainer>(false, StdFs),
- deno_node::deno_node::init_ops::<PermissionsContainer>(
- None,
- Some(Arc::new(deno_node::RealFs)),
+ deno_fs::deno_fs::init_ops::<PermissionsContainer>(
+ false,
+ Arc::new(deno_fs::RealFs),
),
+ deno_node::deno_node::init_ops::<PermissionsContainer>(None, None),
cli::init_ops_and_esm(), // NOTE: This needs to be init_ops_and_esm!
];
diff --git a/cli/factory.rs b/cli/factory.rs
index 73d0cb8ea..295794a51 100644
--- a/cli/factory.rs
+++ b/cli/factory.rs
@@ -42,6 +42,7 @@ use crate::worker::HasNodeSpecifierChecker;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
+use deno_runtime::deno_fs;
use deno_runtime::deno_node;
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
use deno_runtime::deno_node::NodeResolver;
@@ -553,6 +554,7 @@ impl CliFactory {
let node_code_translator = self.node_code_translator().await?.clone();
let options = self.cli_options().clone();
let main_worker_options = self.create_cli_main_worker_options()?;
+ let fs = Arc::new(deno_fs::RealFs);
let node_fs = self.node_fs().clone();
let root_cert_store_provider = self.root_cert_store_provider().clone();
let node_resolver = self.node_resolver().await?.clone();
@@ -579,6 +581,7 @@ impl CliFactory {
),
)),
root_cert_store_provider.clone(),
+ fs.clone(),
node_fs.clone(),
maybe_inspector_server.clone(),
main_worker_options.clone(),
@@ -610,6 +613,7 @@ impl CliFactory {
),
)),
self.root_cert_store_provider().clone(),
+ Arc::new(deno_fs::RealFs),
self.node_fs().clone(),
self.maybe_inspector_server().clone(),
self.create_cli_main_worker_options()?,
diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs
index 2ef21d417..0f65db679 100644
--- a/cli/standalone/mod.rs
+++ b/cli/standalone/mod.rs
@@ -30,6 +30,7 @@ use deno_core::ModuleSpecifier;
use deno_core::ModuleType;
use deno_core::ResolutionKind;
use deno_graph::source::Resolver;
+use deno_runtime::deno_fs;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_tls::rustls::RootCertStore;
@@ -253,6 +254,7 @@ pub async fn run(
BlobStore::default(),
Box::new(module_loader_factory),
root_cert_store_provider,
+ Arc::new(deno_fs::RealFs),
node_fs,
None,
CliMainWorkerOptions {
diff --git a/cli/worker.rs b/cli/worker.rs
index ae8822fe4..5216af263 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -18,6 +18,7 @@ use deno_core::SharedArrayBufferStore;
use deno_core::SourceMapGetter;
use deno_runtime::colors;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
+use deno_runtime::deno_fs;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::NodeResolver;
@@ -97,6 +98,7 @@ struct SharedWorkerState {
compiled_wasm_module_store: CompiledWasmModuleStore,
module_loader_factory: Box<dyn ModuleLoaderFactory>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
+ fs: Arc<dyn deno_fs::FileSystem>,
node_fs: Arc<dyn deno_node::NodeFs>,
maybe_inspector_server: Option<Arc<InspectorServer>>,
}
@@ -308,6 +310,7 @@ impl CliMainWorkerFactory {
blob_store: BlobStore,
module_loader_factory: Box<dyn ModuleLoaderFactory>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
+ fs: Arc<dyn deno_fs::FileSystem>,
node_fs: Arc<dyn deno_node::NodeFs>,
maybe_inspector_server: Option<Arc<InspectorServer>>,
options: CliMainWorkerOptions,
@@ -325,6 +328,7 @@ impl CliMainWorkerFactory {
compiled_wasm_module_store: Default::default(),
module_loader_factory,
root_cert_store_provider,
+ fs,
node_fs,
maybe_inspector_server,
}),
@@ -445,6 +449,7 @@ impl CliMainWorkerFactory {
should_break_on_first_statement: shared.options.inspect_brk,
should_wait_for_inspector_session: shared.options.inspect_wait,
module_loader,
+ fs: shared.fs.clone(),
node_fs: Some(shared.node_fs.clone()),
npm_resolver: Some(shared.npm_resolver.clone()),
get_error_class_fn: Some(&errors::get_error_class_name),
@@ -570,6 +575,7 @@ fn create_web_worker_callback(
format_js_error_fn: Some(Arc::new(format_js_error)),
source_map_getter: maybe_source_map_getter,
module_loader,
+ fs: shared.fs.clone(),
node_fs: Some(shared.node_fs.clone()),
npm_resolver: Some(shared.npm_resolver.clone()),
worker_type: args.worker_type,
@@ -597,13 +603,8 @@ fn create_web_worker_callback(
#[cfg(test)]
mod tests {
- use std::rc::Rc;
-
use super::*;
use deno_core::resolve_path;
- use deno_core::FsModuleLoader;
- use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
- use deno_runtime::deno_web::BlobStore;
use deno_runtime::permissions::Permissions;
fn create_test_worker() -> MainWorker {
@@ -612,31 +613,8 @@ mod tests {
let permissions = PermissionsContainer::new(Permissions::default());
let options = WorkerOptions {
- bootstrap: BootstrapOptions::default(),
- extensions: vec![],
startup_snapshot: Some(crate::js::deno_isolate_init()),
- unsafely_ignore_certificate_errors: None,
- root_cert_store_provider: None,
- seed: None,
- format_js_error_fn: None,
- source_map_getter: None,
- web_worker_preload_module_cb: Arc::new(|_| unreachable!()),
- web_worker_pre_execute_module_cb: Arc::new(|_| unreachable!()),
- create_web_worker_cb: Arc::new(|_| unreachable!()),
- maybe_inspector_server: None,
- should_break_on_first_statement: false,
- should_wait_for_inspector_session: false,
- module_loader: Rc::new(FsModuleLoader),
- node_fs: Some(Arc::new(deno_node::RealFs)),
- npm_resolver: None,
- get_error_class_fn: None,
- cache_storage_dir: None,
- origin_storage_dir: None,
- blob_store: BlobStore::default(),
- broadcast_channel: InMemoryBroadcastChannel::default(),
- shared_array_buffer_store: None,
- compiled_wasm_module_store: None,
- stdio: Default::default(),
+ ..Default::default()
};
MainWorker::bootstrap_from_options(main_module, permissions, options)
diff --git a/core/resources.rs b/core/resources.rs
index 84e6847fc..94d2a2306 100644
--- a/core/resources.rs
+++ b/core/resources.rs
@@ -187,6 +187,13 @@ pub trait Resource: Any + 'static {
None
}
+ /// Resources backed by a file descriptor can let ops know to allow for
+ /// low-level optimizations.
+ #[cfg(windows)]
+ fn backing_fd(self: Rc<Self>) -> Option<std::os::windows::io::RawHandle> {
+ None
+ }
+
fn size_hint(&self) -> (u64, Option<u64>) {
(0, None)
}
diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml
index 10c71a543..f6d563b64 100644
--- a/ext/fs/Cargo.toml
+++ b/ext/fs/Cargo.toml
@@ -17,8 +17,8 @@ path = "lib.rs"
async-trait.workspace = true
deno_core.workspace = true
deno_io.workspace = true
-filetime = "0.2.16"
-fs3 = "0.5.0"
+filetime.workspace = true
+fs3.workspace = true
libc.workspace = true
log.workspace = true
rand.workspace = true
diff --git a/ext/fs/interface.rs b/ext/fs/interface.rs
index 184cb8096..1847b5982 100644
--- a/ext/fs/interface.rs
+++ b/ext/fs/interface.rs
@@ -1,6 +1,5 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
@@ -8,6 +7,10 @@ use std::rc::Rc;
use serde::Deserialize;
use serde::Serialize;
+use deno_io::fs::File;
+use deno_io::fs::FsResult;
+use deno_io::fs::FsStat;
+
#[derive(Deserialize, Default, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
#[serde(default)]
@@ -52,27 +55,6 @@ impl OpenOptions {
}
}
-pub struct FsStat {
- pub is_file: bool,
- pub is_directory: bool,
- pub is_symlink: bool,
- pub size: u64,
-
- pub mtime: Option<u64>,
- pub atime: Option<u64>,
- pub birthtime: Option<u64>,
-
- pub dev: u64,
- pub ino: u64,
- pub mode: u32,
- pub nlink: u64,
- pub uid: u32,
- pub gid: u32,
- pub rdev: u64,
- pub blksize: u64,
- pub blocks: u64,
-}
-
#[derive(Deserialize)]
pub enum FsFileType {
#[serde(rename = "file")]
@@ -90,93 +72,25 @@ pub struct FsDirEntry {
pub is_symlink: bool,
}
-pub enum FsError {
- Io(io::Error),
- FileBusy,
- NotSupported,
-}
-
-impl From<io::Error> for FsError {
- fn from(err: io::Error) -> Self {
- Self::Io(err)
- }
-}
-
-pub type FsResult<T> = Result<T, FsError>;
-
-#[async_trait::async_trait(?Send)]
-pub trait File {
- fn write_all_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<()>;
- async fn write_all_async(self: Rc<Self>, buf: Vec<u8>) -> FsResult<()>;
-
- fn read_all_sync(self: Rc<Self>) -> FsResult<Vec<u8>>;
- async fn read_all_async(self: Rc<Self>) -> FsResult<Vec<u8>>;
-
- fn chmod_sync(self: Rc<Self>, pathmode: u32) -> FsResult<()>;
- async fn chmod_async(self: Rc<Self>, mode: u32) -> FsResult<()>;
-
- fn seek_sync(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64>;
- async fn seek_async(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64>;
-
- fn datasync_sync(self: Rc<Self>) -> FsResult<()>;
- async fn datasync_async(self: Rc<Self>) -> FsResult<()>;
-
- fn sync_sync(self: Rc<Self>) -> FsResult<()>;
- async fn sync_async(self: Rc<Self>) -> FsResult<()>;
-
- fn stat_sync(self: Rc<Self>) -> FsResult<FsStat>;
- async fn stat_async(self: Rc<Self>) -> FsResult<FsStat>;
-
- fn lock_sync(self: Rc<Self>, exclusive: bool) -> FsResult<()>;
- async fn lock_async(self: Rc<Self>, exclusive: bool) -> FsResult<()>;
- fn unlock_sync(self: Rc<Self>) -> FsResult<()>;
- async fn unlock_async(self: Rc<Self>) -> FsResult<()>;
-
- fn truncate_sync(self: Rc<Self>, len: u64) -> FsResult<()>;
- async fn truncate_async(self: Rc<Self>, len: u64) -> FsResult<()>;
-
- fn utime_sync(
- self: Rc<Self>,
- atime_secs: i64,
- atime_nanos: u32,
- mtime_secs: i64,
- mtime_nanos: u32,
- ) -> FsResult<()>;
- async fn utime_async(
- self: Rc<Self>,
- atime_secs: i64,
- atime_nanos: u32,
- mtime_secs: i64,
- mtime_nanos: u32,
- ) -> FsResult<()>;
-}
-
#[async_trait::async_trait(?Send)]
-pub trait FileSystem: Clone {
- type File: File;
-
+pub trait FileSystem: Send + Sync {
fn cwd(&self) -> FsResult<PathBuf>;
fn tmp_dir(&self) -> FsResult<PathBuf>;
- fn chdir(&self, path: impl AsRef<Path>) -> FsResult<()>;
+ fn chdir(&self, path: &Path) -> FsResult<()>;
fn umask(&self, mask: Option<u32>) -> FsResult<u32>;
fn open_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
options: OpenOptions,
- ) -> FsResult<Self::File>;
+ ) -> FsResult<Rc<dyn File>>;
async fn open_async(
&self,
path: PathBuf,
options: OpenOptions,
- ) -> FsResult<Self::File>;
+ ) -> FsResult<Rc<dyn File>>;
- fn mkdir_sync(
- &self,
- path: impl AsRef<Path>,
- recusive: bool,
- mode: u32,
- ) -> FsResult<()>;
+ fn mkdir_sync(&self, path: &Path, recusive: bool, mode: u32) -> FsResult<()>;
async fn mkdir_async(
&self,
path: PathBuf,
@@ -184,12 +98,12 @@ pub trait FileSystem: Clone {
mode: u32,
) -> FsResult<()>;
- fn chmod_sync(&self, path: impl AsRef<Path>, mode: u32) -> FsResult<()>;
+ fn chmod_sync(&self, path: &Path, mode: u32) -> FsResult<()>;
async fn chmod_async(&self, path: PathBuf, mode: u32) -> FsResult<()>;
fn chown_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
uid: Option<u32>,
gid: Option<u32>,
) -> FsResult<()>;
@@ -200,52 +114,36 @@ pub trait FileSystem: Clone {
gid: Option<u32>,
) -> FsResult<()>;
- fn remove_sync(
- &self,
- path: impl AsRef<Path>,
- recursive: bool,
- ) -> FsResult<()>;
+ fn remove_sync(&self, path: &Path, recursive: bool) -> FsResult<()>;
async fn remove_async(&self, path: PathBuf, recursive: bool) -> FsResult<()>;
- fn copy_file_sync(
- &self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
- ) -> FsResult<()>;
+ fn copy_file_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()>;
async fn copy_file_async(
&self,
oldpath: PathBuf,
newpath: PathBuf,
) -> FsResult<()>;
- fn stat_sync(&self, path: impl AsRef<Path>) -> FsResult<FsStat>;
+ fn stat_sync(&self, path: &Path) -> FsResult<FsStat>;
async fn stat_async(&self, path: PathBuf) -> FsResult<FsStat>;
- fn lstat_sync(&self, path: impl AsRef<Path>) -> FsResult<FsStat>;
+ fn lstat_sync(&self, path: &Path) -> FsResult<FsStat>;
async fn lstat_async(&self, path: PathBuf) -> FsResult<FsStat>;
- fn realpath_sync(&self, path: impl AsRef<Path>) -> FsResult<PathBuf>;
+ fn realpath_sync(&self, path: &Path) -> FsResult<PathBuf>;
async fn realpath_async(&self, path: PathBuf) -> FsResult<PathBuf>;
- fn read_dir_sync(&self, path: impl AsRef<Path>) -> FsResult<Vec<FsDirEntry>>;
+ fn read_dir_sync(&self, path: &Path) -> FsResult<Vec<FsDirEntry>>;
async fn read_dir_async(&self, path: PathBuf) -> FsResult<Vec<FsDirEntry>>;
- fn rename_sync(
- &self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
- ) -> FsResult<()>;
+ fn rename_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()>;
async fn rename_async(
&self,
oldpath: PathBuf,
newpath: PathBuf,
) -> FsResult<()>;
- fn link_sync(
- &self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
- ) -> FsResult<()>;
+ fn link_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()>;
async fn link_async(
&self,
oldpath: PathBuf,
@@ -254,8 +152,8 @@ pub trait FileSystem: Clone {
fn symlink_sync(
&self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
+ oldpath: &Path,
+ newpath: &Path,
file_type: Option<FsFileType>,
) -> FsResult<()>;
async fn symlink_async(
@@ -265,15 +163,15 @@ pub trait FileSystem: Clone {
file_type: Option<FsFileType>,
) -> FsResult<()>;
- fn read_link_sync(&self, path: impl AsRef<Path>) -> FsResult<PathBuf>;
+ fn read_link_sync(&self, path: &Path) -> FsResult<PathBuf>;
async fn read_link_async(&self, path: PathBuf) -> FsResult<PathBuf>;
- fn truncate_sync(&self, path: impl AsRef<Path>, len: u64) -> FsResult<()>;
+ fn truncate_sync(&self, path: &Path, len: u64) -> FsResult<()>;
async fn truncate_async(&self, path: PathBuf, len: u64) -> FsResult<()>;
fn utime_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
atime_secs: i64,
atime_nanos: u32,
mtime_secs: i64,
@@ -290,12 +188,11 @@ pub trait FileSystem: Clone {
fn write_file_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
options: OpenOptions,
data: &[u8],
) -> FsResult<()> {
let file = self.open_sync(path, options)?;
- let file = Rc::new(file);
if let Some(mode) = options.mode {
file.clone().chmod_sync(mode)?;
}
@@ -309,25 +206,22 @@ pub trait FileSystem: Clone {
data: Vec<u8>,
) -> FsResult<()> {
let file = self.open_async(path, options).await?;
- let file = Rc::new(file);
if let Some(mode) = options.mode {
file.clone().chmod_async(mode).await?;
}
- file.write_all_async(data).await?;
+ file.write_all(data.into()).await?;
Ok(())
}
- fn read_file_sync(&self, path: impl AsRef<Path>) -> FsResult<Vec<u8>> {
+ fn read_file_sync(&self, path: &Path) -> FsResult<Vec<u8>> {
let options = OpenOptions::read();
let file = self.open_sync(path, options)?;
- let file = Rc::new(file);
let buf = file.read_all_sync()?;
Ok(buf)
}
async fn read_file_async(&self, path: PathBuf) -> FsResult<Vec<u8>> {
let options = OpenOptions::read();
- let file = self.clone().open_async(path, options).await?;
- let file = Rc::new(file);
+ let file = self.open_async(path, options).await?;
let buf = file.read_all_async().await?;
Ok(buf)
}
diff --git a/ext/fs/lib.rs b/ext/fs/lib.rs
index 464d84ade..4fdf6b3f1 100644
--- a/ext/fs/lib.rs
+++ b/ext/fs/lib.rs
@@ -4,25 +4,21 @@ mod interface;
mod ops;
mod std_fs;
-pub use crate::interface::File;
pub use crate::interface::FileSystem;
pub use crate::interface::FsDirEntry;
-pub use crate::interface::FsError;
pub use crate::interface::FsFileType;
-pub use crate::interface::FsResult;
-pub use crate::interface::FsStat;
pub use crate::interface::OpenOptions;
use crate::ops::*;
-pub use crate::std_fs::StdFs;
+pub use crate::std_fs::RealFs;
use deno_core::error::AnyError;
use deno_core::OpState;
-use deno_core::Resource;
use std::cell::RefCell;
use std::convert::From;
use std::path::Path;
use std::rc::Rc;
+use std::sync::Arc;
pub trait FsPermissions {
fn check_read(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
@@ -87,78 +83,77 @@ pub(crate) fn check_unstable2(state: &Rc<RefCell<OpState>>, api_name: &str) {
deno_core::extension!(deno_fs,
deps = [ deno_web ],
- parameters = [Fs: FileSystem, P: FsPermissions],
- bounds = [Fs::File: Resource],
+ parameters = [P: FsPermissions],
ops = [
- op_cwd<Fs, P>,
- op_umask<Fs>,
- op_chdir<Fs, P>,
+ op_cwd<P>,
+ op_umask,
+ op_chdir<P>,
- op_open_sync<Fs, P>,
- op_open_async<Fs, P>,
- op_mkdir_sync<Fs, P>,
- op_mkdir_async<Fs, P>,
- op_chmod_sync<Fs, P>,
- op_chmod_async<Fs, P>,
- op_chown_sync<Fs, P>,
- op_chown_async<Fs, P>,
- op_remove_sync<Fs, P>,
- op_remove_async<Fs, P>,
- op_copy_file_sync<Fs, P>,
- op_copy_file_async<Fs, P>,
- op_stat_sync<Fs, P>,
- op_stat_async<Fs, P>,
- op_lstat_sync<Fs, P>,
- op_lstat_async<Fs, P>,
- op_realpath_sync<Fs, P>,
- op_realpath_async<Fs, P>,
- op_read_dir_sync<Fs, P>,
- op_read_dir_async<Fs, P>,
- op_rename_sync<Fs, P>,
- op_rename_async<Fs, P>,
- op_link_sync<Fs, P>,
- op_link_async<Fs, P>,
- op_symlink_sync<Fs, P>,
- op_symlink_async<Fs, P>,
- op_read_link_sync<Fs, P>,
- op_read_link_async<Fs, P>,
- op_truncate_sync<Fs, P>,
- op_truncate_async<Fs, P>,
- op_utime_sync<Fs, P>,
- op_utime_async<Fs, P>,
- op_make_temp_dir_sync<Fs, P>,
- op_make_temp_dir_async<Fs, P>,
- op_make_temp_file_sync<Fs, P>,
- op_make_temp_file_async<Fs, P>,
- op_write_file_sync<Fs, P>,
- op_write_file_async<Fs, P>,
- op_read_file_sync<Fs, P>,
- op_read_file_async<Fs, P>,
- op_read_file_text_sync<Fs, P>,
- op_read_file_text_async<Fs, P>,
+ op_open_sync<P>,
+ op_open_async<P>,
+ op_mkdir_sync<P>,
+ op_mkdir_async<P>,
+ op_chmod_sync<P>,
+ op_chmod_async<P>,
+ op_chown_sync<P>,
+ op_chown_async<P>,
+ op_remove_sync<P>,
+ op_remove_async<P>,
+ op_copy_file_sync<P>,
+ op_copy_file_async<P>,
+ op_stat_sync<P>,
+ op_stat_async<P>,
+ op_lstat_sync<P>,
+ op_lstat_async<P>,
+ op_realpath_sync<P>,
+ op_realpath_async<P>,
+ op_read_dir_sync<P>,
+ op_read_dir_async<P>,
+ op_rename_sync<P>,
+ op_rename_async<P>,
+ op_link_sync<P>,
+ op_link_async<P>,
+ op_symlink_sync<P>,
+ op_symlink_async<P>,
+ op_read_link_sync<P>,
+ op_read_link_async<P>,
+ op_truncate_sync<P>,
+ op_truncate_async<P>,
+ op_utime_sync<P>,
+ op_utime_async<P>,
+ op_make_temp_dir_sync<P>,
+ op_make_temp_dir_async<P>,
+ op_make_temp_file_sync<P>,
+ op_make_temp_file_async<P>,
+ op_write_file_sync<P>,
+ op_write_file_async<P>,
+ op_read_file_sync<P>,
+ op_read_file_async<P>,
+ op_read_file_text_sync<P>,
+ op_read_file_text_async<P>,
- op_seek_sync<Fs>,
- op_seek_async<Fs>,
- op_fdatasync_sync<Fs>,
- op_fdatasync_async<Fs>,
- op_fsync_sync<Fs>,
- op_fsync_async<Fs>,
- op_fstat_sync<Fs>,
- op_fstat_async<Fs>,
- op_flock_sync<Fs>,
- op_flock_async<Fs>,
- op_funlock_sync<Fs>,
- op_funlock_async<Fs>,
- op_ftruncate_sync<Fs>,
- op_ftruncate_async<Fs>,
- op_futime_sync<Fs>,
- op_futime_async<Fs>,
+ op_seek_sync,
+ op_seek_async,
+ op_fdatasync_sync,
+ op_fdatasync_async,
+ op_fsync_sync,
+ op_fsync_async,
+ op_fstat_sync,
+ op_fstat_async,
+ op_flock_sync,
+ op_flock_async,
+ op_funlock_sync,
+ op_funlock_async,
+ op_ftruncate_sync,
+ op_ftruncate_async,
+ op_futime_sync,
+ op_futime_async,
],
esm = [ "30_fs.js" ],
options = {
unstable: bool,
- fs: Fs,
+ fs: Arc<dyn FileSystem>,
},
state = |state, options| {
state.put(UnstableChecker { unstable: options.unstable });
diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs
index 8c5d21201..c9996d8ce 100644
--- a/ext/fs/ops.rs
+++ b/ext/fs/ops.rs
@@ -7,65 +7,39 @@ use std::io::SeekFrom;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
+use std::sync::Arc;
use deno_core::error::custom_error;
-use deno_core::error::not_supported;
-use deno_core::error::resource_unavailable;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
use deno_core::OpState;
-use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
+use deno_io::fs::FileResource;
+use deno_io::fs::FsError;
+use deno_io::fs::FsStat;
use rand::rngs::ThreadRng;
use rand::thread_rng;
use rand::Rng;
use serde::Serialize;
-use tokio::task::JoinError;
use crate::check_unstable;
use crate::check_unstable2;
use crate::interface::FsDirEntry;
-use crate::interface::FsError;
use crate::interface::FsFileType;
-use crate::interface::FsStat;
-use crate::File;
use crate::FileSystem;
use crate::FsPermissions;
use crate::OpenOptions;
-impl From<JoinError> for FsError {
- fn from(err: JoinError) -> Self {
- if err.is_cancelled() {
- todo!("async tasks must not be cancelled")
- }
- if err.is_panic() {
- std::panic::resume_unwind(err.into_panic()); // resume the panic on the main thread
- }
- unreachable!()
- }
-}
-
-impl From<FsError> for AnyError {
- fn from(err: FsError) -> Self {
- match err {
- FsError::Io(err) => AnyError::from(err),
- FsError::FileBusy => resource_unavailable(),
- FsError::NotSupported => not_supported(),
- }
- }
-}
-
#[op]
-pub fn op_cwd<Fs, P>(state: &mut OpState) -> Result<String, AnyError>
+pub fn op_cwd<P>(state: &mut OpState) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
let path = fs.cwd()?;
state
.borrow_mut::<P>()
@@ -75,34 +49,36 @@ where
}
#[op]
-fn op_chdir<Fs, P>(state: &mut OpState, directory: &str) -> Result<(), AnyError>
+fn op_chdir<P>(state: &mut OpState, directory: &str) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let d = PathBuf::from(&directory);
state.borrow_mut::<P>().check_read(&d, "Deno.chdir()")?;
- state.borrow::<Fs>().chdir(&d).context_path("chdir", &d)
+ state
+ .borrow::<Arc<dyn FileSystem>>()
+ .chdir(&d)
+ .context_path("chdir", &d)
}
#[op]
-fn op_umask<Fs>(state: &mut OpState, mask: Option<u32>) -> Result<u32, AnyError>
+fn op_umask(state: &mut OpState, mask: Option<u32>) -> Result<u32, AnyError>
where
- Fs: FileSystem + 'static,
{
check_unstable(state, "Deno.umask");
- state.borrow::<Fs>().umask(mask).context("umask")
+ state
+ .borrow::<Arc<dyn FileSystem>>()
+ .umask(mask)
+ .context("umask")
}
#[op]
-fn op_open_sync<Fs, P>(
+fn op_open_sync<P>(
state: &mut OpState,
path: String,
options: Option<OpenOptions>,
) -> Result<ResourceId, AnyError>
where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -111,22 +87,22 @@ where
let permissions = state.borrow_mut::<P>();
permissions.check(&options, &path, "Deno.openSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
let file = fs.open_sync(&path, options).context_path("open", &path)?;
- let rid = state.resource_table.add(file);
+ let rid = state
+ .resource_table
+ .add(FileResource::new(file, "fsFile".to_string()));
Ok(rid)
}
#[op]
-async fn op_open_async<Fs, P>(
+async fn op_open_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
options: Option<OpenOptions>,
) -> Result<ResourceId, AnyError>
where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -136,26 +112,28 @@ where
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
permissions.check(&options, &path, "Deno.open()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
let file = fs
.open_async(path.clone(), options)
.await
.context_path("open", &path)?;
- let rid = state.borrow_mut().resource_table.add(file);
+ let rid = state
+ .borrow_mut()
+ .resource_table
+ .add(FileResource::new(file, "fsFile".to_string()));
Ok(rid)
}
#[op]
-fn op_mkdir_sync<Fs, P>(
+fn op_mkdir_sync<P>(
state: &mut OpState,
path: String,
recursive: bool,
mode: Option<u32>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -166,7 +144,7 @@ where
.borrow_mut::<P>()
.check_write(&path, "Deno.mkdirSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.mkdir_sync(&path, recursive, mode)
.context_path("mkdir", &path)?;
@@ -174,14 +152,13 @@ where
}
#[op]
-async fn op_mkdir_async<Fs, P>(
+async fn op_mkdir_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
recursive: bool,
mode: Option<u32>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -191,7 +168,7 @@ where
let fs = {
let mut state = state.borrow_mut();
state.borrow_mut::<P>().check_write(&path, "Deno.mkdir()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.mkdir_async(path.clone(), recursive, mode)
@@ -202,39 +179,37 @@ where
}
#[op]
-fn op_chmod_sync<Fs, P>(
+fn op_chmod_sync<P>(
state: &mut OpState,
path: String,
mode: u32,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
state
.borrow_mut::<P>()
.check_write(&path, "Deno.chmodSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.chmod_sync(&path, mode).context_path("chmod", &path)?;
Ok(())
}
#[op]
-async fn op_chmod_async<Fs, P>(
+async fn op_chmod_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
mode: u32,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
let fs = {
let mut state = state.borrow_mut();
state.borrow_mut::<P>().check_write(&path, "Deno.chmod()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.chmod_async(path.clone(), mode)
.await
@@ -243,42 +218,40 @@ where
}
#[op]
-fn op_chown_sync<Fs, P>(
+fn op_chown_sync<P>(
state: &mut OpState,
path: String,
uid: Option<u32>,
gid: Option<u32>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
state
.borrow_mut::<P>()
.check_write(&path, "Deno.chownSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.chown_sync(&path, uid, gid)
.context_path("chown", &path)?;
Ok(())
}
#[op]
-async fn op_chown_async<Fs, P>(
+async fn op_chown_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
uid: Option<u32>,
gid: Option<u32>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
let fs = {
let mut state = state.borrow_mut();
state.borrow_mut::<P>().check_write(&path, "Deno.chown()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.chown_async(path.clone(), uid, gid)
.await
@@ -287,13 +260,12 @@ where
}
#[op]
-fn op_remove_sync<Fs, P>(
+fn op_remove_sync<P>(
state: &mut OpState,
path: &str,
recursive: bool,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -302,7 +274,7 @@ where
.borrow_mut::<P>()
.check_write(&path, "Deno.removeSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.remove_sync(&path, recursive)
.context_path("remove", &path)?;
@@ -310,13 +282,12 @@ where
}
#[op]
-async fn op_remove_async<Fs, P>(
+async fn op_remove_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
recursive: bool,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -326,7 +297,7 @@ where
state
.borrow_mut::<P>()
.check_write(&path, "Deno.remove()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.remove_async(path.clone(), recursive)
@@ -337,13 +308,12 @@ where
}
#[op]
-fn op_copy_file_sync<Fs, P>(
+fn op_copy_file_sync<P>(
state: &mut OpState,
from: &str,
to: &str,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let from = PathBuf::from(from);
@@ -353,7 +323,7 @@ where
permissions.check_read(&from, "Deno.copyFileSync()")?;
permissions.check_write(&to, "Deno.copyFileSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.copy_file_sync(&from, &to)
.context_two_path("copy", &from, &to)?;
@@ -361,13 +331,12 @@ where
}
#[op]
-async fn op_copy_file_async<Fs, P>(
+async fn op_copy_file_async<P>(
state: Rc<RefCell<OpState>>,
from: String,
to: String,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let from = PathBuf::from(from);
@@ -378,7 +347,7 @@ where
let permissions = state.borrow_mut::<P>();
permissions.check_read(&from, "Deno.copyFile()")?;
permissions.check_write(&to, "Deno.copyFile()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.copy_file_async(from.clone(), to.clone())
@@ -389,20 +358,19 @@ where
}
#[op]
-fn op_stat_sync<Fs, P>(
+fn op_stat_sync<P>(
state: &mut OpState,
path: String,
stat_out_buf: &mut [u32],
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
state
.borrow_mut::<P>()
.check_read(&path, "Deno.statSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
let stat = fs.stat_sync(&path).context_path("stat", &path)?;
let serializable_stat = SerializableStat::from(stat);
serializable_stat.write(stat_out_buf);
@@ -410,12 +378,11 @@ where
}
#[op]
-async fn op_stat_async<Fs, P>(
+async fn op_stat_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
) -> Result<SerializableStat, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -423,7 +390,7 @@ where
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
permissions.check_read(&path, "Deno.stat()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
let stat = fs
.stat_async(path.clone())
@@ -433,20 +400,19 @@ where
}
#[op]
-fn op_lstat_sync<Fs, P>(
+fn op_lstat_sync<P>(
state: &mut OpState,
path: String,
stat_out_buf: &mut [u32],
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
state
.borrow_mut::<P>()
.check_read(&path, "Deno.lstatSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
let stat = fs.lstat_sync(&path).context_path("lstat", &path)?;
let serializable_stat = SerializableStat::from(stat);
serializable_stat.write(stat_out_buf);
@@ -454,12 +420,11 @@ where
}
#[op]
-async fn op_lstat_async<Fs, P>(
+async fn op_lstat_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
) -> Result<SerializableStat, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -467,7 +432,7 @@ where
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
permissions.check_read(&path, "Deno.lstat()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
let stat = fs
.lstat_async(path.clone())
@@ -477,17 +442,16 @@ where
}
#[op]
-fn op_realpath_sync<Fs, P>(
+fn op_realpath_sync<P>(
state: &mut OpState,
path: String,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
- let fs = state.borrow::<Fs>().clone();
+ let fs = state.borrow::<Arc<dyn FileSystem>>().clone();
let permissions = state.borrow_mut::<P>();
permissions.check_read(&path, "Deno.realPathSync()")?;
if path.is_relative() {
@@ -502,12 +466,11 @@ where
}
#[op]
-async fn op_realpath_async<Fs, P>(
+async fn op_realpath_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -515,7 +478,7 @@ where
let fs;
{
let mut state = state.borrow_mut();
- fs = state.borrow::<Fs>().clone();
+ fs = state.borrow::<Arc<dyn FileSystem>>().clone();
let permissions = state.borrow_mut::<P>();
permissions.check_read(&path, "Deno.realPath()")?;
if path.is_relative() {
@@ -532,12 +495,11 @@ where
}
#[op]
-fn op_read_dir_sync<Fs, P>(
+fn op_read_dir_sync<P>(
state: &mut OpState,
path: String,
) -> Result<Vec<FsDirEntry>, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -546,19 +508,18 @@ where
.borrow_mut::<P>()
.check_read(&path, "Deno.readDirSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
let entries = fs.read_dir_sync(&path).context_path("readdir", &path)?;
Ok(entries)
}
#[op]
-async fn op_read_dir_async<Fs, P>(
+async fn op_read_dir_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
) -> Result<Vec<FsDirEntry>, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -568,7 +529,7 @@ where
state
.borrow_mut::<P>()
.check_read(&path, "Deno.readDir()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
let entries = fs
@@ -580,13 +541,12 @@ where
}
#[op]
-fn op_rename_sync<Fs, P>(
+fn op_rename_sync<P>(
state: &mut OpState,
oldpath: String,
newpath: String,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let oldpath = PathBuf::from(oldpath);
@@ -597,7 +557,7 @@ where
permissions.check_write(&oldpath, "Deno.renameSync()")?;
permissions.check_write(&newpath, "Deno.renameSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.rename_sync(&oldpath, &newpath)
.context_two_path("rename", &oldpath, &newpath)?;
@@ -605,13 +565,12 @@ where
}
#[op]
-async fn op_rename_async<Fs, P>(
+async fn op_rename_async<P>(
state: Rc<RefCell<OpState>>,
oldpath: String,
newpath: String,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let oldpath = PathBuf::from(oldpath);
@@ -623,7 +582,7 @@ where
permissions.check_read(&oldpath, "Deno.rename()")?;
permissions.check_write(&oldpath, "Deno.rename()")?;
permissions.check_write(&newpath, "Deno.rename()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.rename_async(oldpath.clone(), newpath.clone())
@@ -634,13 +593,12 @@ where
}
#[op]
-fn op_link_sync<Fs, P>(
+fn op_link_sync<P>(
state: &mut OpState,
oldpath: &str,
newpath: &str,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let oldpath = PathBuf::from(oldpath);
@@ -652,7 +610,7 @@ where
permissions.check_read(&newpath, "Deno.linkSync()")?;
permissions.check_write(&newpath, "Deno.linkSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.link_sync(&oldpath, &newpath)
.context_two_path("link", &oldpath, &newpath)?;
@@ -660,13 +618,12 @@ where
}
#[op]
-async fn op_link_async<Fs, P>(
+async fn op_link_async<P>(
state: Rc<RefCell<OpState>>,
oldpath: String,
newpath: String,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let oldpath = PathBuf::from(&oldpath);
@@ -679,7 +636,7 @@ where
permissions.check_write(&oldpath, "Deno.link()")?;
permissions.check_read(&newpath, "Deno.link()")?;
permissions.check_write(&newpath, "Deno.link()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.link_async(oldpath.clone(), newpath.clone())
@@ -690,14 +647,13 @@ where
}
#[op]
-fn op_symlink_sync<Fs, P>(
+fn op_symlink_sync<P>(
state: &mut OpState,
oldpath: &str,
newpath: &str,
file_type: Option<FsFileType>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let oldpath = PathBuf::from(oldpath);
@@ -707,7 +663,7 @@ where
permissions.check_write_all("Deno.symlinkSync()")?;
permissions.check_read_all("Deno.symlinkSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.symlink_sync(&oldpath, &newpath, file_type)
.context_two_path("symlink", &oldpath, &newpath)?;
@@ -715,14 +671,13 @@ where
}
#[op]
-async fn op_symlink_async<Fs, P>(
+async fn op_symlink_async<P>(
state: Rc<RefCell<OpState>>,
oldpath: String,
newpath: String,
file_type: Option<FsFileType>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let oldpath = PathBuf::from(&oldpath);
@@ -733,7 +688,7 @@ where
let permissions = state.borrow_mut::<P>();
permissions.check_write_all("Deno.symlink()")?;
permissions.check_read_all("Deno.symlink()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.symlink_async(oldpath.clone(), newpath.clone(), file_type)
@@ -744,12 +699,11 @@ where
}
#[op]
-fn op_read_link_sync<Fs, P>(
+fn op_read_link_sync<P>(
state: &mut OpState,
path: String,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -758,7 +712,7 @@ where
.borrow_mut::<P>()
.check_read(&path, "Deno.readLink()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
let target = fs.read_link_sync(&path).context_path("readlink", &path)?;
let target_string = path_into_string(target.into_os_string())?;
@@ -766,12 +720,11 @@ where
}
#[op]
-async fn op_read_link_async<Fs, P>(
+async fn op_read_link_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -781,7 +734,7 @@ where
state
.borrow_mut::<P>()
.check_read(&path, "Deno.readLink()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
let target = fs
@@ -793,13 +746,12 @@ where
}
#[op]
-fn op_truncate_sync<Fs, P>(
+fn op_truncate_sync<P>(
state: &mut OpState,
path: &str,
len: u64,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -808,7 +760,7 @@ where
.borrow_mut::<P>()
.check_write(&path, "Deno.truncateSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.truncate_sync(&path, len)
.context_path("truncate", &path)?;
@@ -816,13 +768,12 @@ where
}
#[op]
-async fn op_truncate_async<Fs, P>(
+async fn op_truncate_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
len: u64,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -832,7 +783,7 @@ where
state
.borrow_mut::<P>()
.check_write(&path, "Deno.truncate()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.truncate_async(path.clone(), len)
@@ -843,7 +794,7 @@ where
}
#[op]
-fn op_utime_sync<Fs, P>(
+fn op_utime_sync<P>(
state: &mut OpState,
path: &str,
atime_secs: i64,
@@ -852,14 +803,13 @@ fn op_utime_sync<Fs, P>(
mtime_nanos: u32,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
.context_path("utime", &path)?;
@@ -867,7 +817,7 @@ where
}
#[op]
-async fn op_utime_async<Fs, P>(
+async fn op_utime_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
atime_secs: i64,
@@ -876,7 +826,6 @@ async fn op_utime_async<Fs, P>(
mtime_nanos: u32,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -884,7 +833,7 @@ where
let fs = {
let mut state = state.borrow_mut();
state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
- state.borrow::<Fs>().clone()
+ state.borrow::<Arc<dyn FileSystem>>().clone()
};
fs.utime_async(
@@ -901,17 +850,16 @@ where
}
#[op]
-fn op_make_temp_dir_sync<Fs, P>(
+fn op_make_temp_dir_sync<P>(
state: &mut OpState,
dir: Option<String>,
prefix: Option<String>,
suffix: Option<String>,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
- let (dir, fs) = make_temp_check_sync::<Fs, P>(state, dir)?;
+ let (dir, fs) = make_temp_check_sync::<P>(state, dir)?;
let mut rng = thread_rng();
@@ -935,17 +883,16 @@ where
}
#[op]
-async fn op_make_temp_dir_async<Fs, P>(
+async fn op_make_temp_dir_async<P>(
state: Rc<RefCell<OpState>>,
dir: Option<String>,
prefix: Option<String>,
suffix: Option<String>,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
- let (dir, fs) = make_temp_check_async::<Fs, P>(state, dir)?;
+ let (dir, fs) = make_temp_check_async::<P>(state, dir)?;
let mut rng = thread_rng();
@@ -969,17 +916,16 @@ where
}
#[op]
-fn op_make_temp_file_sync<Fs, P>(
+fn op_make_temp_file_sync<P>(
state: &mut OpState,
dir: Option<String>,
prefix: Option<String>,
suffix: Option<String>,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
- let (dir, fs) = make_temp_check_sync::<Fs, P>(state, dir)?;
+ let (dir, fs) = make_temp_check_sync::<P>(state, dir)?;
let open_opts = OpenOptions {
write: true,
@@ -1010,17 +956,16 @@ where
}
#[op]
-async fn op_make_temp_file_async<Fs, P>(
+async fn op_make_temp_file_async<P>(
state: Rc<RefCell<OpState>>,
dir: Option<String>,
prefix: Option<String>,
suffix: Option<String>,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
- let (dir, fs) = make_temp_check_async::<Fs, P>(state, dir)?;
+ let (dir, fs) = make_temp_check_async::<P>(state, dir)?;
let open_opts = OpenOptions {
write: true,
@@ -1049,15 +994,14 @@ where
.context("tmpfile")
}
-fn make_temp_check_sync<Fs, P>(
+fn make_temp_check_sync<P>(
state: &mut OpState,
dir: Option<String>,
-) -> Result<(PathBuf, Fs), AnyError>
+) -> Result<(PathBuf, Arc<dyn FileSystem>), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
- let fs = state.borrow::<Fs>().clone();
+ let fs = state.borrow::<Arc<dyn FileSystem>>().clone();
let dir = match dir {
Some(dir) => {
let dir = PathBuf::from(dir);
@@ -1079,16 +1023,15 @@ where
Ok((dir, fs))
}
-fn make_temp_check_async<Fs, P>(
+fn make_temp_check_async<P>(
state: Rc<RefCell<OpState>>,
dir: Option<String>,
-) -> Result<(PathBuf, Fs), AnyError>
+) -> Result<(PathBuf, Arc<dyn FileSystem>), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let mut state = state.borrow_mut();
- let fs = state.borrow::<Fs>().clone();
+ let fs = state.borrow::<Arc<dyn FileSystem>>().clone();
let dir = match dir {
Some(dir) => {
let dir = PathBuf::from(dir);
@@ -1128,7 +1071,7 @@ fn tmp_name(
}
#[op]
-fn op_write_file_sync<Fs, P>(
+fn op_write_file_sync<P>(
state: &mut OpState,
path: String,
mode: Option<u32>,
@@ -1138,7 +1081,6 @@ fn op_write_file_sync<Fs, P>(
data: ZeroCopyBuf,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -1147,7 +1089,7 @@ where
let options = OpenOptions::write(create, append, create_new, mode);
permissions.check(&options, &path, "Deno.writeFileSync()")?;
- let fs = state.borrow::<Fs>();
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
fs.write_file_sync(&path, options, &data)
.context_path("writefile", &path)?;
@@ -1156,7 +1098,7 @@ where
}
#[op]
-async fn op_write_file_async<Fs, P>(
+async fn op_write_file_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
mode: Option<u32>,
@@ -1167,7 +1109,6 @@ async fn op_write_file_async<Fs, P>(
cancel_rid: Option<ResourceId>,
) -> Result<(), AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -1180,7 +1121,7 @@ where
permissions.check(&options, &path, "Deno.writeFile()")?;
let cancel_handle = cancel_rid
.and_then(|rid| state.resource_table.get::<CancelHandle>(rid).ok());
- (state.borrow::<Fs>().clone(), cancel_handle)
+ (state.borrow::<Arc<dyn FileSystem>>().clone(), cancel_handle)
};
let fut = fs.write_file_async(path.clone(), options, data.to_vec());
@@ -1201,12 +1142,11 @@ where
}
#[op]
-fn op_read_file_sync<Fs, P>(
+fn op_read_file_sync<P>(
state: &mut OpState,
path: String,
) -> Result<ZeroCopyBuf, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -1214,20 +1154,19 @@ where
let permissions = state.borrow_mut::<P>();
permissions.check_read(&path, "Deno.readFileSync()")?;
- let fs = state.borrow::<Fs>();
- let buf = fs.read_file_sync(path).context("readfile")?;
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
+ let buf = fs.read_file_sync(&path).context("readfile")?;
Ok(buf.into())
}
#[op]
-async fn op_read_file_async<Fs, P>(
+async fn op_read_file_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
cancel_rid: Option<ResourceId>,
) -> Result<ZeroCopyBuf, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -1238,7 +1177,7 @@ where
permissions.check_read(&path, "Deno.readFile()")?;
let cancel_handle = cancel_rid
.and_then(|rid| state.resource_table.get::<CancelHandle>(rid).ok());
- (state.borrow::<Fs>().clone(), cancel_handle)
+ (state.borrow::<Arc<dyn FileSystem>>().clone(), cancel_handle)
};
let fut = fs.read_file_async(path.clone());
@@ -1259,12 +1198,11 @@ where
}
#[op]
-fn op_read_file_text_sync<Fs, P>(
+fn op_read_file_text_sync<P>(
state: &mut OpState,
path: String,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -1272,20 +1210,19 @@ where
let permissions = state.borrow_mut::<P>();
permissions.check_read(&path, "Deno.readFileSync()")?;
- let fs = state.borrow::<Fs>();
- let buf = fs.read_file_sync(path).context("readfile")?;
+ let fs = state.borrow::<Arc<dyn FileSystem>>();
+ let buf = fs.read_file_sync(&path).context("readfile")?;
Ok(string_from_utf8_lossy(buf))
}
#[op]
-async fn op_read_file_text_async<Fs, P>(
+async fn op_read_file_text_async<P>(
state: Rc<RefCell<OpState>>,
path: String,
cancel_rid: Option<ResourceId>,
) -> Result<String, AnyError>
where
- Fs: FileSystem + 'static,
P: FsPermissions + 'static,
{
let path = PathBuf::from(path);
@@ -1296,7 +1233,7 @@ where
permissions.check_read(&path, "Deno.readFile()")?;
let cancel_handle = cancel_rid
.and_then(|rid| state.resource_table.get::<CancelHandle>(rid).ok());
- (state.borrow::<Fs>().clone(), cancel_handle)
+ (state.borrow::<Arc<dyn FileSystem>>().clone(), cancel_handle)
};
let fut = fs.read_file_async(path.clone());
@@ -1340,106 +1277,75 @@ fn to_seek_from(offset: i64, whence: i32) -> Result<SeekFrom, AnyError> {
}
#[op]
-fn op_seek_sync<Fs>(
+fn op_seek_sync(
state: &mut OpState,
rid: ResourceId,
offset: i64,
whence: i32,
-) -> Result<u64, AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
+) -> Result<u64, AnyError> {
let pos = to_seek_from(offset, whence)?;
- let file = state.resource_table.get::<Fs::File>(rid)?;
+ let file = FileResource::get_file(state, rid)?;
let cursor = file.seek_sync(pos)?;
Ok(cursor)
}
#[op]
-async fn op_seek_async<Fs>(
+async fn op_seek_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
offset: i64,
whence: i32,
-) -> Result<u64, AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
+) -> Result<u64, AnyError> {
let pos = to_seek_from(offset, whence)?;
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+ let file = FileResource::get_file(&state.borrow(), rid)?;
let cursor = file.seek_async(pos).await?;
Ok(cursor)
}
#[op]
-fn op_fdatasync_sync<Fs>(
+fn op_fdatasync_sync(
state: &mut OpState,
rid: ResourceId,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(state, rid)?;
file.datasync_sync()?;
Ok(())
}
#[op]
-async fn op_fdatasync_async<Fs>(
+async fn op_fdatasync_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(&state.borrow(), rid)?;
file.datasync_async().await?;
Ok(())
}
#[op]
-fn op_fsync_sync<Fs>(
- state: &mut OpState,
- rid: ResourceId,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.resource_table.get::<Fs::File>(rid)?;
+fn op_fsync_sync(state: &mut OpState, rid: ResourceId) -> Result<(), AnyError> {
+ let file = FileResource::get_file(state, rid)?;
file.sync_sync()?;
Ok(())
}
#[op]
-async fn op_fsync_async<Fs>(
+async fn op_fsync_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(&state.borrow(), rid)?;
file.sync_async().await?;
Ok(())
}
#[op]
-fn op_fstat_sync<Fs>(
+fn op_fstat_sync(
state: &mut OpState,
rid: ResourceId,
stat_out_buf: &mut [u32],
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(state, rid)?;
let stat = file.stat_sync()?;
let serializable_stat = SerializableStat::from(stat);
serializable_stat.write(stat_out_buf);
@@ -1447,143 +1353,107 @@ where
}
#[op]
-async fn op_fstat_async<Fs>(
+async fn op_fstat_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
-) -> Result<SerializableStat, AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+) -> Result<SerializableStat, AnyError> {
+ let file = FileResource::get_file(&state.borrow(), rid)?;
let stat = file.stat_async().await?;
Ok(stat.into())
}
#[op]
-fn op_flock_sync<Fs>(
+fn op_flock_sync(
state: &mut OpState,
rid: ResourceId,
exclusive: bool,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
+) -> Result<(), AnyError> {
check_unstable(state, "Deno.flockSync");
- let file = state.resource_table.get::<Fs::File>(rid)?;
+ let file = FileResource::get_file(state, rid)?;
file.lock_sync(exclusive)?;
Ok(())
}
#[op]
-async fn op_flock_async<Fs>(
+async fn op_flock_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
exclusive: bool,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
+) -> Result<(), AnyError> {
check_unstable2(&state, "Deno.flock");
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+ let file = FileResource::get_file(&state.borrow(), rid)?;
file.lock_async(exclusive).await?;
Ok(())
}
#[op]
-fn op_funlock_sync<Fs>(
+fn op_funlock_sync(
state: &mut OpState,
rid: ResourceId,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
+) -> Result<(), AnyError> {
check_unstable(state, "Deno.funlockSync");
- let file = state.resource_table.get::<Fs::File>(rid)?;
+ let file = FileResource::get_file(state, rid)?;
file.unlock_sync()?;
Ok(())
}
#[op]
-async fn op_funlock_async<Fs>(
+async fn op_funlock_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
+) -> Result<(), AnyError> {
check_unstable2(&state, "Deno.funlock");
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+ let file = FileResource::get_file(&state.borrow(), rid)?;
file.unlock_async().await?;
Ok(())
}
#[op]
-fn op_ftruncate_sync<Fs>(
+fn op_ftruncate_sync(
state: &mut OpState,
rid: ResourceId,
len: u64,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(state, rid)?;
file.truncate_sync(len)?;
Ok(())
}
#[op]
-async fn op_ftruncate_async<Fs>(
+async fn op_ftruncate_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
len: u64,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(&state.borrow(), rid)?;
file.truncate_async(len).await?;
Ok(())
}
#[op]
-fn op_futime_sync<Fs>(
+fn op_futime_sync(
state: &mut OpState,
rid: ResourceId,
atime_secs: i64,
atime_nanos: u32,
mtime_secs: i64,
mtime_nanos: u32,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(state, rid)?;
file.utime_sync(atime_secs, atime_nanos, mtime_secs, mtime_nanos)?;
Ok(())
}
#[op]
-async fn op_futime_async<Fs>(
+async fn op_futime_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
atime_secs: i64,
atime_nanos: u32,
mtime_secs: i64,
mtime_nanos: u32,
-) -> Result<(), AnyError>
-where
- Fs: FileSystem + 'static,
- Fs::File: Resource,
-{
- let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
+) -> Result<(), AnyError> {
+ let file = FileResource::get_file(&state.borrow(), rid)?;
file
.utime_async(atime_secs, atime_nanos, mtime_secs, mtime_nanos)
.await?;
diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs
index 4bdbf4943..a657939db 100644
--- a/ext/fs/std_fs.rs
+++ b/ext/fs/std_fs.rs
@@ -4,34 +4,29 @@
use std::fs;
use std::io;
-use std::io::Read;
-use std::io::Seek;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
-use std::time::SystemTime;
-use std::time::UNIX_EPOCH;
-use deno_io::StdFileResource;
-use fs3::FileExt;
+use deno_io::fs::File;
+use deno_io::fs::FsResult;
+use deno_io::fs::FsStat;
+use deno_io::StdFileResourceInner;
use crate::interface::FsDirEntry;
-use crate::interface::FsError;
use crate::interface::FsFileType;
-use crate::interface::FsResult;
-use crate::interface::FsStat;
-use crate::File;
use crate::FileSystem;
use crate::OpenOptions;
+#[cfg(not(unix))]
+use deno_io::fs::FsError;
+
#[derive(Clone)]
-pub struct StdFs;
+pub struct RealFs;
#[async_trait::async_trait(?Send)]
-impl FileSystem for StdFs {
- type File = StdFileResource;
-
+impl FileSystem for RealFs {
fn cwd(&self) -> FsResult<PathBuf> {
std::env::current_dir().map_err(Into::into)
}
@@ -40,7 +35,7 @@ impl FileSystem for StdFs {
Ok(std::env::temp_dir())
}
- fn chdir(&self, path: impl AsRef<Path>) -> FsResult<()> {
+ fn chdir(&self, path: &Path) -> FsResult<()> {
std::env::set_current_dir(path).map_err(Into::into)
}
@@ -78,27 +73,27 @@ impl FileSystem for StdFs {
fn open_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
options: OpenOptions,
- ) -> FsResult<Self::File> {
+ ) -> FsResult<Rc<dyn File>> {
let opts = open_options(options);
let std_file = opts.open(path)?;
- Ok(StdFileResource::fs_file(std_file))
+ Ok(Rc::new(StdFileResourceInner::file(std_file)))
}
async fn open_async(
&self,
path: PathBuf,
options: OpenOptions,
- ) -> FsResult<Self::File> {
+ ) -> FsResult<Rc<dyn File>> {
let opts = open_options(options);
let std_file =
tokio::task::spawn_blocking(move || opts.open(path)).await??;
- Ok(StdFileResource::fs_file(std_file))
+ Ok(Rc::new(StdFileResourceInner::file(std_file)))
}
fn mkdir_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
recursive: bool,
mode: u32,
) -> FsResult<()> {
@@ -110,19 +105,19 @@ impl FileSystem for StdFs {
recursive: bool,
mode: u32,
) -> FsResult<()> {
- tokio::task::spawn_blocking(move || mkdir(path, recursive, mode)).await?
+ tokio::task::spawn_blocking(move || mkdir(&path, recursive, mode)).await?
}
- fn chmod_sync(&self, path: impl AsRef<Path>, mode: u32) -> FsResult<()> {
+ fn chmod_sync(&self, path: &Path, mode: u32) -> FsResult<()> {
chmod(path, mode)
}
async fn chmod_async(&self, path: PathBuf, mode: u32) -> FsResult<()> {
- tokio::task::spawn_blocking(move || chmod(path, mode)).await?
+ tokio::task::spawn_blocking(move || chmod(&path, mode)).await?
}
fn chown_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
uid: Option<u32>,
gid: Option<u32>,
) -> FsResult<()> {
@@ -134,68 +129,56 @@ impl FileSystem for StdFs {
uid: Option<u32>,
gid: Option<u32>,
) -> FsResult<()> {
- tokio::task::spawn_blocking(move || chown(path, uid, gid)).await?
+ tokio::task::spawn_blocking(move || chown(&path, uid, gid)).await?
}
- fn remove_sync(
- &self,
- path: impl AsRef<Path>,
- recursive: bool,
- ) -> FsResult<()> {
+ fn remove_sync(&self, path: &Path, recursive: bool) -> FsResult<()> {
remove(path, recursive)
}
async fn remove_async(&self, path: PathBuf, recursive: bool) -> FsResult<()> {
- tokio::task::spawn_blocking(move || remove(path, recursive)).await?
+ tokio::task::spawn_blocking(move || remove(&path, recursive)).await?
}
- fn copy_file_sync(
- &self,
- from: impl AsRef<Path>,
- to: impl AsRef<Path>,
- ) -> FsResult<()> {
+ fn copy_file_sync(&self, from: &Path, to: &Path) -> FsResult<()> {
copy_file(from, to)
}
async fn copy_file_async(&self, from: PathBuf, to: PathBuf) -> FsResult<()> {
- tokio::task::spawn_blocking(move || copy_file(from, to)).await?
+ tokio::task::spawn_blocking(move || copy_file(&from, &to)).await?
}
- fn stat_sync(&self, path: impl AsRef<Path>) -> FsResult<FsStat> {
+ fn stat_sync(&self, path: &Path) -> FsResult<FsStat> {
stat(path).map(Into::into)
}
async fn stat_async(&self, path: PathBuf) -> FsResult<FsStat> {
- tokio::task::spawn_blocking(move || stat(path))
+ tokio::task::spawn_blocking(move || stat(&path))
.await?
.map(Into::into)
}
- fn lstat_sync(&self, path: impl AsRef<Path>) -> FsResult<FsStat> {
+ fn lstat_sync(&self, path: &Path) -> FsResult<FsStat> {
lstat(path).map(Into::into)
}
async fn lstat_async(&self, path: PathBuf) -> FsResult<FsStat> {
- tokio::task::spawn_blocking(move || lstat(path))
+ tokio::task::spawn_blocking(move || lstat(&path))
.await?
.map(Into::into)
}
- fn realpath_sync(&self, path: impl AsRef<Path>) -> FsResult<PathBuf> {
+ fn realpath_sync(&self, path: &Path) -> FsResult<PathBuf> {
realpath(path)
}
async fn realpath_async(&self, path: PathBuf) -> FsResult<PathBuf> {
- tokio::task::spawn_blocking(move || realpath(path)).await?
+ tokio::task::spawn_blocking(move || realpath(&path)).await?
}
- fn read_dir_sync(&self, path: impl AsRef<Path>) -> FsResult<Vec<FsDirEntry>> {
+ fn read_dir_sync(&self, path: &Path) -> FsResult<Vec<FsDirEntry>> {
read_dir(path)
}
async fn read_dir_async(&self, path: PathBuf) -> FsResult<Vec<FsDirEntry>> {
- tokio::task::spawn_blocking(move || read_dir(path)).await?
+ tokio::task::spawn_blocking(move || read_dir(&path)).await?
}
- fn rename_sync(
- &self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
- ) -> FsResult<()> {
+ fn rename_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
fs::rename(oldpath, newpath).map_err(Into::into)
}
async fn rename_async(
@@ -208,11 +191,7 @@ impl FileSystem for StdFs {
.map_err(Into::into)
}
- fn link_sync(
- &self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
- ) -> FsResult<()> {
+ fn link_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
fs::hard_link(oldpath, newpath).map_err(Into::into)
}
async fn link_async(
@@ -227,8 +206,8 @@ impl FileSystem for StdFs {
fn symlink_sync(
&self,
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
+ oldpath: &Path,
+ newpath: &Path,
file_type: Option<FsFileType>,
) -> FsResult<()> {
symlink(oldpath, newpath, file_type)
@@ -239,11 +218,11 @@ impl FileSystem for StdFs {
newpath: PathBuf,
file_type: Option<FsFileType>,
) -> FsResult<()> {
- tokio::task::spawn_blocking(move || symlink(oldpath, newpath, file_type))
+ tokio::task::spawn_blocking(move || symlink(&oldpath, &newpath, file_type))
.await?
}
- fn read_link_sync(&self, path: impl AsRef<Path>) -> FsResult<PathBuf> {
+ fn read_link_sync(&self, path: &Path) -> FsResult<PathBuf> {
fs::read_link(path).map_err(Into::into)
}
async fn read_link_async(&self, path: PathBuf) -> FsResult<PathBuf> {
@@ -252,16 +231,16 @@ impl FileSystem for StdFs {
.map_err(Into::into)
}
- fn truncate_sync(&self, path: impl AsRef<Path>, len: u64) -> FsResult<()> {
+ fn truncate_sync(&self, path: &Path, len: u64) -> FsResult<()> {
truncate(path, len)
}
async fn truncate_async(&self, path: PathBuf, len: u64) -> FsResult<()> {
- tokio::task::spawn_blocking(move || truncate(path, len)).await?
+ tokio::task::spawn_blocking(move || truncate(&path, len)).await?
}
fn utime_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
atime_secs: i64,
atime_nanos: u32,
mtime_secs: i64,
@@ -289,7 +268,7 @@ impl FileSystem for StdFs {
fn write_file_sync(
&self,
- path: impl AsRef<Path>,
+ path: &Path,
options: OpenOptions,
data: &[u8],
) -> FsResult<()> {
@@ -324,7 +303,7 @@ impl FileSystem for StdFs {
.await?
}
- fn read_file_sync(&self, path: impl AsRef<Path>) -> FsResult<Vec<u8>> {
+ fn read_file_sync(&self, path: &Path) -> FsResult<Vec<u8>> {
fs::read(path).map_err(Into::into)
}
async fn read_file_async(&self, path: PathBuf) -> FsResult<Vec<u8>> {
@@ -334,7 +313,7 @@ impl FileSystem for StdFs {
}
}
-fn mkdir(path: impl AsRef<Path>, recursive: bool, mode: u32) -> FsResult<()> {
+fn mkdir(path: &Path, recursive: bool, mode: u32) -> FsResult<()> {
let mut builder = fs::DirBuilder::new();
builder.recursive(recursive);
#[cfg(unix)]
@@ -350,7 +329,7 @@ fn mkdir(path: impl AsRef<Path>, recursive: bool, mode: u32) -> FsResult<()> {
}
#[cfg(unix)]
-fn chmod(path: impl AsRef<Path>, mode: u32) -> FsResult<()> {
+fn chmod(path: &Path, mode: u32) -> FsResult<()> {
use std::os::unix::fs::PermissionsExt;
let permissions = fs::Permissions::from_mode(mode);
fs::set_permissions(path, permissions)?;
@@ -359,24 +338,20 @@ fn chmod(path: impl AsRef<Path>, mode: u32) -> FsResult<()> {
// TODO: implement chmod for Windows (#4357)
#[cfg(not(unix))]
-fn chmod(path: impl AsRef<Path>, _mode: u32) -> FsResult<()> {
+fn chmod(path: &Path, _mode: u32) -> FsResult<()> {
// Still check file/dir exists on Windows
std::fs::metadata(path)?;
Err(FsError::NotSupported)
}
#[cfg(unix)]
-fn chown(
- path: impl AsRef<Path>,
- uid: Option<u32>,
- gid: Option<u32>,
-) -> FsResult<()> {
+fn chown(path: &Path, uid: Option<u32>, gid: Option<u32>) -> FsResult<()> {
use nix::unistd::chown;
use nix::unistd::Gid;
use nix::unistd::Uid;
let owner = uid.map(Uid::from_raw);
let group = gid.map(Gid::from_raw);
- let res = chown(path.as_ref(), owner, group);
+ let res = chown(path, owner, group);
if let Err(err) = res {
return Err(io::Error::from_raw_os_error(err as i32).into());
}
@@ -385,60 +360,57 @@ fn chown(
// TODO: implement chown for Windows
#[cfg(not(unix))]
-fn chown(
- _path: impl AsRef<Path>,
- _uid: Option<u32>,
- _gid: Option<u32>,
-) -> FsResult<()> {
+fn chown(_path: &Path, _uid: Option<u32>, _gid: Option<u32>) -> FsResult<()> {
Err(FsError::NotSupported)
}
-fn remove(path: impl AsRef<Path>, recursive: bool) -> FsResult<()> {
+fn remove(path: &Path, recursive: bool) -> FsResult<()> {
// TODO: this is racy. This should open fds, and then `unlink` those.
- let metadata = fs::symlink_metadata(&path)?;
+ let metadata = fs::symlink_metadata(path)?;
let file_type = metadata.file_type();
let res = if file_type.is_dir() {
if recursive {
- fs::remove_dir_all(&path)
+ fs::remove_dir_all(path)
} else {
- fs::remove_dir(&path)
+ fs::remove_dir(path)
}
} else if file_type.is_symlink() {
#[cfg(unix)]
{
- fs::remove_file(&path)
+ fs::remove_file(path)
}
#[cfg(not(unix))]
{
use std::os::windows::prelude::MetadataExt;
use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
- fs::remove_dir(&path)
+ fs::remove_dir(path)
} else {
- fs::remove_file(&path)
+ fs::remove_file(path)
}
}
} else {
- fs::remove_file(&path)
+ fs::remove_file(path)
};
res.map_err(Into::into)
}
-fn copy_file(from: impl AsRef<Path>, to: impl AsRef<Path>) -> FsResult<()> {
+fn copy_file(from: &Path, to: &Path) -> FsResult<()> {
#[cfg(target_os = "macos")]
{
use libc::clonefile;
use libc::stat;
use libc::unlink;
use std::ffi::CString;
+ use std::io::Read;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::fs::PermissionsExt;
use std::os::unix::prelude::OsStrExt;
- let from_str = CString::new(from.as_ref().as_os_str().as_bytes()).unwrap();
- let to_str = CString::new(to.as_ref().as_os_str().as_bytes()).unwrap();
+ let from_str = CString::new(from.as_os_str().as_bytes()).unwrap();
+ let to_str = CString::new(to.as_os_str().as_bytes()).unwrap();
// SAFETY: `from` and `to` are valid C strings.
// std::fs::copy does open() + fcopyfile() on macOS. We try to use
@@ -499,36 +471,37 @@ fn copy_file(from: impl AsRef<Path>, to: impl AsRef<Path>) -> FsResult<()> {
}
#[cfg(not(windows))]
-fn stat(path: impl AsRef<Path>) -> FsResult<FsStat> {
+fn stat(path: &Path) -> FsResult<FsStat> {
let metadata = fs::metadata(path)?;
- Ok(metadata_to_fsstat(metadata))
+ Ok(FsStat::from_std(metadata))
}
#[cfg(windows)]
-fn stat(path: impl AsRef<Path>) -> FsResult<FsStat> {
- let metadata = fs::metadata(path.as_ref())?;
- let mut fsstat = metadata_to_fsstat(metadata);
+fn stat(path: &Path) -> FsResult<FsStat> {
+ let metadata = fs::metadata(path)?;
+ let mut fsstat = FsStat::from_std(metadata);
use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS;
- let path = path.as_ref().canonicalize()?;
+ let path = path.canonicalize()?;
stat_extra(&mut fsstat, &path, FILE_FLAG_BACKUP_SEMANTICS)?;
Ok(fsstat)
}
#[cfg(not(windows))]
-fn lstat(path: impl AsRef<Path>) -> FsResult<FsStat> {
+fn lstat(path: &Path) -> FsResult<FsStat> {
let metadata = fs::symlink_metadata(path)?;
- Ok(metadata_to_fsstat(metadata))
+ Ok(FsStat::from_std(metadata))
}
#[cfg(windows)]
-fn lstat(path: impl AsRef<Path>) -> FsResult<FsStat> {
- let metadata = fs::symlink_metadata(path.as_ref())?;
- let mut fsstat = metadata_to_fsstat(metadata);
+fn lstat(path: &Path) -> FsResult<FsStat> {
use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS;
use winapi::um::winbase::FILE_FLAG_OPEN_REPARSE_POINT;
+
+ let metadata = fs::symlink_metadata(path)?;
+ let mut fsstat = FsStat::from_std(metadata);
stat_extra(
&mut fsstat,
- path.as_ref(),
+ path,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
)?;
Ok(fsstat)
@@ -595,62 +568,11 @@ fn stat_extra(
}
}
-#[inline(always)]
-fn metadata_to_fsstat(metadata: fs::Metadata) -> FsStat {
- macro_rules! unix_or_zero {
- ($member:ident) => {{
- #[cfg(unix)]
- {
- use std::os::unix::fs::MetadataExt;
- metadata.$member()
- }
- #[cfg(not(unix))]
- {
- 0
- }
- }};
- }
-
- #[inline(always)]
- fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> Option<u64> {
- match maybe_time {
- Ok(time) => Some(
- time
- .duration_since(UNIX_EPOCH)
- .map(|t| t.as_millis() as u64)
- .unwrap_or_else(|err| err.duration().as_millis() as u64),
- ),
- Err(_) => None,
- }
- }
-
- FsStat {
- is_file: metadata.is_file(),
- is_directory: metadata.is_dir(),
- is_symlink: metadata.file_type().is_symlink(),
- size: metadata.len(),
-
- mtime: to_msec(metadata.modified()),
- atime: to_msec(metadata.accessed()),
- birthtime: to_msec(metadata.created()),
-
- dev: unix_or_zero!(dev),
- ino: unix_or_zero!(ino),
- mode: unix_or_zero!(mode),
- nlink: unix_or_zero!(nlink),
- uid: unix_or_zero!(uid),
- gid: unix_or_zero!(gid),
- rdev: unix_or_zero!(rdev),
- blksize: unix_or_zero!(blksize),
- blocks: unix_or_zero!(blocks),
- }
-}
-
-fn realpath(path: impl AsRef<Path>) -> FsResult<PathBuf> {
- Ok(deno_core::strip_unc_prefix(path.as_ref().canonicalize()?))
+fn realpath(path: &Path) -> FsResult<PathBuf> {
+ Ok(deno_core::strip_unc_prefix(path.canonicalize()?))
}
-fn read_dir(path: impl AsRef<Path>) -> FsResult<Vec<FsDirEntry>> {
+fn read_dir(path: &Path) -> FsResult<Vec<FsDirEntry>> {
let entries = fs::read_dir(path)?
.filter_map(|entry| {
let entry = entry.ok()?;
@@ -679,24 +601,24 @@ fn read_dir(path: impl AsRef<Path>) -> FsResult<Vec<FsDirEntry>> {
#[cfg(not(windows))]
fn symlink(
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
+ oldpath: &Path,
+ newpath: &Path,
_file_type: Option<FsFileType>,
) -> FsResult<()> {
- std::os::unix::fs::symlink(oldpath.as_ref(), newpath.as_ref())?;
+ std::os::unix::fs::symlink(oldpath, newpath)?;
Ok(())
}
#[cfg(windows)]
fn symlink(
- oldpath: impl AsRef<Path>,
- newpath: impl AsRef<Path>,
+ oldpath: &Path,
+ newpath: &Path,
file_type: Option<FsFileType>,
) -> FsResult<()> {
let file_type = match file_type {
Some(file_type) => file_type,
None => {
- let old_meta = fs::metadata(&oldpath);
+ let old_meta = fs::metadata(oldpath);
match old_meta {
Ok(metadata) => {
if metadata.is_file() {
@@ -723,17 +645,17 @@ fn symlink(
match file_type {
FsFileType::File => {
- std::os::windows::fs::symlink_file(&oldpath, &newpath)?;
+ std::os::windows::fs::symlink_file(oldpath, newpath)?;
}
FsFileType::Directory => {
- std::os::windows::fs::symlink_dir(&oldpath, &newpath)?;
+ std::os::windows::fs::symlink_dir(oldpath, newpath)?;
}
};
Ok(())
}
-fn truncate(path: impl AsRef<Path>, len: u64) -> FsResult<()> {
+fn truncate(path: &Path, len: u64) -> FsResult<()> {
let file = fs::OpenOptions::new().write(true).open(path)?;
file.set_len(len)?;
Ok(())
@@ -760,162 +682,3 @@ fn open_options(options: OpenOptions) -> fs::OpenOptions {
open_options.create_new(options.create_new);
open_options
}
-
-fn sync<T>(
- resource: Rc<StdFileResource>,
- f: impl FnOnce(&mut fs::File) -> io::Result<T>,
-) -> FsResult<T> {
- let res = resource
- .with_file2(|file| f(file))
- .ok_or(FsError::FileBusy)??;
- Ok(res)
-}
-
-async fn nonblocking<T: Send + 'static>(
- resource: Rc<StdFileResource>,
- f: impl FnOnce(&mut fs::File) -> io::Result<T> + Send + 'static,
-) -> FsResult<T> {
- let res = resource.with_file_blocking_task2(f).await?;
- Ok(res)
-}
-
-#[async_trait::async_trait(?Send)]
-impl File for StdFileResource {
- fn write_all_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<()> {
- sync(self, |file| file.write_all(buf))
- }
- async fn write_all_async(self: Rc<Self>, buf: Vec<u8>) -> FsResult<()> {
- nonblocking(self, move |file| file.write_all(&buf)).await
- }
-
- fn read_all_sync(self: Rc<Self>) -> FsResult<Vec<u8>> {
- sync(self, |file| {
- let mut buf = Vec::new();
- file.read_to_end(&mut buf)?;
- Ok(buf)
- })
- }
- async fn read_all_async(self: Rc<Self>) -> FsResult<Vec<u8>> {
- nonblocking(self, |file| {
- let mut buf = Vec::new();
- file.read_to_end(&mut buf)?;
- Ok(buf)
- })
- .await
- }
-
- fn chmod_sync(self: Rc<Self>, _mode: u32) -> FsResult<()> {
- #[cfg(unix)]
- {
- sync(self, |file| {
- use std::os::unix::prelude::PermissionsExt;
- file.set_permissions(fs::Permissions::from_mode(_mode))
- })
- }
- #[cfg(not(unix))]
- Err(FsError::NotSupported)
- }
-
- async fn chmod_async(self: Rc<Self>, _mode: u32) -> FsResult<()> {
- #[cfg(unix)]
- {
- nonblocking(self, move |file| {
- use std::os::unix::prelude::PermissionsExt;
- file.set_permissions(fs::Permissions::from_mode(_mode))
- })
- .await
- }
- #[cfg(not(unix))]
- Err(FsError::NotSupported)
- }
-
- fn seek_sync(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64> {
- sync(self, |file| file.seek(pos))
- }
- async fn seek_async(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64> {
- nonblocking(self, move |file| file.seek(pos)).await
- }
-
- fn datasync_sync(self: Rc<Self>) -> FsResult<()> {
- sync(self, |file| file.sync_data())
- }
- async fn datasync_async(self: Rc<Self>) -> FsResult<()> {
- nonblocking(self, |file| file.sync_data()).await
- }
-
- fn sync_sync(self: Rc<Self>) -> FsResult<()> {
- sync(self, |file| file.sync_all())
- }
- async fn sync_async(self: Rc<Self>) -> FsResult<()> {
- nonblocking(self, |file| file.sync_all()).await
- }
-
- fn stat_sync(self: Rc<Self>) -> FsResult<FsStat> {
- sync(self, |file| file.metadata().map(metadata_to_fsstat))
- }
- async fn stat_async(self: Rc<Self>) -> FsResult<FsStat> {
- nonblocking(self, |file| file.metadata().map(metadata_to_fsstat)).await
- }
-
- fn lock_sync(self: Rc<Self>, exclusive: bool) -> FsResult<()> {
- sync(self, |file| {
- if exclusive {
- file.lock_exclusive()
- } else {
- file.lock_shared()
- }
- })
- }
- async fn lock_async(self: Rc<Self>, exclusive: bool) -> FsResult<()> {
- nonblocking(self, move |file| {
- if exclusive {
- file.lock_exclusive()
- } else {
- file.lock_shared()
- }
- })
- .await
- }
-
- fn unlock_sync(self: Rc<Self>) -> FsResult<()> {
- sync(self, |file| file.unlock())
- }
- async fn unlock_async(self: Rc<Self>) -> FsResult<()> {
- nonblocking(self, |file| file.unlock()).await
- }
-
- fn truncate_sync(self: Rc<Self>, len: u64) -> FsResult<()> {
- sync(self, |file| file.set_len(len))
- }
- async fn truncate_async(self: Rc<Self>, len: u64) -> FsResult<()> {
- nonblocking(self, move |file| file.set_len(len)).await
- }
-
- fn utime_sync(
- self: Rc<Self>,
- atime_secs: i64,
- atime_nanos: u32,
- mtime_secs: i64,
- mtime_nanos: u32,
- ) -> FsResult<()> {
- let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
- let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
- sync(self, |file| {
- filetime::set_file_handle_times(file, Some(atime), Some(mtime))
- })
- }
- async fn utime_async(
- self: Rc<Self>,
- atime_secs: i64,
- atime_nanos: u32,
- mtime_secs: i64,
- mtime_nanos: u32,
- ) -> FsResult<()> {
- let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
- let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
- nonblocking(self, move |file| {
- filetime::set_file_handle_times(file, Some(atime), Some(mtime))
- })
- .await
- }
-}
diff --git a/ext/io/Cargo.toml b/ext/io/Cargo.toml
index 55b2ccab6..fc9de711f 100644
--- a/ext/io/Cargo.toml
+++ b/ext/io/Cargo.toml
@@ -14,7 +14,10 @@ description = "IO promitives for Deno extensions"
path = "lib.rs"
[dependencies]
+async-trait.workspace = true
deno_core.workspace = true
+filetime.workspace = true
+fs3.workspace = true
once_cell.workspace = true
tokio.workspace = true
diff --git a/ext/io/fs.rs b/ext/io/fs.rs
new file mode 100644
index 000000000..bb6bdec4f
--- /dev/null
+++ b/ext/io/fs.rs
@@ -0,0 +1,330 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+use std::borrow::Cow;
+use std::io;
+use std::rc::Rc;
+use std::time::SystemTime;
+use std::time::UNIX_EPOCH;
+
+use deno_core::error::not_supported;
+use deno_core::error::resource_unavailable;
+use deno_core::error::AnyError;
+use deno_core::BufMutView;
+use deno_core::BufView;
+use deno_core::OpState;
+use deno_core::ResourceId;
+use tokio::task::JoinError;
+
+pub enum FsError {
+ Io(io::Error),
+ FileBusy,
+ NotSupported,
+}
+
+impl From<io::Error> for FsError {
+ fn from(err: io::Error) -> Self {
+ Self::Io(err)
+ }
+}
+
+impl From<FsError> for AnyError {
+ fn from(err: FsError) -> Self {
+ match err {
+ FsError::Io(err) => AnyError::from(err),
+ FsError::FileBusy => resource_unavailable(),
+ FsError::NotSupported => not_supported(),
+ }
+ }
+}
+
+impl From<JoinError> for FsError {
+ fn from(err: JoinError) -> Self {
+ if err.is_cancelled() {
+ todo!("async tasks must not be cancelled")
+ }
+ if err.is_panic() {
+ std::panic::resume_unwind(err.into_panic()); // resume the panic on the main thread
+ }
+ unreachable!()
+ }
+}
+
+pub type FsResult<T> = Result<T, FsError>;
+
+pub struct FsStat {
+ pub is_file: bool,
+ pub is_directory: bool,
+ pub is_symlink: bool,
+ pub size: u64,
+
+ pub mtime: Option<u64>,
+ pub atime: Option<u64>,
+ pub birthtime: Option<u64>,
+
+ pub dev: u64,
+ pub ino: u64,
+ pub mode: u32,
+ pub nlink: u64,
+ pub uid: u32,
+ pub gid: u32,
+ pub rdev: u64,
+ pub blksize: u64,
+ pub blocks: u64,
+}
+
+impl FsStat {
+ pub fn from_std(metadata: std::fs::Metadata) -> Self {
+ macro_rules! unix_or_zero {
+ ($member:ident) => {{
+ #[cfg(unix)]
+ {
+ use std::os::unix::fs::MetadataExt;
+ metadata.$member()
+ }
+ #[cfg(not(unix))]
+ {
+ 0
+ }
+ }};
+ }
+
+ #[inline(always)]
+ fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> Option<u64> {
+ match maybe_time {
+ Ok(time) => Some(
+ time
+ .duration_since(UNIX_EPOCH)
+ .map(|t| t.as_millis() as u64)
+ .unwrap_or_else(|err| err.duration().as_millis() as u64),
+ ),
+ Err(_) => None,
+ }
+ }
+
+ Self {
+ is_file: metadata.is_file(),
+ is_directory: metadata.is_dir(),
+ is_symlink: metadata.file_type().is_symlink(),
+ size: metadata.len(),
+
+ mtime: to_msec(metadata.modified()),
+ atime: to_msec(metadata.accessed()),
+ birthtime: to_msec(metadata.created()),
+
+ dev: unix_or_zero!(dev),
+ ino: unix_or_zero!(ino),
+ mode: unix_or_zero!(mode),
+ nlink: unix_or_zero!(nlink),
+ uid: unix_or_zero!(uid),
+ gid: unix_or_zero!(gid),
+ rdev: unix_or_zero!(rdev),
+ blksize: unix_or_zero!(blksize),
+ blocks: unix_or_zero!(blocks),
+ }
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+pub trait File {
+ fn read_sync(self: Rc<Self>, buf: &mut [u8]) -> FsResult<usize>;
+ async fn read(self: Rc<Self>, limit: usize) -> FsResult<BufView> {
+ let vec = vec![0; limit];
+ let buf = BufMutView::from(vec);
+ let (nread, buf) = self.read_byob(buf).await?;
+ let mut vec = buf.unwrap_vec();
+ if vec.len() != nread {
+ vec.truncate(nread);
+ }
+ Ok(BufView::from(vec))
+ }
+ async fn read_byob(
+ self: Rc<Self>,
+ buf: BufMutView,
+ ) -> FsResult<(usize, BufMutView)>;
+
+ fn write_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<usize>;
+ async fn write(
+ self: Rc<Self>,
+ buf: BufView,
+ ) -> FsResult<deno_core::WriteOutcome>;
+
+ fn write_all_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<()>;
+ async fn write_all(self: Rc<Self>, buf: BufView) -> FsResult<()>;
+
+ fn read_all_sync(self: Rc<Self>) -> FsResult<Vec<u8>>;
+ async fn read_all_async(self: Rc<Self>) -> FsResult<Vec<u8>>;
+
+ fn chmod_sync(self: Rc<Self>, pathmode: u32) -> FsResult<()>;
+ async fn chmod_async(self: Rc<Self>, mode: u32) -> FsResult<()>;
+
+ fn seek_sync(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64>;
+ async fn seek_async(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64>;
+
+ fn datasync_sync(self: Rc<Self>) -> FsResult<()>;
+ async fn datasync_async(self: Rc<Self>) -> FsResult<()>;
+
+ fn sync_sync(self: Rc<Self>) -> FsResult<()>;
+ async fn sync_async(self: Rc<Self>) -> FsResult<()>;
+
+ fn stat_sync(self: Rc<Self>) -> FsResult<FsStat>;
+ async fn stat_async(self: Rc<Self>) -> FsResult<FsStat>;
+
+ fn lock_sync(self: Rc<Self>, exclusive: bool) -> FsResult<()>;
+ async fn lock_async(self: Rc<Self>, exclusive: bool) -> FsResult<()>;
+
+ fn unlock_sync(self: Rc<Self>) -> FsResult<()>;
+ async fn unlock_async(self: Rc<Self>) -> FsResult<()>;
+
+ fn truncate_sync(self: Rc<Self>, len: u64) -> FsResult<()>;
+ async fn truncate_async(self: Rc<Self>, len: u64) -> FsResult<()>;
+
+ fn utime_sync(
+ self: Rc<Self>,
+ atime_secs: i64,
+ atime_nanos: u32,
+ mtime_secs: i64,
+ mtime_nanos: u32,
+ ) -> FsResult<()>;
+ async fn utime_async(
+ self: Rc<Self>,
+ atime_secs: i64,
+ atime_nanos: u32,
+ mtime_secs: i64,
+ mtime_nanos: u32,
+ ) -> FsResult<()>;
+
+ // lower level functionality
+ fn as_stdio(self: Rc<Self>) -> FsResult<std::process::Stdio>;
+ #[cfg(unix)]
+ fn backing_fd(self: Rc<Self>) -> Option<std::os::unix::prelude::RawFd>;
+ #[cfg(windows)]
+ fn backing_fd(self: Rc<Self>) -> Option<std::os::windows::io::RawHandle>;
+ fn try_clone_inner(self: Rc<Self>) -> FsResult<Rc<dyn File>>;
+}
+
+pub struct FileResource {
+ name: String,
+ file: Rc<dyn File>,
+}
+
+impl FileResource {
+ pub fn new(file: Rc<dyn File>, name: String) -> Self {
+ Self { name, file }
+ }
+
+ pub fn with_resource<F, R>(
+ state: &OpState,
+ rid: ResourceId,
+ f: F,
+ ) -> Result<R, AnyError>
+ where
+ F: FnOnce(Rc<FileResource>) -> Result<R, AnyError>,
+ {
+ let resource = state.resource_table.get::<FileResource>(rid)?;
+ f(resource)
+ }
+
+ pub fn get_file(
+ state: &OpState,
+ rid: ResourceId,
+ ) -> Result<Rc<dyn File>, AnyError> {
+ let resource = state.resource_table.get::<FileResource>(rid)?;
+ Ok(resource.file())
+ }
+
+ pub fn with_file<F, R>(
+ state: &OpState,
+ rid: ResourceId,
+ f: F,
+ ) -> Result<R, AnyError>
+ where
+ F: FnOnce(Rc<dyn File>) -> Result<R, AnyError>,
+ {
+ Self::with_resource(state, rid, |r| f(r.file.clone()))
+ }
+
+ pub fn file(&self) -> Rc<dyn File> {
+ self.file.clone()
+ }
+}
+
+impl deno_core::Resource for FileResource {
+ fn name(&self) -> Cow<str> {
+ Cow::Borrowed(&self.name)
+ }
+
+ fn read(
+ self: Rc<Self>,
+ limit: usize,
+ ) -> deno_core::AsyncResult<deno_core::BufView> {
+ Box::pin(async move {
+ self
+ .file
+ .clone()
+ .read(limit)
+ .await
+ .map_err(|err| err.into())
+ })
+ }
+
+ fn read_byob(
+ self: Rc<Self>,
+ buf: deno_core::BufMutView,
+ ) -> deno_core::AsyncResult<(usize, deno_core::BufMutView)> {
+ Box::pin(async move {
+ self
+ .file
+ .clone()
+ .read_byob(buf)
+ .await
+ .map_err(|err| err.into())
+ })
+ }
+
+ fn write(
+ self: Rc<Self>,
+ buf: deno_core::BufView,
+ ) -> deno_core::AsyncResult<deno_core::WriteOutcome> {
+ Box::pin(async move {
+ self.file.clone().write(buf).await.map_err(|err| err.into())
+ })
+ }
+
+ fn write_all(
+ self: Rc<Self>,
+ buf: deno_core::BufView,
+ ) -> deno_core::AsyncResult<()> {
+ Box::pin(async move {
+ self
+ .file
+ .clone()
+ .write_all(buf)
+ .await
+ .map_err(|err| err.into())
+ })
+ }
+
+ fn read_byob_sync(
+ self: Rc<Self>,
+ data: &mut [u8],
+ ) -> Result<usize, deno_core::anyhow::Error> {
+ self.file.clone().read_sync(data).map_err(|err| err.into())
+ }
+
+ fn write_sync(
+ self: Rc<Self>,
+ data: &[u8],
+ ) -> Result<usize, deno_core::anyhow::Error> {
+ self.file.clone().write_sync(data).map_err(|err| err.into())
+ }
+
+ #[cfg(unix)]
+ fn backing_fd(self: Rc<Self>) -> Option<std::os::unix::prelude::RawFd> {
+ self.file.clone().backing_fd()
+ }
+
+ #[cfg(windows)]
+ fn backing_fd(self: Rc<Self>) -> Option<std::os::windows::io::RawHandle> {
+ self.file.clone().backing_fd()
+ }
+}
diff --git a/ext/io/lib.rs b/ext/io/lib.rs
index 73ce72578..49e4ab714 100644
--- a/ext/io/lib.rs
+++ b/ext/io/lib.rs
@@ -1,6 +1,5 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_core::error::resource_unavailable;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::AsyncMutFuture;
@@ -13,8 +12,12 @@ use deno_core::CancelTryFuture;
use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
-use deno_core::ResourceId;
use deno_core::TaskQueue;
+use fs::FileResource;
+use fs::FsError;
+use fs::FsResult;
+use fs::FsStat;
+use fs3::FileExt;
use once_cell::sync::Lazy;
use std::borrow::Cow;
use std::cell::RefCell;
@@ -22,6 +25,7 @@ use std::fs::File as StdFile;
use std::io;
use std::io::ErrorKind;
use std::io::Read;
+use std::io::Seek;
use std::io::Write;
use std::rc::Rc;
use tokio::io::AsyncRead;
@@ -40,6 +44,8 @@ use winapi::um::processenv::GetStdHandle;
#[cfg(windows)]
use winapi::um::winbase;
+pub mod fs;
+
// Store the stdio fd/handles in global statics in order to keep them
// alive for the duration of the application since the last handle/fd
// being dropped will close the corresponding pipe.
@@ -89,39 +95,39 @@ deno_core::extension!(deno_io,
if let Some(stdio) = options.stdio {
let t = &mut state.resource_table;
- let rid = t.add(StdFileResource::stdio(
- match stdio.stdin {
- StdioPipe::Inherit => StdFileResourceInner {
- kind: StdFileResourceKind::Stdin,
- file: STDIN_HANDLE.try_clone().unwrap(),
- },
+ let rid = t.add(fs::FileResource::new(
+ Rc::new(match stdio.stdin {
+ StdioPipe::Inherit => StdFileResourceInner::new(
+ StdFileResourceKind::Stdin,
+ STDIN_HANDLE.try_clone().unwrap(),
+ ),
StdioPipe::File(pipe) => StdFileResourceInner::file(pipe),
- },
- "stdin",
+ }),
+ "stdin".to_string(),
));
assert_eq!(rid, 0, "stdin must have ResourceId 0");
- let rid = t.add(StdFileResource::stdio(
- match stdio.stdout {
- StdioPipe::Inherit => StdFileResourceInner {
- kind: StdFileResourceKind::Stdout,
- file: STDOUT_HANDLE.try_clone().unwrap(),
- },
+ let rid = t.add(FileResource::new(
+ Rc::new(match stdio.stdout {
+ StdioPipe::Inherit => StdFileResourceInner::new(
+ StdFileResourceKind::Stdout,
+ STDOUT_HANDLE.try_clone().unwrap(),
+ ),
StdioPipe::File(pipe) => StdFileResourceInner::file(pipe),
- },
- "stdout",
+ }),
+ "stdout".to_string(),
));
assert_eq!(rid, 1, "stdout must have ResourceId 1");
- let rid = t.add(StdFileResource::stdio(
- match stdio.stderr {
- StdioPipe::Inherit => StdFileResourceInner {
- kind: StdFileResourceKind::Stderr,
- file: STDERR_HANDLE.try_clone().unwrap(),
- },
+ let rid = t.add(FileResource::new(
+ Rc::new(match stdio.stderr {
+ StdioPipe::Inherit => StdFileResourceInner::new(
+ StdFileResourceKind::Stderr,
+ STDERR_HANDLE.try_clone().unwrap(),
+ ),
StdioPipe::File(pipe) => StdFileResourceInner::file(pipe),
- },
- "stderr",
+ }),
+ "stderr".to_string(),
));
assert_eq!(rid, 2, "stderr must have ResourceId 2");
}
@@ -291,34 +297,88 @@ enum StdFileResourceKind {
Stderr,
}
-struct StdFileResourceInner {
+pub struct StdFileResourceInner {
kind: StdFileResourceKind,
- file: StdFile,
+ // We can't use an AsyncRefCell here because we need to allow
+ // access to the resource synchronously at any time and
+ // asynchronously one at a time in order
+ cell: RefCell<Option<StdFile>>,
+ // Used to keep async actions in order and only allow one
+ // to occur at a time
+ cell_async_task_queue: TaskQueue,
}
impl StdFileResourceInner {
pub fn file(fs_file: StdFile) -> Self {
+ StdFileResourceInner::new(StdFileResourceKind::File, fs_file)
+ }
+
+ fn new(kind: StdFileResourceKind, fs_file: StdFile) -> Self {
StdFileResourceInner {
- kind: StdFileResourceKind::File,
- file: fs_file,
+ kind,
+ cell: RefCell::new(Some(fs_file)),
+ cell_async_task_queue: Default::default(),
}
}
- pub fn with_file<R>(&mut self, f: impl FnOnce(&mut StdFile) -> R) -> R {
- f(&mut self.file)
+ fn with_sync<F, R>(&self, action: F) -> FsResult<R>
+ where
+ F: FnOnce(&mut StdFile) -> FsResult<R>,
+ {
+ match self.cell.try_borrow_mut() {
+ Ok(mut cell) if cell.is_some() => action(cell.as_mut().unwrap()),
+ _ => Err(fs::FsError::FileBusy),
+ }
}
- pub fn try_clone(&self) -> Result<Self, std::io::Error> {
- Ok(Self {
- kind: self.kind,
- file: self.file.try_clone()?,
+ async fn with_inner_blocking_task<F, R: 'static + Send>(&self, action: F) -> R
+ where
+ F: FnOnce(&mut StdFile) -> R + Send + 'static,
+ {
+ // we want to restrict this to one async action at a time
+ let _permit = self.cell_async_task_queue.acquire().await;
+ // we take the value out of the cell, use it on a blocking task,
+ // then put it back into the cell when we're done
+ let mut did_take = false;
+ let mut cell_value = {
+ let mut cell = self.cell.borrow_mut();
+ match cell.as_mut().unwrap().try_clone().ok() {
+ Some(value) => value,
+ None => {
+ did_take = true;
+ cell.take().unwrap()
+ }
+ }
+ };
+ let (cell_value, result) = tokio::task::spawn_blocking(move || {
+ let result = action(&mut cell_value);
+ (cell_value, result)
})
+ .await
+ .unwrap();
+
+ if did_take {
+ // put it back
+ self.cell.borrow_mut().replace(cell_value);
+ }
+
+ result
}
- pub fn write_and_maybe_flush(
- &mut self,
- buf: &[u8],
- ) -> Result<usize, AnyError> {
+ async fn with_blocking_task<F, R: 'static + Send>(&self, action: F) -> R
+ where
+ F: FnOnce() -> R + Send + 'static,
+ {
+ // we want to restrict this to one async action at a time
+ let _permit = self.cell_async_task_queue.acquire().await;
+
+ tokio::task::spawn_blocking(action).await.unwrap()
+ }
+}
+
+#[async_trait::async_trait(?Send)]
+impl crate::fs::File for StdFileResourceInner {
+ fn write_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<usize> {
// Rust will line buffer and we don't want that behavior
// (see https://github.com/denoland/deno/issues/948), so flush stdout and stderr.
// Although an alternative solution could be to bypass Rust's std by
@@ -326,7 +386,7 @@ impl StdFileResourceInner {
// that we get solved for free by using Rust's stdio wrappers (see
// std/src/sys/windows/stdio.rs in Rust's source code).
match self.kind {
- StdFileResourceKind::File => Ok(self.file.write(buf)?),
+ StdFileResourceKind::File => self.with_sync(|file| Ok(file.write(buf)?)),
StdFileResourceKind::Stdin => {
Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
}
@@ -347,14 +407,22 @@ impl StdFileResourceInner {
}
}
- pub fn write_all_and_maybe_flush(
- &mut self,
- buf: &[u8],
- ) -> Result<(), AnyError> {
- // this method exists instead of using a `Write` implementation
- // so that we can acquire the locks once and do both actions
+ fn read_sync(self: Rc<Self>, buf: &mut [u8]) -> FsResult<usize> {
+ match self.kind {
+ StdFileResourceKind::File | StdFileResourceKind::Stdin => {
+ self.with_sync(|file| Ok(file.read(buf)?))
+ }
+ StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
+ Err(FsError::NotSupported)
+ }
+ }
+ }
+
+ fn write_all_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<()> {
match self.kind {
- StdFileResourceKind::File => Ok(self.file.write_all(buf)?),
+ StdFileResourceKind::File => {
+ self.with_sync(|file| Ok(file.write_all(buf)?))
+ }
StdFileResourceKind::Stdin => {
Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
}
@@ -374,292 +442,292 @@ impl StdFileResourceInner {
}
}
}
-}
-
-impl Read for StdFileResourceInner {
- fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ async fn write_all(self: Rc<Self>, buf: BufView) -> FsResult<()> {
match self.kind {
- StdFileResourceKind::File | StdFileResourceKind::Stdin => {
- self.file.read(buf)
+ StdFileResourceKind::File => {
+ self
+ .with_inner_blocking_task(move |file| Ok(file.write_all(&buf)?))
+ .await
}
- StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
- Err(ErrorKind::Unsupported.into())
+ StdFileResourceKind::Stdin => {
+ Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
+ }
+ StdFileResourceKind::Stdout => {
+ self
+ .with_blocking_task(move || {
+ // bypass the file and use std::io::stdout()
+ let mut stdout = std::io::stdout().lock();
+ stdout.write_all(&buf)?;
+ stdout.flush()?;
+ Ok(())
+ })
+ .await
+ }
+ StdFileResourceKind::Stderr => {
+ self
+ .with_blocking_task(move || {
+ // bypass the file and use std::io::stderr()
+ let mut stderr = std::io::stderr().lock();
+ stderr.write_all(&buf)?;
+ stderr.flush()?;
+ Ok(())
+ })
+ .await
}
}
}
-}
-pub struct StdFileResource {
- name: String,
- // We can't use an AsyncRefCell here because we need to allow
- // access to the resource synchronously at any time and
- // asynchronously one at a time in order
- cell: RefCell<Option<StdFileResourceInner>>,
- // Used to keep async actions in order and only allow one
- // to occur at a time
- cell_async_task_queue: TaskQueue,
-}
-
-impl StdFileResource {
- fn stdio(inner: StdFileResourceInner, name: &str) -> Self {
- Self {
- cell: RefCell::new(Some(inner)),
- cell_async_task_queue: Default::default(),
- name: name.to_string(),
+ async fn write(
+ self: Rc<Self>,
+ view: BufView,
+ ) -> FsResult<deno_core::WriteOutcome> {
+ match self.kind {
+ StdFileResourceKind::File => {
+ self
+ .with_inner_blocking_task(|file| {
+ let nwritten = file.write(&view)?;
+ Ok(deno_core::WriteOutcome::Partial { nwritten, view })
+ })
+ .await
+ }
+ StdFileResourceKind::Stdin => {
+ Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
+ }
+ StdFileResourceKind::Stdout => {
+ self
+ .with_blocking_task(|| {
+ // bypass the file and use std::io::stdout()
+ let mut stdout = std::io::stdout().lock();
+ let nwritten = stdout.write(&view)?;
+ stdout.flush()?;
+ Ok(deno_core::WriteOutcome::Partial { nwritten, view })
+ })
+ .await
+ }
+ StdFileResourceKind::Stderr => {
+ self
+ .with_blocking_task(|| {
+ // bypass the file and use std::io::stderr()
+ let mut stderr = std::io::stderr().lock();
+ let nwritten = stderr.write(&view)?;
+ stderr.flush()?;
+ Ok(deno_core::WriteOutcome::Partial { nwritten, view })
+ })
+ .await
+ }
}
}
- pub fn fs_file(fs_file: StdFile) -> Self {
- Self {
- cell: RefCell::new(Some(StdFileResourceInner::file(fs_file))),
- cell_async_task_queue: Default::default(),
- name: "fsFile".to_string(),
+ fn read_all_sync(self: Rc<Self>) -> FsResult<Vec<u8>> {
+ match self.kind {
+ StdFileResourceKind::File | StdFileResourceKind::Stdin => {
+ let mut buf = Vec::new();
+ self.with_sync(|file| Ok(file.read_to_end(&mut buf)?))?;
+ Ok(buf)
+ }
+ StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
+ Err(FsError::NotSupported)
+ }
}
}
-
- fn with_inner<TResult, E>(
- &self,
- action: impl FnOnce(&mut StdFileResourceInner) -> Result<TResult, E>,
- ) -> Option<Result<TResult, E>> {
- match self.cell.try_borrow_mut() {
- Ok(mut cell) if cell.is_some() => {
- let mut file = cell.take().unwrap();
- let result = action(&mut file);
- cell.replace(file);
- Some(result)
+ async fn read_all_async(self: Rc<Self>) -> FsResult<Vec<u8>> {
+ match self.kind {
+ StdFileResourceKind::File | StdFileResourceKind::Stdin => {
+ self
+ .with_inner_blocking_task(|file| {
+ let mut buf = Vec::new();
+ file.read_to_end(&mut buf)?;
+ Ok(buf)
+ })
+ .await
+ }
+ StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
+ Err(FsError::NotSupported)
}
- _ => None,
}
}
- async fn with_inner_blocking_task<F, R: Send + 'static>(&self, action: F) -> R
- where
- F: FnOnce(&mut StdFileResourceInner) -> R + Send + 'static,
- {
- // we want to restrict this to one async action at a time
- let _permit = self.cell_async_task_queue.acquire().await;
- // we take the value out of the cell, use it on a blocking task,
- // then put it back into the cell when we're done
- let mut did_take = false;
- let mut cell_value = {
- let mut cell = self.cell.borrow_mut();
- match cell.as_mut().unwrap().try_clone() {
- Ok(value) => value,
- Err(_) => {
- did_take = true;
- cell.take().unwrap()
- }
- }
- };
- let (cell_value, result) = tokio::task::spawn_blocking(move || {
- let result = action(&mut cell_value);
- (cell_value, result)
- })
- .await
- .unwrap();
-
- if did_take {
- // put it back
- self.cell.borrow_mut().replace(cell_value);
+ fn chmod_sync(self: Rc<Self>, _mode: u32) -> FsResult<()> {
+ #[cfg(unix)]
+ {
+ use std::os::unix::prelude::PermissionsExt;
+ self.with_sync(|file| {
+ Ok(file.set_permissions(std::fs::Permissions::from_mode(_mode))?)
+ })
}
-
- result
+ #[cfg(not(unix))]
+ Err(FsError::NotSupported)
+ }
+ async fn chmod_async(self: Rc<Self>, _mode: u32) -> FsResult<()> {
+ #[cfg(unix)]
+ {
+ use std::os::unix::prelude::PermissionsExt;
+ self
+ .with_inner_blocking_task(move |file| {
+ Ok(file.set_permissions(std::fs::Permissions::from_mode(_mode))?)
+ })
+ .await
+ }
+ #[cfg(not(unix))]
+ Err(FsError::NotSupported)
}
- async fn read_byob(
- self: Rc<Self>,
- mut buf: BufMutView,
- ) -> Result<(usize, BufMutView), AnyError> {
+ fn seek_sync(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64> {
+ self.with_sync(|file| Ok(file.seek(pos)?))
+ }
+ async fn seek_async(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64> {
self
- .with_inner_blocking_task(move |inner| {
- let nread = inner.read(&mut buf)?;
- Ok((nread, buf))
- })
+ .with_inner_blocking_task(move |file| Ok(file.seek(pos)?))
.await
}
- async fn write(
- self: Rc<Self>,
- view: BufView,
- ) -> Result<deno_core::WriteOutcome, AnyError> {
+ fn datasync_sync(self: Rc<Self>) -> FsResult<()> {
+ self.with_sync(|file| Ok(file.sync_data()?))
+ }
+ async fn datasync_async(self: Rc<Self>) -> FsResult<()> {
self
- .with_inner_blocking_task(move |inner| {
- let nwritten = inner.write_and_maybe_flush(&view)?;
- Ok(deno_core::WriteOutcome::Partial { nwritten, view })
- })
+ .with_inner_blocking_task(|file| Ok(file.sync_data()?))
.await
}
- async fn write_all(self: Rc<Self>, view: BufView) -> Result<(), AnyError> {
+ fn sync_sync(self: Rc<Self>) -> FsResult<()> {
+ self.with_sync(|file| Ok(file.sync_all()?))
+ }
+ async fn sync_async(self: Rc<Self>) -> FsResult<()> {
self
- .with_inner_blocking_task(move |inner| {
- inner.write_all_and_maybe_flush(&view)
- })
+ .with_inner_blocking_task(|file| Ok(file.sync_all()?))
.await
}
- fn read_byob_sync(self: Rc<Self>, buf: &mut [u8]) -> Result<usize, AnyError> {
- self
- .with_inner(|inner| inner.read(buf))
- .ok_or_else(resource_unavailable)?
- .map_err(Into::into)
+ fn stat_sync(self: Rc<Self>) -> FsResult<FsStat> {
+ self.with_sync(|file| Ok(file.metadata().map(FsStat::from_std)?))
}
-
- fn write_sync(self: Rc<Self>, data: &[u8]) -> Result<usize, AnyError> {
+ async fn stat_async(self: Rc<Self>) -> FsResult<FsStat> {
self
- .with_inner(|inner| inner.write_and_maybe_flush(data))
- .ok_or_else(resource_unavailable)?
- }
-
- fn with_resource<F, R>(
- state: &mut OpState,
- rid: ResourceId,
- f: F,
- ) -> Result<R, AnyError>
- where
- F: FnOnce(Rc<StdFileResource>) -> Result<R, AnyError>,
- {
- let resource = state.resource_table.get::<StdFileResource>(rid)?;
- f(resource)
+ .with_inner_blocking_task(|file| {
+ Ok(file.metadata().map(FsStat::from_std)?)
+ })
+ .await
}
- pub fn with_file<F, R>(
- state: &mut OpState,
- rid: ResourceId,
- f: F,
- ) -> Result<R, AnyError>
- where
- F: FnOnce(&mut StdFile) -> Result<R, AnyError>,
- {
- Self::with_resource(state, rid, move |resource| {
- resource
- .with_inner(move |inner| inner.with_file(f))
- .ok_or_else(resource_unavailable)?
+ fn lock_sync(self: Rc<Self>, exclusive: bool) -> FsResult<()> {
+ self.with_sync(|file| {
+ if exclusive {
+ file.lock_exclusive()?;
+ } else {
+ file.lock_shared()?;
+ }
+ Ok(())
})
}
-
- pub fn with_file2<F, R>(self: Rc<Self>, f: F) -> Option<Result<R, io::Error>>
- where
- F: FnOnce(&mut StdFile) -> Result<R, io::Error>,
- {
- self.with_inner(move |inner| inner.with_file(f))
- }
-
- pub async fn with_file_blocking_task<F, R: Send + 'static>(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
- f: F,
- ) -> Result<R, AnyError>
- where
- F: (FnOnce(&mut StdFile) -> Result<R, AnyError>) + Send + 'static,
- {
- let resource = state
- .borrow_mut()
- .resource_table
- .get::<StdFileResource>(rid)?;
-
- resource
- .with_inner_blocking_task(move |inner| inner.with_file(f))
+ async fn lock_async(self: Rc<Self>, exclusive: bool) -> FsResult<()> {
+ self
+ .with_inner_blocking_task(move |file| {
+ if exclusive {
+ file.lock_exclusive()?;
+ } else {
+ file.lock_shared()?;
+ }
+ Ok(())
+ })
.await
}
- pub async fn with_file_blocking_task2<F, R: Send + 'static>(
- self: Rc<Self>,
- f: F,
- ) -> Result<R, io::Error>
- where
- F: (FnOnce(&mut StdFile) -> Result<R, io::Error>) + Send + 'static,
- {
+ fn unlock_sync(self: Rc<Self>) -> FsResult<()> {
+ self.with_sync(|file| Ok(file.unlock()?))
+ }
+ async fn unlock_async(self: Rc<Self>) -> FsResult<()> {
self
- .with_inner_blocking_task(move |inner| inner.with_file(f))
+ .with_inner_blocking_task(|file| Ok(file.unlock()?))
.await
}
- pub fn clone_file(
- state: &mut OpState,
- rid: ResourceId,
- ) -> Result<StdFile, AnyError> {
- Self::with_file(state, rid, move |std_file| {
- std_file.try_clone().map_err(AnyError::from)
- })
+ fn truncate_sync(self: Rc<Self>, len: u64) -> FsResult<()> {
+ self.with_sync(|file| Ok(file.set_len(len)?))
}
-
- pub fn as_stdio(
- state: &mut OpState,
- rid: u32,
- ) -> Result<std::process::Stdio, AnyError> {
- Self::with_resource(state, rid, |resource| {
- resource
- .with_inner(|inner| match inner.kind {
- StdFileResourceKind::File => {
- let file = inner.file.try_clone()?;
- Ok(file.into())
- }
- _ => Ok(std::process::Stdio::inherit()),
- })
- .ok_or_else(resource_unavailable)?
- })
- }
-}
-
-impl Resource for StdFileResource {
- fn name(&self) -> Cow<str> {
- self.name.as_str().into()
+ async fn truncate_async(self: Rc<Self>, len: u64) -> FsResult<()> {
+ self
+ .with_inner_blocking_task(move |file| Ok(file.set_len(len)?))
+ .await
}
- fn read(self: Rc<Self>, limit: usize) -> AsyncResult<deno_core::BufView> {
- Box::pin(async move {
- let vec = vec![0; limit];
- let buf = BufMutView::from(vec);
- let (nread, buf) = StdFileResource::read_byob(self, buf).await?;
- let mut vec = buf.unwrap_vec();
- if vec.len() != nread {
- vec.truncate(nread);
- }
- Ok(BufView::from(vec))
+ fn utime_sync(
+ self: Rc<Self>,
+ atime_secs: i64,
+ atime_nanos: u32,
+ mtime_secs: i64,
+ mtime_nanos: u32,
+ ) -> FsResult<()> {
+ let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
+ let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
+
+ self.with_sync(|file| {
+ filetime::set_file_handle_times(file, Some(atime), Some(mtime))?;
+ Ok(())
})
}
-
- fn read_byob(
+ async fn utime_async(
self: Rc<Self>,
- buf: deno_core::BufMutView,
- ) -> AsyncResult<(usize, deno_core::BufMutView)> {
- Box::pin(StdFileResource::read_byob(self, buf))
- }
+ atime_secs: i64,
+ atime_nanos: u32,
+ mtime_secs: i64,
+ mtime_nanos: u32,
+ ) -> FsResult<()> {
+ let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
+ let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
- fn write(
- self: Rc<Self>,
- view: deno_core::BufView,
- ) -> AsyncResult<deno_core::WriteOutcome> {
- Box::pin(StdFileResource::write(self, view))
+ self
+ .with_inner_blocking_task(move |file| {
+ filetime::set_file_handle_times(file, Some(atime), Some(mtime))?;
+ Ok(())
+ })
+ .await
}
- fn write_all(self: Rc<Self>, view: deno_core::BufView) -> AsyncResult<()> {
- Box::pin(StdFileResource::write_all(self, view))
+ async fn read_byob(
+ self: Rc<Self>,
+ mut buf: BufMutView,
+ ) -> FsResult<(usize, BufMutView)> {
+ self
+ .with_inner_blocking_task(|file| {
+ let nread = file.read(&mut buf)?;
+ Ok((nread, buf))
+ })
+ .await
}
- fn write_sync(
- self: Rc<Self>,
- data: &[u8],
- ) -> Result<usize, deno_core::anyhow::Error> {
- StdFileResource::write_sync(self, data)
+ fn try_clone_inner(self: Rc<Self>) -> FsResult<Rc<dyn fs::File>> {
+ let inner: &Option<_> = &self.cell.borrow();
+ match inner {
+ Some(inner) => Ok(Rc::new(StdFileResourceInner {
+ kind: self.kind,
+ cell: RefCell::new(Some(inner.try_clone()?)),
+ cell_async_task_queue: Default::default(),
+ })),
+ None => Err(FsError::FileBusy),
+ }
}
- fn read_byob_sync(
- self: Rc<Self>,
- data: &mut [u8],
- ) -> Result<usize, deno_core::anyhow::Error> {
- StdFileResource::read_byob_sync(self, data)
+ fn as_stdio(self: Rc<Self>) -> FsResult<std::process::Stdio> {
+ match self.kind {
+ StdFileResourceKind::File => self.with_sync(|file| {
+ let file = file.try_clone()?;
+ Ok(file.into())
+ }),
+ _ => Ok(std::process::Stdio::inherit()),
+ }
}
#[cfg(unix)]
fn backing_fd(self: Rc<Self>) -> Option<std::os::unix::prelude::RawFd> {
use std::os::unix::io::AsRawFd;
- self
- .with_inner(move |std_file| {
- Ok::<_, ()>(std_file.with_file(|f| f.as_raw_fd()))
- })?
- .ok()
+ self.with_sync(|file| Ok(file.as_raw_fd())).ok()
+ }
+
+ #[cfg(windows)]
+ fn backing_fd(self: Rc<Self>) -> Option<std::os::windows::io::RawHandle> {
+ use std::os::windows::prelude::AsRawHandle;
+ self.with_sync(|file| Ok(file.as_raw_handle())).ok()
}
}
@@ -671,12 +739,7 @@ pub fn op_print(
is_err: bool,
) -> Result<(), AnyError> {
let rid = if is_err { 2 } else { 1 };
- StdFileResource::with_resource(state, rid, move |resource| {
- resource
- .with_inner(|inner| {
- inner.write_all_and_maybe_flush(msg.as_bytes())?;
- Ok(())
- })
- .ok_or_else(resource_unavailable)?
+ FileResource::with_file(state, rid, move |file| {
+ Ok(file.write_all_sync(msg.as_bytes())?)
})
}
diff --git a/runtime/build.rs b/runtime/build.rs
index bba2eae55..d096df7db 100644
--- a/runtime/build.rs
+++ b/runtime/build.rs
@@ -18,7 +18,6 @@ mod startup_snapshot {
use deno_core::Extension;
use deno_core::ExtensionFileSource;
use deno_core::ModuleCode;
- use deno_fs::StdFs;
use std::path::Path;
fn transpile_ts_for_snapshotting(
@@ -310,7 +309,10 @@ mod startup_snapshot {
deno_napi::deno_napi::init_ops_and_esm::<Permissions>(),
deno_http::deno_http::init_ops_and_esm(),
deno_io::deno_io::init_ops_and_esm(Default::default()),
- deno_fs::deno_fs::init_ops_and_esm::<_, Permissions>(false, StdFs),
+ deno_fs::deno_fs::init_ops_and_esm::<Permissions>(
+ false,
+ std::sync::Arc::new(deno_fs::RealFs),
+ ),
runtime::init_ops_and_esm(),
// FIXME(bartlomieju): these extensions are specified last, because they
// depend on `runtime`, even though it should be other way around
diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs
index cf8740255..d991c961f 100644
--- a/runtime/ops/process.rs
+++ b/runtime/ops/process.rs
@@ -12,10 +12,10 @@ use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
+use deno_io::fs::FileResource;
use deno_io::ChildStderrResource;
use deno_io::ChildStdinResource;
use deno_io::ChildStdoutResource;
-use deno_io::StdFileResource;
use serde::Deserialize;
use serde::Serialize;
use std::borrow::Cow;
@@ -93,7 +93,9 @@ impl StdioOrRid {
) -> Result<std::process::Stdio, AnyError> {
match &self {
StdioOrRid::Stdio(val) => Ok(val.as_stdio()),
- StdioOrRid::Rid(rid) => StdFileResource::as_stdio(state, *rid),
+ StdioOrRid::Rid(rid) => {
+ FileResource::with_file(state, *rid, |file| Ok(file.as_stdio()?))
+ }
}
}
}
diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs
index a3dc03a6f..7f24daec4 100644
--- a/runtime/ops/tty.rs
+++ b/runtime/ops/tty.rs
@@ -1,10 +1,14 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use std::io::Error;
+use std::rc::Rc;
+
+use deno_core::error::resource_unavailable;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
-use deno_io::StdFileResource;
-use std::io::Error;
+use deno_core::Resource;
+use deno_io::fs::FileResource;
#[cfg(unix)]
use deno_core::ResourceId;
@@ -14,8 +18,6 @@ use nix::sys::termios;
use std::cell::RefCell;
#[cfg(unix)]
use std::collections::HashMap;
-#[cfg(unix)]
-use std::rc::Rc;
#[cfg(unix)]
#[derive(Default, Clone)]
@@ -44,13 +46,14 @@ use winapi::shared::minwindef::DWORD;
use winapi::um::wincon;
#[cfg(windows)]
-fn get_windows_handle(
- f: &std::fs::File,
+fn get_fd_from_resource(
+ resource: Rc<FileResource>,
) -> Result<std::os::windows::io::RawHandle, AnyError> {
- use std::os::windows::io::AsRawHandle;
use winapi::um::handleapi;
- let handle = f.as_raw_handle();
+ let Some(handle) = resource.backing_fd() else {
+ return Err(resource_unavailable());
+ };
if handle == handleapi::INVALID_HANDLE_VALUE {
return Err(Error::last_os_error().into());
} else if handle.is_null() {
@@ -59,6 +62,16 @@ fn get_windows_handle(
Ok(handle)
}
+#[cfg(not(windows))]
+fn get_fd_from_resource(
+ resource: Rc<FileResource>,
+) -> Result<std::os::unix::prelude::RawFd, AnyError> {
+ match resource.backing_fd() {
+ Some(fd) => Ok(fd),
+ None => Err(resource_unavailable()),
+ }
+}
+
deno_core::extension!(
deno_tty,
ops = [op_stdin_set_raw, op_isatty, op_console_size],
@@ -106,23 +119,15 @@ fn op_stdin_set_raw(
// Copyright (c) 2019 Timon. MIT license.
#[cfg(windows)]
{
- use std::os::windows::io::AsRawHandle;
use winapi::shared::minwindef::FALSE;
use winapi::um::consoleapi;
- use winapi::um::handleapi;
if cbreak {
return Err(deno_core::error::not_supported());
}
- StdFileResource::with_file(state, rid, move |std_file| {
- let handle = std_file.as_raw_handle();
-
- if handle == handleapi::INVALID_HANDLE_VALUE {
- return Err(Error::last_os_error().into());
- } else if handle.is_null() {
- return Err(custom_error("ReferenceError", "null handle"));
- }
+ FileResource::with_resource(state, rid, move |resource| {
+ let handle = get_fd_from_resource(resource)?;
let mut original_mode: DWORD = 0;
// SAFETY: winapi call
if unsafe { consoleapi::GetConsoleMode(handle, &mut original_mode) }
@@ -147,13 +152,11 @@ fn op_stdin_set_raw(
}
#[cfg(unix)]
{
- use std::os::unix::io::AsRawFd;
-
let tty_mode_store = state.borrow::<TtyModeStore>().clone();
let previous_mode = tty_mode_store.get(rid);
- StdFileResource::with_file(state, rid, move |std_file| {
- let raw_fd = std_file.as_raw_fd();
+ FileResource::with_resource(state, rid, move |resource| {
+ let raw_fd = get_fd_from_resource(resource)?;
if is_raw {
let mut raw = match previous_mode {
@@ -201,13 +204,14 @@ fn op_isatty(
rid: u32,
out: &mut [u8],
) -> Result<(), AnyError> {
- StdFileResource::with_file(state, rid, move |std_file| {
+ FileResource::with_resource(state, rid, move |resource| {
+ let raw_fd = get_fd_from_resource(resource)?;
#[cfg(windows)]
{
use winapi::shared::minwindef::FALSE;
use winapi::um::consoleapi;
- let handle = get_windows_handle(std_file)?;
+ let handle = raw_fd;
let mut test_mode: DWORD = 0;
// If I cannot get mode out of console, it is not a console.
// TODO(bartlomieju):
@@ -220,8 +224,6 @@ fn op_isatty(
}
#[cfg(unix)]
{
- use std::os::unix::io::AsRawFd;
- let raw_fd = std_file.as_raw_fd();
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
{
@@ -242,8 +244,9 @@ fn op_console_size(
result: &mut [u32],
rid: u32,
) -> Result<(), AnyError> {
- StdFileResource::with_file(state, rid, move |std_file| {
- let size = console_size(std_file)?;
+ FileResource::with_resource(state, rid, move |resource| {
+ let fd = get_fd_from_resource(resource)?;
+ let size = console_size_from_fd(fd)?;
result[0] = size.cols;
result[1] = size.rows;
Ok(())
@@ -276,40 +279,50 @@ pub fn console_size(
{
use std::os::windows::io::AsRawHandle;
let handle = std_file.as_raw_handle();
-
- // SAFETY: winapi calls
- unsafe {
- let mut bufinfo: winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO =
- std::mem::zeroed();
-
- if winapi::um::wincon::GetConsoleScreenBufferInfo(handle, &mut bufinfo)
- == 0
- {
- return Err(Error::last_os_error());
- }
- Ok(ConsoleSize {
- cols: bufinfo.dwSize.X as u32,
- rows: bufinfo.dwSize.Y as u32,
- })
- }
+ console_size_from_fd(handle)
}
-
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
-
let fd = std_file.as_raw_fd();
- // SAFETY: libc calls
- unsafe {
- let mut size: libc::winsize = std::mem::zeroed();
- if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 {
- return Err(Error::last_os_error());
- }
- Ok(ConsoleSize {
- cols: size.ws_col as u32,
- rows: size.ws_row as u32,
- })
+ console_size_from_fd(fd)
+ }
+}
+
+#[cfg(windows)]
+fn console_size_from_fd(
+ handle: std::os::windows::io::RawHandle,
+) -> Result<ConsoleSize, std::io::Error> {
+ // SAFETY: winapi calls
+ unsafe {
+ let mut bufinfo: winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO =
+ std::mem::zeroed();
+
+ if winapi::um::wincon::GetConsoleScreenBufferInfo(handle, &mut bufinfo) == 0
+ {
+ return Err(Error::last_os_error());
}
+ Ok(ConsoleSize {
+ cols: bufinfo.dwSize.X as u32,
+ rows: bufinfo.dwSize.Y as u32,
+ })
+ }
+}
+
+#[cfg(not(windows))]
+fn console_size_from_fd(
+ fd: std::os::unix::prelude::RawFd,
+) -> Result<ConsoleSize, std::io::Error> {
+ // SAFETY: libc calls
+ unsafe {
+ let mut size: libc::winsize = std::mem::zeroed();
+ if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 {
+ return Err(Error::last_os_error());
+ }
+ Ok(ConsoleSize {
+ cols: size.ws_col as u32,
+ rows: size.ws_row as u32,
+ })
}
}
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index 1b3dd2809..e485c0c35 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -34,7 +34,7 @@ use deno_core::RuntimeOptions;
use deno_core::SharedArrayBufferStore;
use deno_core::Snapshot;
use deno_core::SourceMapGetter;
-use deno_fs::StdFs;
+use deno_fs::FileSystem;
use deno_io::Stdio;
use deno_kv::sqlite::SqliteDbHandler;
use deno_tls::RootCertStoreProvider;
@@ -331,6 +331,7 @@ pub struct WebWorkerOptions {
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
pub seed: Option<u64>,
+ pub fs: Arc<dyn FileSystem>,
pub module_loader: Rc<dyn ModuleLoader>,
pub node_fs: Option<Arc<dyn deno_node::NodeFs>>,
pub npm_resolver: Option<Arc<dyn deno_node::NpmResolver>>,
@@ -441,7 +442,7 @@ impl WebWorker {
deno_napi::deno_napi::init_ops::<PermissionsContainer>(),
deno_http::deno_http::init_ops(),
deno_io::deno_io::init_ops(Some(options.stdio)),
- deno_fs::deno_fs::init_ops::<_, PermissionsContainer>(unstable, StdFs),
+ deno_fs::deno_fs::init_ops::<PermissionsContainer>(unstable, options.fs),
deno_node::deno_node::init_ops::<PermissionsContainer>(
options.npm_resolver,
options.node_fs,
diff --git a/runtime/worker.rs b/runtime/worker.rs
index ac67011f0..b9db21780 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -30,7 +30,7 @@ use deno_core::RuntimeOptions;
use deno_core::SharedArrayBufferStore;
use deno_core::Snapshot;
use deno_core::SourceMapGetter;
-use deno_fs::StdFs;
+use deno_fs::FileSystem;
use deno_io::Stdio;
use deno_kv::sqlite::SqliteDbHandler;
use deno_tls::RootCertStoreProvider;
@@ -87,6 +87,7 @@ pub struct WorkerOptions {
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
pub seed: Option<u64>,
+ pub fs: Arc<dyn FileSystem>,
/// Implementation of `ModuleLoader` which will be
/// called when V8 requests to load ES modules.
///
@@ -149,6 +150,7 @@ impl Default for WorkerOptions {
create_web_worker_cb: Arc::new(|_| {
unimplemented!("web workers are not supported")
}),
+ fs: Arc::new(deno_fs::RealFs),
module_loader: Rc::new(FsModuleLoader),
seed: None,
unsafely_ignore_certificate_errors: Default::default(),
@@ -266,7 +268,7 @@ impl MainWorker {
deno_napi::deno_napi::init_ops::<PermissionsContainer>(),
deno_http::deno_http::init_ops(),
deno_io::deno_io::init_ops(Some(options.stdio)),
- deno_fs::deno_fs::init_ops::<_, PermissionsContainer>(unstable, StdFs),
+ deno_fs::deno_fs::init_ops::<PermissionsContainer>(unstable, options.fs),
deno_node::deno_node::init_ops::<PermissionsContainer>(
options.npm_resolver,
options.node_fs,