Host::mkdir and Host::remove

This commit is contained in:
ChristianVisintin
2020-11-14 15:41:17 +01:00
parent 37d2bc9485
commit 5033657936
2 changed files with 174 additions and 23 deletions
+169 -23
View File
@@ -37,14 +37,41 @@ use users::{get_group_by_gid, get_user_by_uid};
// Locals // Locals
use crate::fs::{FsDirectory, FsEntry, FsFile}; use crate::fs::{FsDirectory, FsEntry, FsFile};
/// ## HostError /// ## HostErrorType
/// ///
/// HostError provides errors related to local host file system /// HostErrorType provides an overview of the specific host error
pub enum HostError { #[derive(PartialEq, std::fmt::Debug)]
pub enum HostErrorType {
NoSuchFileOrDirectory, NoSuchFileOrDirectory,
ReadonlyFile, ReadonlyFile,
DirNotAccessible, DirNotAccessible,
FileNotAccessible, FileNotAccessible,
FileAlreadyExists,
CouldNotCreateFile,
DeleteFailed,
}
/// ### HostError
///
/// HostError is a wrapper for the error type and the exact io error
pub struct HostError {
pub error: HostErrorType,
pub ioerr: Option<std::io::Error>
}
impl HostError {
/// ### new
///
/// Instantiates a new HostError
pub(crate) fn new(error: HostErrorType, errno: Option<std::io::Error>) -> HostError {
HostError {
error: error,
ioerr: errno
}
}
} }
/// ## Localhost /// ## Localhost
@@ -67,7 +94,7 @@ impl Localhost {
}; };
// Check if dir exists // Check if dir exists
if !host.file_exists(host.wrkdir.as_path()) { if !host.file_exists(host.wrkdir.as_path()) {
return Err(HostError::NoSuchFileOrDirectory); return Err(HostError::new(HostErrorType::NoSuchFileOrDirectory, None));
} }
// Retrieve files for provided path // Retrieve files for provided path
host.files = match host.scan_dir() { host.files = match host.scan_dir() {
@@ -97,7 +124,7 @@ impl Localhost {
pub fn change_wrkdir(&mut self, new_dir: PathBuf) -> Result<PathBuf, HostError> { pub fn change_wrkdir(&mut self, new_dir: PathBuf) -> Result<PathBuf, HostError> {
// Check whether directory exists // Check whether directory exists
if !self.file_exists(new_dir.as_path()) { if !self.file_exists(new_dir.as_path()) {
return Err(HostError::NoSuchFileOrDirectory); return Err(HostError::new(HostErrorType::NoSuchFileOrDirectory, None));
} }
let prev_dir: PathBuf = self.wrkdir.clone(); // Backup location let prev_dir: PathBuf = self.wrkdir.clone(); // Backup location
// Update working directory // Update working directory
@@ -114,16 +141,86 @@ impl Localhost {
Ok(self.wrkdir.clone()) Ok(self.wrkdir.clone())
} }
/// ### mkdir
///
/// Make a directory in the current path and update the file list
pub fn mkdir(&mut self, dir_name: String) -> Result<(), HostError> {
let mut dir_path: PathBuf = self.wrkdir.clone();
dir_path.push(dir_name);
// If dir already exists, return Error
if dir_path.exists() {
return Err(HostError::new(HostErrorType::FileAlreadyExists, None));
}
match std::fs::create_dir(dir_path) {
Ok(_) => {
// Update dir
self.files = match self.scan_dir() {
Ok(f) => f,
Err(err) => return Err(err)
};
Ok(())
},
Err(err) => Err(HostError::new(HostErrorType::CouldNotCreateFile, Some(err)))
}
}
/// ### remove
///
/// Remove file entry from current directory
pub fn remove(&mut self, entry: &FsEntry) -> Result<(), HostError> {
let mut f_path: PathBuf = self.wrkdir.clone();
match entry {
FsEntry::Directory(dir) => {
f_path.push(dir.name.clone());
// If file doesn't exist; return error
if ! f_path.exists() {
return Err(HostError::new(HostErrorType::NoSuchFileOrDirectory, None))
}
// Remove
match std::fs::remove_dir_all(f_path) {
Ok(_) => {
// Update dir
self.files = match self.scan_dir() {
Ok(f) => f,
Err(err) => return Err(err)
};
Ok(())
},
Err(err) => Err(HostError::new(HostErrorType::DeleteFailed, Some(err)))
}
},
FsEntry::File(file) => {
f_path.push(file.name.clone());
// If file doesn't exist; return error
if ! f_path.exists() {
return Err(HostError::new(HostErrorType::NoSuchFileOrDirectory, None))
}
// Remove
match std::fs::remove_file(f_path) {
Ok(_) => {
// Update dir
self.files = match self.scan_dir() {
Ok(f) => f,
Err(err) => return Err(err)
};
Ok(())
},
Err(err) => Err(HostError::new(HostErrorType::DeleteFailed, Some(err)))
}
}
}
}
/// ### open_file_read /// ### open_file_read
/// ///
/// Open file for read /// Open file for read
pub fn open_file_read(&self, file: &Path) -> Result<File, HostError> { pub fn open_file_read(&self, file: &Path) -> Result<File, HostError> {
if !self.file_exists(file) { if !self.file_exists(file) {
return Err(HostError::NoSuchFileOrDirectory); return Err(HostError::new(HostErrorType::NoSuchFileOrDirectory, None))
} }
match OpenOptions::new().create(false).read(true).write(false).open(file) { match OpenOptions::new().create(false).read(true).write(false).open(file) {
Ok(f) => Ok(f), Ok(f) => Ok(f),
Err(_) => Err(HostError::FileNotAccessible), Err(err) => Err(HostError::new(HostErrorType::FileNotAccessible, Some(err))),
} }
} }
@@ -133,9 +230,9 @@ impl Localhost {
pub fn open_file_write(&self, file: &Path) -> Result<File, HostError> { pub fn open_file_write(&self, file: &Path) -> Result<File, HostError> {
match OpenOptions::new().create(true).write(true).truncate(true).open(file) { match OpenOptions::new().create(true).write(true).truncate(true).open(file) {
Ok(f) => Ok(f), Ok(f) => Ok(f),
Err(_) => match self.file_exists(file) { Err(err) => match self.file_exists(file) {
true => Err(HostError::ReadonlyFile), true => Err(HostError::new(HostErrorType::ReadonlyFile, Some(err))),
false => Err(HostError::FileNotAccessible), false => Err(HostError::new(HostErrorType::FileNotAccessible, Some(err))),
}, },
} }
} }
@@ -154,7 +251,7 @@ impl Localhost {
fn scan_dir(&self) -> Result<Vec<FsEntry>, HostError> { fn scan_dir(&self) -> Result<Vec<FsEntry>, HostError> {
let entries = match std::fs::read_dir(self.wrkdir.as_path()) { let entries = match std::fs::read_dir(self.wrkdir.as_path()) {
Ok(e) => e, Ok(e) => e,
Err(_) => return Err(HostError::DirNotAccessible), Err(err) => return Err(HostError::new(HostErrorType::DirNotAccessible, Some(err))),
}; };
let mut fs_entries: Vec<FsEntry> = Vec::new(); let mut fs_entries: Vec<FsEntry> = Vec::new();
for entry in entries { for entry in entries {
@@ -300,6 +397,13 @@ mod tests {
#[cfg(any(unix, macos, linux))] #[cfg(any(unix, macos, linux))]
use std::os::unix::fs::{PermissionsExt, symlink}; use std::os::unix::fs::{PermissionsExt, symlink};
#[test]
fn test_host_error_new() {
let error: HostError = HostError::new(HostErrorType::CouldNotCreateFile, None);
assert_eq!(error.error, HostErrorType::CouldNotCreateFile);
assert!(error.ioerr.is_none());
}
#[test] #[test]
#[cfg(any(unix, macos, linux))] #[cfg(any(unix, macos, linux))]
fn test_host_localhost_new() { fn test_host_localhost_new() {
@@ -444,25 +548,67 @@ mod tests {
let files: Vec<FsEntry> = host.list_dir(); let files: Vec<FsEntry> = host.list_dir();
println!("Entries {:?}", files); println!("Entries {:?}", files);
// Verify files // Verify files
let foo_file: &FsEntry = files.get(0).unwrap(); let file_0: &FsEntry = files.get(0).unwrap();
match foo_file { match file_0 {
FsEntry::File(foo_file) => { FsEntry::File(file_0) => {
assert_eq!(foo_file.name, String::from("foo.txt")); if file_0.name == String::from("foo.txt") {
assert!(foo_file.symlink.is_none()); assert!(file_0.symlink.is_none());
} else {
assert_eq!(*file_0.symlink.as_ref().unwrap(), PathBuf::from(format!("{}/foo.txt", tmpdir.path().display())));
}
}, },
_ => panic!("expected entry 0 to be file: {:?}", foo_file) _ => panic!("expected entry 0 to be file: {:?}", file_0)
}; };
// Verify simlink // Verify simlink
let bar_file: &FsEntry = files.get(1).unwrap(); let file_1: &FsEntry = files.get(1).unwrap();
match bar_file { match file_1 {
FsEntry::File(bar_file) => { FsEntry::File(file_1) => {
assert_eq!(bar_file.name, String::from("bar.txt")); if file_1.name == String::from("bar.txt") {
assert_eq!(*bar_file.symlink.as_ref().unwrap(), PathBuf::from(format!("{}/foo.txt", tmpdir.path().display()))); assert_eq!(*file_1.symlink.as_ref().unwrap(), PathBuf::from(format!("{}/foo.txt", tmpdir.path().display())));
} else {
assert!(file_1.symlink.is_none());
}
}, },
_ => panic!("expected entry 1 to be file: {:?}", bar_file) _ => panic!("expected entry 0 to be file: {:?}", file_1)
}; };
} }
#[test]
#[cfg(any(unix, macos, linux))]
fn test_host_localhost_mkdir() {
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
let files: Vec<FsEntry> = host.list_dir();
assert_eq!(files.len(), 0); // There should be 0 files now
assert!(host.mkdir(String::from("test_dir")).is_ok());
let files: Vec<FsEntry> = host.list_dir();
assert_eq!(files.len(), 1); // There should be 1 file now
// Try to re-create directory
assert!(host.mkdir(String::from("test_dir")).is_err())
}
#[test]
#[cfg(any(unix, macos, linux))]
fn test_host_localhost_remove() {
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
// Create sample file
assert!(File::create(format!("{}/foo.txt", tmpdir.path().display()).as_str()).is_ok());
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
let files: Vec<FsEntry> = host.list_dir();
assert_eq!(files.len(), 1); // There should be 1 file now
// Remove file
assert!(host.remove(files.get(0).unwrap()).is_ok());
// There should be 0 files now
let files: Vec<FsEntry> = host.list_dir();
assert_eq!(files.len(), 0); // There should be 0 files now
// Create directory
assert!(host.mkdir(String::from("test_dir")).is_ok());
// Delete directory
let files: Vec<FsEntry> = host.list_dir();
assert_eq!(files.len(), 1); // There should be 1 file now
assert!(host.remove(files.get(0).unwrap()).is_ok());
}
/// ### create_sample_file /// ### create_sample_file
/// ///
/// Create a sample file /// Create a sample file
+5
View File
@@ -29,6 +29,11 @@ extern crate getopts;
use getopts::Options; use getopts::Options;
use std::env; use std::env;
// Include
mod filetransfer;
mod fs;
mod host;
/// ### print_usage /// ### print_usage
/// ///
/// Print usage /// Print usage