Skip to content

Commit 3ee2e6c

Browse files
authored
fix: check path is valid executable when resolving command name (#154)
1 parent 8aba89f commit 3ee2e6c

File tree

5 files changed

+47
-14
lines changed

5 files changed

+47
-14
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ sys_traits = { version = "0.1.14", optional = true, features = ["real", "winapi"
2929
which = { version = "8.0.0", default-features = false, optional = true }
3030

3131
[target.'cfg(unix)'.dependencies]
32-
nix = { version = "0.29.0", features = ["signal"], optional = true }
32+
nix = { version = "0.29.0", features = ["fs", "signal"], optional = true }
3333

3434
[target.'cfg(windows)'.dependencies]
3535
windows-sys = { version = "0.59.0", features = ["Win32_Security", "Win32_System_JobObjects", "Win32_System_Threading"], optional = true }

src/shell/command.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ async fn resolve_command<'a>(
125125
// only bother checking for a shebang when the path has a slash
126126
// in it because for global commands someone on Windows likely
127127
// won't have a script with a shebang in it on Windows
128-
if command_name.name.to_string_lossy().contains('/') {
128+
if Path::new(&command_name.name).components().count() > 1 {
129129
if let Some(shebang) = resolve_shebang(&command_path).map_err(|err| {
130130
ResolveCommandError::FailedShebang(FailedShebangError::Any(err.into()))
131131
})? {

src/shell/execute.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ fn evaluate_word_parts(
839839
}
840840
}
841841
}
842-
let is_absolute = std::path::PathBuf::from(&current_text).is_absolute();
842+
let is_absolute = Path::new(&current_text).is_absolute();
843843
let cwd = state.cwd();
844844
let pattern = if is_absolute {
845845
current_text

src/shell/types.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::ffi::OsStr;
88
use std::ffi::OsString;
99
use std::io::Read;
1010
use std::io::Write;
11+
use std::path::Path;
1112
use std::path::PathBuf;
1213
use std::rc::Rc;
1314
use std::rc::Weak;
@@ -148,11 +149,11 @@ impl ShellState {
148149
name.to_os_string()
149150
};
150151
if name == "PWD" {
151-
let cwd = PathBuf::from(value);
152+
let cwd = Path::new(value);
152153
if cwd.is_absolute() {
153154
if let Ok(cwd) = deno_path_util::fs::canonicalize_path_maybe_not_exists(
154155
&sys_traits::impls::RealSys,
155-
&cwd,
156+
cwd,
156157
) {
157158
// this will update the environment variable too
158159
self.set_cwd(cwd);

src/shell/which.rs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,12 @@ pub fn resolve_command_path(
4242
return Err(CommandPathResolutionError::CommandEmpty);
4343
}
4444

45-
// check for absolute
46-
if PathBuf::from(command_name).is_absolute() {
47-
return Ok(PathBuf::from(command_name));
45+
// check for absolute or relative path
46+
let path = Path::new(command_name);
47+
if path.is_absolute() {
48+
return Ok(path.to_path_buf());
49+
} else if path.components().count() > 1 {
50+
return Ok(base_dir.join(command_name));
4851
}
4952

5053
let result = which::WhichConfig::new_with_sys(state.clone())
@@ -95,7 +98,7 @@ impl which::sys::Sys for ShellState {
9598
fn env_windows_path_ext(&self) -> Cow<'static, [String]> {
9699
Cow::Owned(
97100
self
98-
.env_path_ext()
101+
.get_var(OsStr::new("PATHEXT"))
99102
.and_then(|pathext| {
100103
Some(
101104
pathext
@@ -141,13 +144,42 @@ impl which::sys::Sys for ShellState {
141144
Ok(Box::new(iter))
142145
}
143146

147+
#[cfg(unix)]
144148
fn is_valid_executable(
145149
&self,
146-
_path: &std::path::Path,
150+
path: &std::path::Path,
147151
) -> std::io::Result<bool> {
148-
// we've considered everything to be executable so that cross platform
149-
// shebangs work and so that people don't need to bother marking an
150-
// item as executable in git, which is annoying for Windows users
151-
Ok(true)
152+
use nix::unistd::AccessFlags;
153+
use nix::unistd::access;
154+
155+
match access(path, AccessFlags::X_OK) {
156+
Ok(()) => Ok(true),
157+
Err(nix::errno::Errno::ENOENT) => Ok(false),
158+
Err(e) => Err(std::io::Error::from_raw_os_error(e as i32)),
159+
}
160+
}
161+
162+
#[cfg(windows)]
163+
fn is_valid_executable(
164+
&self,
165+
path: &std::path::Path,
166+
) -> std::io::Result<bool> {
167+
use std::os::windows::ffi::OsStrExt;
168+
169+
let name = path
170+
.as_os_str()
171+
.encode_wide()
172+
.chain(Some(0))
173+
.collect::<Vec<u16>>();
174+
let mut bt: u32 = 0;
175+
// SAFETY: winapi call
176+
unsafe {
177+
Ok(
178+
windows_sys::Win32::Storage::FileSystem::GetBinaryTypeW(
179+
name.as_ptr(),
180+
&mut bt,
181+
) != 0,
182+
)
183+
}
152184
}
153185
}

0 commit comments

Comments
 (0)