From 71dbe7ea8565c3845e203b2e48eb3681cbef34f0 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Tue, 1 Dec 2020 15:57:31 +0100 Subject: [PATCH] FileTransferError with message and code --- src/filetransfer/mod.rs | 68 +++++++++++++++++++++++-------- src/filetransfer/sftp_transfer.rs | 62 ++++++++++++++-------------- 2 files changed, 82 insertions(+), 48 deletions(-) diff --git a/src/filetransfer/mod.rs b/src/filetransfer/mod.rs index 585a59f..8265dec 100644 --- a/src/filetransfer/mod.rs +++ b/src/filetransfer/mod.rs @@ -29,6 +29,7 @@ use std::path::{Path, PathBuf}; use crate::fs::FsEntry; // Transfers +//pub mod ftp_transfer; pub mod sftp_transfer; /// ## FileTransferProtocol @@ -45,7 +46,16 @@ pub enum FileTransferProtocol { /// /// FileTransferError defines the possible errors available for a file transfer -pub enum FileTransferError { +pub struct FileTransferError { + code: FileTransferErrorType, + msg: Option, +} + +/// ## FileTransferErrorType +/// +/// FileTransferErrorType defines the possible errors available for a file transfer + +pub enum FileTransferErrorType { AuthenticationFailed, BadAddress, ConnectionError, @@ -56,27 +66,51 @@ pub enum FileTransferError { NoSuchFileOrDirectory, ProtocolError, UninitializedSession, - //UnknownError, +} + +impl FileTransferError { + /// ### new + /// + /// Instantiates a new FileTransferError + pub fn new(code: FileTransferErrorType) -> FileTransferError { + FileTransferError { + code: code, + msg: None, + } + } + + /// ### new_ex + /// + /// Instantiates a new FileTransferError with message + pub fn new_ex(code: FileTransferErrorType, msg: String) -> FileTransferError { + let mut err: FileTransferError = FileTransferError::new(code); + err.msg = Some(msg); + err + } } impl std::fmt::Display for FileTransferError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let err: String = match self { - FileTransferError::AuthenticationFailed => { - String::from("Authentication failed: bad credentials") + let err: String = match &self.code { + FileTransferErrorType::AuthenticationFailed => { + String::from("Authentication failed") } - FileTransferError::BadAddress => String::from("Bad address syntax"), - FileTransferError::ConnectionError => String::from("Connection error"), - FileTransferError::DirStatFailed => String::from("Could not stat directory"), - FileTransferError::FileCreateDenied => String::from("Failed to create file"), - FileTransferError::FileReadonly => String::from("File is readonly"), - FileTransferError::IoErr(err) => format!("IO Error: {}", err), - FileTransferError::NoSuchFileOrDirectory => String::from("No such file or directory"), - FileTransferError::ProtocolError => String::from("Protocol error"), - FileTransferError::UninitializedSession => String::from("Uninitialized session"), - //FileTransferError::UnknownError => String::from("Unknown error"), + FileTransferErrorType::BadAddress => String::from("Bad address syntax"), + FileTransferErrorType::ConnectionError => String::from("Connection error"), + FileTransferErrorType::DirStatFailed => String::from("Could not stat directory"), + FileTransferErrorType::FileCreateDenied => String::from("Failed to create file"), + FileTransferErrorType::FileReadonly => String::from("File is readonly"), + FileTransferErrorType::IoErr(err) => format!("IO Error: {}", err), + FileTransferErrorType::NoSuchFileOrDirectory => { + String::from("No such file or directory") + } + FileTransferErrorType::ProtocolError => String::from("Protocol error"), + FileTransferErrorType::UninitializedSession => String::from("Uninitialized session"), }; - write!(f, "{}", err) + match &self.msg { + Some(msg) => write!(f, "{} ({})", err, msg), + None => write!(f, "{}", err), + } } } @@ -142,7 +176,7 @@ pub trait FileTransfer { fn rename(&self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError>; /// ### stat - /// + /// /// Stat file and return FsEntry fn stat(&self, path: &Path) -> Result; diff --git a/src/filetransfer/sftp_transfer.rs b/src/filetransfer/sftp_transfer.rs index 5670656..fbb99b2 100644 --- a/src/filetransfer/sftp_transfer.rs +++ b/src/filetransfer/sftp_transfer.rs @@ -27,7 +27,7 @@ extern crate ssh2; // Locals -use super::{FileTransfer, FileTransferError}; +use super::{FileTransfer, FileTransferError, FileTransferErrorType}; use crate::fs::{FsDirectory, FsEntry, FsFile}; // Includes @@ -69,17 +69,17 @@ impl SftpFileTransfer { match self.sftp.as_ref().unwrap().realpath(root.as_path()) { Ok(p) => match self.sftp.as_ref().unwrap().stat(p.as_path()) { Ok(_) => Ok(PathBuf::from(p)), - Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)), }, - Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)), } } false => match self.sftp.as_ref().unwrap().realpath(p) { Ok(p) => match self.sftp.as_ref().unwrap().stat(p.as_path()) { Ok(_) => Ok(PathBuf::from(p)), - Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)), }, - Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)), }, } } @@ -188,37 +188,37 @@ impl FileTransfer for SftpFileTransfer { // Setup tcp stream let tcp: TcpStream = match TcpStream::connect(format!("{}:{}", address, port)) { Ok(stream) => stream, - Err(_) => return Err(FileTransferError::BadAddress), + Err(_) => return Err(FileTransferError::new(FileTransferErrorType::BadAddress)), }; // Create session let mut session: Session = match Session::new() { Ok(s) => s, - Err(_) => return Err(FileTransferError::ConnectionError), + Err(_) => return Err(FileTransferError::new(FileTransferErrorType::ConnectionError)), }; // Set TCP stream session.set_tcp_stream(tcp); // Open connection if let Err(_) = session.handshake() { - return Err(FileTransferError::ConnectionError); + return Err(FileTransferError::new(FileTransferErrorType::ConnectionError)); } // Try authentication if let Err(_) = session.userauth_password( username.unwrap_or(String::from("")).as_str(), password.unwrap_or(String::from("")).as_str(), ) { - return Err(FileTransferError::AuthenticationFailed); + return Err(FileTransferError::new(FileTransferErrorType::AuthenticationFailed)); } // Set blocking to true session.set_blocking(true); // Get Sftp client let sftp: Sftp = match session.sftp() { Ok(s) => s, - Err(_) => return Err(FileTransferError::ProtocolError), + Err(_) => return Err(FileTransferError::new(FileTransferErrorType::ProtocolError)), }; // Get working directory self.wrkdir = match sftp.realpath(PathBuf::from(".").as_path()) { Ok(p) => p, - Err(_) => return Err(FileTransferError::ProtocolError), + Err(_) => return Err(FileTransferError::new(FileTransferErrorType::ProtocolError)), }; // Set session self.session = Some(session); @@ -241,10 +241,10 @@ impl FileTransfer for SftpFileTransfer { self.sftp = None; Ok(()) } - Err(_) => Err(FileTransferError::ConnectionError), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::ConnectionError)), } } - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), } } @@ -261,7 +261,7 @@ impl FileTransfer for SftpFileTransfer { fn pwd(&self) -> Result { match self.sftp { Some(_) => Ok(self.wrkdir.clone()), - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), } } @@ -278,7 +278,7 @@ impl FileTransfer for SftpFileTransfer { }; Ok(self.wrkdir.clone()) } - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), } } @@ -295,7 +295,7 @@ impl FileTransfer for SftpFileTransfer { }; // Get files match sftp.readdir(dir.as_path()) { - Err(_) => return Err(FileTransferError::DirStatFailed), + Err(_) => return Err(FileTransferError::new(FileTransferErrorType::DirStatFailed)), Ok(files) => { // Allocate vector let mut entries: Vec = Vec::with_capacity(files.len()); @@ -307,7 +307,7 @@ impl FileTransfer for SftpFileTransfer { } } } - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), } } @@ -321,10 +321,10 @@ impl FileTransfer for SftpFileTransfer { let path: PathBuf = self.get_abs_path(PathBuf::from(dir).as_path()); match sftp.mkdir(path.as_path(), 0o775) { Ok(_) => Ok(()), - Err(_) => Err(FileTransferError::FileCreateDenied), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileCreateDenied)), } } - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), } } @@ -333,7 +333,7 @@ impl FileTransfer for SftpFileTransfer { /// Remove a file or a directory fn remove(&self, file: &FsEntry) -> Result<(), FileTransferError> { match self.sftp.as_ref() { - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), Some(sftp) => { // Match if file is a file or a directory match file { @@ -341,7 +341,7 @@ impl FileTransfer for SftpFileTransfer { // Remove file match sftp.unlink(f.abs_path.as_path()) { Ok(_) => Ok(()), - Err(_) => Err(FileTransferError::FileReadonly), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileReadonly)), } } FsEntry::Directory(d) => { @@ -358,7 +358,7 @@ impl FileTransfer for SftpFileTransfer { // Finally remove directory match sftp.rmdir(d.abs_path.as_path()) { Ok(_) => Ok(()), - Err(_) => Err(FileTransferError::FileReadonly), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileReadonly)), } } Err(err) => return Err(err), @@ -374,7 +374,7 @@ impl FileTransfer for SftpFileTransfer { /// Rename file or a directory fn rename(&self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError> { match self.sftp.as_ref() { - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), Some(sftp) => { // Resolve destination path let abs_dst: PathBuf = self.get_abs_path(dst); @@ -385,7 +385,7 @@ impl FileTransfer for SftpFileTransfer { }; match sftp.rename(abs_src.as_path(), abs_dst.as_path(), None) { Ok(_) => Ok(()), - Err(_) => Err(FileTransferError::FileCreateDenied), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileCreateDenied)), } } } @@ -405,10 +405,10 @@ impl FileTransfer for SftpFileTransfer { // Get file match sftp.stat(dir.as_path()) { Ok(metadata) => Ok(self.make_fsentry(dir.as_path(), &metadata)), - Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)), } } - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), } } @@ -419,12 +419,12 @@ impl FileTransfer for SftpFileTransfer { /// Data contains the file data fn send_file(&self, file_name: &Path) -> Result, FileTransferError> { match self.sftp.as_ref() { - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), Some(sftp) => { let remote_path: PathBuf = self.get_abs_path(file_name); match sftp.create(remote_path.as_path()) { Ok(file) => Ok(Box::new(file)), - Err(_) => Err(FileTransferError::FileCreateDenied), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileCreateDenied)), } } } @@ -435,7 +435,7 @@ impl FileTransfer for SftpFileTransfer { /// Receive file from remote with provided name fn recv_file(&self, file_name: &Path) -> Result<(Box, usize), FileTransferError> { match self.sftp.as_ref() { - None => Err(FileTransferError::UninitializedSession), + None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)), Some(sftp) => { // Get remote file name let remote_path: PathBuf = match self.get_remote_path(file_name) { @@ -449,11 +449,11 @@ impl FileTransfer for SftpFileTransfer { file.seek(std::io::SeekFrom::End(0)).unwrap_or(0) as usize; // rewind if let Err(err) = file.seek(std::io::SeekFrom::Start(0)) { - return Err(FileTransferError::IoErr(err)); + return Err(FileTransferError::new(FileTransferErrorType::IoErr(err))); } Ok((Box::new(file), file_size)) } - Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), + Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)), } } }