mirror of
https://github.com/nushell/nushell
synced 2024-11-10 07:04:13 +00:00
fix: fixcd (#6799)
* fix: fixcd try to fix Log: try to fix the bug with can enter a permisson error fold * change wording * fat * fmt Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
This commit is contained in:
parent
bb968304da
commit
b9195c2668
4 changed files with 140 additions and 5 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -1974,9 +1974,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.134"
|
||||
version = "0.2.135"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
|
||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
|
@ -2583,6 +2583,7 @@ dependencies = [
|
|||
"is-root",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"lscolors",
|
||||
"md-5",
|
||||
|
|
|
@ -98,6 +98,7 @@ winreg = "0.10.1"
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
umask = "2.0.0"
|
||||
users = "0.11.0"
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
||||
version = "2.1.3"
|
||||
|
|
|
@ -6,6 +6,29 @@ use nu_protocol::engine::{Command, EngineState, Stack};
|
|||
use nu_protocol::{
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
// when the file under the fold executeable
|
||||
#[cfg(unix)]
|
||||
mod permission_mods {
|
||||
pub type Mode = u32;
|
||||
pub mod unix {
|
||||
use super::Mode;
|
||||
pub const USER_EXECUTE: Mode = libc::S_IXUSR as Mode;
|
||||
pub const GROUP_EXECUTE: Mode = libc::S_IXGRP as Mode;
|
||||
pub const OTHER_EXECUTE: Mode = libc::S_IXOTH as Mode;
|
||||
}
|
||||
}
|
||||
|
||||
// use to return the message of the result of change director
|
||||
// TODO: windows, maybe should use file_attributes function in https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html
|
||||
// TODO: the meaning of the result of the function can be found in https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
|
||||
// TODO: if have realize the logic on windows, remove the cfg
|
||||
#[derive(Debug)]
|
||||
enum PermissionResult<'a> {
|
||||
PermissionOk,
|
||||
PermissionDenied(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cd;
|
||||
|
@ -141,6 +164,7 @@ impl Command for Cd {
|
|||
}
|
||||
};
|
||||
|
||||
let path_tointo = path.clone();
|
||||
let path_value = Value::String { val: path, span };
|
||||
let cwd = Value::String {
|
||||
val: cwd.to_string_lossy().to_string(),
|
||||
|
@ -172,9 +196,16 @@ impl Command for Cd {
|
|||
|
||||
//FIXME: this only changes the current scope, but instead this environment variable
|
||||
//should probably be a block that loads the information from the state in the overlay
|
||||
|
||||
stack.add_env_var("PWD".into(), path_value);
|
||||
Ok(PipelineData::new(call.head))
|
||||
match have_permission(&path_tointo) {
|
||||
PermissionResult::PermissionOk => {
|
||||
stack.add_env_var("PWD".into(), path_value);
|
||||
Ok(PipelineData::new(call.head))
|
||||
}
|
||||
PermissionResult::PermissionDenied(reason) => Err(ShellError::IOError(format!(
|
||||
"Cannot change directory to {}: {}",
|
||||
path_tointo, reason
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -197,3 +228,65 @@ impl Command for Cd {
|
|||
]
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn have_permission(dir: impl AsRef<Path>) -> PermissionResult<'static> {
|
||||
match dir.as_ref().read_dir() {
|
||||
Err(e) => {
|
||||
if matches!(e.kind(), std::io::ErrorKind::PermissionDenied) {
|
||||
PermissionResult::PermissionDenied("Folder is unable to be read")
|
||||
} else {
|
||||
PermissionResult::PermissionOk
|
||||
}
|
||||
}
|
||||
Ok(_) => PermissionResult::PermissionOk,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn have_permission(dir: impl AsRef<Path>) -> PermissionResult<'static> {
|
||||
match dir.as_ref().metadata() {
|
||||
Ok(metadata) => {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
let bits = metadata.mode();
|
||||
let has_bit = |bit| bits & bit == bit;
|
||||
let current_user = users::get_current_uid();
|
||||
if current_user == 0 {
|
||||
return PermissionResult::PermissionOk;
|
||||
}
|
||||
let current_group = users::get_current_gid();
|
||||
let owner_user = metadata.uid();
|
||||
let owner_group = metadata.gid();
|
||||
match (current_user == owner_user, current_group == owner_group) {
|
||||
(true, _) => {
|
||||
if has_bit(permission_mods::unix::USER_EXECUTE) {
|
||||
PermissionResult::PermissionOk
|
||||
} else {
|
||||
PermissionResult::PermissionDenied(
|
||||
"You are the owner but do not have the execute permission",
|
||||
)
|
||||
}
|
||||
}
|
||||
(false, true) => {
|
||||
if has_bit(permission_mods::unix::GROUP_EXECUTE) {
|
||||
PermissionResult::PermissionOk
|
||||
} else {
|
||||
PermissionResult::PermissionDenied(
|
||||
"You are in the group but do not have the execute permission",
|
||||
)
|
||||
}
|
||||
}
|
||||
// other_user or root
|
||||
(false, false) => {
|
||||
if has_bit(permission_mods::unix::OTHER_EXECUTE) {
|
||||
PermissionResult::PermissionOk
|
||||
} else {
|
||||
PermissionResult::PermissionDenied(
|
||||
"You are neither the owner, in the group, nor the super user and do not have permission",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => PermissionResult::PermissionDenied("Could not retrieve the metadata"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,3 +289,43 @@ fn test_change_windows_drive() {
|
|||
.exists());
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn cd_permission_deined_folder() {
|
||||
Playground::setup("cd_test_21", |dirs, sandbox| {
|
||||
sandbox.mkdir("banned");
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
r#"
|
||||
chmod -x banned
|
||||
cd banned
|
||||
"#
|
||||
);
|
||||
assert!(actual.err.contains("Cannot change directory to"));
|
||||
nu!(
|
||||
cwd: dirs.test(),
|
||||
r#"
|
||||
chmod +x banned
|
||||
rm banned
|
||||
"#
|
||||
);
|
||||
});
|
||||
}
|
||||
// FIXME: cd_permission_deined_folder on windows
|
||||
#[ignore]
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn cd_permission_deined_folder() {
|
||||
Playground::setup("cd_test_21", |dirs, sandbox| {
|
||||
sandbox.mkdir("banned");
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
r#"
|
||||
icacls banned /deny BUILTIN\Administrators:F
|
||||
cd banned
|
||||
"#
|
||||
);
|
||||
assert!(actual.err.contains("Folder is not able to read"));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue