summaryrefslogtreecommitdiff
path: root/ext/node/ops/fs.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2024-03-13 10:57:59 +0000
committerGitHub <noreply@github.com>2024-03-13 10:57:59 +0000
commitf377fce640002c687bb2f36918f857fcc2f7bc7b (patch)
tree2192831a7a9328e8fb1030fc0e127ac841e73024 /ext/node/ops/fs.rs
parent5cfa03ceca396b1c21a826cb44a984329cf35078 (diff)
feat(node): implement fs.statfs() (#22862)
Diffstat (limited to 'ext/node/ops/fs.rs')
-rw-r--r--ext/node/ops/fs.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/ext/node/ops/fs.rs b/ext/node/ops/fs.rs
index c5ae2371e..28d95eabe 100644
--- a/ext/node/ops/fs.rs
+++ b/ext/node/ops/fs.rs
@@ -9,6 +9,7 @@ use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::OpState;
use deno_fs::FileSystemRc;
+use serde::Serialize;
use crate::NodePermissions;
@@ -78,3 +79,139 @@ where
fs.cp_async(path, new_path).await?;
Ok(())
}
+
+#[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]
+#[serde]
+pub fn op_node_statfs<P>(
+ state: Rc<RefCell<OpState>>,
+ #[string] path: String,
+ bigint: bool,
+) -> Result<StatFs, AnyError>
+where
+ P: NodePermissions + 'static,
+{
+ {
+ let mut state = state.borrow_mut();
+ state
+ .borrow_mut::<P>()
+ .check_read_with_api_name(Path::new(&path), Some("node:fs.statfs"))?;
+ state
+ .borrow_mut::<P>()
+ .check_sys("statfs", "node:fs.statfs")?;
+ }
+ #[cfg(unix)]
+ {
+ use std::ffi::OsStr;
+ use std::os::unix::ffi::OsStrExt;
+
+ let path = OsStr::new(&path);
+ let mut cpath = path.as_bytes().to_vec();
+ cpath.push(0);
+ if bigint {
+ #[cfg(not(target_os = "macos"))]
+ // 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(target_os = "macos")]
+ // 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 {
+ typ: result.f_type 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 {
+ typ: result.f_type 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 deno_core::anyhow::anyhow;
+ 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::new(&path).canonicalize()?;
+ let root = path
+ .ancestors()
+ .last()
+ .ok_or(anyhow!("Path has no root."))?;
+ let root = OsStr::new(root).encode_wide().collect::<Vec<_>>();
+ let mut sectors_per_cluster = 0;
+ let mut bytes_per_sector = 0;
+ let mut available_clusters = 0;
+ let mut total_clusters = 0;
+ // SAFETY: Normal GetDiskFreeSpaceW usage.
+ let code = unsafe {
+ GetDiskFreeSpaceW(
+ root.as_ptr(),
+ &mut sectors_per_cluster,
+ &mut bytes_per_sector,
+ &mut available_clusters,
+ &mut total_clusters,
+ )
+ };
+ if code == 0 {
+ return Err(std::io::Error::last_os_error().into());
+ }
+ Ok(StatFs {
+ typ: 0,
+ bsize: (bytes_per_sector * sectors_per_cluster) as _,
+ blocks: total_clusters as _,
+ bfree: available_clusters as _,
+ bavail: available_clusters as _,
+ files: 0,
+ ffree: 0,
+ })
+ }
+ #[cfg(not(any(unix, windows)))]
+ {
+ let _ = path;
+ let _ = bigint;
+ Err(anyhow!("Unsupported platform."))
+ }
+}