summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2024-10-18 06:38:17 -0700
committerGitHub <noreply@github.com>2024-10-18 06:38:17 -0700
commit85a99eb405ef3ec5f8e478d93b2c866afbc53f95 (patch)
tree681e7c8862a2ddca6d9d8e3531b3a7d2340ff901
parentc77c9b29581b76e00caa56f654ba4326d297f355 (diff)
refactor(ext/fs): use concrete error types (#26317)
-rw-r--r--Cargo.lock13
-rw-r--r--Cargo.toml2
-rw-r--r--ext/fs/Cargo.toml1
-rw-r--r--ext/fs/lib.rs2
-rw-r--r--ext/fs/ops.rs573
-rw-r--r--runtime/errors.rs31
6 files changed, 424 insertions, 198 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bcbbaaae0..9b2baf79c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1423,9 +1423,9 @@ dependencies = [
[[package]]
name = "deno_core"
-version = "0.314.1"
+version = "0.314.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcd11ab87426c611b7170138a768dad7170c8fb66d8095b773d25e58fd254ea"
+checksum = "83138917579676069b423c3eb9be3c1e579f60dc022d85f6ded4c792456255ff"
dependencies = [
"anyhow",
"bincode",
@@ -1600,6 +1600,7 @@ dependencies = [
"rand",
"rayon",
"serde",
+ "thiserror",
"winapi",
"windows-sys 0.52.0",
]
@@ -1916,9 +1917,9 @@ dependencies = [
[[package]]
name = "deno_ops"
-version = "0.190.0"
+version = "0.190.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a48a3e06cace18a2c49e148da067678c6af80e70757a8c3991301397cf6b9919"
+checksum = "26f46d4e4f52f26c882b74a9b58810ea75252b807cf0966166ec333077cdfd85"
dependencies = [
"proc-macro-rules",
"proc-macro2",
@@ -6215,9 +6216,9 @@ dependencies = [
[[package]]
name = "serde_v8"
-version = "0.223.0"
+version = "0.223.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c127bb9f2024433d06789b242477c808fd7f7dc4c3278576dd5bc99c4e5c75ff"
+checksum = "9cf3d859dda87ee96423c01244f10af864fa6d6a9fcdc2b77e0595078ea0ea11"
dependencies = [
"num-bigint",
"serde",
diff --git a/Cargo.toml b/Cargo.toml
index 3bf5342b8..e2f439e37 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies]
deno_ast = { version = "=0.42.2", features = ["transpiling"] }
-deno_core = { version = "0.314.1" }
+deno_core = { version = "0.314.2" }
deno_bench_util = { version = "0.167.0", path = "./bench_util" }
deno_lockfile = "=0.23.1"
diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml
index a33347f9c..313c84fdb 100644
--- a/ext/fs/Cargo.toml
+++ b/ext/fs/Cargo.toml
@@ -28,6 +28,7 @@ libc.workspace = true
rand.workspace = true
rayon = "1.8.0"
serde.workspace = true
+thiserror.workspace = true
[target.'cfg(unix)'.dependencies]
nix.workspace = true
diff --git a/ext/fs/lib.rs b/ext/fs/lib.rs
index bd49078b2..cd2baf22a 100644
--- a/ext/fs/lib.rs
+++ b/ext/fs/lib.rs
@@ -14,6 +14,8 @@ pub use crate::interface::FileSystemRc;
pub use crate::interface::FsDirEntry;
pub use crate::interface::FsFileType;
pub use crate::interface::OpenOptions;
+pub use crate::ops::FsOpsError;
+pub use crate::ops::OperationError;
pub use crate::std_fs::RealFs;
pub use crate::sync::MaybeSend;
pub use crate::sync::MaybeSync;
diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs
index b13d3a7d1..a3f59da4e 100644
--- a/ext/fs/ops.rs
+++ b/ext/fs/ops.rs
@@ -1,6 +1,8 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::cell::RefCell;
+use std::error::Error;
+use std::fmt::Formatter;
use std::io;
use std::io::SeekFrom;
use std::path::Path;
@@ -8,10 +10,6 @@ use std::path::PathBuf;
use std::path::StripPrefixError;
use std::rc::Rc;
-use deno_core::anyhow::bail;
-use deno_core::error::custom_error;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
@@ -34,6 +32,67 @@ use crate::interface::FsFileType;
use crate::FsPermissions;
use crate::OpenOptions;
+#[derive(Debug, thiserror::Error)]
+pub enum FsOpsError {
+ #[error("{0}")]
+ Io(#[source] std::io::Error),
+ #[error("{0}")]
+ OperationError(#[source] OperationError),
+ #[error(transparent)]
+ Permission(deno_core::error::AnyError),
+ #[error(transparent)]
+ Resource(deno_core::error::AnyError),
+ #[error("File name or path {0:?} is not valid UTF-8")]
+ InvalidUtf8(std::ffi::OsString),
+ #[error("{0}")]
+ StripPrefix(#[from] StripPrefixError),
+ #[error("{0}")]
+ Canceled(#[from] deno_core::Canceled),
+ #[error("Invalid seek mode: {0}")]
+ InvalidSeekMode(i32),
+ #[error("Invalid control character in prefix or suffix: {0:?}")]
+ InvalidControlCharacter(String),
+ #[error("Invalid character in prefix or suffix: {0:?}")]
+ InvalidCharacter(String),
+ #[cfg(windows)]
+ #[error("Invalid trailing character in suffix")]
+ InvalidTrailingCharacter,
+ #[error("Requires {err} access to {path}, {}", print_not_capable_info(*.standalone, .err))]
+ NotCapableAccess {
+ // NotCapable
+ standalone: bool,
+ err: &'static str,
+ path: String,
+ },
+ #[error("permission denied: {0}")]
+ NotCapable(&'static str), // NotCapable
+ #[error(transparent)]
+ Other(deno_core::error::AnyError),
+}
+
+impl From<FsError> for FsOpsError {
+ fn from(err: FsError) -> Self {
+ match err {
+ FsError::Io(err) => FsOpsError::Io(err),
+ FsError::FileBusy => {
+ FsOpsError::Other(deno_core::error::resource_unavailable())
+ }
+ FsError::NotSupported => {
+ FsOpsError::Other(deno_core::error::not_supported())
+ }
+ FsError::NotCapable(err) => FsOpsError::NotCapable(err),
+ }
+ }
+}
+
+fn print_not_capable_info(standalone: bool, err: &'static str) -> String {
+ if standalone {
+ format!("specify the required permissions during compilation using `deno compile --allow-{err}`")
+ } else {
+ format!("run again with the --allow-{err} flag")
+ }
+}
+
fn sync_permission_check<'a, P: FsPermissions + 'static>(
permissions: &'a mut P,
api_name: &'static str,
@@ -58,7 +117,7 @@ fn map_permission_error(
operation: &'static str,
error: FsError,
path: &Path,
-) -> AnyError {
+) -> FsOpsError {
match error {
FsError::NotCapable(err) => {
let path = format!("{path:?}");
@@ -67,14 +126,12 @@ fn map_permission_error(
} else {
(path.as_str(), "")
};
- let msg = if deno_permissions::is_standalone() {
- format!(
- "Requires {err} access to {path}{truncated}, specify the required permissions during compilation using `deno compile --allow-{err}`")
- } else {
- format!(
- "Requires {err} access to {path}{truncated}, run again with the --allow-{err} flag")
- };
- custom_error("NotCapable", msg)
+
+ FsOpsError::NotCapableAccess {
+ standalone: deno_permissions::is_standalone(),
+ err,
+ path: format!("{path}{truncated}"),
+ }
}
err => Err::<(), _>(err)
.context_path(operation, path)
@@ -85,7 +142,7 @@ fn map_permission_error(
#[op2]
#[string]
-pub fn op_fs_cwd<P>(state: &mut OpState) -> Result<String, AnyError>
+pub fn op_fs_cwd<P>(state: &mut OpState) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -93,7 +150,8 @@ where
let path = fs.cwd()?;
state
.borrow_mut::<P>()
- .check_read_blind(&path, "CWD", "Deno.cwd()")?;
+ .check_read_blind(&path, "CWD", "Deno.cwd()")
+ .map_err(FsOpsError::Permission)?;
let path_str = path_into_string(path.into_os_string())?;
Ok(path_str)
}
@@ -102,13 +160,14 @@ where
pub fn op_fs_chdir<P>(
state: &mut OpState,
#[string] directory: &str,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let d = state
.borrow_mut::<P>()
- .check_read(directory, "Deno.chdir()")?;
+ .check_read(directory, "Deno.chdir()")
+ .map_err(FsOpsError::Permission)?;
state
.borrow::<FileSystemRc>()
.chdir(&d)
@@ -119,7 +178,7 @@ where
pub fn op_fs_umask(
state: &mut OpState,
mask: Option<u32>,
-) -> Result<u32, AnyError>
+) -> Result<u32, FsOpsError>
where
{
state.borrow::<FileSystemRc>().umask(mask).context("umask")
@@ -131,7 +190,7 @@ pub fn op_fs_open_sync<P>(
state: &mut OpState,
#[string] path: String,
#[serde] options: Option<OpenOptions>,
-) -> Result<ResourceId, AnyError>
+) -> Result<ResourceId, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -158,7 +217,7 @@ pub async fn op_fs_open_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
#[serde] options: Option<OpenOptions>,
-) -> Result<ResourceId, AnyError>
+) -> Result<ResourceId, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -186,7 +245,7 @@ pub fn op_fs_mkdir_sync<P>(
#[string] path: String,
recursive: bool,
mode: Option<u32>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -194,7 +253,8 @@ where
let path = state
.borrow_mut::<P>()
- .check_write(&path, "Deno.mkdirSync()")?;
+ .check_write(&path, "Deno.mkdirSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.mkdir_sync(&path, recursive, Some(mode))
@@ -209,7 +269,7 @@ pub async fn op_fs_mkdir_async<P>(
#[string] path: String,
recursive: bool,
mode: Option<u32>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -217,7 +277,10 @@ where
let (fs, path) = {
let mut state = state.borrow_mut();
- let path = state.borrow_mut::<P>().check_write(&path, "Deno.mkdir()")?;
+ let path = state
+ .borrow_mut::<P>()
+ .check_write(&path, "Deno.mkdir()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
@@ -233,13 +296,14 @@ pub fn op_fs_chmod_sync<P>(
state: &mut OpState,
#[string] path: String,
mode: u32,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_write(&path, "Deno.chmodSync()")?;
+ .check_write(&path, "Deno.chmodSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.chmod_sync(&path, mode).context_path("chmod", &path)?;
Ok(())
@@ -250,13 +314,16 @@ pub async fn op_fs_chmod_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
mode: u32,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, path) = {
let mut state = state.borrow_mut();
- let path = state.borrow_mut::<P>().check_write(&path, "Deno.chmod()")?;
+ let path = state
+ .borrow_mut::<P>()
+ .check_write(&path, "Deno.chmod()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
fs.chmod_async(path.clone(), mode)
@@ -271,13 +338,14 @@ pub fn op_fs_chown_sync<P>(
#[string] path: String,
uid: Option<u32>,
gid: Option<u32>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_write(&path, "Deno.chownSync()")?;
+ .check_write(&path, "Deno.chownSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.chown_sync(&path, uid, gid)
.context_path("chown", &path)?;
@@ -290,13 +358,16 @@ pub async fn op_fs_chown_async<P>(
#[string] path: String,
uid: Option<u32>,
gid: Option<u32>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, path) = {
let mut state = state.borrow_mut();
- let path = state.borrow_mut::<P>().check_write(&path, "Deno.chown()")?;
+ let path = state
+ .borrow_mut::<P>()
+ .check_write(&path, "Deno.chown()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
fs.chown_async(path.clone(), uid, gid)
@@ -310,13 +381,14 @@ pub fn op_fs_remove_sync<P>(
state: &mut OpState,
#[string] path: &str,
recursive: bool,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_write(path, "Deno.removeSync()")?;
+ .check_write(path, "Deno.removeSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.remove_sync(&path, recursive)
@@ -330,7 +402,7 @@ pub async fn op_fs_remove_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
recursive: bool,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -339,11 +411,13 @@ where
let path = if recursive {
state
.borrow_mut::<P>()
- .check_write(&path, "Deno.remove()")?
+ .check_write(&path, "Deno.remove()")
+ .map_err(FsOpsError::Permission)?
} else {
state
.borrow_mut::<P>()
- .check_write_partial(&path, "Deno.remove()")?
+ .check_write_partial(&path, "Deno.remove()")
+ .map_err(FsOpsError::Permission)?
};
(state.borrow::<FileSystemRc>().clone(), path)
@@ -361,13 +435,17 @@ pub fn op_fs_copy_file_sync<P>(
state: &mut OpState,
#[string] from: &str,
#[string] to: &str,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let permissions = state.borrow_mut::<P>();
- let from = permissions.check_read(from, "Deno.copyFileSync()")?;
- let to = permissions.check_write(to, "Deno.copyFileSync()")?;
+ let from = permissions
+ .check_read(from, "Deno.copyFileSync()")
+ .map_err(FsOpsError::Permission)?;
+ let to = permissions
+ .check_write(to, "Deno.copyFileSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.copy_file_sync(&from, &to)
@@ -381,15 +459,19 @@ pub async fn op_fs_copy_file_async<P>(
state: Rc<RefCell<OpState>>,
#[string] from: String,
#[string] to: String,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, from, to) = {
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
- let from = permissions.check_read(&from, "Deno.copyFile()")?;
- let to = permissions.check_write(&to, "Deno.copyFile()")?;
+ let from = permissions
+ .check_read(&from, "Deno.copyFile()")
+ .map_err(FsOpsError::Permission)?;
+ let to = permissions
+ .check_write(&to, "Deno.copyFile()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), from, to)
};
@@ -405,13 +487,14 @@ pub fn op_fs_stat_sync<P>(
state: &mut OpState,
#[string] path: String,
#[buffer] stat_out_buf: &mut [u32],
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_read(&path, "Deno.statSync()")?;
+ .check_read(&path, "Deno.statSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
let stat = fs.stat_sync(&path).context_path("stat", &path)?;
let serializable_stat = SerializableStat::from(stat);
@@ -424,14 +507,16 @@ where
pub async fn op_fs_stat_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
-) -> Result<SerializableStat, AnyError>
+) -> Result<SerializableStat, FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, path) = {
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
- let path = permissions.check_read(&path, "Deno.stat()")?;
+ let path = permissions
+ .check_read(&path, "Deno.stat()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
let stat = fs
@@ -446,13 +531,14 @@ pub fn op_fs_lstat_sync<P>(
state: &mut OpState,
#[string] path: String,
#[buffer] stat_out_buf: &mut [u32],
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_read(&path, "Deno.lstatSync()")?;
+ .check_read(&path, "Deno.lstatSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
let stat = fs.lstat_sync(&path).context_path("lstat", &path)?;
let serializable_stat = SerializableStat::from(stat);
@@ -465,14 +551,16 @@ where
pub async fn op_fs_lstat_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
-) -> Result<SerializableStat, AnyError>
+) -> Result<SerializableStat, FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, path) = {
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
- let path = permissions.check_read(&path, "Deno.lstat()")?;
+ let path = permissions
+ .check_read(&path, "Deno.lstat()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
let stat = fs
@@ -487,15 +575,19 @@ where
pub fn op_fs_realpath_sync<P>(
state: &mut OpState,
#[string] path: String,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
let fs = state.borrow::<FileSystemRc>().clone();
let permissions = state.borrow_mut::<P>();
- let path = permissions.check_read(&path, "Deno.realPathSync()")?;
+ let path = permissions
+ .check_read(&path, "Deno.realPathSync()")
+ .map_err(FsOpsError::Permission)?;
if path.is_relative() {
- permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPathSync()")?;
+ permissions
+ .check_read_blind(&fs.cwd()?, "CWD", "Deno.realPathSync()")
+ .map_err(FsOpsError::Permission)?;
}
let resolved_path =
@@ -510,7 +602,7 @@ where
pub async fn op_fs_realpath_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -518,9 +610,13 @@ where
let mut state = state.borrow_mut();
let fs = state.borrow::<FileSystemRc>().clone();
let permissions = state.borrow_mut::<P>();
- let path = permissions.check_read(&path, "Deno.realPath()")?;
+ let path = permissions
+ .check_read(&path, "Deno.realPath()")
+ .map_err(FsOpsError::Permission)?;
if path.is_relative() {
- permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPath()")?;
+ permissions
+ .check_read_blind(&fs.cwd()?, "CWD", "Deno.realPath()")
+ .map_err(FsOpsError::Permission)?;
}
(fs, path)
};
@@ -538,13 +634,14 @@ where
pub fn op_fs_read_dir_sync<P>(
state: &mut OpState,
#[string] path: String,
-) -> Result<Vec<FsDirEntry>, AnyError>
+) -> Result<Vec<FsDirEntry>, FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_read(&path, "Deno.readDirSync()")?;
+ .check_read(&path, "Deno.readDirSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
let entries = fs.read_dir_sync(&path).context_path("readdir", &path)?;
@@ -557,7 +654,7 @@ where
pub async fn op_fs_read_dir_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
-) -> Result<Vec<FsDirEntry>, AnyError>
+) -> Result<Vec<FsDirEntry>, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -565,7 +662,8 @@ where
let mut state = state.borrow_mut();
let path = state
.borrow_mut::<P>()
- .check_read(&path, "Deno.readDir()")?;
+ .check_read(&path, "Deno.readDir()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
@@ -582,14 +680,20 @@ pub fn op_fs_rename_sync<P>(
state: &mut OpState,
#[string] oldpath: String,
#[string] newpath: String,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let permissions = state.borrow_mut::<P>();
- let _ = permissions.check_read(&oldpath, "Deno.renameSync()")?;
- let oldpath = permissions.check_write(&oldpath, "Deno.renameSync()")?;
- let newpath = permissions.check_write(&newpath, "Deno.renameSync()")?;
+ let _ = permissions
+ .check_read(&oldpath, "Deno.renameSync()")
+ .map_err(FsOpsError::Permission)?;
+ let oldpath = permissions
+ .check_write(&oldpath, "Deno.renameSync()")
+ .map_err(FsOpsError::Permission)?;
+ let newpath = permissions
+ .check_write(&newpath, "Deno.renameSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.rename_sync(&oldpath, &newpath)
@@ -603,16 +707,22 @@ pub async fn op_fs_rename_async<P>(
state: Rc<RefCell<OpState>>,
#[string] oldpath: String,
#[string] newpath: String,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, oldpath, newpath) = {
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
- _ = permissions.check_read(&oldpath, "Deno.rename()")?;
- let oldpath = permissions.check_write(&oldpath, "Deno.rename()")?;
- let newpath = permissions.check_write(&newpath, "Deno.rename()")?;
+ _ = permissions
+ .check_read(&oldpath, "Deno.rename()")
+ .map_err(FsOpsError::Permission)?;
+ let oldpath = permissions
+ .check_write(&oldpath, "Deno.rename()")
+ .map_err(FsOpsError::Permission)?;
+ let newpath = permissions
+ .check_write(&newpath, "Deno.rename()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), oldpath, newpath)
};
@@ -628,15 +738,23 @@ pub fn op_fs_link_sync<P>(
state: &mut OpState,
#[string] oldpath: &str,
#[string] newpath: &str,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let permissions = state.borrow_mut::<P>();
- _ = permissions.check_read(oldpath, "Deno.linkSync()")?;
- let oldpath = permissions.check_write(oldpath, "Deno.linkSync()")?;
- _ = permissions.check_read(newpath, "Deno.linkSync()")?;
- let newpath = permissions.check_write(newpath, "Deno.linkSync()")?;
+ _ = permissions
+ .check_read(oldpath, "Deno.linkSync()")
+ .map_err(FsOpsError::Permission)?;
+ let oldpath = permissions
+ .check_write(oldpath, "Deno.linkSync()")
+ .map_err(FsOpsError::Permission)?;
+ _ = permissions
+ .check_read(newpath, "Deno.linkSync()")
+ .map_err(FsOpsError::Permission)?;
+ let newpath = permissions
+ .check_write(newpath, "Deno.linkSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.link_sync(&oldpath, &newpath)
@@ -650,17 +768,25 @@ pub async fn op_fs_link_async<P>(
state: Rc<RefCell<OpState>>,
#[string] oldpath: String,
#[string] newpath: String,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, oldpath, newpath) = {
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
- _ = permissions.check_read(&oldpath, "Deno.link()")?;
- let oldpath = permissions.check_write(&oldpath, "Deno.link()")?;
- _ = permissions.check_read(&newpath, "Deno.link()")?;
- let newpath = permissions.check_write(&newpath, "Deno.link()")?;
+ _ = permissions
+ .check_read(&oldpath, "Deno.link()")
+ .map_err(FsOpsError::Permission)?;
+ let oldpath = permissions
+ .check_write(&oldpath, "Deno.link()")
+ .map_err(FsOpsError::Permission)?;
+ _ = permissions
+ .check_read(&newpath, "Deno.link()")
+ .map_err(FsOpsError::Permission)?;
+ let newpath = permissions
+ .check_write(&newpath, "Deno.link()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), oldpath, newpath)
};
@@ -677,7 +803,7 @@ pub fn op_fs_symlink_sync<P>(
#[string] oldpath: &str,
#[string] newpath: &str,
#[serde] file_type: Option<FsFileType>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -685,8 +811,12 @@ where
let newpath = PathBuf::from(newpath);
let permissions = state.borrow_mut::<P>();
- permissions.check_write_all("Deno.symlinkSync()")?;
- permissions.check_read_all("Deno.symlinkSync()")?;
+ permissions
+ .check_write_all("Deno.symlinkSync()")
+ .map_err(FsOpsError::Permission)?;
+ permissions
+ .check_read_all("Deno.symlinkSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.symlink_sync(&oldpath, &newpath, file_type)
@@ -701,7 +831,7 @@ pub async fn op_fs_symlink_async<P>(
#[string] oldpath: String,
#[string] newpath: String,
#[serde] file_type: Option<FsFileType>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -711,8 +841,12 @@ where
let fs = {
let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>();
- permissions.check_write_all("Deno.symlink()")?;
- permissions.check_read_all("Deno.symlink()")?;
+ permissions
+ .check_write_all("Deno.symlink()")
+ .map_err(FsOpsError::Permission)?;
+ permissions
+ .check_read_all("Deno.symlink()")
+ .map_err(FsOpsError::Permission)?;
state.borrow::<FileSystemRc>().clone()
};
@@ -728,13 +862,14 @@ where
pub fn op_fs_read_link_sync<P>(
state: &mut OpState,
#[string] path: String,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_read(&path, "Deno.readLink()")?;
+ .check_read(&path, "Deno.readLink()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
@@ -748,7 +883,7 @@ where
pub async fn op_fs_read_link_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -756,7 +891,8 @@ where
let mut state = state.borrow_mut();
let path = state
.borrow_mut::<P>()
- .check_read(&path, "Deno.readLink()")?;
+ .check_read(&path, "Deno.readLink()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
@@ -773,13 +909,14 @@ pub fn op_fs_truncate_sync<P>(
state: &mut OpState,
#[string] path: &str,
#[number] len: u64,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let path = state
.borrow_mut::<P>()
- .check_write(path, "Deno.truncateSync()")?;
+ .check_write(path, "Deno.truncateSync()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.truncate_sync(&path, len)
@@ -793,7 +930,7 @@ pub async fn op_fs_truncate_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
#[number] len: u64,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -801,7 +938,8 @@ where
let mut state = state.borrow_mut();
let path = state
.borrow_mut::<P>()
- .check_write(&path, "Deno.truncate()")?;
+ .check_write(&path, "Deno.truncate()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
@@ -820,11 +958,14 @@ pub fn op_fs_utime_sync<P>(
#[smi] atime_nanos: u32,
#[number] mtime_secs: i64,
#[smi] mtime_nanos: u32,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
- let path = state.borrow_mut::<P>().check_write(path, "Deno.utime()")?;
+ let path = state
+ .borrow_mut::<P>()
+ .check_write(path, "Deno.utime()")
+ .map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>();
fs.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
@@ -841,13 +982,16 @@ pub async fn op_fs_utime_async<P>(
#[smi] atime_nanos: u32,
#[number] mtime_secs: i64,
#[smi] mtime_nanos: u32,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
let (fs, path) = {
let mut state = state.borrow_mut();
- let path = state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
+ let path = state
+ .borrow_mut::<P>()
+ .check_write(&path, "Deno.utime()")
+ .map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path)
};
@@ -871,7 +1015,7 @@ pub fn op_fs_make_temp_dir_sync<P>(
#[string] dir_arg: Option<String>,
#[string] prefix: Option<String>,
#[string] suffix: Option<String>,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -913,7 +1057,7 @@ pub async fn op_fs_make_temp_dir_async<P>(
#[string] dir_arg: Option<String>,
#[string] prefix: Option<String>,
#[string] suffix: Option<String>,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -959,7 +1103,7 @@ pub fn op_fs_make_temp_file_sync<P>(
#[string] dir_arg: Option<String>,
#[string] prefix: Option<String>,
#[string] suffix: Option<String>,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1007,7 +1151,7 @@ pub async fn op_fs_make_temp_file_async<P>(
#[string] dir_arg: Option<String>,
#[string] prefix: Option<String>,
#[string] suffix: Option<String>,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1069,18 +1213,22 @@ fn make_temp_check_sync<P>(
state: &mut OpState,
dir: Option<&str>,
api_name: &str,
-) -> Result<(PathBuf, FileSystemRc), AnyError>
+) -> Result<(PathBuf, FileSystemRc), FsOpsError>
where
P: FsPermissions + 'static,
{
let fs = state.borrow::<FileSystemRc>().clone();
let dir = match dir {
- Some(dir) => state.borrow_mut::<P>().check_write(dir, api_name)?,
+ Some(dir) => state
+ .borrow_mut::<P>()
+ .check_write(dir, api_name)
+ .map_err(FsOpsError::Permission)?,
None => {
let dir = fs.tmp_dir().context("tmpdir")?;
state
.borrow_mut::<P>()
- .check_write_blind(&dir, "TMP", api_name)?;
+ .check_write_blind(&dir, "TMP", api_name)
+ .map_err(FsOpsError::Permission)?;
dir
}
};
@@ -1091,19 +1239,23 @@ fn make_temp_check_async<P>(
state: Rc<RefCell<OpState>>,
dir: Option<&str>,
api_name: &str,
-) -> Result<(PathBuf, FileSystemRc), AnyError>
+) -> Result<(PathBuf, FileSystemRc), FsOpsError>
where
P: FsPermissions + 'static,
{
let mut state = state.borrow_mut();
let fs = state.borrow::<FileSystemRc>().clone();
let dir = match dir {
- Some(dir) => state.borrow_mut::<P>().check_write(dir, api_name)?,
+ Some(dir) => state
+ .borrow_mut::<P>()
+ .check_write(dir, api_name)
+ .map_err(FsOpsError::Permission)?,
None => {
let dir = fs.tmp_dir().context("tmpdir")?;
state
.borrow_mut::<P>()
- .check_write_blind(&dir, "TMP", api_name)?;
+ .check_write_blind(&dir, "TMP", api_name)
+ .map_err(FsOpsError::Permission)?;
dir
}
};
@@ -1116,10 +1268,10 @@ where
fn validate_temporary_filename_component(
component: &str,
#[allow(unused_variables)] suffix: bool,
-) -> Result<(), AnyError> {
+) -> Result<(), FsOpsError> {
// Ban ASCII and Unicode control characters: these will often fail
if let Some(c) = component.matches(|c: char| c.is_control()).next() {
- bail!("Invalid control character in prefix or suffix: {:?}", c);
+ return Err(FsOpsError::InvalidControlCharacter(c.to_string()));
}
// Windows has the most restrictive filenames. As temp files aren't normal files, we just
// use this set of banned characters for all platforms because wildcard-like files can also
@@ -1135,13 +1287,13 @@ fn validate_temporary_filename_component(
.matches(|c: char| "<>:\"/\\|?*".contains(c))
.next()
{
- bail!("Invalid character in prefix or suffix: {:?}", c);
+ return Err(FsOpsError::InvalidCharacter(c.to_string()));
}
// This check is only for Windows
#[cfg(windows)]
if suffix && component.ends_with(|c: char| ". ".contains(c)) {
- bail!("Invalid trailing character in suffix");
+ return Err(FsOpsError::InvalidTrailingCharacter);
}
Ok(())
@@ -1152,7 +1304,7 @@ fn tmp_name(
dir: &Path,
prefix: Option<&str>,
suffix: Option<&str>,
-) -> Result<PathBuf, AnyError> {
+) -> Result<PathBuf, FsOpsError> {
let prefix = prefix.unwrap_or("");
validate_temporary_filename_component(prefix, false)?;
let suffix = suffix.unwrap_or("");
@@ -1179,7 +1331,7 @@ pub fn op_fs_write_file_sync<P>(
create: bool,
create_new: bool,
#[buffer] data: JsBuffer,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1207,7 +1359,7 @@ pub async fn op_fs_write_file_async<P>(
create_new: bool,
#[buffer] data: JsBuffer,
#[smi] cancel_rid: Option<ResourceId>,
-) -> Result<(), AnyError>
+) -> Result<(), FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1255,7 +1407,7 @@ where
pub fn op_fs_read_file_sync<P>(
state: &mut OpState,
#[string] path: String,
-) -> Result<ToJsBuffer, AnyError>
+) -> Result<ToJsBuffer, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1277,7 +1429,7 @@ pub async fn op_fs_read_file_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
#[smi] cancel_rid: Option<ResourceId>,
-) -> Result<ToJsBuffer, AnyError>
+) -> Result<ToJsBuffer, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1318,7 +1470,7 @@ where
pub fn op_fs_read_file_text_sync<P>(
state: &mut OpState,
#[string] path: String,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1340,7 +1492,7 @@ pub async fn op_fs_read_file_text_async<P>(
state: Rc<RefCell<OpState>>,
#[string] path: String,
#[smi] cancel_rid: Option<ResourceId>,
-) -> Result<String, AnyError>
+) -> Result<String, FsOpsError>
where
P: FsPermissions + 'static,
{
@@ -1377,13 +1529,13 @@ where
Ok(str)
}
-fn to_seek_from(offset: i64, whence: i32) -> Result<SeekFrom, AnyError> {
+fn to_seek_from(offset: i64, whence: i32) -> Result<SeekFrom, FsOpsError> {
let seek_from = match whence {
0 => SeekFrom::Start(offset as u64),
1 => SeekFrom::Current(offset),
2 => SeekFrom::End(offset),
_ => {
- return Err(type_error(format!("Invalid seek mode: {whence}")));
+ return Err(FsOpsError::InvalidSeekMode(whence));
}
};
Ok(seek_from)
@@ -1396,9 +1548,10 @@ pub fn op_fs_seek_sync(
#[smi] rid: ResourceId,
#[number] offset: i64,
#[smi] whence: i32,
-) -> Result<u64, AnyError> {
+) -> Result<u64, FsOpsError> {
let pos = to_seek_from(offset, whence)?;
- let file = FileResource::get_file(state, rid)?;
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
let cursor = file.seek_sync(pos)?;
Ok(cursor)
}
@@ -1410,9 +1563,10 @@ pub async fn op_fs_seek_async(
#[smi] rid: ResourceId,
#[number] offset: i64,
#[smi] whence: i32,
-) -> Result<u64, AnyError> {
+) -> Result<u64, FsOpsError> {
let pos = to_seek_from(offset, whence)?;
- let file = FileResource::get_file(&state.borrow(), rid)?;
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
let cursor = file.seek_async(pos).await?;
Ok(cursor)
}
@@ -1421,8 +1575,9 @@ pub async fn op_fs_seek_async(
pub fn op_fs_file_sync_data_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
file.datasync_sync()?;
Ok(())
}
@@ -1431,8 +1586,9 @@ pub fn op_fs_file_sync_data_sync(
pub async fn op_fs_file_sync_data_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<(), FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
file.datasync_async().await?;
Ok(())
}
@@ -1441,8 +1597,9 @@ pub async fn op_fs_file_sync_data_async(
pub fn op_fs_file_sync_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
file.sync_sync()?;
Ok(())
}
@@ -1451,8 +1608,9 @@ pub fn op_fs_file_sync_sync(
pub async fn op_fs_file_sync_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<(), FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
file.sync_async().await?;
Ok(())
}
@@ -1462,8 +1620,9 @@ pub fn op_fs_file_stat_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
#[buffer] stat_out_buf: &mut [u32],
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
let stat = file.stat_sync()?;
let serializable_stat = SerializableStat::from(stat);
serializable_stat.write(stat_out_buf);
@@ -1475,8 +1634,9 @@ pub fn op_fs_file_stat_sync(
pub async fn op_fs_file_stat_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
-) -> Result<SerializableStat, AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<SerializableStat, FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
let stat = file.stat_async().await?;
Ok(stat.into())
}
@@ -1486,8 +1646,9 @@ pub fn op_fs_flock_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
exclusive: bool,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
file.lock_sync(exclusive)?;
Ok(())
}
@@ -1497,8 +1658,9 @@ pub async fn op_fs_flock_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
exclusive: bool,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<(), FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
file.lock_async(exclusive).await?;
Ok(())
}
@@ -1507,8 +1669,9 @@ pub async fn op_fs_flock_async(
pub fn op_fs_funlock_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
file.unlock_sync()?;
Ok(())
}
@@ -1517,8 +1680,9 @@ pub fn op_fs_funlock_sync(
pub async fn op_fs_funlock_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<(), FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
file.unlock_async().await?;
Ok(())
}
@@ -1528,8 +1692,9 @@ pub fn op_fs_ftruncate_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
#[number] len: u64,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
file.truncate_sync(len)?;
Ok(())
}
@@ -1539,8 +1704,9 @@ pub async fn op_fs_file_truncate_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
#[number] len: u64,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<(), FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
file.truncate_async(len).await?;
Ok(())
}
@@ -1553,8 +1719,9 @@ pub fn op_fs_futime_sync(
#[smi] atime_nanos: u32,
#[number] mtime_secs: i64,
#[smi] mtime_nanos: u32,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(state, rid)?;
+) -> Result<(), FsOpsError> {
+ let file =
+ FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?;
file.utime_sync(atime_secs, atime_nanos, mtime_secs, mtime_nanos)?;
Ok(())
}
@@ -1567,42 +1734,64 @@ pub async fn op_fs_futime_async(
#[smi] atime_nanos: u32,
#[number] mtime_secs: i64,
#[smi] mtime_nanos: u32,
-) -> Result<(), AnyError> {
- let file = FileResource::get_file(&state.borrow(), rid)?;
+) -> Result<(), FsOpsError> {
+ let file = FileResource::get_file(&state.borrow(), rid)
+ .map_err(FsOpsError::Resource)?;
file
.utime_async(atime_secs, atime_nanos, mtime_secs, mtime_nanos)
.await?;
Ok(())
}
-trait WithContext {
- fn context<E: Into<Box<dyn std::error::Error + Send + Sync>>>(
- self,
- desc: E,
- ) -> AnyError;
+#[derive(Debug)]
+pub struct OperationError {
+ operation: &'static str,
+ kind: OperationErrorKind,
+ pub err: FsError,
}
-impl WithContext for FsError {
- fn context<E: Into<Box<dyn std::error::Error + Send + Sync>>>(
- self,
- desc: E,
- ) -> AnyError {
- match self {
- FsError::Io(io) => {
- AnyError::new(io::Error::new(io.kind(), desc)).context(io)
+impl std::fmt::Display for OperationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ if let FsError::Io(e) = &self.err {
+ std::fmt::Display::fmt(&e, f)?;
+ f.write_str(": ")?;
+ }
+
+ f.write_str(self.operation)?;
+
+ match &self.kind {
+ OperationErrorKind::Bare => Ok(()),
+ OperationErrorKind::WithPath(path) => write!(f, " '{}'", path.display()),
+ OperationErrorKind::WithTwoPaths(from, to) => {
+ write!(f, " '{}' -> '{}'", from.display(), to.display())
}
- _ => self.into(),
}
}
}
+impl std::error::Error for OperationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ if let FsError::Io(err) = &self.err {
+ Some(err)
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum OperationErrorKind {
+ Bare,
+ WithPath(PathBuf),
+ WithTwoPaths(PathBuf, PathBuf),
+}
+
trait MapErrContext {
type R;
- fn context_fn<F, E>(self, f: F) -> Self::R
+ fn context_fn<F>(self, f: F) -> Self::R
where
- F: FnOnce() -> E,
- E: Into<Box<dyn std::error::Error + Send + Sync>>;
+ F: FnOnce(FsError) -> OperationError;
fn context(self, desc: &'static str) -> Self::R;
@@ -1617,25 +1806,29 @@ trait MapErrContext {
}
impl<T> MapErrContext for Result<T, FsError> {
- type R = Result<T, AnyError>;
+ type R = Result<T, FsOpsError>;
- fn context_fn<F, E>(self, f: F) -> Self::R
+ fn context_fn<F>(self, f: F) -> Self::R
where
- F: FnOnce() -> E,
- E: Into<Box<dyn std::error::Error + Send + Sync>>,
+ F: FnOnce(FsError) -> OperationError,
{
- self.map_err(|err| {
- let message = f();
- err.context(message)
- })
+ self.map_err(|err| FsOpsError::OperationError(f(err)))
}
- fn context(self, desc: &'static str) -> Self::R {
- self.context_fn(move || desc)
+ fn context(self, operation: &'static str) -> Self::R {
+ self.context_fn(move |err| OperationError {
+ operation,
+ kind: OperationErrorKind::Bare,
+ err,
+ })
}
fn context_path(self, operation: &'static str, path: &Path) -> Self::R {
- self.context_fn(|| format!("{operation} '{}'", path.display()))
+ self.context_fn(|err| OperationError {
+ operation,
+ kind: OperationErrorKind::WithPath(path.to_path_buf()),
+ err,
+ })
}
fn context_two_path(
@@ -1644,21 +1837,19 @@ impl<T> MapErrContext for Result<T, FsError> {
oldpath: &Path,
newpath: &Path,
) -> Self::R {
- self.context_fn(|| {
- format!(
- "{operation} '{}' -> '{}'",
- oldpath.display(),
- newpath.display()
- )
+ self.context_fn(|err| OperationError {
+ operation,
+ kind: OperationErrorKind::WithTwoPaths(
+ oldpath.to_path_buf(),
+ newpath.to_path_buf(),
+ ),
+ err,
})
}
}
-fn path_into_string(s: std::ffi::OsString) -> Result<String, AnyError> {
- s.into_string().map_err(|s| {
- let message = format!("File name or path {s:?} is not valid UTF-8");
- custom_error("InvalidData", message)
- })
+fn path_into_string(s: std::ffi::OsString) -> Result<String, FsOpsError> {
+ s.into_string().map_err(FsOpsError::InvalidUtf8)
}
macro_rules! create_struct_writer {
diff --git a/runtime/errors.rs b/runtime/errors.rs
index 935f62d26..25fc664a5 100644
--- a/runtime/errors.rs
+++ b/runtime/errors.rs
@@ -23,6 +23,8 @@ use deno_ffi::DlfcnError;
use deno_ffi::IRError;
use deno_ffi::ReprError;
use deno_ffi::StaticError;
+use deno_fs::FsOpsError;
+use deno_io::fs::FsError;
use deno_kv::KvCheckError;
use deno_kv::KvError;
use deno_kv::KvMutationError;
@@ -366,6 +368,34 @@ fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str {
}
}
+fn get_fs_error(error: &FsOpsError) -> &'static str {
+ match error {
+ FsOpsError::Io(e) => get_io_error_class(e),
+ FsOpsError::OperationError(e) => match &e.err {
+ FsError::Io(e) => get_io_error_class(e),
+ FsError::FileBusy => "Busy",
+ FsError::NotSupported => "NotSupported",
+ FsError::NotCapable(_) => "NotCapable",
+ },
+ FsOpsError::Permission(e)
+ | FsOpsError::Resource(e)
+ | FsOpsError::Other(e) => get_error_class_name(e).unwrap_or("Error"),
+ FsOpsError::InvalidUtf8(_) => "InvalidData",
+ FsOpsError::StripPrefix(_) => "Error",
+ FsOpsError::Canceled(e) => {
+ let io_err: io::Error = e.to_owned().into();
+ get_io_error_class(&io_err)
+ }
+ FsOpsError::InvalidSeekMode(_) => "TypeError",
+ FsOpsError::InvalidControlCharacter(_) => "Error",
+ FsOpsError::InvalidCharacter(_) => "Error",
+ #[cfg(windows)]
+ FsOpsError::InvalidTrailingCharacter => "Error",
+ FsOpsError::NotCapableAccess { .. } => "NotCapable",
+ FsOpsError::NotCapable(_) => "NotCapable",
+ }
+}
+
fn get_kv_error(error: &KvError) -> &'static str {
match error {
KvError::DatabaseHandler(e) | KvError::Resource(e) | KvError::Kv(e) => {
@@ -470,6 +500,7 @@ pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
.or_else(|| e.downcast_ref::<BlobError>().map(get_web_blob_error_class))
.or_else(|| e.downcast_ref::<IRError>().map(|_| "TypeError"))
.or_else(|| e.downcast_ref::<ReprError>().map(get_ffi_repr_error_class))
+ .or_else(|| e.downcast_ref::<FsOpsError>().map(get_fs_error))
.or_else(|| {
e.downcast_ref::<DlfcnError>()
.map(get_ffi_dlfcn_error_class)