Move std::sys::wasi::ext
to std::os::wasi
This commit is contained in:
parent
a808fd44a3
commit
3edba7a806
8 changed files with 2 additions and 26 deletions
|
@ -19,8 +19,7 @@ cfg_if::cfg_if! {
|
|||
|
||||
pub mod linux;
|
||||
|
||||
#[stable(feature = "wasi_ext_doc", since = "1.35.0")]
|
||||
pub use crate::sys::wasi_ext as wasi;
|
||||
pub mod wasi;
|
||||
|
||||
pub mod windows;
|
||||
} else if #[cfg(doc)] {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
//! WASI-specific definitions
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys::ext::*;
|
6
library/std/src/os/wasi/ffi.rs
Normal file
6
library/std/src/os/wasi/ffi.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
//! WASI-specific extension to the primitives in the `std::ffi` module
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::sys_common::os_str_bytes::*;
|
536
library/std/src/os/wasi/fs.rs
Normal file
536
library/std/src/os/wasi/fs.rs
Normal file
|
@ -0,0 +1,536 @@
|
|||
//! WASI-specific extensions to primitives in the `std::fs` module.
|
||||
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![unstable(feature = "wasi_ext", issue = "none")]
|
||||
|
||||
use crate::ffi::OsStr;
|
||||
use crate::fs::{self, File, Metadata, OpenOptions};
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
|
||||
// Used for `File::read` on intra-doc links
|
||||
#[allow(unused_imports)]
|
||||
use io::{Read, Write};
|
||||
|
||||
/// WASI-specific extensions to [`File`].
|
||||
pub trait FileExt {
|
||||
/// Reads a number of bytes starting from a given offset.
|
||||
///
|
||||
/// Returns the number of bytes read.
|
||||
///
|
||||
/// The offset is relative to the start of the file and thus independent
|
||||
/// from the current cursor.
|
||||
///
|
||||
/// The current file cursor is not affected by this function.
|
||||
///
|
||||
/// Note that similar to [`File::read`], it is not an error to return with a
|
||||
/// short read.
|
||||
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
|
||||
let bufs = &mut [IoSliceMut::new(buf)];
|
||||
self.read_vectored_at(bufs, offset)
|
||||
}
|
||||
|
||||
/// Reads a number of bytes starting from a given offset.
|
||||
///
|
||||
/// Returns the number of bytes read.
|
||||
///
|
||||
/// The offset is relative to the start of the file and thus independent
|
||||
/// from the current cursor.
|
||||
///
|
||||
/// The current file cursor is not affected by this function.
|
||||
///
|
||||
/// Note that similar to [`File::read_vectored`], it is not an error to
|
||||
/// return with a short read.
|
||||
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
|
||||
|
||||
/// Reads the exact number of byte required to fill `buf` from the given offset.
|
||||
///
|
||||
/// The offset is relative to the start of the file and thus independent
|
||||
/// from the current cursor.
|
||||
///
|
||||
/// The current file cursor is not affected by this function.
|
||||
///
|
||||
/// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
|
||||
///
|
||||
/// [`read_at`]: FileExt::read_at
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If this function encounters an error of the kind
|
||||
/// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
|
||||
/// will continue.
|
||||
///
|
||||
/// If this function encounters an "end of file" before completely filling
|
||||
/// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
|
||||
/// The contents of `buf` are unspecified in this case.
|
||||
///
|
||||
/// If any other read error is encountered then this function immediately
|
||||
/// returns. The contents of `buf` are unspecified in this case.
|
||||
///
|
||||
/// If this function returns an error, it is unspecified how many bytes it
|
||||
/// has read, but it will never read more than would be necessary to
|
||||
/// completely fill the buffer.
|
||||
#[stable(feature = "rw_exact_all_at", since = "1.33.0")]
|
||||
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
|
||||
while !buf.is_empty() {
|
||||
match self.read_at(buf, offset) {
|
||||
Ok(0) => break,
|
||||
Ok(n) => {
|
||||
let tmp = buf;
|
||||
buf = &mut tmp[n..];
|
||||
offset += n as u64;
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
if !buf.is_empty() {
|
||||
Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a number of bytes starting from a given offset.
|
||||
///
|
||||
/// Returns the number of bytes written.
|
||||
///
|
||||
/// The offset is relative to the start of the file and thus independent
|
||||
/// from the current cursor.
|
||||
///
|
||||
/// The current file cursor is not affected by this function.
|
||||
///
|
||||
/// When writing beyond the end of the file, the file is appropriately
|
||||
/// extended and the intermediate bytes are initialized with the value 0.
|
||||
///
|
||||
/// Note that similar to [`File::write`], it is not an error to return a
|
||||
/// short write.
|
||||
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
|
||||
let bufs = &[IoSlice::new(buf)];
|
||||
self.write_vectored_at(bufs, offset)
|
||||
}
|
||||
|
||||
/// Writes a number of bytes starting from a given offset.
|
||||
///
|
||||
/// Returns the number of bytes written.
|
||||
///
|
||||
/// The offset is relative to the start of the file and thus independent
|
||||
/// from the current cursor.
|
||||
///
|
||||
/// The current file cursor is not affected by this function.
|
||||
///
|
||||
/// When writing beyond the end of the file, the file is appropriately
|
||||
/// extended and the intermediate bytes are initialized with the value 0.
|
||||
///
|
||||
/// Note that similar to [`File::write_vectored`], it is not an error to return a
|
||||
/// short write.
|
||||
fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
|
||||
|
||||
/// Attempts to write an entire buffer starting from a given offset.
|
||||
///
|
||||
/// The offset is relative to the start of the file and thus independent
|
||||
/// from the current cursor.
|
||||
///
|
||||
/// The current file cursor is not affected by this function.
|
||||
///
|
||||
/// This method will continuously call [`write_at`] until there is no more data
|
||||
/// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
|
||||
/// returned. This method will not return until the entire buffer has been
|
||||
/// successfully written or such an error occurs. The first error that is
|
||||
/// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
|
||||
/// returned.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return the first error of
|
||||
/// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
|
||||
///
|
||||
/// [`write_at`]: FileExt::write_at
|
||||
#[stable(feature = "rw_exact_all_at", since = "1.33.0")]
|
||||
fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
|
||||
while !buf.is_empty() {
|
||||
match self.write_at(buf, offset) {
|
||||
Ok(0) => {
|
||||
return Err(io::Error::new_const(
|
||||
io::ErrorKind::WriteZero,
|
||||
&"failed to write whole buffer",
|
||||
));
|
||||
}
|
||||
Ok(n) => {
|
||||
buf = &buf[n..];
|
||||
offset += n as u64
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the current position within the file.
|
||||
///
|
||||
/// This corresponds to the `fd_tell` syscall and is similar to
|
||||
/// `seek` where you offset 0 bytes from the current position.
|
||||
fn tell(&self) -> io::Result<u64>;
|
||||
|
||||
/// Adjust the flags associated with this file.
|
||||
///
|
||||
/// This corresponds to the `fd_fdstat_set_flags` syscall.
|
||||
fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
|
||||
|
||||
/// Adjust the rights associated with this file.
|
||||
///
|
||||
/// This corresponds to the `fd_fdstat_set_rights` syscall.
|
||||
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
|
||||
|
||||
/// Provide file advisory information on a file descriptor.
|
||||
///
|
||||
/// This corresponds to the `fd_advise` syscall.
|
||||
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
|
||||
|
||||
/// Force the allocation of space in a file.
|
||||
///
|
||||
/// This corresponds to the `fd_allocate` syscall.
|
||||
fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
|
||||
|
||||
/// Create a directory.
|
||||
///
|
||||
/// This corresponds to the `path_create_directory` syscall.
|
||||
fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
|
||||
|
||||
/// Read the contents of a symbolic link.
|
||||
///
|
||||
/// This corresponds to the `path_readlink` syscall.
|
||||
fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
|
||||
|
||||
/// Return the attributes of a file or directory.
|
||||
///
|
||||
/// This corresponds to the `path_filestat_get` syscall.
|
||||
fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
|
||||
|
||||
/// Unlink a file.
|
||||
///
|
||||
/// This corresponds to the `path_unlink_file` syscall.
|
||||
fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
|
||||
|
||||
/// Remove a directory.
|
||||
///
|
||||
/// This corresponds to the `path_remove_directory` syscall.
|
||||
fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
|
||||
}
|
||||
|
||||
// FIXME: bind fd_fdstat_get - need to define a custom return type
|
||||
// FIXME: bind fd_readdir - can't return `ReadDir` since we only have entry name
|
||||
// FIXME: bind fd_filestat_set_times maybe? - on crates.io for unix
|
||||
// FIXME: bind path_filestat_set_times maybe? - on crates.io for unix
|
||||
// FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle
|
||||
// FIXME: bind random_get maybe? - on crates.io for unix
|
||||
|
||||
impl FileExt for fs::File {
|
||||
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
|
||||
self.as_inner().fd().pread(bufs, offset)
|
||||
}
|
||||
|
||||
fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
|
||||
self.as_inner().fd().pwrite(bufs, offset)
|
||||
}
|
||||
|
||||
fn tell(&self) -> io::Result<u64> {
|
||||
self.as_inner().fd().tell()
|
||||
}
|
||||
|
||||
fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
|
||||
self.as_inner().fd().set_flags(flags)
|
||||
}
|
||||
|
||||
fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
|
||||
self.as_inner().fd().set_rights(rights, inheriting)
|
||||
}
|
||||
|
||||
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
|
||||
self.as_inner().fd().advise(offset, len, advice)
|
||||
}
|
||||
|
||||
fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
|
||||
self.as_inner().fd().allocate(offset, len)
|
||||
}
|
||||
|
||||
fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
|
||||
self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?)
|
||||
}
|
||||
|
||||
fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
|
||||
self.as_inner().read_link(path.as_ref())
|
||||
}
|
||||
|
||||
fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> {
|
||||
let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?;
|
||||
Ok(FromInner::from_inner(m))
|
||||
}
|
||||
|
||||
fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||
self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?)
|
||||
}
|
||||
|
||||
fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||
self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?)
|
||||
}
|
||||
}
|
||||
|
||||
/// WASI-specific extensions to [`fs::OpenOptions`].
|
||||
pub trait OpenOptionsExt {
|
||||
/// Pass custom `dirflags` argument to `path_open`.
|
||||
///
|
||||
/// This option configures the `dirflags` argument to the
|
||||
/// `path_open` syscall which `OpenOptions` will eventually call. The
|
||||
/// `dirflags` argument configures how the file is looked up, currently
|
||||
/// primarily affecting whether symlinks are followed or not.
|
||||
///
|
||||
/// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are
|
||||
/// followed. You can call this method with 0 to disable following symlinks
|
||||
fn lookup_flags(&mut self, flags: u32) -> &mut Self;
|
||||
|
||||
/// Indicates whether `OpenOptions` must open a directory or not.
|
||||
///
|
||||
/// This method will configure whether the `__WASI_O_DIRECTORY` flag is
|
||||
/// passed when opening a file. When passed it will require that the opened
|
||||
/// path is a directory.
|
||||
///
|
||||
/// This option is by default `false`
|
||||
fn directory(&mut self, dir: bool) -> &mut Self;
|
||||
|
||||
/// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
|
||||
/// field of `path_open`.
|
||||
///
|
||||
/// This option is by default `false`
|
||||
fn dsync(&mut self, dsync: bool) -> &mut Self;
|
||||
|
||||
/// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
|
||||
/// field of `path_open`.
|
||||
///
|
||||
/// This option is by default `false`
|
||||
fn nonblock(&mut self, nonblock: bool) -> &mut Self;
|
||||
|
||||
/// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
|
||||
/// field of `path_open`.
|
||||
///
|
||||
/// This option is by default `false`
|
||||
fn rsync(&mut self, rsync: bool) -> &mut Self;
|
||||
|
||||
/// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
|
||||
/// field of `path_open`.
|
||||
///
|
||||
/// This option is by default `false`
|
||||
fn sync(&mut self, sync: bool) -> &mut Self;
|
||||
|
||||
/// Indicates the value that should be passed in for the `fs_rights_base`
|
||||
/// parameter of `path_open`.
|
||||
///
|
||||
/// This option defaults based on the `read` and `write` configuration of
|
||||
/// this `OpenOptions` builder. If this method is called, however, the
|
||||
/// exact mask passed in will be used instead.
|
||||
fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
|
||||
|
||||
/// Indicates the value that should be passed in for the
|
||||
/// `fs_rights_inheriting` parameter of `path_open`.
|
||||
///
|
||||
/// The default for this option is the same value as what will be passed
|
||||
/// for the `fs_rights_base` parameter but if this method is called then
|
||||
/// the specified value will be used instead.
|
||||
fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self;
|
||||
|
||||
/// Open a file or directory.
|
||||
///
|
||||
/// This corresponds to the `path_open` syscall.
|
||||
fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
|
||||
}
|
||||
|
||||
impl OpenOptionsExt for OpenOptions {
|
||||
fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions {
|
||||
self.as_inner_mut().lookup_flags(flags);
|
||||
self
|
||||
}
|
||||
|
||||
fn directory(&mut self, dir: bool) -> &mut OpenOptions {
|
||||
self.as_inner_mut().directory(dir);
|
||||
self
|
||||
}
|
||||
|
||||
fn dsync(&mut self, enabled: bool) -> &mut OpenOptions {
|
||||
self.as_inner_mut().dsync(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions {
|
||||
self.as_inner_mut().nonblock(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
fn rsync(&mut self, enabled: bool) -> &mut OpenOptions {
|
||||
self.as_inner_mut().rsync(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
fn sync(&mut self, enabled: bool) -> &mut OpenOptions {
|
||||
self.as_inner_mut().sync(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions {
|
||||
self.as_inner_mut().fs_rights_base(rights);
|
||||
self
|
||||
}
|
||||
|
||||
fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions {
|
||||
self.as_inner_mut().fs_rights_inheriting(rights);
|
||||
self
|
||||
}
|
||||
|
||||
fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> {
|
||||
let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?;
|
||||
Ok(File::from_inner(inner))
|
||||
}
|
||||
}
|
||||
|
||||
/// WASI-specific extensions to [`fs::Metadata`].
|
||||
pub trait MetadataExt {
|
||||
/// Returns the `st_dev` field of the internal `filestat_t`
|
||||
fn dev(&self) -> u64;
|
||||
/// Returns the `st_ino` field of the internal `filestat_t`
|
||||
fn ino(&self) -> u64;
|
||||
/// Returns the `st_nlink` field of the internal `filestat_t`
|
||||
fn nlink(&self) -> u64;
|
||||
/// Returns the `st_size` field of the internal `filestat_t`
|
||||
fn size(&self) -> u64;
|
||||
/// Returns the `st_atim` field of the internal `filestat_t`
|
||||
fn atim(&self) -> u64;
|
||||
/// Returns the `st_mtim` field of the internal `filestat_t`
|
||||
fn mtim(&self) -> u64;
|
||||
/// Returns the `st_ctim` field of the internal `filestat_t`
|
||||
fn ctim(&self) -> u64;
|
||||
}
|
||||
|
||||
impl MetadataExt for fs::Metadata {
|
||||
fn dev(&self) -> u64 {
|
||||
self.as_inner().as_wasi().dev
|
||||
}
|
||||
fn ino(&self) -> u64 {
|
||||
self.as_inner().as_wasi().ino
|
||||
}
|
||||
fn nlink(&self) -> u64 {
|
||||
self.as_inner().as_wasi().nlink
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
self.as_inner().as_wasi().size
|
||||
}
|
||||
fn atim(&self) -> u64 {
|
||||
self.as_inner().as_wasi().atim
|
||||
}
|
||||
fn mtim(&self) -> u64 {
|
||||
self.as_inner().as_wasi().mtim
|
||||
}
|
||||
fn ctim(&self) -> u64 {
|
||||
self.as_inner().as_wasi().ctim
|
||||
}
|
||||
}
|
||||
|
||||
/// WASI-specific extensions for [`fs::FileType`].
|
||||
///
|
||||
/// Adds support for special WASI file types such as block/character devices,
|
||||
/// pipes, and sockets.
|
||||
pub trait FileTypeExt {
|
||||
/// Returns `true` if this file type is a block device.
|
||||
fn is_block_device(&self) -> bool;
|
||||
/// Returns `true` if this file type is a character device.
|
||||
fn is_character_device(&self) -> bool;
|
||||
/// Returns `true` if this file type is a socket datagram.
|
||||
fn is_socket_dgram(&self) -> bool;
|
||||
/// Returns `true` if this file type is a socket stream.
|
||||
fn is_socket_stream(&self) -> bool;
|
||||
}
|
||||
|
||||
impl FileTypeExt for fs::FileType {
|
||||
fn is_block_device(&self) -> bool {
|
||||
self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
|
||||
}
|
||||
fn is_character_device(&self) -> bool {
|
||||
self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
|
||||
}
|
||||
fn is_socket_dgram(&self) -> bool {
|
||||
self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
|
||||
}
|
||||
fn is_socket_stream(&self) -> bool {
|
||||
self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
|
||||
}
|
||||
}
|
||||
|
||||
/// WASI-specific extension methods for [`fs::DirEntry`].
|
||||
pub trait DirEntryExt {
|
||||
/// Returns the underlying `d_ino` field of the `dirent_t`
|
||||
fn ino(&self) -> u64;
|
||||
}
|
||||
|
||||
impl DirEntryExt for fs::DirEntry {
|
||||
fn ino(&self) -> u64 {
|
||||
self.as_inner().ino()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a hard link.
|
||||
///
|
||||
/// This corresponds to the `path_link` syscall.
|
||||
pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
|
||||
old_fd: &File,
|
||||
old_flags: u32,
|
||||
old_path: P,
|
||||
new_fd: &File,
|
||||
new_path: U,
|
||||
) -> io::Result<()> {
|
||||
old_fd.as_inner().fd().link(
|
||||
old_flags,
|
||||
osstr2str(old_path.as_ref().as_ref())?,
|
||||
new_fd.as_inner().fd(),
|
||||
osstr2str(new_path.as_ref().as_ref())?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Rename a file or directory.
|
||||
///
|
||||
/// This corresponds to the `path_rename` syscall.
|
||||
pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
|
||||
old_fd: &File,
|
||||
old_path: P,
|
||||
new_fd: &File,
|
||||
new_path: U,
|
||||
) -> io::Result<()> {
|
||||
old_fd.as_inner().fd().rename(
|
||||
osstr2str(old_path.as_ref().as_ref())?,
|
||||
new_fd.as_inner().fd(),
|
||||
osstr2str(new_path.as_ref().as_ref())?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a symbolic link.
|
||||
///
|
||||
/// This corresponds to the `path_symlink` syscall.
|
||||
pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
|
||||
old_path: P,
|
||||
fd: &File,
|
||||
new_path: U,
|
||||
) -> io::Result<()> {
|
||||
fd.as_inner()
|
||||
.fd()
|
||||
.symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
|
||||
}
|
||||
|
||||
/// Create a symbolic link.
|
||||
///
|
||||
/// This is a convenience API similar to `std::os::unix::fs::symlink` and
|
||||
/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
|
||||
pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
|
||||
crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
|
||||
}
|
||||
|
||||
fn osstr2str(f: &OsStr) -> io::Result<&str> {
|
||||
f.to_str().ok_or_else(|| io::Error::new_const(io::ErrorKind::Other, &"input must be utf-8"))
|
||||
}
|
201
library/std/src/os/wasi/io.rs
Normal file
201
library/std/src/os/wasi/io.rs
Normal file
|
@ -0,0 +1,201 @@
|
|||
//! WASI-specific extensions to general I/O primitives
|
||||
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![unstable(feature = "wasi_ext", issue = "none")]
|
||||
|
||||
use crate::fs;
|
||||
use crate::io;
|
||||
use crate::net;
|
||||
use crate::sys;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
|
||||
/// Raw file descriptors.
|
||||
pub type RawFd = u32;
|
||||
|
||||
/// A trait to extract the raw WASI file descriptor from an underlying
|
||||
/// object.
|
||||
pub trait AsRawFd {
|
||||
/// Extracts the raw file descriptor.
|
||||
///
|
||||
/// This method does **not** pass ownership of the raw file descriptor
|
||||
/// to the caller. The descriptor is only guaranteed to be valid while
|
||||
/// the original object has not yet been destroyed.
|
||||
fn as_raw_fd(&self) -> RawFd;
|
||||
}
|
||||
|
||||
/// A trait to express the ability to construct an object from a raw file
|
||||
/// descriptor.
|
||||
pub trait FromRawFd {
|
||||
/// Constructs a new instance of `Self` from the given raw file
|
||||
/// descriptor.
|
||||
///
|
||||
/// This function **consumes ownership** of the specified file
|
||||
/// descriptor. The returned object will take responsibility for closing
|
||||
/// it when the object goes out of scope.
|
||||
///
|
||||
/// This function is also unsafe as the primitives currently returned
|
||||
/// have the contract that they are the sole owner of the file
|
||||
/// descriptor they are wrapping. Usage of this function could
|
||||
/// accidentally allow violating this contract which can cause memory
|
||||
/// unsafety in code that relies on it being true.
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self;
|
||||
}
|
||||
|
||||
/// A trait to express the ability to consume an object and acquire ownership of
|
||||
/// its raw file descriptor.
|
||||
pub trait IntoRawFd {
|
||||
/// Consumes this object, returning the raw underlying file descriptor.
|
||||
///
|
||||
/// This function **transfers ownership** of the underlying file descriptor
|
||||
/// to the caller. Callers are then the unique owners of the file descriptor
|
||||
/// and must close the descriptor once it's no longer needed.
|
||||
fn into_raw_fd(self) -> RawFd;
|
||||
}
|
||||
|
||||
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
|
||||
impl AsRawFd for RawFd {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
|
||||
impl IntoRawFd for RawFd {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self
|
||||
}
|
||||
}
|
||||
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
|
||||
impl FromRawFd for RawFd {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for net::TcpStream {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().as_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for net::TcpStream {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
|
||||
net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for net::TcpStream {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_fd().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for net::TcpListener {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().as_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for net::TcpListener {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
|
||||
net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for net::TcpListener {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_fd().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for net::UdpSocket {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().as_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for net::UdpSocket {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
|
||||
net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for net::UdpSocket {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_fd().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for fs::File {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().as_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for fs::File {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
|
||||
fs::File::from_inner(sys::fs::File::from_inner(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for fs::File {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_fd().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for io::Stdin {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
libc::STDIN_FILENO as RawFd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for io::Stdout {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
libc::STDOUT_FILENO as RawFd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for io::Stderr {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
libc::STDERR_FILENO as RawFd
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRawFd for io::StdinLock<'a> {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
libc::STDIN_FILENO as RawFd
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRawFd for io::StdoutLock<'a> {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
libc::STDOUT_FILENO as RawFd
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRawFd for io::StderrLock<'a> {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
libc::STDERR_FILENO as RawFd
|
||||
}
|
||||
}
|
53
library/std/src/os/wasi/mod.rs
Normal file
53
library/std/src/os/wasi/mod.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
//! Platform-specific extensions to `std` for WASI.
|
||||
//!
|
||||
//! Provides access to platform-level information on WASI, and exposes
|
||||
//! WASI-specific functions that would otherwise be inappropriate as
|
||||
//! part of the core `std` library.
|
||||
//!
|
||||
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
|
||||
//! `OsString`), allows to set permissions more granularly, extract low-level
|
||||
//! file descriptors from files and sockets, and has platform-specific helpers
|
||||
//! for spawning processes.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use std::fs::File;
|
||||
//! use std::os::wasi::prelude::*;
|
||||
//!
|
||||
//! fn main() -> std::io::Result<()> {
|
||||
//! let f = File::create("foo.txt")?;
|
||||
//! let fd = f.as_raw_fd();
|
||||
//!
|
||||
//! // use fd with native WASI bindings
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![doc(cfg(target_os = "wasi"))]
|
||||
|
||||
pub mod ffi;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
|
||||
/// A prelude for conveniently writing platform-specific code.
|
||||
///
|
||||
/// Includes all extension traits, and some important type definitions.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub mod prelude {
|
||||
#[doc(no_inline)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::ffi::{OsStrExt, OsStringExt};
|
||||
#[doc(no_inline)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::fs::FileTypeExt;
|
||||
#[doc(no_inline)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
|
||||
#[doc(no_inline)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue