1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

stat: use struct libc::statfs now

This commit is contained in:
Knight 2016-06-05 11:30:46 +08:00
parent 48968f3d8a
commit 580667295c

View file

@ -12,7 +12,7 @@ extern crate time;
use self::time::Timespec; use self::time::Timespec;
pub use self::libc::{S_IFMT, S_IFDIR, S_IFCHR, S_IFBLK, S_IFREG, S_IFIFO, S_IFLNK, S_IFSOCK, pub use self::libc::{S_IFMT, S_IFDIR, S_IFCHR, S_IFBLK, S_IFREG, S_IFIFO, S_IFLNK, S_IFSOCK,
S_ISUID, S_ISGID, S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_ISUID, S_ISGID, S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP,
S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH}; S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, mode_t, c_int, strerror};
#[macro_export] #[macro_export]
macro_rules! has { macro_rules! has {
@ -26,7 +26,7 @@ pub fn pretty_time(sec: i64, nsec: i64) -> String {
time::strftime("%Y-%m-%d %H:%M:%S.%f %z", &tm).unwrap() time::strftime("%Y-%m-%d %H:%M:%S.%f %z", &tm).unwrap()
} }
pub fn pretty_filetype<'a>(mode: u32, size: u64) -> &'a str { pub fn pretty_filetype<'a>(mode: mode_t, size: u64) -> &'a str {
match mode & S_IFMT { match mode & S_IFMT {
S_IFREG => { S_IFREG => {
if size != 0 { if size != 0 {
@ -47,7 +47,7 @@ pub fn pretty_filetype<'a>(mode: u32, size: u64) -> &'a str {
} }
} }
pub fn pretty_access(mode: u32) -> String { pub fn pretty_access(mode: mode_t) -> String {
let mut result = String::with_capacity(10); let mut result = String::with_capacity(10);
result.push(match mode & S_IFMT { result.push(match mode & S_IFMT {
S_IFDIR => 'd', S_IFDIR => 'd',
@ -136,57 +136,116 @@ use std::path::Path;
use std::borrow::Cow; use std::borrow::Cow;
use std::ffi::CString; use std::ffi::CString;
use std::convert::{AsRef, From}; use std::convert::{AsRef, From};
use std::error::Error;
use std::io::Error as IOError;
pub struct Statfs { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
pub f_type: i64, use self::libc::statfs as Sstatfs;
pub f_bsize: i64, // #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
pub f_blocks: u64, // use self::libc::statvfs as Sstatfs;
pub f_bfree: u64,
pub f_bavail: u64, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
pub f_files: u64, use self::libc::statfs as statfs_fn;
pub f_ffree: u64, // #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
pub f_namelen: i64, // use self::libc::statvfs as statfs_fn;
pub f_frsize: i64,
pub f_fsid: u64, pub trait FsMeta {
fn fs_type(&self) -> i64;
fn iosize(&self) -> i64;
fn blksize(&self) -> i64;
fn total_blocks(&self) -> u64;
fn free_blocks(&self) -> u64;
fn avail_blocks(&self) -> u64;
fn total_fnodes(&self) -> u64;
fn free_fnodes(&self) -> u64;
fn fsid(&self) -> u64;
fn namelen(&self) -> i64;
} }
pub fn statfs<P: AsRef<Path>>(path: P) -> Result<Statfs, String> impl FsMeta for Sstatfs {
where Vec<u8>: From<P> fn blksize(&self) -> i64 {
{ self.f_bsize as i64
use std::error::Error; }
match CString::new(path) { fn total_blocks(&self) -> u64 {
Ok(p) => { self.f_blocks as u64
let mut buffer = unsafe { mem::zeroed() }; }
unsafe { fn free_blocks(&self) -> u64 {
match self::libc::statfs(p.as_ptr(), &mut buffer) { self.f_bfree as u64
0 => { }
let fsid: u64; fn avail_blocks(&self) -> u64 {
if cfg!(unix) { self.f_bavail as u64
}
fn total_fnodes(&self) -> u64 {
self.f_files as u64
}
fn free_fnodes(&self) -> u64 {
self.f_ffree as u64
}
fn fs_type(&self) -> i64 {
self.f_type as i64
}
#[cfg(target_os = "linux")]
fn iosize(&self) -> i64 {
self.f_frsize as i64
}
#[cfg(target_os = "macos")]
fn iosize(&self) -> i64 {
self.f_iosize as i64
}
// FIXME:
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
fn iosize(&self) -> i64 {
0
}
// Linux, SunOS, HP-UX, 4.4BSD, FreeBSD have a system call statfs() that returns // Linux, SunOS, HP-UX, 4.4BSD, FreeBSD have a system call statfs() that returns
// a struct statfs, containing a fsid_t f_fsid, where fsid_t is defined // a struct statfs, containing a fsid_t f_fsid, where fsid_t is defined
// as struct { int val[2]; } // as struct { int val[2]; }
let f_fsid: &[u32; 2] = transmute(&buffer.f_fsid); //
fsid = (f_fsid[0] as u64) << 32_u64 | f_fsid[1] as u64;
} else {
// Solaris, Irix and POSIX have a system call statvfs(2) that returns a // Solaris, Irix and POSIX have a system call statvfs(2) that returns a
// struct statvfs, containing an unsigned long f_fsid // struct statvfs, containing an unsigned long f_fsid
fsid = 0; #[cfg(any(target_os = "macos", target_os = "linux"))]
fn fsid(&self) -> u64 {
let f_fsid: &[u32; 2] = unsafe { transmute(&self.f_fsid) };
(f_fsid[0] as u64) << 32 | f_fsid[1] as u64
} }
Ok(Statfs { // FIXME:
f_type: buffer.f_type as i64, #[cfg(not(any(target_os = "macos", target_os = "linux")))]
f_bsize: buffer.f_bsize as i64, fn fsid(&self) -> u64 {
f_blocks: buffer.f_blocks as u64, 0
f_bfree: buffer.f_bfree as u64, }
f_bavail: buffer.f_bavail as u64,
f_files: buffer.f_files as u64, #[cfg(target_os = "linux")]
f_ffree: buffer.f_ffree as u64, fn namelen(&self) -> i64 {
f_fsid: fsid, self.f_namelen as i64
f_namelen: buffer.f_namelen as i64, }
f_frsize: buffer.f_frsize as i64, #[cfg(target_os = "macos")]
}) fn namelen(&self) -> i64 {
1024
}
// FIXME:
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
fn namelen(&self) -> u64 {
0
}
}
pub fn statfs<P: AsRef<Path>>(path: P) -> Result<Sstatfs, String>
where Vec<u8>: From<P>
{
match CString::new(path) {
Ok(p) => {
let mut buffer: Sstatfs = unsafe { mem::zeroed() };
unsafe {
match statfs_fn(p.as_ptr(), &mut buffer) {
0 => Ok(buffer),
_ => {
let errno = IOError::last_os_error().raw_os_error().unwrap_or(0);
Err(CString::from_raw(strerror(errno))
.into_string()
.unwrap_or("Unknown Error".to_owned()))
} }
// TODO: Return explicit error message
_ => Err("Unknown error".to_owned()),
} }
} }
} }