Files
wasmtime/crates/wasi-common/src/sys/osfile.rs

149 lines
4.5 KiB
Rust

use super::sys_impl::oshandle::RawOsHandle;
use super::{fd, AsFile};
use crate::handle::{
Advice, Fdflags, Filesize, Filestat, Filetype, Fstflags, Handle, HandleRights,
};
use crate::sched::Timestamp;
use crate::{Error, Result};
use std::any::Any;
use std::cell::Cell;
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::ops::Deref;
#[derive(Debug)]
/// A file backed by the operating system's file system. Dereferences to a
/// `RawOsHandle`. Its impl of `Handle` uses Rust's `std` to implement all
/// file descriptor operations.
///
/// # Constructing `OsFile`
///
/// `OsFile` can currently only be constructed from `std::fs::File` using
/// the `std::convert::TryFrom` trait:
///
/// ```rust,no_run
/// use std::fs::OpenOptions;
/// use std::convert::TryFrom;
/// use wasi_common::OsFile;
///
/// let file = OpenOptions::new().read(true).open("some_file").unwrap();
/// let os_file = OsFile::try_from(file).unwrap();
/// ```
pub struct OsFile {
rights: Cell<HandleRights>,
handle: RawOsHandle,
}
impl OsFile {
pub(super) fn new(rights: HandleRights, handle: RawOsHandle) -> Self {
let rights = Cell::new(rights);
Self { rights, handle }
}
}
impl Deref for OsFile {
type Target = RawOsHandle;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl Handle for OsFile {
fn as_any(&self) -> &dyn Any {
self
}
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
let handle = self.handle.try_clone()?;
let rights = self.rights.clone();
Ok(Box::new(Self { rights, handle }))
}
fn get_file_type(&self) -> Filetype {
Filetype::RegularFile
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
}
fn set_rights(&self, rights: HandleRights) {
self.rights.set(rights)
}
// FdOps
fn advise(&self, advice: Advice, offset: Filesize, len: Filesize) -> Result<()> {
fd::advise(self, advice, offset, len)
}
fn allocate(&self, offset: Filesize, len: Filesize) -> Result<()> {
let fd = self.as_file()?;
let metadata = fd.metadata()?;
let current_size = metadata.len();
let wanted_size = offset.checked_add(len).ok_or(Error::TooBig)?;
// This check will be unnecessary when rust-lang/rust#63326 is fixed
if wanted_size > i64::max_value() as u64 {
return Err(Error::TooBig);
}
if wanted_size > current_size {
fd.set_len(wanted_size)?;
}
Ok(())
}
fn datasync(&self) -> Result<()> {
self.as_file()?.sync_data()?;
Ok(())
}
fn fdstat_get(&self) -> Result<Fdflags> {
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
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<Filestat> {
fd::filestat_get(&*self.as_file()?)
}
fn filestat_set_size(&self, size: Filesize) -> Result<()> {
self.as_file()?.set_len(size)?;
Ok(())
}
fn filestat_set_times(
&self,
atim: Timestamp,
mtim: Timestamp,
fst_flags: Fstflags,
) -> Result<()> {
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 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 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)?;
Ok(nread)
}
fn seek(&self, offset: SeekFrom) -> Result<u64> {
let pos = self.as_file()?.seek(offset)?;
Ok(pos)
}
fn sync(&self) -> Result<()> {
self.as_file()?.sync_all()?;
Ok(())
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
let nwritten = self.as_file()?.write_vectored(&iovs)?;
Ok(nwritten)
}
}