// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; use deno_core::OpState; use deno_core::ResourceId; use deno_core::op2; use deno_fs::FileSystemRc; use deno_fs::OpenOptions; use deno_io::fs::FileResource; use deno_permissions::OpenAccessKind; use serde::Serialize; use crate::NodePermissions; #[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum FsError { #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), #[class(inherit)] #[error("{0}")] Io( #[from] #[inherit] std::io::Error, ), #[cfg(windows)] #[class(generic)] #[error("Path has no root.")] PathHasNoRoot, #[cfg(not(any(unix, windows)))] #[class(generic)] #[error("Unsupported platform.")] UnsupportedPlatform, #[class(inherit)] #[error(transparent)] Fs( #[from] #[inherit] deno_io::fs::FsError, ), } #[op2(fast, stack_trace)] pub fn op_node_fs_exists_sync
(
state: &mut OpState,
#[string] path: &str,
) -> Result ().check_open(
Cow::Borrowed(Path::new(path)),
OpenAccessKind::ReadNoFollow,
Some("node:fs.existsSync()"),
)?;
let fs = state.borrow:: (
state: Rc ().check_open(
Cow::Owned(PathBuf::from(path)),
OpenAccessKind::ReadNoFollow,
Some("node:fs.exists()"),
)?;
(state.borrow:: (
state: &mut OpState,
#[string] path: &str,
#[string] new_path: &str,
) -> Result<(), FsError>
where
P: NodePermissions + 'static,
{
let path = state.borrow_mut:: ().check_open(
Cow::Borrowed(Path::new(path)),
OpenAccessKind::Read,
Some("node:fs.cpSync"),
)?;
let new_path = state.borrow_mut:: ().check_open(
Cow::Borrowed(Path::new(new_path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.cpSync"),
)?;
let fs = state.borrow:: (
state: Rc ().check_open(
Cow::Owned(PathBuf::from(path)),
OpenAccessKind::Read,
Some("node:fs.cpSync"),
)?;
let new_path = state.borrow_mut:: ().check_open(
Cow::Owned(PathBuf::from(new_path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.cpSync"),
)?;
(state.borrow:: (
state: &mut OpState,
#[string] path: &str,
#[smi] flags: i32,
#[smi] mode: u32,
) -> Result ().check_open(
Cow::Borrowed(path),
open_options_to_access_kind(&options),
Some("node:fs.openSync"),
)?;
let file = fs.open_sync(&path, options)?;
let rid = state
.resource_table
.add(FileResource::new(file, "fsFile".to_string()));
Ok(rid)
}
#[op2(async, stack_trace)]
#[smi]
pub async fn op_node_open (
state: Rc ().check_open(
Cow::Owned(path),
open_options_to_access_kind(&options),
Some("node:fs.open"),
)?,
)
};
let file = fs.open_async(path.as_owned(), options).await?;
let rid = state
.borrow_mut()
.resource_table
.add(FileResource::new(file, "fsFile".to_string()));
Ok(rid)
}
#[derive(Debug, Serialize)]
pub struct StatFs {
#[serde(rename = "type")]
pub typ: u64,
pub bsize: u64,
pub blocks: u64,
pub bfree: u64,
pub bavail: u64,
pub files: u64,
pub ffree: u64,
}
#[op2(stack_trace)]
#[serde]
pub fn op_node_statfs (
state: Rc ().check_open(
Cow::Borrowed(Path::new(path)),
OpenAccessKind::ReadNoFollow,
Some("node:fs.statfs"),
)?;
state
.borrow_mut:: ()
.check_sys("statfs", "node:fs.statfs")?;
path
};
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
let path = path.as_os_str();
let mut cpath = path.as_bytes().to_vec();
cpath.push(0);
if bigint {
#[cfg(not(any(
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd"
)))]
// SAFETY: `cpath` is NUL-terminated and result is pointer to valid statfs memory.
let (code, result) = unsafe {
let mut result: libc::statfs64 = std::mem::zeroed();
(libc::statfs64(cpath.as_ptr() as _, &mut result), result)
};
#[cfg(any(
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd"
))]
// SAFETY: `cpath` is NUL-terminated and result is pointer to valid statfs memory.
let (code, result) = unsafe {
let mut result: libc::statfs = std::mem::zeroed();
(libc::statfs(cpath.as_ptr() as _, &mut result), result)
};
if code == -1 {
return Err(std::io::Error::last_os_error().into());
}
Ok(StatFs {
#[cfg(not(target_os = "openbsd"))]
typ: result.f_type as _,
#[cfg(target_os = "openbsd")]
typ: 0 as _,
bsize: result.f_bsize as _,
blocks: result.f_blocks as _,
bfree: result.f_bfree as _,
bavail: result.f_bavail as _,
files: result.f_files as _,
ffree: result.f_ffree as _,
})
} else {
// SAFETY: `cpath` is NUL-terminated and result is pointer to valid statfs memory.
let (code, result) = unsafe {
let mut result: libc::statfs = std::mem::zeroed();
(libc::statfs(cpath.as_ptr() as _, &mut result), result)
};
if code == -1 {
return Err(std::io::Error::last_os_error().into());
}
Ok(StatFs {
#[cfg(not(target_os = "openbsd"))]
typ: result.f_type as _,
#[cfg(target_os = "openbsd")]
typ: 0 as _,
bsize: result.f_bsize as _,
blocks: result.f_blocks as _,
bfree: result.f_bfree as _,
bavail: result.f_bavail as _,
files: result.f_files as _,
ffree: result.f_ffree as _,
})
}
}
#[cfg(windows)]
{
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use windows_sys::Win32::Storage::FileSystem::GetDiskFreeSpaceW;
let _ = bigint;
// Using a vfs here doesn't make sense, it won't align with the windows API
// call below.
#[allow(clippy::disallowed_methods)]
let path = path.canonicalize()?;
let root = path.ancestors().last().ok_or(FsError::PathHasNoRoot)?;
let mut root = OsStr::new(root).encode_wide().collect:: (
state: &mut OpState,
#[string] path: &str,
#[number] atime_secs: i64,
#[smi] atime_nanos: u32,
#[number] mtime_secs: i64,
#[smi] mtime_nanos: u32,
) -> Result<(), FsError>
where
P: NodePermissions + 'static,
{
let path = state.borrow_mut:: ().check_open(
Cow::Borrowed(Path::new(path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.lutimes"),
)?;
let fs = state.borrow:: (
state: Rc ().check_open(
Cow::Owned(PathBuf::from(path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.lutimesSync"),
)?;
(state.borrow:: (
state: &mut OpState,
#[string] path: &str,
uid: Option ().check_open(
Cow::Borrowed(Path::new(path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.lchownSync"),
)?;
let fs = state.borrow:: (
state: Rc ().check_open(
Cow::Owned(PathBuf::from(path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.lchown"),
)?;
(state.borrow:: (
state: &mut OpState,
#[string] path: &str,
#[smi] mode: u32,
) -> Result<(), FsError>
where
P: NodePermissions + 'static,
{
let path = state.borrow_mut:: ().check_open(
Cow::Borrowed(Path::new(path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.lchmodSync"),
)?;
let fs = state.borrow:: (
state: Rc ().check_open(
Cow::Owned(PathBuf::from(path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.lchmod"),
)?;
(state.borrow:: (
state: &mut OpState,
#[string] path: &str,
) -> Result ().check_open(
Cow::Borrowed(Path::new(&path)),
OpenAccessKind::WriteNoFollow,
Some("node:fs.mkdtempSync()"),
)?;
let fs = state.borrow:: (
state: Rc ().check_open(
Cow::Owned(PathBuf::from(path.clone())),
OpenAccessKind::WriteNoFollow,
Some("node:fs.mkdtemp()"),
)?;
(state.borrow::