mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
FileTransferError with message and code
This commit is contained in:
@@ -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>;
|
||||||
|
|
||||||
|
|||||||
@@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user