mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
stat: add fsext.rs
Mainly includes the pretty-* functions, turning the file types, file system types and time into human-readable form.
This commit is contained in:
parent
3202c18c54
commit
0926cd43ac
1 changed files with 359 additions and 0 deletions
359
src/stat/fsext.rs
Normal file
359
src/stat/fsext.rs
Normal file
|
@ -0,0 +1,359 @@
|
||||||
|
extern crate libc;
|
||||||
|
extern crate time;
|
||||||
|
|
||||||
|
use self::time::Timespec;
|
||||||
|
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_IXGRP, S_IROTH, S_IWOTH, S_IXOTH};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! has {
|
||||||
|
($mode:expr, $perm:expr) => (
|
||||||
|
($mode & $perm != 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_time(sec: i64, nsec: i64) -> String {
|
||||||
|
let tm = time::at(Timespec::new(sec, nsec as i32));
|
||||||
|
time::strftime("%Y-%m-%d %H:%M:%S.%f %z", &tm).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_filetype<'a>(mode: u32, size: u64) -> &'a str {
|
||||||
|
match mode & S_IFMT {
|
||||||
|
S_IFREG => {
|
||||||
|
if size != 0 {
|
||||||
|
"regular file"
|
||||||
|
} else {
|
||||||
|
"regular empty file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S_IFDIR => "directory",
|
||||||
|
S_IFLNK => "symbolic link",
|
||||||
|
S_IFCHR => "character special file",
|
||||||
|
S_IFBLK => "block special file",
|
||||||
|
S_IFIFO => "fifo",
|
||||||
|
S_IFSOCK => "socket",
|
||||||
|
// TODO: Other file types
|
||||||
|
// See coreutils/gnulib/lib/file-type.c
|
||||||
|
_ => "weird file",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_access(mode: u32) -> String {
|
||||||
|
let mut result = String::with_capacity(10);
|
||||||
|
result.push(match mode & S_IFMT {
|
||||||
|
S_IFDIR => 'd',
|
||||||
|
S_IFCHR => 'c',
|
||||||
|
S_IFBLK => 'b',
|
||||||
|
S_IFREG => '-',
|
||||||
|
S_IFIFO => 'p',
|
||||||
|
S_IFLNK => 'l',
|
||||||
|
S_IFSOCK => 's',
|
||||||
|
// TODO: Other file types
|
||||||
|
// See coreutils/gnulib/lib/filemode.c
|
||||||
|
_ => '?',
|
||||||
|
});
|
||||||
|
|
||||||
|
result.push(if has!(mode, S_IRUSR) {
|
||||||
|
'r'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
result.push(if has!(mode, S_IWUSR) {
|
||||||
|
'w'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
result.push(if has!(mode, S_ISUID as u32) {
|
||||||
|
if has!(mode, S_IXUSR) {
|
||||||
|
's'
|
||||||
|
} else {
|
||||||
|
'S'
|
||||||
|
}
|
||||||
|
} else if has!(mode, S_IXUSR) {
|
||||||
|
'x'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
|
||||||
|
result.push(if has!(mode, S_IRGRP) {
|
||||||
|
'r'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
result.push(if has!(mode, S_IWGRP) {
|
||||||
|
'w'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
result.push(if has!(mode, S_ISGID as u32) {
|
||||||
|
if has!(mode, S_IXGRP) {
|
||||||
|
's'
|
||||||
|
} else {
|
||||||
|
'S'
|
||||||
|
}
|
||||||
|
} else if has!(mode, S_IXGRP) {
|
||||||
|
'x'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
|
||||||
|
result.push(if has!(mode, S_IROTH) {
|
||||||
|
'r'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
result.push(if has!(mode, S_IWOTH) {
|
||||||
|
'w'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
result.push(if has!(mode, S_ISVTX as u32) {
|
||||||
|
if has!(mode, S_IXOTH) {
|
||||||
|
't'
|
||||||
|
} else {
|
||||||
|
'T'
|
||||||
|
}
|
||||||
|
} else if has!(mode, S_IXOTH) {
|
||||||
|
'x'
|
||||||
|
} else {
|
||||||
|
'-'
|
||||||
|
});
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::mem::{self, transmute};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::convert::{AsRef, From};
|
||||||
|
|
||||||
|
pub struct Statfs {
|
||||||
|
pub f_type: i64,
|
||||||
|
pub f_bsize: i64,
|
||||||
|
pub f_blocks: u64,
|
||||||
|
pub f_bfree: u64,
|
||||||
|
pub f_bavail: u64,
|
||||||
|
pub f_files: u64,
|
||||||
|
pub f_ffree: u64,
|
||||||
|
pub f_namelen: i64,
|
||||||
|
pub f_frsize: i64,
|
||||||
|
pub f_fsid: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn statfs<P: AsRef<Path>>(path: P) -> Result<Statfs, String>
|
||||||
|
where Vec<u8>: From<P>
|
||||||
|
{
|
||||||
|
use std::error::Error;
|
||||||
|
match CString::new(path) {
|
||||||
|
Ok(p) => {
|
||||||
|
let mut buffer = unsafe { mem::zeroed() };
|
||||||
|
unsafe {
|
||||||
|
match self::libc::statfs(p.as_ptr(), &mut buffer) {
|
||||||
|
0 => {
|
||||||
|
let fsid: u64;
|
||||||
|
if cfg!(unix) {
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// struct statvfs, containing an unsigned long f_fsid
|
||||||
|
fsid = 0;
|
||||||
|
}
|
||||||
|
Ok(Statfs {
|
||||||
|
f_type: buffer.f_type as i64,
|
||||||
|
f_bsize: buffer.f_bsize as i64,
|
||||||
|
f_blocks: buffer.f_blocks as u64,
|
||||||
|
f_bfree: buffer.f_bfree as u64,
|
||||||
|
f_bavail: buffer.f_bavail as u64,
|
||||||
|
f_files: buffer.f_files as u64,
|
||||||
|
f_ffree: buffer.f_ffree as u64,
|
||||||
|
f_fsid: fsid,
|
||||||
|
f_namelen: buffer.f_namelen as i64,
|
||||||
|
f_frsize: buffer.f_frsize as i64,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// TODO: Return explicit error message
|
||||||
|
_ => Err("Unknown error".to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.description().to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_fstype<'a>(fstype: i64) -> Cow<'a, str> {
|
||||||
|
match fstype {
|
||||||
|
0x61636673 => "acfs".into(),
|
||||||
|
0xADF5 => "adfs".into(),
|
||||||
|
0xADFF => "affs".into(),
|
||||||
|
0x5346414F => "afs".into(),
|
||||||
|
0x09041934 => "anon-inode FS".into(),
|
||||||
|
0x61756673 => "aufs".into(),
|
||||||
|
0x0187 => "autofs".into(),
|
||||||
|
0x42465331 => "befs".into(),
|
||||||
|
0x62646576 => "bdevfs".into(),
|
||||||
|
0x1BADFACE => "bfs".into(),
|
||||||
|
0xCAFE4A11 => "bpf_fs".into(),
|
||||||
|
0x42494E4D => "binfmt_misc".into(),
|
||||||
|
0x9123683E => "btrfs".into(),
|
||||||
|
0x73727279 => "btrfs_test".into(),
|
||||||
|
0x00C36400 => "ceph".into(),
|
||||||
|
0x0027E0EB => "cgroupfs".into(),
|
||||||
|
0xFF534D42 => "cifs".into(),
|
||||||
|
0x73757245 => "coda".into(),
|
||||||
|
0x012FF7B7 => "coh".into(),
|
||||||
|
0x62656570 => "configfs".into(),
|
||||||
|
0x28CD3D45 => "cramfs".into(),
|
||||||
|
0x453DCD28 => "cramfs-wend".into(),
|
||||||
|
0x64626720 => "debugfs".into(),
|
||||||
|
0x1373 => "devfs".into(),
|
||||||
|
0x1CD1 => "devpts".into(),
|
||||||
|
0xF15F => "ecryptfs".into(),
|
||||||
|
0xDE5E81E4 => "efivarfs".into(),
|
||||||
|
0x00414A53 => "efs".into(),
|
||||||
|
0x5DF5 => "exofs".into(),
|
||||||
|
0x137D => "ext".into(),
|
||||||
|
0xEF53 => "ext2/ext3".into(),
|
||||||
|
0xEF51 => "ext2".into(),
|
||||||
|
0xF2F52010 => "f2fs".into(),
|
||||||
|
0x4006 => "fat".into(),
|
||||||
|
0x19830326 => "fhgfs".into(),
|
||||||
|
0x65735546 => "fuseblk".into(),
|
||||||
|
0x65735543 => "fusectl".into(),
|
||||||
|
0x0BAD1DEA => "futexfs".into(),
|
||||||
|
0x01161970 => "gfs/gfs2".into(),
|
||||||
|
0x47504653 => "gpfs".into(),
|
||||||
|
0x4244 => "hfs".into(),
|
||||||
|
0x482B => "hfs+".into(),
|
||||||
|
0x4858 => "hfsx".into(),
|
||||||
|
0x00C0FFEE => "hostfs".into(),
|
||||||
|
0xF995E849 => "hpfs".into(),
|
||||||
|
0x958458F6 => "hugetlbfs".into(),
|
||||||
|
0x11307854 => "inodefs".into(),
|
||||||
|
0x013111A8 => "ibrix".into(),
|
||||||
|
0x2BAD1DEA => "inotifyfs".into(),
|
||||||
|
0x9660 => "isofs".into(),
|
||||||
|
0x4004 => "isofs".into(),
|
||||||
|
0x4000 => "isofs".into(),
|
||||||
|
0x07C0 => "jffs".into(),
|
||||||
|
0x72B6 => "jffs2".into(),
|
||||||
|
0x3153464A => "jfs".into(),
|
||||||
|
0x6B414653 => "k-afs".into(),
|
||||||
|
0xC97E8168 => "logfs".into(),
|
||||||
|
0x0BD00BD0 => "lustre".into(),
|
||||||
|
0x5346314D => "m1fs".into(),
|
||||||
|
0x137F => "minix".into(),
|
||||||
|
0x138F => "minix (30 char.)".into(),
|
||||||
|
0x2468 => "minix v2".into(),
|
||||||
|
0x2478 => "minix v2 (30 char.)".into(),
|
||||||
|
0x4D5A => "minix3".into(),
|
||||||
|
0x19800202 => "mqueue".into(),
|
||||||
|
0x4D44 => "msdos".into(),
|
||||||
|
0x564C => "novell".into(),
|
||||||
|
0x6969 => "nfs".into(),
|
||||||
|
0x6E667364 => "nfsd".into(),
|
||||||
|
0x3434 => "nilfs".into(),
|
||||||
|
0x6E736673 => "nsfs".into(),
|
||||||
|
0x5346544E => "ntfs".into(),
|
||||||
|
0x9FA1 => "openprom".into(),
|
||||||
|
0x7461636F => "ocfs2".into(),
|
||||||
|
0x794C7630 => "overlayfs".into(),
|
||||||
|
0xAAD7AAEA => "panfs".into(),
|
||||||
|
0x50495045 => "pipefs".into(),
|
||||||
|
0x7C7C6673 => "prl_fs".into(),
|
||||||
|
0x9FA0 => "proc".into(),
|
||||||
|
0x6165676C => "pstorefs".into(),
|
||||||
|
0x002F => "qnx4".into(),
|
||||||
|
0x68191122 => "qnx6".into(),
|
||||||
|
0x858458F6 => "ramfs".into(),
|
||||||
|
0x52654973 => "reiserfs".into(),
|
||||||
|
0x7275 => "romfs".into(),
|
||||||
|
0x67596969 => "rpc_pipefs".into(),
|
||||||
|
0x73636673 => "securityfs".into(),
|
||||||
|
0xF97CFF8C => "selinux".into(),
|
||||||
|
0x43415D53 => "smackfs".into(),
|
||||||
|
0x517B => "smb".into(),
|
||||||
|
0xFE534D42 => "smb2".into(),
|
||||||
|
0xBEEFDEAD => "snfs".into(),
|
||||||
|
0x534F434B => "sockfs".into(),
|
||||||
|
0x73717368 => "squashfs".into(),
|
||||||
|
0x62656572 => "sysfs".into(),
|
||||||
|
0x012FF7B6 => "sysv2".into(),
|
||||||
|
0x012FF7B5 => "sysv4".into(),
|
||||||
|
0x01021994 => "tmpfs".into(),
|
||||||
|
0x74726163 => "tracefs".into(),
|
||||||
|
0x24051905 => "ubifs".into(),
|
||||||
|
0x15013346 => "udf".into(),
|
||||||
|
0x00011954 => "ufs".into(),
|
||||||
|
0x54190100 => "ufs".into(),
|
||||||
|
0x9FA2 => "usbdevfs".into(),
|
||||||
|
0x01021997 => "v9fs".into(),
|
||||||
|
0xBACBACBC => "vmhgfs".into(),
|
||||||
|
0xA501FCF5 => "vxfs".into(),
|
||||||
|
0x565A4653 => "vzfs".into(),
|
||||||
|
0x53464846 => "wslfs".into(),
|
||||||
|
0xABBA1974 => "xenfs".into(),
|
||||||
|
0x012FF7B4 => "xenix".into(),
|
||||||
|
0x58465342 => "xfs".into(),
|
||||||
|
0x012FD16D => "xia".into(),
|
||||||
|
0x2FC12FC1 => "zfs".into(),
|
||||||
|
other => format!("UNKNOWN ({:#x})", other).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_access() {
|
||||||
|
assert_eq!("drwxr-xr-x", pretty_access(S_IFDIR | 0o755));
|
||||||
|
assert_eq!("-rw-r--r--", pretty_access(S_IFREG | 0o644));
|
||||||
|
assert_eq!("srw-r-----", pretty_access(S_IFSOCK | 0o640));
|
||||||
|
assert_eq!("lrw-r-xr-x", pretty_access(S_IFLNK | 0o655));
|
||||||
|
assert_eq!("?rw-r-xr-x", pretty_access(0o655));
|
||||||
|
|
||||||
|
assert_eq!("brwSr-xr-x",
|
||||||
|
pretty_access(S_IFBLK | S_ISUID as u32 | 0o655));
|
||||||
|
assert_eq!("brwsr-xr-x",
|
||||||
|
pretty_access(S_IFBLK | S_ISUID as u32 | 0o755));
|
||||||
|
|
||||||
|
assert_eq!("prw---sr--",
|
||||||
|
pretty_access(S_IFIFO | S_ISGID as u32 | 0o614));
|
||||||
|
assert_eq!("prw---Sr--",
|
||||||
|
pretty_access(S_IFIFO | S_ISGID as u32 | 0o604));
|
||||||
|
|
||||||
|
assert_eq!("c---r-xr-t",
|
||||||
|
pretty_access(S_IFCHR | S_ISVTX as u32 | 0o055));
|
||||||
|
assert_eq!("c---r-xr-T",
|
||||||
|
pretty_access(S_IFCHR | S_ISVTX as u32 | 0o054));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_type() {
|
||||||
|
assert_eq!("block special file", pretty_filetype(S_IFBLK, 0));
|
||||||
|
assert_eq!("character special file", pretty_filetype(S_IFCHR, 0));
|
||||||
|
assert_eq!("regular file", pretty_filetype(S_IFREG, 1));
|
||||||
|
assert_eq!("regular empty file", pretty_filetype(S_IFREG, 0));
|
||||||
|
assert_eq!("weird file", pretty_filetype(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fs_type() {
|
||||||
|
assert_eq!("ext2/ext3", pretty_fstype(0xEF53));
|
||||||
|
assert_eq!("tmpfs", pretty_fstype(0x01021994));
|
||||||
|
assert_eq!("nfs", pretty_fstype(0x6969));
|
||||||
|
assert_eq!("btrfs", pretty_fstype(0x9123683e));
|
||||||
|
assert_eq!("xfs", pretty_fstype(0x58465342));
|
||||||
|
assert_eq!("zfs", pretty_fstype(0x2FC12FC1));
|
||||||
|
assert_eq!("ntfs", pretty_fstype(0x5346544e));
|
||||||
|
assert_eq!("fat", pretty_fstype(0x4006));
|
||||||
|
assert_eq!("UNKNOWN (0x1234)", pretty_fstype(0x1234));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue