More robust extension checking

This commit is contained in:
Chris Denton 2024-07-18 14:35:01 +00:00 committed by Pietro Albini
parent d6c8169c18
commit c811d3126f
No known key found for this signature in database
GPG Key ID: CD76B35F7734769E
4 changed files with 27 additions and 7 deletions

View File

@ -13,7 +13,7 @@
#[macro_use] #[macro_use]
pub mod compat; pub mod compat;
mod api; pub mod api;
pub mod args; pub mod args;
pub mod c; pub mod c;

View File

@ -272,11 +272,24 @@ pub fn spawn(
None None
}; };
let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?; let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
// Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd" let has_bat_extension = |program: &[u16]| {
let is_batch_file = matches!( matches!(
program.len().checked_sub(5).and_then(|i| program.get(i..)), // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0]) program.len().checked_sub(4).and_then(|i| program.get(i..)),
); Some([46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68])
)
};
let is_batch_file = if path::is_verbatim(&program) {
has_bat_extension(&program[..program.len() - 1])
} else {
super::fill_utf16_buf(
|buffer, size| unsafe {
// resolve the path so we can test the final file name.
c::GetFullPathNameW(program.as_ptr(), size, buffer, ptr::null_mut())
},
|program| has_bat_extension(program),
)?
};
let (program, mut cmd_str) = if is_batch_file { let (program, mut cmd_str) = if is_batch_file {
( (
command_prompt()?, command_prompt()?,

View File

@ -1,5 +1,6 @@
use crate::ffi::{OsStr, OsString}; use crate::ffi::{OsStr, OsString};
use crate::path::{Path, PathBuf, Prefix}; use crate::path::{Path, PathBuf, Prefix};
use crate::sys::api::utf16;
use crate::sys::pal::{c, fill_utf16_buf, os2path, to_u16s}; use crate::sys::pal::{c, fill_utf16_buf, os2path, to_u16s};
use crate::{io, ptr}; use crate::{io, ptr};
@ -19,6 +20,10 @@ pub fn is_verbatim_sep(b: u8) -> bool {
b == b'\\' b == b'\\'
} }
pub fn is_verbatim(path: &[u16]) -> bool {
path.starts_with(utf16!(r"\\?\")) || path.starts_with(utf16!(r"\??\"))
}
/// Returns true if `path` looks like a lone filename. /// Returns true if `path` looks like a lone filename.
pub(crate) fn is_file_name(path: &OsStr) -> bool { pub(crate) fn is_file_name(path: &OsStr) -> bool {
!path.as_encoded_bytes().iter().copied().any(is_sep_byte) !path.as_encoded_bytes().iter().copied().any(is_sep_byte)

View File

@ -32,7 +32,9 @@ fn parent() {
let bat2 = String::from(bat.to_str().unwrap()); let bat2 = String::from(bat.to_str().unwrap());
bat.set_file_name("windows-bat-args3.bat"); bat.set_file_name("windows-bat-args3.bat");
let bat3 = String::from(bat.to_str().unwrap()); let bat3 = String::from(bat.to_str().unwrap());
let bat = [bat1.as_str(), bat2.as_str(), bat3.as_str()]; bat.set_file_name("windows-bat-args1.bat .. ");
let bat4 = String::from(bat.to_str().unwrap());
let bat = [bat1.as_str(), bat2.as_str(), bat3.as_str(), bat4.as_str()];
check_args(&bat, &["a", "b"]).unwrap(); check_args(&bat, &["a", "b"]).unwrap();
check_args(&bat, &["c is for cat", "d is for dog"]).unwrap(); check_args(&bat, &["c is for cat", "d is for dog"]).unwrap();