Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi-common/src/sync/file.rs
1693 views
1
use crate::{
2
Error, ErrorExt,
3
file::{Advice, FdFlags, FileType, Filestat, WasiFile},
4
};
5
use cap_fs_ext::MetadataExt;
6
use fs_set_times::{SetTimes, SystemTimeSpec};
7
use io_lifetimes::AsFilelike;
8
use std::any::Any;
9
use std::io::{self, IsTerminal};
10
use system_interface::{
11
fs::{FileIoExt, GetSetFdFlags},
12
io::{IoExt, ReadReady},
13
};
14
15
pub struct File(cap_std::fs::File);
16
17
impl File {
18
pub fn from_cap_std(file: cap_std::fs::File) -> Self {
19
File(file)
20
}
21
}
22
23
#[wiggle::async_trait]
24
impl WasiFile for File {
25
fn as_any(&self) -> &dyn Any {
26
self
27
}
28
#[cfg(unix)]
29
fn pollable(&self) -> Option<rustix::fd::BorrowedFd<'_>> {
30
Some(self.0.as_fd())
31
}
32
#[cfg(windows)]
33
fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
34
Some(self.0.as_raw_handle_or_socket())
35
}
36
async fn datasync(&self) -> Result<(), Error> {
37
self.0.sync_data()?;
38
Ok(())
39
}
40
async fn sync(&self) -> Result<(), Error> {
41
self.0.sync_all()?;
42
Ok(())
43
}
44
async fn get_filetype(&self) -> Result<FileType, Error> {
45
let meta = self.0.metadata()?;
46
Ok(filetype_from(&meta.file_type()))
47
}
48
async fn get_fdflags(&self) -> Result<FdFlags, Error> {
49
let fdflags = get_fd_flags(&self.0)?;
50
Ok(fdflags)
51
}
52
async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> {
53
if fdflags.intersects(
54
crate::file::FdFlags::DSYNC | crate::file::FdFlags::SYNC | crate::file::FdFlags::RSYNC,
55
) {
56
return Err(Error::invalid_argument().context("cannot set DSYNC, SYNC, or RSYNC flag"));
57
}
58
let set_fd_flags = self.0.new_set_fd_flags(to_sysif_fdflags(fdflags))?;
59
self.0.set_fd_flags(set_fd_flags)?;
60
Ok(())
61
}
62
async fn get_filestat(&self) -> Result<Filestat, Error> {
63
let meta = self.0.metadata()?;
64
Ok(Filestat {
65
device_id: meta.dev(),
66
inode: meta.ino(),
67
filetype: filetype_from(&meta.file_type()),
68
nlink: meta.nlink(),
69
size: meta.len(),
70
atim: meta.accessed().map(|t| Some(t.into_std())).unwrap_or(None),
71
mtim: meta.modified().map(|t| Some(t.into_std())).unwrap_or(None),
72
ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None),
73
})
74
}
75
async fn set_filestat_size(&self, size: u64) -> Result<(), Error> {
76
self.0.set_len(size)?;
77
Ok(())
78
}
79
async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
80
self.0.advise(offset, len, convert_advice(advice))?;
81
Ok(())
82
}
83
async fn set_times(
84
&self,
85
atime: Option<crate::SystemTimeSpec>,
86
mtime: Option<crate::SystemTimeSpec>,
87
) -> Result<(), Error> {
88
self.0
89
.set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
90
Ok(())
91
}
92
async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
93
let n = self.0.read_vectored(bufs)?;
94
Ok(n.try_into()?)
95
}
96
async fn read_vectored_at<'a>(
97
&self,
98
bufs: &mut [io::IoSliceMut<'a>],
99
offset: u64,
100
) -> Result<u64, Error> {
101
let n = self.0.read_vectored_at(bufs, offset)?;
102
Ok(n.try_into()?)
103
}
104
async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
105
let n = self.0.write_vectored(bufs)?;
106
Ok(n.try_into()?)
107
}
108
async fn write_vectored_at<'a>(
109
&self,
110
bufs: &[io::IoSlice<'a>],
111
offset: u64,
112
) -> Result<u64, Error> {
113
if bufs.iter().map(|i| i.len()).sum::<usize>() == 0 {
114
return Ok(0);
115
}
116
let n = self.0.write_vectored_at(bufs, offset)?;
117
Ok(n.try_into()?)
118
}
119
async fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
120
Ok(self.0.seek(pos)?)
121
}
122
async fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
123
let n = self.0.peek(buf)?;
124
Ok(n.try_into()?)
125
}
126
fn num_ready_bytes(&self) -> Result<u64, Error> {
127
Ok(self.0.num_ready_bytes()?)
128
}
129
fn isatty(&self) -> bool {
130
#[cfg(unix)]
131
return self.0.as_fd().is_terminal();
132
#[cfg(windows)]
133
return self.0.as_handle().is_terminal();
134
}
135
}
136
137
pub fn filetype_from(ft: &cap_std::fs::FileType) -> FileType {
138
use cap_fs_ext::FileTypeExt;
139
if ft.is_dir() {
140
FileType::Directory
141
} else if ft.is_symlink() {
142
FileType::SymbolicLink
143
} else if ft.is_socket() {
144
if ft.is_block_device() {
145
FileType::SocketDgram
146
} else {
147
FileType::SocketStream
148
}
149
} else if ft.is_block_device() {
150
FileType::BlockDevice
151
} else if ft.is_char_device() {
152
FileType::CharacterDevice
153
} else if ft.is_file() {
154
FileType::RegularFile
155
} else {
156
FileType::Unknown
157
}
158
}
159
160
#[cfg(windows)]
161
use io_lifetimes::{AsHandle, BorrowedHandle};
162
#[cfg(windows)]
163
impl AsHandle for File {
164
fn as_handle(&self) -> BorrowedHandle<'_> {
165
self.0.as_handle()
166
}
167
}
168
169
#[cfg(windows)]
170
use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
171
#[cfg(windows)]
172
impl AsRawHandleOrSocket for File {
173
#[inline]
174
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
175
self.0.as_raw_handle_or_socket()
176
}
177
}
178
179
#[cfg(unix)]
180
use io_lifetimes::{AsFd, BorrowedFd};
181
182
#[cfg(unix)]
183
impl AsFd for File {
184
fn as_fd(&self) -> BorrowedFd<'_> {
185
self.0.as_fd()
186
}
187
}
188
189
pub(crate) fn convert_systimespec(t: Option<crate::SystemTimeSpec>) -> Option<SystemTimeSpec> {
190
match t {
191
Some(crate::SystemTimeSpec::Absolute(t)) => Some(SystemTimeSpec::Absolute(t.into_std())),
192
Some(crate::SystemTimeSpec::SymbolicNow) => Some(SystemTimeSpec::SymbolicNow),
193
None => None,
194
}
195
}
196
197
pub(crate) fn to_sysif_fdflags(f: crate::file::FdFlags) -> system_interface::fs::FdFlags {
198
let mut out = system_interface::fs::FdFlags::empty();
199
if f.contains(crate::file::FdFlags::APPEND) {
200
out |= system_interface::fs::FdFlags::APPEND;
201
}
202
if f.contains(crate::file::FdFlags::DSYNC) {
203
out |= system_interface::fs::FdFlags::DSYNC;
204
}
205
if f.contains(crate::file::FdFlags::NONBLOCK) {
206
out |= system_interface::fs::FdFlags::NONBLOCK;
207
}
208
if f.contains(crate::file::FdFlags::RSYNC) {
209
out |= system_interface::fs::FdFlags::RSYNC;
210
}
211
if f.contains(crate::file::FdFlags::SYNC) {
212
out |= system_interface::fs::FdFlags::SYNC;
213
}
214
out
215
}
216
217
/// Return the file-descriptor flags for a given file-like object.
218
///
219
/// This returns the flags needed to implement [`WasiFile::get_fdflags`].
220
pub fn get_fd_flags<Filelike: AsFilelike>(f: Filelike) -> io::Result<crate::file::FdFlags> {
221
let f = f.as_filelike().get_fd_flags()?;
222
let mut out = crate::file::FdFlags::empty();
223
if f.contains(system_interface::fs::FdFlags::APPEND) {
224
out |= crate::file::FdFlags::APPEND;
225
}
226
if f.contains(system_interface::fs::FdFlags::DSYNC) {
227
out |= crate::file::FdFlags::DSYNC;
228
}
229
if f.contains(system_interface::fs::FdFlags::NONBLOCK) {
230
out |= crate::file::FdFlags::NONBLOCK;
231
}
232
if f.contains(system_interface::fs::FdFlags::RSYNC) {
233
out |= crate::file::FdFlags::RSYNC;
234
}
235
if f.contains(system_interface::fs::FdFlags::SYNC) {
236
out |= crate::file::FdFlags::SYNC;
237
}
238
Ok(out)
239
}
240
241
fn convert_advice(advice: Advice) -> system_interface::fs::Advice {
242
match advice {
243
Advice::Normal => system_interface::fs::Advice::Normal,
244
Advice::Sequential => system_interface::fs::Advice::Sequential,
245
Advice::Random => system_interface::fs::Advice::Random,
246
Advice::WillNeed => system_interface::fs::Advice::WillNeed,
247
Advice::DontNeed => system_interface::fs::Advice::DontNeed,
248
Advice::NoReuse => system_interface::fs::Advice::NoReuse,
249
}
250
}
251
252