Apply file mode of file downloaded from remote

This commit is contained in:
ChristianVisintin 2020-12-18 11:31:51 +01:00
parent 50b523f9f4
commit 900d9ac3c6
3 changed files with 98 additions and 2 deletions

View file

@ -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

View file

@ -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

View file

@ -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(),