I want to use libc::statfs64
to get the f_type
value of a file path.
I wrote the following code and it appears to be working.
However, I'm not familiar with calling C functions, so some questions remain, as you can see from the comments in the code.
Can anyone give me some advice?
#[cfg(not(unix))]
compile_error!("This program is for Unix-like systems.");
use std::{ffi::CString, io, mem::MaybeUninit, os::unix::prelude::OsStrExt, path::Path};
use libc::{c_char, statfs64};
fn main() -> io::Result<()> {
// path for debugging
let path: &Path = Path::new("/tmp");
let stat: statfs64 = unsafe {
// Q1. Is MaybeUninit suitable for allocating memory for structs passed to libc functions?
let mut uninit = MaybeUninit::<statfs64>::uninit();
// Q2. I want to get `*const c_char` from `&Path` to pass it to `libc::statfs64`.
// Is this code correct (on Unix)?
let path_str = CString::new(path.as_os_str().as_bytes())?;
let path_ptr: *const c_char = path_str.as_ptr();
let status = libc::statfs64(path_ptr, uninit.as_mut_ptr());
if status == 0 {
// Q3. Is `assume_init()` the proper way to get a value from MaybeUninit,
// which holds a struct initialized by a C function?
uninit.assume_init()
} else {
// Q4. Do I need to drop or free the `uninit` variable before returning `Err`?
// If the answer is yes, how should I do it?
uninit.assume_init_drop();
return Err(io::Error::last_os_error());
}
};
println!("path = {}", path.display());
println!("f_type = {}", stat.f_type);
// Q5. Do I need to drop or free the `stat` variable here?
//libc::free(...);
Ok(())
}