indexbus_platform_ops/linux/
fs.rs1use std::path::Path;
6
7use crate::errors::{Error, Result};
8
9pub fn is_hugetlbfs(path: &Path) -> Result<bool> {
13 let mut s: libc::statfs = unsafe { std::mem::zeroed() };
14 let c_path = std::ffi::CString::new(path.to_string_lossy().as_bytes())
15 .map_err(|e| Error::msg(format!("invalid path for CString: {e}")))?;
16
17 let rc = unsafe { libc::statfs(c_path.as_ptr(), &mut s as *mut libc::statfs) };
18 if rc != 0 {
19 return Err(Error::msg(format!(
20 "statfs({}) failed: {}",
21 path.display(),
22 std::io::Error::last_os_error()
23 )));
24 }
25
26 Ok((s.f_type as u64) == 0x9584_58f6)
27}
28
29pub fn probe_dir_writable(dir: &Path) -> Result<()> {
33 let path = dir.join(format!(".indexbus_write_test_{}", std::process::id()));
34
35 let res = (|| -> Result<()> {
36 let mut f = std::fs::OpenOptions::new()
37 .create(true)
38 .write(true)
39 .truncate(true)
40 .open(&path)
41 .map_err(|e| Error::msg(format!("dir not writable (open {}): {e}", path.display())))?;
42
43 if is_hugetlbfs(dir).unwrap_or(false) {
44 const TWO_MIB: u64 = 2 * 1024 * 1024;
45 f.set_len(TWO_MIB).map_err(|e| {
46 Error::msg(format!(
47 "dir not writable (set_len {} to {} bytes): {e}",
48 path.display(),
49 TWO_MIB
50 ))
51 })?;
52 } else {
53 use std::io::Write;
54 f.write_all(b"ok\n").map_err(|e| {
55 Error::msg(format!("dir not writable (write {}): {e}", path.display()))
56 })?;
57 }
58
59 Ok(())
60 })();
61
62 let _ = std::fs::remove_file(&path);
63 res
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn is_hugetlbfs_errors_on_missing_path() {
72 let missing = std::path::PathBuf::from(format!(
73 "/tmp/indexbus_missing_{}_{}",
74 std::process::id(),
75 crate::time::monotonic_now_ns()
76 ));
77 let err = is_hugetlbfs(&missing).unwrap_err();
78 assert!(err.to_string().contains("statfs("));
79 }
80
81 #[test]
82 fn probe_dir_writable_succeeds_for_temp_dir() {
83 let dir = std::env::temp_dir();
84 probe_dir_writable(&dir).unwrap();
85 }
86
87 #[test]
88 fn probe_dir_writable_errors_when_not_a_dir() {
89 let base = std::env::temp_dir().join(format!(
90 "indexbus_ops_probe_{}_{}",
91 std::process::id(),
92 crate::time::monotonic_now_ns()
93 ));
94 std::fs::write(&base, "not a dir").unwrap();
95
96 let err = probe_dir_writable(&base).unwrap_err();
97 assert!(err.to_string().contains("dir not writable"));
98
99 let _ = std::fs::remove_file(&base);
100 }
101}