use std::fs;
use std::fs::FileType;
use std::path::Path;
use std::time::SystemTime;
use walkdir::DirEntry;
#[cfg(target_family = "windows")]
use {
std::collections::HashSet,
std::env,
std::ffi::OsStr,
once_cell::unsync::Lazy,
};
use crate::error::MyResult;
pub struct Metadata {
pub file_type: FileType,
pub file_mode: u32,
pub file_size: u64,
pub file_time: SystemTime,
}
impl Metadata {
pub fn from_entry(entry: &DirEntry) -> MyResult<Metadata> {
Self::create_metadata(entry.metadata()?, entry.path())
}
pub fn from_path(path: &Path) -> MyResult<Metadata> {
Self::create_metadata(fs::metadata(&path)?, path)
}
}
#[cfg(target_family = "windows")]
impl Metadata {
fn create_metadata(file_data: fs::Metadata, path: &Path) -> MyResult<Metadata> {
use std::os::windows::fs::MetadataExt;
let file_type = file_data.file_type();
let file_mode = Self::convert_mode(file_data.file_attributes(), path);
let file_size = file_data.file_size();
let file_time = file_data.modified()?;
let file_data = Metadata { file_type, file_mode, file_size, file_time };
return Ok(file_data);
}
fn convert_mode(attributes: u32, path: &Path) -> u32 {
let extensions = Lazy::new(|| {
Self::parse_extensions()
});
let mut octal = 0x04; if attributes & 0x01 == 0 {
octal |= 0x02; }
if let Some(ext) = path.extension().and_then(OsStr::to_str) {
let ext = ext.to_uppercase();
if extensions.contains(&ext) {
octal |= 0x01; }
}
return octal + (octal << 3) + (octal << 6);
}
fn parse_extensions() -> HashSet<String> {
let mut extensions = HashSet::new();
if let Ok(variable) = env::var("PATH_EXT") {
for ext in variable.split(";") {
if let Some(ext) = ext.strip_prefix(".") {
extensions.insert(ext.to_uppercase());
}
}
}
return extensions;
}
}
#[cfg(target_family = "unix")]
impl Metadata {
fn create_metadata(file_data: fs::Metadata, _path: &Path) -> MyResult<Metadata> {
use std::os::unix::fs::MetadataExt;
let file_type = file_data.file_type();
let file_mode = file_data.mode();
let file_size = file_data.size();
let file_time = file_data.modified()?;
let file_data = Metadata { file_type, file_mode, file_size, file_time };
return Ok(file_data);
}
}