use std::convert::TryFrom;
use std::path::Path;
use std::str::FromStr;
use std::time::SystemTime;
use super::{FileType, ListParser, ParseError, ParseResult, PosixPex, PosixPexQuery};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct File {
pub(crate) name: String,
pub(crate) file_type: FileType,
pub(crate) size: usize,
pub(crate) modified: SystemTime,
pub(crate) uid: Option<u32>,
pub(crate) gid: Option<u32>,
pub(crate) posix_pex: (PosixPex, PosixPex, PosixPex),
}
impl File {
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn is_directory(&self) -> bool {
self.file_type.is_directory()
}
pub fn is_file(&self) -> bool {
self.file_type.is_file()
}
pub fn is_symlink(&self) -> bool {
self.file_type.is_symlink()
}
pub fn symlink(&self) -> Option<&Path> {
self.file_type.symlink()
}
pub fn file_type(&self) -> &FileType {
&self.file_type
}
pub fn size(&self) -> usize {
self.size
}
pub fn modified(&self) -> SystemTime {
self.modified
}
pub fn uid(&self) -> Option<u32> {
self.uid.to_owned()
}
pub fn gid(&self) -> Option<u32> {
self.gid.to_owned()
}
pub fn can_read(&self, who: PosixPexQuery) -> bool {
self.query_pex(who).can_read()
}
pub fn can_write(&self, who: PosixPexQuery) -> bool {
self.query_pex(who).can_write()
}
pub fn can_execute(&self, who: PosixPexQuery) -> bool {
self.query_pex(who).can_execute()
}
fn query_pex(&self, who: PosixPexQuery) -> &PosixPex {
match who {
PosixPexQuery::Group => &self.posix_pex.1,
PosixPexQuery::Others => &self.posix_pex.2,
PosixPexQuery::Owner => &self.posix_pex.0,
}
}
#[deprecated(
since = "7.1.0",
note = "Use `FileParser::parse_mlsd` or `FileParser::parse_mlst` instead"
)]
pub fn from_mlsx_line(line: &str) -> ParseResult<Self> {
super::ListParser::parse_mlsx(line)
}
#[deprecated(since = "7.1.0", note = "Use `FileParser::parse_posix` instead")]
pub fn from_posix_line(line: &str) -> ParseResult<Self> {
super::ListParser::parse_posix(line)
}
#[deprecated(since = "7.1.0", note = "Use `FileParser::parse_dos` instead")]
pub fn from_dos_line(line: &str) -> ParseResult<Self> {
super::ListParser::parse_dos(line)
}
}
impl FromStr for File {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
impl TryFrom<&str> for File {
type Error = ParseError;
fn try_from(line: &str) -> Result<Self, Self::Error> {
ListParser::parse_posix(line)
.or_else(|_| ListParser::parse_dos(line))
.or_else(|_| ListParser::parse_mlsd(line))
.or_else(|_| ListParser::parse_mlst(line))
}
}
impl TryFrom<&String> for File {
type Error = ParseError;
fn try_from(line: &String) -> Result<Self, Self::Error> {
Self::try_from(line.as_str())
}
}
impl TryFrom<String> for File {
type Error = ParseError;
fn try_from(line: String) -> Result<Self, Self::Error> {
File::try_from(line.as_str())
}
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn file_getters() {
let file: File = File {
name: String::from("provola.txt"),
file_type: FileType::File,
size: 2048,
modified: SystemTime::UNIX_EPOCH,
gid: Some(0),
uid: Some(0),
posix_pex: (PosixPex::from(7), PosixPex::from(5), PosixPex::from(4)),
};
assert_eq!(file.name(), "provola.txt");
assert_eq!(file.is_directory(), false);
assert_eq!(file.is_file(), true);
assert_eq!(file.is_symlink(), false);
assert_eq!(file.symlink(), None);
assert_eq!(file.size(), 2048);
assert_eq!(file.gid(), Some(0));
assert_eq!(file.uid(), Some(0));
assert_eq!(file.modified(), SystemTime::UNIX_EPOCH);
assert_eq!(file.can_read(PosixPexQuery::Owner), true);
assert_eq!(file.can_write(PosixPexQuery::Owner), true);
assert_eq!(file.can_execute(PosixPexQuery::Owner), true);
assert_eq!(file.can_read(PosixPexQuery::Group), true);
assert_eq!(file.can_write(PosixPexQuery::Group), false);
assert_eq!(file.can_execute(PosixPexQuery::Group), true);
assert_eq!(file.can_read(PosixPexQuery::Others), true);
assert_eq!(file.can_write(PosixPexQuery::Others), false);
assert_eq!(file.can_execute(PosixPexQuery::Others), false);
}
#[test]
fn file_type_getter() {
let file = File {
name: String::from("test.txt"),
file_type: FileType::File,
size: 0,
modified: SystemTime::UNIX_EPOCH,
gid: None,
uid: None,
posix_pex: (PosixPex::from(0), PosixPex::from(0), PosixPex::from(0)),
};
assert_eq!(file.file_type(), &FileType::File);
let dir = File {
name: String::from("mydir"),
file_type: FileType::Directory,
size: 0,
modified: SystemTime::UNIX_EPOCH,
gid: None,
uid: None,
posix_pex: (PosixPex::from(0), PosixPex::from(0), PosixPex::from(0)),
};
assert_eq!(dir.file_type(), &FileType::Directory);
}
#[test]
fn try_from_str_posix() {
let file = File::try_from("-rw-r--r-- 1 user group 1234 Nov 5 2018 example.txt").unwrap();
assert_eq!(file.name(), "example.txt");
assert!(file.is_file());
}
#[test]
fn try_from_str_dos() {
let file = File::try_from("04-08-14 03:09PM 8192 omar.txt").unwrap();
assert_eq!(file.name(), "omar.txt");
assert!(file.is_file());
}
#[test]
fn try_from_str_mlsx() {
let file = File::try_from("type=file;size=8192;modify=20181105163248; omar.txt").unwrap();
assert_eq!(file.name(), "omar.txt");
assert!(file.is_file());
}
#[test]
fn try_from_string_ref() {
let line = String::from("-rw-r--r-- 1 user group 1234 Nov 5 2018 example.txt");
let file = File::try_from(&line).unwrap();
assert_eq!(file.name(), "example.txt");
}
#[test]
fn try_from_string_owned() {
let line = String::from("-rw-r--r-- 1 user group 1234 Nov 5 2018 example.txt");
let file = File::try_from(line).unwrap();
assert_eq!(file.name(), "example.txt");
}
#[test]
fn from_str_trait() {
let file: File = "-rw-r--r-- 1 user group 1234 Nov 5 2018 example.txt"
.parse()
.unwrap();
assert_eq!(file.name(), "example.txt");
}
#[test]
fn try_from_invalid_line() {
assert!(File::try_from("type=badtype;size=0;modify=20181105163248; bad.txt").is_err());
}
#[test]
fn file_type() {
use std::path::PathBuf;
assert_eq!(FileType::Directory.is_directory(), true);
assert_eq!(FileType::Directory.is_file(), false);
assert_eq!(FileType::Directory.is_symlink(), false);
assert_eq!(FileType::Directory.symlink(), None);
assert_eq!(FileType::File.is_directory(), false);
assert_eq!(FileType::File.is_file(), true);
assert_eq!(FileType::File.is_symlink(), false);
assert_eq!(FileType::File.symlink(), None);
assert_eq!(FileType::Symlink(PathBuf::default()).is_directory(), false);
assert_eq!(FileType::Symlink(PathBuf::default()).is_file(), false);
assert_eq!(FileType::Symlink(PathBuf::default()).is_symlink(), true);
assert_eq!(
FileType::Symlink(PathBuf::default()).symlink(),
Some(PathBuf::default().as_path())
);
}
}