2024-01-01 14:58:21 -05:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2020-09-21 08:26:41 -04:00
2020-09-14 12:48:57 -04:00
use deno_core ::error ::AnyError ;
2023-09-12 06:42:05 -04:00
use deno_core ::op2 ;
2023-08-23 19:03:05 -04:00
use deno_core ::unsync ::spawn_blocking ;
2023-09-13 23:36:24 -04:00
use deno_core ::unsync ::TaskQueue ;
2020-12-16 11:14:12 -05:00
use deno_core ::AsyncMutFuture ;
use deno_core ::AsyncRefCell ;
2021-11-09 13:26:17 -05:00
use deno_core ::AsyncResult ;
2022-10-09 10:49:25 -04:00
use deno_core ::BufMutView ;
use deno_core ::BufView ;
2020-12-16 11:14:12 -05:00
use deno_core ::CancelHandle ;
use deno_core ::CancelTryFuture ;
2020-09-10 09:57:45 -04:00
use deno_core ::OpState ;
2020-12-16 11:14:12 -05:00
use deno_core ::RcRef ;
use deno_core ::Resource ;
2023-08-01 14:48:39 -04:00
use deno_core ::ResourceHandle ;
use deno_core ::ResourceHandleFd ;
2023-05-04 14:28:42 -04:00
use fs ::FileResource ;
use fs ::FsError ;
use fs ::FsResult ;
use fs ::FsStat ;
use fs3 ::FileExt ;
2021-12-18 16:14:42 -05:00
use once_cell ::sync ::Lazy ;
2020-12-16 11:14:12 -05:00
use std ::borrow ::Cow ;
2022-04-19 10:41:31 -04:00
use std ::cell ::RefCell ;
2021-10-25 11:16:16 -04:00
use std ::fs ::File as StdFile ;
2023-09-13 23:36:24 -04:00
use std ::future ::Future ;
2023-04-12 09:13:32 -04:00
use std ::io ;
2022-05-11 12:48:38 -04:00
use std ::io ::ErrorKind ;
2021-01-14 23:32:27 -05:00
use std ::io ::Read ;
2023-05-04 14:28:42 -04:00
use std ::io ::Seek ;
2021-01-14 23:32:27 -05:00
use std ::io ::Write ;
2020-08-18 12:30:13 -04:00
use std ::rc ::Rc ;
2020-12-16 11:14:12 -05:00
use tokio ::io ::AsyncRead ;
use tokio ::io ::AsyncReadExt ;
use tokio ::io ::AsyncWrite ;
use tokio ::io ::AsyncWriteExt ;
2021-01-14 23:32:27 -05:00
use tokio ::process ;
2019-11-14 12:10:25 -05:00
2020-12-16 11:14:12 -05:00
#[ cfg(unix) ]
2019-11-14 12:10:25 -05:00
use std ::os ::unix ::io ::FromRawFd ;
#[ cfg(windows) ]
2023-01-14 23:18:58 -05:00
use std ::os ::windows ::io ::FromRawHandle ;
#[ cfg(windows) ]
use winapi ::um ::processenv ::GetStdHandle ;
#[ cfg(windows) ]
use winapi ::um ::winbase ;
2019-11-14 12:10:25 -05:00
2024-05-29 12:53:04 -04:00
#[ cfg(windows) ]
use parking_lot ::Condvar ;
#[ cfg(windows) ]
use parking_lot ::Mutex ;
#[ cfg(windows) ]
use std ::sync ::Arc ;
2023-05-04 14:28:42 -04:00
pub mod fs ;
2024-02-21 20:00:57 -05:00
mod pipe ;
#[ cfg(windows) ]
mod winpipe ;
2024-08-15 12:38:46 -04:00
mod bi_pipe ;
2024-02-21 20:00:57 -05:00
pub use pipe ::pipe ;
pub use pipe ::AsyncPipeRead ;
pub use pipe ::AsyncPipeWrite ;
pub use pipe ::PipeRead ;
pub use pipe ::PipeWrite ;
2024-09-27 15:35:37 -04:00
pub use pipe ::RawPipeHandle ;
2023-05-04 14:28:42 -04:00
2024-08-15 12:38:46 -04:00
pub use bi_pipe ::bi_pipe_pair_raw ;
pub use bi_pipe ::BiPipe ;
pub use bi_pipe ::BiPipeRead ;
pub use bi_pipe ::BiPipeResource ;
pub use bi_pipe ::BiPipeWrite ;
pub use bi_pipe ::RawBiPipeHandle ;
2024-09-27 15:35:37 -04:00
/// Abstraction over `AsRawFd` (unix) and `AsRawHandle` (windows)
pub trait AsRawIoHandle {
fn as_raw_io_handle ( & self ) -> RawIoHandle ;
}
#[ cfg(unix) ]
impl < T > AsRawIoHandle for T
where
T : std ::os ::unix ::io ::AsRawFd ,
{
fn as_raw_io_handle ( & self ) -> RawIoHandle {
self . as_raw_fd ( )
}
}
#[ cfg(windows) ]
impl < T > AsRawIoHandle for T
where
T : std ::os ::windows ::io ::AsRawHandle ,
{
fn as_raw_io_handle ( & self ) -> RawIoHandle {
self . as_raw_handle ( )
}
}
/// Abstraction over `IntoRawFd` (unix) and `IntoRawHandle` (windows)
pub trait IntoRawIoHandle {
fn into_raw_io_handle ( self ) -> RawIoHandle ;
}
#[ cfg(unix) ]
impl < T > IntoRawIoHandle for T
where
T : std ::os ::unix ::io ::IntoRawFd ,
{
fn into_raw_io_handle ( self ) -> RawIoHandle {
self . into_raw_fd ( )
}
}
#[ cfg(windows) ]
impl < T > IntoRawIoHandle for T
where
T : std ::os ::windows ::io ::IntoRawHandle ,
{
fn into_raw_io_handle ( self ) -> RawIoHandle {
self . into_raw_handle ( )
}
}
/// Abstraction over `FromRawFd` (unix) and `FromRawHandle` (windows)
pub trait FromRawIoHandle : Sized {
/// Constructs a type from a raw io handle (fd/HANDLE).
///
/// # Safety
///
/// Refer to the standard library docs ([unix](https://doc.rust-lang.org/stable/std/os/windows/io/trait.FromRawHandle.html#tymethod.from_raw_handle)) ([windows](https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.from_raw_fd))
///
unsafe fn from_raw_io_handle ( handle : RawIoHandle ) -> Self ;
}
#[ cfg(unix) ]
impl < T > FromRawIoHandle for T
where
T : std ::os ::unix ::io ::FromRawFd ,
{
unsafe fn from_raw_io_handle ( fd : RawIoHandle ) -> T {
// SAFETY: upheld by caller
unsafe { T ::from_raw_fd ( fd ) }
}
}
#[ cfg(windows) ]
impl < T > FromRawIoHandle for T
where
T : std ::os ::windows ::io ::FromRawHandle ,
{
unsafe fn from_raw_io_handle ( fd : RawIoHandle ) -> T {
// SAFETY: upheld by caller
unsafe { T ::from_raw_handle ( fd ) }
}
}
#[ cfg(unix) ]
pub type RawIoHandle = std ::os ::fd ::RawFd ;
#[ cfg(windows) ]
pub type RawIoHandle = std ::os ::windows ::io ::RawHandle ;
pub fn close_raw_handle ( handle : RawIoHandle ) {
#[ cfg(unix) ]
{
// SAFETY: libc call
unsafe {
libc ::close ( handle ) ;
}
}
#[ cfg(windows) ]
{
// SAFETY: win32 call
unsafe {
windows_sys ::Win32 ::Foundation ::CloseHandle ( handle as _ ) ;
}
}
}
2022-05-11 12:48:38 -04:00
// Store the stdio fd/handles in global statics in order to keep them
// alive for the duration of the application since the last handle/fd
// being dropped will close the corresponding pipe.
2021-10-25 11:16:16 -04:00
#[ cfg(unix) ]
2022-12-12 20:52:10 -05:00
pub static STDIN_HANDLE : Lazy < StdFile > = Lazy ::new ( | | {
2022-06-25 18:13:24 -04:00
// SAFETY: corresponds to OS stdin
unsafe { StdFile ::from_raw_fd ( 0 ) }
} ) ;
2021-12-18 16:14:42 -05:00
#[ cfg(unix) ]
2022-12-12 20:52:10 -05:00
pub static STDOUT_HANDLE : Lazy < StdFile > = Lazy ::new ( | | {
2022-06-25 18:13:24 -04:00
// SAFETY: corresponds to OS stdout
unsafe { StdFile ::from_raw_fd ( 1 ) }
} ) ;
2021-12-18 16:14:42 -05:00
#[ cfg(unix) ]
2022-12-12 20:52:10 -05:00
pub static STDERR_HANDLE : Lazy < StdFile > = Lazy ::new ( | | {
2022-06-25 18:13:24 -04:00
// SAFETY: corresponds to OS stderr
unsafe { StdFile ::from_raw_fd ( 2 ) }
} ) ;
2021-10-25 11:16:16 -04:00
#[ cfg(windows) ]
2022-12-12 20:52:10 -05:00
pub static STDIN_HANDLE : Lazy < StdFile > = Lazy ::new ( | | {
2022-06-25 18:13:24 -04:00
// SAFETY: corresponds to OS stdin
unsafe { StdFile ::from_raw_handle ( GetStdHandle ( winbase ::STD_INPUT_HANDLE ) ) }
2021-12-18 16:14:42 -05:00
} ) ;
#[ cfg(windows) ]
2022-12-12 20:52:10 -05:00
pub static STDOUT_HANDLE : Lazy < StdFile > = Lazy ::new ( | | {
2022-06-25 18:13:24 -04:00
// SAFETY: corresponds to OS stdout
unsafe { StdFile ::from_raw_handle ( GetStdHandle ( winbase ::STD_OUTPUT_HANDLE ) ) }
2021-12-18 16:14:42 -05:00
} ) ;
#[ cfg(windows) ]
2022-12-12 20:52:10 -05:00
pub static STDERR_HANDLE : Lazy < StdFile > = Lazy ::new ( | | {
2022-06-25 18:13:24 -04:00
// SAFETY: corresponds to OS stderr
unsafe { StdFile ::from_raw_handle ( GetStdHandle ( winbase ::STD_ERROR_HANDLE ) ) }
2021-12-18 16:14:42 -05:00
} ) ;
2019-08-21 20:42:48 -04:00
2023-03-17 14:22:15 -04:00
deno_core ::extension! ( deno_io ,
deps = [ deno_web ] ,
esm = [ " 12_io.js " ] ,
2023-03-17 18:15:27 -04:00
options = {
stdio : Option < Stdio > ,
2023-03-17 14:22:15 -04:00
} ,
middleware = | op | match op . name {
2024-04-12 15:45:38 -04:00
" op_print " = > op_print ( ) ,
2023-03-17 14:22:15 -04:00
_ = > op ,
} ,
2023-03-17 18:15:27 -04:00
state = | state , options | {
if let Some ( stdio ) = options . stdio {
2024-05-29 12:53:04 -04:00
#[ cfg(windows) ]
let stdin_state = {
let st = Arc ::new ( Mutex ::new ( WinTtyState ::default ( ) ) ) ;
state . put ( st . clone ( ) ) ;
st
} ;
#[ cfg(unix) ]
let stdin_state = ( ) ;
2023-03-17 18:15:27 -04:00
let t = & mut state . resource_table ;
2023-03-09 09:56:19 -05:00
2023-05-04 14:28:42 -04:00
let rid = t . add ( fs ::FileResource ::new (
2024-02-23 13:11:15 -05:00
Rc ::new ( match stdio . stdin . pipe {
StdioPipeInner ::Inherit = > StdFileResourceInner ::new (
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::Stdin ( stdin_state ) ,
2023-05-04 14:28:42 -04:00
STDIN_HANDLE . try_clone ( ) . unwrap ( ) ,
) ,
2024-02-23 13:11:15 -05:00
StdioPipeInner ::File ( pipe ) = > StdFileResourceInner ::file ( pipe ) ,
2023-05-04 14:28:42 -04:00
} ) ,
" stdin " . to_string ( ) ,
2023-03-17 18:15:27 -04:00
) ) ;
assert_eq! ( rid , 0 , " stdin must have ResourceId 0 " ) ;
2022-10-07 08:38:06 -04:00
2023-05-04 14:28:42 -04:00
let rid = t . add ( FileResource ::new (
2024-02-23 13:11:15 -05:00
Rc ::new ( match stdio . stdout . pipe {
StdioPipeInner ::Inherit = > StdFileResourceInner ::new (
2023-05-04 14:28:42 -04:00
StdFileResourceKind ::Stdout ,
STDOUT_HANDLE . try_clone ( ) . unwrap ( ) ,
) ,
2024-02-23 13:11:15 -05:00
StdioPipeInner ::File ( pipe ) = > StdFileResourceInner ::file ( pipe ) ,
2023-05-04 14:28:42 -04:00
} ) ,
" stdout " . to_string ( ) ,
2023-03-17 18:15:27 -04:00
) ) ;
assert_eq! ( rid , 1 , " stdout must have ResourceId 1 " ) ;
2022-10-07 08:38:06 -04:00
2023-05-04 14:28:42 -04:00
let rid = t . add ( FileResource ::new (
2024-02-23 13:11:15 -05:00
Rc ::new ( match stdio . stderr . pipe {
StdioPipeInner ::Inherit = > StdFileResourceInner ::new (
2023-05-04 14:28:42 -04:00
StdFileResourceKind ::Stderr ,
STDERR_HANDLE . try_clone ( ) . unwrap ( ) ,
) ,
2024-02-23 13:11:15 -05:00
StdioPipeInner ::File ( pipe ) = > StdFileResourceInner ::file ( pipe ) ,
2023-05-04 14:28:42 -04:00
} ) ,
" stderr " . to_string ( ) ,
2023-03-17 18:15:27 -04:00
) ) ;
assert_eq! ( rid , 2 , " stderr must have ResourceId 2 " ) ;
}
2023-03-17 14:22:15 -04:00
} ,
) ;
2023-03-09 09:56:19 -05:00
2024-02-23 13:11:15 -05:00
#[ derive(Default) ]
pub struct StdioPipe {
pipe : StdioPipeInner ,
2023-03-04 19:39:48 -05:00
}
2024-02-23 13:11:15 -05:00
impl StdioPipe {
pub const fn inherit ( ) -> Self {
StdioPipe {
pipe : StdioPipeInner ::Inherit ,
}
}
pub fn file ( f : impl Into < StdFile > ) -> Self {
StdioPipe {
pipe : StdioPipeInner ::File ( f . into ( ) ) ,
}
2023-03-04 19:39:48 -05:00
}
}
2024-02-23 13:11:15 -05:00
#[ derive(Default) ]
enum StdioPipeInner {
#[ default ]
Inherit ,
File ( StdFile ) ,
}
2023-03-04 19:39:48 -05:00
impl Clone for StdioPipe {
fn clone ( & self ) -> Self {
2024-02-23 13:11:15 -05:00
match & self . pipe {
StdioPipeInner ::Inherit = > Self {
pipe : StdioPipeInner ::Inherit ,
} ,
StdioPipeInner ::File ( pipe ) = > Self {
pipe : StdioPipeInner ::File ( pipe . try_clone ( ) . unwrap ( ) ) ,
} ,
2023-03-04 19:39:48 -05:00
}
}
}
/// Specify how stdin, stdout, and stderr are piped.
/// By default, inherits from the process.
#[ derive(Clone, Default) ]
pub struct Stdio {
pub stdin : StdioPipe ,
pub stdout : StdioPipe ,
pub stderr : StdioPipe ,
}
2021-01-14 23:32:27 -05:00
#[ derive(Debug) ]
pub struct WriteOnlyResource < S > {
stream : AsyncRefCell < S > ,
}
impl < S : 'static > From < S > for WriteOnlyResource < S > {
fn from ( stream : S ) -> Self {
Self {
stream : stream . into ( ) ,
}
}
}
impl < S > WriteOnlyResource < S >
where
S : AsyncWrite + Unpin + 'static ,
{
pub fn borrow_mut ( self : & Rc < Self > ) -> AsyncMutFuture < S > {
RcRef ::map ( self , | r | & r . stream ) . borrow_mut ( )
}
2022-10-09 10:49:25 -04:00
async fn write ( self : Rc < Self > , data : & [ u8 ] ) -> Result < usize , AnyError > {
2021-01-14 23:32:27 -05:00
let mut stream = self . borrow_mut ( ) . await ;
2022-10-09 10:49:25 -04:00
let nwritten = stream . write ( data ) . await ? ;
2021-01-14 23:32:27 -05:00
Ok ( nwritten )
}
2021-11-09 13:26:17 -05:00
async fn shutdown ( self : Rc < Self > ) -> Result < ( ) , AnyError > {
2021-01-14 23:32:27 -05:00
let mut stream = self . borrow_mut ( ) . await ;
stream . shutdown ( ) . await ? ;
Ok ( ( ) )
}
2022-04-20 18:20:33 -04:00
pub fn into_inner ( self ) -> S {
self . stream . into_inner ( )
}
2021-01-14 23:32:27 -05:00
}
#[ derive(Debug) ]
pub struct ReadOnlyResource < S > {
stream : AsyncRefCell < S > ,
cancel_handle : CancelHandle ,
}
impl < S : 'static > From < S > for ReadOnlyResource < S > {
fn from ( stream : S ) -> Self {
Self {
stream : stream . into ( ) ,
cancel_handle : Default ::default ( ) ,
}
}
}
impl < S > ReadOnlyResource < S >
where
S : AsyncRead + Unpin + 'static ,
{
pub fn borrow_mut ( self : & Rc < Self > ) -> AsyncMutFuture < S > {
RcRef ::map ( self , | r | & r . stream ) . borrow_mut ( )
}
pub fn cancel_handle ( self : & Rc < Self > ) -> RcRef < CancelHandle > {
RcRef ::map ( self , | r | & r . cancel_handle )
}
pub fn cancel_read_ops ( & self ) {
self . cancel_handle . cancel ( )
}
2022-10-09 10:49:25 -04:00
async fn read ( self : Rc < Self > , data : & mut [ u8 ] ) -> Result < usize , AnyError > {
2021-01-14 23:32:27 -05:00
let mut rd = self . borrow_mut ( ) . await ;
2022-10-09 10:49:25 -04:00
let nread = rd . read ( data ) . try_or_cancel ( self . cancel_handle ( ) ) . await ? ;
Ok ( nread )
2021-01-14 23:32:27 -05:00
}
2022-04-20 18:20:33 -04:00
pub fn into_inner ( self ) -> S {
self . stream . into_inner ( )
}
2021-01-14 23:32:27 -05:00
}
pub type ChildStdinResource = WriteOnlyResource < process ::ChildStdin > ;
impl Resource for ChildStdinResource {
fn name ( & self ) -> Cow < str > {
" childStdin " . into ( )
}
2021-11-09 13:26:17 -05:00
2022-10-09 10:49:25 -04:00
deno_core ::impl_writable! ( ) ;
2021-11-09 13:26:17 -05:00
fn shutdown ( self : Rc < Self > ) -> AsyncResult < ( ) > {
Box ::pin ( self . shutdown ( ) )
}
2021-01-14 23:32:27 -05:00
}
pub type ChildStdoutResource = ReadOnlyResource < process ::ChildStdout > ;
impl Resource for ChildStdoutResource {
2022-10-09 10:49:25 -04:00
deno_core ::impl_readable_byob! ( ) ;
2021-01-14 23:32:27 -05:00
fn name ( & self ) -> Cow < str > {
" childStdout " . into ( )
}
fn close ( self : Rc < Self > ) {
self . cancel_read_ops ( ) ;
}
}
pub type ChildStderrResource = ReadOnlyResource < process ::ChildStderr > ;
impl Resource for ChildStderrResource {
2022-10-09 10:49:25 -04:00
deno_core ::impl_readable_byob! ( ) ;
2021-01-14 23:32:27 -05:00
fn name ( & self ) -> Cow < str > {
" childStderr " . into ( )
}
fn close ( self : Rc < Self > ) {
self . cancel_read_ops ( ) ;
}
2020-12-16 11:14:12 -05:00
}
2020-03-11 18:19:24 -04:00
2024-05-29 12:53:04 -04:00
#[ cfg(windows) ]
#[ derive(Default) ]
pub struct WinTtyState {
pub cancelled : bool ,
pub reading : bool ,
pub screen_buffer_info :
Option < winapi ::um ::wincon ::CONSOLE_SCREEN_BUFFER_INFO > ,
pub cvar : Arc < Condvar > ,
}
#[ derive(Clone) ]
2022-09-04 22:33:06 -04:00
enum StdFileResourceKind {
File ,
2022-07-13 11:16:42 -04:00
// For stdout and stderr, we sometimes instead use std::io::stdout() directly,
// because we get some Windows specific functionality for free by using Rust
// std's wrappers. So we take a bit of a complexity hit in order to not
// have to duplicate the functionality in Rust's std/src/sys/windows/stdio.rs
2024-05-29 12:53:04 -04:00
#[ cfg(windows) ]
Stdin ( Arc < Mutex < WinTtyState > > ) ,
#[ cfg(not(windows)) ]
Stdin ( ( ) ) ,
2022-09-04 22:33:06 -04:00
Stdout ,
Stderr ,
}
2023-05-04 14:28:42 -04:00
pub struct StdFileResourceInner {
2022-09-04 22:33:06 -04:00
kind : StdFileResourceKind ,
2023-05-04 14:28:42 -04:00
// We can't use an AsyncRefCell here because we need to allow
// access to the resource synchronously at any time and
// asynchronously one at a time in order
cell : RefCell < Option < StdFile > > ,
// Used to keep async actions in order and only allow one
// to occur at a time
2023-09-13 23:36:24 -04:00
cell_async_task_queue : Rc < TaskQueue > ,
2023-08-01 14:48:39 -04:00
handle : ResourceHandleFd ,
2022-05-11 12:48:38 -04:00
}
impl StdFileResourceInner {
pub fn file ( fs_file : StdFile ) -> Self {
2023-05-04 14:28:42 -04:00
StdFileResourceInner ::new ( StdFileResourceKind ::File , fs_file )
}
fn new ( kind : StdFileResourceKind , fs_file : StdFile ) -> Self {
2023-08-01 14:48:39 -04:00
// We know this will be an fd
let handle = ResourceHandle ::from_fd_like ( & fs_file ) . as_fd_like ( ) . unwrap ( ) ;
2022-09-04 22:33:06 -04:00
StdFileResourceInner {
2023-05-04 14:28:42 -04:00
kind ,
2023-08-01 14:48:39 -04:00
handle ,
2023-05-04 14:28:42 -04:00
cell : RefCell ::new ( Some ( fs_file ) ) ,
cell_async_task_queue : Default ::default ( ) ,
2022-09-04 22:33:06 -04:00
}
2022-05-11 12:48:38 -04:00
}
2023-05-04 14:28:42 -04:00
fn with_sync < F , R > ( & self , action : F ) -> FsResult < R >
where
F : FnOnce ( & mut StdFile ) -> FsResult < R > ,
{
match self . cell . try_borrow_mut ( ) {
Ok ( mut cell ) if cell . is_some ( ) = > action ( cell . as_mut ( ) . unwrap ( ) ) ,
_ = > Err ( fs ::FsError ::FileBusy ) ,
}
2022-09-04 22:33:06 -04:00
}
2023-09-13 23:36:24 -04:00
fn with_inner_blocking_task < F , R : 'static + Send > (
& self ,
action : F ,
) -> impl Future < Output = R > + '_
2023-05-04 14:28:42 -04:00
where
F : FnOnce ( & mut StdFile ) -> R + Send + 'static ,
{
// we want to restrict this to one async action at a time
2023-09-13 23:36:24 -04:00
let acquire_fut = self . cell_async_task_queue . acquire ( ) ;
async move {
let permit = acquire_fut . await ;
// we take the value out of the cell, use it on a blocking task,
// then put it back into the cell when we're done
let mut did_take = false ;
let mut cell_value = {
let mut cell = self . cell . borrow_mut ( ) ;
match cell . as_mut ( ) . unwrap ( ) . try_clone ( ) . ok ( ) {
Some ( value ) = > value ,
None = > {
did_take = true ;
cell . take ( ) . unwrap ( )
}
2023-05-04 14:28:42 -04:00
}
2023-09-13 23:36:24 -04:00
} ;
let ( cell_value , result ) = spawn_blocking ( move | | {
let result = action ( & mut cell_value ) ;
( cell_value , result )
} )
. await
. unwrap ( ) ;
if did_take {
// put it back
self . cell . borrow_mut ( ) . replace ( cell_value ) ;
2023-05-04 14:28:42 -04:00
}
2023-09-13 23:36:24 -04:00
drop ( permit ) ; // explicit for clarity
result
}
2022-05-11 12:48:38 -04:00
}
2023-09-13 23:36:24 -04:00
fn with_blocking_task < F , R : 'static + Send > (
& self ,
action : F ,
) -> impl Future < Output = R >
2023-05-04 14:28:42 -04:00
where
F : FnOnce ( ) -> R + Send + 'static ,
{
// we want to restrict this to one async action at a time
2023-09-13 23:36:24 -04:00
let acquire_fut = self . cell_async_task_queue . acquire ( ) ;
async move {
let _permit = acquire_fut . await ;
spawn_blocking ( action ) . await . unwrap ( )
}
2023-05-04 14:28:42 -04:00
}
2024-05-29 12:53:04 -04:00
#[ cfg(windows) ]
async fn handle_stdin_read (
& self ,
state : Arc < Mutex < WinTtyState > > ,
mut buf : BufMutView ,
) -> FsResult < ( usize , BufMutView ) > {
loop {
let state = state . clone ( ) ;
let fut = self . with_inner_blocking_task ( move | file | {
/* Start reading, and set the reading flag to true */
state . lock ( ) . reading = true ;
let nread = match file . read ( & mut buf ) {
Ok ( nread ) = > nread ,
Err ( e ) = > return Err ( ( e . into ( ) , buf ) ) ,
} ;
let mut state = state . lock ( ) ;
state . reading = false ;
/* If we canceled the read by sending a VK_RETURN event, restore
the screen state to undo the visual effect of the VK_RETURN event * /
if state . cancelled {
if let Some ( screen_buffer_info ) = state . screen_buffer_info {
// SAFETY: WinAPI calls to open conout$ and restore visual state.
unsafe {
let handle = winapi ::um ::fileapi ::CreateFileW (
" conout$ "
. encode_utf16 ( )
. chain ( Some ( 0 ) )
. collect ::< Vec < _ > > ( )
. as_ptr ( ) ,
winapi ::um ::winnt ::GENERIC_READ
| winapi ::um ::winnt ::GENERIC_WRITE ,
winapi ::um ::winnt ::FILE_SHARE_READ
| winapi ::um ::winnt ::FILE_SHARE_WRITE ,
std ::ptr ::null_mut ( ) ,
winapi ::um ::fileapi ::OPEN_EXISTING ,
0 ,
std ::ptr ::null_mut ( ) ,
) ;
let mut pos = screen_buffer_info . dwCursorPosition ;
/* If the cursor was at the bottom line of the screen buffer, the
VK_RETURN would have caused the buffer contents to scroll up by
one line . The right position to reset the cursor to is therefore one
line higher * /
if pos . Y = = screen_buffer_info . dwSize . Y - 1 {
pos . Y - = 1 ;
}
winapi ::um ::wincon ::SetConsoleCursorPosition ( handle , pos ) ;
winapi ::um ::handleapi ::CloseHandle ( handle ) ;
}
}
/* Reset the cancelled flag */
state . cancelled = false ;
/* Unblock the main thread */
state . cvar . notify_one ( ) ;
return Err ( ( FsError ::FileBusy , buf ) ) ;
}
Ok ( ( nread , buf ) )
} ) ;
match fut . await {
Err ( ( FsError ::FileBusy , b ) ) = > {
buf = b ;
continue ;
}
other = > return other . map_err ( | ( e , _ ) | e ) ,
}
}
}
2023-05-04 14:28:42 -04:00
}
#[ async_trait::async_trait(?Send) ]
impl crate ::fs ::File for StdFileResourceInner {
fn write_sync ( self : Rc < Self > , buf : & [ u8 ] ) -> FsResult < usize > {
2022-07-13 11:16:42 -04:00
// Rust will line buffer and we don't want that behavior
// (see https://github.com/denoland/deno/issues/948), so flush stdout and stderr.
// Although an alternative solution could be to bypass Rust's std by
// using the raw fds/handles, it will cause encoding issues on Windows
// that we get solved for free by using Rust's stdio wrappers (see
// std/src/sys/windows/stdio.rs in Rust's source code).
2022-09-04 22:33:06 -04:00
match self . kind {
2023-05-04 14:28:42 -04:00
StdFileResourceKind ::File = > self . with_sync ( | file | Ok ( file . write ( buf ) ? ) ) ,
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::Stdin ( _ ) = > {
2022-07-13 11:16:42 -04:00
Err ( Into ::< std ::io ::Error > ::into ( ErrorKind ::Unsupported ) . into ( ) )
}
2022-09-04 22:33:06 -04:00
StdFileResourceKind ::Stdout = > {
2022-07-13 11:16:42 -04:00
// bypass the file and use std::io::stdout()
let mut stdout = std ::io ::stdout ( ) . lock ( ) ;
let nwritten = stdout . write ( buf ) ? ;
stdout . flush ( ) ? ;
Ok ( nwritten )
}
2022-09-04 22:33:06 -04:00
StdFileResourceKind ::Stderr = > {
2022-07-13 11:16:42 -04:00
// bypass the file and use std::io::stderr()
let mut stderr = std ::io ::stderr ( ) . lock ( ) ;
let nwritten = stderr . write ( buf ) ? ;
stderr . flush ( ) ? ;
Ok ( nwritten )
}
2022-05-11 12:48:38 -04:00
}
}
2023-05-04 14:28:42 -04:00
fn read_sync ( self : Rc < Self > , buf : & mut [ u8 ] ) -> FsResult < usize > {
match self . kind {
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::File | StdFileResourceKind ::Stdin ( _ ) = > {
2023-05-04 14:28:42 -04:00
self . with_sync ( | file | Ok ( file . read ( buf ) ? ) )
}
StdFileResourceKind ::Stdout | StdFileResourceKind ::Stderr = > {
Err ( FsError ::NotSupported )
}
}
}
fn write_all_sync ( self : Rc < Self > , buf : & [ u8 ] ) -> FsResult < ( ) > {
2022-09-04 22:33:06 -04:00
match self . kind {
2023-05-04 14:28:42 -04:00
StdFileResourceKind ::File = > {
self . with_sync ( | file | Ok ( file . write_all ( buf ) ? ) )
}
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::Stdin ( _ ) = > {
2022-07-13 11:16:42 -04:00
Err ( Into ::< std ::io ::Error > ::into ( ErrorKind ::Unsupported ) . into ( ) )
}
2022-09-04 22:33:06 -04:00
StdFileResourceKind ::Stdout = > {
2022-07-13 11:16:42 -04:00
// bypass the file and use std::io::stdout()
let mut stdout = std ::io ::stdout ( ) . lock ( ) ;
stdout . write_all ( buf ) ? ;
stdout . flush ( ) ? ;
Ok ( ( ) )
}
2022-09-04 22:33:06 -04:00
StdFileResourceKind ::Stderr = > {
2022-07-13 11:16:42 -04:00
// bypass the file and use std::io::stderr()
let mut stderr = std ::io ::stderr ( ) . lock ( ) ;
stderr . write_all ( buf ) ? ;
stderr . flush ( ) ? ;
Ok ( ( ) )
}
2022-05-11 12:48:38 -04:00
}
}
2023-05-04 14:28:42 -04:00
async fn write_all ( self : Rc < Self > , buf : BufView ) -> FsResult < ( ) > {
2022-09-04 22:33:06 -04:00
match self . kind {
2023-05-04 14:28:42 -04:00
StdFileResourceKind ::File = > {
self
. with_inner_blocking_task ( move | file | Ok ( file . write_all ( & buf ) ? ) )
. await
2022-09-04 22:33:06 -04:00
}
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::Stdin ( _ ) = > {
2023-05-04 14:28:42 -04:00
Err ( Into ::< std ::io ::Error > ::into ( ErrorKind ::Unsupported ) . into ( ) )
}
StdFileResourceKind ::Stdout = > {
self
. with_blocking_task ( move | | {
// bypass the file and use std::io::stdout()
let mut stdout = std ::io ::stdout ( ) . lock ( ) ;
stdout . write_all ( & buf ) ? ;
stdout . flush ( ) ? ;
Ok ( ( ) )
} )
. await
}
StdFileResourceKind ::Stderr = > {
self
. with_blocking_task ( move | | {
// bypass the file and use std::io::stderr()
let mut stderr = std ::io ::stderr ( ) . lock ( ) ;
stderr . write_all ( & buf ) ? ;
stderr . flush ( ) ? ;
Ok ( ( ) )
} )
. await
2022-09-04 22:33:06 -04:00
}
2022-05-11 12:48:38 -04:00
}
}
2023-05-04 14:28:42 -04:00
async fn write (
self : Rc < Self > ,
view : BufView ,
) -> FsResult < deno_core ::WriteOutcome > {
match self . kind {
StdFileResourceKind ::File = > {
self
. with_inner_blocking_task ( | file | {
let nwritten = file . write ( & view ) ? ;
Ok ( deno_core ::WriteOutcome ::Partial { nwritten , view } )
} )
. await
}
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::Stdin ( _ ) = > {
2023-05-04 14:28:42 -04:00
Err ( Into ::< std ::io ::Error > ::into ( ErrorKind ::Unsupported ) . into ( ) )
}
StdFileResourceKind ::Stdout = > {
self
. with_blocking_task ( | | {
// bypass the file and use std::io::stdout()
let mut stdout = std ::io ::stdout ( ) . lock ( ) ;
let nwritten = stdout . write ( & view ) ? ;
stdout . flush ( ) ? ;
Ok ( deno_core ::WriteOutcome ::Partial { nwritten , view } )
} )
. await
}
StdFileResourceKind ::Stderr = > {
self
. with_blocking_task ( | | {
// bypass the file and use std::io::stderr()
let mut stderr = std ::io ::stderr ( ) . lock ( ) ;
let nwritten = stderr . write ( & view ) ? ;
stderr . flush ( ) ? ;
Ok ( deno_core ::WriteOutcome ::Partial { nwritten , view } )
} )
. await
}
2020-12-16 11:14:12 -05:00
}
}
2023-05-04 14:28:42 -04:00
fn read_all_sync ( self : Rc < Self > ) -> FsResult < Vec < u8 > > {
match self . kind {
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::File | StdFileResourceKind ::Stdin ( _ ) = > {
2023-05-04 14:28:42 -04:00
let mut buf = Vec ::new ( ) ;
self . with_sync ( | file | Ok ( file . read_to_end ( & mut buf ) ? ) ) ? ;
Ok ( buf )
}
StdFileResourceKind ::Stdout | StdFileResourceKind ::Stderr = > {
Err ( FsError ::NotSupported )
}
2020-12-16 11:14:12 -05:00
}
}
2023-05-04 14:28:42 -04:00
async fn read_all_async ( self : Rc < Self > ) -> FsResult < Vec < u8 > > {
match self . kind {
2024-05-29 12:53:04 -04:00
StdFileResourceKind ::File | StdFileResourceKind ::Stdin ( _ ) = > {
2023-05-04 14:28:42 -04:00
self
. with_inner_blocking_task ( | file | {
let mut buf = Vec ::new ( ) ;
file . read_to_end ( & mut buf ) ? ;
Ok ( buf )
} )
. await
}
StdFileResourceKind ::Stdout | StdFileResourceKind ::Stderr = > {
Err ( FsError ::NotSupported )
2022-05-11 12:48:38 -04:00
}
2022-05-10 10:13:08 -04:00
}
}
2023-05-04 14:28:42 -04:00
fn chmod_sync ( self : Rc < Self > , _mode : u32 ) -> FsResult < ( ) > {
#[ cfg(unix) ]
{
use std ::os ::unix ::prelude ::PermissionsExt ;
self . with_sync ( | file | {
Ok ( file . set_permissions ( std ::fs ::Permissions ::from_mode ( _mode ) ) ? )
} )
2022-09-04 22:33:06 -04:00
}
2023-05-04 14:28:42 -04:00
#[ cfg(not(unix)) ]
Err ( FsError ::NotSupported )
}
async fn chmod_async ( self : Rc < Self > , _mode : u32 ) -> FsResult < ( ) > {
#[ cfg(unix) ]
{
use std ::os ::unix ::prelude ::PermissionsExt ;
self
. with_inner_blocking_task ( move | file | {
Ok ( file . set_permissions ( std ::fs ::Permissions ::from_mode ( _mode ) ) ? )
} )
. await
}
#[ cfg(not(unix)) ]
Err ( FsError ::NotSupported )
2022-05-10 10:13:08 -04:00
}
2023-05-04 14:28:42 -04:00
fn seek_sync ( self : Rc < Self > , pos : io ::SeekFrom ) -> FsResult < u64 > {
self . with_sync ( | file | Ok ( file . seek ( pos ) ? ) )
}
async fn seek_async ( self : Rc < Self > , pos : io ::SeekFrom ) -> FsResult < u64 > {
2022-07-13 11:16:42 -04:00
self
2023-05-04 14:28:42 -04:00
. with_inner_blocking_task ( move | file | Ok ( file . seek ( pos ) ? ) )
2022-07-13 11:16:42 -04:00
. await
2020-12-16 11:14:12 -05:00
}
2023-05-04 14:28:42 -04:00
fn datasync_sync ( self : Rc < Self > ) -> FsResult < ( ) > {
self . with_sync ( | file | Ok ( file . sync_data ( ) ? ) )
}
async fn datasync_async ( self : Rc < Self > ) -> FsResult < ( ) > {
2022-07-13 11:16:42 -04:00
self
2023-05-04 14:28:42 -04:00
. with_inner_blocking_task ( | file | Ok ( file . sync_data ( ) ? ) )
2022-07-13 11:16:42 -04:00
. await
2021-01-14 23:32:27 -05:00
}
2020-12-16 11:14:12 -05:00
2023-05-04 14:28:42 -04:00
fn sync_sync ( self : Rc < Self > ) -> FsResult < ( ) > {
self . with_sync ( | file | Ok ( file . sync_all ( ) ? ) )
}
async fn sync_async ( self : Rc < Self > ) -> FsResult < ( ) > {
2022-10-09 10:49:25 -04:00
self
2023-05-04 14:28:42 -04:00
. with_inner_blocking_task ( | file | Ok ( file . sync_all ( ) ? ) )
2022-10-09 10:49:25 -04:00
. await
}
2023-05-04 14:28:42 -04:00
fn stat_sync ( self : Rc < Self > ) -> FsResult < FsStat > {
self . with_sync ( | file | Ok ( file . metadata ( ) . map ( FsStat ::from_std ) ? ) )
2023-04-05 18:14:16 -04:00
}
2023-05-04 14:28:42 -04:00
async fn stat_async ( self : Rc < Self > ) -> FsResult < FsStat > {
2023-04-12 09:13:32 -04:00
self
2023-05-04 14:28:42 -04:00
. with_inner_blocking_task ( | file | {
Ok ( file . metadata ( ) . map ( FsStat ::from_std ) ? )
} )
. await
2022-05-11 12:48:38 -04:00
}
2020-12-16 11:14:12 -05:00
2023-05-04 14:28:42 -04:00
fn lock_sync ( self : Rc < Self > , exclusive : bool ) -> FsResult < ( ) > {
self . with_sync ( | file | {
if exclusive {
file . lock_exclusive ( ) ? ;
} else {
file . lock_shared ( ) ? ;
}
Ok ( ( ) )
2022-07-13 11:16:42 -04:00
} )
}
2023-05-04 14:28:42 -04:00
async fn lock_async ( self : Rc < Self > , exclusive : bool ) -> FsResult < ( ) > {
self
. with_inner_blocking_task ( move | file | {
if exclusive {
file . lock_exclusive ( ) ? ;
} else {
file . lock_shared ( ) ? ;
}
Ok ( ( ) )
} )
2022-07-13 11:16:42 -04:00
. await
2020-12-16 11:14:12 -05:00
}
2022-04-26 09:26:05 -04:00
2023-05-04 14:28:42 -04:00
fn unlock_sync ( self : Rc < Self > ) -> FsResult < ( ) > {
self . with_sync ( | file | Ok ( file . unlock ( ) ? ) )
}
async fn unlock_async ( self : Rc < Self > ) -> FsResult < ( ) > {
2023-04-12 09:13:32 -04:00
self
2023-05-04 14:28:42 -04:00
. with_inner_blocking_task ( | file | Ok ( file . unlock ( ) ? ) )
2023-04-12 09:13:32 -04:00
. await
}
2023-05-04 14:28:42 -04:00
fn truncate_sync ( self : Rc < Self > , len : u64 ) -> FsResult < ( ) > {
self . with_sync ( | file | Ok ( file . set_len ( len ) ? ) )
2022-05-11 12:48:38 -04:00
}
2023-05-04 14:28:42 -04:00
async fn truncate_async ( self : Rc < Self > , len : u64 ) -> FsResult < ( ) > {
self
. with_inner_blocking_task ( move | file | Ok ( file . set_len ( len ) ? ) )
. await
2020-12-16 11:14:12 -05:00
}
2023-05-04 14:28:42 -04:00
fn utime_sync (
self : Rc < Self > ,
atime_secs : i64 ,
atime_nanos : u32 ,
mtime_secs : i64 ,
mtime_nanos : u32 ,
) -> FsResult < ( ) > {
let atime = filetime ::FileTime ::from_unix_time ( atime_secs , atime_nanos ) ;
let mtime = filetime ::FileTime ::from_unix_time ( mtime_secs , mtime_nanos ) ;
self . with_sync ( | file | {
filetime ::set_file_handle_times ( file , Some ( atime ) , Some ( mtime ) ) ? ;
Ok ( ( ) )
2022-10-09 10:49:25 -04:00
} )
2021-11-09 13:26:17 -05:00
}
2023-05-04 14:28:42 -04:00
async fn utime_async (
2022-10-09 10:49:25 -04:00
self : Rc < Self > ,
2023-05-04 14:28:42 -04:00
atime_secs : i64 ,
atime_nanos : u32 ,
mtime_secs : i64 ,
mtime_nanos : u32 ,
) -> FsResult < ( ) > {
let atime = filetime ::FileTime ::from_unix_time ( atime_secs , atime_nanos ) ;
let mtime = filetime ::FileTime ::from_unix_time ( mtime_secs , mtime_nanos ) ;
2022-08-18 08:05:02 -04:00
2023-05-04 14:28:42 -04:00
self
. with_inner_blocking_task ( move | file | {
filetime ::set_file_handle_times ( file , Some ( atime ) , Some ( mtime ) ) ? ;
Ok ( ( ) )
} )
. await
2023-04-05 17:13:01 -04:00
}
2023-04-05 18:14:16 -04:00
2023-05-04 14:28:42 -04:00
async fn read_byob (
self : Rc < Self > ,
mut buf : BufMutView ,
) -> FsResult < ( usize , BufMutView ) > {
2024-05-29 12:53:04 -04:00
match & self . kind {
/* On Windows, we need to handle special read cancellation logic for stdin */
#[ cfg(windows) ]
StdFileResourceKind ::Stdin ( state ) = > {
self . handle_stdin_read ( state . clone ( ) , buf ) . await
}
_ = > {
self
. with_inner_blocking_task ( | file | {
let nread = file . read ( & mut buf ) ? ;
Ok ( ( nread , buf ) )
} )
. await
}
}
2023-04-05 18:14:16 -04:00
}
2023-05-04 14:28:42 -04:00
fn try_clone_inner ( self : Rc < Self > ) -> FsResult < Rc < dyn fs ::File > > {
let inner : & Option < _ > = & self . cell . borrow ( ) ;
match inner {
Some ( inner ) = > Ok ( Rc ::new ( StdFileResourceInner {
2024-05-29 12:53:04 -04:00
kind : self . kind . clone ( ) ,
2023-05-04 14:28:42 -04:00
cell : RefCell ::new ( Some ( inner . try_clone ( ) ? ) ) ,
cell_async_task_queue : Default ::default ( ) ,
2023-08-01 14:48:39 -04:00
handle : self . handle ,
2023-05-04 14:28:42 -04:00
} ) ) ,
None = > Err ( FsError ::FileBusy ) ,
}
2023-04-05 18:14:16 -04:00
}
2023-05-04 14:28:42 -04:00
fn as_stdio ( self : Rc < Self > ) -> FsResult < std ::process ::Stdio > {
match self . kind {
StdFileResourceKind ::File = > self . with_sync ( | file | {
let file = file . try_clone ( ) ? ;
Ok ( file . into ( ) )
} ) ,
_ = > Ok ( std ::process ::Stdio ::inherit ( ) ) ,
}
2023-04-05 17:13:01 -04:00
}
2022-10-09 10:49:25 -04:00
2023-08-01 14:48:39 -04:00
fn backing_fd ( self : Rc < Self > ) -> Option < ResourceHandleFd > {
Some ( self . handle )
2022-08-18 08:05:02 -04:00
}
2019-10-11 14:41:54 -04:00
}
2022-05-01 14:44:55 -04:00
// override op_print to use the stdout and stderr in the resource table
2023-09-12 06:42:05 -04:00
#[ op2(fast) ]
2022-05-01 14:44:55 -04:00
pub fn op_print (
state : & mut OpState ,
2023-09-12 06:42:05 -04:00
#[ string ] msg : & str ,
2022-05-01 14:44:55 -04:00
is_err : bool ,
) -> Result < ( ) , AnyError > {
let rid = if is_err { 2 } else { 1 } ;
2023-05-04 14:28:42 -04:00
FileResource ::with_file ( state , rid , move | file | {
Ok ( file . write_all_sync ( msg . as_bytes ( ) ) ? )
2022-05-01 14:44:55 -04:00
} )
}