diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2024-03-13 10:57:59 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-13 10:57:59 +0000 |
commit | f377fce640002c687bb2f36918f857fcc2f7bc7b (patch) | |
tree | 2192831a7a9328e8fb1030fc0e127ac841e73024 /ext/node/ops/fs.rs | |
parent | 5cfa03ceca396b1c21a826cb44a984329cf35078 (diff) |
feat(node): implement fs.statfs() (#22862)
Diffstat (limited to 'ext/node/ops/fs.rs')
-rw-r--r-- | ext/node/ops/fs.rs | 137 |
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.")) + } +} |