[Solved] Getting available disk space with libc


#1

Hello, I’m trying to port this C code to Rust:

inline float get_available_disk_space()
	{
		struct statvfs fs;
		statvfs("data", &fs);

		return ((float) fs.f_bsize)*fs.f_bavail;
}

And I see that in libc we have both the structure and the function. The issue is I cannot instantiate an empty structure, since it has private fields:

libc::statvfs {
        f_bsize: 0,
        f_frsize: 0,
        f_blocks: 0,
        f_bfree: 0,
        f_bavail: 0,
        f_files: 0,
        f_ffree: 0,
        f_favail: 0,
        f_fsid: 0,
        f_flag: 0,
        f_namemax: 0,
        __f_spare: [0; 6],
    };

This gives this error:

error[E0063]: missing field `__f_spare` in initializer of `libc::statvfs`
  --> src/logic/init.rs:24:21
   |
24 |     let mut stats = libc::statvfs {
   |                     ^^^^^^^^^^^^^ missing `__f_spare`

error: aborting due to previous error

And if I add it, it won’t complain because that field is private. How can I do it?


#2

Use mem::uninitialized or mem::zeroed.


#3

Yes, std::mem::uninitialized seems to be what you need:

unsafe {
let mut buf: libc::statvfs = std::mem::uninitialized();
let path = CString::new("/").unwrap();
libc::statvfs(path.as_ptr(), &mut buf as *mut _);
println!("{}", buf.f_frsize);
}


#4

Cool! thanks :slight_smile:

Another issue I have is that the path I have (for the statvfs) is an actual &Path, And I know I can get an OsStr from it, but how can I get a CString / CStr from it safely?


#5

I will answer to myself here. Since I’m using Unix, it’s as simple as:

use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;

let dir = CString::new(path.as_os_str().as_bytes())?;