mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Summary In https://github.com/openai/codex/pull/21584, we disabled doctests for crates that lack any doctests. We can enforce that property via `cargo shear --deny-warnings`: crates that lack doctests will be flagged if doctests are enabled, and crates with doctests will be flagged if doctests are disabled. A few additional notes: - By adding `--deny-warnings`, `cargo shear` also flagged a number of modules that were not reachable at all. Some of those have been removed. - This PR removes a usage of `windows_modules!` (since `cargo shear` and `rustfmt` couldn't see through it) in favor of simple `#[cfg(target_os = "windows")]` macros. As a consequence, many of these files exhibit churn in this PR, since they weren't being formatted by `rustfmt` at all on main. - Again, to make the code more analyzable, this PR also removes some usages of `#[path = "cwd_junction.rs"]` in favor of a more standard module structure. The bin sidecar structure is still retained, but, e.g., `windows-sandbox-rs/src/bin/command_runner.rs` was moved to `windows-sandbox-rs/src/bin/command_runner/main.rs`, and so on. --------- Co-authored-by: Codex <noreply@openai.com>
242 lines
7.8 KiB
Rust
242 lines
7.8 KiB
Rust
use anyhow::Result;
|
|
use std::ffi::OsStr;
|
|
use std::os::windows::ffi::OsStrExt;
|
|
use windows_sys::Win32::Foundation::ERROR_INSUFFICIENT_BUFFER;
|
|
use windows_sys::Win32::Foundation::GetLastError;
|
|
use windows_sys::Win32::Foundation::HLOCAL;
|
|
use windows_sys::Win32::Foundation::LocalFree;
|
|
use windows_sys::Win32::Security::Authorization::ConvertSidToStringSidW;
|
|
use windows_sys::Win32::Security::Authorization::ConvertStringSidToSidW;
|
|
use windows_sys::Win32::Security::CopySid;
|
|
use windows_sys::Win32::Security::GetLengthSid;
|
|
use windows_sys::Win32::Security::LookupAccountNameW;
|
|
use windows_sys::Win32::Security::SID_NAME_USE;
|
|
use windows_sys::Win32::System::Diagnostics::Debug::FORMAT_MESSAGE_ALLOCATE_BUFFER;
|
|
use windows_sys::Win32::System::Diagnostics::Debug::FORMAT_MESSAGE_FROM_SYSTEM;
|
|
use windows_sys::Win32::System::Diagnostics::Debug::FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
use windows_sys::Win32::System::Diagnostics::Debug::FormatMessageW;
|
|
|
|
pub fn to_wide<S: AsRef<OsStr>>(s: S) -> Vec<u16> {
|
|
let mut v: Vec<u16> = s.as_ref().encode_wide().collect();
|
|
v.push(0);
|
|
v
|
|
}
|
|
|
|
/// Quote a single Windows command-line argument following the rules used by
|
|
/// CommandLineToArgvW/CRT so that spaces, quotes, and backslashes are preserved.
|
|
/// Reference behavior matches Rust std::process::Command on Windows.
|
|
#[cfg(target_os = "windows")]
|
|
pub fn quote_windows_arg(arg: &str) -> String {
|
|
let needs_quotes = arg.is_empty()
|
|
|| arg
|
|
.chars()
|
|
.any(|c| matches!(c, ' ' | '\t' | '\n' | '\r' | '"'));
|
|
if !needs_quotes {
|
|
return arg.to_string();
|
|
}
|
|
|
|
let mut quoted = String::with_capacity(arg.len() + 2);
|
|
quoted.push('"');
|
|
let mut backslashes = 0;
|
|
for ch in arg.chars() {
|
|
match ch {
|
|
'\\' => {
|
|
backslashes += 1;
|
|
}
|
|
'"' => {
|
|
quoted.push_str(&"\\".repeat(backslashes * 2 + 1));
|
|
quoted.push('"');
|
|
backslashes = 0;
|
|
}
|
|
_ => {
|
|
if backslashes > 0 {
|
|
quoted.push_str(&"\\".repeat(backslashes));
|
|
backslashes = 0;
|
|
}
|
|
quoted.push(ch);
|
|
}
|
|
}
|
|
}
|
|
if backslashes > 0 {
|
|
quoted.push_str(&"\\".repeat(backslashes * 2));
|
|
}
|
|
quoted.push('"');
|
|
quoted
|
|
}
|
|
|
|
/// Build a Windows command line for CreateProcess-style APIs.
|
|
#[cfg(target_os = "windows")]
|
|
pub fn argv_to_command_line(argv: &[String]) -> String {
|
|
argv.iter()
|
|
.map(|arg| quote_windows_arg(arg))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
}
|
|
|
|
// Produce a readable description for a Win32 error code.
|
|
pub fn format_last_error(err: i32) -> String {
|
|
unsafe {
|
|
let mut buf_ptr: *mut u16 = std::ptr::null_mut();
|
|
let flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_FROM_SYSTEM
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
let len = FormatMessageW(
|
|
flags,
|
|
std::ptr::null(),
|
|
err as u32,
|
|
0,
|
|
// FORMAT_MESSAGE_ALLOCATE_BUFFER expects a pointer to receive the allocated buffer.
|
|
// Cast &mut *mut u16 to *mut u16 as required by windows-sys.
|
|
(&mut buf_ptr as *mut *mut u16) as *mut u16,
|
|
0,
|
|
std::ptr::null_mut(),
|
|
);
|
|
if len == 0 || buf_ptr.is_null() {
|
|
return format!("Win32 error {err}");
|
|
}
|
|
let slice = std::slice::from_raw_parts(buf_ptr, len as usize);
|
|
let mut s = String::from_utf16_lossy(slice);
|
|
s = s.trim().to_string();
|
|
let _ = LocalFree(buf_ptr as HLOCAL);
|
|
s
|
|
}
|
|
}
|
|
|
|
pub fn string_from_sid_bytes(sid: &[u8]) -> Result<String, String> {
|
|
unsafe {
|
|
let mut str_ptr: *mut u16 = std::ptr::null_mut();
|
|
let ok = ConvertSidToStringSidW(sid.as_ptr() as *mut std::ffi::c_void, &mut str_ptr);
|
|
if ok == 0 || str_ptr.is_null() {
|
|
return Err(format!(
|
|
"ConvertSidToStringSidW failed: {}",
|
|
std::io::Error::last_os_error()
|
|
));
|
|
}
|
|
let mut len = 0;
|
|
while *str_ptr.add(len) != 0 {
|
|
len += 1;
|
|
}
|
|
let slice = std::slice::from_raw_parts(str_ptr, len);
|
|
let out = String::from_utf16_lossy(slice);
|
|
let _ = LocalFree(str_ptr as HLOCAL);
|
|
Ok(out)
|
|
}
|
|
}
|
|
|
|
const SID_ADMINISTRATORS: &str = "S-1-5-32-544";
|
|
const SID_USERS: &str = "S-1-5-32-545";
|
|
const SID_AUTHENTICATED_USERS: &str = "S-1-5-11";
|
|
const SID_EVERYONE: &str = "S-1-1-0";
|
|
const SID_SYSTEM: &str = "S-1-5-18";
|
|
|
|
pub fn resolve_sid(name: &str) -> Result<Vec<u8>> {
|
|
if let Some(sid_str) = well_known_sid_str(name) {
|
|
return sid_bytes_from_string(sid_str);
|
|
}
|
|
let name_w = to_wide(OsStr::new(name));
|
|
let mut sid_buffer = vec![0u8; 68];
|
|
let mut sid_len: u32 = sid_buffer.len() as u32;
|
|
let mut domain: Vec<u16> = Vec::new();
|
|
let mut domain_len: u32 = 0;
|
|
let mut use_type: SID_NAME_USE = 0;
|
|
loop {
|
|
let ok = unsafe {
|
|
LookupAccountNameW(
|
|
std::ptr::null(),
|
|
name_w.as_ptr(),
|
|
sid_buffer.as_mut_ptr() as *mut std::ffi::c_void,
|
|
&mut sid_len,
|
|
domain.as_mut_ptr(),
|
|
&mut domain_len,
|
|
&mut use_type,
|
|
)
|
|
};
|
|
if ok != 0 {
|
|
sid_buffer.truncate(sid_len as usize);
|
|
return Ok(sid_buffer);
|
|
}
|
|
let err = unsafe { GetLastError() };
|
|
if err == ERROR_INSUFFICIENT_BUFFER {
|
|
sid_buffer.resize(sid_len as usize, 0);
|
|
domain.resize(domain_len as usize, 0);
|
|
continue;
|
|
}
|
|
return Err(anyhow::anyhow!(
|
|
"LookupAccountNameW failed for {name}: {err}"
|
|
));
|
|
}
|
|
}
|
|
|
|
fn well_known_sid_str(name: &str) -> Option<&'static str> {
|
|
match name {
|
|
"Administrators" => Some(SID_ADMINISTRATORS),
|
|
"Users" => Some(SID_USERS),
|
|
"Authenticated Users" => Some(SID_AUTHENTICATED_USERS),
|
|
"Everyone" => Some(SID_EVERYONE),
|
|
"SYSTEM" => Some(SID_SYSTEM),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn sid_bytes_from_string(sid_str: &str) -> Result<Vec<u8>> {
|
|
let sid_w = to_wide(OsStr::new(sid_str));
|
|
let mut psid: *mut std::ffi::c_void = std::ptr::null_mut();
|
|
if unsafe { ConvertStringSidToSidW(sid_w.as_ptr(), &mut psid) } == 0 {
|
|
return Err(anyhow::anyhow!(
|
|
"ConvertStringSidToSidW failed for {sid_str}: {}",
|
|
unsafe { GetLastError() }
|
|
));
|
|
}
|
|
let sid_len = unsafe { GetLengthSid(psid) };
|
|
if sid_len == 0 {
|
|
unsafe {
|
|
LocalFree(psid as _);
|
|
}
|
|
return Err(anyhow::anyhow!("GetLengthSid failed for {sid_str}"));
|
|
}
|
|
let mut out = vec![0u8; sid_len as usize];
|
|
let ok = unsafe { CopySid(sid_len, out.as_mut_ptr() as *mut std::ffi::c_void, psid) };
|
|
unsafe {
|
|
LocalFree(psid as _);
|
|
}
|
|
if ok == 0 {
|
|
return Err(anyhow::anyhow!("CopySid failed for {sid_str}"));
|
|
}
|
|
Ok(out)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::argv_to_command_line;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn argv_to_command_line_quotes_each_argument_independently() {
|
|
let argv = vec![
|
|
"cmd.exe".to_string(),
|
|
"/c".to_string(),
|
|
"\"C:\\Program Files\\PowerShell\\7\\pwsh.exe\" -NoProfile -EncodedCommand abc=="
|
|
.to_string(),
|
|
];
|
|
|
|
assert_eq!(
|
|
argv_to_command_line(&argv),
|
|
"cmd.exe /c \"\\\"C:\\Program Files\\PowerShell\\7\\pwsh.exe\\\" -NoProfile -EncodedCommand abc==\""
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn argv_to_command_line_quotes_regular_program_args() {
|
|
let argv = vec![
|
|
"pwsh.exe".to_string(),
|
|
"-Command".to_string(),
|
|
"Write-Output \"hello world\"".to_string(),
|
|
];
|
|
|
|
assert_eq!(
|
|
argv_to_command_line(&argv),
|
|
"pwsh.exe -Command \"Write-Output \\\"hello world\\\"\""
|
|
);
|
|
}
|
|
}
|