@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.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -0
  3. package/THIRD_PARTY_NOTICES.md +302 -0
  4. package/crates/runtime-core/Cargo.lock +5099 -0
  5. package/crates/runtime-core/Cargo.toml +66 -0
  6. package/crates/runtime-core/README.md +47 -0
  7. package/crates/runtime-core/src/bin/wasm-oj-compiler.rs +418 -0
  8. package/crates/runtime-core/src/bin/wasm-oj-runner.rs +294 -0
  9. package/crates/runtime-core/src/capabilities.rs +118 -0
  10. package/crates/runtime-core/src/compiler.rs +658 -0
  11. package/crates/runtime-core/src/contract.rs +5 -0
  12. package/crates/runtime-core/src/deterministic.rs +1051 -0
  13. package/crates/runtime-core/src/error.rs +58 -0
  14. package/crates/runtime-core/src/filesystem.rs +547 -0
  15. package/crates/runtime-core/src/filesystem_quota.rs +167 -0
  16. package/crates/runtime-core/src/go_compiler_session.rs +297 -0
  17. package/crates/runtime-core/src/interactive.rs +1019 -0
  18. package/crates/runtime-core/src/judge_package.rs +1539 -0
  19. package/crates/runtime-core/src/lib.rs +98 -0
  20. package/crates/runtime-core/src/memory.rs +84 -0
  21. package/crates/runtime-core/src/meter.rs +549 -0
  22. package/crates/runtime-core/src/module_imports.rs +149 -0
  23. package/crates/runtime-core/src/module_policy.rs +714 -0
  24. package/crates/runtime-core/src/output.rs +204 -0
  25. package/crates/runtime-core/src/run/mod.rs +208 -0
  26. package/crates/runtime-core/src/run/native.rs +260 -0
  27. package/crates/runtime-core/src/run/web.rs +229 -0
  28. package/crates/runtime-core/src/run/web_runtime.rs +109 -0
  29. package/crates/runtime-core/src/types.rs +268 -0
  30. package/crates/runtime-core/src/web.rs +83 -0
  31. package/dist/chunks/go-toolchain-Dbt-lp2L.js +426 -0
  32. package/dist/chunks/java-toolchain-DajoRCHu.js +44 -0
  33. package/dist/chunks/python-toolchain-Dx834o2A.js +4 -0
  34. package/dist/chunks/rust-toolchain-CJ3sMxPE.js +252 -0
  35. package/dist/chunks/toolchains-C6KuA1yM.js +224 -0
  36. package/dist/go-stage.mjs +193 -0
  37. package/dist/index.d.ts +221 -0
  38. package/dist/index.js +4393 -0
  39. package/dist/java-stage.mjs +111 -0
  40. package/dist/python-stage.mjs +90 -0
  41. package/dist/rustc-stage.mjs +301 -0
  42. package/dist/server-build-stage.mjs +2564 -0
  43. package/dist/server-runner-stage.mjs +155 -0
  44. package/licenses/fflate-MIT.txt +21 -0
  45. package/licenses/runtime-core-dependencies.html +6253 -0
  46. package/licenses/runtime-core-dependencies.json +3041 -0
  47. package/licenses/wasmer-sdk-MIT.txt +21 -0
  48. package/licenses/wasmer-sdk-dependencies.html +6901 -0
  49. package/licenses/wasmer-sdk-dependencies.json +3013 -0
  50. package/package.json +70 -0
  51. package/rust-toolchain.toml +5 -0
  52. package/testdata/wojjdg02-v2-text.hex +1 -0
  53. package/vendor/shared-buffer/Cargo.toml +22 -0
  54. package/vendor/shared-buffer/LICENSE_APACHE.md +176 -0
  55. package/vendor/shared-buffer/LICENSE_MIT.md +25 -0
  56. package/vendor/shared-buffer/README.md +34 -0
  57. package/vendor/shared-buffer/src/lib.rs +58 -0
  58. package/vendor/shared-buffer/src/mmap.rs +250 -0
  59. package/vendor/shared-buffer/src/owned.rs +389 -0
  60. package/vendor/virtual-fs/Cargo.toml +181 -0
  61. package/vendor/virtual-fs/LICENSE +25 -0
  62. package/vendor/virtual-fs/src/arc_box_file.rs +142 -0
  63. package/vendor/virtual-fs/src/arc_file.rs +182 -0
  64. package/vendor/virtual-fs/src/arc_fs.rs +68 -0
  65. package/vendor/virtual-fs/src/buffer_file.rs +103 -0
  66. package/vendor/virtual-fs/src/builder.rs +232 -0
  67. package/vendor/virtual-fs/src/combine_file.rs +101 -0
  68. package/vendor/virtual-fs/src/cow_file.rs +345 -0
  69. package/vendor/virtual-fs/src/dual_write_file.rs +113 -0
  70. package/vendor/virtual-fs/src/empty_fs.rs +81 -0
  71. package/vendor/virtual-fs/src/filesystems.rs +108 -0
  72. package/vendor/virtual-fs/src/host_fs.rs +1390 -0
  73. package/vendor/virtual-fs/src/lib.rs +782 -0
  74. package/vendor/virtual-fs/src/limiter.rs +252 -0
  75. package/vendor/virtual-fs/src/mem_fs/file.rs +1799 -0
  76. package/vendor/virtual-fs/src/mem_fs/file_opener.rs +941 -0
  77. package/vendor/virtual-fs/src/mem_fs/filesystem.rs +2134 -0
  78. package/vendor/virtual-fs/src/mem_fs/mod.rs +245 -0
  79. package/vendor/virtual-fs/src/mem_fs/offloaded_file.rs +474 -0
  80. package/vendor/virtual-fs/src/mem_fs/stdio.rs +318 -0
  81. package/vendor/virtual-fs/src/mount_fs.rs +2225 -0
  82. package/vendor/virtual-fs/src/null_file.rs +87 -0
  83. package/vendor/virtual-fs/src/ops.rs +364 -0
  84. package/vendor/virtual-fs/src/overlay_fs.rs +2216 -0
  85. package/vendor/virtual-fs/src/passthru_fs.rs +119 -0
  86. package/vendor/virtual-fs/src/pipe.rs +603 -0
  87. package/vendor/virtual-fs/src/random_file.rs +88 -0
  88. package/vendor/virtual-fs/src/special_file.rs +108 -0
  89. package/vendor/virtual-fs/src/static_file.rs +133 -0
  90. package/vendor/virtual-fs/src/static_fs.rs +460 -0
  91. package/vendor/virtual-fs/src/tmp_fs.rs +95 -0
  92. package/vendor/virtual-fs/src/trace_fs.rs +258 -0
  93. package/vendor/virtual-fs/src/webc_volume_fs.rs +829 -0
  94. 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
+ }