From f211130a57fda8a61b578a63cd86594a0d6a4503 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 16 Aug 2021 17:16:20 +0200 Subject: [PATCH 1/4] feat(vfs) Unified API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, this patch contains multiple features. First off, it renames the types from `host_fs` and `mem_fs` so that they use the same names. Apart from the module name, the types owned by the module are the same, which simplifies the usage greatly. Second, the code has been cleaned up a little bit. The more important clean up is probably the renaming of `MemKind` to `Node`. It's OK to do that here, because the code is not released yet. Third, a new `FileDescriptor` type is introduced. It represents a “generic” file descriptor, that a `VirtualFile` can hold. It contains a value with the size of the larger size a file descriptor on any platform, namely on Windows where a file descriptor is the size of a pointer (compared to Unix where it's a `i32`). Then a bunch of `TryInto` implementations are written to convert it to `RawFd` (on Unix) or `RawHandle` (on Windows). I'm not confident it's the best design for the moment, but it's better than before where Windows file descriptors were impossible to represent. Note that we cannot make `FileDescriptor` generic over the system for 2 reasons 1. We can activate multiple file systems at the same time, so the representation of a file descriptor can change between file system, 2. If we make `FileDescriptor` generic, then the size of `dyn VirtualFile` is unknown at compile-time, which makes impossible to use in `wasmer-wasi`, hence this design decision of taking the larger possible size for a file descriptor so that it fits all scenarios. --- lib/vfs/src/host_fs.rs | 136 +++++++++++++++++++++++------------------ lib/vfs/src/lib.rs | 7 ++- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index af060173b14..4c7d0d52eb3 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -4,9 +4,65 @@ use serde::{de, Deserialize, Serialize}; use std::convert::TryInto; use std::fs; use std::io::{Read, Seek, Write}; +#[cfg(unix)] +use std::os::unix::io::{AsRawFd, RawFd}; +#[cfg(windows)] +use std::os::windows::io::{AsRawHandle, RawHandle}; use std::path::{Path, PathBuf}; use std::time::SystemTime; +impl FileDescriptor { + #[cfg(unix)] + fn as_raw(&self) -> Result { + self.inner.try_into().map_err(|_| FsError::InvalidFd) + } + + #[cfg(windows)] + fn as_raw(&self) -> Result { + self.inner.try_into().map_err(|_| FsError::InvalidFd) + } +} + +trait TryIntoFileDescriptor { + type Error; + + fn try_into_filedescriptor(&self) -> Result; +} + +#[cfg(unix)] +impl TryIntoFileDescriptor for T +where + T: AsRawFd, +{ + type Error = FsError; + + fn try_into_filedescriptor(&self) -> Result { + Ok(FileDescriptor { + inner: self + .as_raw_fd() + .try_into() + .map_err(|_| FsError::InvalidFd)?, + }) + } +} + +#[cfg(windows)] +impl TryIntoFileDescriptor for T +where + T: AsRawHandle, +{ + type Error = FsError; + + fn try_into_filedescriptor(&self) -> Result { + Ok(FileDescriptor { + inner: self + .as_raw_handle() + .try_into() + .map_err(|_| FsError::InvalidFd)?, + }) + } +} + #[derive(Debug, Default, Clone)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct HostFileSystem; @@ -336,29 +392,14 @@ impl VirtualFile for HostFile { } fn bytes_available(&self) -> Result { - // unwrap is safe because of get_raw_fd implementation - let host_fd = self.get_raw_fd().unwrap(); - - host_file_bytes_available(host_fd) - } - - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { - use std::os::unix::io::AsRawFd; - Some(self.inner.as_raw_fd()) - } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { - unimplemented!( - "HostFile::get_raw_fd in VirtualFile is not implemented for non-Unix-like targets yet" - ); + host_file_bytes_available(self.inner.try_into_filedescriptor()?) } } #[cfg(unix)] -fn host_file_bytes_available(host_fd: i32) -> Result { +fn host_file_bytes_available(host_fd: FileDescriptor) -> Result { let mut bytes_found = 0 as libc::c_int; - let result = unsafe { libc::ioctl(host_fd, libc::FIONREAD, &mut bytes_found) }; + let result = unsafe { libc::ioctl(host_fd.as_raw()?, libc::FIONREAD, &mut bytes_found) }; match result { // success @@ -371,7 +412,7 @@ fn host_file_bytes_available(host_fd: i32) -> Result { } #[cfg(not(unix))] -fn host_file_bytes_available(_raw_fd: i32) -> Result { +fn host_file_bytes_available(_host_fd: FileDescriptor) -> Result { unimplemented!("host_file_bytes_available not yet implemented for non-Unix-like targets. This probably means the program tried to use wasi::poll_oneoff") } @@ -448,21 +489,12 @@ impl VirtualFile for Stdout { Ok(()) } fn bytes_available(&self) -> Result { - // unwrap is safe because of get_raw_fd implementation - let host_fd = self.get_raw_fd().unwrap(); - - host_file_bytes_available(host_fd) + // SAFETY: We can call `unwrap` because we are sure + // `Self::get_fd` returns `Some` value. + host_file_bytes_available(self.get_fd().unwrap()?) } - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { - use std::os::unix::io::AsRawFd; - Some(io::stdout().as_raw_fd()) - } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { - unimplemented!( - "Stdout::get_raw_fd in VirtualFile is not implemented for non-Unix-like targets yet" - ); + fn get_fd(&self) -> Option> { + Some(io::stdout().try_into_filedescriptor()) } } @@ -539,21 +571,12 @@ impl VirtualFile for Stderr { Ok(()) } fn bytes_available(&self) -> Result { - // unwrap is safe because of get_raw_fd implementation - let host_fd = self.get_raw_fd().unwrap(); - - host_file_bytes_available(host_fd) + // SAFETY: We can call `unwrap` because we are sure + // `Self::get_fd` returns `Some` value. + host_file_bytes_available(self.get_fd().unwrap()?) } - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { - use std::os::unix::io::AsRawFd; - Some(io::stderr().as_raw_fd()) - } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { - unimplemented!( - "Stderr::get_raw_fd in VirtualFile is not implemented for non-Unix-like targets yet" - ); + fn get_fd(&self) -> Option> { + Some(io::stderr().try_into_filedescriptor()) } } @@ -630,20 +653,11 @@ impl VirtualFile for Stdin { Ok(()) } fn bytes_available(&self) -> Result { - // unwrap is safe because of get_raw_fd implementation - let host_fd = self.get_raw_fd().unwrap(); - - host_file_bytes_available(host_fd) + // SAFETY: We can call `unwrap` because we are sure + // `Self::get_fd` returns `Some` value. + host_file_bytes_available(self.get_fd().unwrap()?) } - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { - use std::os::unix::io::AsRawFd; - Some(io::stdin().as_raw_fd()) - } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { - unimplemented!( - "Stdin::get_raw_fd in VirtualFile is not implemented for non-Unix-like targets yet" - ); + fn get_fd(&self) -> Option> { + Some(io::stdin().try_into_filedescriptor()) } } diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 601a8d7915c..2b82c62ad1a 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -12,6 +12,11 @@ pub mod host_fs; #[cfg(feature = "mem_fs")] pub mod mem_fs; +#[repr(transparent)] +pub struct FileDescriptor { + inner: usize, +} + pub trait FileSystem: fmt::Debug + Send + Sync + 'static { fn read_dir(&self, path: &Path) -> Result; fn create_dir(&self, path: &Path) -> Result<(), FsError>; @@ -163,7 +168,7 @@ pub trait VirtualFile: fmt::Debug + Send + Write + Read + Seek + 'static + Upcas /// Used for polling. Default returns `None` because this method cannot be implemented for most types /// Returns the underlying host fd - fn get_raw_fd(&self) -> Option { + fn get_fd(&self) -> Option> { None } } From ab83efebe3843725f570bc432a4f18ca2da027f6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 17 Aug 2021 14:15:51 +0200 Subject: [PATCH 2/4] Fix merge conflict. --- lib/vfs/src/host_fs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index eb23177d1f0..62d7ce871fc 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -4,7 +4,6 @@ use serde::{de, Deserialize, Serialize}; use std::convert::TryInto; use std::fs; use std::io::{self, Read, Seek, Write}; -use std::io::{Read, Seek, Write}; #[cfg(unix)] use std::os::unix::io::{AsRawFd, RawFd}; #[cfg(windows)] From 9e6c07dd9a0064674b15a12ce47e68b77af23ea2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 17 Aug 2021 14:44:09 +0200 Subject: [PATCH 3/4] Fix merge conflict. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When rebasing, Git losts some of the commit. Here is a bunch of them in a single commit… To learn more, see https://github.com/wasmerio/wasmer/pull/2528/commits/f211130a57fda8a61b578a63cd86594a0d6a4503. --- lib/vfs/src/host_fs.rs | 238 ++++++++++++++--------- lib/vfs/src/lib.rs | 54 +++--- lib/vfs/src/mem_fs.rs | 420 +++++++++++++++++++++++------------------ 3 files changed, 409 insertions(+), 303 deletions(-) diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index 62d7ce871fc..64f6454973e 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -1,4 +1,7 @@ -use crate::*; +use crate::{ + DirEntry, FileDescriptor, FileType, FsError, Metadata, OpenOptions, OpenOptionsConfig, ReadDir, + Result, VirtualFile, +}; #[cfg(feature = "enable-serde")] use serde::{de, Deserialize, Serialize}; use std::convert::TryInto; @@ -10,23 +13,12 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::os::windows::io::{AsRawHandle, RawHandle}; use std::path::{Path, PathBuf}; use std::time::{SystemTime, UNIX_EPOCH}; - -impl FileDescriptor { - #[cfg(unix)] - fn as_raw(&self) -> Result { - self.inner.try_into().map_err(|_| FsError::InvalidFd) - } - - #[cfg(windows)] - fn as_raw(&self) -> Result { - self.inner.try_into().map_err(|_| FsError::InvalidFd) - } -} +use tracing::debug; trait TryIntoFileDescriptor { type Error; - fn try_into_filedescriptor(&self) -> Result; + fn try_into_filedescriptor(&self) -> std::result::Result; } #[cfg(unix)] @@ -36,7 +28,7 @@ where { type Error = FsError; - fn try_into_filedescriptor(&self) -> Result { + fn try_into_filedescriptor(&self) -> std::result::Result { Ok(FileDescriptor { inner: self .as_raw_fd() @@ -46,6 +38,15 @@ where } } +#[cfg(unix)] +impl TryInto for FileDescriptor { + type Error = FsError; + + fn try_into(self) -> std::result::Result { + self.inner.try_into().map_err(|_| FsError::InvalidFd) + } +} + #[cfg(windows)] impl TryIntoFileDescriptor for T where @@ -63,15 +64,24 @@ where } } +#[cfg(windows)] +impl TryInto for FileDescriptor { + type Error = FsError; + + fn try_into(self) -> std::result::Result { + self.inner.try_into().map_err(|_| FsError::InvalidFd) + } +} + #[derive(Debug, Default, Clone)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct HostFileSystem; +pub struct FileSystem; -impl FileSystem for HostFileSystem { - fn read_dir(&self, path: &Path) -> Result { +impl crate::FileSystem for FileSystem { + fn read_dir(&self, path: &Path) -> Result { let read_dir = fs::read_dir(path)?; let data = read_dir - .map(|entry| -> Result { + .map(|entry| { let entry = entry?; let metadata = entry.metadata()?; Ok(DirEntry { @@ -79,29 +89,32 @@ impl FileSystem for HostFileSystem { metadata: Ok(metadata.try_into()?), }) }) - .collect::, io::Error>>() + .collect::, io::Error>>() .map_err::(Into::into)?; Ok(ReadDir::new(data)) } - fn create_dir(&self, path: &Path) -> Result<(), FsError> { + + fn create_dir(&self, path: &Path) -> Result<()> { fs::create_dir(path).map_err(Into::into) } - fn remove_dir(&self, path: &Path) -> Result<(), FsError> { + + fn remove_dir(&self, path: &Path) -> Result<()> { fs::remove_dir(path).map_err(Into::into) } - fn rename(&self, from: &Path, to: &Path) -> Result<(), FsError> { + + fn rename(&self, from: &Path, to: &Path) -> Result<()> { fs::rename(from, to).map_err(Into::into) } - fn remove_file(&self, path: &Path) -> Result<(), FsError> { + fn remove_file(&self, path: &Path) -> Result<()> { fs::remove_file(path).map_err(Into::into) } fn new_open_options(&self) -> OpenOptions { - OpenOptions::new(Box::new(HostFileOpener)) + OpenOptions::new(Box::new(FileOpener)) } - fn metadata(&self, path: &Path) -> Result { + fn metadata(&self, path: &Path) -> Result { fs::metadata(path) .and_then(TryInto::try_into) .map_err(Into::into) @@ -111,7 +124,7 @@ impl FileSystem for HostFileSystem { impl TryInto for fs::Metadata { type Error = io::Error; - fn try_into(self) -> Result { + fn try_into(self) -> std::result::Result { let filetype = self.file_type(); let (char_device, block_device, socket, fifo) = { #[cfg(unix)] @@ -161,14 +174,10 @@ impl TryInto for fs::Metadata { } #[derive(Debug, Clone)] -pub struct HostFileOpener; - -impl FileOpener for HostFileOpener { - fn open( - &mut self, - path: &Path, - conf: &OpenOptionsConfig, - ) -> Result, FsError> { +pub struct FileOpener; + +impl crate::FileOpener for FileOpener { + fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { // TODO: handle create implying write, etc. let read = conf.read(); let write = conf.write(); @@ -183,7 +192,7 @@ impl FileOpener for HostFileOpener { .open(path) .map_err(Into::into) .map(|file| { - Box::new(HostFile::new(file, path.to_owned(), read, write, append)) + Box::new(File::new(file, path.to_owned(), read, write, append)) as Box }) } @@ -192,7 +201,7 @@ impl FileOpener for HostFileOpener { /// A thin wrapper around `std::fs::File` #[derive(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize))] -pub struct HostFile { +pub struct File { #[cfg_attr(feature = "enable-serde", serde(skip_serializing))] pub inner: fs::File, pub host_path: PathBuf, @@ -200,8 +209,8 @@ pub struct HostFile { } #[cfg(feature = "enable-serde")] -impl<'de> Deserialize<'de> for HostFile { - fn deserialize(deserializer: D) -> Result +impl<'de> Deserialize<'de> for File { + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { @@ -212,13 +221,13 @@ impl<'de> Deserialize<'de> for HostFile { Flags, } - struct HostFileVisitor; + struct FileVisitor; - impl<'de> de::Visitor<'de> for HostFileVisitor { - type Value = HostFile; + impl<'de> de::Visitor<'de> for FileVisitor { + type Value = File; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("struct HostFile") + formatter.write_str("struct File") } fn visit_seq(self, mut seq: V) -> Result @@ -232,12 +241,12 @@ impl<'de> Deserialize<'de> for HostFile { .next_element()? .ok_or_else(|| de::Error::invalid_length(1, &self))?; let inner = fs::OpenOptions::new() - .read(flags & HostFile::READ != 0) - .write(flags & HostFile::WRITE != 0) - .append(flags & HostFile::APPEND != 0) + .read(flags & File::READ != 0) + .write(flags & File::WRITE != 0) + .append(flags & File::APPEND != 0) .open(&host_path) .map_err(|_| de::Error::custom("Could not open file on this system"))?; - Ok(HostFile { + Ok(File { inner, host_path, flags, @@ -269,12 +278,12 @@ impl<'de> Deserialize<'de> for HostFile { let host_path = host_path.ok_or_else(|| de::Error::missing_field("host_path"))?; let flags = flags.ok_or_else(|| de::Error::missing_field("flags"))?; let inner = fs::OpenOptions::new() - .read(flags & HostFile::READ != 0) - .write(flags & HostFile::WRITE != 0) - .append(flags & HostFile::APPEND != 0) + .read(flags & File::READ != 0) + .write(flags & File::WRITE != 0) + .append(flags & File::APPEND != 0) .open(&host_path) .map_err(|_| de::Error::custom("Could not open file on this system"))?; - Ok(HostFile { + Ok(File { inner, host_path, flags, @@ -283,11 +292,11 @@ impl<'de> Deserialize<'de> for HostFile { } const FIELDS: &[&str] = &["host_path", "flags"]; - deserializer.deserialize_struct("HostFile", FIELDS, HostFileVisitor) + deserializer.deserialize_struct("File", FIELDS, FileVisitor) } } -impl HostFile { +impl File { const READ: u16 = 1; const WRITE: u16 = 2; const APPEND: u16 = 4; @@ -295,15 +304,19 @@ impl HostFile { /// creates a new host file from a `std::fs::File` and a path pub fn new(file: fs::File, host_path: PathBuf, read: bool, write: bool, append: bool) -> Self { let mut flags = 0; + if read { flags |= Self::READ; } + if write { flags |= Self::WRITE; } + if append { flags |= Self::APPEND; } + Self { inner: file, host_path, @@ -316,42 +329,50 @@ impl HostFile { } } -impl Read for HostFile { +impl Read for File { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.inner.read_to_end(buf) } + fn read_to_string(&mut self, buf: &mut String) -> io::Result { self.inner.read_to_string(buf) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.inner.read_exact(buf) } } -impl Seek for HostFile { + +impl Seek for File { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { self.inner.seek(pos) } } -impl Write for HostFile { + +impl Write for File { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.inner.write_all(buf) } + fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> { self.inner.write_fmt(fmt) } } #[cfg_attr(feature = "enable-serde", typetag::serde)] -impl VirtualFile for HostFile { +impl VirtualFile for File { fn last_accessed(&self) -> u64 { self.metadata() .accessed() @@ -383,26 +404,26 @@ impl VirtualFile for HostFile { self.metadata().len() } - fn set_len(&mut self, new_size: u64) -> Result<(), FsError> { + fn set_len(&mut self, new_size: u64) -> Result<()> { fs::File::set_len(&self.inner, new_size).map_err(Into::into) } - fn unlink(&mut self) -> Result<(), FsError> { + fn unlink(&mut self) -> Result<()> { fs::remove_file(&self.host_path).map_err(Into::into) } - fn sync_to_disk(&self) -> Result<(), FsError> { + fn sync_to_disk(&self) -> Result<()> { self.inner.sync_all().map_err(Into::into) } - fn bytes_available(&self) -> Result { + fn bytes_available(&self) -> Result { host_file_bytes_available(self.inner.try_into_filedescriptor()?) } } #[cfg(unix)] -fn host_file_bytes_available(host_fd: FileDescriptor) -> Result { +fn host_file_bytes_available(host_fd: FileDescriptor) -> Result { let mut bytes_found = 0 as libc::c_int; - let result = unsafe { libc::ioctl(host_fd.as_raw()?, libc::FIONREAD, &mut bytes_found) }; + let result = unsafe { libc::ioctl(host_fd.try_into()?, libc::FIONREAD, &mut bytes_found) }; match result { // success @@ -415,7 +436,7 @@ fn host_file_bytes_available(host_fd: FileDescriptor) -> Result } #[cfg(not(unix))] -fn host_file_bytes_available(_host_fd: FileDescriptor) -> Result { +fn host_file_bytes_available(_host_fd: FileDescriptor) -> Result { unimplemented!("host_file_bytes_available not yet implemented for non-Unix-like targets. This probably means the program tried to use wasi::poll_oneoff") } @@ -424,6 +445,7 @@ fn host_file_bytes_available(_host_fd: FileDescriptor) -> Result #[derive(Debug, Default)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Stdout; + impl Read for Stdout { fn read(&mut self, _buf: &mut [u8]) -> io::Result { Err(io::Error::new( @@ -431,18 +453,21 @@ impl Read for Stdout { "can not read from stdout", )) } + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stdout", )) } + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stdout", )) } + fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, @@ -450,21 +475,26 @@ impl Read for Stdout { )) } } + impl Seek for Stdout { fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "can not seek stdout")) } } + impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { io::stdout().write(buf) } + fn flush(&mut self) -> io::Result<()> { io::stdout().flush() } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { io::stdout().write_all(buf) } + fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> { io::stdout().write_fmt(fmt) } @@ -475,29 +505,34 @@ impl VirtualFile for Stdout { fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, _new_size: u64) -> Result<()> { debug!("Calling VirtualFile::set_len on stdout; this is probably a bug"); Err(FsError::PermissionDenied) } - fn unlink(&mut self) -> Result<(), FsError> { + + fn unlink(&mut self) -> Result<()> { Ok(()) } - fn bytes_available(&self) -> Result { - // SAFETY: We can call `unwrap` because we are sure - // `Self::get_fd` returns `Some` value. - host_file_bytes_available(self.get_fd().unwrap()?) + + fn bytes_available(&self) -> Result { + host_file_bytes_available(io::stdout().try_into_filedescriptor()?) } - fn get_fd(&self) -> Option> { - Some(io::stdout().try_into_filedescriptor()) + + fn get_fd(&self) -> Option { + io::stdout().try_into_filedescriptor().ok() } } @@ -506,6 +541,7 @@ impl VirtualFile for Stdout { #[derive(Debug, Default)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Stderr; + impl Read for Stderr { fn read(&mut self, _buf: &mut [u8]) -> io::Result { Err(io::Error::new( @@ -513,18 +549,21 @@ impl Read for Stderr { "can not read from stderr", )) } + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stderr", )) } + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stderr", )) } + fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, @@ -532,21 +571,26 @@ impl Read for Stderr { )) } } + impl Seek for Stderr { fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "can not seek stderr")) } } + impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { io::stderr().write(buf) } + fn flush(&mut self) -> io::Result<()> { io::stderr().flush() } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { io::stderr().write_all(buf) } + fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> { io::stderr().write_fmt(fmt) } @@ -557,29 +601,34 @@ impl VirtualFile for Stderr { fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, _new_size: u64) -> Result<()> { debug!("Calling VirtualFile::set_len on stderr; this is probably a bug"); Err(FsError::PermissionDenied) } - fn unlink(&mut self) -> Result<(), FsError> { + + fn unlink(&mut self) -> Result<()> { Ok(()) } - fn bytes_available(&self) -> Result { - // SAFETY: We can call `unwrap` because we are sure - // `Self::get_fd` returns `Some` value. - host_file_bytes_available(self.get_fd().unwrap()?) + + fn bytes_available(&self) -> Result { + host_file_bytes_available(io::stderr().try_into_filedescriptor()?) } - fn get_fd(&self) -> Option> { - Some(io::stderr().try_into_filedescriptor()) + + fn get_fd(&self) -> Option { + io::stderr().try_into_filedescriptor().ok() } } @@ -592,21 +641,26 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::stdin().read(buf) } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { io::stdin().read_to_end(buf) } + fn read_to_string(&mut self, buf: &mut String) -> io::Result { io::stdin().read_to_string(buf) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { io::stdin().read_exact(buf) } } + impl Seek for Stdin { fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "can not seek stdin")) } } + impl Write for Stdin { fn write(&mut self, _buf: &[u8]) -> io::Result { Err(io::Error::new( @@ -614,18 +668,21 @@ impl Write for Stdin { "can not write to stdin", )) } + fn flush(&mut self) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, "can not write to stdin", )) } + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, "can not write to stdin", )) } + fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, @@ -639,28 +696,33 @@ impl VirtualFile for Stdin { fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, _new_size: u64) -> Result<()> { debug!("Calling VirtualFile::set_len on stdin; this is probably a bug"); Err(FsError::PermissionDenied) } - fn unlink(&mut self) -> Result<(), FsError> { + + fn unlink(&mut self) -> Result<()> { Ok(()) } - fn bytes_available(&self) -> Result { - // SAFETY: We can call `unwrap` because we are sure - // `Self::get_fd` returns `Some` value. - host_file_bytes_available(self.get_fd().unwrap()?) + + fn bytes_available(&self) -> Result { + host_file_bytes_available(io::stdin().try_into_filedescriptor()?) } - fn get_fd(&self) -> Option> { - Some(io::stdin().try_into_filedescriptor()) + + fn get_fd(&self) -> Option { + io::stdin().try_into_filedescriptor().ok() } } diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 9aa2bc4687f..3a59662b698 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -4,7 +4,6 @@ use std::fmt; use std::io::{self, Read, Seek, Write}; use std::path::{Path, PathBuf}; use thiserror::Error; -use tracing::debug; #[cfg(all(not(feature = "host_fs"), not(feature = "mem_fs")))] compile_error!("At least the `host_fs` or the `mem_fs` feature must be enabled. Please, pick one."); @@ -14,33 +13,31 @@ pub mod host_fs; #[cfg(feature = "mem_fs")] pub mod mem_fs; +pub type Result = std::result::Result; + #[repr(transparent)] pub struct FileDescriptor { inner: usize, } pub trait FileSystem: fmt::Debug + Send + Sync + 'static { - fn read_dir(&self, path: &Path) -> Result; - fn create_dir(&self, path: &Path) -> Result<(), FsError>; - fn remove_dir(&self, path: &Path) -> Result<(), FsError>; - fn rename(&self, from: &Path, to: &Path) -> Result<(), FsError>; - fn metadata(&self, path: &Path) -> Result; + fn read_dir(&self, path: &Path) -> Result; + fn create_dir(&self, path: &Path) -> Result<()>; + fn remove_dir(&self, path: &Path) -> Result<()>; + fn rename(&self, from: &Path, to: &Path) -> Result<()>; + fn metadata(&self, path: &Path) -> Result; /// This method gets metadata without following symlinks in the path. /// Currently identical to `metadata` because symlinks aren't implemented /// yet. - fn symlink_metadata(&self, path: &Path) -> Result { + fn symlink_metadata(&self, path: &Path) -> Result { self.metadata(path) } - fn remove_file(&self, path: &Path) -> Result<(), FsError>; + fn remove_file(&self, path: &Path) -> Result<()>; fn new_open_options(&self) -> OpenOptions; } pub trait FileOpener { - fn open( - &mut self, - path: &Path, - conf: &OpenOptionsConfig, - ) -> Result, FsError>; + fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result>; } #[derive(Debug, Clone)] @@ -131,7 +128,7 @@ impl OpenOptions { self } - pub fn open>(&mut self, path: P) -> Result, FsError> { + pub fn open>(&mut self, path: P) -> Result> { self.opener.open(path.as_ref(), &self.conf) } } @@ -153,24 +150,24 @@ pub trait VirtualFile: fmt::Debug + Send + Write + Read + Seek + 'static + Upcas /// Change the size of the file, if the `new_size` is greater than the current size /// the extra bytes will be allocated and zeroed - fn set_len(&mut self, new_size: u64) -> Result<(), FsError>; + fn set_len(&mut self, new_size: u64) -> Result<()>; /// Request deletion of the file - fn unlink(&mut self) -> Result<(), FsError>; + fn unlink(&mut self) -> Result<()>; /// Store file contents and metadata to disk /// Default implementation returns `Ok(())`. You should implement this method if you care /// about flushing your cache to permanent storage - fn sync_to_disk(&self) -> Result<(), FsError> { + fn sync_to_disk(&self) -> Result<()> { Ok(()) } /// Returns the number of bytes available. This function must not block - fn bytes_available(&self) -> Result; + fn bytes_available(&self) -> Result; /// Used for polling. Default returns `None` because this method cannot be implemented for most types /// Returns the underlying host fd - fn get_fd(&self) -> Option> { + fn get_fd(&self) -> Option { None } } @@ -331,7 +328,7 @@ impl ReadDir { pub struct DirEntry { pub path: PathBuf, // weird hack, to fix this we probably need an internal trait object or callbacks or something - pub metadata: Result, + pub metadata: Result, } impl DirEntry { @@ -339,11 +336,11 @@ impl DirEntry { self.path.clone() } - pub fn metadata(&self) -> Result { + pub fn metadata(&self) -> Result { self.metadata.clone() } - pub fn file_type(&self) -> Result { + pub fn file_type(&self) -> Result { let metadata = self.metadata.clone()?; Ok(metadata.file_type()) } @@ -429,9 +426,9 @@ impl FileType { } impl Iterator for ReadDir { - type Item = Result; + type Item = Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { if let Some(v) = self.data.get(self.index).cloned() { self.index += 1; return Some(Ok(v)); @@ -439,12 +436,3 @@ impl Iterator for ReadDir { None } } - -/*impl From for FsError { - fn from(vfs_error: vfs::VfsError) -> Self { - match vfs_error { - vfs::VfsError::IoError(io_error) => io_error.into(), - _ => todo!("Not yet handled vfs error type {:?}", vfs_error) - } - } -}*/ diff --git a/lib/vfs/src/mem_fs.rs b/lib/vfs/src/mem_fs.rs index addc97440d6..471326c8b21 100644 --- a/lib/vfs/src/mem_fs.rs +++ b/lib/vfs/src/mem_fs.rs @@ -1,156 +1,184 @@ -use crate::*; +use crate::{ + FileDescriptor, FsError, Metadata, OpenOptions, OpenOptionsConfig, ReadDir, Result, VirtualFile, +}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::io::{Read, Seek, Write}; +use std::io::{self, Read, Seek, Write}; use std::path::Path; use std::sync::{Arc, Mutex}; +use tracing::debug; + +pub type Inode = u64; #[derive(Debug, Clone)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -enum MemKind { +enum Node { File { name: String, - inode: u64, + inode: Inode, }, Directory { name: String, - contents: HashMap, + children: HashMap, }, } -impl Default for MemKind { +impl Default for Node { fn default() -> Self { - MemKind::Directory { + Node::Directory { name: "/".to_string(), - contents: Default::default(), + children: Default::default(), } } } #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct MemFileSystem { - inner: Arc>, +pub struct FileSystem { + inner: Arc>, } #[derive(Default, Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct MemFileSystemInner { +pub struct FileSystemInner { // done for recursion purposes - fs: MemKind, - inodes: HashMap>, - next_inode: u64, + fs: Node, + inodes: HashMap>, + next_inode: Inode, } -impl MemFileSystemInner { +impl FileSystemInner { /// Removes a file, returning the `inode` number - fn remove_file_inner(&mut self, path: &Path) -> Result { + fn remove_file_inner(&mut self, path: &Path) -> Result { let parent = path.parent().unwrap(); let file = path.file_name().unwrap(); - let memkind = self.get_memkind_at_mut(parent).unwrap(); - let inode: u64 = match memkind { - MemKind::Directory { contents, .. } => { - let name = file.to_str().unwrap().to_string(); - let inode: u64 = match contents.get(&name).unwrap() { - MemKind::File { inode, .. } => *inode, + + let node = self.get_node_at_mut(parent).unwrap(); + let inode = match node { + Node::Directory { children, .. } => { + let name = file.to_str().unwrap(); + let inode = match children.get(name).unwrap() { + Node::File { inode, .. } => *inode, _ => return Err(FsError::NotAFile), }; - contents.remove(&name); + children.remove(name); + inode } _ => return Err(FsError::NotAFile), }; + Ok(inode) } #[allow(dead_code)] - fn get_memkind_at(&self, path: &Path) -> Option<&MemKind> { + fn get_node_at(&self, path: &Path) -> Option<&Node> { let mut components = path.components(); + if path.is_absolute() { components.next()?; } - let mut memkind: &MemKind = &self.fs; + let mut node: &Node = &self.fs; for component in components { - match memkind { - MemKind::Directory { contents, .. } => { - memkind = contents.get(component.as_os_str().to_str().unwrap())?; + match node { + Node::Directory { children, .. } => { + node = children.get(component.as_os_str().to_str().unwrap())?; } _ => return None, } } - Some(memkind) + + Some(node) } - fn get_memkind_at_mut(&mut self, path: &Path) -> Option<&mut MemKind> { + + fn get_node_at_mut(&mut self, path: &Path) -> Option<&mut Node> { let mut components = path.components(); + if path.is_absolute() { components.next()?; } - let mut memkind: &mut MemKind = &mut self.fs; + let mut node: &mut Node = &mut self.fs; for component in components { - match memkind { - MemKind::Directory { contents, .. } => { - memkind = contents.get_mut(component.as_os_str().to_str().unwrap())?; + match node { + Node::Directory { children, .. } => { + node = children.get_mut(component.as_os_str().to_str().unwrap())?; } _ => return None, } } - Some(memkind) + + Some(node) } } -impl FileSystem for MemFileSystem { - fn read_dir(&self, _path: &Path) -> Result { +impl crate::FileSystem for FileSystem { + fn read_dir(&self, _path: &Path) -> Result { todo!() } - fn create_dir(&self, path: &Path) -> Result<(), FsError> { + + fn create_dir(&self, path: &Path) -> Result<()> { let parent = path.parent().unwrap(); let file = path.file_name().unwrap(); + let mut inner = self.inner.lock().unwrap(); - let memkind = inner.get_memkind_at_mut(parent).unwrap(); - match memkind { - MemKind::Directory { contents, .. } => { - let name = file.to_str().unwrap().to_string(); - if contents.contains_key(&name) { + let node = inner.get_node_at_mut(parent).unwrap(); + + match node { + Node::Directory { children, .. } => { + let name = file.to_str().unwrap(); + + if children.contains_key(name) { return Err(FsError::AlreadyExists); } - let mk = MemKind::Directory { - name: name.clone(), - contents: Default::default(), + + let directory = Node::Directory { + name: name.to_owned(), + children: Default::default(), }; - contents.insert(name.clone(), mk); + + children.insert(name.to_owned(), directory); } _ => return Err(FsError::BaseNotDirectory), } + Ok(()) } - fn remove_dir(&self, path: &Path) -> Result<(), FsError> { + + fn remove_dir(&self, path: &Path) -> Result<()> { let parent = path.parent().unwrap(); let file = path.file_name().unwrap(); + let mut inner = self.inner.lock().unwrap(); - let memkind = inner.get_memkind_at_mut(parent).unwrap(); - match memkind { - MemKind::Directory { contents, .. } => { - let name = file.to_str().unwrap().to_string(); - match contents.get(&name).unwrap() { - MemKind::Directory { contents, .. } => { - if !contents.is_empty() { + let node = inner.get_node_at_mut(parent).unwrap(); + + match node { + Node::Directory { children, .. } => { + let name = file.to_str().unwrap(); + + match children.get(name).unwrap() { + Node::Directory { children, .. } => { + if !children.is_empty() { return Err(FsError::DirectoryNotEmpty); } } _ => return Err(FsError::BaseNotDirectory), } - contents.remove(&name); + + children.remove(name); } + _ => return Err(FsError::BaseNotDirectory), } + Ok(()) } - fn rename(&self, from: &Path, to: &Path) -> Result<(), FsError> { + + fn rename(&self, from: &Path, to: &Path) -> Result<()> { let inner = self.inner.lock().unwrap(); // We assume that we move into a location that has a parent. // Otherwise (the root) should not be replaceable, and we should trigger an @@ -158,98 +186,80 @@ impl FileSystem for MemFileSystem { let parent_to = to.parent().unwrap(); // TODO: return a proper error (not generic unknown) - let memkind_from = inner.get_memkind_at(from).ok_or(FsError::UnknownError)?; + let node_from = inner.get_node_at(from).ok_or(FsError::UnknownError)?; let mut inner = self.inner.lock().unwrap(); - let memkind_to = inner - .get_memkind_at_mut(parent_to) + let node_to = inner + .get_node_at_mut(parent_to) .ok_or(FsError::BaseNotDirectory)?; - // We update the to contents of the new dir, adding the old memkind - match memkind_to { - MemKind::Directory { contents, .. } => { - let name = to.file_name().unwrap().to_str().unwrap().to_string(); - contents.insert(name, memkind_from.clone()); + // We update the to children of the new dir, adding the old node + match node_to { + Node::Directory { children, .. } => { + let name = to.file_name().unwrap().to_str().unwrap(); + + children.insert(name.to_owned(), node_from.clone()); } // If we are trying to move from the root `/dir1` to `/file/dir2` _ => return Err(FsError::BaseNotDirectory), } - // We remove the old memkind location - match memkind_from { - MemKind::Directory { .. } => { + // We remove the old node location + match node_from { + Node::Directory { .. } => { self.remove_dir(from)?; } - MemKind::File { .. } => { + Node::File { .. } => { inner.remove_file_inner(from)?; } } + Ok(()) } - fn remove_file(&self, path: &Path) -> Result<(), FsError> { + fn remove_file(&self, path: &Path) -> Result<()> { let mut inner = self.inner.lock().unwrap(); let inode = inner.remove_file_inner(path)?; inner.inodes.remove(&inode).unwrap(); + Ok(()) } + fn new_open_options(&self) -> OpenOptions { - OpenOptions::new(Box::new(MemFileOpener(self.clone()))) - } - - fn metadata(&self, _path: &Path) -> Result { - // let inner = self.inner.lock().unwrap(); - // let memkind = inner.get_memkind_at(path) - Ok(Metadata { - ft: FileType { - dir: false, - file: true, - symlink: false, - char_device: false, - block_device: false, - socket: false, - fifo: false, - }, - accessed: 0 as u64, - created: 0 as u64, - modified: 0 as u64, - len: 0, - }) + OpenOptions::new(Box::new(FileOpener(self.clone()))) + } + + fn metadata(&self, _path: &Path) -> Result { + unimplemented!() } } #[derive(Clone)] -pub struct MemFileOpener(MemFileSystem); - -impl FileOpener for MemFileOpener { - fn open( - &mut self, - path: &Path, - conf: &OpenOptionsConfig, - ) -> Result, FsError> { +pub struct FileOpener(FileSystem); + +impl crate::FileOpener for FileOpener { + fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { // TODO: handle create implying write, etc. let read = conf.read(); let write = conf.write(); let append = conf.append(); - let virtual_file = - Box::new(MemFile::new(vec![], read, write, append)) as Box; + let virtual_file = Box::new(File::new(vec![], read, write, append)) as Box; let mut inner = self.0.inner.lock().unwrap(); let inode = inner.next_inode; let parent_path = path.parent().unwrap(); - let file_name = path.file_name().unwrap().to_str().unwrap().to_string(); + let file_name = path.file_name().unwrap().to_str().unwrap(); // TODO: replace with an actual missing directory error - let parent_memkind = inner - .get_memkind_at_mut(parent_path) - .ok_or(FsError::IOError)?; - match parent_memkind { - MemKind::Directory { contents, .. } => { - if contents.contains_key(&file_name) { + let parent_node = inner.get_node_at_mut(parent_path).ok_or(FsError::IOError)?; + match parent_node { + Node::Directory { children, .. } => { + if children.contains_key(file_name) { return Err(FsError::AlreadyExists); } - contents.insert( - file_name.clone(), - MemKind::File { - name: file_name, + + children.insert( + file_name.to_owned(), + Node::File { + name: file_name.to_owned(), inode, }, ); @@ -263,7 +273,7 @@ impl FileOpener for MemFileOpener { inner.next_inode += 1; inner.inodes.insert(inode, virtual_file); - Ok(Box::new(MemFileHandle { + Ok(Box::new(FileHandle { fs: self.0.clone(), inode, }) as Box) @@ -272,7 +282,7 @@ impl FileOpener for MemFileOpener { #[derive(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct MemFile { +pub struct File { buffer: Vec, cursor: usize, flags: u16, @@ -281,7 +291,7 @@ pub struct MemFile { created_time: u64, } -impl MemFile { +impl File { const READ: u16 = 1; const WRITE: u16 = 2; const APPEND: u16 = 4; @@ -289,15 +299,19 @@ impl MemFile { /// creates a new host file from a `std::fs::File` and a path pub fn new(buffer: Vec, read: bool, write: bool, append: bool) -> Self { let mut flags = 0; + if read { flags |= Self::READ; } + if write { flags |= Self::WRITE; } + if append { flags |= Self::APPEND; } + Self { buffer, cursor: 0, @@ -309,31 +323,40 @@ impl MemFile { } } -impl Read for MemFile { +impl Read for File { fn read(&mut self, buf: &mut [u8]) -> io::Result { let upper_limit = std::cmp::min(self.buffer.len() - self.cursor, buf.len()); + for i in 0..upper_limit { buf[i] = self.buffer[self.cursor + i]; } + self.cursor += upper_limit; + Ok(upper_limit) } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let data_to_copy = self.buffer.len() - self.cursor; buf.reserve(data_to_copy); + for i in self.cursor..self.buffer.len() { buf.push(self.buffer[i]); } + Ok(data_to_copy) } + fn read_to_string(&mut self, buf: &mut String) -> io::Result { let s = std::str::from_utf8(&self.buffer[self.cursor..]) .map_err(|_e| io::ErrorKind::InvalidInput)?; buf.push_str(s); let amount_read = self.buffer.len() - self.cursor; self.cursor = self.buffer.len(); + Ok(amount_read) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { if buf.len() < (self.buffer.len() - self.cursor) { return Err(std::io::Error::new( @@ -341,14 +364,18 @@ impl Read for MemFile { "Not enough bytes available", )); } + for i in 0..buf.len() { buf[i] = self.buffer[self.cursor + i]; } + self.cursor += buf.len(); + Ok(()) } } -impl Seek for MemFile { + +impl Seek for File { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { match pos { io::SeekFrom::Start(s) => self.cursor = s as usize, @@ -359,79 +386,91 @@ impl Seek for MemFile { Ok(self.cursor as u64) } } -impl Write for MemFile { + +impl Write for File { fn write(&mut self, buf: &[u8]) -> io::Result { self.buffer.write(buf) } + fn flush(&mut self) -> io::Result<()> { self.buffer.flush() } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.buffer.write_all(buf) } + fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> { self.buffer.write_fmt(fmt) } } #[cfg_attr(feature = "enable-serde", typetag::serde)] -impl VirtualFile for MemFile { +impl VirtualFile for File { fn last_accessed(&self) -> u64 { self.last_accessed } + fn last_modified(&self) -> u64 { self.last_modified } + fn created_time(&self) -> u64 { self.created_time } + fn size(&self) -> u64 { self.buffer.len() as u64 } - fn set_len(&mut self, new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, new_size: u64) -> Result<()> { self.buffer.resize(new_size as usize, 0); Ok(()) } - fn unlink(&mut self) -> Result<(), FsError> { + + fn unlink(&mut self) -> Result<()> { self.buffer.clear(); self.cursor = 0; Ok(()) } - fn sync_to_disk(&self) -> Result<(), FsError> { + + fn sync_to_disk(&self) -> Result<()> { Ok(()) } - fn bytes_available(&self) -> Result { + + fn bytes_available(&self) -> Result { Ok(self.buffer.len() - self.cursor) } - fn get_raw_fd(&self) -> Option { + + fn get_fd(&self) -> Option { None } } #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct MemFileHandle { +pub struct FileHandle { // hack, just skip it // #[serde(skip)] - fs: MemFileSystem, + fs: FileSystem, inode: u64, } -impl MemFileHandle { +impl FileHandle { // not optimal,but good enough for now fn no_file_err() -> std::io::Error { std::io::Error::new(std::io::ErrorKind::NotFound, "File was closed") } } -impl std::fmt::Debug for MemFileHandle { +impl std::fmt::Debug for FileHandle { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("MemFileHandle") + f.debug_struct("FileHandle") .field("inode", &self.inode) .finish() } } -impl Read for MemFileHandle { +impl Read for FileHandle { fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -441,6 +480,7 @@ impl Read for MemFileHandle { file.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -450,6 +490,7 @@ impl Read for MemFileHandle { file.read_to_end(buf) } + fn read_to_string(&mut self, buf: &mut String) -> io::Result { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -459,6 +500,7 @@ impl Read for MemFileHandle { file.read_to_string(buf) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -469,7 +511,8 @@ impl Read for MemFileHandle { file.read_exact(buf) } } -impl Seek for MemFileHandle { + +impl Seek for FileHandle { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -480,7 +523,8 @@ impl Seek for MemFileHandle { file.seek(pos) } } -impl Write for MemFileHandle { + +impl Write for FileHandle { fn write(&mut self, buf: &[u8]) -> io::Result { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -490,6 +534,7 @@ impl Write for MemFileHandle { file.write(buf) } + fn flush(&mut self) -> io::Result<()> { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -499,6 +544,7 @@ impl Write for MemFileHandle { file.flush() } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -508,6 +554,7 @@ impl Write for MemFileHandle { file.write_all(buf) } + fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> { let mut inner = self.fs.inner.lock().unwrap(); let file = inner @@ -520,7 +567,7 @@ impl Write for MemFileHandle { } #[cfg_attr(feature = "enable-serde", typetag::serde)] -impl VirtualFile for MemFileHandle { +impl VirtualFile for FileHandle { fn last_accessed(&self) -> u64 { let inner = self.fs.inner.lock().unwrap(); inner @@ -561,7 +608,7 @@ impl VirtualFile for MemFileHandle { .unwrap_or_default() } - fn set_len(&mut self, new_size: u64) -> Result<(), FsError> { + fn set_len(&mut self, new_size: u64) -> Result<()> { let mut inner = self.fs.inner.lock().unwrap(); let file = inner .inodes @@ -571,7 +618,7 @@ impl VirtualFile for MemFileHandle { file.set_len(new_size) } - fn unlink(&mut self) -> Result<(), FsError> { + fn unlink(&mut self) -> Result<()> { let mut inner = self.fs.inner.lock().unwrap(); let file = inner .inodes @@ -581,7 +628,7 @@ impl VirtualFile for MemFileHandle { file.unlink() } - fn sync_to_disk(&self) -> Result<(), FsError> { + fn sync_to_disk(&self) -> Result<()> { let inner = self.fs.inner.lock().unwrap(); let file = inner .inodes @@ -591,7 +638,7 @@ impl VirtualFile for MemFileHandle { file.sync_to_disk() } - fn bytes_available(&self) -> Result { + fn bytes_available(&self) -> Result { let inner = self.fs.inner.lock().unwrap(); let file = inner .inodes @@ -601,16 +648,14 @@ impl VirtualFile for MemFileHandle { file.bytes_available() } - fn get_raw_fd(&self) -> Option { + fn get_fd(&self) -> Option { let inner = self.fs.inner.lock().unwrap(); let file = inner.inodes.get(&self.inode)?; - file.get_raw_fd() + file.get_fd() } } -// Stdin / Stdout / Stderr definitions - /// A wrapper type around Stdout that implements `VirtualFile` #[derive(Debug, Default)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] @@ -625,18 +670,21 @@ impl Read for Stdout { "can not read from stdout", )) } + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stdout", )) } + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stdout", )) } + fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, @@ -644,26 +692,31 @@ impl Read for Stdout { )) } } + impl Seek for Stdout { fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "can not seek stdout")) } } + impl Write for Stdout { fn write(&mut self, _buf: &[u8]) -> io::Result { // io::stdout().write(buf) unimplemented!(); } + fn flush(&mut self) -> io::Result<()> { // io::stdout().flush() // unimplemented!(); Ok(()) } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { // io::stdout().write_all(buf) self.buf.extend_from_slice(&buf); Ok(()) } + fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> { // io::stdout().write_fmt(fmt) unimplemented!(); @@ -675,34 +728,30 @@ impl VirtualFile for Stdout { fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, _new_size: u64) -> Result<()> { debug!("Calling VirtualFile::set_len on stdout; this is probably a bug"); Err(FsError::PermissionDenied) } - fn unlink(&mut self) -> Result<(), FsError> { - Ok(()) - } - fn bytes_available(&self) -> Result { - // unwrap is safe because of get_raw_fd implementation - unimplemented!(); - } - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { - unimplemented!(); + fn unlink(&mut self) -> Result<()> { + Ok(()) } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { + fn bytes_available(&self) -> Result { + // unwrap is safe because of get_raw_fd implementation unimplemented!(); } } @@ -714,6 +763,7 @@ impl VirtualFile for Stdout { pub struct Stderr { pub buf: Vec, } + impl Read for Stderr { fn read(&mut self, _buf: &mut [u8]) -> io::Result { Err(io::Error::new( @@ -721,18 +771,21 @@ impl Read for Stderr { "can not read from stderr", )) } + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stderr", )) } + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "can not read from stderr", )) } + fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, @@ -740,27 +793,32 @@ impl Read for Stderr { )) } } + impl Seek for Stderr { fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "can not seek stderr")) } } + impl Write for Stderr { fn write(&mut self, _buf: &[u8]) -> io::Result { // io::stderr().write(buf) unimplemented!(); } + fn flush(&mut self) -> io::Result<()> { // io::stderr().flush() // unimplemented!(); Ok(()) } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.buf.extend_from_slice(&buf); Ok(()) // io::stderr().write_all(buf) // unimplemented!(); } + fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> { // io::stderr().write_fmt(fmt) unimplemented!(); @@ -772,35 +830,31 @@ impl VirtualFile for Stderr { fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, _new_size: u64) -> Result<()> { debug!("Calling VirtualFile::set_len on stderr; this is probably a bug"); Err(FsError::PermissionDenied) } - fn unlink(&mut self) -> Result<(), FsError> { + + fn unlink(&mut self) -> Result<()> { Ok(()) } - fn bytes_available(&self) -> Result { - unimplemented!(); - } - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { + + fn bytes_available(&self) -> Result { unimplemented!(); } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { - unimplemented!( - "Stderr::get_raw_fd in VirtualFile is not implemented for non-Unix-like targets yet" - ); - } } /// A wrapper type around Stdin that implements `VirtualFile` and @@ -820,24 +874,29 @@ impl Read for Stdin { Ok(len) // unimplemented!(); } + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { // io::stdin().read_to_end(buf) unimplemented!(); } + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { // io::stdin().read_to_string(buf) unimplemented!(); } + fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> { // io::stdin().read_exact(buf) unimplemented!(); } } + impl Seek for Stdin { fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "can not seek stdin")) } } + impl Write for Stdin { fn write(&mut self, _buf: &[u8]) -> io::Result { Err(io::Error::new( @@ -845,18 +904,21 @@ impl Write for Stdin { "can not write to stdin", )) } + fn flush(&mut self) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, "can not write to stdin", )) } + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, "can not write to stdin", )) } + fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, @@ -870,35 +932,29 @@ impl VirtualFile for Stdin { fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> { + + fn set_len(&mut self, _new_size: u64) -> Result<()> { debug!("Calling VirtualFile::set_len on stdin; this is probably a bug"); Err(FsError::PermissionDenied) } - fn unlink(&mut self) -> Result<(), FsError> { + + fn unlink(&mut self) -> Result<()> { Ok(()) } - fn bytes_available(&self) -> Result { - unimplemented!(); - } - #[cfg(unix)] - fn get_raw_fd(&self) -> Option { - // use std::os::unix::io::AsRawFd; - // Some(io::stdin().as_raw_fd()) + + fn bytes_available(&self) -> Result { unimplemented!(); } - #[cfg(not(unix))] - fn get_raw_fd(&self) -> Option { - unimplemented!( - "Stdin::get_raw_fd in VirtualFile is not implemented for non-Unix-like targets yet" - ); - } } From ff9c7f17c9da67bb1cebdfbe1d23002490ffdcbf Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 17 Aug 2021 14:51:25 +0200 Subject: [PATCH 4/4] fix(vfs) Change `FileDescriptor` to be unit. --- lib/vfs/src/host_fs.rs | 24 +++++++++++------------- lib/vfs/src/lib.rs | 4 +--- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index 64f6454973e..4d18f723053 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -29,12 +29,11 @@ where type Error = FsError; fn try_into_filedescriptor(&self) -> std::result::Result { - Ok(FileDescriptor { - inner: self - .as_raw_fd() + Ok(FileDescriptor( + self.as_raw_fd() .try_into() .map_err(|_| FsError::InvalidFd)?, - }) + )) } } @@ -43,7 +42,7 @@ impl TryInto for FileDescriptor { type Error = FsError; fn try_into(self) -> std::result::Result { - self.inner.try_into().map_err(|_| FsError::InvalidFd) + self.0.try_into().map_err(|_| FsError::InvalidFd) } } @@ -55,12 +54,11 @@ where type Error = FsError; fn try_into_filedescriptor(&self) -> Result { - Ok(FileDescriptor { - inner: self - .as_raw_handle() + Ok(FileDescriptor( + self.as_raw_handle() .try_into() .map_err(|_| FsError::InvalidFd)?, - }) + )) } } @@ -69,7 +67,7 @@ impl TryInto for FileDescriptor { type Error = FsError; fn try_into(self) -> std::result::Result { - self.inner.try_into().map_err(|_| FsError::InvalidFd) + self.0.try_into().map_err(|_| FsError::InvalidFd) } } @@ -210,7 +208,7 @@ pub struct File { #[cfg(feature = "enable-serde")] impl<'de> Deserialize<'de> for File { - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { @@ -230,7 +228,7 @@ impl<'de> Deserialize<'de> for File { formatter.write_str("struct File") } - fn visit_seq(self, mut seq: V) -> Result + fn visit_seq(self, mut seq: V) -> std::result::Result where V: de::SeqAccess<'de>, { @@ -253,7 +251,7 @@ impl<'de> Deserialize<'de> for File { }) } - fn visit_map(self, mut map: V) -> Result + fn visit_map(self, mut map: V) -> std::result::Result where V: de::MapAccess<'de>, { diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 3a59662b698..eb54277635a 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -16,9 +16,7 @@ pub mod mem_fs; pub type Result = std::result::Result; #[repr(transparent)] -pub struct FileDescriptor { - inner: usize, -} +pub struct FileDescriptor(usize); pub trait FileSystem: fmt::Debug + Send + Sync + 'static { fn read_dir(&self, path: &Path) -> Result;