1use std::borrow::Cow;
4use std::cell::RefCell;
5use std::fs::File as StdFile;
6use std::future::Future;
7use std::io;
8use std::io::ErrorKind;
9use std::io::Read;
10use std::io::Seek;
11use std::io::Write;
12#[cfg(unix)]
13use std::os::unix::io::FromRawFd;
14#[cfg(windows)]
15use std::os::windows::io::FromRawHandle;
16use std::rc::Rc;
17#[cfg(windows)]
18use std::sync::Arc;
19
20use deno_core::futures::TryFutureExt;
21use deno_core::op2;
22use deno_core::unsync::spawn_blocking;
23use deno_core::unsync::TaskQueue;
24use deno_core::AsyncMutFuture;
25use deno_core::AsyncRefCell;
26use deno_core::AsyncResult;
27use deno_core::BufMutView;
28use deno_core::BufView;
29use deno_core::CancelHandle;
30use deno_core::CancelTryFuture;
31use deno_core::OpState;
32use deno_core::RcRef;
33use deno_core::Resource;
34use deno_core::ResourceHandle;
35use deno_core::ResourceHandleFd;
36use deno_error::JsErrorBox;
37use fs::FileResource;
38use fs::FsError;
39use fs::FsResult;
40use fs::FsStat;
41use fs3::FileExt;
42use once_cell::sync::Lazy;
43#[cfg(windows)]
44use parking_lot::Condvar;
45#[cfg(windows)]
46use parking_lot::Mutex;
47use tokio::io::AsyncRead;
48use tokio::io::AsyncReadExt;
49use tokio::io::AsyncWrite;
50use tokio::io::AsyncWriteExt;
51use tokio::process;
52#[cfg(windows)]
53use winapi::um::processenv::GetStdHandle;
54#[cfg(windows)]
55use winapi::um::winbase;
56
57pub mod fs;
58mod pipe;
59#[cfg(windows)]
60mod winpipe;
61
62mod bi_pipe;
63
64pub use bi_pipe::bi_pipe_pair_raw;
65pub use bi_pipe::BiPipe;
66pub use bi_pipe::BiPipeRead;
67pub use bi_pipe::BiPipeResource;
68pub use bi_pipe::BiPipeWrite;
69pub use bi_pipe::RawBiPipeHandle;
70pub use pipe::pipe;
71pub use pipe::AsyncPipeRead;
72pub use pipe::AsyncPipeWrite;
73pub use pipe::PipeRead;
74pub use pipe::PipeWrite;
75pub use pipe::RawPipeHandle;
76
77pub trait AsRawIoHandle {
79 fn as_raw_io_handle(&self) -> RawIoHandle;
80}
81
82#[cfg(unix)]
83impl<T> AsRawIoHandle for T
84where
85 T: std::os::unix::io::AsRawFd,
86{
87 fn as_raw_io_handle(&self) -> RawIoHandle {
88 self.as_raw_fd()
89 }
90}
91
92#[cfg(windows)]
93impl<T> AsRawIoHandle for T
94where
95 T: std::os::windows::io::AsRawHandle,
96{
97 fn as_raw_io_handle(&self) -> RawIoHandle {
98 self.as_raw_handle()
99 }
100}
101
102pub trait IntoRawIoHandle {
104 fn into_raw_io_handle(self) -> RawIoHandle;
105}
106
107#[cfg(unix)]
108impl<T> IntoRawIoHandle for T
109where
110 T: std::os::unix::io::IntoRawFd,
111{
112 fn into_raw_io_handle(self) -> RawIoHandle {
113 self.into_raw_fd()
114 }
115}
116
117#[cfg(windows)]
118impl<T> IntoRawIoHandle for T
119where
120 T: std::os::windows::io::IntoRawHandle,
121{
122 fn into_raw_io_handle(self) -> RawIoHandle {
123 self.into_raw_handle()
124 }
125}
126
127pub trait FromRawIoHandle: Sized {
129 unsafe fn from_raw_io_handle(handle: RawIoHandle) -> Self;
136}
137
138#[cfg(unix)]
139impl<T> FromRawIoHandle for T
140where
141 T: std::os::unix::io::FromRawFd,
142{
143 unsafe fn from_raw_io_handle(fd: RawIoHandle) -> T {
144 unsafe { T::from_raw_fd(fd) }
146 }
147}
148
149#[cfg(windows)]
150impl<T> FromRawIoHandle for T
151where
152 T: std::os::windows::io::FromRawHandle,
153{
154 unsafe fn from_raw_io_handle(fd: RawIoHandle) -> T {
155 unsafe { T::from_raw_handle(fd) }
157 }
158}
159
160#[cfg(unix)]
161pub type RawIoHandle = std::os::fd::RawFd;
162
163#[cfg(windows)]
164pub type RawIoHandle = std::os::windows::io::RawHandle;
165
166pub fn close_raw_handle(handle: RawIoHandle) {
167 #[cfg(unix)]
168 {
169 unsafe {
171 libc::close(handle);
172 }
173 }
174 #[cfg(windows)]
175 {
176 unsafe {
178 windows_sys::Win32::Foundation::CloseHandle(handle as _);
179 }
180 }
181}
182
183#[cfg(unix)]
187pub static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| {
188 unsafe { StdFile::from_raw_fd(0) }
190});
191#[cfg(unix)]
192pub static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| {
193 unsafe { StdFile::from_raw_fd(1) }
195});
196#[cfg(unix)]
197pub static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| {
198 unsafe { StdFile::from_raw_fd(2) }
200});
201
202#[cfg(windows)]
203pub static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| {
204 unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_INPUT_HANDLE)) }
206});
207#[cfg(windows)]
208pub static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| {
209 unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_OUTPUT_HANDLE)) }
211});
212#[cfg(windows)]
213pub static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| {
214 unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_ERROR_HANDLE)) }
216});
217
218deno_core::extension!(deno_io,
219 deps = [ deno_web ],
220 esm = [ "12_io.js" ],
221 options = {
222 stdio: Option<Stdio>,
223 },
224 middleware = |op| match op.name {
225 "op_print" => op_print(),
226 _ => op,
227 },
228 state = |state, options| {
229 if let Some(stdio) = options.stdio {
230 #[cfg(windows)]
231 let stdin_state = {
232 let st = Arc::new(Mutex::new(WinTtyState::default()));
233 state.put(st.clone());
234 st
235 };
236 #[cfg(unix)]
237 let stdin_state = ();
238
239 let t = &mut state.resource_table;
240
241 let rid = t.add(fs::FileResource::new(
242 Rc::new(match stdio.stdin.pipe {
243 StdioPipeInner::Inherit => StdFileResourceInner::new(
244 StdFileResourceKind::Stdin(stdin_state),
245 STDIN_HANDLE.try_clone().unwrap(),
246 ),
247 StdioPipeInner::File(pipe) => StdFileResourceInner::file(pipe),
248 }),
249 "stdin".to_string(),
250 ));
251 assert_eq!(rid, 0, "stdin must have ResourceId 0");
252
253 let rid = t.add(FileResource::new(
254 Rc::new(match stdio.stdout.pipe {
255 StdioPipeInner::Inherit => StdFileResourceInner::new(
256 StdFileResourceKind::Stdout,
257 STDOUT_HANDLE.try_clone().unwrap(),
258 ),
259 StdioPipeInner::File(pipe) => StdFileResourceInner::file(pipe),
260 }),
261 "stdout".to_string(),
262 ));
263 assert_eq!(rid, 1, "stdout must have ResourceId 1");
264
265 let rid = t.add(FileResource::new(
266 Rc::new(match stdio.stderr.pipe {
267 StdioPipeInner::Inherit => StdFileResourceInner::new(
268 StdFileResourceKind::Stderr,
269 STDERR_HANDLE.try_clone().unwrap(),
270 ),
271 StdioPipeInner::File(pipe) => StdFileResourceInner::file(pipe),
272 }),
273 "stderr".to_string(),
274 ));
275 assert_eq!(rid, 2, "stderr must have ResourceId 2");
276 }
277 },
278);
279
280#[derive(Default)]
281pub struct StdioPipe {
282 pipe: StdioPipeInner,
283}
284
285impl StdioPipe {
286 pub const fn inherit() -> Self {
287 StdioPipe {
288 pipe: StdioPipeInner::Inherit,
289 }
290 }
291
292 pub fn file(f: impl Into<StdFile>) -> Self {
293 StdioPipe {
294 pipe: StdioPipeInner::File(f.into()),
295 }
296 }
297}
298
299#[derive(Default)]
300enum StdioPipeInner {
301 #[default]
302 Inherit,
303 File(StdFile),
304}
305
306impl Clone for StdioPipe {
307 fn clone(&self) -> Self {
308 match &self.pipe {
309 StdioPipeInner::Inherit => Self {
310 pipe: StdioPipeInner::Inherit,
311 },
312 StdioPipeInner::File(pipe) => Self {
313 pipe: StdioPipeInner::File(pipe.try_clone().unwrap()),
314 },
315 }
316 }
317}
318
319#[derive(Clone, Default)]
322pub struct Stdio {
323 pub stdin: StdioPipe,
324 pub stdout: StdioPipe,
325 pub stderr: StdioPipe,
326}
327
328#[derive(Debug)]
329pub struct WriteOnlyResource<S> {
330 stream: AsyncRefCell<S>,
331}
332
333impl<S: 'static> From<S> for WriteOnlyResource<S> {
334 fn from(stream: S) -> Self {
335 Self {
336 stream: stream.into(),
337 }
338 }
339}
340
341impl<S> WriteOnlyResource<S>
342where
343 S: AsyncWrite + Unpin + 'static,
344{
345 pub fn borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<S> {
346 RcRef::map(self, |r| &r.stream).borrow_mut()
347 }
348
349 async fn write(self: Rc<Self>, data: &[u8]) -> Result<usize, io::Error> {
350 let mut stream = self.borrow_mut().await;
351 let nwritten = stream.write(data).await?;
352 Ok(nwritten)
353 }
354
355 async fn shutdown(self: Rc<Self>) -> Result<(), io::Error> {
356 let mut stream = self.borrow_mut().await;
357 stream.shutdown().await?;
358 Ok(())
359 }
360
361 pub fn into_inner(self) -> S {
362 self.stream.into_inner()
363 }
364}
365
366#[derive(Debug)]
367pub struct ReadOnlyResource<S> {
368 stream: AsyncRefCell<S>,
369 cancel_handle: CancelHandle,
370}
371
372impl<S: 'static> From<S> for ReadOnlyResource<S> {
373 fn from(stream: S) -> Self {
374 Self {
375 stream: stream.into(),
376 cancel_handle: Default::default(),
377 }
378 }
379}
380
381impl<S> ReadOnlyResource<S>
382where
383 S: AsyncRead + Unpin + 'static,
384{
385 pub fn borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<S> {
386 RcRef::map(self, |r| &r.stream).borrow_mut()
387 }
388
389 pub fn cancel_handle(self: &Rc<Self>) -> RcRef<CancelHandle> {
390 RcRef::map(self, |r| &r.cancel_handle)
391 }
392
393 pub fn cancel_read_ops(&self) {
394 self.cancel_handle.cancel()
395 }
396
397 async fn read(self: Rc<Self>, data: &mut [u8]) -> Result<usize, io::Error> {
398 let mut rd = self.borrow_mut().await;
399 let nread = rd.read(data).try_or_cancel(self.cancel_handle()).await?;
400 Ok(nread)
401 }
402
403 pub fn into_inner(self) -> S {
404 self.stream.into_inner()
405 }
406}
407
408pub type ChildStdinResource = WriteOnlyResource<process::ChildStdin>;
409
410impl Resource for ChildStdinResource {
411 fn name(&self) -> Cow<str> {
412 "childStdin".into()
413 }
414
415 deno_core::impl_writable!();
416
417 fn shutdown(self: Rc<Self>) -> AsyncResult<()> {
418 Box::pin(self.shutdown().map_err(JsErrorBox::from_err))
419 }
420}
421
422pub type ChildStdoutResource = ReadOnlyResource<process::ChildStdout>;
423
424impl Resource for ChildStdoutResource {
425 deno_core::impl_readable_byob!();
426
427 fn name(&self) -> Cow<str> {
428 "childStdout".into()
429 }
430
431 fn close(self: Rc<Self>) {
432 self.cancel_read_ops();
433 }
434}
435
436pub type ChildStderrResource = ReadOnlyResource<process::ChildStderr>;
437
438impl Resource for ChildStderrResource {
439 deno_core::impl_readable_byob!();
440
441 fn name(&self) -> Cow<str> {
442 "childStderr".into()
443 }
444
445 fn close(self: Rc<Self>) {
446 self.cancel_read_ops();
447 }
448}
449
450#[cfg(windows)]
451#[derive(Default)]
452pub struct WinTtyState {
453 pub cancelled: bool,
454 pub reading: bool,
455 pub screen_buffer_info:
456 Option<winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO>,
457 pub cvar: Arc<Condvar>,
458}
459
460#[derive(Clone)]
461enum StdFileResourceKind {
462 File,
463 #[cfg(windows)]
468 Stdin(Arc<Mutex<WinTtyState>>),
469 #[cfg(not(windows))]
470 Stdin(()),
471 Stdout,
472 Stderr,
473}
474
475pub struct StdFileResourceInner {
476 kind: StdFileResourceKind,
477 cell: RefCell<Option<StdFile>>,
481 cell_async_task_queue: Rc<TaskQueue>,
484 handle: ResourceHandleFd,
485}
486
487impl StdFileResourceInner {
488 pub fn file(fs_file: StdFile) -> Self {
489 StdFileResourceInner::new(StdFileResourceKind::File, fs_file)
490 }
491
492 fn new(kind: StdFileResourceKind, fs_file: StdFile) -> Self {
493 let handle = ResourceHandle::from_fd_like(&fs_file).as_fd_like().unwrap();
495 StdFileResourceInner {
496 kind,
497 handle,
498 cell: RefCell::new(Some(fs_file)),
499 cell_async_task_queue: Default::default(),
500 }
501 }
502
503 fn with_sync<F, R>(&self, action: F) -> FsResult<R>
504 where
505 F: FnOnce(&mut StdFile) -> FsResult<R>,
506 {
507 match self.cell.try_borrow_mut() {
508 Ok(mut cell) if cell.is_some() => action(cell.as_mut().unwrap()),
509 _ => Err(fs::FsError::FileBusy),
510 }
511 }
512
513 fn with_inner_blocking_task<F, R: 'static + Send>(
514 &self,
515 action: F,
516 ) -> impl Future<Output = R> + '_
517 where
518 F: FnOnce(&mut StdFile) -> R + Send + 'static,
519 {
520 let acquire_fut = self.cell_async_task_queue.acquire();
522 async move {
523 let permit = acquire_fut.await;
524 let mut did_take = false;
527 let mut cell_value = {
528 let mut cell = self.cell.borrow_mut();
529 match cell.as_mut().unwrap().try_clone().ok() {
530 Some(value) => value,
531 None => {
532 did_take = true;
533 cell.take().unwrap()
534 }
535 }
536 };
537 let (cell_value, result) = spawn_blocking(move || {
538 let result = action(&mut cell_value);
539 (cell_value, result)
540 })
541 .await
542 .unwrap();
543
544 if did_take {
545 self.cell.borrow_mut().replace(cell_value);
547 }
548
549 drop(permit); result
551 }
552 }
553
554 fn with_blocking_task<F, R: 'static + Send>(
555 &self,
556 action: F,
557 ) -> impl Future<Output = R>
558 where
559 F: FnOnce() -> R + Send + 'static,
560 {
561 let acquire_fut = self.cell_async_task_queue.acquire();
563 async move {
564 let _permit = acquire_fut.await;
565 spawn_blocking(action).await.unwrap()
566 }
567 }
568
569 #[cfg(windows)]
570 async fn handle_stdin_read(
571 &self,
572 state: Arc<Mutex<WinTtyState>>,
573 mut buf: BufMutView,
574 ) -> FsResult<(usize, BufMutView)> {
575 loop {
576 let state = state.clone();
577
578 let fut = self.with_inner_blocking_task(move |file| {
579 state.lock().reading = true;
581 let nread = match file.read(&mut buf) {
582 Ok(nread) => nread,
583 Err(e) => return Err((e.into(), buf)),
584 };
585
586 let mut state = state.lock();
587 state.reading = false;
588
589 if state.cancelled {
592 if let Some(screen_buffer_info) = state.screen_buffer_info {
593 unsafe {
595 let handle = winapi::um::fileapi::CreateFileW(
596 "conout$"
597 .encode_utf16()
598 .chain(Some(0))
599 .collect::<Vec<_>>()
600 .as_ptr(),
601 winapi::um::winnt::GENERIC_READ
602 | winapi::um::winnt::GENERIC_WRITE,
603 winapi::um::winnt::FILE_SHARE_READ
604 | winapi::um::winnt::FILE_SHARE_WRITE,
605 std::ptr::null_mut(),
606 winapi::um::fileapi::OPEN_EXISTING,
607 0,
608 std::ptr::null_mut(),
609 );
610
611 let mut pos = screen_buffer_info.dwCursorPosition;
612 if pos.Y == screen_buffer_info.dwSize.Y - 1 {
617 pos.Y -= 1;
618 }
619
620 winapi::um::wincon::SetConsoleCursorPosition(handle, pos);
621 winapi::um::handleapi::CloseHandle(handle);
622 }
623 }
624
625 state.cancelled = false;
627
628 state.cvar.notify_one();
630
631 return Err((FsError::FileBusy, buf));
632 }
633
634 Ok((nread, buf))
635 });
636
637 match fut.await {
638 Err((FsError::FileBusy, b)) => {
639 buf = b;
640 continue;
641 }
642 other => return other.map_err(|(e, _)| e),
643 }
644 }
645 }
646}
647
648#[async_trait::async_trait(?Send)]
649impl crate::fs::File for StdFileResourceInner {
650 fn write_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<usize> {
651 match self.kind {
658 StdFileResourceKind::File => self.with_sync(|file| Ok(file.write(buf)?)),
659 StdFileResourceKind::Stdin(_) => {
660 Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
661 }
662 StdFileResourceKind::Stdout => {
663 let mut stdout = std::io::stdout().lock();
665 let nwritten = stdout.write(buf)?;
666 stdout.flush()?;
667 Ok(nwritten)
668 }
669 StdFileResourceKind::Stderr => {
670 let mut stderr = std::io::stderr().lock();
672 let nwritten = stderr.write(buf)?;
673 stderr.flush()?;
674 Ok(nwritten)
675 }
676 }
677 }
678
679 fn read_sync(self: Rc<Self>, buf: &mut [u8]) -> FsResult<usize> {
680 match self.kind {
681 StdFileResourceKind::File | StdFileResourceKind::Stdin(_) => {
682 self.with_sync(|file| Ok(file.read(buf)?))
683 }
684 StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
685 Err(FsError::NotSupported)
686 }
687 }
688 }
689
690 fn write_all_sync(self: Rc<Self>, buf: &[u8]) -> FsResult<()> {
691 match self.kind {
692 StdFileResourceKind::File => {
693 self.with_sync(|file| Ok(file.write_all(buf)?))
694 }
695 StdFileResourceKind::Stdin(_) => {
696 Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
697 }
698 StdFileResourceKind::Stdout => {
699 let mut stdout = std::io::stdout().lock();
701 stdout.write_all(buf)?;
702 stdout.flush()?;
703 Ok(())
704 }
705 StdFileResourceKind::Stderr => {
706 let mut stderr = std::io::stderr().lock();
708 stderr.write_all(buf)?;
709 stderr.flush()?;
710 Ok(())
711 }
712 }
713 }
714 async fn write_all(self: Rc<Self>, buf: BufView) -> FsResult<()> {
715 match self.kind {
716 StdFileResourceKind::File => {
717 self
718 .with_inner_blocking_task(move |file| Ok(file.write_all(&buf)?))
719 .await
720 }
721 StdFileResourceKind::Stdin(_) => {
722 Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
723 }
724 StdFileResourceKind::Stdout => {
725 self
726 .with_blocking_task(move || {
727 let mut stdout = std::io::stdout().lock();
729 stdout.write_all(&buf)?;
730 stdout.flush()?;
731 Ok(())
732 })
733 .await
734 }
735 StdFileResourceKind::Stderr => {
736 self
737 .with_blocking_task(move || {
738 let mut stderr = std::io::stderr().lock();
740 stderr.write_all(&buf)?;
741 stderr.flush()?;
742 Ok(())
743 })
744 .await
745 }
746 }
747 }
748
749 async fn write(
750 self: Rc<Self>,
751 view: BufView,
752 ) -> FsResult<deno_core::WriteOutcome> {
753 match self.kind {
754 StdFileResourceKind::File => {
755 self
756 .with_inner_blocking_task(|file| {
757 let nwritten = file.write(&view)?;
758 Ok(deno_core::WriteOutcome::Partial { nwritten, view })
759 })
760 .await
761 }
762 StdFileResourceKind::Stdin(_) => {
763 Err(Into::<std::io::Error>::into(ErrorKind::Unsupported).into())
764 }
765 StdFileResourceKind::Stdout => {
766 self
767 .with_blocking_task(|| {
768 let mut stdout = std::io::stdout().lock();
770 let nwritten = stdout.write(&view)?;
771 stdout.flush()?;
772 Ok(deno_core::WriteOutcome::Partial { nwritten, view })
773 })
774 .await
775 }
776 StdFileResourceKind::Stderr => {
777 self
778 .with_blocking_task(|| {
779 let mut stderr = std::io::stderr().lock();
781 let nwritten = stderr.write(&view)?;
782 stderr.flush()?;
783 Ok(deno_core::WriteOutcome::Partial { nwritten, view })
784 })
785 .await
786 }
787 }
788 }
789
790 fn read_all_sync(self: Rc<Self>) -> FsResult<Cow<'static, [u8]>> {
791 match self.kind {
792 StdFileResourceKind::File | StdFileResourceKind::Stdin(_) => {
793 let mut buf = Vec::new();
794 self.with_sync(|file| Ok(file.read_to_end(&mut buf)?))?;
795 Ok(Cow::Owned(buf))
796 }
797 StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
798 Err(FsError::NotSupported)
799 }
800 }
801 }
802 async fn read_all_async(self: Rc<Self>) -> FsResult<Cow<'static, [u8]>> {
803 match self.kind {
804 StdFileResourceKind::File | StdFileResourceKind::Stdin(_) => {
805 self
806 .with_inner_blocking_task(|file| {
807 let mut buf = Vec::new();
808 file.read_to_end(&mut buf)?;
809 Ok(Cow::Owned(buf))
810 })
811 .await
812 }
813 StdFileResourceKind::Stdout | StdFileResourceKind::Stderr => {
814 Err(FsError::NotSupported)
815 }
816 }
817 }
818
819 fn chmod_sync(self: Rc<Self>, _mode: u32) -> FsResult<()> {
820 #[cfg(unix)]
821 {
822 use std::os::unix::prelude::PermissionsExt;
823 self.with_sync(|file| {
824 Ok(file.set_permissions(std::fs::Permissions::from_mode(_mode))?)
825 })
826 }
827 #[cfg(not(unix))]
828 Err(FsError::NotSupported)
829 }
830 async fn chmod_async(self: Rc<Self>, _mode: u32) -> FsResult<()> {
831 #[cfg(unix)]
832 {
833 use std::os::unix::prelude::PermissionsExt;
834 self
835 .with_inner_blocking_task(move |file| {
836 Ok(file.set_permissions(std::fs::Permissions::from_mode(_mode))?)
837 })
838 .await
839 }
840 #[cfg(not(unix))]
841 Err(FsError::NotSupported)
842 }
843
844 fn seek_sync(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64> {
845 self.with_sync(|file| Ok(file.seek(pos)?))
846 }
847 async fn seek_async(self: Rc<Self>, pos: io::SeekFrom) -> FsResult<u64> {
848 self
849 .with_inner_blocking_task(move |file| Ok(file.seek(pos)?))
850 .await
851 }
852
853 fn datasync_sync(self: Rc<Self>) -> FsResult<()> {
854 self.with_sync(|file| Ok(file.sync_data()?))
855 }
856 async fn datasync_async(self: Rc<Self>) -> FsResult<()> {
857 self
858 .with_inner_blocking_task(|file| Ok(file.sync_data()?))
859 .await
860 }
861
862 fn sync_sync(self: Rc<Self>) -> FsResult<()> {
863 self.with_sync(|file| Ok(file.sync_all()?))
864 }
865 async fn sync_async(self: Rc<Self>) -> FsResult<()> {
866 self
867 .with_inner_blocking_task(|file| Ok(file.sync_all()?))
868 .await
869 }
870
871 fn stat_sync(self: Rc<Self>) -> FsResult<FsStat> {
872 self.with_sync(|file| Ok(file.metadata().map(FsStat::from_std)?))
873 }
874 async fn stat_async(self: Rc<Self>) -> FsResult<FsStat> {
875 self
876 .with_inner_blocking_task(|file| {
877 Ok(file.metadata().map(FsStat::from_std)?)
878 })
879 .await
880 }
881
882 fn lock_sync(self: Rc<Self>, exclusive: bool) -> FsResult<()> {
883 self.with_sync(|file| {
884 if exclusive {
885 file.lock_exclusive()?;
886 } else {
887 file.lock_shared()?;
888 }
889 Ok(())
890 })
891 }
892 async fn lock_async(self: Rc<Self>, exclusive: bool) -> FsResult<()> {
893 self
894 .with_inner_blocking_task(move |file| {
895 if exclusive {
896 file.lock_exclusive()?;
897 } else {
898 file.lock_shared()?;
899 }
900 Ok(())
901 })
902 .await
903 }
904
905 fn unlock_sync(self: Rc<Self>) -> FsResult<()> {
906 self.with_sync(|file| Ok(file.unlock()?))
907 }
908 async fn unlock_async(self: Rc<Self>) -> FsResult<()> {
909 self
910 .with_inner_blocking_task(|file| Ok(file.unlock()?))
911 .await
912 }
913
914 fn truncate_sync(self: Rc<Self>, len: u64) -> FsResult<()> {
915 self.with_sync(|file| Ok(file.set_len(len)?))
916 }
917 async fn truncate_async(self: Rc<Self>, len: u64) -> FsResult<()> {
918 self
919 .with_inner_blocking_task(move |file| Ok(file.set_len(len)?))
920 .await
921 }
922
923 fn utime_sync(
924 self: Rc<Self>,
925 atime_secs: i64,
926 atime_nanos: u32,
927 mtime_secs: i64,
928 mtime_nanos: u32,
929 ) -> FsResult<()> {
930 let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
931 let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
932
933 self.with_sync(|file| {
934 filetime::set_file_handle_times(file, Some(atime), Some(mtime))?;
935 Ok(())
936 })
937 }
938 async fn utime_async(
939 self: Rc<Self>,
940 atime_secs: i64,
941 atime_nanos: u32,
942 mtime_secs: i64,
943 mtime_nanos: u32,
944 ) -> FsResult<()> {
945 let atime = filetime::FileTime::from_unix_time(atime_secs, atime_nanos);
946 let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos);
947
948 self
949 .with_inner_blocking_task(move |file| {
950 filetime::set_file_handle_times(file, Some(atime), Some(mtime))?;
951 Ok(())
952 })
953 .await
954 }
955
956 async fn read_byob(
957 self: Rc<Self>,
958 mut buf: BufMutView,
959 ) -> FsResult<(usize, BufMutView)> {
960 match &self.kind {
961 #[cfg(windows)]
963 StdFileResourceKind::Stdin(state) => {
964 self.handle_stdin_read(state.clone(), buf).await
965 }
966 _ => {
967 self
968 .with_inner_blocking_task(|file| {
969 let nread = file.read(&mut buf)?;
970 Ok((nread, buf))
971 })
972 .await
973 }
974 }
975 }
976
977 fn try_clone_inner(self: Rc<Self>) -> FsResult<Rc<dyn fs::File>> {
978 let inner: &Option<_> = &self.cell.borrow();
979 match inner {
980 Some(inner) => Ok(Rc::new(StdFileResourceInner {
981 kind: self.kind.clone(),
982 cell: RefCell::new(Some(inner.try_clone()?)),
983 cell_async_task_queue: Default::default(),
984 handle: self.handle,
985 })),
986 None => Err(FsError::FileBusy),
987 }
988 }
989
990 fn as_stdio(self: Rc<Self>) -> FsResult<std::process::Stdio> {
991 match self.kind {
992 StdFileResourceKind::File => self.with_sync(|file| {
993 let file = file.try_clone()?;
994 Ok(file.into())
995 }),
996 _ => Ok(std::process::Stdio::inherit()),
997 }
998 }
999
1000 fn backing_fd(self: Rc<Self>) -> Option<ResourceHandleFd> {
1001 Some(self.handle)
1002 }
1003}
1004
1005#[op2(fast)]
1007pub fn op_print(
1008 state: &mut OpState,
1009 #[string] msg: &str,
1010 is_err: bool,
1011) -> Result<(), JsErrorBox> {
1012 let rid = if is_err { 2 } else { 1 };
1013 FileResource::with_file(state, rid, move |file| {
1014 file
1015 .write_all_sync(msg.as_bytes())
1016 .map_err(JsErrorBox::from_err)
1017 })
1018}