FTP transfer

This commit is contained in:
ChristianVisintin
2020-12-03 14:45:17 +01:00
parent 803c235966
commit 33e64d1b43

View File

@@ -34,11 +34,11 @@ use crate::utils::lstime_to_systime;
// Includes // Includes
use ftp::openssl::ssl::{SslContext, SslMethod}; use ftp::openssl::ssl::{SslContext, SslMethod};
use ftp::{FtpError, FtpStream}; use ftp::FtpStream;
use regex::Regex; use regex::Regex;
use std::io::{Read, Seek, Write}; use std::io::{Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime}; use std::time::SystemTime;
/// ## FtpFileTransfer /// ## FtpFileTransfer
/// ///
@@ -79,7 +79,7 @@ impl FtpFileTransfer {
} }
// Collect metadata // Collect metadata
// Get if is directory and if is symlink // Get if is directory and if is symlink
let (is_dir, is_symlink): (bool, bool) = match metadata.get(1).unwrap().as_str() { let (is_dir, _is_symlink): (bool, bool) = match metadata.get(1).unwrap().as_str() {
"-" => (false, false), "-" => (false, false),
"l" => (false, true), "l" => (false, true),
"d" => (true, false), "d" => (true, false),
@@ -238,24 +238,25 @@ impl FileTransfer for FtpFileTransfer {
}; };
// If SSL, open secure session // If SSL, open secure session
if self.ftps { if self.ftps {
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let ctx = SslContext::builder(SslMethod::tls()).unwrap();
let ctx = ctx.build(); let ctx = ctx.build();
if let Err(err) = stream.into_secure(ctx) { stream = match stream.into_secure(ctx) {
return Err(FileTransferError::new_ex( Ok(s) => s,
FileTransferErrorType::SslError, Err(err) => {
format!("{}", err), return Err(FileTransferError::new_ex(
)); FileTransferErrorType::SslError,
} format!("{}", err),
))
}
};
} }
// If username / password... // If username / password...
if let Some(username) = username { if let Some(username) = username {
if let Err(err) = stream.login( let password: String = match password {
username.as_str(), Some(pwd) => String::from(pwd),
match password { None => String::new(),
Some(pwd) => pwd.as_ref(), };
None => "", if let Err(err) = stream.login(username.as_str(), password.as_str()) {
},
) {
return Err(FileTransferError::new_ex( return Err(FileTransferError::new_ex(
FileTransferErrorType::AuthenticationFailed, FileTransferErrorType::AuthenticationFailed,
format!("{}", err), format!("{}", err),
@@ -273,7 +274,7 @@ impl FileTransfer for FtpFileTransfer {
/// Disconnect from the remote server /// Disconnect from the remote server
fn disconnect(&mut self) -> Result<(), FileTransferError> { fn disconnect(&mut self) -> Result<(), FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => match stream.quit() { Some(stream) => match stream.quit() {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => Err(FileTransferError::new_ex( Err(err) => Err(FileTransferError::new_ex(
@@ -301,8 +302,8 @@ impl FileTransfer for FtpFileTransfer {
/// ///
/// Print working directory /// Print working directory
fn pwd(&self) -> Result<PathBuf, FileTransferError> { fn pwd(&mut self) -> Result<PathBuf, FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => match stream.pwd() { Some(stream) => match stream.pwd() {
Ok(path) => Ok(PathBuf::from(path.as_str())), Ok(path) => Ok(PathBuf::from(path.as_str())),
Err(err) => Err(FileTransferError::new_ex( Err(err) => Err(FileTransferError::new_ex(
@@ -321,7 +322,7 @@ impl FileTransfer for FtpFileTransfer {
/// Change working directory /// Change working directory
fn change_dir(&mut self, dir: &Path) -> Result<PathBuf, FileTransferError> { fn change_dir(&mut self, dir: &Path) -> Result<PathBuf, FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => match stream.cwd(&dir.to_string_lossy()) { Some(stream) => match stream.cwd(&dir.to_string_lossy()) {
Ok(_) => Ok(PathBuf::from(dir)), Ok(_) => Ok(PathBuf::from(dir)),
Err(err) => Err(FileTransferError::new_ex( Err(err) => Err(FileTransferError::new_ex(
@@ -339,8 +340,8 @@ impl FileTransfer for FtpFileTransfer {
/// ///
/// List directory entries /// List directory entries
fn list_dir(&self, path: &Path) -> Result<Vec<FsEntry>, FileTransferError> { fn list_dir(&mut self, path: &Path) -> Result<Vec<FsEntry>, FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => match stream.list(Some(&path.to_string_lossy())) { Some(stream) => match stream.list(Some(&path.to_string_lossy())) {
Ok(entries) => { Ok(entries) => {
// Prepare result // Prepare result
@@ -367,12 +368,12 @@ impl FileTransfer for FtpFileTransfer {
/// ### mkdir /// ### mkdir
/// ///
/// Make directory /// Make directory
fn mkdir(&self, dir: &Path) -> Result<(), FileTransferError> { fn mkdir(&mut self, dir: &Path) -> Result<(), FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => match stream.mkdir(&dir.to_string_lossy()) { Some(stream) => match stream.mkdir(&dir.to_string_lossy()) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => Err(FileTransferError::new_ex( Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::DirStatFailed, FileTransferErrorType::FileCreateDenied,
format!("{}", err), format!("{}", err),
)), )),
}, },
@@ -385,60 +386,60 @@ impl FileTransfer for FtpFileTransfer {
/// ### remove /// ### remove
/// ///
/// Remove a file or a directory /// Remove a file or a directory
fn remove(&self, fsentry: &FsEntry) -> Result<(), FileTransferError> { fn remove(&mut self, fsentry: &FsEntry) -> Result<(), FileTransferError> {
match self.stream { if self.stream.is_none() {
Some(stream) => match fsentry { return Err(FileTransferError::new(
// Match fs entry... FileTransferErrorType::UninitializedSession,
FsEntry::File(file) => { ));
// Remove file directly }
match stream.rm(file.name.as_ref()) { match fsentry {
Ok(_) => Ok(()), // Match fs entry...
Err(err) => Err(FileTransferError::new_ex( FsEntry::File(file) => {
FileTransferErrorType::DirStatFailed, // Remove file directly
format!("{}", err), match self.stream.as_mut().unwrap().rm(file.name.as_ref()) {
)), Ok(_) => Ok(()),
} Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::PexError,
format!("{}", err),
)),
} }
FsEntry::Directory(dir) => { }
// Get directory files FsEntry::Directory(dir) => {
match self.list_dir(dir.abs_path.as_path()) { // Get directory files
Ok(files) => { match self.list_dir(dir.abs_path.as_path()) {
// Remove recursively files Ok(files) => {
for file in files.iter() { // Remove recursively files
if let Err(err) = self.remove(&file) { for file in files.iter() {
return Err(FileTransferError::new_ex( if let Err(err) = self.remove(&file) {
FileTransferErrorType::DirStatFailed, return Err(FileTransferError::new_ex(
format!("{}", err), FileTransferErrorType::PexError,
));
}
}
// Once all files in directory have been deleted, remove directory
match stream.rmdir(dir.name.as_str()) {
Ok(_) => Ok(()),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::DirStatFailed,
format!("{}", err), format!("{}", err),
)), ));
} }
} }
Err(err) => Err(FileTransferError::new_ex( // Once all files in directory have been deleted, remove directory
FileTransferErrorType::DirStatFailed, match self.stream.as_mut().unwrap().rmdir(dir.name.as_str()) {
format!("{}", err), Ok(_) => Ok(()),
)), Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::PexError,
format!("{}", err),
)),
}
} }
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::DirStatFailed,
format!("{}", err),
)),
} }
}, }
None => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession,
)),
} }
} }
/// ### rename /// ### rename
/// ///
/// Rename file or a directory /// Rename file or a directory
fn rename(&self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError> { fn rename(&mut self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => { Some(stream) => {
// Get name // Get name
let src_name: String = match file { let src_name: String = match file {
@@ -458,7 +459,7 @@ impl FileTransfer for FtpFileTransfer {
match stream.rename(src_name.as_str(), &dst_name.as_path().to_string_lossy()) { match stream.rename(src_name.as_str(), &dst_name.as_path().to_string_lossy()) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => Err(FileTransferError::new_ex( Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::DirStatFailed, FileTransferErrorType::FileCreateDenied,
format!("{}", err), format!("{}", err),
)), )),
} }
@@ -472,9 +473,9 @@ impl FileTransfer for FtpFileTransfer {
/// ### stat /// ### stat
/// ///
/// Stat file and return FsEntry /// Stat file and return FsEntry
fn stat(&self, path: &Path) -> Result<FsEntry, FileTransferError> { fn stat(&mut self, _path: &Path) -> Result<FsEntry, FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => Err(FileTransferError::new( Some(_) => Err(FileTransferError::new(
FileTransferErrorType::UnsupportedFeature, FileTransferErrorType::UnsupportedFeature,
)), )),
None => Err(FileTransferError::new( None => Err(FileTransferError::new(
@@ -489,9 +490,15 @@ impl FileTransfer for FtpFileTransfer {
/// File name is referred to the name of the file as it will be saved /// File name is referred to the name of the file as it will be saved
/// Data contains the file data /// Data contains the file data
/// Returns file and its size /// Returns file and its size
fn send_file(&self, file_name: &Path) -> Result<Box<dyn Write>, FileTransferError> { fn send_file(&mut self, file_name: &Path) -> Result<Box<dyn Write>, FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => {} Some(stream) => match stream.put_with_stream(&file_name.to_string_lossy()) {
Ok(writer) => Ok(Box::new(writer)),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::FileCreateDenied,
format!("{}", err),
)),
},
None => Err(FileTransferError::new( None => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession, FileTransferErrorType::UninitializedSession,
)), )),
@@ -502,9 +509,15 @@ impl FileTransfer for FtpFileTransfer {
/// ///
/// Receive file from remote with provided name /// Receive file from remote with provided name
/// Returns file and its size /// Returns file and its size
fn recv_file(&self, file_name: &Path) -> Result<(Box<dyn Read>, usize), FileTransferError> { fn recv_file(&mut self, file_name: &Path) -> Result<Box<dyn Read>, FileTransferError> {
match self.stream { match &mut self.stream {
Some(stream) => {} Some(stream) => match stream.get(&file_name.to_string_lossy()) {
Ok(reader) => Ok(Box::new(reader)),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::NoSuchFileOrDirectory,
format!("{}", err),
)),
},
None => Err(FileTransferError::new( None => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession, FileTransferErrorType::UninitializedSession,
)), )),