1use core::slice;
8use std::{
9 ffi::{CStr, OsStr},
10 mem::MaybeUninit,
11 path::Path,
12};
13use wasi::{
14 CiovecArray, Dircookie, Event, Fd, Fdflags, Fdstat, Filedelta, Filesize, Filestat, Fstflags,
15 IovecArray, Lookupflags, Oflags, Prestat, PrestatDir, PrestatU, Rights, Size, Subscription,
16 Timestamp,
17};
18
19use crate::{
20 embed::{Node, NodeDirBody, NodeFileBody, NodeIdTrait, Storage},
21 BackingFd, Error, FileSystem, UserFd,
22};
23
24pub(crate) unsafe fn fd_advise<S: Storage>(
25 fs: &mut FileSystem<S>,
26 fd: UserFd,
27 offset: Filesize,
28 len: Filesize,
29 advice: i32,
30) -> Result<(), Error> {
31 let fd = fs.get_backing_fd(fd)?;
32 match fd {
33 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
34 BackingFd::Wasi(fd) => {
35 let ret = wasi::wasi_snapshot_preview1::fd_advise(
36 fd as i32,
37 offset as i64,
38 len as i64,
39 advice as i32,
40 );
41 match ret {
42 0 => Ok(()),
43 _ => Err(Error(ret as u16)),
44 }
45 }
46 }
47}
48
49pub(crate) unsafe fn fd_allocate<S: Storage>(
50 fs: &mut FileSystem<S>,
51 fd: UserFd,
52 offset: Filesize,
53 len: Filesize,
54) -> Result<(), Error> {
55 let fd = fs.get_backing_fd(fd)?;
56 match fd {
57 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
58 BackingFd::Wasi(fd) => {
59 let ret =
60 wasi::wasi_snapshot_preview1::fd_allocate(fd as i32, offset as i64, len as i64);
61 match ret {
62 0 => Ok(()),
63 _ => Err(Error(ret as u16)),
64 }
65 }
66 }
67}
68
69pub(crate) unsafe fn fd_close<S: Storage>(fs: &mut FileSystem<S>, fd: UserFd) -> Result<(), Error> {
70 let fd = fs.get_backing_fd(fd)?;
71 match fd {
72 BackingFd::Virtual(vfd) => Ok(fs.embedded_fs.close_file(vfd)?),
73 BackingFd::Wasi(fd) => {
74 let ret = wasi::wasi_snapshot_preview1::fd_close(fd as i32);
75 match ret {
76 0 => Ok(()),
77 _ => Err(Error(ret as u16)),
78 }
79 }
80 }
81}
82
83pub(crate) unsafe fn fd_datasync<S: Storage>(
84 fs: &mut FileSystem<S>,
85 fd: UserFd,
86) -> Result<(), Error> {
87 let fd = fs.get_backing_fd(fd)?;
88 match fd {
89 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
90 BackingFd::Wasi(fd) => {
91 let ret = wasi::wasi_snapshot_preview1::fd_datasync(fd as i32);
92 match ret {
93 0 => Ok(()),
94 _ => Err(Error(ret as u16)),
95 }
96 }
97 }
98}
99
100pub(crate) unsafe fn fd_fdstat_get<S: Storage>(
101 fs: &mut FileSystem<S>,
102 fd: UserFd,
103) -> Result<Fdstat, Error> {
104 let fd = fs.get_backing_fd(fd)?;
105 match fd {
106 BackingFd::Virtual(vfd) => {
107 let stat = fs.embedded_fs.get_fd_stat(vfd)?;
108 Ok(stat)
109 }
110 BackingFd::Wasi(fd) => {
111 let mut rp0 = MaybeUninit::<Fdstat>::uninit();
112 let ret =
113 wasi::wasi_snapshot_preview1::fd_fdstat_get(fd as i32, rp0.as_mut_ptr() as i32);
114 match ret {
115 0 => Ok(rp0.assume_init()),
116 _ => Err(Error(ret as u16)),
117 }
118 }
119 }
120}
121
122pub(crate) unsafe fn fd_fdstat_set_flags<S: Storage>(
123 fs: &mut FileSystem<S>,
124 fd: UserFd,
125 flags: Fdflags,
126) -> Result<(), Error> {
127 let fd = fs.get_backing_fd(fd)?;
128 match fd {
129 BackingFd::Virtual(vfd) => {
130 let entry = fs.embedded_fs.get_fd_entry_mut(vfd)?;
131 entry.flags = flags;
132 Ok(())
133 }
134 BackingFd::Wasi(fd) => {
135 let ret = wasi::wasi_snapshot_preview1::fd_fdstat_set_flags(fd as i32, flags as i32);
136 match ret {
137 0 => Ok(()),
138 _ => Err(Error(ret as u16)),
139 }
140 }
141 }
142}
143
144pub(crate) unsafe fn fd_fdstat_set_rights<S: Storage>(
145 fs: &mut FileSystem<S>,
146 fd: UserFd,
147 fs_rights_base: Rights,
148 fs_rights_inheriting: Rights,
149) -> Result<(), Error> {
150 let fd = fs.get_backing_fd(fd)?;
151 match fd {
152 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
153 BackingFd::Wasi(fd) => {
154 let ret = wasi::wasi_snapshot_preview1::fd_fdstat_set_rights(
155 fd as i32,
156 fs_rights_base as i64,
157 fs_rights_inheriting as i64,
158 );
159 match ret {
160 0 => Ok(()),
161 _ => Err(Error(ret as u16)),
162 }
163 }
164 }
165}
166
167pub(crate) unsafe fn fd_filestat_get<S: Storage>(
168 fs: &mut FileSystem<S>,
169 fd: UserFd,
170) -> Result<Filestat, Error> {
171 let fd = fs.get_backing_fd(fd)?;
172 match fd {
173 BackingFd::Virtual(vfd) => {
174 let fd_entry = fs.embedded_fs.get_fd_entry(vfd)?;
175 Ok(fs.embedded_fs.get_filestat_from_node_id(fd_entry.node_id))
176 }
177 BackingFd::Wasi(fd) => {
178 let mut rp0 = MaybeUninit::<Filestat>::uninit();
179 let ret =
180 wasi::wasi_snapshot_preview1::fd_filestat_get(fd as i32, rp0.as_mut_ptr() as i32);
181 match ret {
182 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Filestat)),
183 _ => Err(Error(ret as u16)),
184 }
185 }
186 }
187}
188
189pub(crate) unsafe fn fd_filestat_set_size<S: Storage>(
190 fs: &mut FileSystem<S>,
191 fd: UserFd,
192 size: Filesize,
193) -> Result<(), Error> {
194 let fd = fs.get_backing_fd(fd)?;
195 match fd {
196 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
197 BackingFd::Wasi(fd) => {
198 let ret = wasi::wasi_snapshot_preview1::fd_filestat_set_size(fd as i32, size as i64);
199 match ret {
200 0 => Ok(()),
201 _ => Err(Error(ret as u16)),
202 }
203 }
204 }
205}
206
207pub(crate) unsafe fn fd_filestat_set_times<S: Storage>(
208 fs: &mut FileSystem<S>,
209 fd: UserFd,
210 atim: Timestamp,
211 mtim: Timestamp,
212 fst_flags: Fstflags,
213) -> Result<(), Error> {
214 let fd = fs.get_backing_fd(fd)?;
215 match fd {
216 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
217 BackingFd::Wasi(fd) => {
218 let ret = wasi::wasi_snapshot_preview1::fd_filestat_set_times(
219 fd as i32,
220 atim as i64,
221 mtim as i64,
222 fst_flags as i32,
223 );
224 match ret {
225 0 => Ok(()),
226 _ => Err(Error(ret as u16)),
227 }
228 }
229 }
230}
231
232pub(crate) unsafe fn fd_pread<S: Storage>(
233 fs: &mut FileSystem<S>,
234 fd: UserFd,
235 iovs: IovecArray<'_>,
236 offset: Filesize,
237) -> Result<Size, Error> {
238 let fd = fs.get_backing_fd(fd)?;
239 match fd {
240 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
241 BackingFd::Wasi(fd) => {
242 let mut rp0 = MaybeUninit::<Size>::uninit();
243 let ret = wasi::wasi_snapshot_preview1::fd_pread(
244 fd as i32,
245 iovs.as_ptr() as i32,
246 iovs.len() as i32,
247 offset as i64,
248 rp0.as_mut_ptr() as i32,
249 );
250 match ret {
251 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Size)),
252 _ => Err(Error(ret as u16)),
253 }
254 }
255 }
256}
257
258pub(crate) unsafe fn fd_prestat_get<S: Storage>(
259 fs: &mut FileSystem<S>,
260 fd: UserFd,
261) -> Result<Prestat, Error> {
262 let fd = fs.get_backing_fd(fd)?;
263 match fd {
264 BackingFd::Virtual(vfd) => {
265 if let Some(dir) = fs.embedded_fs.get_preopened_dir_path(vfd) {
266 let stat = Prestat {
267 tag: wasi::PREOPENTYPE_DIR.raw(),
268 u: PrestatU {
269 dir: PrestatDir {
270 pr_name_len: dir.as_bytes().len(),
271 },
272 },
273 };
274 Ok(stat)
275 } else {
276 Err(wasi::ERRNO_BADF.into())
277 }
278 }
279 BackingFd::Wasi(fd) => {
280 let mut rp0 = MaybeUninit::<Prestat>::uninit();
281 let ret =
282 wasi::wasi_snapshot_preview1::fd_prestat_get(fd as i32, rp0.as_mut_ptr() as i32);
283 match ret {
284 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Prestat)),
285 _ => Err(Error(ret as u16)),
286 }
287 }
288 }
289}
290
291pub(crate) unsafe fn fd_prestat_dir_name<S: Storage>(
292 fs: &mut FileSystem<S>,
293 fd: UserFd,
294 path: *mut u8,
295 path_len: u32,
296) -> Result<(), Error> {
297 let fd = fs.get_backing_fd(fd)?;
298 match fd {
299 BackingFd::Virtual(vfd) => {
300 if let Some(dir) = fs.embedded_fs.get_preopened_dir_path(vfd) {
301 let path = slice::from_raw_parts_mut(path, path_len as usize);
302 for (offset, byte) in dir.as_bytes().iter().enumerate() {
303 path[offset] = *byte;
304 }
305 Ok(())
306 } else {
307 Err(wasi::ERRNO_BADF.into())
308 }
309 }
310 BackingFd::Wasi(fd) => {
311 let ret = wasi::wasi_snapshot_preview1::fd_prestat_dir_name(
312 fd as i32,
313 path as i32,
314 path_len as i32,
315 );
316 match ret {
317 0 => Ok(()),
318 _ => Err(Error(ret as u16)),
319 }
320 }
321 }
322}
323
324pub(crate) unsafe fn fd_pwrite<S: Storage>(
325 fs: &mut FileSystem<S>,
326 fd: UserFd,
327 iovs: CiovecArray<'_>,
328 offset: Filesize,
329) -> Result<Size, Error> {
330 let fd = fs.get_backing_fd(fd)?;
331 match fd {
332 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
333 BackingFd::Wasi(fd) => {
334 let mut rp0 = MaybeUninit::<Size>::uninit();
335 let ret = wasi::wasi_snapshot_preview1::fd_pwrite(
336 fd as i32,
337 iovs.as_ptr() as i32,
338 iovs.len() as i32,
339 offset as i64,
340 rp0.as_mut_ptr() as i32,
341 );
342 match ret {
343 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Size)),
344 _ => Err(Error(ret as u16)),
345 }
346 }
347 }
348}
349
350pub(crate) unsafe fn fd_read<S: Storage>(
351 fs: &mut FileSystem<S>,
352 fd: UserFd,
353 iovs: IovecArray<'_>,
354) -> Result<Size, Error> {
355 let fd = fs.get_backing_fd(fd)?;
356 match fd {
357 BackingFd::Virtual(vfd) => {
358 let node = fs.embedded_fs.get_node(vfd)?;
359 match node {
360 Node::Dir { .. } => Err(wasi::ERRNO_ISDIR.into()),
361 Node::File(body) => {
362 let open = fs.embedded_fs.get_fd_entry(vfd)?;
363 let mut cursor = std::io::Cursor::new(body.content());
364 cursor.set_position(open.offset as u64);
365 let read_bytes = read_bytes(cursor, iovs)?;
366 let open = fs.embedded_fs.get_fd_entry_mut(vfd)?;
367 open.offset += read_bytes;
368 Ok(read_bytes)
369 }
370 }
371 }
372 BackingFd::Wasi(fd) => {
373 let mut rp0 = MaybeUninit::<Size>::uninit();
374 let ret = wasi::wasi_snapshot_preview1::fd_read(
375 fd as i32,
376 iovs.as_ptr() as i32,
377 iovs.len() as i32,
378 rp0.as_mut_ptr() as i32,
379 );
380 match ret {
381 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Size)),
382 _ => Err(Error(ret as u16)),
383 }
384 }
385 }
386}
387
388pub(crate) unsafe fn fd_readdir<S: Storage>(
389 fs: &mut FileSystem<S>,
390 fd: UserFd,
391 buf: *mut u8,
392 buf_len: u32,
393 cookie: Dircookie,
394) -> Result<Size, Error> {
395 let fd = fs.get_backing_fd(fd)?;
396 match fd {
397 BackingFd::Virtual(vfd) => {
398 let node = fs.embedded_fs.get_node(vfd)?;
399 let entries = match node {
400 Node::Dir(body) => body.entries(),
401 Node::File { .. } => {
402 return Err(wasi::ERRNO_NOTDIR.into());
403 }
404 };
405 let mut bufused = 0;
406 let mut current_cookie = cookie;
407 let mut buf = buf;
408 let buf_len = buf_len as usize;
409 for entry in entries.skip(cookie as usize) {
410 current_cookie += 1;
411 let name_len = entry.name.len();
412 let node_id = fs.embedded_fs.get_node_id_by_link(entry.link_id);
413 let node_stat = fs.embedded_fs.get_filestat_from_node_id(node_id);
414 let dirent = wasi::Dirent {
415 d_next: current_cookie,
416 d_ino: node_id.ino() as u64,
417 d_namlen: name_len as u32,
418 d_type: node_stat.filetype,
419 };
420
421 let dirent_len = std::mem::size_of::<wasi::Dirent>();
423 let dirent_copy_len = std::cmp::min(dirent_len, buf_len - bufused);
424 std::ptr::copy(&dirent as *const _ as *const u8, buf, dirent_copy_len);
426 if dirent_copy_len < dirent_len {
428 return Ok(buf_len);
430 }
431 buf = buf.add(dirent_copy_len);
432 bufused += dirent_copy_len;
433
434 let name_copy_len = std::cmp::min(name_len, buf_len - bufused);
436 std::ptr::copy(entry.name.as_ptr(), buf, name_copy_len);
438
439 if name_copy_len < name_len {
440 return Ok(buf_len);
441 }
442 buf = buf.add(name_len);
443 bufused += name_copy_len;
444 }
445 Ok(bufused)
446 }
447 BackingFd::Wasi(fd) => {
448 let mut rp0 = MaybeUninit::<Size>::uninit();
449 let ret = wasi::wasi_snapshot_preview1::fd_readdir(
450 fd as i32,
451 buf as i32,
452 buf_len as i32,
453 cookie as i64,
454 rp0.as_mut_ptr() as i32,
455 );
456 match ret {
457 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Size)),
458 _ => Err(Error(ret as u16)),
459 }
460 }
461 }
462}
463
464pub(crate) unsafe fn fd_renumber<S: Storage>(
465 fs: &mut FileSystem<S>,
466 fd: UserFd,
467 to: UserFd,
468) -> Result<(), Error> {
469 let fd = fs.get_backing_fd(fd)?;
470 let to = fs.get_backing_fd(to)?;
471 match (fd, to) {
472 (BackingFd::Wasi(fd), BackingFd::Wasi(to)) => {
473 let ret = wasi::wasi_snapshot_preview1::fd_renumber(fd as i32, to as i32);
474 match ret {
475 0 => Ok(()),
476 _ => Err(Error(ret as u16)),
477 }
478 }
479 (_, _) => Err(wasi::ERRNO_NOTSUP.into()),
480 }
481}
482
483pub(crate) unsafe fn fd_seek<S: Storage>(
484 fs: &mut FileSystem<S>,
485 fd: UserFd,
486 offset: Filedelta,
487 whence: i32,
488) -> Result<Filesize, Error> {
489 let fd = fs.get_backing_fd(fd)?;
490 fn compute_new_offset(base: usize, offset: Filedelta) -> Result<usize, Error> {
491 let new_offset = if offset >= 0 {
492 base + (offset as usize)
493 } else {
494 let neg_offset = (-offset) as usize;
495 if neg_offset <= base {
496 base - neg_offset
497 } else {
498 return Err(wasi::ERRNO_INVAL.into());
499 }
500 };
501 Ok(new_offset)
502 }
503 match fd {
504 BackingFd::Virtual(vfd) => {
505 let whence: wasi::Whence = std::mem::transmute(whence as u8);
506 match whence {
507 wasi::WHENCE_SET => {
508 let fd_entry = fs.embedded_fs.get_fd_entry_mut(vfd)?;
509 fd_entry.offset = offset as usize;
510 Ok(offset as Filesize)
511 }
512 wasi::WHENCE_CUR => {
513 let fd_entry = fs.embedded_fs.get_fd_entry_mut(vfd)?;
514 let absolute_offset = compute_new_offset(fd_entry.offset, offset)?;
515 fd_entry.offset = absolute_offset;
516 Ok(absolute_offset as Filesize)
517 }
518 wasi::WHENCE_END => {
519 let fd_entry = fs.embedded_fs.get_fd_entry(vfd)?;
520 let node = fs.embedded_fs.get_node(vfd)?;
521 match node {
522 Node::File(body) => {
523 let content_len = body.content().len();
524 let fd_entry = fs.embedded_fs.get_fd_entry_mut(vfd)?;
525 let absolute_offset = compute_new_offset(content_len, offset)?;
526 fd_entry.offset = absolute_offset;
527 Ok(absolute_offset as Filesize)
528 }
529 Node::Dir { .. } => Err(wasi::ERRNO_INVAL.into()),
530 }
531 }
532 _ => Err(wasi::ERRNO_INVAL.into()),
533 }
534 }
535 BackingFd::Wasi(fd) => {
536 let mut rp0 = MaybeUninit::<Filesize>::uninit();
537 let ret = wasi::wasi_snapshot_preview1::fd_seek(
538 fd as i32,
539 offset,
540 whence as i32,
541 rp0.as_mut_ptr() as i32,
542 );
543 match ret {
544 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Filesize)),
545 _ => Err(Error(ret as u16)),
546 }
547 }
548 }
549}
550
551pub(crate) unsafe fn fd_sync<S: Storage>(fs: &mut FileSystem<S>, fd: UserFd) -> Result<(), Error> {
552 let fd = fs.get_backing_fd(fd)?;
553 match fd {
554 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
555 BackingFd::Wasi(fd) => {
556 let ret = wasi::wasi_snapshot_preview1::fd_sync(fd as i32);
557 match ret {
558 0 => Ok(()),
559 _ => Err(Error(ret as u16)),
560 }
561 }
562 }
563}
564
565pub(crate) unsafe fn fd_tell<S: Storage>(
566 fs: &mut FileSystem<S>,
567 fd: UserFd,
568) -> Result<Filesize, Error> {
569 let fd = fs.get_backing_fd(fd)?;
570 match fd {
571 BackingFd::Virtual(vfd) => {
572 let node = fs.embedded_fs.get_node(vfd)?;
573 let open = fs.embedded_fs.get_fd_entry_mut(vfd)?;
574 Ok(open.offset as u64)
575 }
576 BackingFd::Wasi(fd) => {
577 let mut rp0 = MaybeUninit::<Filesize>::uninit();
578 let ret = wasi::wasi_snapshot_preview1::fd_tell(fd as i32, rp0.as_mut_ptr() as i32);
579 match ret {
580 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Filesize)),
581 _ => Err(Error(ret as u16)),
582 }
583 }
584 }
585}
586
587pub(crate) unsafe fn fd_write<S: Storage>(
588 fs: &mut FileSystem<S>,
589 fd: UserFd,
590 iovs: CiovecArray<'_>,
591) -> Result<Size, Error> {
592 let fd = fs.get_backing_fd(fd)?;
593 match fd {
594 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
595 BackingFd::Wasi(fd) => {
596 let mut rp0 = MaybeUninit::<Size>::uninit();
597 let ret = wasi::wasi_snapshot_preview1::fd_write(
598 fd as i32,
599 iovs.as_ptr() as i32,
600 iovs.len() as i32,
601 rp0.as_mut_ptr() as i32,
602 );
603 match ret {
604 0 => Ok(rp0.assume_init()),
605 _ => Err(Error(ret as u16)),
606 }
607 }
608 }
609}
610
611pub(crate) unsafe fn path_create_directory<S: Storage>(
612 fs: &mut FileSystem<S>,
613 fd: UserFd,
614 path: &CStr,
615) -> Result<(), Error> {
616 let fd = fs.get_backing_fd(fd)?;
617 match fd {
618 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
619 BackingFd::Wasi(fd) => {
620 let ret = wasi::wasi_snapshot_preview1::path_create_directory(
621 fd as i32,
622 path.as_ptr() as i32,
623 path.to_bytes().len() as i32,
624 );
625 match ret {
626 0 => Ok(()),
627 _ => Err(Error(ret as u16)),
628 }
629 }
630 }
631}
632
633pub(crate) unsafe fn path_filestat_get<S: Storage>(
634 fs: &mut FileSystem<S>,
635 fd: UserFd,
636 flags: Lookupflags,
637 path: &CStr,
638) -> Result<Filestat, Error> {
639 let fd = fs.get_backing_fd(fd)?;
640 match fd {
641 BackingFd::Virtual(vfd) => {
642 let path = cstr_to_path(path)?;
643 Ok(fs.embedded_fs.get_filestat_at_path(vfd, path)?)
644 }
645 BackingFd::Wasi(fd) => {
646 let mut rp0 = MaybeUninit::<Filestat>::uninit();
647 let ret = wasi::wasi_snapshot_preview1::path_filestat_get(
648 fd as i32,
649 flags as i32,
650 path.as_ptr() as i32,
651 path.to_bytes().len() as i32,
652 rp0.as_mut_ptr() as i32,
653 );
654 match ret {
655 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Filestat)),
656 _ => Err(Error(ret as u16)),
657 }
658 }
659 }
660}
661
662pub(crate) unsafe fn path_filestat_set_times<S: Storage>(
663 fs: &mut FileSystem<S>,
664 fd: UserFd,
665 flags: Lookupflags,
666 path: &CStr,
667 atim: Timestamp,
668 mtim: Timestamp,
669 fst_flags: Fstflags,
670) -> Result<(), Error> {
671 let fd = fs.get_backing_fd(fd)?;
672 match fd {
673 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
674 BackingFd::Wasi(fd) => {
675 let ret = wasi::wasi_snapshot_preview1::path_filestat_set_times(
676 fd as i32,
677 flags as i32,
678 path.as_ptr() as i32,
679 path.to_bytes().len() as i32,
680 atim as i64,
681 mtim as i64,
682 fst_flags as i32,
683 );
684 match ret {
685 0 => Ok(()),
686 _ => Err(Error(ret as u16)),
687 }
688 }
689 }
690}
691
692pub(crate) unsafe fn path_link<S: Storage>(
693 fs: &mut FileSystem<S>,
694 old_fd: UserFd,
695 old_flags: Lookupflags,
696 old_path: &CStr,
697 new_fd: UserFd,
698 new_path: &CStr,
699) -> Result<(), Error> {
700 let old_fd = fs.get_backing_fd(old_fd)?;
701 let new_fd = fs.get_backing_fd(new_fd)?;
702 match (old_fd, new_fd) {
703 (BackingFd::Wasi(old_fd), BackingFd::Wasi(new_fd)) => {
704 let ret = wasi::wasi_snapshot_preview1::path_link(
705 old_fd as i32,
706 old_flags as i32,
707 old_path.as_ptr() as i32,
708 old_path.to_bytes().len() as i32,
709 new_fd as i32,
710 new_path.as_ptr() as i32,
711 new_path.to_bytes().len() as i32,
712 );
713 match ret {
714 0 => Ok(()),
715 _ => Err(Error(ret as u16)),
716 }
717 }
718 (_, _) => Err(wasi::ERRNO_NOTSUP.into()),
719 }
720}
721
722pub(crate) unsafe fn path_open<S: Storage>(
723 fs: &mut FileSystem<S>,
724 fd: UserFd,
725 dirflags: Lookupflags,
726 path: &CStr,
727 oflags: Oflags,
728 fs_rights_base: Rights,
729 fs_rights_inheriting: Rights,
730 fdflags: Fdflags,
731) -> Result<UserFd, Error> {
732 let fd = fs.get_backing_fd(fd)?;
733 match fd {
734 BackingFd::Virtual(vfd) => {
735 let path = cstr_to_path(path)?;
736 let new_vfd = fs.embedded_fs.open_file(vfd, path, fdflags)?;
737 Ok(fs.issue_user_fd(BackingFd::Virtual(new_vfd)))
738 }
739 BackingFd::Wasi(fd) => {
740 let mut rp0 = MaybeUninit::<Fd>::uninit();
741 let ret = wasi::wasi_snapshot_preview1::path_open(
742 fd as i32,
743 dirflags as i32,
744 path.as_ptr() as i32,
745 path.to_bytes().len() as i32,
746 oflags as i32,
747 fs_rights_base as i64,
748 fs_rights_inheriting as i64,
749 fdflags as i32,
750 rp0.as_mut_ptr() as i32,
751 );
752 match ret {
753 0 => {
754 let new_fd = BackingFd::Wasi(rp0.assume_init());
755 Ok(fs.issue_user_fd(new_fd))
756 }
757 _ => Err(Error(ret as u16)),
758 }
759 }
760 }
761}
762
763pub(crate) unsafe fn path_readlink<S: Storage>(
764 fs: &mut FileSystem<S>,
765 fd: UserFd,
766 path: &CStr,
767 buf: *mut u8,
768 buf_len: u32,
769) -> Result<Size, Error> {
770 let fd = fs.get_backing_fd(fd)?;
771 match fd {
772 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_INVAL.into()),
773 BackingFd::Wasi(fd) => {
774 let mut rp0 = MaybeUninit::<Size>::uninit();
775 let ret = wasi::wasi_snapshot_preview1::path_readlink(
776 fd as i32,
777 path.as_ptr() as i32,
778 path.to_bytes().len() as i32,
779 buf as i32,
780 buf_len as i32,
781 rp0.as_mut_ptr() as i32,
782 );
783 match ret {
784 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Size)),
785 _ => Err(Error(ret as u16)),
786 }
787 }
788 }
789}
790
791pub(crate) unsafe fn path_remove_directory<S: Storage>(
792 fs: &mut FileSystem<S>,
793 fd: UserFd,
794 path: &CStr,
795) -> Result<(), Error> {
796 let fd = fs.get_backing_fd(fd)?;
797 match fd {
798 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
799 BackingFd::Wasi(fd) => {
800 let ret = wasi::wasi_snapshot_preview1::path_remove_directory(
801 fd as i32,
802 path.as_ptr() as i32,
803 path.to_bytes().len() as i32,
804 );
805 match ret {
806 0 => Ok(()),
807 _ => Err(Error(ret as u16)),
808 }
809 }
810 }
811}
812
813pub(crate) unsafe fn path_rename<S: Storage>(
814 fs: &mut FileSystem<S>,
815 fd: UserFd,
816 old_path: &CStr,
817 new_fd: UserFd,
818 new_path: &CStr,
819) -> Result<(), Error> {
820 let fd = fs.get_backing_fd(fd)?;
821 let new_fd = fs.get_backing_fd(new_fd)?;
822 match (fd, new_fd) {
823 (BackingFd::Wasi(fd), BackingFd::Wasi(new_fd)) => {
824 let ret = wasi::wasi_snapshot_preview1::path_rename(
825 fd as i32,
826 old_path.as_ptr() as i32,
827 old_path.to_bytes().len() as i32,
828 new_fd as i32,
829 new_path.as_ptr() as i32,
830 new_path.to_bytes().len() as i32,
831 );
832 match ret {
833 0 => Ok(()),
834 _ => Err(Error(ret as u16)),
835 }
836 }
837 (_, _) => Err(wasi::ERRNO_NOTSUP.into()),
838 }
839}
840
841pub(crate) unsafe fn path_symlink<S: Storage>(
842 fs: &mut FileSystem<S>,
843 old_path: &CStr,
844 fd: UserFd,
845 new_path: &CStr,
846) -> Result<(), Error> {
847 let fd = fs.get_backing_fd(fd)?;
848 match fd {
849 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
850 BackingFd::Wasi(fd) => {
851 let ret = wasi::wasi_snapshot_preview1::path_symlink(
852 old_path.as_ptr() as i32,
853 old_path.to_bytes().len() as i32,
854 fd as i32,
855 new_path.as_ptr() as i32,
856 new_path.to_bytes().len() as i32,
857 );
858 match ret {
859 0 => Ok(()),
860 _ => Err(Error(ret as u16)),
861 }
862 }
863 }
864}
865
866pub(crate) unsafe fn path_unlink_file<S: Storage>(
867 fs: &mut FileSystem<S>,
868 fd: UserFd,
869 path: &CStr,
870) -> Result<(), Error> {
871 let fd = fs.get_backing_fd(fd)?;
872 match fd {
873 BackingFd::Virtual(vfd) => Err(wasi::ERRNO_NOTSUP.into()),
874 BackingFd::Wasi(fd) => {
875 let ret = wasi::wasi_snapshot_preview1::path_unlink_file(
876 fd as i32,
877 path.as_ptr() as i32,
878 path.to_bytes().len() as i32,
879 );
880 match ret {
881 0 => Ok(()),
882 _ => Err(Error(ret as u16)),
883 }
884 }
885 }
886}
887
888pub(crate) unsafe fn poll_oneoff<S: Storage>(
889 fs: &mut FileSystem<S>,
890 in_: *const Subscription,
891 out: *mut Event,
892 nsubscriptions: u32,
893) -> Result<Size, Error> {
894 let in_ = slice::from_raw_parts(in_, nsubscriptions as usize);
895 let mut new_in = Vec::<Subscription>::new();
896 for sub in in_ {
897 match sub.u.tag {
898 0 => {
899 new_in.push(*sub);
900 }
901 1 | 2 => {
902 let mut new_sub = *sub;
903 let fd = if sub.u.tag == 1 {
904 sub.u.u.fd_read.file_descriptor
905 } else {
906 sub.u.u.fd_write.file_descriptor
907 };
908 let fd = fs.get_backing_fd(fd)?;
909 let new_fd = match fd {
910 BackingFd::Virtual(_) => return Err(wasi::ERRNO_NOTSUP.into()),
911 BackingFd::Wasi(fd) => fd,
912 };
913
914 if sub.u.tag == 1 {
915 new_sub.u.u.fd_read.file_descriptor = new_fd;
916 } else {
917 new_sub.u.u.fd_write.file_descriptor = new_fd;
918 }
919
920 new_in.push(new_sub);
921 }
922 _ => return Err(wasi::ERRNO_INVAL.into()),
923 }
924 }
925 let mut rp0 = MaybeUninit::<Fdstat>::uninit();
926 let ret = wasi::wasi_snapshot_preview1::poll_oneoff(
927 new_in.as_ptr() as i32,
928 out as i32,
929 nsubscriptions as i32,
930 rp0.as_mut_ptr() as i32,
931 );
932
933 match ret {
934 0 => Ok(core::ptr::read(rp0.as_mut_ptr() as i32 as *const Size)),
935 _ => Err(Error(ret as u16)),
936 }
937}
938
939fn read_bytes<R: std::io::Read>(mut src: R, iovs: wasi::IovecArray) -> Result<usize, wasi::Errno> {
940 let mut bytes_read = 0;
941 for iov in iovs {
942 unsafe {
943 let buf = slice::from_raw_parts_mut(iov.buf, iov.buf_len);
944 bytes_read += src.read(buf).map_err(|_| wasi::ERRNO_IO)?;
945 }
946 }
947 Ok(bytes_read)
948}
949
950fn cstr_to_path(path: &CStr) -> Result<&Path, wasi::Errno> {
951 let os_str: &OsStr = unsafe { std::mem::transmute(path.to_bytes()) };
952 Ok(Path::new(os_str))
953}