extern crate libc;
use crate::{colors::*, get_ending};
use chrono::{DateTime, Local};
use libc::{S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};
use std::os::unix::fs::PermissionsExt;
use std::{error::Error, path::Path};
#[derive(Clone)]
pub struct Entry {
mode: (bool, u32),
size: f64,
modified: DateTime<Local>,
file_name: String,
pub print: String,
}
impl Entry {
pub fn new(mode: (bool, u32), size: f64, modified: DateTime<Local>, file_name: String) -> Self {
let mut entry = Entry {
mode,
size,
modified,
file_name,
print: String::new(),
};
entry.generate_print();
entry
}
pub fn from_path(path: &Path) -> Result<Self, Box<dyn Error>> {
let metadata = path.metadata()?;
let mode = (metadata.is_dir(), metadata.permissions().mode());
let size = metadata.len() as f64;
let modified: DateTime<Local> = DateTime::from(metadata.modified()?);
let file_name = format!("{:?}", path);
let entry = Entry::new(mode, size, modified, file_name);
Ok(entry)
}
fn generate_print(&mut self) {
let order = if self.size % 1000000000000.0 != self.size {
self.size /= 1000000000000.0;
"TB"
} else if self.size % 1000000000.0 != self.size {
self.size /= 1000000000.0;
"GB"
} else if self.size % 1000000.0 != self.size {
self.size /= 1000000.0;
"MB"
} else if self.size % 1000.0 != self.size {
self.size /= 1000.0;
"KB"
} else {
"B"
};
let ending = get_ending(&self.file_name);
let file_name = if self.mode.0 {
format!("{}{}{}", BLUE, ending, RESET)
} else {
ending
};
self.print = format!(
"{} {} {} {}",
self.clone().parse_permissions(),
format_args!(
"{}{:>5} {}{:<2}{}",
MAGENTA,
format!("{:.1}", self.size),
BOLD,
order,
RESET
),
format_args!(
"{}{}{}",
CYAN,
self.modified.format("%_d %b %H %H:%M"),
RESET
),
file_name
);
}
fn parse_permissions(self) -> String {
let mut formated_mode = String::new();
let directory: String = if self.mode.0 {
format!("{}{}d{}", BLUE, BOLD, RESET)
} else {
format!("{}ยท{}", BLACK, RESET)
};
formated_mode.push_str(directory.as_str());
let user = self.triplet(S_IRUSR, S_IWUSR, S_IXUSR);
formated_mode.push_str(user.as_str());
let group = self.triplet(S_IRGRP, S_IWGRP, S_IXGRP);
formated_mode.push_str(group.as_str());
let other = self.triplet(S_IROTH, S_IWOTH, S_IXOTH);
formated_mode.push_str(other.as_str());
formated_mode
}
fn triplet(&self, read: u32, write: u32, execute: u32) -> String {
match (
self.mode.1 & read,
self.mode.1 & write,
self.mode.1 & execute,
) {
(0, 0, 0) => format!("{}---{}", BLACK, RESET),
(_, 0, 0) => format!("{}{}r{}{}--{}", BOLD, GREEN, RESET, BLACK, RESET),
(0, _, 0) => format!("{}-{}{}w{}{}-{}", BLACK, BOLD, YELLOW, RESET, BLACK, RESET),
(0, 0, _) => format!("{}--{}{}x{}", BLACK, BOLD, RED, RESET),
(_, 0, _) => format!(
"{}{}r{}{}-{}{}x{}",
BOLD, GREEN, RESET, BLACK, BOLD, RED, RESET
),
(_, _, 0) => format!("{}{}r{}w{}{}-{}", BOLD, GREEN, YELLOW, RESET, BLACK, RESET),
(0, _, _) => format!("{}-{}{}w{}x{}", BLACK, BOLD, YELLOW, RED, RESET),
(_, _, _) => format!("{}{}r{}w{}x{}", BOLD, GREEN, YELLOW, RED, RESET),
}
}
}