File transfer exec command

This commit is contained in:
veeso
2021-03-04 16:07:08 +01:00
parent 88a014807f
commit 51f0c56b84
4 changed files with 158 additions and 1 deletions

View File

@@ -581,6 +581,15 @@ impl FileTransfer for FtpFileTransfer {
}
}
/// ### exec
///
/// Execute a command on remote host
fn exec(&mut self, _cmd: &str) -> Result<String, FileTransferError> {
Err(FileTransferError::new(
FileTransferErrorType::UnsupportedFeature,
))
}
/// ### send_file
///
/// Send file to remote
@@ -1068,6 +1077,19 @@ mod tests {
assert!(ftp.disconnect().is_ok());
}*/
#[test]
fn test_filetransfer_ftp_exec() {
let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false);
// Connect
assert!(ftp
.connect(String::from("speedtest.tele2.net"), 21, None, None)
.is_ok());
// Pwd
assert!(ftp.exec("echo 1;").is_err());
// Disconnect
assert!(ftp.disconnect().is_ok());
}
#[test]
fn test_filetransfer_ftp_uninitialized() {
let file: FsFile = FsFile {

View File

@@ -189,6 +189,11 @@ pub trait FileTransfer {
/// Stat file and return FsEntry
fn stat(&mut self, path: &Path) -> Result<FsEntry, FileTransferError>;
/// ### exec
///
/// Execute a command on remote host
fn exec(&mut self, cmd: &str) -> Result<String, FileTransferError>;
/// ### send_file
///
/// Send file to remote

View File

@@ -737,6 +737,27 @@ impl FileTransfer for ScpFileTransfer {
}
}
/// ### exec
///
/// Execute a command on remote host
fn exec(&mut self, cmd: &str) -> Result<String, FileTransferError> {
match self.is_connected() {
true => {
let p: PathBuf = self.wrkdir.clone();
match self.perform_shell_cmd_with_path(p.as_path(), cmd) {
Ok(output) => Ok(output),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
format!("{}", err),
)),
}
}
false => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession,
)),
}
}
/// ### send_file
///
/// Send file to remote
@@ -1016,6 +1037,25 @@ mod tests {
}
}
#[test]
fn test_filetransfer_scp_exec() {
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());
assert!(client
.connect(
String::from("test.rebex.net"),
22,
Some(String::from("demo")),
Some(String::from("password"))
)
.is_ok());
// Check session and scp
assert!(client.session.is_some());
// Exec
assert_eq!(client.exec("echo 5").ok().unwrap().as_str(), "5\n");
// Disconnect
assert!(client.disconnect().is_ok());
}
#[test]
fn test_filetransfer_scp_recv() {
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());

View File

@@ -32,7 +32,7 @@ use crate::fs::{FsDirectory, FsEntry, FsFile};
use crate::system::sshkey_storage::SshKeyStorage;
// Includes
use ssh2::{FileStat, OpenFlags, OpenType, Session, Sftp};
use ssh2::{Channel, FileStat, OpenFlags, OpenType, Session, Sftp};
use std::io::{BufReader, BufWriter, Read, Write};
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
use std::path::{Path, PathBuf};
@@ -189,6 +189,57 @@ impl SftpFileTransfer {
}),
}
}
/// ### perform_shell_cmd_with
///
/// Perform a shell command, but change directory to specified path first
fn perform_shell_cmd_with_path(&mut self, cmd: &str) -> Result<String, FileTransferError> {
self.perform_shell_cmd(format!("cd \"{}\"; {}", self.wrkdir.display(), cmd).as_str())
}
/// ### perform_shell_cmd
///
/// Perform a shell command and read the output from shell
/// This operation is, obviously, blocking.
fn perform_shell_cmd(&mut self, cmd: &str) -> Result<String, FileTransferError> {
match self.session.as_mut() {
Some(session) => {
// Create channel
let mut channel: Channel = match session.channel_session() {
Ok(ch) => ch,
Err(err) => {
return Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
format!("Could not open channel: {}", err),
))
}
};
// Execute command
if let Err(err) = channel.exec(cmd) {
return Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
format!("Could not execute command \"{}\": {}", cmd, err),
));
}
// Read output
let mut output: String = String::new();
match channel.read_to_string(&mut output) {
Ok(_) => {
// Wait close
let _ = channel.wait_close();
Ok(output)
}
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
format!("Could not read output: {}", err),
)),
}
}
None => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession,
)),
}
}
}
impl FileTransfer for SftpFileTransfer {
@@ -547,6 +598,26 @@ impl FileTransfer for SftpFileTransfer {
}
}
/// ### exec
///
/// Execute a command on remote host
fn exec(&mut self, cmd: &str) -> Result<String, FileTransferError> {
match self.is_connected() {
true => {
match self.perform_shell_cmd_with_path(cmd) {
Ok(output) => Ok(output),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
format!("{}", err),
)),
}
}
false => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession,
)),
}
}
/// ### send_file
///
/// Send file to remote
@@ -856,6 +927,25 @@ mod tests {
}
}
#[test]
fn test_filetransfer_sftp_exec() {
let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty());
assert!(client
.connect(
String::from("test.rebex.net"),
22,
Some(String::from("demo")),
Some(String::from("password"))
)
.is_ok());
// Check session and scp
assert!(client.session.is_some());
// Exec
assert_eq!(client.exec("echo 5").ok().unwrap().as_str(), "5\n");
// Disconnect
assert!(client.disconnect().is_ok());
}
#[test]
fn test_filetransfer_sftp_recv() {
let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty());