@wasm-oj/server 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/THIRD_PARTY_NOTICES.md +302 -0
- package/crates/runtime-core/Cargo.lock +5099 -0
- package/crates/runtime-core/Cargo.toml +66 -0
- package/crates/runtime-core/README.md +47 -0
- package/crates/runtime-core/src/bin/wasm-oj-compiler.rs +418 -0
- package/crates/runtime-core/src/bin/wasm-oj-runner.rs +294 -0
- package/crates/runtime-core/src/capabilities.rs +118 -0
- package/crates/runtime-core/src/compiler.rs +658 -0
- package/crates/runtime-core/src/contract.rs +5 -0
- package/crates/runtime-core/src/deterministic.rs +1051 -0
- package/crates/runtime-core/src/error.rs +58 -0
- package/crates/runtime-core/src/filesystem.rs +547 -0
- package/crates/runtime-core/src/filesystem_quota.rs +167 -0
- package/crates/runtime-core/src/go_compiler_session.rs +297 -0
- package/crates/runtime-core/src/interactive.rs +1019 -0
- package/crates/runtime-core/src/judge_package.rs +1539 -0
- package/crates/runtime-core/src/lib.rs +98 -0
- package/crates/runtime-core/src/memory.rs +84 -0
- package/crates/runtime-core/src/meter.rs +549 -0
- package/crates/runtime-core/src/module_imports.rs +149 -0
- package/crates/runtime-core/src/module_policy.rs +714 -0
- package/crates/runtime-core/src/output.rs +204 -0
- package/crates/runtime-core/src/run/mod.rs +208 -0
- package/crates/runtime-core/src/run/native.rs +260 -0
- package/crates/runtime-core/src/run/web.rs +229 -0
- package/crates/runtime-core/src/run/web_runtime.rs +109 -0
- package/crates/runtime-core/src/types.rs +268 -0
- package/crates/runtime-core/src/web.rs +83 -0
- package/dist/chunks/go-toolchain-Dbt-lp2L.js +426 -0
- package/dist/chunks/java-toolchain-DajoRCHu.js +44 -0
- package/dist/chunks/python-toolchain-Dx834o2A.js +4 -0
- package/dist/chunks/rust-toolchain-CJ3sMxPE.js +252 -0
- package/dist/chunks/toolchains-C6KuA1yM.js +224 -0
- package/dist/go-stage.mjs +193 -0
- package/dist/index.d.ts +221 -0
- package/dist/index.js +4393 -0
- package/dist/java-stage.mjs +111 -0
- package/dist/python-stage.mjs +90 -0
- package/dist/rustc-stage.mjs +301 -0
- package/dist/server-build-stage.mjs +2564 -0
- package/dist/server-runner-stage.mjs +155 -0
- package/licenses/fflate-MIT.txt +21 -0
- package/licenses/runtime-core-dependencies.html +6253 -0
- package/licenses/runtime-core-dependencies.json +3041 -0
- package/licenses/wasmer-sdk-MIT.txt +21 -0
- package/licenses/wasmer-sdk-dependencies.html +6901 -0
- package/licenses/wasmer-sdk-dependencies.json +3013 -0
- package/package.json +70 -0
- package/rust-toolchain.toml +5 -0
- package/testdata/wojjdg02-v2-text.hex +1 -0
- package/vendor/shared-buffer/Cargo.toml +22 -0
- package/vendor/shared-buffer/LICENSE_APACHE.md +176 -0
- package/vendor/shared-buffer/LICENSE_MIT.md +25 -0
- package/vendor/shared-buffer/README.md +34 -0
- package/vendor/shared-buffer/src/lib.rs +58 -0
- package/vendor/shared-buffer/src/mmap.rs +250 -0
- package/vendor/shared-buffer/src/owned.rs +389 -0
- package/vendor/virtual-fs/Cargo.toml +181 -0
- package/vendor/virtual-fs/LICENSE +25 -0
- package/vendor/virtual-fs/src/arc_box_file.rs +142 -0
- package/vendor/virtual-fs/src/arc_file.rs +182 -0
- package/vendor/virtual-fs/src/arc_fs.rs +68 -0
- package/vendor/virtual-fs/src/buffer_file.rs +103 -0
- package/vendor/virtual-fs/src/builder.rs +232 -0
- package/vendor/virtual-fs/src/combine_file.rs +101 -0
- package/vendor/virtual-fs/src/cow_file.rs +345 -0
- package/vendor/virtual-fs/src/dual_write_file.rs +113 -0
- package/vendor/virtual-fs/src/empty_fs.rs +81 -0
- package/vendor/virtual-fs/src/filesystems.rs +108 -0
- package/vendor/virtual-fs/src/host_fs.rs +1390 -0
- package/vendor/virtual-fs/src/lib.rs +782 -0
- package/vendor/virtual-fs/src/limiter.rs +252 -0
- package/vendor/virtual-fs/src/mem_fs/file.rs +1799 -0
- package/vendor/virtual-fs/src/mem_fs/file_opener.rs +941 -0
- package/vendor/virtual-fs/src/mem_fs/filesystem.rs +2134 -0
- package/vendor/virtual-fs/src/mem_fs/mod.rs +245 -0
- package/vendor/virtual-fs/src/mem_fs/offloaded_file.rs +474 -0
- package/vendor/virtual-fs/src/mem_fs/stdio.rs +318 -0
- package/vendor/virtual-fs/src/mount_fs.rs +2225 -0
- package/vendor/virtual-fs/src/null_file.rs +87 -0
- package/vendor/virtual-fs/src/ops.rs +364 -0
- package/vendor/virtual-fs/src/overlay_fs.rs +2216 -0
- package/vendor/virtual-fs/src/passthru_fs.rs +119 -0
- package/vendor/virtual-fs/src/pipe.rs +603 -0
- package/vendor/virtual-fs/src/random_file.rs +88 -0
- package/vendor/virtual-fs/src/special_file.rs +108 -0
- package/vendor/virtual-fs/src/static_file.rs +133 -0
- package/vendor/virtual-fs/src/static_fs.rs +460 -0
- package/vendor/virtual-fs/src/tmp_fs.rs +95 -0
- package/vendor/virtual-fs/src/trace_fs.rs +258 -0
- package/vendor/virtual-fs/src/webc_volume_fs.rs +829 -0
- package/vendor/virtual-fs/src/zero_file.rs +90 -0
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
#![cfg_attr(docsrs, feature(doc_cfg))]
|
|
2
|
+
|
|
3
|
+
#[cfg(feature = "enable-serde")]
|
|
4
|
+
const _: () = {
|
|
5
|
+
#[deprecated(
|
|
6
|
+
note = "The `enable-serde` feature is deprecated and will be removed in the next major release of Wasmer."
|
|
7
|
+
)]
|
|
8
|
+
fn __enable_serde_deprecated() {}
|
|
9
|
+
let _ = __enable_serde_deprecated;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
#[cfg(test)]
|
|
13
|
+
#[macro_use]
|
|
14
|
+
extern crate pretty_assertions;
|
|
15
|
+
|
|
16
|
+
use futures::future::BoxFuture;
|
|
17
|
+
use shared_buffer::OwnedBuffer;
|
|
18
|
+
use std::any::Any;
|
|
19
|
+
use std::ffi::OsString;
|
|
20
|
+
use std::fmt;
|
|
21
|
+
use std::io;
|
|
22
|
+
use std::ops::Deref;
|
|
23
|
+
use std::path::{Path, PathBuf};
|
|
24
|
+
use std::pin::Pin;
|
|
25
|
+
use std::task::Context;
|
|
26
|
+
use std::task::Poll;
|
|
27
|
+
use thiserror::Error;
|
|
28
|
+
|
|
29
|
+
pub mod arc_box_file;
|
|
30
|
+
pub mod arc_file;
|
|
31
|
+
pub mod arc_fs;
|
|
32
|
+
pub mod buffer_file;
|
|
33
|
+
pub mod builder;
|
|
34
|
+
pub mod combine_file;
|
|
35
|
+
pub mod cow_file;
|
|
36
|
+
pub mod dual_write_file;
|
|
37
|
+
pub mod empty_fs;
|
|
38
|
+
#[cfg(feature = "host-fs")]
|
|
39
|
+
pub mod host_fs;
|
|
40
|
+
pub mod mem_fs;
|
|
41
|
+
pub mod mount_fs;
|
|
42
|
+
pub mod null_file;
|
|
43
|
+
pub mod passthru_fs;
|
|
44
|
+
pub mod random_file;
|
|
45
|
+
pub mod special_file;
|
|
46
|
+
pub mod tmp_fs;
|
|
47
|
+
pub mod zero_file;
|
|
48
|
+
// tty_file -> see wasmer_wasi::tty_file
|
|
49
|
+
mod filesystems;
|
|
50
|
+
pub(crate) mod ops;
|
|
51
|
+
mod overlay_fs;
|
|
52
|
+
pub mod pipe;
|
|
53
|
+
mod static_file;
|
|
54
|
+
#[cfg(feature = "static-fs")]
|
|
55
|
+
pub mod static_fs;
|
|
56
|
+
mod trace_fs;
|
|
57
|
+
#[cfg(feature = "webc-fs")]
|
|
58
|
+
mod webc_volume_fs;
|
|
59
|
+
|
|
60
|
+
pub mod limiter;
|
|
61
|
+
|
|
62
|
+
pub use arc_box_file::*;
|
|
63
|
+
pub use arc_file::*;
|
|
64
|
+
pub use arc_fs::*;
|
|
65
|
+
pub use buffer_file::*;
|
|
66
|
+
pub use builder::*;
|
|
67
|
+
pub use combine_file::*;
|
|
68
|
+
pub use cow_file::*;
|
|
69
|
+
pub use dual_write_file::*;
|
|
70
|
+
pub use empty_fs::*;
|
|
71
|
+
pub use filesystems::FileSystems;
|
|
72
|
+
pub use mount_fs::*;
|
|
73
|
+
pub use null_file::*;
|
|
74
|
+
pub use overlay_fs::OverlayFileSystem;
|
|
75
|
+
pub use passthru_fs::*;
|
|
76
|
+
pub use pipe::*;
|
|
77
|
+
pub use special_file::*;
|
|
78
|
+
pub use static_file::StaticFile;
|
|
79
|
+
pub use tmp_fs::*;
|
|
80
|
+
pub use trace_fs::TraceFileSystem;
|
|
81
|
+
#[cfg(feature = "webc-fs")]
|
|
82
|
+
pub use webc_volume_fs::WebcVolumeFileSystem;
|
|
83
|
+
pub use zero_file::*;
|
|
84
|
+
|
|
85
|
+
pub type Result<T> = std::result::Result<T, FsError>;
|
|
86
|
+
|
|
87
|
+
// re-exports
|
|
88
|
+
pub use tokio::io::ReadBuf;
|
|
89
|
+
pub use tokio::io::{AsyncRead, AsyncReadExt};
|
|
90
|
+
pub use tokio::io::{AsyncSeek, AsyncSeekExt};
|
|
91
|
+
pub use tokio::io::{AsyncWrite, AsyncWriteExt};
|
|
92
|
+
|
|
93
|
+
pub trait CloneableVirtualFile: VirtualFile + Clone {}
|
|
94
|
+
|
|
95
|
+
pub use ops::{copy_reference, copy_reference_ext, create_dir_all, walk};
|
|
96
|
+
|
|
97
|
+
pub trait FileSystem: fmt::Debug + Send + Sync + 'static + Upcastable {
|
|
98
|
+
fn readlink(&self, path: &Path) -> Result<PathBuf>;
|
|
99
|
+
fn read_dir(&self, path: &Path) -> Result<ReadDir>;
|
|
100
|
+
fn create_dir(&self, path: &Path) -> Result<()>;
|
|
101
|
+
fn create_symlink(&self, _source: &Path, _target: &Path) -> Result<()> {
|
|
102
|
+
Err(FsError::Unsupported)
|
|
103
|
+
}
|
|
104
|
+
fn hard_link(&self, _source: &Path, _target: &Path) -> Result<()> {
|
|
105
|
+
Err(FsError::Unsupported)
|
|
106
|
+
}
|
|
107
|
+
fn remove_dir(&self, path: &Path) -> Result<()>;
|
|
108
|
+
fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>>;
|
|
109
|
+
fn metadata(&self, path: &Path) -> Result<Metadata>;
|
|
110
|
+
/// This method gets metadata without following symlinks in the path.
|
|
111
|
+
/// Currently identical to `metadata` because symlinks aren't implemented
|
|
112
|
+
/// yet.
|
|
113
|
+
fn symlink_metadata(&self, path: &Path) -> Result<Metadata>;
|
|
114
|
+
fn remove_file(&self, path: &Path) -> Result<()>;
|
|
115
|
+
|
|
116
|
+
fn new_open_options(&self) -> OpenOptions<'_>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
impl dyn FileSystem + 'static {
|
|
120
|
+
#[inline]
|
|
121
|
+
pub fn downcast_ref<T: 'static>(&'_ self) -> Option<&'_ T> {
|
|
122
|
+
self.upcast_any_ref().downcast_ref::<T>()
|
|
123
|
+
}
|
|
124
|
+
#[inline]
|
|
125
|
+
pub fn downcast_mut<T: 'static>(&'_ mut self) -> Option<&'_ mut T> {
|
|
126
|
+
self.upcast_any_mut().downcast_mut::<T>()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#[async_trait::async_trait]
|
|
131
|
+
impl<D, F> FileSystem for D
|
|
132
|
+
where
|
|
133
|
+
D: Deref<Target = F> + std::fmt::Debug + Send + Sync + 'static,
|
|
134
|
+
F: FileSystem + ?Sized,
|
|
135
|
+
{
|
|
136
|
+
fn read_dir(&self, path: &Path) -> Result<ReadDir> {
|
|
137
|
+
(**self).read_dir(path)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn readlink(&self, path: &Path) -> Result<PathBuf> {
|
|
141
|
+
(**self).readlink(path)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fn create_dir(&self, path: &Path) -> Result<()> {
|
|
145
|
+
(**self).create_dir(path)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fn create_symlink(&self, source: &Path, target: &Path) -> Result<()> {
|
|
149
|
+
(**self).create_symlink(source, target)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
fn remove_dir(&self, path: &Path) -> Result<()> {
|
|
153
|
+
(**self).remove_dir(path)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, Result<()>> {
|
|
157
|
+
Box::pin(async { (**self).rename(from, to).await })
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
fn metadata(&self, path: &Path) -> Result<Metadata> {
|
|
161
|
+
(**self).metadata(path)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
fn symlink_metadata(&self, path: &Path) -> Result<Metadata> {
|
|
165
|
+
(**self).symlink_metadata(path)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
fn remove_file(&self, path: &Path) -> Result<()> {
|
|
169
|
+
(**self).remove_file(path)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
fn new_open_options(&self) -> OpenOptions<'_> {
|
|
173
|
+
(**self).new_open_options()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
pub trait FileOpener {
|
|
178
|
+
fn open(
|
|
179
|
+
&self,
|
|
180
|
+
path: &Path,
|
|
181
|
+
conf: &OpenOptionsConfig,
|
|
182
|
+
) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
#[derive(Debug, Clone)]
|
|
186
|
+
pub struct OpenOptionsConfig {
|
|
187
|
+
pub read: bool,
|
|
188
|
+
pub write: bool,
|
|
189
|
+
pub create_new: bool,
|
|
190
|
+
pub create: bool,
|
|
191
|
+
pub append: bool,
|
|
192
|
+
pub truncate: bool,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
impl OpenOptionsConfig {
|
|
196
|
+
/// Returns the minimum allowed rights, given the rights of the parent directory
|
|
197
|
+
pub fn minimum_rights(&self, parent_rights: &Self) -> Self {
|
|
198
|
+
Self {
|
|
199
|
+
read: parent_rights.read && self.read,
|
|
200
|
+
write: parent_rights.write && self.write,
|
|
201
|
+
create_new: parent_rights.create_new && self.create_new,
|
|
202
|
+
create: parent_rights.create && self.create,
|
|
203
|
+
append: parent_rights.append && self.append,
|
|
204
|
+
truncate: parent_rights.truncate && self.truncate,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
pub const fn read(&self) -> bool {
|
|
209
|
+
self.read
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pub const fn write(&self) -> bool {
|
|
213
|
+
self.write
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
pub const fn create_new(&self) -> bool {
|
|
217
|
+
self.create_new
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
pub const fn create(&self) -> bool {
|
|
221
|
+
self.create
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
pub const fn append(&self) -> bool {
|
|
225
|
+
self.append
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
pub const fn truncate(&self) -> bool {
|
|
229
|
+
self.truncate
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/// Would a file opened with this [`OpenOptionsConfig`] change files on the
|
|
233
|
+
/// filesystem.
|
|
234
|
+
pub const fn would_mutate(&self) -> bool {
|
|
235
|
+
let OpenOptionsConfig {
|
|
236
|
+
read: _,
|
|
237
|
+
write,
|
|
238
|
+
create_new,
|
|
239
|
+
create,
|
|
240
|
+
append,
|
|
241
|
+
truncate,
|
|
242
|
+
} = *self;
|
|
243
|
+
append || write || create || create_new || truncate
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
impl fmt::Debug for OpenOptions<'_> {
|
|
248
|
+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
249
|
+
self.conf.fmt(f)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
pub struct OpenOptions<'a> {
|
|
254
|
+
opener: &'a dyn FileOpener,
|
|
255
|
+
conf: OpenOptionsConfig,
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
impl<'a> OpenOptions<'a> {
|
|
259
|
+
pub fn new(opener: &'a dyn FileOpener) -> Self {
|
|
260
|
+
Self {
|
|
261
|
+
opener,
|
|
262
|
+
conf: OpenOptionsConfig {
|
|
263
|
+
read: false,
|
|
264
|
+
write: false,
|
|
265
|
+
create_new: false,
|
|
266
|
+
create: false,
|
|
267
|
+
append: false,
|
|
268
|
+
truncate: false,
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
pub fn get_config(&self) -> OpenOptionsConfig {
|
|
274
|
+
self.conf.clone()
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/// Use an existing [`OpenOptionsConfig`] to configure this [`OpenOptions`].
|
|
278
|
+
pub fn options(&mut self, options: OpenOptionsConfig) -> &mut Self {
|
|
279
|
+
self.conf = options;
|
|
280
|
+
self
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/// Sets the option for read access.
|
|
284
|
+
///
|
|
285
|
+
/// This option, when true, will indicate that the file should be
|
|
286
|
+
/// `read`-able if opened.
|
|
287
|
+
pub fn read(&mut self, read: bool) -> &mut Self {
|
|
288
|
+
self.conf.read = read;
|
|
289
|
+
self
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/// Sets the option for write access.
|
|
293
|
+
///
|
|
294
|
+
/// This option, when true, will indicate that the file should be
|
|
295
|
+
/// `write`-able if opened.
|
|
296
|
+
///
|
|
297
|
+
/// If the file already exists, any write calls on it will overwrite its
|
|
298
|
+
/// contents, without truncating it.
|
|
299
|
+
pub fn write(&mut self, write: bool) -> &mut Self {
|
|
300
|
+
self.conf.write = write;
|
|
301
|
+
self
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/// Sets the option for the append mode.
|
|
305
|
+
///
|
|
306
|
+
/// This option, when true, means that writes will append to a file instead
|
|
307
|
+
/// of overwriting previous contents.
|
|
308
|
+
/// Note that setting `.write(true).append(true)` has the same effect as
|
|
309
|
+
/// setting only `.append(true)`.
|
|
310
|
+
pub fn append(&mut self, append: bool) -> &mut Self {
|
|
311
|
+
self.conf.append = append;
|
|
312
|
+
self
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/// Sets the option for truncating a previous file.
|
|
316
|
+
///
|
|
317
|
+
/// If a file is successfully opened with this option set it will truncate
|
|
318
|
+
/// the file to 0 length if it already exists.
|
|
319
|
+
///
|
|
320
|
+
/// The file must be opened with write access for truncate to work.
|
|
321
|
+
pub fn truncate(&mut self, truncate: bool) -> &mut Self {
|
|
322
|
+
self.conf.truncate = truncate;
|
|
323
|
+
self
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/// Sets the option to create a new file, or open it if it already exists.
|
|
327
|
+
pub fn create(&mut self, create: bool) -> &mut Self {
|
|
328
|
+
self.conf.create = create;
|
|
329
|
+
self
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/// Sets the option to create a new file, failing if it already exists.
|
|
333
|
+
pub fn create_new(&mut self, create_new: bool) -> &mut Self {
|
|
334
|
+
self.conf.create_new = create_new;
|
|
335
|
+
self
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
pub fn open<P: AsRef<Path>>(
|
|
339
|
+
&mut self,
|
|
340
|
+
path: P,
|
|
341
|
+
) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> {
|
|
342
|
+
self.opener.open(path.as_ref(), &self.conf)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/// This trait relies on your file closing when it goes out of scope via `Drop`
|
|
347
|
+
pub trait VirtualFile:
|
|
348
|
+
fmt::Debug + AsyncRead + AsyncWrite + AsyncSeek + Unpin + Upcastable + Send
|
|
349
|
+
{
|
|
350
|
+
/// the last time the file was accessed in nanoseconds as a UNIX timestamp
|
|
351
|
+
fn last_accessed(&self) -> u64;
|
|
352
|
+
|
|
353
|
+
/// the last time the file was modified in nanoseconds as a UNIX timestamp
|
|
354
|
+
fn last_modified(&self) -> u64;
|
|
355
|
+
|
|
356
|
+
/// the time at which the file was created in nanoseconds as a UNIX timestamp
|
|
357
|
+
fn created_time(&self) -> u64;
|
|
358
|
+
|
|
359
|
+
#[allow(unused_variables)]
|
|
360
|
+
/// sets accessed and modified time
|
|
361
|
+
fn set_times(&mut self, atime: Option<u64>, mtime: Option<u64>) -> crate::Result<()> {
|
|
362
|
+
Ok(())
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/// the size of the file in bytes
|
|
366
|
+
fn size(&self) -> u64;
|
|
367
|
+
|
|
368
|
+
/// Change the size of the file, if the `new_size` is greater than the current size
|
|
369
|
+
/// the extra bytes will be allocated and zeroed
|
|
370
|
+
fn set_len(&mut self, new_size: u64) -> Result<()>;
|
|
371
|
+
|
|
372
|
+
/// Remove the file from the filesystem namespace.
|
|
373
|
+
///
|
|
374
|
+
/// Existing open handles may continue to operate after this call.
|
|
375
|
+
/// Backends may defer final storage reclamation until the last open
|
|
376
|
+
/// handle is dropped.
|
|
377
|
+
fn unlink(&mut self) -> Result<()>;
|
|
378
|
+
|
|
379
|
+
/// Indicates if the file is opened or closed. This function must not block
|
|
380
|
+
/// Defaults to a status of being constantly open
|
|
381
|
+
fn is_open(&self) -> bool {
|
|
382
|
+
true
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/// Used for "special" files such as `stdin`, `stdout` and `stderr`.
|
|
386
|
+
/// Always returns the same file descriptor (0, 1 or 2). Returns `None`
|
|
387
|
+
/// on normal files
|
|
388
|
+
fn get_special_fd(&self) -> Option<u32> {
|
|
389
|
+
None
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/// Writes to this file using an mmap offset and reference
|
|
393
|
+
/// (this method only works for mmap optimized file systems)
|
|
394
|
+
fn write_from_mmap(&mut self, _offset: u64, _len: u64) -> std::io::Result<()> {
|
|
395
|
+
Err(std::io::ErrorKind::Unsupported.into())
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/// This method will copy a file from a source to this destination where
|
|
399
|
+
/// the default is to do a straight byte copy however file system implementors
|
|
400
|
+
/// may optimize this to do a zero copy
|
|
401
|
+
fn copy_reference(
|
|
402
|
+
&mut self,
|
|
403
|
+
mut src: Box<dyn VirtualFile + Send + Sync + 'static>,
|
|
404
|
+
) -> BoxFuture<'_, std::io::Result<()>> {
|
|
405
|
+
Box::pin(async move {
|
|
406
|
+
let bytes_written = tokio::io::copy(&mut src, self).await?;
|
|
407
|
+
tracing::trace!(bytes_written, "Copying file into host filesystem");
|
|
408
|
+
Ok(())
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/// This method will copy a file from a source to this destination where
|
|
413
|
+
/// the default is to do a straight byte copy however file system implementors
|
|
414
|
+
/// may optimize this to cheaply clone and store the OwnedBuffer directly
|
|
415
|
+
fn copy_from_owned_buffer(&mut self, src: &OwnedBuffer) -> BoxFuture<'_, std::io::Result<()>> {
|
|
416
|
+
let src = src.clone();
|
|
417
|
+
Box::pin(async move {
|
|
418
|
+
let mut bytes = src.as_slice();
|
|
419
|
+
let bytes_written = tokio::io::copy(&mut bytes, self).await?;
|
|
420
|
+
tracing::trace!(bytes_written, "Copying file into host filesystem");
|
|
421
|
+
Ok(())
|
|
422
|
+
})
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/// Get the full contents of this file as an [`OwnedBuffer`].
|
|
426
|
+
///
|
|
427
|
+
/// **NOTE**: Only implement this if the file is already available in-memory
|
|
428
|
+
/// and can be cloned cheaply!
|
|
429
|
+
///
|
|
430
|
+
/// Allows consumers to do zero-copy cloning of the underlying data.
|
|
431
|
+
fn as_owned_buffer(&self) -> Option<OwnedBuffer> {
|
|
432
|
+
None
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/// Polls the file for when there is data to be read
|
|
436
|
+
fn poll_read_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>>;
|
|
437
|
+
|
|
438
|
+
/// Polls the file for when it is available for writing
|
|
439
|
+
fn poll_write_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>>;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Implementation of `Upcastable` taken from https://users.rust-lang.org/t/why-does-downcasting-not-work-for-subtraits/33286/7 .
|
|
443
|
+
/// Trait needed to get downcasting from `VirtualFile` to work.
|
|
444
|
+
pub trait Upcastable {
|
|
445
|
+
fn upcast_any_ref(&'_ self) -> &'_ dyn Any;
|
|
446
|
+
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any;
|
|
447
|
+
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any>;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
impl<T: Any + fmt::Debug + 'static> Upcastable for T {
|
|
451
|
+
#[inline]
|
|
452
|
+
fn upcast_any_ref(&'_ self) -> &'_ dyn Any {
|
|
453
|
+
self
|
|
454
|
+
}
|
|
455
|
+
#[inline]
|
|
456
|
+
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any {
|
|
457
|
+
self
|
|
458
|
+
}
|
|
459
|
+
#[inline]
|
|
460
|
+
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any> {
|
|
461
|
+
self
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/// Determines the mode that stdio handlers will operate in
|
|
466
|
+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
467
|
+
pub enum StdioMode {
|
|
468
|
+
/// Stdio will be piped to a file descriptor
|
|
469
|
+
Piped,
|
|
470
|
+
/// Stdio will inherit the file handlers of its parent
|
|
471
|
+
Inherit,
|
|
472
|
+
/// Stdio will be dropped
|
|
473
|
+
Null,
|
|
474
|
+
/// Stdio will be sent to the log handler
|
|
475
|
+
Log,
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/// Error type for external users
|
|
479
|
+
#[derive(Error, Copy, Clone, Debug, PartialEq, Eq)]
|
|
480
|
+
pub enum FsError {
|
|
481
|
+
/// The fd given as a base was not a directory so the operation was not possible
|
|
482
|
+
#[error("fd not a directory")]
|
|
483
|
+
BaseNotDirectory,
|
|
484
|
+
/// Expected a file but found not a file
|
|
485
|
+
#[error("fd not a file")]
|
|
486
|
+
NotAFile,
|
|
487
|
+
/// The fd given was not usable
|
|
488
|
+
#[error("invalid fd")]
|
|
489
|
+
InvalidFd,
|
|
490
|
+
/// File exists
|
|
491
|
+
#[error("file exists")]
|
|
492
|
+
AlreadyExists,
|
|
493
|
+
/// The filesystem has failed to lock a resource.
|
|
494
|
+
#[error("lock error")]
|
|
495
|
+
Lock,
|
|
496
|
+
/// Something failed when doing IO. These errors can generally not be handled.
|
|
497
|
+
/// It may work if tried again.
|
|
498
|
+
#[error("io error")]
|
|
499
|
+
IOError,
|
|
500
|
+
/// The address was in use
|
|
501
|
+
#[error("address is in use")]
|
|
502
|
+
AddressInUse,
|
|
503
|
+
/// The address could not be found
|
|
504
|
+
#[error("address could not be found")]
|
|
505
|
+
AddressNotAvailable,
|
|
506
|
+
/// A pipe was closed
|
|
507
|
+
#[error("broken pipe (was closed)")]
|
|
508
|
+
BrokenPipe,
|
|
509
|
+
/// The connection was aborted
|
|
510
|
+
#[error("connection aborted")]
|
|
511
|
+
ConnectionAborted,
|
|
512
|
+
/// The connection request was refused
|
|
513
|
+
#[error("connection refused")]
|
|
514
|
+
ConnectionRefused,
|
|
515
|
+
/// The connection was reset
|
|
516
|
+
#[error("connection reset")]
|
|
517
|
+
ConnectionReset,
|
|
518
|
+
/// The operation was interrupted before it could finish
|
|
519
|
+
#[error("operation interrupted")]
|
|
520
|
+
Interrupted,
|
|
521
|
+
/// Invalid internal data, if the argument data is invalid, use `InvalidInput`
|
|
522
|
+
#[error("invalid internal data")]
|
|
523
|
+
InvalidData,
|
|
524
|
+
/// The provided data is invalid
|
|
525
|
+
#[error("invalid input")]
|
|
526
|
+
InvalidInput,
|
|
527
|
+
/// Could not perform the operation because there was not an open connection
|
|
528
|
+
#[error("connection is not open")]
|
|
529
|
+
NotConnected,
|
|
530
|
+
/// The requested file or directory could not be found
|
|
531
|
+
#[error("entry not found")]
|
|
532
|
+
EntryNotFound,
|
|
533
|
+
/// The requested device couldn't be accessed
|
|
534
|
+
#[error("can't access device")]
|
|
535
|
+
NoDevice,
|
|
536
|
+
/// Caller was not allowed to perform this operation
|
|
537
|
+
#[error("permission denied")]
|
|
538
|
+
PermissionDenied,
|
|
539
|
+
/// The operation did not complete within the given amount of time
|
|
540
|
+
#[error("time out")]
|
|
541
|
+
TimedOut,
|
|
542
|
+
/// Found EOF when EOF was not expected
|
|
543
|
+
#[error("unexpected eof")]
|
|
544
|
+
UnexpectedEof,
|
|
545
|
+
/// Operation would block, this error lets the caller know that they can try again
|
|
546
|
+
#[error("blocking operation. try again")]
|
|
547
|
+
WouldBlock,
|
|
548
|
+
/// A call to write returned 0
|
|
549
|
+
#[error("write returned 0")]
|
|
550
|
+
WriteZero,
|
|
551
|
+
/// Directory not Empty
|
|
552
|
+
#[error("directory not empty")]
|
|
553
|
+
DirectoryNotEmpty,
|
|
554
|
+
#[error("storage full")]
|
|
555
|
+
StorageFull,
|
|
556
|
+
/// Some other unhandled error. If you see this, it's probably a bug.
|
|
557
|
+
#[error("unknown error found")]
|
|
558
|
+
UnknownError,
|
|
559
|
+
/// Operation is not supported on this filesystem
|
|
560
|
+
#[error("unsupported")]
|
|
561
|
+
Unsupported,
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
impl From<io::Error> for FsError {
|
|
565
|
+
fn from(io_error: io::Error) -> Self {
|
|
566
|
+
match io_error.kind() {
|
|
567
|
+
io::ErrorKind::AddrInUse => FsError::AddressInUse,
|
|
568
|
+
io::ErrorKind::AddrNotAvailable => FsError::AddressNotAvailable,
|
|
569
|
+
io::ErrorKind::AlreadyExists => FsError::AlreadyExists,
|
|
570
|
+
io::ErrorKind::BrokenPipe => FsError::BrokenPipe,
|
|
571
|
+
io::ErrorKind::ConnectionAborted => FsError::ConnectionAborted,
|
|
572
|
+
io::ErrorKind::ConnectionRefused => FsError::ConnectionRefused,
|
|
573
|
+
io::ErrorKind::ConnectionReset => FsError::ConnectionReset,
|
|
574
|
+
io::ErrorKind::Interrupted => FsError::Interrupted,
|
|
575
|
+
io::ErrorKind::InvalidData => FsError::InvalidData,
|
|
576
|
+
io::ErrorKind::InvalidInput => FsError::InvalidInput,
|
|
577
|
+
io::ErrorKind::NotConnected => FsError::NotConnected,
|
|
578
|
+
io::ErrorKind::NotFound => FsError::EntryNotFound,
|
|
579
|
+
io::ErrorKind::PermissionDenied => FsError::PermissionDenied,
|
|
580
|
+
io::ErrorKind::TimedOut => FsError::TimedOut,
|
|
581
|
+
io::ErrorKind::UnexpectedEof => FsError::UnexpectedEof,
|
|
582
|
+
io::ErrorKind::WouldBlock => FsError::WouldBlock,
|
|
583
|
+
io::ErrorKind::WriteZero => FsError::WriteZero,
|
|
584
|
+
// NOTE: Add this once the "io_error_more" Rust feature is stabilized
|
|
585
|
+
// io::ErrorKind::StorageFull => FsError::StorageFull,
|
|
586
|
+
io::ErrorKind::Other => FsError::IOError,
|
|
587
|
+
// if the following triggers, a new error type was added to this non-exhaustive enum
|
|
588
|
+
_ => FsError::UnknownError,
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
impl From<FsError> for io::Error {
|
|
594
|
+
fn from(val: FsError) -> Self {
|
|
595
|
+
let kind = match val {
|
|
596
|
+
FsError::AddressInUse => io::ErrorKind::AddrInUse,
|
|
597
|
+
FsError::AddressNotAvailable => io::ErrorKind::AddrNotAvailable,
|
|
598
|
+
FsError::AlreadyExists => io::ErrorKind::AlreadyExists,
|
|
599
|
+
FsError::BrokenPipe => io::ErrorKind::BrokenPipe,
|
|
600
|
+
FsError::ConnectionAborted => io::ErrorKind::ConnectionAborted,
|
|
601
|
+
FsError::ConnectionRefused => io::ErrorKind::ConnectionRefused,
|
|
602
|
+
FsError::ConnectionReset => io::ErrorKind::ConnectionReset,
|
|
603
|
+
FsError::Interrupted => io::ErrorKind::Interrupted,
|
|
604
|
+
FsError::InvalidData => io::ErrorKind::InvalidData,
|
|
605
|
+
FsError::InvalidInput => io::ErrorKind::InvalidInput,
|
|
606
|
+
FsError::NotConnected => io::ErrorKind::NotConnected,
|
|
607
|
+
FsError::EntryNotFound => io::ErrorKind::NotFound,
|
|
608
|
+
FsError::PermissionDenied => io::ErrorKind::PermissionDenied,
|
|
609
|
+
FsError::TimedOut => io::ErrorKind::TimedOut,
|
|
610
|
+
FsError::UnexpectedEof => io::ErrorKind::UnexpectedEof,
|
|
611
|
+
FsError::WouldBlock => io::ErrorKind::WouldBlock,
|
|
612
|
+
FsError::WriteZero => io::ErrorKind::WriteZero,
|
|
613
|
+
FsError::IOError => io::ErrorKind::Other,
|
|
614
|
+
FsError::BaseNotDirectory => io::ErrorKind::Other,
|
|
615
|
+
FsError::NotAFile => io::ErrorKind::Other,
|
|
616
|
+
FsError::InvalidFd => io::ErrorKind::Other,
|
|
617
|
+
FsError::Lock => io::ErrorKind::Other,
|
|
618
|
+
FsError::NoDevice => io::ErrorKind::Other,
|
|
619
|
+
FsError::DirectoryNotEmpty => io::ErrorKind::Other,
|
|
620
|
+
FsError::UnknownError => io::ErrorKind::Other,
|
|
621
|
+
FsError::StorageFull => io::ErrorKind::Other,
|
|
622
|
+
FsError::Unsupported => io::ErrorKind::Unsupported,
|
|
623
|
+
// NOTE: Add this once the "io_error_more" Rust feature is stabilized
|
|
624
|
+
// FsError::StorageFull => io::ErrorKind::StorageFull,
|
|
625
|
+
};
|
|
626
|
+
kind.into()
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
#[derive(Debug)]
|
|
631
|
+
pub struct ReadDir {
|
|
632
|
+
// TODO: to do this properly we need some kind of callback to the core FS abstraction
|
|
633
|
+
pub(crate) data: Vec<DirEntry>,
|
|
634
|
+
index: usize,
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
impl ReadDir {
|
|
638
|
+
pub fn new(data: Vec<DirEntry>) -> Self {
|
|
639
|
+
Self { data, index: 0 }
|
|
640
|
+
}
|
|
641
|
+
pub fn is_empty(&self) -> bool {
|
|
642
|
+
self.data.is_empty()
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
647
|
+
pub struct DirEntry {
|
|
648
|
+
pub path: PathBuf,
|
|
649
|
+
// weird hack, to fix this we probably need an internal trait object or callbacks or something
|
|
650
|
+
pub metadata: Result<Metadata>,
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
impl DirEntry {
|
|
654
|
+
pub fn path(&self) -> PathBuf {
|
|
655
|
+
self.path.clone()
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
pub fn metadata(&self) -> Result<Metadata> {
|
|
659
|
+
self.metadata.clone()
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
pub fn file_type(&self) -> Result<FileType> {
|
|
663
|
+
let metadata = self.metadata.clone()?;
|
|
664
|
+
Ok(metadata.file_type())
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
pub fn file_name(&self) -> OsString {
|
|
668
|
+
self.path
|
|
669
|
+
.file_name()
|
|
670
|
+
.unwrap_or(self.path.as_os_str())
|
|
671
|
+
.to_owned()
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
pub fn is_white_out(&self) -> Option<PathBuf> {
|
|
675
|
+
ops::is_white_out(&self.path)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
#[allow(clippy::len_without_is_empty)] // Clippy thinks it's an iterator.
|
|
680
|
+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
681
|
+
// TODO: review this, proper solution would probably use a trait object internally
|
|
682
|
+
pub struct Metadata {
|
|
683
|
+
pub ft: FileType,
|
|
684
|
+
pub accessed: u64,
|
|
685
|
+
pub created: u64,
|
|
686
|
+
pub modified: u64,
|
|
687
|
+
pub len: u64,
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
impl Metadata {
|
|
691
|
+
pub fn is_file(&self) -> bool {
|
|
692
|
+
self.ft.is_file()
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
pub fn is_dir(&self) -> bool {
|
|
696
|
+
self.ft.is_dir()
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
pub fn accessed(&self) -> u64 {
|
|
700
|
+
self.accessed
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
pub fn created(&self) -> u64 {
|
|
704
|
+
self.created
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
pub fn modified(&self) -> u64 {
|
|
708
|
+
self.modified
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
pub fn file_type(&self) -> FileType {
|
|
712
|
+
self.ft.clone()
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
pub fn len(&self) -> u64 {
|
|
716
|
+
self.len
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
721
|
+
// TODO: review this, proper solution would probably use a trait object internally
|
|
722
|
+
pub struct FileType {
|
|
723
|
+
pub dir: bool,
|
|
724
|
+
pub file: bool,
|
|
725
|
+
pub symlink: bool,
|
|
726
|
+
// TODO: the following 3 only exist on unix in the standard FS API.
|
|
727
|
+
// We should mirror that API and extend with that trait too.
|
|
728
|
+
pub char_device: bool,
|
|
729
|
+
pub block_device: bool,
|
|
730
|
+
pub socket: bool,
|
|
731
|
+
pub fifo: bool,
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
impl FileType {
|
|
735
|
+
pub fn new_dir() -> Self {
|
|
736
|
+
Self {
|
|
737
|
+
dir: true,
|
|
738
|
+
..Default::default()
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
pub fn new_file() -> Self {
|
|
743
|
+
Self {
|
|
744
|
+
file: true,
|
|
745
|
+
..Default::default()
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
pub fn is_dir(&self) -> bool {
|
|
750
|
+
self.dir
|
|
751
|
+
}
|
|
752
|
+
pub fn is_file(&self) -> bool {
|
|
753
|
+
self.file
|
|
754
|
+
}
|
|
755
|
+
pub fn is_symlink(&self) -> bool {
|
|
756
|
+
self.symlink
|
|
757
|
+
}
|
|
758
|
+
pub fn is_char_device(&self) -> bool {
|
|
759
|
+
self.char_device
|
|
760
|
+
}
|
|
761
|
+
pub fn is_block_device(&self) -> bool {
|
|
762
|
+
self.block_device
|
|
763
|
+
}
|
|
764
|
+
pub fn is_socket(&self) -> bool {
|
|
765
|
+
self.socket
|
|
766
|
+
}
|
|
767
|
+
pub fn is_fifo(&self) -> bool {
|
|
768
|
+
self.fifo
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
impl Iterator for ReadDir {
|
|
773
|
+
type Item = Result<DirEntry>;
|
|
774
|
+
|
|
775
|
+
fn next(&mut self) -> Option<Result<DirEntry>> {
|
|
776
|
+
if let Some(v) = self.data.get(self.index).cloned() {
|
|
777
|
+
self.index += 1;
|
|
778
|
+
return Some(Ok(v));
|
|
779
|
+
}
|
|
780
|
+
None
|
|
781
|
+
}
|
|
782
|
+
}
|