mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
FTP transfer
This commit is contained in:
@@ -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) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(err) => {
|
||||||
return Err(FileTransferError::new_ex(
|
return Err(FileTransferError::new_ex(
|
||||||
FileTransferErrorType::SslError,
|
FileTransferErrorType::SslError,
|
||||||
format!("{}", err),
|
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,16 +386,20 @@ 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(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
match fsentry {
|
||||||
// Match fs entry...
|
// Match fs entry...
|
||||||
FsEntry::File(file) => {
|
FsEntry::File(file) => {
|
||||||
// Remove file directly
|
// Remove file directly
|
||||||
match stream.rm(file.name.as_ref()) {
|
match self.stream.as_mut().unwrap().rm(file.name.as_ref()) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(FileTransferError::new_ex(
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
FileTransferErrorType::DirStatFailed,
|
FileTransferErrorType::PexError,
|
||||||
format!("{}", err),
|
format!("{}", err),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@@ -407,16 +412,16 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
for file in files.iter() {
|
for file in files.iter() {
|
||||||
if let Err(err) = self.remove(&file) {
|
if let Err(err) = self.remove(&file) {
|
||||||
return Err(FileTransferError::new_ex(
|
return Err(FileTransferError::new_ex(
|
||||||
FileTransferErrorType::DirStatFailed,
|
FileTransferErrorType::PexError,
|
||||||
format!("{}", err),
|
format!("{}", err),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Once all files in directory have been deleted, remove directory
|
// Once all files in directory have been deleted, remove directory
|
||||||
match stream.rmdir(dir.name.as_str()) {
|
match self.stream.as_mut().unwrap().rmdir(dir.name.as_str()) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(FileTransferError::new_ex(
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
FileTransferErrorType::DirStatFailed,
|
FileTransferErrorType::PexError,
|
||||||
format!("{}", err),
|
format!("{}", err),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@@ -427,18 +432,14 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
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,
|
||||||
)),
|
)),
|
||||||
|
|||||||
Reference in New Issue
Block a user