2022-01-07 22:09:52 -05:00
|
|
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
2021-10-25 11:16:16 -04:00
|
|
|
|
|
|
|
/// Ensures that stdin, stdout, and stderr are open and have valid HANDLEs
|
|
|
|
/// associated with them. There are many places where a `std::fs::File` is
|
|
|
|
/// constructed from a stdio handle; if the handle is null this causes a panic.
|
|
|
|
pub fn ensure_stdio_open() {
|
|
|
|
#[cfg(windows)]
|
|
|
|
unsafe {
|
|
|
|
use std::mem::size_of;
|
|
|
|
use winapi::shared::minwindef::DWORD;
|
|
|
|
use winapi::shared::minwindef::FALSE;
|
|
|
|
use winapi::shared::minwindef::TRUE;
|
|
|
|
use winapi::shared::ntdef::NULL;
|
|
|
|
use winapi::shared::winerror::ERROR_INVALID_HANDLE;
|
|
|
|
use winapi::um::errhandlingapi::GetLastError;
|
|
|
|
use winapi::um::fileapi::CreateFileA;
|
|
|
|
use winapi::um::fileapi::OPEN_EXISTING;
|
|
|
|
use winapi::um::handleapi::GetHandleInformation;
|
|
|
|
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
|
|
|
use winapi::um::minwinbase::SECURITY_ATTRIBUTES;
|
|
|
|
use winapi::um::processenv::GetStdHandle;
|
|
|
|
use winapi::um::processenv::SetStdHandle;
|
|
|
|
use winapi::um::winbase::STD_ERROR_HANDLE;
|
|
|
|
use winapi::um::winbase::STD_INPUT_HANDLE;
|
|
|
|
use winapi::um::winbase::STD_OUTPUT_HANDLE;
|
|
|
|
use winapi::um::winnt::FILE_ATTRIBUTE_NORMAL;
|
|
|
|
use winapi::um::winnt::FILE_GENERIC_READ;
|
|
|
|
use winapi::um::winnt::FILE_GENERIC_WRITE;
|
|
|
|
use winapi::um::winnt::FILE_READ_ATTRIBUTES;
|
|
|
|
use winapi::um::winnt::FILE_SHARE_READ;
|
|
|
|
use winapi::um::winnt::FILE_SHARE_WRITE;
|
|
|
|
|
|
|
|
for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE] {
|
|
|
|
// Check whether stdio handle is open.
|
|
|
|
let is_valid = match GetStdHandle(std_handle) {
|
|
|
|
NULL | INVALID_HANDLE_VALUE => false,
|
|
|
|
handle => {
|
|
|
|
// The stdio handle is open; check whether its handle is valid.
|
|
|
|
let mut flags: DWORD = 0;
|
|
|
|
match GetHandleInformation(handle, &mut flags) {
|
|
|
|
TRUE => true,
|
|
|
|
FALSE if GetLastError() == ERROR_INVALID_HANDLE => false,
|
|
|
|
FALSE => {
|
|
|
|
panic!("GetHandleInformation failed (error {})", GetLastError());
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if !is_valid {
|
|
|
|
// Open NUL device.
|
|
|
|
let desired_access = match std_handle {
|
|
|
|
STD_INPUT_HANDLE => FILE_GENERIC_READ,
|
|
|
|
_ => FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
|
|
|
|
};
|
|
|
|
let security_attributes = SECURITY_ATTRIBUTES {
|
|
|
|
nLength: size_of::<SECURITY_ATTRIBUTES>() as DWORD,
|
|
|
|
lpSecurityDescriptor: NULL,
|
|
|
|
bInheritHandle: TRUE,
|
|
|
|
};
|
|
|
|
let file_handle = CreateFileA(
|
|
|
|
b"\\\\?\\NUL\0" as *const _ as *mut _,
|
|
|
|
desired_access,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
&security_attributes as *const _ as *mut _,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL,
|
|
|
|
);
|
|
|
|
match file_handle {
|
|
|
|
NULL => unreachable!(),
|
|
|
|
INVALID_HANDLE_VALUE => {
|
|
|
|
panic!("Could not open NUL device (error {})", GetLastError());
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assign the opened NUL handle to the missing stdio handle.
|
|
|
|
let success = SetStdHandle(std_handle, file_handle);
|
|
|
|
match success {
|
|
|
|
TRUE => {}
|
|
|
|
FALSE => panic!("SetStdHandle failed (error {})", GetLastError()),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|