Fix remote paths for Windows

This commit is contained in:
veeso
2021-04-02 22:09:58 +02:00
parent d48e05cd74
commit b610da16a9
5 changed files with 72 additions and 11 deletions

View File

@@ -21,6 +21,9 @@ Released on FIXME:
- Bugfix:
- [Issue 10](https://github.com/veeso/termscp/issues/10): Fixed port not being loaded from bookmarks into gui
- [Issue 9](https://github.com/veeso/termscp/issues/9): Fixed issues related to paths on remote when using Windows
- Dependencies:
- Added `path-slash 0.1.4` (Windows only)
## 0.4.0

7
Cargo.lock generated
View File

@@ -930,6 +930,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "path-slash"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cacbb3c4ff353b534a67fb8d7524d00229da4cb1dc8c79f4db96e375ab5b619"
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -1397,6 +1403,7 @@ dependencies = [
"keyring",
"lazy_static",
"magic-crypt",
"path-slash",
"rand 0.8.2",
"regex",
"rpassword",

View File

@@ -41,12 +41,18 @@ ureq = { version = "2.0.2", features = ["json"] }
whoami = "1.1.0"
wildmatch = "1.0.13"
# POSIX dependencies
[target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies]
users = "0.11.0"
# Windows + MacOS
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
keyring = "0.10.1"
# Windows dependencies
[target.'cfg(target_os = "windows")'.dependencies]
path-slash = "0.1.4"
# Features
[features]
githubActions = [] # used to run particular on github actions

View File

@@ -28,6 +28,8 @@
// Dependencies
extern crate chrono;
extern crate ftp4;
#[cfg(os_target = "windows")]
extern crate path_slash;
extern crate regex;
use super::{FileTransfer, FileTransferError, FileTransferErrorType};
@@ -61,6 +63,20 @@ impl FtpFileTransfer {
FtpFileTransfer { stream: None, ftps }
}
/// ### resolve
///
/// Fix provided path; on Windows fixes the backslashes, converting them to slashes
/// While on POSIX does nothing
#[cfg(target_os = "windows")]
fn resolve(p: &Path) -> PathBuf {
PathBuf::from(path_slash::PathExt::to_slash_lossy(p).as_str())
}
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
fn resolve(p: &Path) -> PathBuf {
p.to_path_buf()
}
/// ### parse_list_line
///
/// Parse a line of LIST command output and instantiates an FsEntry from it
@@ -165,6 +181,7 @@ impl FtpFileTransfer {
}
let mut abs_path: PathBuf = PathBuf::from(path);
abs_path.push(file_name.as_str());
let abs_path: PathBuf = Self::resolve(abs_path.as_path());
// get extension
let extension: Option<String> = abs_path
.as_path()
@@ -253,6 +270,7 @@ impl FtpFileTransfer {
// Get absolute path
let mut abs_path: PathBuf = PathBuf::from(path);
abs_path.push(file_name.as_str());
let abs_path: PathBuf = Self::resolve(abs_path.as_path());
// Get extension
let extension: Option<String> = abs_path
.as_path()
@@ -411,9 +429,10 @@ impl FileTransfer for FtpFileTransfer {
/// Change working directory
fn change_dir(&mut self, dir: &Path) -> Result<PathBuf, FileTransferError> {
let dir: PathBuf = Self::resolve(dir);
match &mut self.stream {
Some(stream) => match stream.cwd(&dir.to_string_lossy()) {
Ok(_) => Ok(PathBuf::from(dir)),
Some(stream) => match stream.cwd(&dir.as_path().to_string_lossy()) {
Ok(_) => Ok(dir),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::ConnectionError,
format!("{}", err),
@@ -440,14 +459,15 @@ impl FileTransfer for FtpFileTransfer {
/// List directory entries
fn list_dir(&mut self, path: &Path) -> Result<Vec<FsEntry>, FileTransferError> {
let dir: PathBuf = Self::resolve(path);
match &mut self.stream {
Some(stream) => match stream.list(Some(&path.to_string_lossy())) {
Some(stream) => match stream.list(Some(&dir.as_path().to_string_lossy())) {
Ok(entries) => {
// Prepare result
let mut result: Vec<FsEntry> = Vec::with_capacity(entries.len());
// Iterate over entries
for entry in entries.iter() {
if let Ok(file) = self.parse_list_line(path, entry) {
if let Ok(file) = self.parse_list_line(dir.as_path(), entry) {
result.push(file);
}
}
@@ -468,8 +488,9 @@ impl FileTransfer for FtpFileTransfer {
///
/// Make directory
fn mkdir(&mut self, dir: &Path) -> Result<(), FileTransferError> {
let dir: PathBuf = Self::resolve(dir);
match &mut self.stream {
Some(stream) => match stream.mkdir(&dir.to_string_lossy()) {
Some(stream) => match stream.mkdir(&dir.as_path().to_string_lossy()) {
Ok(_) => Ok(()),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::FileCreateDenied,
@@ -538,6 +559,7 @@ impl FileTransfer for FtpFileTransfer {
///
/// Rename file or a directory
fn rename(&mut self, file: &FsEntry, dst: &Path) -> Result<(), FileTransferError> {
let dst: PathBuf = Self::resolve(dst);
match &mut self.stream {
Some(stream) => {
// Get name
@@ -603,8 +625,9 @@ impl FileTransfer for FtpFileTransfer {
_local: &FsFile,
file_name: &Path,
) -> Result<Box<dyn Write>, FileTransferError> {
let file_name: PathBuf = Self::resolve(file_name);
match &mut self.stream {
Some(stream) => match stream.put_with_stream(&file_name.to_string_lossy()) {
Some(stream) => match stream.put_with_stream(&file_name.as_path().to_string_lossy()) {
Ok(writer) => Ok(Box::new(writer)), // NOTE: don't use BufWriter here, since already returned by the library
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::FileCreateDenied,

View File

@@ -26,6 +26,8 @@
* SOFTWARE.
*/
// Dependencies
#[cfg(os_target = "windows")]
extern crate path_slash;
extern crate regex;
extern crate ssh2;
@@ -65,6 +67,20 @@ impl ScpFileTransfer {
}
}
/// ### resolve
///
/// Fix provided path; on Windows fixes the backslashes, converting them to slashes
/// While on POSIX does nothing
#[cfg(target_os = "windows")]
fn resolve(p: &Path) -> PathBuf {
PathBuf::from(path_slash::PathExt::to_slash_lossy(p).as_str())
}
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
fn resolve(p: &Path) -> PathBuf {
p.to_path_buf()
}
/// ### parse_ls_output
///
/// Parse a line of `ls -l` output and tokenize the output into a `FsEntry`
@@ -174,6 +190,7 @@ impl ScpFileTransfer {
}
let mut abs_path: PathBuf = PathBuf::from(path);
abs_path.push(file_name.as_str());
let abs_path: PathBuf = Self::resolve(abs_path.as_path());
// Get extension
let extension: Option<String> = abs_path
.as_path()
@@ -448,7 +465,7 @@ impl FileTransfer for ScpFileTransfer {
false => {
let mut p: PathBuf = PathBuf::from(".");
p.push(dir);
p
Self::resolve(p.as_path())
}
};
// Change directory
@@ -491,6 +508,7 @@ impl FileTransfer for ScpFileTransfer {
fn copy(&mut self, src: &FsEntry, dst: &Path) -> Result<(), FileTransferError> {
match self.is_connected() {
true => {
let dst: PathBuf = Self::resolve(dst);
// Run `cp -rf`
let p: PathBuf = self.wrkdir.clone();
match self.perform_shell_cmd_with_path(
@@ -534,6 +552,7 @@ impl FileTransfer for ScpFileTransfer {
match self.is_connected() {
true => {
// Send ls -l to path
let path: PathBuf = Self::resolve(path);
let p: PathBuf = self.wrkdir.clone();
match self.perform_shell_cmd_with_path(
p.as_path(),
@@ -546,7 +565,7 @@ impl FileTransfer for ScpFileTransfer {
for line in lines.iter() {
// First line must always be ignored
// Parse row, if ok push to entries
if let Ok(entry) = self.parse_ls_output(path, line) {
if let Ok(entry) = self.parse_ls_output(path.as_path(), line) {
entries.push(entry);
}
}
@@ -571,6 +590,7 @@ impl FileTransfer for ScpFileTransfer {
fn mkdir(&mut self, dir: &Path) -> Result<(), FileTransferError> {
match self.is_connected() {
true => {
let dir: PathBuf = Self::resolve(dir);
let p: PathBuf = self.wrkdir.clone();
// Mkdir dir && echo 0
match self.perform_shell_cmd_with_path(
@@ -644,6 +664,7 @@ impl FileTransfer for ScpFileTransfer {
match self.is_connected() {
true => {
// Get path
let dst: PathBuf = Self::resolve(dst);
let path: PathBuf = file.get_abs_path();
let p: PathBuf = self.wrkdir.clone();
match self.perform_shell_cmd_with_path(
@@ -693,7 +714,7 @@ impl FileTransfer for ScpFileTransfer {
false => {
let mut p: PathBuf = self.wrkdir.clone();
p.push(path);
p
Self::resolve(p.as_path())
}
};
match self.is_connected() {
@@ -767,6 +788,7 @@ impl FileTransfer for ScpFileTransfer {
) -> Result<Box<dyn Write>, FileTransferError> {
match self.session.as_ref() {
Some(session) => {
let file_name: PathBuf = Self::resolve(file_name);
// Set blocking to true
session.set_blocking(true);
// Calculate file mode
@@ -798,7 +820,7 @@ impl FileTransfer for ScpFileTransfer {
Err(_) => local.size as u64, // NOTE: fallback to fsentry size
};
// Send file
match session.scp_send(file_name, mode, file_size, Some(times)) {
match session.scp_send(file_name.as_path(), mode, file_size, Some(times)) {
Ok(channel) => Ok(Box::new(BufWriter::with_capacity(65536, channel))),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
@@ -1053,7 +1075,7 @@ mod tests {
}
#[test]
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
//#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
fn test_filetransfer_scp_find() {
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());
assert!(client