mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
ftp transfer, brough parse_list_line as a method of the struct
This commit is contained in:
@@ -33,8 +33,8 @@ use crate::fs::{FsDirectory, FsEntry, FsFile};
|
|||||||
use crate::utils::lstime_to_systime;
|
use crate::utils::lstime_to_systime;
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
use ftp::{FtpStream, FtpError};
|
|
||||||
use ftp::openssl::ssl::{SslContext, SslMethod};
|
use ftp::openssl::ssl::{SslContext, SslMethod};
|
||||||
|
use ftp::{FtpError, FtpStream};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::io::{Read, Seek, Write};
|
use std::io::{Read, Seek, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@@ -49,7 +49,6 @@ pub struct FtpFileTransfer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FtpFileTransfer {
|
impl FtpFileTransfer {
|
||||||
|
|
||||||
/// ### new
|
/// ### new
|
||||||
///
|
///
|
||||||
/// Instantiates a new `FtpFileTransfer`
|
/// Instantiates a new `FtpFileTransfer`
|
||||||
@@ -60,10 +59,162 @@ impl FtpFileTransfer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ### parse_list_line
|
||||||
|
///
|
||||||
|
/// Parse a line of LIST command output and instantiates an FsEntry from it
|
||||||
|
fn parse_list_line(&self, path: &Path, line: &str) -> Result<FsEntry, ()> {
|
||||||
|
// Prepare list regex
|
||||||
|
// NOTE: about this damn regex <https://stackoverflow.com/questions/32480890/is-there-a-regex-to-parse-the-values-from-an-ftp-directory-listing>
|
||||||
|
lazy_static! {
|
||||||
|
static ref LS_RE: Regex = Regex::new(r#"^([\-ld])([\-rwxs]{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+(\w{3}\s+\d{1,2}\s+(?:\d{1,2}:\d{1,2}|\d{4}))\s+(.+)$"#).unwrap();
|
||||||
|
}
|
||||||
|
// Apply regex to result
|
||||||
|
match LS_RE.captures(line) {
|
||||||
|
// String matches regex
|
||||||
|
Some(metadata) => {
|
||||||
|
// NOTE: metadata fmt: (regex, file_type, permissions, link_count, uid, gid, filesize, mtime, filename)
|
||||||
|
// Expected 7 + 1 (8) values: + 1 cause regex is repeated at 0
|
||||||
|
if metadata.len() < 8 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
// Collect metadata
|
||||||
|
// Get if is directory and if is symlink
|
||||||
|
let (is_dir, is_symlink): (bool, bool) = match metadata.get(1).unwrap().as_str() {
|
||||||
|
"-" => (false, false),
|
||||||
|
"l" => (false, true),
|
||||||
|
"d" => (true, false),
|
||||||
|
_ => return Err(()), // Ignore special files
|
||||||
|
};
|
||||||
|
// Check string length (unix pex)
|
||||||
|
if metadata.get(2).unwrap().as_str().len() < 9 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
// Get unix pex
|
||||||
|
let unix_pex: (u8, u8, u8) = {
|
||||||
|
let owner_pex: u8 = {
|
||||||
|
let mut count: u8 = 0;
|
||||||
|
for (i, c) in metadata.get(2).unwrap().as_str()[0..3].chars().enumerate() {
|
||||||
|
match c {
|
||||||
|
'-' => {}
|
||||||
|
_ => {
|
||||||
|
count = count
|
||||||
|
+ match i {
|
||||||
|
0 => 4,
|
||||||
|
1 => 2,
|
||||||
|
2 => 1,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
};
|
||||||
|
let group_pex: u8 = {
|
||||||
|
let mut count: u8 = 0;
|
||||||
|
for (i, c) in metadata.get(2).unwrap().as_str()[3..6].chars().enumerate() {
|
||||||
|
match c {
|
||||||
|
'-' => {}
|
||||||
|
_ => {
|
||||||
|
count = count
|
||||||
|
+ match i {
|
||||||
|
0 => 4,
|
||||||
|
1 => 2,
|
||||||
|
2 => 1,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
};
|
||||||
|
let others_pex: u8 = {
|
||||||
|
let mut count: u8 = 0;
|
||||||
|
for (i, c) in metadata.get(2).unwrap().as_str()[6..9].chars().enumerate() {
|
||||||
|
match c {
|
||||||
|
'-' => {}
|
||||||
|
_ => {
|
||||||
|
count = count
|
||||||
|
+ match i {
|
||||||
|
0 => 4,
|
||||||
|
1 => 2,
|
||||||
|
2 => 1,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
};
|
||||||
|
(owner_pex, group_pex, others_pex)
|
||||||
|
};
|
||||||
|
// Parse mtime and convert to SystemTime
|
||||||
|
let mtime: SystemTime = match lstime_to_systime(
|
||||||
|
metadata.get(7).unwrap().as_str(),
|
||||||
|
"%b %d %Y",
|
||||||
|
"%b %d %H:%M",
|
||||||
|
) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => return Err(()),
|
||||||
|
};
|
||||||
|
// Get uid
|
||||||
|
let uid: Option<u32> = match metadata.get(4).unwrap().as_str().parse::<u32>() {
|
||||||
|
Ok(uid) => Some(uid),
|
||||||
|
Err(_) => None,
|
||||||
|
};
|
||||||
|
// Get gid
|
||||||
|
let gid: Option<u32> = match metadata.get(5).unwrap().as_str().parse::<u32>() {
|
||||||
|
Ok(gid) => Some(gid),
|
||||||
|
Err(_) => None,
|
||||||
|
};
|
||||||
|
// Get filesize
|
||||||
|
let filesize: usize = match metadata.get(6).unwrap().as_str().parse::<usize>() {
|
||||||
|
Ok(sz) => sz,
|
||||||
|
Err(_) => return Err(()),
|
||||||
|
};
|
||||||
|
let file_name: String = String::from(metadata.get(8).unwrap().as_str());
|
||||||
|
let mut abs_path: PathBuf = PathBuf::from(path);
|
||||||
|
let extension: Option<String> = match abs_path.as_path().extension() {
|
||||||
|
None => None,
|
||||||
|
Some(s) => Some(String::from(s.to_string_lossy())),
|
||||||
|
};
|
||||||
|
abs_path.push(file_name.as_str());
|
||||||
|
// Return
|
||||||
|
// Push to entries
|
||||||
|
Ok(match is_dir {
|
||||||
|
true => FsEntry::Directory(FsDirectory {
|
||||||
|
name: file_name,
|
||||||
|
abs_path: abs_path,
|
||||||
|
last_change_time: mtime,
|
||||||
|
last_access_time: mtime,
|
||||||
|
creation_time: mtime,
|
||||||
|
readonly: false,
|
||||||
|
symlink: None,
|
||||||
|
user: uid,
|
||||||
|
group: gid,
|
||||||
|
unix_pex: Some(unix_pex),
|
||||||
|
}),
|
||||||
|
false => FsEntry::File(FsFile {
|
||||||
|
name: file_name,
|
||||||
|
abs_path: abs_path,
|
||||||
|
last_change_time: mtime,
|
||||||
|
last_access_time: mtime,
|
||||||
|
creation_time: mtime,
|
||||||
|
size: filesize,
|
||||||
|
ftype: extension,
|
||||||
|
readonly: false,
|
||||||
|
symlink: None,
|
||||||
|
user: uid,
|
||||||
|
group: gid,
|
||||||
|
unix_pex: Some(unix_pex),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileTransfer for FtpFileTransfer {
|
impl FileTransfer for FtpFileTransfer {
|
||||||
|
|
||||||
/// ### connect
|
/// ### connect
|
||||||
///
|
///
|
||||||
/// Connect to the remote server
|
/// Connect to the remote server
|
||||||
@@ -78,23 +229,37 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
// Get stream
|
// Get stream
|
||||||
let mut stream: FtpStream = match FtpStream::connect(format!("{}:{}", address, port)) {
|
let mut stream: FtpStream = match FtpStream::connect(format!("{}:{}", address, port)) {
|
||||||
Ok(stream) => stream,
|
Ok(stream) => stream,
|
||||||
Err(err) => return Err(FileTransferError::new_ex(FileTransferErrorType::ConnectionError, format!("{}", err))),
|
Err(err) => {
|
||||||
|
return Err(FileTransferError::new_ex(
|
||||||
|
FileTransferErrorType::ConnectionError,
|
||||||
|
format!("{}", err),
|
||||||
|
))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 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 mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||||
let ctx = ctx.build();
|
let ctx = ctx.build();
|
||||||
if let Err(err) = stream.into_secure(ctx) {
|
if let Err(err) = stream.into_secure(ctx) {
|
||||||
return Err(FileTransferError::new_ex(FileTransferErrorType::SslError, 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(username.as_str(), match password {
|
if let Err(err) = stream.login(
|
||||||
Some(pwd) => pwd.as_ref(),
|
username.as_str(),
|
||||||
None => ""
|
match password {
|
||||||
}) {
|
Some(pwd) => pwd.as_ref(),
|
||||||
return Err(FileTransferError::new_ex(FileTransferErrorType::AuthenticationFailed, format!("{}", err)))
|
None => "",
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
return Err(FileTransferError::new_ex(
|
||||||
|
FileTransferErrorType::AuthenticationFailed,
|
||||||
|
format!("{}", err),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set stream
|
// Set stream
|
||||||
@@ -111,9 +276,14 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => match stream.quit() {
|
Some(stream) => match stream.quit() {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(FileTransferError::new_ex(FileTransferErrorType::ConnectionError, format!("{}", err)))
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
|
FileTransferErrorType::ConnectionError,
|
||||||
|
format!("{}", err),
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,9 +305,14 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
match self.stream {
|
match 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(FileTransferErrorType::ConnectionError, format!("{}", err)))
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
|
FileTransferErrorType::ConnectionError,
|
||||||
|
format!("{}", err),
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,9 +324,14 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => match stream.cwd(&dir.as_os_str().to_string_lossy()) {
|
Some(stream) => match stream.cwd(&dir.as_os_str().to_string_lossy()) {
|
||||||
Ok(_) => Ok(PathBuf::from(dir)),
|
Ok(_) => Ok(PathBuf::from(dir)),
|
||||||
Err(err) => Err(FileTransferError::new_ex(FileTransferErrorType::ConnectionError, format!("{}", err))),
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
}
|
FileTransferErrorType::ConnectionError,
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
format!("{}", err),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,11 +340,6 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// List directory entries
|
/// List directory entries
|
||||||
|
|
||||||
fn list_dir(&self, path: &Path) -> Result<Vec<FsEntry>, FileTransferError> {
|
fn list_dir(&self, path: &Path) -> Result<Vec<FsEntry>, FileTransferError> {
|
||||||
// Prepare list regex
|
|
||||||
// NOTE: about this damn regex <https://stackoverflow.com/questions/32480890/is-there-a-regex-to-parse-the-values-from-an-ftp-directory-listing>
|
|
||||||
lazy_static! {
|
|
||||||
static ref LS_RE: Regex = Regex::new(r#"^([\-ld])([\-rwxs]{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+(\w{3}\s+\d{1,2}\s+(?:\d{1,2}:\d{1,2}|\d{4}))\s+(.+)$"#).unwrap();
|
|
||||||
}
|
|
||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => match stream.list(Some(&path.as_os_str().to_string_lossy())) {
|
Some(stream) => match stream.list(Some(&path.as_os_str().to_string_lossy())) {
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
@@ -172,138 +347,20 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
let mut result: Vec<FsEntry> = Vec::with_capacity(entries.len());
|
let mut result: Vec<FsEntry> = Vec::with_capacity(entries.len());
|
||||||
// Iterate over entries
|
// Iterate over entries
|
||||||
for entry in entries.iter() {
|
for entry in entries.iter() {
|
||||||
// Apply regex to result
|
if let Ok(file) = self.parse_list_line(path, entry) {
|
||||||
if let Some(metadata) = LS_RE.captures(entry) { // String matches regex
|
result.push(file);
|
||||||
// NOTE: metadata fmt: (regex, file_type, permissions, link_count, uid, gid, filesize, mtime, filename)
|
|
||||||
// Expected 7 + 1 (8) values: + 1 cause regex is repeated at 0
|
|
||||||
if metadata.len() < 8 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Collect metadata
|
|
||||||
// Get if is directory and if is symlink
|
|
||||||
let (is_dir, is_symlink): (bool, bool) = match metadata.get(1).unwrap().as_str() {
|
|
||||||
"-" => (false, false),
|
|
||||||
"l" => (false, true),
|
|
||||||
"d" => (true, false),
|
|
||||||
_ => continue, // Ignore special files
|
|
||||||
};
|
|
||||||
// Check string length (unix pex)
|
|
||||||
if metadata.get(2).unwrap().as_str().len() < 9 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Get unix pex
|
|
||||||
let unix_pex: (u8, u8, u8) = {
|
|
||||||
let owner_pex: u8 = {
|
|
||||||
let mut count: u8 = 0;
|
|
||||||
for (i, c) in metadata.get(2).unwrap().as_str()[0..3].chars().enumerate() {
|
|
||||||
match c {
|
|
||||||
'-' => {},
|
|
||||||
_ => count = count + match i {
|
|
||||||
0 => 4,
|
|
||||||
1 => 2,
|
|
||||||
2 => 1,
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count
|
|
||||||
};
|
|
||||||
let group_pex: u8 = {
|
|
||||||
let mut count: u8 = 0;
|
|
||||||
for (i, c) in metadata.get(2).unwrap().as_str()[3..6].chars().enumerate() {
|
|
||||||
match c {
|
|
||||||
'-' => {},
|
|
||||||
_ => count = count + match i {
|
|
||||||
0 => 4,
|
|
||||||
1 => 2,
|
|
||||||
2 => 1,
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count
|
|
||||||
};
|
|
||||||
let others_pex: u8 = {
|
|
||||||
let mut count: u8 = 0;
|
|
||||||
for (i, c) in metadata.get(2).unwrap().as_str()[6..9].chars().enumerate() {
|
|
||||||
match c {
|
|
||||||
'-' => {},
|
|
||||||
_ => count = count + match i {
|
|
||||||
0 => 4,
|
|
||||||
1 => 2,
|
|
||||||
2 => 1,
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count
|
|
||||||
};
|
|
||||||
(owner_pex, group_pex, others_pex)
|
|
||||||
};
|
|
||||||
// Parse mtime and convert to SystemTime
|
|
||||||
let mtime: SystemTime = match lstime_to_systime(metadata.get(7).unwrap().as_str(), "%b %d %Y", "%b %d %H:%M") {
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(_) => continue
|
|
||||||
};
|
|
||||||
// Get uid
|
|
||||||
let uid: Option<u32> = match metadata.get(4).unwrap().as_str().parse::<u32>() {
|
|
||||||
Ok(uid) => Some(uid),
|
|
||||||
Err(_) => None
|
|
||||||
};
|
|
||||||
// Get gid
|
|
||||||
let gid: Option<u32> = match metadata.get(5).unwrap().as_str().parse::<u32>() {
|
|
||||||
Ok(gid) => Some(gid),
|
|
||||||
Err(_) => None
|
|
||||||
};
|
|
||||||
// Get filesize
|
|
||||||
let filesize: usize = match metadata.get(6).unwrap().as_str().parse::<usize>() {
|
|
||||||
Ok(sz) => sz,
|
|
||||||
Err(_) => continue
|
|
||||||
};
|
|
||||||
let file_name: String = String::from(metadata.get(8).unwrap().as_str());
|
|
||||||
let mut abs_path: PathBuf = PathBuf::from(path);
|
|
||||||
let extension: Option<String> = match abs_path.as_path().extension() {
|
|
||||||
None => None,
|
|
||||||
Some(s) => Some(String::from(s.to_string_lossy()))
|
|
||||||
};
|
|
||||||
abs_path.push(file_name.as_str());
|
|
||||||
// Return
|
|
||||||
// Push to entries
|
|
||||||
result.push(match is_dir {
|
|
||||||
true => FsEntry::Directory(FsDirectory {
|
|
||||||
name: file_name,
|
|
||||||
abs_path: abs_path,
|
|
||||||
last_change_time: mtime,
|
|
||||||
last_access_time: mtime,
|
|
||||||
creation_time: mtime,
|
|
||||||
readonly: false,
|
|
||||||
symlink: None,
|
|
||||||
user: uid,
|
|
||||||
group: gid,
|
|
||||||
unix_pex: Some(unix_pex),
|
|
||||||
}),
|
|
||||||
false => FsEntry::File(FsFile {
|
|
||||||
name: file_name,
|
|
||||||
abs_path: abs_path,
|
|
||||||
last_change_time: mtime,
|
|
||||||
last_access_time: mtime,
|
|
||||||
creation_time: mtime,
|
|
||||||
size: filesize,
|
|
||||||
ftype: extension,
|
|
||||||
readonly: false,
|
|
||||||
symlink: None,
|
|
||||||
user: uid,
|
|
||||||
group: gid,
|
|
||||||
unix_pex: Some(unix_pex),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
Err(err) => Err(FileTransferError::new_ex(FileTransferErrorType::DirStatFailed, format!("{}", err))),
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
}
|
FileTransferErrorType::DirStatFailed,
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
format!("{}", err),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,8 +369,10 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// Make directory
|
/// Make directory
|
||||||
fn mkdir(&self, dir: &Path) -> Result<(), FileTransferError> {
|
fn mkdir(&self, dir: &Path) -> Result<(), FileTransferError> {
|
||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => {},
|
Some(stream) => {}
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,8 +381,10 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// 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.stream {
|
match self.stream {
|
||||||
Some(stream) => {},
|
Some(stream) => {}
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,8 +393,10 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// 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.stream {
|
match self.stream {
|
||||||
Some(stream) => {},
|
Some(stream) => {}
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,8 +405,12 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// 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> {
|
||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => Err(FileTransferError::new(FileTransferErrorType::UnsupportedFeature)),
|
Some(stream) => Err(FileTransferError::new(
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
FileTransferErrorType::UnsupportedFeature,
|
||||||
|
)),
|
||||||
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +422,10 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// 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(&self, file_name: &Path) -> Result<Box<dyn Write>, FileTransferError> {
|
||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => {},
|
Some(stream) => {}
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,9 +435,10 @@ impl FileTransfer for FtpFileTransfer {
|
|||||||
/// 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(&self, file_name: &Path) -> Result<(Box<dyn Read>, usize), FileTransferError> {
|
||||||
match self.stream {
|
match self.stream {
|
||||||
Some(stream) => {},
|
Some(stream) => {}
|
||||||
None => Err(FileTransferError::new(FileTransferErrorType::UninitializedSession))
|
None => Err(FileTransferError::new(
|
||||||
|
FileTransferErrorType::UninitializedSession,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user