mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Optimizing FsEntry and relatd stuff
This commit is contained in:
535
src/fs/mod.rs
535
src/fs/mod.rs
@@ -94,26 +94,118 @@ impl FsEntry {
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_name
|
||||
///
|
||||
/// Get file name from `FsEntry`
|
||||
pub fn get_name(&self) -> String {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.name.clone(),
|
||||
FsEntry::File(file) => file.name.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_last_change_time
|
||||
///
|
||||
/// Get last change time from `FsEntry`
|
||||
pub fn get_last_change_time(&self) -> SystemTime {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.last_change_time,
|
||||
FsEntry::File(file) => file.last_change_time,
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_last_access_time
|
||||
///
|
||||
/// Get access time from `FsEntry`
|
||||
pub fn get_last_access_time(&self) -> SystemTime {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.last_access_time,
|
||||
FsEntry::File(file) => file.last_access_time,
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_creation_time
|
||||
///
|
||||
/// Get creation time from `FsEntry`
|
||||
pub fn get_creation_time(&self) -> SystemTime {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.creation_time,
|
||||
FsEntry::File(file) => file.creation_time,
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_size
|
||||
///
|
||||
/// Get size from `FsEntry`. For directories is always 4096
|
||||
pub fn get_size(&self) -> usize {
|
||||
match self {
|
||||
FsEntry::Directory(_) => 4096,
|
||||
FsEntry::File(file) => file.size,
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_ftype
|
||||
///
|
||||
/// Get file type from `FsEntry`. For directories is always None
|
||||
pub fn get_ftype(&self) -> Option<String> {
|
||||
match self {
|
||||
FsEntry::Directory(_) => None,
|
||||
FsEntry::File(file) => file.ftype.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_user
|
||||
///
|
||||
/// Get uid from `FsEntry`
|
||||
pub fn get_user(&self) -> Option<u32> {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.user.clone(),
|
||||
FsEntry::File(file) => file.user.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_group
|
||||
///
|
||||
/// Get gid from `FsEntry`
|
||||
pub fn get_group(&self) -> Option<u32> {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.group.clone(),
|
||||
FsEntry::File(file) => file.group.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_unix_pex
|
||||
///
|
||||
/// Get unix pex from `FsEntry`
|
||||
pub fn get_unix_pex(&self) -> Option<(u8, u8, u8)> {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.unix_pex.clone(),
|
||||
FsEntry::File(file) => file.unix_pex.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### is_symlink
|
||||
///
|
||||
/// Returns whether the `FsEntry` is a symlink
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => dir.symlink.is_some(),
|
||||
FsEntry::File(file) => file.symlink.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_realfile
|
||||
///
|
||||
/// Return the real file pointed by a `FsEntry`
|
||||
pub fn get_realfile(&self) -> Option<FsEntry> {
|
||||
pub fn get_realfile(&self) -> FsEntry {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => match &dir.symlink {
|
||||
Some(symlink) => match symlink.get_realfile() {
|
||||
// Recursive call
|
||||
Some(e) => e.get_realfile(), // Recursive call
|
||||
None => Some(*symlink.clone()),
|
||||
},
|
||||
None => None,
|
||||
Some(symlink) => symlink.get_realfile(),
|
||||
None => self.clone(),
|
||||
},
|
||||
FsEntry::File(file) => match &file.symlink {
|
||||
Some(symlink) => match symlink.get_realfile() {
|
||||
// Recursive call
|
||||
Some(e) => e.get_realfile(), // Recursive call
|
||||
None => Some(*symlink.clone()),
|
||||
},
|
||||
None => None,
|
||||
Some(symlink) => symlink.get_realfile(),
|
||||
None => self.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -125,102 +217,50 @@ impl std::fmt::Display for FsEntry {
|
||||
/// Format File Entry as `ls` does
|
||||
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => {
|
||||
// Create mode string
|
||||
let mut mode: String = String::with_capacity(10);
|
||||
let file_type: char = match dir.symlink {
|
||||
Some(_) => 'l',
|
||||
None => 'd',
|
||||
};
|
||||
mode.push(file_type);
|
||||
match dir.unix_pex {
|
||||
None => mode.push_str("?????????"),
|
||||
Some((owner, group, others)) => {
|
||||
mode.push_str(fmt_pex(owner, group, others).as_str())
|
||||
}
|
||||
}
|
||||
// Get username
|
||||
let username: String = match dir.user {
|
||||
Some(uid) => match get_user_by_uid(uid) {
|
||||
Some(user) => user.name().to_string_lossy().to_string(),
|
||||
None => uid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
// Get group
|
||||
/*
|
||||
let group: String = match dir.group {
|
||||
Some(gid) => match get_group_by_gid(gid) {
|
||||
Some(group) => group.name().to_string_lossy().to_string(),
|
||||
None => gid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
*/
|
||||
// Get byte size
|
||||
let size: String = String::from("4096");
|
||||
// Get date
|
||||
let datetime: String = time_to_str(dir.last_change_time, "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let dir_name: String = match dir.name.len() >= 24 {
|
||||
false => dir.name.clone(),
|
||||
true => format!("{}...", &dir.name.as_str()[0..20]),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{:24}\t{:12}\t{:12}\t{:9}\t{:17}",
|
||||
dir_name, mode, username, size, datetime
|
||||
)
|
||||
}
|
||||
FsEntry::File(file) => {
|
||||
// Create mode string
|
||||
let mut mode: String = String::with_capacity(10);
|
||||
let file_type: char = match file.symlink {
|
||||
Some(_) => 'l',
|
||||
None => '-',
|
||||
};
|
||||
mode.push(file_type);
|
||||
match file.unix_pex {
|
||||
None => mode.push_str("?????????"),
|
||||
Some((owner, group, others)) => {
|
||||
mode.push_str(fmt_pex(owner, group, others).as_str())
|
||||
}
|
||||
}
|
||||
// Get username
|
||||
let username: String = match file.user {
|
||||
Some(uid) => match get_user_by_uid(uid) {
|
||||
Some(user) => user.name().to_string_lossy().to_string(),
|
||||
None => uid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
// Get group
|
||||
/*
|
||||
let group: String = match file.group {
|
||||
Some(gid) => match get_group_by_gid(gid) {
|
||||
Some(group) => group.name().to_string_lossy().to_string(),
|
||||
None => gid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
*/
|
||||
// Get byte size
|
||||
let size: ByteSize = ByteSize(file.size as u64);
|
||||
// Get date
|
||||
let datetime: String = time_to_str(file.last_change_time, "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let file_name: String = match file.name.len() >= 24 {
|
||||
false => file.name.clone(),
|
||||
true => format!("{}...", &file.name.as_str()[0..20]),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{:24}\t{:12}\t{:12}\t{:9}\t{:17}",
|
||||
file_name, mode, username, size, datetime
|
||||
)
|
||||
}
|
||||
// Create mode string
|
||||
let mut mode: String = String::with_capacity(10);
|
||||
let file_type: char = match self.is_symlink() {
|
||||
true => 'l',
|
||||
false => 'd',
|
||||
};
|
||||
mode.push(file_type);
|
||||
match self.get_unix_pex() {
|
||||
None => mode.push_str("?????????"),
|
||||
Some((owner, group, others)) => mode.push_str(fmt_pex(owner, group, others).as_str()),
|
||||
}
|
||||
// Get username
|
||||
let username: String = match self.get_user() {
|
||||
Some(uid) => match get_user_by_uid(uid) {
|
||||
Some(user) => user.name().to_string_lossy().to_string(),
|
||||
None => uid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
// Get group
|
||||
/*
|
||||
let group: String = match self.get_group() {
|
||||
Some(gid) => match get_group_by_gid(gid) {
|
||||
Some(group) => group.name().to_string_lossy().to_string(),
|
||||
None => gid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
*/
|
||||
// Get byte size
|
||||
let size: ByteSize = ByteSize(self.get_size() as u64);
|
||||
// Get date
|
||||
let datetime: String = time_to_str(self.get_last_change_time(), "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let name: String = self.get_name();
|
||||
let name: String = match name.len() >= 24 {
|
||||
false => name,
|
||||
true => format!("{}...", &name.as_str()[0..20]),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{:24}\t{:12}\t{:12}\t{:9}\t{:17}",
|
||||
name, mode, username, size, datetime
|
||||
)
|
||||
}
|
||||
|
||||
/// ### fmt_ls
|
||||
@@ -229,91 +269,202 @@ impl std::fmt::Display for FsEntry {
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
FsEntry::Directory(dir) => {
|
||||
// Create mode string
|
||||
let mut mode: String = String::with_capacity(10);
|
||||
let file_type: char = match dir.symlink {
|
||||
Some(_) => 'l',
|
||||
None => 'd',
|
||||
};
|
||||
mode.push(file_type);
|
||||
match dir.unix_pex {
|
||||
None => mode.push_str("?????????"),
|
||||
Some((owner, group, others)) => {
|
||||
mode.push_str(fmt_pex(owner, group, others).as_str())
|
||||
}
|
||||
}
|
||||
// Get username
|
||||
let username: String = match dir.user {
|
||||
Some(uid) => uid.to_string(),
|
||||
None => String::from("0"),
|
||||
};
|
||||
// Get group
|
||||
/*
|
||||
let group: String = match dir.group {
|
||||
Some(gid) => gid.to_string(),
|
||||
None => String::from("0"),
|
||||
};
|
||||
*/
|
||||
// Get byte size
|
||||
let size: String = String::from("4096");
|
||||
// Get date
|
||||
let datetime: String = time_to_str(dir.last_change_time, "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let dir_name: String = match dir.name.len() >= 24 {
|
||||
false => dir.name.clone(),
|
||||
true => format!("{}...", &dir.name.as_str()[0..20]),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{:24}\t{:12}\t{:12}\t{:9}\t{:17}",
|
||||
dir_name, mode, username, size, datetime
|
||||
)
|
||||
}
|
||||
FsEntry::File(file) => {
|
||||
// Create mode string
|
||||
let mut mode: String = String::with_capacity(10);
|
||||
let file_type: char = match file.symlink {
|
||||
Some(_) => 'l',
|
||||
None => '-',
|
||||
};
|
||||
mode.push(file_type);
|
||||
match file.unix_pex {
|
||||
None => mode.push_str("?????????"),
|
||||
Some((owner, group, others)) => {
|
||||
mode.push_str(fmt_pex(owner, group, others).as_str())
|
||||
}
|
||||
}
|
||||
// Get username
|
||||
let username: String = match file.user {
|
||||
Some(uid) => uid.to_string(),
|
||||
None => String::from("0"),
|
||||
};
|
||||
// Get group
|
||||
/*
|
||||
let group: String = match file.group {
|
||||
Some(gid) => gid.to_string(),
|
||||
None => String::from("0"),
|
||||
};
|
||||
*/
|
||||
// Get byte size
|
||||
let size: ByteSize = ByteSize(file.size as u64);
|
||||
// Get date
|
||||
let datetime: String = time_to_str(file.last_change_time, "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let file_name: String = match file.name.len() >= 24 {
|
||||
false => file.name.clone(),
|
||||
true => format!("{}...", &file.name.as_str()[0..20]),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{:24}\t{:12}\t{:12}\t{:9}\t{:17}",
|
||||
file_name, mode, username, size, datetime
|
||||
)
|
||||
}
|
||||
// Create mode string
|
||||
let mut mode: String = String::with_capacity(10);
|
||||
let file_type: char = match self.is_symlink() {
|
||||
true => 'l',
|
||||
false => 'd',
|
||||
};
|
||||
mode.push(file_type);
|
||||
match self.get_unix_pex() {
|
||||
None => mode.push_str("?????????"),
|
||||
Some((owner, group, others)) => mode.push_str(fmt_pex(owner, group, others).as_str()),
|
||||
}
|
||||
// Get username
|
||||
let username: usize = match self.get_user() {
|
||||
Some(uid) => uid,
|
||||
None => 0,
|
||||
};
|
||||
// Get group
|
||||
/*
|
||||
let group: String = match self.get_group() {
|
||||
Some(gid) => match get_group_by_gid(gid) {
|
||||
Some(group) => group.name().to_string_lossy().to_string(),
|
||||
None => gid.to_string(),
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
*/
|
||||
// Get byte size
|
||||
let size: ByteSize = ByteSize(self.get_size() as u64);
|
||||
// Get date
|
||||
let datetime: String = time_to_str(self.get_last_change_time(), "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let name: String = self.get_name();
|
||||
let name: String = match name.len() >= 24 {
|
||||
false => name,
|
||||
true => format!("{}...", &name.as_str()[0..20]),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{:24}\t{:12}\t{:12}\t{:9}\t{:17}",
|
||||
name, mode, username, size, datetime
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: tests
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fs_fsentry_dir() {
|
||||
let t_now: SystemTime = SystemTime::now();
|
||||
let entry: FsEntry = FsEntry::Directory(FsDirectory {
|
||||
name: String::from("foo"),
|
||||
abs_path: PathBuf::from("/foo"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
readonly: false,
|
||||
symlink: None, // UNIX only
|
||||
user: Some(0), // UNIX only
|
||||
group: Some(0), // UNIX only
|
||||
unix_pex: Some((7, 5, 5)), // UNIX only
|
||||
});
|
||||
assert_eq!(entry.get_abs_path(), PathBuf::from("/foo"));
|
||||
assert_eq!(entry.get_name(), String::from("foo"));
|
||||
assert_eq!(entry.get_last_access_time(), t_now);
|
||||
assert_eq!(entry.get_last_change_time(), t_now);
|
||||
assert_eq!(entry.get_creation_time(), t_now);
|
||||
assert_eq!(entry.get_size(), 4096);
|
||||
assert_eq!(entry.get_ftype(), None);
|
||||
assert_eq!(entry.get_user(), Some(0));
|
||||
assert_eq!(entry.get_group(), Some(0));
|
||||
assert_eq!(entry.is_symlink(), false);
|
||||
assert_eq!(entry.get_unix_pex(), Some((7, 5, 5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_fsentry_file() {
|
||||
let t_now: SystemTime = SystemTime::now();
|
||||
let entry: FsEntry = FsEntry::File(FsFile {
|
||||
name: String::from("bar.txt"),
|
||||
abs_path: PathBuf::from("/bar.txt"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
size: 8192,
|
||||
readonly: false,
|
||||
ftype: Some(String::from("txt")),
|
||||
symlink: None, // UNIX only
|
||||
user: Some(0), // UNIX only
|
||||
group: Some(0), // UNIX only
|
||||
unix_pex: Some((6, 4, 4)), // UNIX only
|
||||
});
|
||||
assert_eq!(entry.get_abs_path(), PathBuf::from("/bar.txt"));
|
||||
assert_eq!(entry.get_name(), String::from("bar.txt"));
|
||||
assert_eq!(entry.get_last_access_time(), t_now);
|
||||
assert_eq!(entry.get_last_change_time(), t_now);
|
||||
assert_eq!(entry.get_creation_time(), t_now);
|
||||
assert_eq!(entry.get_size(), 8192);
|
||||
assert_eq!(entry.get_ftype(), Some(String::from("txt")));
|
||||
assert_eq!(entry.get_user(), Some(0));
|
||||
assert_eq!(entry.get_group(), Some(0));
|
||||
assert_eq!(entry.get_unix_pex(), Some((6, 4, 4)));
|
||||
assert_eq!(entry.is_symlink(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_fsentry_realfile_none() {
|
||||
let t_now: SystemTime = SystemTime::now();
|
||||
// With file...
|
||||
let entry: FsEntry = FsEntry::File(FsFile {
|
||||
name: String::from("bar.txt"),
|
||||
abs_path: PathBuf::from("/bar.txt"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
size: 8192,
|
||||
readonly: false,
|
||||
ftype: Some(String::from("txt")),
|
||||
symlink: None, // UNIX only
|
||||
user: Some(0), // UNIX only
|
||||
group: Some(0), // UNIX only
|
||||
unix_pex: Some((6, 4, 4)), // UNIX only
|
||||
});
|
||||
// Symlink is None...
|
||||
assert_eq!(
|
||||
entry.get_realfile().get_abs_path(),
|
||||
PathBuf::from("/bar.txt")
|
||||
);
|
||||
// With directory...
|
||||
let entry: FsEntry = FsEntry::Directory(FsDirectory {
|
||||
name: String::from("foo"),
|
||||
abs_path: PathBuf::from("/foo"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
readonly: false,
|
||||
symlink: None, // UNIX only
|
||||
user: Some(0), // UNIX only
|
||||
group: Some(0), // UNIX only
|
||||
unix_pex: Some((7, 5, 5)), // UNIX only
|
||||
});
|
||||
assert_eq!(entry.is_symlink(), true);
|
||||
assert_eq!(entry.get_realfile().get_abs_path(), PathBuf::from("/foo"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_fsentry_realfile_some() {
|
||||
let t_now: SystemTime = SystemTime::now();
|
||||
// Prepare entries
|
||||
// root -> child -> target
|
||||
let entry_target: FsEntry = FsEntry::Directory(FsDirectory {
|
||||
name: String::from("projects"),
|
||||
abs_path: PathBuf::from("/home/cvisintin/projects"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
readonly: false,
|
||||
symlink: None, // UNIX only
|
||||
user: Some(0), // UNIX only
|
||||
group: Some(0), // UNIX only
|
||||
unix_pex: Some((7, 7, 7)), // UNIX only
|
||||
});
|
||||
let entry_child: FsEntry = FsEntry::Directory(FsDirectory {
|
||||
name: String::from("projects"),
|
||||
abs_path: PathBuf::from("/develop/projects"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
readonly: false,
|
||||
symlink: Some(Box::new(entry_target)),
|
||||
user: Some(0),
|
||||
group: Some(0),
|
||||
unix_pex: Some((7, 7, 7)),
|
||||
});
|
||||
let entry_root: FsEntry = FsEntry::File(FsFile {
|
||||
name: String::from("projects"),
|
||||
abs_path: PathBuf::from("/projects"),
|
||||
last_change_time: t_now,
|
||||
last_access_time: t_now,
|
||||
creation_time: t_now,
|
||||
size: 8,
|
||||
readonly: false,
|
||||
ftype: None,
|
||||
symlink: Some(Box::new(entry_child)),
|
||||
user: Some(0),
|
||||
group: Some(0),
|
||||
unix_pex: Some((7, 7, 7)),
|
||||
});
|
||||
// get real file
|
||||
let real_file: FsEntry = entry_root.get_realfile();
|
||||
// real file must be projects in /home/cvisintin
|
||||
assert_eq!(
|
||||
real_file.get_abs_path(),
|
||||
PathBuf::from("/home/cvisintin/projects")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user