Skip to content

Commit

Permalink
Make AsFile fallible
Browse files Browse the repository at this point in the history
Return `EBADF` in `AsFile` in case a `Handle` cannot be made into
a `std::fs::File`.
  • Loading branch information
Jakub Konka committed Apr 28, 2020
1 parent 068a699 commit 26c894a
Show file tree
Hide file tree
Showing 13 changed files with 49 additions and 45 deletions.
7 changes: 4 additions & 3 deletions crates/wasi-common/src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ use stdio::Stdio;
use sys_impl::get_file_type;

pub(crate) trait AsFile {
fn as_file(&self) -> ManuallyDrop<File>;
fn as_file(&self) -> io::Result<ManuallyDrop<File>>;
}

impl AsFile for dyn Handle + 'static {
fn as_file(&self) -> ManuallyDrop<File> {
fn as_file(&self) -> io::Result<ManuallyDrop<File>> {
if let Some(file) = self.as_any().downcast_ref::<OsFile>() {
file.as_file()
} else if let Some(dir) = self.as_any().downcast_ref::<OsDir>() {
Expand All @@ -51,7 +51,8 @@ impl AsFile for dyn Handle + 'static {
} else if let Some(other) = self.as_any().downcast_ref::<OsOther>() {
other.as_file()
} else {
panic!("non-OS resource cannot be made into a File")
log::error!("tried to make std::fs::File from non-OS handle");
Err(io::Error::from_raw_os_error(libc::EBADF))
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/wasi-common/src/sys/osdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,24 @@ impl Handle for OsDir {
}
// FdOps
fn fdstat_get(&self) -> Result<types::Fdflags> {
fd::fdstat_get(&self.as_file())
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
if let Some(new_file) = fd::fdstat_set_flags(&self.as_file(), fdflags)? {
if let Some(new_file) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
self.handle.update_from(new_file);
}
Ok(())
}
fn filestat_get(&self) -> Result<types::Filestat> {
fd::filestat_get(&self.as_file())
fd::filestat_get(&*self.as_file()?)
}
fn filestat_set_times(
&self,
atim: types::Timestamp,
mtim: types::Timestamp,
fst_flags: types::Fstflags,
) -> Result<()> {
fd::filestat_set_times(&self.as_file(), atim, mtim, fst_flags)
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
}
fn readdir<'a>(
&'a self,
Expand Down
26 changes: 13 additions & 13 deletions crates/wasi-common/src/sys/osfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Handle for OsFile {
fd::advise(self, advice, offset, len)
}
fn allocate(&self, offset: types::Filesize, len: types::Filesize) -> Result<()> {
let fd = self.as_file();
let fd = self.as_file()?;
let metadata = fd.metadata()?;
let current_size = metadata.len();
let wanted_size = offset.checked_add(len).ok_or(Errno::TooBig)?;
Expand All @@ -71,23 +71,23 @@ impl Handle for OsFile {
Ok(())
}
fn datasync(&self) -> Result<()> {
self.as_file().sync_data()?;
self.as_file()?.sync_data()?;
Ok(())
}
fn fdstat_get(&self) -> Result<types::Fdflags> {
fd::fdstat_get(&self.as_file())
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
if let Some(new_handle) = fd::fdstat_set_flags(&self.as_file(), fdflags)? {
if let Some(new_handle) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
self.handle.update_from(new_handle);
}
Ok(())
}
fn filestat_get(&self) -> Result<types::Filestat> {
fd::filestat_get(&self.as_file())
fd::filestat_get(&*self.as_file()?)
}
fn filestat_set_size(&self, size: types::Filesize) -> Result<()> {
self.as_file().set_len(size)?;
self.as_file()?.set_len(size)?;
Ok(())
}
fn filestat_set_times(
Expand All @@ -96,38 +96,38 @@ impl Handle for OsFile {
mtim: types::Timestamp,
fst_flags: types::Fstflags,
) -> Result<()> {
fd::filestat_set_times(&self.as_file(), atim, mtim, fst_flags)
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
}
fn preadv(&self, buf: &mut [io::IoSliceMut], offset: u64) -> Result<usize> {
let mut fd: &File = &self.as_file();
let mut fd: &File = &*self.as_file()?;
let cur_pos = fd.seek(SeekFrom::Current(0))?;
fd.seek(SeekFrom::Start(offset))?;
let nread = self.read_vectored(buf)?;
fd.seek(SeekFrom::Start(cur_pos))?;
Ok(nread)
}
fn pwritev(&self, buf: &[io::IoSlice], offset: u64) -> Result<usize> {
let mut fd: &File = &self.as_file();
let mut fd: &File = &*self.as_file()?;
let cur_pos = fd.seek(SeekFrom::Current(0))?;
fd.seek(SeekFrom::Start(offset))?;
let nwritten = self.write_vectored(&buf)?;
fd.seek(SeekFrom::Start(cur_pos))?;
Ok(nwritten)
}
fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result<usize> {
let nread = self.as_file().read_vectored(iovs)?;
let nread = self.as_file()?.read_vectored(iovs)?;
Ok(nread)
}
fn seek(&self, offset: SeekFrom) -> Result<u64> {
let pos = self.as_file().seek(offset)?;
let pos = self.as_file()?.seek(offset)?;
Ok(pos)
}
fn sync(&self) -> Result<()> {
self.as_file().sync_all()?;
self.as_file()?.sync_all()?;
Ok(())
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
let nwritten = self.as_file().write_vectored(&iovs)?;
let nwritten = self.as_file()?.write_vectored(&iovs)?;
Ok(nwritten)
}
}
8 changes: 4 additions & 4 deletions crates/wasi-common/src/sys/osother.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,20 @@ impl Handle for OsOther {
}
// FdOps
fn fdstat_get(&self) -> Result<types::Fdflags> {
fd::fdstat_get(&self.as_file())
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
if let Some(handle) = fd::fdstat_set_flags(&self.as_file(), fdflags)? {
if let Some(handle) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
self.handle.update_from(handle);
}
Ok(())
}
fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result<usize> {
let nread = self.as_file().read_vectored(iovs)?;
let nread = self.as_file()?.read_vectored(iovs)?;
Ok(nread)
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
let mut fd: &File = &self.as_file();
let mut fd: &File = &*self.as_file()?;
let nwritten = if self.is_tty() {
SandboxedTTYWriter::new(&mut fd).write_vectored(&iovs)?
} else {
Expand Down
4 changes: 2 additions & 2 deletions crates/wasi-common/src/sys/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ impl Handle for Stdio {
}
// FdOps
fn fdstat_get(&self) -> Result<types::Fdflags> {
fd::fdstat_get(&self.as_file())
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
if let Some(_) = fd::fdstat_set_flags(&self.as_file(), fdflags)? {
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
// OK, this means we should somehow update the underlying os handle,
// and we can't do that with `std::io::std{in, out, err}`, so we'll
// panic for now.
Expand Down
4 changes: 2 additions & 2 deletions crates/wasi-common/src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ use yanix::file::{AtFlag, OFlag};
pub(crate) use sys_impl::*;

impl<T: AsRawFd> AsFile for T {
fn as_file(&self) -> ManuallyDrop<File> {
fn as_file(&self) -> io::Result<ManuallyDrop<File>> {
let file = unsafe { File::from_raw_fd(self.as_raw_fd()) };
ManuallyDrop::new(file)
Ok(ManuallyDrop::new(file))
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/wasi-common/src/sys/unix/oshandle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub(crate) struct OsHandle(Cell<RawFd>);
impl OsHandle {
/// Tries clone `self`.
pub(crate) fn try_clone(&self) -> io::Result<Self> {
let fd = self.as_file().try_clone()?;
let fd = self.as_file()?.try_clone()?;
Ok(Self(Cell::new(fd.into_raw_fd())))
}
/// Consumes `other` taking the ownership of the underlying
Expand Down
14 changes: 8 additions & 6 deletions crates/wasi-common/src/sys/unix/poll.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::entry::EntryHandle;
use crate::poll::{ClockEventData, FdEventData};
use crate::sys::osfile::OsFile;
use crate::sys::AsFile;
use crate::wasi::{types, Errno, Result};
use std::io;
Expand All @@ -17,7 +16,7 @@ pub(crate) fn oneoff(
return Ok(());
}

let mut poll_fds: Vec<_> = fd_events
let poll_fds: Result<Vec<_>> = fd_events
.iter()
.map(|event| {
let mut flags = PollFlags::empty();
Expand All @@ -29,9 +28,11 @@ pub(crate) fn oneoff(
// events we filtered before. If we get something else here, the code has a serious bug.
_ => unreachable!(),
};
unsafe { PollFd::new(event.handle.as_file().as_raw_fd(), flags) }
let file = event.handle.as_file()?;
unsafe { Ok(PollFd::new(file.as_raw_fd(), flags)) }
})
.collect();
let mut poll_fds = poll_fds?;

let poll_timeout = timeout.map_or(-1, |timeout| {
let delay = timeout.delay / 1_000_000; // poll syscall requires delay to expressed in milliseconds
Expand Down Expand Up @@ -77,15 +78,16 @@ fn handle_fd_event(
events: &mut Vec<types::Event>,
) -> Result<()> {
fn query_nbytes(handle: EntryHandle) -> Result<u64> {
if let Some(file) = handle.as_any().downcast_ref::<OsFile>() {
let file = handle.as_file()?;
if handle.get_file_type() == types::Filetype::RegularFile {
// fionread may overflow for large files, so use another way for regular files.
use yanix::file::tell;
let meta = file.as_file().metadata()?;
let meta = file.metadata()?;
let len = meta.len();
let host_offset = unsafe { tell(file.as_raw_fd())? };
return Ok(len - host_offset);
}
Ok(unsafe { fionread(handle.as_file().as_raw_fd())?.into() })
Ok(unsafe { fionread(file.as_raw_fd())?.into() })
}

for (fd_event, poll_fd) in ready_events {
Expand Down
2 changes: 1 addition & 1 deletion crates/wasi-common/src/sys/windows/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub(crate) fn readdir(
use winx::file::get_file_path;

let cookie = cookie.try_into()?;
let path = get_file_path(&dirfd.as_file())?;
let path = get_file_path(&*dirfd.as_file()?)?;
// std::fs::ReadDir doesn't return . and .., so we need to emulate it
let path = Path::new(&path);
// The directory /.. is the same as / on Unix (at least on ext4), so emulate this behavior too
Expand Down
6 changes: 3 additions & 3 deletions crates/wasi-common/src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use winapi::shared::winerror;
use winx::file::{CreationDisposition, Flags};

impl<T: AsRawHandle> AsFile for T {
fn as_file(&self) -> ManuallyDrop<File> {
fn as_file(&self) -> io::Result<ManuallyDrop<File>> {
let file = unsafe { File::from_raw_handle(self.as_raw_handle()) };
ManuallyDrop::new(file)
Ok(ManuallyDrop::new(file))
}
}

Expand All @@ -35,7 +35,7 @@ pub(crate) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
types::Filetype::CharacterDevice
} else if file_type.is_disk() {
// disk file: file, dir or disk device
let file = file.as_file();
let file = file.as_file()?;
let meta = file.metadata()?;
if meta.is_dir() {
types::Filetype::Directory
Expand Down
2 changes: 1 addition & 1 deletion crates/wasi-common/src/sys/windows/oshandle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub(crate) struct OsHandle(Cell<RawHandle>);
impl OsHandle {
/// Tries cloning `self`.
pub(crate) fn try_clone(&self) -> io::Result<Self> {
let handle = self.as_file().try_clone()?;
let handle = self.as_file()?.try_clone()?;
Ok(Self(Cell::new(handle.into_raw_handle())))
}
/// Consumes `other` taking the ownership of the underlying
Expand Down
6 changes: 3 additions & 3 deletions crates/wasi-common/src/sys/windows/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn concatenate<P: AsRef<Path>>(file: &OsDir, path: P) -> Result<PathBuf> {
return Err(Errno::Notcapable);
}

let dir_path = get_file_path(&file.as_file())?;
let dir_path = get_file_path(&*file.as_file()?)?;
// concatenate paths
let mut out_path = PathBuf::from(dir_path);
out_path.push(path.as_ref());
Expand Down Expand Up @@ -127,7 +127,7 @@ pub(crate) fn readlinkat(dirfd: &OsDir, s_path: &str) -> Result<String> {
// we need to strip the prefix from the absolute path
// as otherwise we will error out since WASI is not capable
// of dealing with absolute paths
let dir_path = get_file_path(&dirfd.as_file())?;
let dir_path = get_file_path(&*dirfd.as_file()?)?;
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path
.strip_prefix(dir_path)
Expand Down Expand Up @@ -295,7 +295,7 @@ pub(crate) fn readlink(dirfd: &OsDir, path: &str, buf: &mut [u8]) -> Result<usiz
// we need to strip the prefix from the absolute path
// as otherwise we will error out since WASI is not capable
// of dealing with absolute paths
let dir_path = get_file_path(&dirfd.as_file())?;
let dir_path = get_file_path(&*dirfd.as_file()?)?;
let dir_path = PathBuf::from(strip_extended_prefix(dir_path));
let target_path = target_path
.strip_prefix(dir_path)
Expand Down
5 changes: 3 additions & 2 deletions crates/wasi-common/src/sys/windows/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ fn handle_rw_event(event: FdEventData, out_events: &mut Vec<types::Event>) {
if event.r#type == types::Eventtype::FdRead {
handle
.as_file()
.metadata()
.and_then(|f| f.metadata())
.map(|m| m.len())
.map_err(Into::into)
} else {
Expand Down Expand Up @@ -235,7 +235,8 @@ pub(crate) fn oneoff(
handle_error_event(event, Errno::Notsup, events);
}
} else {
panic!("can poll FdEvent for OS resources only");
log::error!("can poll FdEvent for OS resources only");
return Err(Errno::Badf);
}
}

Expand Down

0 comments on commit 26c894a

Please sign in to comment.