FileTransferError with message and code

This commit is contained in:
ChristianVisintin
2020-12-01 15:57:31 +01:00
parent cd3ffae285
commit 71dbe7ea85
2 changed files with 82 additions and 48 deletions

View File

@@ -29,6 +29,7 @@ use std::path::{Path, PathBuf};
use crate::fs::FsEntry; use crate::fs::FsEntry;
// Transfers // Transfers
//pub mod ftp_transfer;
pub mod sftp_transfer; pub mod sftp_transfer;
/// ## FileTransferProtocol /// ## FileTransferProtocol
@@ -45,7 +46,16 @@ pub enum FileTransferProtocol {
/// ///
/// FileTransferError defines the possible errors available for a file transfer /// FileTransferError defines the possible errors available for a file transfer
pub enum FileTransferError { pub struct FileTransferError {
code: FileTransferErrorType,
msg: Option<String>,
}
/// ## FileTransferErrorType
///
/// FileTransferErrorType defines the possible errors available for a file transfer
pub enum FileTransferErrorType {
AuthenticationFailed, AuthenticationFailed,
BadAddress, BadAddress,
ConnectionError, ConnectionError,
@@ -56,27 +66,51 @@ pub enum FileTransferError {
NoSuchFileOrDirectory, NoSuchFileOrDirectory,
ProtocolError, ProtocolError,
UninitializedSession, 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 { impl std::fmt::Display for FileTransferError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let err: String = match self { let err: String = match &self.code {
FileTransferError::AuthenticationFailed => { FileTransferErrorType::AuthenticationFailed => {
String::from("Authentication failed: bad credentials") String::from("Authentication failed")
} }
FileTransferError::BadAddress => String::from("Bad address syntax"), FileTransferErrorType::BadAddress => String::from("Bad address syntax"),
FileTransferError::ConnectionError => String::from("Connection error"), FileTransferErrorType::ConnectionError => String::from("Connection error"),
FileTransferError::DirStatFailed => String::from("Could not stat directory"), FileTransferErrorType::DirStatFailed => String::from("Could not stat directory"),
FileTransferError::FileCreateDenied => String::from("Failed to create file"), FileTransferErrorType::FileCreateDenied => String::from("Failed to create file"),
FileTransferError::FileReadonly => String::from("File is readonly"), FileTransferErrorType::FileReadonly => String::from("File is readonly"),
FileTransferError::IoErr(err) => format!("IO Error: {}", err), FileTransferErrorType::IoErr(err) => format!("IO Error: {}", err),
FileTransferError::NoSuchFileOrDirectory => String::from("No such file or directory"), FileTransferErrorType::NoSuchFileOrDirectory => {
FileTransferError::ProtocolError => String::from("Protocol error"), String::from("No such file or directory")
FileTransferError::UninitializedSession => String::from("Uninitialized session"), }
//FileTransferError::UnknownError => String::from("Unknown error"), 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>; fn rename(&self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError>;
/// ### stat /// ### stat
/// ///
/// Stat file and return FsEntry /// Stat file and return FsEntry
fn stat(&self, path: &Path) -> Result<FsEntry, FileTransferError>; fn stat(&self, path: &Path) -> Result<FsEntry, FileTransferError>;

View File

@@ -27,7 +27,7 @@
extern crate ssh2; extern crate ssh2;
// Locals // Locals
use super::{FileTransfer, FileTransferError}; use super::{FileTransfer, FileTransferError, FileTransferErrorType};
use crate::fs::{FsDirectory, FsEntry, FsFile}; use crate::fs::{FsDirectory, FsEntry, FsFile};
// Includes // Includes
@@ -69,17 +69,17 @@ impl SftpFileTransfer {
match self.sftp.as_ref().unwrap().realpath(root.as_path()) { match self.sftp.as_ref().unwrap().realpath(root.as_path()) {
Ok(p) => match self.sftp.as_ref().unwrap().stat(p.as_path()) { Ok(p) => match self.sftp.as_ref().unwrap().stat(p.as_path()) {
Ok(_) => Ok(PathBuf::from(p)), 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) { false => match self.sftp.as_ref().unwrap().realpath(p) {
Ok(p) => match self.sftp.as_ref().unwrap().stat(p.as_path()) { Ok(p) => match self.sftp.as_ref().unwrap().stat(p.as_path()) {
Ok(_) => Ok(PathBuf::from(p)), 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 // Setup tcp stream
let tcp: TcpStream = match TcpStream::connect(format!("{}:{}", address, port)) { let tcp: TcpStream = match TcpStream::connect(format!("{}:{}", address, port)) {
Ok(stream) => stream, Ok(stream) => stream,
Err(_) => return Err(FileTransferError::BadAddress), Err(_) => return Err(FileTransferError::new(FileTransferErrorType::BadAddress)),
}; };
// Create session // Create session
let mut session: Session = match Session::new() { let mut session: Session = match Session::new() {
Ok(s) => s, Ok(s) => s,
Err(_) => return Err(FileTransferError::ConnectionError), Err(_) => return Err(FileTransferError::new(FileTransferErrorType::ConnectionError)),
}; };
// Set TCP stream // Set TCP stream
session.set_tcp_stream(tcp); session.set_tcp_stream(tcp);
// Open connection // Open connection
if let Err(_) = session.handshake() { if let Err(_) = session.handshake() {
return Err(FileTransferError::ConnectionError); return Err(FileTransferError::new(FileTransferErrorType::ConnectionError));
} }
// Try authentication // Try authentication
if let Err(_) = session.userauth_password( if let Err(_) = session.userauth_password(
username.unwrap_or(String::from("")).as_str(), username.unwrap_or(String::from("")).as_str(),
password.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 // Set blocking to true
session.set_blocking(true); session.set_blocking(true);
// Get Sftp client // Get Sftp client
let sftp: Sftp = match session.sftp() { let sftp: Sftp = match session.sftp() {
Ok(s) => s, Ok(s) => s,
Err(_) => return Err(FileTransferError::ProtocolError), Err(_) => return Err(FileTransferError::new(FileTransferErrorType::ProtocolError)),
}; };
// Get working directory // Get working directory
self.wrkdir = match sftp.realpath(PathBuf::from(".").as_path()) { self.wrkdir = match sftp.realpath(PathBuf::from(".").as_path()) {
Ok(p) => p, Ok(p) => p,
Err(_) => return Err(FileTransferError::ProtocolError), Err(_) => return Err(FileTransferError::new(FileTransferErrorType::ProtocolError)),
}; };
// Set session // Set session
self.session = Some(session); self.session = Some(session);
@@ -241,10 +241,10 @@ impl FileTransfer for SftpFileTransfer {
self.sftp = None; self.sftp = None;
Ok(()) 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<PathBuf, FileTransferError> { fn pwd(&self) -> Result<PathBuf, FileTransferError> {
match self.sftp { match self.sftp {
Some(_) => Ok(self.wrkdir.clone()), 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()) Ok(self.wrkdir.clone())
} }
None => Err(FileTransferError::UninitializedSession), None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)),
} }
} }
@@ -295,7 +295,7 @@ impl FileTransfer for SftpFileTransfer {
}; };
// Get files // Get files
match sftp.readdir(dir.as_path()) { match sftp.readdir(dir.as_path()) {
Err(_) => return Err(FileTransferError::DirStatFailed), Err(_) => return Err(FileTransferError::new(FileTransferErrorType::DirStatFailed)),
Ok(files) => { Ok(files) => {
// Allocate vector // Allocate vector
let mut entries: Vec<FsEntry> = Vec::with_capacity(files.len()); let mut entries: Vec<FsEntry> = 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()); let path: PathBuf = self.get_abs_path(PathBuf::from(dir).as_path());
match sftp.mkdir(path.as_path(), 0o775) { match sftp.mkdir(path.as_path(), 0o775) {
Ok(_) => Ok(()), 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 /// Remove a file or a directory
fn remove(&self, file: &FsEntry) -> Result<(), FileTransferError> { fn remove(&self, file: &FsEntry) -> Result<(), FileTransferError> {
match self.sftp.as_ref() { match self.sftp.as_ref() {
None => Err(FileTransferError::UninitializedSession), None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)),
Some(sftp) => { Some(sftp) => {
// Match if file is a file or a directory // Match if file is a file or a directory
match file { match file {
@@ -341,7 +341,7 @@ impl FileTransfer for SftpFileTransfer {
// Remove file // Remove file
match sftp.unlink(f.abs_path.as_path()) { match sftp.unlink(f.abs_path.as_path()) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err(FileTransferError::FileReadonly), Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileReadonly)),
} }
} }
FsEntry::Directory(d) => { FsEntry::Directory(d) => {
@@ -358,7 +358,7 @@ impl FileTransfer for SftpFileTransfer {
// Finally remove directory // Finally remove directory
match sftp.rmdir(d.abs_path.as_path()) { match sftp.rmdir(d.abs_path.as_path()) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err(FileTransferError::FileReadonly), Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileReadonly)),
} }
} }
Err(err) => return Err(err), Err(err) => return Err(err),
@@ -374,7 +374,7 @@ impl FileTransfer for SftpFileTransfer {
/// Rename file or a directory /// Rename file or a directory
fn rename(&self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError> { fn rename(&self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError> {
match self.sftp.as_ref() { match self.sftp.as_ref() {
None => Err(FileTransferError::UninitializedSession), None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)),
Some(sftp) => { Some(sftp) => {
// Resolve destination path // Resolve destination path
let abs_dst: PathBuf = self.get_abs_path(dst); 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) { match sftp.rename(abs_src.as_path(), abs_dst.as_path(), None) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err(FileTransferError::FileCreateDenied), Err(_) => Err(FileTransferError::new(FileTransferErrorType::FileCreateDenied)),
} }
} }
} }
@@ -405,10 +405,10 @@ impl FileTransfer for SftpFileTransfer {
// Get file // Get file
match sftp.stat(dir.as_path()) { match sftp.stat(dir.as_path()) {
Ok(metadata) => Ok(self.make_fsentry(dir.as_path(), &metadata)), 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 /// Data contains the file data
fn send_file(&self, file_name: &Path) -> Result<Box<dyn Write>, FileTransferError> { fn send_file(&self, file_name: &Path) -> Result<Box<dyn Write>, FileTransferError> {
match self.sftp.as_ref() { match self.sftp.as_ref() {
None => Err(FileTransferError::UninitializedSession), None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)),
Some(sftp) => { Some(sftp) => {
let remote_path: PathBuf = self.get_abs_path(file_name); let remote_path: PathBuf = self.get_abs_path(file_name);
match sftp.create(remote_path.as_path()) { match sftp.create(remote_path.as_path()) {
Ok(file) => Ok(Box::new(file)), 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 /// Receive file from remote with provided name
fn recv_file(&self, file_name: &Path) -> Result<(Box<dyn Read>, usize), FileTransferError> { fn recv_file(&self, file_name: &Path) -> Result<(Box<dyn Read>, usize), FileTransferError> {
match self.sftp.as_ref() { match self.sftp.as_ref() {
None => Err(FileTransferError::UninitializedSession), None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession)),
Some(sftp) => { Some(sftp) => {
// Get remote file name // Get remote file name
let remote_path: PathBuf = match self.get_remote_path(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; file.seek(std::io::SeekFrom::End(0)).unwrap_or(0) as usize;
// rewind // rewind
if let Err(err) = file.seek(std::io::SeekFrom::Start(0)) { 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)) Ok((Box::new(file), file_size))
} }
Err(_) => Err(FileTransferError::NoSuchFileOrDirectory), Err(_) => Err(FileTransferError::new(FileTransferErrorType::NoSuchFileOrDirectory)),
} }
} }
} }