diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index c533eba..78709ec 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -503,7 +503,11 @@ impl FileTransfer for FtpFileTransfer { /// File name is referred to the name of the file as it will be saved /// Data contains the file data /// Returns file and its size - fn send_file(&mut self, file_name: &Path) -> Result, FileTransferError> { + fn send_file( + &mut self, + _local: &FsFile, + file_name: &Path, + ) -> Result, FileTransferError> { match &mut self.stream { Some(stream) => match stream.put_with_stream(&file_name.to_string_lossy()) { Ok(writer) => Ok(Box::new(writer)), @@ -522,9 +526,9 @@ impl FileTransfer for FtpFileTransfer { /// /// Receive file from remote with provided name /// Returns file and its size - fn recv_file(&mut self, file_name: &Path) -> Result, FileTransferError> { + fn recv_file(&mut self, file: &FsFile) -> Result, FileTransferError> { match &mut self.stream { - Some(stream) => match stream.get(&file_name.to_string_lossy()) { + Some(stream) => match stream.get(&file.abs_path.as_path().to_string_lossy()) { Ok(reader) => Ok(Box::new(reader)), Err(err) => Err(FileTransferError::new_ex( FileTransferErrorType::NoSuchFileOrDirectory, diff --git a/src/filetransfer/mod.rs b/src/filetransfer/mod.rs index b25366c..9aa496e 100644 --- a/src/filetransfer/mod.rs +++ b/src/filetransfer/mod.rs @@ -26,7 +26,7 @@ use std::io::{Read, Write}; use std::path::{Path, PathBuf}; -use crate::fs::FsEntry; +use crate::fs::{FsFile, FsEntry}; // Transfers pub mod ftp_transfer; @@ -167,6 +167,7 @@ pub trait FileTransfer { /// ### mkdir /// /// Make directory + /// You must return error in case the directory already exists fn mkdir(&mut self, dir: &Path) -> Result<(), FileTransferError>; /// ### remove @@ -190,13 +191,13 @@ pub trait FileTransfer { /// File name is referred to the name of the file as it will be saved /// Data contains the file data /// Returns file and its size - fn send_file(&mut self, file_name: &Path) -> Result, FileTransferError>; + fn send_file(&mut self, local: &FsFile, file_name: &Path) -> Result, FileTransferError>; /// ### recv_file /// /// Receive file from remote with provided name /// Returns file and its size - fn recv_file(&mut self, file_name: &Path) -> Result, FileTransferError>; + fn recv_file(&mut self, file: &FsFile) -> Result, FileTransferError>; /// ### on_sent /// diff --git a/src/filetransfer/sftp_transfer.rs b/src/filetransfer/sftp_transfer.rs index 764e2fa..66b3217 100644 --- a/src/filetransfer/sftp_transfer.rs +++ b/src/filetransfer/sftp_transfer.rs @@ -31,7 +31,7 @@ use super::{FileTransfer, FileTransferError, FileTransferErrorType}; use crate::fs::{FsDirectory, FsEntry, FsFile}; // Includes -use ssh2::{FileStat, Session, Sftp}; +use ssh2::{FileStat, OpenFlags, OpenType, Session, Sftp}; use std::io::{Read, Write}; use std::net::TcpStream; use std::path::{Path, PathBuf}; @@ -493,14 +493,28 @@ impl FileTransfer for SftpFileTransfer { /// Send file to remote /// File name is referred to the name of the file as it will be saved /// Data contains the file data - fn send_file(&mut self, file_name: &Path) -> Result, FileTransferError> { + fn send_file( + &mut self, + local: &FsFile, + file_name: &Path, + ) -> Result, FileTransferError> { match self.sftp.as_ref() { None => Err(FileTransferError::new( FileTransferErrorType::UninitializedSession, )), Some(sftp) => { let remote_path: PathBuf = self.get_abs_path(file_name); - match sftp.create(remote_path.as_path()) { + // Calculate file mode + let mode: i32 = match local.unix_pex { + None => 0o644, + Some((u, g, o)) => ((u as i32) << 6) + ((g as i32) << 3) + (o as i32), + }; + match sftp.open_mode( + remote_path.as_path(), + OpenFlags::WRITE | OpenFlags::CREATE | OpenFlags::APPEND | OpenFlags::TRUNCATE, + mode, + OpenType::File, + ) { Ok(file) => Ok(Box::new(file)), Err(err) => Err(FileTransferError::new_ex( FileTransferErrorType::FileCreateDenied, @@ -514,14 +528,14 @@ impl FileTransfer for SftpFileTransfer { /// ### recv_file /// /// Receive file from remote with provided name - fn recv_file(&mut self, file_name: &Path) -> Result, FileTransferError> { + fn recv_file(&mut self, file: &FsFile) -> Result, FileTransferError> { match self.sftp.as_ref() { None => Err(FileTransferError::new( FileTransferErrorType::UninitializedSession, )), Some(sftp) => { // 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.abs_path.as_path()) { Ok(p) => p, Err(err) => return Err(err), }; @@ -763,10 +777,22 @@ mod tests { assert!(client.session.is_some()); assert!(client.sftp.is_some()); assert_eq!(client.wrkdir, PathBuf::from("/")); + let file: FsFile = FsFile { + name: String::from("readme.txt"), + abs_path: PathBuf::from("/readme.txt"), + last_change_time: SystemTime::UNIX_EPOCH, + last_access_time: SystemTime::UNIX_EPOCH, + creation_time: SystemTime::UNIX_EPOCH, + size: 0, + ftype: Some(String::from("txt")), // File type + readonly: true, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((6, 4, 4)), // UNIX only + }; // Receive file - assert!(client - .recv_file(PathBuf::from("readme.txt").as_path()) - .is_ok()); + assert!(client.recv_file(&file).is_ok()); // Disconnect assert!(client.disconnect().is_ok()); } @@ -786,9 +812,21 @@ mod tests { assert!(client.sftp.is_some()); assert_eq!(client.wrkdir, PathBuf::from("/")); // Receive file - assert!(client - .recv_file(PathBuf::from("omar.txt").as_path()) - .is_err()); + let file: FsFile = FsFile { + name: String::from("omar.txt"), + abs_path: PathBuf::from("/omar.txt"), + last_change_time: SystemTime::UNIX_EPOCH, + last_access_time: SystemTime::UNIX_EPOCH, + creation_time: SystemTime::UNIX_EPOCH, + size: 0, + ftype: Some(String::from("txt")), // File type + readonly: true, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((6, 4, 4)), // UNIX only + }; + assert!(client.recv_file(&file).is_err()); // Disconnect assert!(client.disconnect().is_ok()); } diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index be9494b..baa6be2 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -124,7 +124,7 @@ impl FileTransferActivity { .local .open_file_read(file.abs_path.as_path()) { - Ok(mut fhnd) => match self.client.send_file(remote_path.as_path()) { + Ok(mut fhnd) => match self.client.send_file(file, remote_path.as_path()) { Ok(mut rhnd) => { // Write file let file_size: usize = @@ -317,7 +317,7 @@ impl FileTransferActivity { { Ok(mut local_file) => { // Download file from remote - match self.client.recv_file(file.abs_path.as_path()) { + match self.client.recv_file(file) { Ok(mut rhnd) => { // Set popup progress self.input_mode = InputMode::Popup(PopupType::Progress(format!(