From 900d9ac3c6dea748c180fee85a9a18745cc7fa6a Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 18 Dec 2020 11:31:51 +0100 Subject: [PATCH] Apply file mode of file downloaded from remote --- CHANGELOG.md | 2 + src/host/mod.rs | 50 ++++++++++++++++++- .../filetransfer_activity/session.rs | 48 ++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d4fe2..eb87c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ Released on ?? - Linux: `/home/alice/.config/termscp/bookmarks.toml` - Windows: `C:\Users\Alice\AppData\Roaming\termscp\bookmarks.toml` - MacOS: `/Users/Alice/Library/Application Support/termscp/bookmarks.toml` +- Bugfix: + - File mode of file on remote is now reported on local file after being downloaded (unix, linux, macos only) ## 0.1.3 diff --git a/src/host/mod.rs b/src/host/mod.rs index 3916a13..4dc0f59 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -23,12 +23,12 @@ * */ -use std::fs::{self, File, Metadata, OpenOptions}; +use std::fs::{self, File, Metadata, OpenOptions, set_permissions}; use std::path::{Path, PathBuf}; use std::time::SystemTime; // Metadata ext #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] -use std::os::unix::fs::MetadataExt; +use std::os::unix::fs::{MetadataExt, PermissionsExt}; // Locals use crate::fs::{FsDirectory, FsEntry, FsFile}; @@ -379,6 +379,25 @@ impl Localhost { }) } + /// ### chmod + /// + /// Change file mode to file, according to UNIX permissions + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] + pub fn chmod(&self, path: &Path, pex: (u8, u8, u8)) -> Result<(), HostError> { + // Get metadta + match fs::metadata(path) { + Ok(metadata) => { + let mut mpex = metadata.permissions(); + mpex.set_mode(self.mode_to_u32(pex)); + match set_permissions(path, mpex) { + Ok(_) => Ok(()), + Err(err) => Err(HostError::new(HostErrorType::FileNotAccessible, Some(err))), + } + } + Err(err) => Err(HostError::new(HostErrorType::FileNotAccessible, Some(err))), + } + } + /// ### open_file_read /// /// Open file for read @@ -452,6 +471,14 @@ impl Localhost { let others: u8 = (mode & 0x7) as u8; (user, group, others) } + + /// mode_to_u32 + /// + /// Convert owner,group,others to u32 + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] + fn mode_to_u32(&self, mode: (u8, u8, u8)) -> u32 { + ((mode.0 as u32) << 6) + ((mode.1 as u32) << 3) + mode.2 as u32 + } } #[cfg(test)] @@ -720,6 +747,25 @@ mod tests { .is_err()); } + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] + #[test] + fn test_host_chmod() { + let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap(); + let file: tempfile::NamedTempFile = create_sample_file(); + let host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap(); + // mode_to_u32 + assert_eq!(host.mode_to_u32((6, 4, 4)), 0o644); + assert_eq!(host.mode_to_u32((7, 7, 5)), 0o775); + // Chmod to file + assert!(host.chmod(file.path(), (7, 7, 5)).is_ok()); + // Chmod to dir + assert!(host.chmod(tmpdir.path(), (7, 5, 0)).is_ok()); + // Error + assert!(host + .chmod(Path::new("/tmp/krgiogoiegj/kwrgnoerig"), (7, 7, 7)) + .is_err()); + } + /// ### create_sample_file /// /// Create a sample file diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index aaf89ef..bf4865b 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -518,6 +518,32 @@ impl FileTransferActivity { .as_str(), ); } + // Apply file mode to file + #[cfg(any( + target_os = "unix", + target_os = "macos", + target_os = "linux" + ))] + if let Some(pex) = file.unix_pex { + if let Err(err) = self + .context + .as_ref() + .unwrap() + .local + .chmod(local_file_path.as_path(), pex) + { + self.log( + LogLevel::Error, + format!( + "Could not apply file mode {:?} to \"{}\": {}", + pex, + local_file_path.display(), + err + ) + .as_ref(), + ); + } + } // Log self.log( LogLevel::Info, @@ -588,6 +614,28 @@ impl FileTransferActivity { .mkdir_ex(local_dir_path.as_path(), true) { Ok(_) => { + // Apply file mode to directory + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] + if let Some(pex) = dir.unix_pex { + if let Err(err) = self + .context + .as_ref() + .unwrap() + .local + .chmod(local_dir_path.as_path(), pex) + { + self.log( + LogLevel::Error, + format!( + "Could not apply file mode {:?} to \"{}\": {}", + pex, + local_dir_path.display(), + err + ) + .as_ref(), + ); + } + } self.log( LogLevel::Info, format!("Created directory \"{}\"", local_dir_path.display()).as_ref(),