use crate::{escape::*, suretree::AttMap};
use log::error;
use std::{
fs::{self, Metadata},
os::unix::prelude::*,
path::Path,
};
pub(crate) fn encode_atts(name: &Path, meta: &Metadata) -> AttMap {
let mode = meta.mode() as libc::mode_t & libc::S_IFMT;
let mut base = AttMap::new();
base.insert("uid".to_string(), meta.uid().to_string());
base.insert("gid".to_string(), meta.gid().to_string());
base.insert(
"perm".to_string(),
(meta.mode() as libc::mode_t & !libc::S_IFMT).to_string(),
);
match mode as libc::mode_t {
libc::S_IFDIR => {
base.insert("kind".to_string(), "dir".to_string());
}
libc::S_IFREG => {
base.insert("kind".to_string(), "file".to_string());
base.insert("ino".to_string(), meta.ino().to_string());
base.insert("size".to_string(), meta.size().to_string());
time_info(&mut base, meta);
}
libc::S_IFLNK => {
base.insert("kind".to_string(), "lnk".to_string());
let link = match fs::read_link(name) {
Ok(l) => l,
Err(err) => {
error!("Unable to read link: {:?} ({})", name, err);
From::from("???")
}
};
base.insert("targ".to_string(), link.as_os_str().as_bytes().escaped());
}
libc::S_IFIFO => {
base.insert("kind".to_string(), "fifo".to_string());
}
libc::S_IFSOCK => {
base.insert("kind".to_string(), "sock".to_string());
}
libc::S_IFCHR => {
base.insert("kind".to_string(), "chr".to_string());
add_dev(&mut base, meta);
}
libc::S_IFBLK => {
base.insert("kind".to_string(), "blk".to_string());
add_dev(&mut base, meta);
}
_ => panic!("Unknown file type: 0o{:o}", mode),
}
base
}
fn add_dev(base: &mut AttMap, meta: &Metadata) {
let rdev = meta.rdev();
base.insert("devmaj".to_string(), ((rdev >> 8) & 0xfff).to_string());
base.insert("devmin".to_string(), (rdev & 0xff).to_string());
}
fn time_info(base: &mut AttMap, meta: &Metadata) {
base.insert("mtime".to_string(), meta.mtime().to_string());
base.insert("ctime".to_string(), meta.ctime().to_string());
}