1use crate::{
2 DirEntry, FileDescriptor, FileType, FsError, Metadata, OpenOptions, OpenOptionsConfig, ReadDir,
3 Result, VirtualFile,
4};
5#[cfg(feature = "enable-serde")]
6use serde::{de, Deserialize, Serialize};
7use std::convert::TryInto;
8use std::fs;
9use std::io::{self, Read, Seek, Write};
10#[cfg(unix)]
11use std::os::unix::io::{AsRawFd, RawFd};
12#[cfg(windows)]
13use std::os::windows::io::{AsRawHandle, RawHandle};
14use std::path::{Path, PathBuf};
15use std::time::{SystemTime, UNIX_EPOCH};
16use tracing::debug;
17
18trait TryIntoFileDescriptor {
19 type Error;
20
21 fn try_into_filedescriptor(&self) -> std::result::Result<FileDescriptor, Self::Error>;
22}
23
24#[cfg(unix)]
25impl<T> TryIntoFileDescriptor for T
26where
27 T: AsRawFd,
28{
29 type Error = FsError;
30
31 fn try_into_filedescriptor(&self) -> std::result::Result<FileDescriptor, Self::Error> {
32 Ok(FileDescriptor(
33 self.as_raw_fd()
34 .try_into()
35 .map_err(|_| FsError::InvalidFd)?,
36 ))
37 }
38}
39
40#[cfg(unix)]
41impl TryInto<RawFd> for FileDescriptor {
42 type Error = FsError;
43
44 fn try_into(self) -> std::result::Result<RawFd, Self::Error> {
45 self.0.try_into().map_err(|_| FsError::InvalidFd)
46 }
47}
48
49#[cfg(windows)]
50impl<T> TryIntoFileDescriptor for T
51where
52 T: AsRawHandle,
53{
54 type Error = FsError;
55
56 fn try_into_filedescriptor(&self) -> std::result::Result<FileDescriptor, Self::Error> {
57 Ok(FileDescriptor(self.as_raw_handle() as usize))
58 }
59}
60
61#[cfg(windows)]
62impl TryInto<RawHandle> for FileDescriptor {
63 type Error = FsError;
64
65 fn try_into(self) -> std::result::Result<RawHandle, Self::Error> {
66 Ok(self.0 as RawHandle)
67 }
68}
69
70#[derive(Debug, Default, Clone)]
71#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
72pub struct FileSystem;
73
74impl crate::FileSystem for FileSystem {
75 fn read_dir(&self, path: &Path) -> Result<ReadDir> {
76 let read_dir = fs::read_dir(path)?;
77 let data = read_dir
78 .map(|entry| {
79 let entry = entry?;
80 let metadata = entry.metadata()?;
81 Ok(DirEntry {
82 path: entry.path(),
83 metadata: Ok(metadata.try_into()?),
84 })
85 })
86 .collect::<std::result::Result<Vec<DirEntry>, io::Error>>()
87 .map_err::<FsError, _>(Into::into)?;
88 Ok(ReadDir::new(data))
89 }
90
91 fn create_dir(&self, path: &Path) -> Result<()> {
92 fs::create_dir(path).map_err(Into::into)
93 }
94
95 fn remove_dir(&self, path: &Path) -> Result<()> {
96 fs::remove_dir(path).map_err(Into::into)
97 }
98
99 fn rename(&self, from: &Path, to: &Path) -> Result<()> {
100 fs::rename(from, to).map_err(Into::into)
101 }
102
103 fn remove_file(&self, path: &Path) -> Result<()> {
104 fs::remove_file(path).map_err(Into::into)
105 }
106
107 fn new_open_options(&self) -> OpenOptions {
108 OpenOptions::new(Box::new(FileOpener))
109 }
110
111 fn metadata(&self, path: &Path) -> Result<Metadata> {
112 fs::metadata(path)
113 .and_then(TryInto::try_into)
114 .map_err(Into::into)
115 }
116}
117
118impl TryInto<Metadata> for fs::Metadata {
119 type Error = io::Error;
120
121 fn try_into(self) -> std::result::Result<Metadata, Self::Error> {
122 let filetype = self.file_type();
123 let (char_device, block_device, socket, fifo) = {
124 #[cfg(unix)]
125 {
126 use std::os::unix::fs::FileTypeExt;
127 (
128 filetype.is_char_device(),
129 filetype.is_block_device(),
130 filetype.is_socket(),
131 filetype.is_fifo(),
132 )
133 }
134 #[cfg(not(unix))]
135 {
136 (false, false, false, false)
137 }
138 };
139
140 Ok(Metadata {
141 ft: FileType {
142 dir: filetype.is_dir(),
143 file: filetype.is_file(),
144 symlink: filetype.is_symlink(),
145 char_device,
146 block_device,
147 socket,
148 fifo,
149 },
150 accessed: self
151 .accessed()
152 .and_then(|time| {
153 time.duration_since(UNIX_EPOCH)
154 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
155 })
156 .map_or(0, |time| time.as_nanos() as u64),
157 created: self
158 .created()
159 .and_then(|time| {
160 time.duration_since(UNIX_EPOCH)
161 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
162 })
163 .map_or(0, |time| time.as_nanos() as u64),
164 modified: self
165 .modified()
166 .and_then(|time| {
167 time.duration_since(UNIX_EPOCH)
168 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
169 })
170 .map_or(0, |time| time.as_nanos() as u64),
171 len: self.len(),
172 })
173 }
174}
175
176#[derive(Debug, Clone)]
177pub struct FileOpener;
178
179impl crate::FileOpener for FileOpener {
180 fn open(
181 &mut self,
182 path: &Path,
183 conf: &OpenOptionsConfig,
184 ) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> {
185 let read = conf.read();
187 let write = conf.write();
188 let append = conf.append();
189 let mut oo = fs::OpenOptions::new();
190 oo.read(conf.read())
191 .write(conf.write())
192 .create_new(conf.create_new())
193 .create(conf.create())
194 .append(conf.append())
195 .truncate(conf.truncate())
196 .open(path)
197 .map_err(Into::into)
198 .map(|file| {
199 Box::new(File::new(file, path.to_owned(), read, write, append))
200 as Box<dyn VirtualFile + Send + Sync + 'static>
201 })
202 }
203}
204
205#[derive(Debug)]
207#[cfg_attr(feature = "enable-serde", derive(Serialize))]
208pub struct File {
209 #[cfg_attr(feature = "enable-serde", serde(skip_serializing))]
210 pub inner: fs::File,
211 pub host_path: PathBuf,
212 #[cfg(feature = "enable-serde")]
213 flags: u16,
214}
215
216#[cfg(feature = "enable-serde")]
217impl<'de> Deserialize<'de> for File {
218 fn deserialize<D>(deserializer: D) -> std::result::Result<File, D::Error>
219 where
220 D: serde::Deserializer<'de>,
221 {
222 #[derive(Deserialize)]
223 #[serde(field_identifier, rename_all = "snake_case")]
224 enum Field {
225 HostPath,
226 Flags,
227 }
228
229 struct FileVisitor;
230
231 impl<'de> de::Visitor<'de> for FileVisitor {
232 type Value = File;
233
234 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
235 formatter.write_str("struct File")
236 }
237
238 fn visit_seq<V>(self, mut seq: V) -> std::result::Result<Self::Value, V::Error>
239 where
240 V: de::SeqAccess<'de>,
241 {
242 let host_path = seq
243 .next_element()?
244 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
245 let flags = seq
246 .next_element()?
247 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
248 let inner = fs::OpenOptions::new()
249 .read(flags & File::READ != 0)
250 .write(flags & File::WRITE != 0)
251 .append(flags & File::APPEND != 0)
252 .open(&host_path)
253 .map_err(|_| de::Error::custom("Could not open file on this system"))?;
254 Ok(File {
255 inner,
256 host_path,
257 flags,
258 })
259 }
260
261 fn visit_map<V>(self, mut map: V) -> std::result::Result<Self::Value, V::Error>
262 where
263 V: de::MapAccess<'de>,
264 {
265 let mut host_path = None;
266 let mut flags = None;
267 while let Some(key) = map.next_key()? {
268 match key {
269 Field::HostPath => {
270 if host_path.is_some() {
271 return Err(de::Error::duplicate_field("host_path"));
272 }
273 host_path = Some(map.next_value()?);
274 }
275 Field::Flags => {
276 if flags.is_some() {
277 return Err(de::Error::duplicate_field("flags"));
278 }
279 flags = Some(map.next_value()?);
280 }
281 }
282 }
283 let host_path = host_path.ok_or_else(|| de::Error::missing_field("host_path"))?;
284 let flags = flags.ok_or_else(|| de::Error::missing_field("flags"))?;
285 let inner = fs::OpenOptions::new()
286 .read(flags & File::READ != 0)
287 .write(flags & File::WRITE != 0)
288 .append(flags & File::APPEND != 0)
289 .open(&host_path)
290 .map_err(|_| de::Error::custom("Could not open file on this system"))?;
291 Ok(File {
292 inner,
293 host_path,
294 flags,
295 })
296 }
297 }
298
299 const FIELDS: &[&str] = &["host_path", "flags"];
300 deserializer.deserialize_struct("File", FIELDS, FileVisitor)
301 }
302}
303
304impl File {
305 const READ: u16 = 1;
306 const WRITE: u16 = 2;
307 const APPEND: u16 = 4;
308
309 pub fn new(file: fs::File, host_path: PathBuf, read: bool, write: bool, append: bool) -> Self {
311 let mut _flags = 0;
312
313 if read {
314 _flags |= Self::READ;
315 }
316
317 if write {
318 _flags |= Self::WRITE;
319 }
320
321 if append {
322 _flags |= Self::APPEND;
323 }
324
325 Self {
326 inner: file,
327 host_path,
328 #[cfg(feature = "enable-serde")]
329 flags: _flags,
330 }
331 }
332
333 pub fn metadata(&self) -> fs::Metadata {
334 self.inner.metadata().unwrap()
335 }
336}
337
338impl Read for File {
339 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
340 self.inner.read(buf)
341 }
342
343 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
344 self.inner.read_to_end(buf)
345 }
346
347 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
348 self.inner.read_to_string(buf)
349 }
350
351 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
352 self.inner.read_exact(buf)
353 }
354}
355
356impl Seek for File {
357 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
358 self.inner.seek(pos)
359 }
360}
361
362impl Write for File {
363 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
364 self.inner.write(buf)
365 }
366
367 fn flush(&mut self) -> io::Result<()> {
368 self.inner.flush()
369 }
370
371 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
372 self.inner.write_all(buf)
373 }
374
375 fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
376 self.inner.write_fmt(fmt)
377 }
378}
379
380impl VirtualFile for File {
382 fn last_accessed(&self) -> u64 {
383 self.metadata()
384 .accessed()
385 .ok()
386 .and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
387 .map(|ct| ct.as_nanos() as u64)
388 .unwrap_or(0)
389 }
390
391 fn last_modified(&self) -> u64 {
392 self.metadata()
393 .modified()
394 .ok()
395 .and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
396 .map(|ct| ct.as_nanos() as u64)
397 .unwrap_or(0)
398 }
399
400 fn created_time(&self) -> u64 {
401 self.metadata()
402 .created()
403 .ok()
404 .and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
405 .map(|ct| ct.as_nanos() as u64)
406 .unwrap_or(0)
407 }
408
409 fn size(&self) -> u64 {
410 self.metadata().len()
411 }
412
413 fn set_len(&mut self, new_size: u64) -> Result<()> {
414 fs::File::set_len(&self.inner, new_size).map_err(Into::into)
415 }
416
417 fn unlink(&mut self) -> Result<()> {
418 fs::remove_file(&self.host_path).map_err(Into::into)
419 }
420 fn sync_to_disk(&self) -> Result<()> {
421 self.inner.sync_all().map_err(Into::into)
422 }
423
424 fn bytes_available(&self) -> Result<usize> {
425 host_file_bytes_available(self.inner.try_into_filedescriptor()?)
426 }
427}
428
429#[cfg(unix)]
430fn host_file_bytes_available(host_fd: FileDescriptor) -> Result<usize> {
431 let mut bytes_found: libc::c_int = 0;
432 let result = unsafe { libc::ioctl(host_fd.try_into()?, libc::FIONREAD, &mut bytes_found) };
433
434 match result {
435 0 => Ok(bytes_found.try_into().unwrap_or(0)),
437 libc::EBADF => Err(FsError::InvalidFd),
438 libc::EFAULT => Err(FsError::InvalidData),
439 libc::EINVAL => Err(FsError::InvalidInput),
440 _ => Err(FsError::IOError),
441 }
442}
443
444#[cfg(not(unix))]
445fn host_file_bytes_available(_host_fd: FileDescriptor) -> Result<usize> {
446 unimplemented!("host_file_bytes_available not yet implemented for non-Unix-like targets. This probably means the program tried to use wasi::poll_oneoff")
447}
448
449#[derive(Debug, Default)]
452#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
453pub struct Stdout;
454
455impl Read for Stdout {
456 fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
457 Err(io::Error::new(
458 io::ErrorKind::Other,
459 "can not read from stdout",
460 ))
461 }
462
463 fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
464 Err(io::Error::new(
465 io::ErrorKind::Other,
466 "can not read from stdout",
467 ))
468 }
469
470 fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
471 Err(io::Error::new(
472 io::ErrorKind::Other,
473 "can not read from stdout",
474 ))
475 }
476
477 fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> {
478 Err(io::Error::new(
479 io::ErrorKind::Other,
480 "can not read from stdout",
481 ))
482 }
483}
484
485impl Seek for Stdout {
486 fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
487 Err(io::Error::new(io::ErrorKind::Other, "can not seek stdout"))
488 }
489}
490
491impl Write for Stdout {
492 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
493 io::stdout().write(buf)
494 }
495
496 fn flush(&mut self) -> io::Result<()> {
497 io::stdout().flush()
498 }
499
500 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
501 io::stdout().write_all(buf)
502 }
503
504 fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
505 io::stdout().write_fmt(fmt)
506 }
507}
508
509impl VirtualFile for Stdout {
511 fn last_accessed(&self) -> u64 {
512 0
513 }
514
515 fn last_modified(&self) -> u64 {
516 0
517 }
518
519 fn created_time(&self) -> u64 {
520 0
521 }
522
523 fn size(&self) -> u64 {
524 0
525 }
526
527 fn set_len(&mut self, _new_size: u64) -> Result<()> {
528 debug!("Calling VirtualFile::set_len on stdout; this is probably a bug");
529 Err(FsError::PermissionDenied)
530 }
531
532 fn unlink(&mut self) -> Result<()> {
533 Ok(())
534 }
535
536 fn bytes_available(&self) -> Result<usize> {
537 host_file_bytes_available(io::stdout().try_into_filedescriptor()?)
538 }
539
540 fn get_fd(&self) -> Option<FileDescriptor> {
541 io::stdout().try_into_filedescriptor().ok()
542 }
543}
544
545#[derive(Debug, Default)]
548#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
549pub struct Stderr;
550
551impl Read for Stderr {
552 fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
553 Err(io::Error::new(
554 io::ErrorKind::Other,
555 "can not read from stderr",
556 ))
557 }
558
559 fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
560 Err(io::Error::new(
561 io::ErrorKind::Other,
562 "can not read from stderr",
563 ))
564 }
565
566 fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
567 Err(io::Error::new(
568 io::ErrorKind::Other,
569 "can not read from stderr",
570 ))
571 }
572
573 fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> {
574 Err(io::Error::new(
575 io::ErrorKind::Other,
576 "can not read from stderr",
577 ))
578 }
579}
580
581impl Seek for Stderr {
582 fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
583 Err(io::Error::new(io::ErrorKind::Other, "can not seek stderr"))
584 }
585}
586
587impl Write for Stderr {
588 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
589 io::stderr().write(buf)
590 }
591
592 fn flush(&mut self) -> io::Result<()> {
593 io::stderr().flush()
594 }
595
596 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
597 io::stderr().write_all(buf)
598 }
599
600 fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
601 io::stderr().write_fmt(fmt)
602 }
603}
604
605impl VirtualFile for Stderr {
607 fn last_accessed(&self) -> u64 {
608 0
609 }
610
611 fn last_modified(&self) -> u64 {
612 0
613 }
614
615 fn created_time(&self) -> u64 {
616 0
617 }
618
619 fn size(&self) -> u64 {
620 0
621 }
622
623 fn set_len(&mut self, _new_size: u64) -> Result<()> {
624 debug!("Calling VirtualFile::set_len on stderr; this is probably a bug");
625 Err(FsError::PermissionDenied)
626 }
627
628 fn unlink(&mut self) -> Result<()> {
629 Ok(())
630 }
631
632 fn bytes_available(&self) -> Result<usize> {
633 host_file_bytes_available(io::stderr().try_into_filedescriptor()?)
634 }
635
636 fn get_fd(&self) -> Option<FileDescriptor> {
637 io::stderr().try_into_filedescriptor().ok()
638 }
639}
640
641#[derive(Debug, Default)]
644#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
645pub struct Stdin;
646impl Read for Stdin {
647 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
648 io::stdin().read(buf)
649 }
650
651 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
652 io::stdin().read_to_end(buf)
653 }
654
655 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
656 io::stdin().read_to_string(buf)
657 }
658
659 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
660 io::stdin().read_exact(buf)
661 }
662}
663
664impl Seek for Stdin {
665 fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
666 Err(io::Error::new(io::ErrorKind::Other, "can not seek stdin"))
667 }
668}
669
670impl Write for Stdin {
671 fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
672 Err(io::Error::new(
673 io::ErrorKind::Other,
674 "can not write to stdin",
675 ))
676 }
677
678 fn flush(&mut self) -> io::Result<()> {
679 Err(io::Error::new(
680 io::ErrorKind::Other,
681 "can not write to stdin",
682 ))
683 }
684
685 fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
686 Err(io::Error::new(
687 io::ErrorKind::Other,
688 "can not write to stdin",
689 ))
690 }
691
692 fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> {
693 Err(io::Error::new(
694 io::ErrorKind::Other,
695 "can not write to stdin",
696 ))
697 }
698}
699
700impl VirtualFile for Stdin {
702 fn last_accessed(&self) -> u64 {
703 0
704 }
705
706 fn last_modified(&self) -> u64 {
707 0
708 }
709
710 fn created_time(&self) -> u64 {
711 0
712 }
713
714 fn size(&self) -> u64 {
715 0
716 }
717
718 fn set_len(&mut self, _new_size: u64) -> Result<()> {
719 debug!("Calling VirtualFile::set_len on stdin; this is probably a bug");
720 Err(FsError::PermissionDenied)
721 }
722
723 fn unlink(&mut self) -> Result<()> {
724 Ok(())
725 }
726
727 fn bytes_available(&self) -> Result<usize> {
728 host_file_bytes_available(io::stdin().try_into_filedescriptor()?)
729 }
730
731 fn get_fd(&self) -> Option<FileDescriptor> {
732 io::stdin().try_into_filedescriptor().ok()
733 }
734}