diff options
Diffstat (limited to 'src/modes/display/fileinfo.rs')
-rw-r--r-- | src/modes/display/fileinfo.rs | 77 |
1 files changed, 48 insertions, 29 deletions
diff --git a/src/modes/display/fileinfo.rs b/src/modes/display/fileinfo.rs index cfb65d7..b649989 100644 --- a/src/modes/display/fileinfo.rs +++ b/src/modes/display/fileinfo.rs @@ -95,7 +95,7 @@ pub enum SizeColumn { /// Used for normal files. It's the size in bytes. Size(u64), /// Used for directories, nothing is displayed - None, + EntryCount(u64), /// Use for CharDevice and BlockDevice. /// It's the major & minor driver versions. MajorMinor((u8, u8)), @@ -105,7 +105,7 @@ impl std::fmt::Display for SizeColumn { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Size(bytes) => write!(f, " {hs}", hs = human_size(*bytes)), - Self::None => write!(f, " - "), + Self::EntryCount(count) => write!(f, " {hs}", hs = human_size(*count)), Self::MajorMinor((major, minor)) => write!(f, "{major:>3},{minor:<3}"), } } @@ -114,7 +114,7 @@ impl std::fmt::Display for SizeColumn { impl SizeColumn { fn new(size: u64, metadata: &Metadata, file_kind: &FileKind<Valid>) -> Self { match file_kind { - FileKind::Directory => Self::None, + FileKind::Directory => Self::EntryCount(size), FileKind::CharDevice | FileKind::BlockDevice => Self::MajorMinor(major_minor(metadata)), _ => Self::Size(size), } @@ -127,42 +127,42 @@ impl SizeColumn { #[derive(Clone, Debug)] pub struct FileInfo { /// Full path of the file - pub path: std::rc::Rc<path::Path>, + pub path: std::sync::Arc<path::Path>, /// Filename - pub filename: std::rc::Rc<str>, + pub filename: std::sync::Arc<str>, /// File size as a `String`, already human formated. /// For char devices and block devices we display major & minor like ls. pub size_column: SizeColumn, /// True size of a file, not formated pub true_size: u64, /// Owner name of the file. - pub owner: std::rc::Rc<str>, + pub owner: std::sync::Arc<str>, /// Group name of the file. - pub group: std::rc::Rc<str>, + pub group: std::sync::Arc<str>, /// System time of last modification - pub system_time: std::rc::Rc<str>, + pub system_time: std::sync::Arc<str>, /// Is this file currently selected ? pub is_selected: bool, /// What kind of file is this ? pub file_kind: FileKind<Valid>, /// Extension of the file. `""` for a directory. - pub extension: std::rc::Rc<str>, + pub extension: std::sync::Arc<str>, /// A formated filename where the "kind" of file /// (directory, char device, block devive, fifo, socket, normal) /// is prepend to the name, allowing a "sort by kind" method. - pub kind_format: std::rc::Rc<str>, + pub kind_format: std::sync::Arc<str>, } impl FileInfo { pub fn new(path: &path::Path, users: &Users) -> Result<Self> { let filename = extract_filename(path)?; let metadata = symlink_metadata(path)?; - let path = std::rc::Rc::from(path); + let true_size = true_size(path, &metadata); + let path = std::sync::Arc::from(path); let owner = extract_owner(&metadata, users); let group = extract_group(&metadata, users); let system_time = extract_datetime(&metadata)?; let is_selected = false; - let true_size = extract_file_size(&metadata); let file_kind = FileKind::new(&metadata, &path); let size_column = SizeColumn::new(true_size, &metadata, &file_kind); let extension = extract_extension(&path).into(); @@ -193,7 +193,7 @@ impl FileInfo { /// The filename is used when we create the fileinfo for "." and ".." in every folder. pub fn from_path_with_name(path: &path::Path, filename: &str, users: &Users) -> Result<Self> { let mut file_info = Self::new(path, users)?; - file_info.filename = std::rc::Rc::from(filename); + file_info.filename = std::sync::Arc::from(filename); file_info.kind_format = filekind_and_filename(filename, &file_info.file_kind); Ok(file_info) } @@ -203,7 +203,7 @@ impl FileInfo { } /// String representation of file permissions - pub fn permissions(&self) -> Result<std::rc::Rc<str>> { + pub fn permissions(&self) -> Result<std::sync::Arc<str>> { Ok(extract_permissions_string(&self.metadata()?)) } @@ -279,7 +279,7 @@ impl FileInfo { let name = if let Ok(name) = extract_filename(&self.path) { name } else { - std::rc::Rc::from("") + std::sync::Arc::from("") }; format!("/{name} ") } @@ -368,30 +368,30 @@ pub fn is_not_hidden(entry: &DirEntry) -> Result<bool> { Ok(is_hidden) } -fn extract_filename(path: &path::Path) -> Result<std::rc::Rc<str>> { +fn extract_filename(path: &path::Path) -> Result<std::sync::Arc<str>> { let s = path .file_name() .unwrap_or_default() .to_str() .context(format!("Couldn't read filename of {p}", p = path.display()))?; - Ok(std::rc::Rc::from(s)) + Ok(std::sync::Arc::from(s)) } /// Returns the modified time. -fn extract_datetime(metadata: &Metadata) -> Result<std::rc::Rc<str>> { +fn extract_datetime(metadata: &Metadata) -> Result<std::sync::Arc<str>> { let datetime: DateTime<Local> = metadata.modified()?.into(); - Ok(std::rc::Rc::from( + Ok(std::sync::Arc::from( format!("{}", datetime.format("%Y/%m/%d %T")).as_str(), )) } /// Reads the permission and converts them into a string. -fn extract_permissions_string(metadata: &Metadata) -> std::rc::Rc<str> { +fn extract_permissions_string(metadata: &Metadata) -> std::sync::Arc<str> { let mode = (metadata.mode() & MAX_MODE) as usize; let s_o = convert_octal_mode(mode >> 6); let s_g = convert_octal_mode((mode >> 3) & 7); let s_a = convert_octal_mode(mode & 7); - std::rc::Rc::from(format!("{s_o}{s_a}{s_g}").as_str()) + std::sync::Arc::from(format!("{s_o}{s_a}{s_g}").as_str()) } /// Convert an integer like `Oo7` into its string representation like `"rwx"` @@ -402,20 +402,29 @@ pub fn convert_octal_mode(mode: usize) -> &'static str { /// Reads the owner name and returns it as a string. /// If it's not possible to get the owner name (happens if the owner exists on a remote machine but not on host), /// it returns the uid as a `Result<String>`. -fn extract_owner(metadata: &Metadata, users: &Users) -> std::rc::Rc<str> { +fn extract_owner(metadata: &Metadata, users: &Users) -> std::sync::Arc<str> { match users.get_user_by_uid(metadata.uid()) { - Some(name) => std::rc::Rc::from(name.as_str()), - None => std::rc::Rc::from(format!("{}", metadata.uid()).as_str()), + Some(name) => std::sync::Arc::from(name.as_str()), + None => std::sync::Arc::from(format!("{}", metadata.uid()).as_str()), } } /// Reads the group name and returns it as a string. /// If it's not possible to get the group name (happens if the group exists on a remote machine but not on host), /// it returns the gid as a `Result<String>`. -fn extract_group(metadata: &Metadata, users: &Users) -> std::rc::Rc<str> { +fn extract_group(metadata: &Metadata, users: &Users) -> std::sync::Arc<str> { match users.get_group_by_gid(metadata.gid()) { - Some(name) => std::rc::Rc::from(name.as_str()), - None => std::rc::Rc::from(format!("{}", metadata.gid()).as_str()), + Some(name) => std::sync::Arc::from(name.as_str()), + None => std::sync::Arc::from(format!("{}", metadata.gid()).as_str()), + } +} + +/// Size of a file, number of entries of a directory +fn true_size(path: &path::Path, metadata: &Metadata) -> u64 { + if path.is_dir() { + count_entries(path).unwrap_or_default() + } else { + extract_file_size(metadata) } } @@ -424,6 +433,16 @@ fn extract_file_size(metadata: &Metadata) -> u64 { metadata.len() } +/// Number of elements of a directory. +/// +/// # Errors +/// +/// Will fail if the provided path isn't a directory +/// or doesn't exist. +fn count_entries(path: &path::Path) -> Result<u64> { + Ok(std::fs::read_dir(path)?.count() as u64) +} + /// Extract the major & minor driver version of a special file. /// It's used for CharDevice & BlockDevice fn major_minor(metadata: &Metadata) -> (u8, u8) { @@ -441,8 +460,8 @@ pub fn extract_extension(path: &path::Path) -> &str { .unwrap_or_default() } -fn filekind_and_filename(filename: &str, file_kind: &FileKind<Valid>) -> std::rc::Rc<str> { - std::rc::Rc::from(format!("{c}{filename}", c = file_kind.sortable_char()).as_str()) +fn filekind_and_filename(filename: &str, file_kind: &FileKind<Valid>) -> std::sync::Arc<str> { + std::sync::Arc::from(format!("{c}{filename}", c = file_kind.sortable_char()).as_str()) } /// true iff the path is a valid symlink (pointing to an existing file). |