1use crate::error::Error;
4use crate::helpers::{max_usize, Ignore};
5use alloc::vec::Vec;
6use minicbor::{Decode, Encode};
7use oc_wasm_futures::invoke::{component_method, Buffer};
8use oc_wasm_helpers::Lockable;
9use oc_wasm_safe::{
10 component::{Invoker, MethodCallError},
11 descriptor, extref, Address,
12};
13
14pub const TYPE: &str = "filesystem";
16
17#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
19pub struct Filesystem(Address);
20
21impl Filesystem {
22 #[must_use = "This function is only useful for its return value"]
28 pub fn new(address: Address) -> Self {
29 Self(address)
30 }
31
32 #[must_use = "This function is only useful for its return value"]
34 pub fn address(&self) -> &Address {
35 &self.0
36 }
37}
38
39impl<'invoker, 'buffer, B: 'buffer + Buffer> Lockable<'invoker, 'buffer, B> for Filesystem {
40 type Locked = Locked<'invoker, 'buffer, B>;
41
42 fn lock(&self, invoker: &'invoker mut Invoker, buffer: &'buffer mut B) -> Self::Locked {
43 Locked {
44 address: self.0,
45 invoker,
46 buffer,
47 }
48 }
49}
50
51pub struct Locked<'invoker, 'buffer, B: Buffer> {
61 address: Address,
63
64 invoker: &'invoker mut Invoker,
66
67 buffer: &'buffer mut B,
69}
70
71impl<'invoker, 'buffer, B: Buffer> Locked<'invoker, 'buffer, B> {
72 pub async fn get_label(self) -> Result<Option<&'buffer str>, Error> {
81 let ret: (Option<&'buffer str>,) = component_method::<(), _, _>(
82 self.invoker,
83 self.buffer,
84 &self.address,
85 "getLabel",
86 None,
87 )
88 .await?;
89 Ok(ret.0)
90 }
91
92 pub async fn set_label(self, label: Option<&str>) -> Result<Option<&'buffer str>, Error> {
105 let label = label.map(|l| unsafe { extref::String::new(l) });
107 let ret: Result<(Option<&'buffer str>,), MethodCallError<'_>> = component_method(
108 self.invoker,
109 self.buffer,
110 &self.address,
111 "setLabel",
112 Some(&(label,)),
113 )
114 .await;
115 match ret {
116 Ok((label,)) => Ok(label),
117 Err(MethodCallError::BadParameters(_)) => Err(Error::StorageReadOnly),
118 Err(MethodCallError::TooManyDescriptors) => Err(Error::TooManyDescriptors),
119 Err(MethodCallError::Other(_)) => Err(Error::Unsupported),
120 Err(e) => Err(Error::BadComponent(e.into())),
121 }
122 }
123
124 pub async fn is_read_only(&mut self) -> Result<bool, Error> {
130 let ret: (bool,) = component_method::<(), _, _>(
131 self.invoker,
132 self.buffer,
133 &self.address,
134 "isReadOnly",
135 None,
136 )
137 .await?;
138 Ok(ret.0)
139 }
140
141 pub async fn get_space_total(&mut self) -> Result<u64, Error> {
147 enum Return {
150 Finite(u64),
151 Infinite,
152 }
153 use minicbor::{data::Type, Decoder};
154 impl<Context> Decode<'_, Context> for Return {
155 fn decode(
156 d: &mut Decoder<'_>,
157 _: &mut Context,
158 ) -> Result<Self, minicbor::decode::Error> {
159 match d.datatype()? {
160 Type::F16 | Type::F32 | Type::F64 => {
161 d.skip()?;
162 Ok(Return::Infinite)
163 }
164 _ => Ok(Return::Finite(d.u64()?)),
165 }
166 }
167 }
168 let ret: (Return,) = component_method::<(), _, _>(
169 self.invoker,
170 self.buffer,
171 &self.address,
172 "spaceTotal",
173 None,
174 )
175 .await?;
176 Ok(match ret.0 {
177 Return::Finite(x) => x,
178 Return::Infinite => u64::MAX,
179 })
180 }
181
182 pub async fn get_space_used(&mut self) -> Result<u64, Error> {
188 let ret: (u64,) = component_method::<(), _, _>(
189 self.invoker,
190 self.buffer,
191 &self.address,
192 "spaceUsed",
193 None,
194 )
195 .await?;
196 Ok(ret.0)
197 }
198
199 pub async fn exists(&mut self, path: &str) -> Result<bool, Error> {
206 self.call_path_to_value("exists", path).await
207 }
208
209 pub async fn size(&mut self, path: &str) -> Result<u64, Error> {
218 self.call_path_to_value("size", path).await
219 }
220
221 pub async fn is_directory(&mut self, path: &str) -> Result<bool, Error> {
228 self.call_path_to_value("isDirectory", path).await
229 }
230
231 pub async fn last_modified(&mut self, path: &str) -> Result<u64, Error> {
242 self.call_path_to_value("lastModified", path).await
243 }
244
245 pub async fn list(self, path: &str) -> Result<Vec<DirectoryEntry<'buffer>>, Error> {
258 let path = unsafe { extref::String::new(path) };
260 let ret: Result<(Option<Vec<DirectoryEntry<'buffer>>>,), _> = component_method(
261 self.invoker,
262 self.buffer,
263 &self.address,
264 "list",
265 Some(&(path,)),
266 )
267 .await;
268 match ret {
269 Ok((Some(listing),)) => Ok(listing),
270 Ok((None,)) | Err(MethodCallError::Other(_)) => Err(Error::FileNotFound),
271 Err(MethodCallError::TooManyDescriptors) => Err(Error::TooManyDescriptors),
272 Err(e) => Err(Error::BadComponent(e.into())),
273 }
274 }
275
276 pub async fn make_directory(&mut self, path: &str) -> Result<(), Error> {
286 let ret: bool = self.call_path_to_value("makeDirectory", path).await?;
287 if ret {
288 Ok(())
289 } else {
290 Err(Error::Failed)
291 }
292 }
293
294 pub async fn remove(&mut self, path: &str) -> Result<(), Error> {
303 let removed: bool = self.call_path_to_value("remove", path).await?;
304 if removed {
305 Ok(())
306 } else {
307 Err(Error::Failed)
308 }
309 }
310
311 pub async fn rename(&mut self, source: &str, destination: &str) -> Result<(), Error> {
321 let source = unsafe { extref::String::new(source) };
323 let destination = unsafe { extref::String::new(destination) };
324 let ret: Result<(bool,), _> = component_method(
325 self.invoker,
326 self.buffer,
327 &self.address,
328 "rename",
329 Some(&(source, destination)),
330 )
331 .await;
332 match ret {
333 Ok((true,)) => Ok(()),
334 Ok((false,)) => Err(Error::Failed),
335 Err(MethodCallError::TooManyDescriptors) => Err(Error::TooManyDescriptors),
336 Err(MethodCallError::Other(_)) => Err(Error::BadFilename),
337 Err(e) => Err(e.into()),
338 }
339 }
340
341 pub async fn open_read(&mut self, path: &str) -> Result<ReadHandle, Error> {
348 Ok(ReadHandle {
349 address: self.address,
350 descriptor: self.call_open(path, "r", Error::FileNotFound).await?,
351 })
352 }
353
354 pub async fn open_write(&mut self, path: &str, mode: WriteMode) -> Result<WriteHandle, Error> {
363 Ok(WriteHandle {
364 address: self.address,
365 descriptor: self.call_open(path, mode.as_str(), Error::Failed).await?,
366 })
367 }
368
369 async fn call_path_to_value<T>(&mut self, method: &str, path: &str) -> Result<T, Error>
377 where
378 for<'a> T: Decode<'a, ()>,
379 {
380 let path = unsafe { extref::String::new(path) };
382 let ret: Result<(T,), _> = component_method(
383 self.invoker,
384 self.buffer,
385 &self.address,
386 method,
387 Some(&(path,)),
388 )
389 .await;
390 match ret {
391 Ok((v,)) => Ok(v),
392 Err(MethodCallError::Other(_)) => Err(Error::BadFilename),
393 Err(e) => Err(e.into()),
394 }
395 }
396
397 async fn call_open(
404 &mut self,
405 path: &str,
406 mode: &str,
407 file_not_found_error: Error,
408 ) -> Result<descriptor::Owned, Error> {
409 let path = unsafe { extref::String::new(path) };
411 let descriptor: Result<(descriptor::Decoded,), MethodCallError<'_>> = component_method(
412 self.invoker,
413 self.buffer,
414 &self.address,
415 "open",
416 Some(&(path, mode)),
417 )
418 .await;
419 match descriptor {
420 Ok((descriptor,)) => Ok(
421 unsafe { descriptor.into_owned() },
424 ),
425 Err(MethodCallError::Other(exception)) => {
426 if exception.is_type("java.io.FileNotFoundException") {
427 Err(file_not_found_error)
429 } else if exception.is_type("java.io.IOException") {
430 const TOO_MANY_OPEN_HANDLES: &str = "too many open handles";
433 const ERROR_MESSAGE_BUFFER_SIZE: usize = TOO_MANY_OPEN_HANDLES.len();
434 let mut message_buffer = [0_u8; ERROR_MESSAGE_BUFFER_SIZE];
435 match exception.message(&mut message_buffer) {
436 Ok(TOO_MANY_OPEN_HANDLES) => Err(Error::TooManyDescriptors),
437 _ => Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown)),
438 }
439 } else {
440 Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown))
443 }
444 }
445 Err(e) => Err(e.into()),
446 }
447 }
448}
449
450#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
452pub enum DirectoryEntryType {
453 File,
455
456 Directory,
458}
459
460#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
462pub struct DirectoryEntry<'buffer> {
463 pub name: &'buffer str,
465
466 pub object_type: DirectoryEntryType,
468}
469
470impl<'buffer, Context> Decode<'buffer, Context> for DirectoryEntry<'buffer> {
471 fn decode(
472 d: &mut minicbor::Decoder<'buffer>,
473 _: &mut Context,
474 ) -> Result<Self, minicbor::decode::Error> {
475 let name = d.str()?;
476 Ok(match name.strip_suffix('/') {
477 Some(name) => DirectoryEntry {
478 name,
479 object_type: DirectoryEntryType::Directory,
480 },
481 None => DirectoryEntry {
482 name,
483 object_type: DirectoryEntryType::File,
484 },
485 })
486 }
487}
488
489#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
491pub enum WriteMode {
492 Truncate,
495
496 Append,
500}
501
502impl WriteMode {
503 fn as_str(self) -> &'static str {
504 match self {
505 Self::Truncate => "w",
506 Self::Append => "a",
507 }
508 }
509}
510
511#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
513pub enum Seek {
514 Set,
516
517 Current,
519
520 End,
522}
523
524impl<Context> Encode<Context> for Seek {
525 fn encode<W: minicbor::encode::Write>(
526 &self,
527 e: &mut minicbor::Encoder<W>,
528 _: &mut Context,
529 ) -> Result<(), minicbor::encode::Error<W::Error>> {
530 e.str(match self {
531 Self::Set => "set",
532 Self::Current => "cur",
533 Self::End => "end",
534 })?;
535 Ok(())
536 }
537}
538
539#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
543pub struct ReadHandle {
544 address: Address,
546
547 descriptor: descriptor::Owned,
549}
550
551impl<'handle, 'invoker, 'buffer, B: 'buffer + Buffer> Lockable<'invoker, 'buffer, B>
552 for &'handle ReadHandle
553{
554 type Locked = LockedReadHandle<'handle, 'invoker, 'buffer, B>;
555
556 fn lock(&self, invoker: &'invoker mut Invoker, buffer: &'buffer mut B) -> Self::Locked {
557 LockedReadHandle {
558 handle: self,
559 invoker,
560 buffer,
561 }
562 }
563}
564
565pub struct LockedReadHandle<'handle, 'invoker, 'buffer, B: Buffer> {
576 handle: &'handle ReadHandle,
578
579 invoker: &'invoker mut Invoker,
581
582 buffer: &'buffer mut B,
584}
585
586impl<'handle, 'invoker, 'buffer, B: Buffer> LockedReadHandle<'handle, 'invoker, 'buffer, B> {
587 pub async fn seek(&mut self, basis: Seek, offset: i64) -> Result<u64, Error> {
594 seek_impl(
595 self.invoker,
596 self.buffer,
597 &self.handle.address,
598 &self.handle.descriptor,
599 basis,
600 offset,
601 )
602 .await
603 }
604
605 pub async fn read(self, length: usize) -> Result<Option<&'buffer [u8]>, Error> {
618 use minicbor::bytes::ByteSlice;
619 #[derive(Encode)]
620 #[cbor(array)]
621 struct Params<'descriptor>(#[n(0)] &'descriptor descriptor::Owned, #[n(1)] usize);
622 let ret: Result<(Option<&'buffer ByteSlice>,), MethodCallError<'_>> = component_method(
623 self.invoker,
624 self.buffer,
625 &self.handle.address,
626 "read",
627 Some(&Params(&self.handle.descriptor, length)),
628 )
629 .await;
630 match ret {
631 Ok((Some(bytes),)) => Ok(Some(bytes)),
632 Ok((None,)) => Ok(None),
633 Err(MethodCallError::Other(exception)) => {
634 if exception.is_type("java.io.IOException") {
635 const NOT_ENOUGH_ENERGY: &str = "not enough energy";
641 let mut message_buffer = [0_u8; NOT_ENOUGH_ENERGY.len()];
642 match exception.message(&mut message_buffer) {
643 Ok(m) if m == NOT_ENOUGH_ENERGY => Err(Error::NotEnoughEnergy),
644 _ => Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown)),
645 }
646 } else {
647 Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown))
648 }
649 }
650 Err(e) => Err(e.into()),
651 }
652 }
653}
654
655#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
659pub struct WriteHandle {
660 address: Address,
662
663 descriptor: descriptor::Owned,
665}
666
667impl<'handle, 'invoker, 'buffer, B: 'buffer + Buffer> Lockable<'invoker, 'buffer, B>
668 for &'handle WriteHandle
669{
670 type Locked = LockedWriteHandle<'handle, 'invoker, 'buffer, B>;
671
672 fn lock(&self, invoker: &'invoker mut Invoker, buffer: &'buffer mut B) -> Self::Locked {
673 LockedWriteHandle {
674 handle: self,
675 invoker,
676 buffer,
677 }
678 }
679}
680
681pub struct LockedWriteHandle<'handle, 'invoker, 'buffer, B: Buffer> {
693 handle: &'handle WriteHandle,
695
696 invoker: &'invoker mut Invoker,
698
699 buffer: &'buffer mut B,
701}
702
703impl<'handle, 'invoker, 'buffer, B: Buffer> LockedWriteHandle<'handle, 'invoker, 'buffer, B> {
704 pub async fn seek(&mut self, basis: Seek, offset: i64) -> Result<u64, Error> {
711 seek_impl(
712 self.invoker,
713 self.buffer,
714 &self.handle.address,
715 &self.handle.descriptor,
716 basis,
717 offset,
718 )
719 .await
720 }
721
722 pub async fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
730 #[derive(Encode)]
731 #[cbor(array)]
732 struct Params<'descriptor, 'bytes>(
733 #[n(0)] &'descriptor descriptor::Owned,
734 #[n(1)] extref::Bytes<'bytes>,
735 );
736 let bytes = unsafe { extref::Bytes::new(bytes) };
738 let ret: Result<Ignore, MethodCallError<'_>> = component_method(
739 self.invoker,
740 self.buffer,
741 &self.handle.address,
742 "write",
743 Some(&Params(&self.handle.descriptor, bytes)),
744 )
745 .await;
746 match ret {
747 Ok(_) => Ok(()),
748 Err(MethodCallError::Other(exception)) => {
749 if exception.is_type("java.io.IOException") {
750 const NOT_ENOUGH_ENERGY: &str = "not enough energy";
756 const NOT_ENOUGH_SPACE: &str = "not enough space";
757 let mut message_buffer =
758 [0_u8; max_usize(NOT_ENOUGH_ENERGY.len(), NOT_ENOUGH_SPACE.len())];
759 match exception.message(&mut message_buffer) {
760 Ok(m) if m == NOT_ENOUGH_ENERGY => Err(Error::NotEnoughEnergy),
761 Ok(m) if m == NOT_ENOUGH_SPACE => Err(Error::DataTooLarge),
762 _ => Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown)),
763 }
764 } else {
765 Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown))
766 }
767 }
768 Err(e) => Err(e.into()),
769 }
770 }
771}
772
773async fn seek_impl<B: Buffer>(
780 invoker: &mut Invoker,
781 buffer: &mut B,
782 address: &Address,
783 descriptor: &descriptor::Owned,
784 basis: Seek,
785 offset: i64,
786) -> Result<u64, Error> {
787 #[derive(Encode)]
788 #[cbor(array)]
789 struct Params<'descriptor>(
790 #[n(0)] &'descriptor descriptor::Owned,
791 #[n(1)] Seek,
792 #[n(2)] i64,
793 );
794 let ret: Result<(u64,), MethodCallError<'_>> = component_method(
795 invoker,
796 buffer,
797 address,
798 "seek",
799 Some(&Params(descriptor, basis, offset)),
800 )
801 .await;
802 match ret {
803 Ok((position,)) => Ok(position),
804 Err(MethodCallError::BadParameters(_)) => Err(Error::NegativeSeek),
805 Err(e) => Err(e.into()),
806 }
807}