diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index f96fad38bd0..4d18f723053 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -1,21 +1,85 @@ -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; use std::fs; use std::io::{self, 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, UNIX_EPOCH}; +use tracing::debug; + +trait TryIntoFileDescriptor { + type Error; + + fn try_into_filedescriptor(&self) -> std::result::Result; +} + +#[cfg(unix)] +impl TryIntoFileDescriptor for T +where + T: AsRawFd, +{ + type Error = FsError; + + fn try_into_filedescriptor(&self) -> std::result::Result { + Ok(FileDescriptor( + self.as_raw_fd() + .try_into() + .map_err(|_| FsError::InvalidFd)?, + )) + } +} + +#[cfg(unix)] +impl TryInto for FileDescriptor { + type Error = FsError; + + fn try_into(self) -> std::result::Result { + self.0.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( + self.as_raw_handle() + .try_into() + .map_err(|_| FsError::InvalidFd)?, + )) + } +} + +#[cfg(windows)] +impl TryInto for FileDescriptor { + type Error = FsError; + + fn try_into(self) -> std::result::Result { + self.0.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 { @@ -23,29 +87,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) @@ -55,7 +122,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)] @@ -105,14 +172,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(); @@ -127,7 +190,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 }) } @@ -136,7 +199,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, @@ -144,8 +207,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) -> std::result::Result where D: serde::Deserializer<'de>, { @@ -156,16 +219,16 @@ 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 + fn visit_seq(self, mut seq: V) -> std::result::Result where V: de::SeqAccess<'de>, { @@ -176,19 +239,19 @@ 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, }) } - fn visit_map(self, mut map: V) -> Result + fn visit_map(self, mut map: V) -> std::result::Result where V: de::MapAccess<'de>, { @@ -213,12 +276,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, @@ -227,11 +290,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; @@ -239,15 +302,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, @@ -260,42 +327,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() @@ -327,41 +402,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 { - // 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" - ); + fn bytes_available(&self) -> Result { + 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.try_into()?, libc::FIONREAD, &mut bytes_found) }; match result { // success @@ -374,7 +434,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") } @@ -383,6 +443,7 @@ fn host_file_bytes_available(_raw_fd: i32) -> 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( @@ -390,18 +451,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, @@ -409,21 +473,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) } @@ -434,38 +503,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 { - // unwrap is safe because of get_raw_fd implementation - let host_fd = self.get_raw_fd().unwrap(); - host_file_bytes_available(host_fd) + fn bytes_available(&self) -> Result { + host_file_bytes_available(io::stdout().try_into_filedescriptor()?) } - #[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 { + io::stdout().try_into_filedescriptor().ok() } } @@ -474,6 +539,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( @@ -481,18 +547,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, @@ -500,21 +569,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) } @@ -525,38 +599,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 { - // 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(io::stderr().as_raw_fd()) + fn bytes_available(&self) -> Result { + host_file_bytes_available(io::stderr().try_into_filedescriptor()?) } - #[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 { + io::stderr().try_into_filedescriptor().ok() } } @@ -569,21 +639,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( @@ -591,18 +666,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, @@ -616,37 +694,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 { - // unwrap is safe because of get_raw_fd implementation - let host_fd = self.get_raw_fd().unwrap(); - host_file_bytes_available(host_fd) + fn bytes_available(&self) -> Result { + host_file_bytes_available(io::stdin().try_into_filedescriptor()?) } - #[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 { + io::stdin().try_into_filedescriptor().ok() } } diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 790f03781b3..eb54277635a 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,28 +13,29 @@ pub mod host_fs; #[cfg(feature = "mem_fs")] pub mod mem_fs; +pub type Result = std::result::Result; + +#[repr(transparent)] +pub struct FileDescriptor(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)] @@ -126,7 +126,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) } } @@ -148,24 +148,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_raw_fd(&self) -> Option { + fn get_fd(&self) -> Option { None } } @@ -326,7 +326,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 { @@ -334,11 +334,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()) } @@ -424,9 +424,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)); @@ -434,12 +434,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" - ); - } }