diff options
Diffstat (limited to 'ext/node/ops/util.rs')
-rw-r--r-- | ext/node/ops/util.rs | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/ext/node/ops/util.rs b/ext/node/ops/util.rs new file mode 100644 index 000000000..1cb80e0e3 --- /dev/null +++ b/ext/node/ops/util.rs @@ -0,0 +1,83 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::op2; +use deno_core::OpState; +use deno_core::ResourceHandle; +use deno_core::ResourceHandleFd; + +#[repr(u32)] +enum HandleType { + #[allow(dead_code)] + Tcp = 0, + Tty, + #[allow(dead_code)] + Udp, + File, + Pipe, + Unknown, +} + +#[op2(fast)] +pub fn op_node_guess_handle_type( + state: &mut OpState, + rid: u32, +) -> Result<u32, AnyError> { + let handle = state.resource_table.get_handle(rid)?; + + let handle_type = match handle { + ResourceHandle::Fd(handle) => guess_handle_type(handle), + _ => HandleType::Unknown, + }; + + Ok(handle_type as u32) +} + +#[cfg(windows)] +fn guess_handle_type(handle: ResourceHandleFd) -> HandleType { + use winapi::um::consoleapi::GetConsoleMode; + use winapi::um::fileapi::GetFileType; + use winapi::um::winbase::FILE_TYPE_CHAR; + use winapi::um::winbase::FILE_TYPE_DISK; + use winapi::um::winbase::FILE_TYPE_PIPE; + + // SAFETY: Call to win32 fileapi. `handle` is a valid fd. + match unsafe { GetFileType(handle) } { + FILE_TYPE_DISK => HandleType::File, + FILE_TYPE_CHAR => { + let mut mode = 0; + // SAFETY: Call to win32 consoleapi. `handle` is a valid fd. + // `mode` is a valid pointer. + if unsafe { GetConsoleMode(handle, &mut mode) } == 1 { + HandleType::Tty + } else { + HandleType::File + } + } + FILE_TYPE_PIPE => HandleType::Pipe, + _ => HandleType::Unknown, + } +} + +#[cfg(unix)] +fn guess_handle_type(handle: ResourceHandleFd) -> HandleType { + use std::io::IsTerminal; + // SAFETY: The resource remains open for the duration of borrow_raw. + if unsafe { std::os::fd::BorrowedFd::borrow_raw(handle).is_terminal() } { + return HandleType::Tty; + } + + // SAFETY: It is safe to zero-initialize a `libc::stat` struct. + let mut s = unsafe { std::mem::zeroed() }; + // SAFETY: Call to libc + if unsafe { libc::fstat(handle, &mut s) } == 1 { + return HandleType::Unknown; + } + + match s.st_mode & 61440 { + libc::S_IFREG | libc::S_IFCHR => HandleType::File, + libc::S_IFIFO => HandleType::Pipe, + libc::S_IFSOCK => HandleType::Tcp, + _ => HandleType::Unknown, + } +} |