1#![allow(unused, clippy::too_many_arguments, clippy::cognitive_complexity)]
2
3pub mod types {
4 pub use wasmer_wasi_types::types::*;
5 pub use wasmer_wasi_types::wasi;
6}
7
8#[cfg(any(
9 target_os = "freebsd",
10 target_os = "linux",
11 target_os = "android",
12 target_vendor = "apple"
13))]
14pub mod unix;
15#[cfg(any(target_arch = "wasm32"))]
16pub mod wasm32;
17#[cfg(any(target_os = "windows"))]
18pub mod windows;
19
20pub mod legacy;
21#[cfg(feature = "wasix")]
23pub mod wasix32;
24#[cfg(feature = "wasix")]
25pub mod wasix64;
26
27use self::types::{
28 wasi::{
29 Addressfamily, Advice, Bid, BusDataFormat, BusErrno, BusHandles, Cid, Clockid, Dircookie,
30 Dirent, Errno, Event, EventEnum, EventFdReadwrite, Eventrwflags, Eventtype, Fd as WasiFd,
31 Fdflags, Fdstat, Filesize, Filestat, Filetype, Fstflags, Linkcount, OptionFd, Pid, Prestat,
32 Rights, Snapshot0Clockid, Sockoption, Sockstatus, Socktype, StdioMode as WasiStdioMode,
33 Streamsecurity, Subscription, SubscriptionEnum, SubscriptionFsReadwrite, Tid, Timestamp,
34 Tty, Whence,
35 },
36 *,
37};
38use crate::state::{bus_error_into_wasi_err, wasi_error_into_bus_err, InodeHttpSocketType};
39use crate::utils::map_io_err;
40use crate::WasiBusProcessId;
41use crate::{
42 mem_error_to_wasi,
43 state::{
44 self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll,
45 virtual_file_type_to_wasi_file_type, Inode, InodeSocket, InodeSocketKind, InodeVal, Kind,
46 PollEvent, PollEventBuilder, WasiPipe, WasiState, MAX_SYMLINKS,
47 },
48 Fd, WasiEnv, WasiError, WasiThread, WasiThreadId,
49};
50use bytes::Bytes;
51use std::borrow::{Borrow, Cow};
52use std::convert::{Infallible, TryInto};
53use std::io::{self, Read, Seek, Write};
54use std::mem::transmute;
55use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
56use std::ops::{Deref, DerefMut};
57use std::sync::atomic::AtomicU64;
58use std::sync::{atomic::Ordering, Mutex};
59use std::sync::{mpsc, Arc};
60use std::time::Duration;
61use tracing::{debug, error, trace, warn};
62use wasmer::{
63 AsStoreMut, Extern, FunctionEnv, FunctionEnvMut, Instance, Memory, Memory32, Memory64,
64 MemorySize, MemoryView, Module, RuntimeError, Value, WasmPtr, WasmSlice,
65};
66use wasmer_vbus::{FileDescriptor, StdioMode};
67use wasmer_vfs::{FsError, VirtualFile};
68use wasmer_vnet::{SocketHttpRequest, StreamSecurity};
69
70#[cfg(any(
71 target_os = "freebsd",
72 target_os = "linux",
73 target_os = "android",
74 target_vendor = "apple"
75))]
76pub use unix::*;
77
78#[cfg(any(target_os = "windows"))]
79pub use windows::*;
80
81#[cfg(any(target_arch = "wasm32"))]
82pub use wasm32::*;
83
84fn to_offset<M: MemorySize>(offset: usize) -> Result<M::Offset, Errno> {
85 let ret: M::Offset = offset.try_into().map_err(|_| Errno::Inval)?;
86 Ok(ret)
87}
88
89fn from_offset<M: MemorySize>(offset: M::Offset) -> Result<usize, Errno> {
90 let ret: usize = offset.try_into().map_err(|_| Errno::Inval)?;
91 Ok(ret)
92}
93
94fn write_bytes_inner<T: Write, M: MemorySize>(
95 mut write_loc: T,
96 memory: &MemoryView,
97 iovs_arr_cell: WasmSlice<__wasi_ciovec_t<M>>,
98) -> Result<usize, Errno> {
99 let mut bytes_written = 0usize;
100 for iov in iovs_arr_cell.iter() {
101 let iov_inner = iov.read().map_err(mem_error_to_wasi)?;
102 let bytes = WasmPtr::<u8, M>::new(iov_inner.buf)
103 .slice(memory, iov_inner.buf_len)
104 .map_err(mem_error_to_wasi)?;
105 let bytes = bytes.read_to_vec().map_err(mem_error_to_wasi)?;
106 write_loc.write_all(&bytes).map_err(map_io_err)?;
107
108 bytes_written += from_offset::<M>(iov_inner.buf_len)?;
109 }
110 Ok(bytes_written)
111}
112
113pub(crate) fn write_bytes<T: Write, M: MemorySize>(
114 mut write_loc: T,
115 memory: &MemoryView,
116 iovs_arr: WasmSlice<__wasi_ciovec_t<M>>,
117) -> Result<usize, Errno> {
118 let result = write_bytes_inner::<_, M>(&mut write_loc, memory, iovs_arr);
119 write_loc.flush();
120 result
121}
122
123pub(crate) fn read_bytes<T: Read, M: MemorySize>(
124 mut reader: T,
125 memory: &MemoryView,
126 iovs_arr: WasmSlice<__wasi_iovec_t<M>>,
127) -> Result<usize, Errno> {
128 let mut bytes_read = 0usize;
129
130 let mut raw_bytes: Vec<u8> = vec![0; 1024];
133
134 for iov in iovs_arr.iter() {
135 let iov_inner = iov.read().map_err(mem_error_to_wasi)?;
136 raw_bytes.clear();
137 let to_read = from_offset::<M>(iov_inner.buf_len)?;
138 raw_bytes.resize(to_read, 0);
139 let has_read = reader.read(&mut raw_bytes).map_err(map_io_err)?;
140
141 let buf = WasmPtr::<u8, M>::new(iov_inner.buf)
142 .slice(memory, iov_inner.buf_len)
143 .map_err(mem_error_to_wasi)?;
144 buf.write_slice(&raw_bytes).map_err(mem_error_to_wasi)?;
145 bytes_read += has_read;
146 if has_read != to_read {
147 return Ok(bytes_read);
148 }
149 }
150 Ok(bytes_read)
151}
152
153fn __sock_actor<T, F>(
154 ctx: &FunctionEnvMut<'_, WasiEnv>,
155 sock: WasiFd,
156 rights: Rights,
157 actor: F,
158) -> Result<T, Errno>
159where
160 F: FnOnce(&crate::state::InodeSocket) -> Result<T, Errno>,
161{
162 let env = ctx.data();
163 let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
164
165 let fd_entry = state.fs.get_fd(sock)?;
166 let ret = {
167 if !rights.is_empty() && !fd_entry.rights.contains(rights) {
168 return Err(Errno::Access);
169 }
170
171 let inode_idx = fd_entry.inode;
172 let inode = &inodes.arena[inode_idx];
173
174 let mut guard = inode.read();
175 let deref = guard.deref();
176 match deref {
177 Kind::Socket { socket } => actor(socket)?,
178 _ => {
179 return Err(Errno::Notsock);
180 }
181 }
182 };
183
184 Ok(ret)
185}
186
187fn __sock_actor_mut<T, F>(
188 ctx: &FunctionEnvMut<'_, WasiEnv>,
189 sock: WasiFd,
190 rights: Rights,
191 actor: F,
192) -> Result<T, Errno>
193where
194 F: FnOnce(&mut crate::state::InodeSocket) -> Result<T, Errno>,
195{
196 let env = ctx.data();
197 let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
198
199 let fd_entry = state.fs.get_fd(sock)?;
200 let ret = {
201 if !rights.is_empty() && !fd_entry.rights.contains(rights) {
202 return Err(Errno::Access);
203 }
204
205 let inode_idx = fd_entry.inode;
206 let inode = &inodes.arena[inode_idx];
207
208 let mut guard = inode.write();
209 let deref_mut = guard.deref_mut();
210 match deref_mut {
211 Kind::Socket { socket } => actor(socket)?,
212 _ => {
213 return Err(Errno::Notsock);
214 }
215 }
216 };
217
218 Ok(ret)
219}
220
221fn __sock_upgrade<F>(
222 ctx: &FunctionEnvMut<'_, WasiEnv>,
223 sock: WasiFd,
224 rights: Rights,
225 actor: F,
226) -> Result<(), Errno>
227where
228 F: FnOnce(&mut crate::state::InodeSocket) -> Result<Option<crate::state::InodeSocket>, Errno>,
229{
230 let env = ctx.data();
231 let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
232
233 let fd_entry = state.fs.get_fd(sock)?;
234 if !rights.is_empty() && !fd_entry.rights.contains(rights) {
235 return Err(Errno::Access);
236 }
237
238 let inode_idx = fd_entry.inode;
239 let inode = &inodes.arena[inode_idx];
240
241 let mut guard = inode.write();
242 let deref_mut = guard.deref_mut();
243 match deref_mut {
244 Kind::Socket { socket } => {
245 let new_socket = actor(socket)?;
246
247 if let Some(mut new_socket) = new_socket {
248 std::mem::swap(socket, &mut new_socket);
249 }
250 }
251 _ => {
252 return Err(Errno::Notsock);
253 }
254 }
255
256 Ok(())
257}
258
259#[must_use]
260fn write_buffer_array<M: MemorySize>(
261 memory: &MemoryView,
262 from: &[Vec<u8>],
263 ptr_buffer: WasmPtr<WasmPtr<u8, M>, M>,
264 buffer: WasmPtr<u8, M>,
265) -> Errno {
266 let ptrs = wasi_try_mem!(ptr_buffer.slice(memory, wasi_try!(to_offset::<M>(from.len()))));
267
268 let mut current_buffer_offset = 0usize;
269 for ((i, sub_buffer), ptr) in from.iter().enumerate().zip(ptrs.iter()) {
270 trace!("ptr: {:?}, subbuffer: {:?}", ptr, sub_buffer);
271 let mut buf_offset = buffer.offset();
272 buf_offset += wasi_try!(to_offset::<M>(current_buffer_offset));
273 let new_ptr = WasmPtr::new(buf_offset);
274 wasi_try_mem!(ptr.write(new_ptr));
275
276 let data =
277 wasi_try_mem!(new_ptr.slice(memory, wasi_try!(to_offset::<M>(sub_buffer.len()))));
278 wasi_try_mem!(data.write_slice(sub_buffer));
279 wasi_try_mem!(wasi_try_mem!(
280 new_ptr.add_offset(wasi_try!(to_offset::<M>(sub_buffer.len())))
281 )
282 .write(memory, 0));
283
284 current_buffer_offset += sub_buffer.len() + 1;
285 }
286
287 Errno::Success
288}
289
290fn get_current_time_in_nanos() -> Result<Timestamp, Errno> {
291 let now = std::time::SystemTime::now();
292 let duration = now
293 .duration_since(std::time::SystemTime::UNIX_EPOCH)
294 .map_err(|_| Errno::Io)?;
295 Ok(duration.as_nanos() as Timestamp)
296}
297
298pub fn args_get<M: MemorySize>(
308 mut ctx: FunctionEnvMut<'_, WasiEnv>,
309 argv: WasmPtr<WasmPtr<u8, M>, M>,
310 argv_buf: WasmPtr<u8, M>,
311) -> Errno {
312 debug!("wasi::args_get");
313 let env = ctx.data();
314 let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
315
316 let result = write_buffer_array(&memory, &state.args, argv, argv_buf);
317
318 debug!(
319 "=> args:\n{}",
320 state
321 .args
322 .iter()
323 .enumerate()
324 .map(|(i, v)| format!("{:>20}: {}", i, ::std::str::from_utf8(v).unwrap()))
325 .collect::<Vec<String>>()
326 .join("\n")
327 );
328
329 result
330}
331
332pub fn args_sizes_get<M: MemorySize>(
340 mut ctx: FunctionEnvMut<'_, WasiEnv>,
341 argc: WasmPtr<M::Offset, M>,
342 argv_buf_size: WasmPtr<M::Offset, M>,
343) -> Errno {
344 debug!("wasi::args_sizes_get");
345 let env = ctx.data();
346 let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
347
348 let argc = argc.deref(&memory);
349 let argv_buf_size = argv_buf_size.deref(&memory);
350
351 let argc_val: M::Offset = wasi_try!(state.args.len().try_into().map_err(|_| Errno::Overflow));
352 let argv_buf_size_val: usize = state.args.iter().map(|v| v.len() + 1).sum();
353 let argv_buf_size_val: M::Offset =
354 wasi_try!(argv_buf_size_val.try_into().map_err(|_| Errno::Overflow));
355 wasi_try_mem!(argc.write(argc_val));
356 wasi_try_mem!(argv_buf_size.write(argv_buf_size_val));
357
358 debug!("=> argc={}, argv_buf_size={}", argc_val, argv_buf_size_val);
359
360 Errno::Success
361}
362
363pub fn clock_res_get<M: MemorySize>(
372 mut ctx: FunctionEnvMut<'_, WasiEnv>,
373 clock_id: Snapshot0Clockid,
374 resolution: WasmPtr<Timestamp, M>,
375) -> Errno {
376 trace!("wasi::clock_res_get");
377 let env = ctx.data();
378 let memory = env.memory_view(&ctx);
379
380 let out_addr = resolution.deref(&memory);
381 let t_out = wasi_try!(platform_clock_res_get(clock_id, out_addr));
382 wasi_try_mem!(resolution.write(&memory, t_out as Timestamp));
383 Errno::Success
384}
385
386pub fn clock_time_get<M: MemorySize>(
397 ctx: FunctionEnvMut<'_, WasiEnv>,
398 clock_id: Snapshot0Clockid,
399 precision: Timestamp,
400 time: WasmPtr<Timestamp, M>,
401) -> Errno {
402 debug!(
403 "wasi::clock_time_get clock_id: {}, precision: {}",
404 clock_id as u8, precision
405 );
406 let env = ctx.data();
407 let memory = env.memory_view(&ctx);
408
409 let t_out = wasi_try!(platform_clock_time_get(clock_id, precision));
410 wasi_try_mem!(time.write(&memory, t_out as Timestamp));
411
412 let result = Errno::Success;
413 trace!(
414 "time: {} => {}",
415 wasi_try_mem!(time.deref(&memory).read()),
416 result
417 );
418 result
419}
420
421pub fn environ_get<M: MemorySize>(
430 ctx: FunctionEnvMut<'_, WasiEnv>,
431 environ: WasmPtr<WasmPtr<u8, M>, M>,
432 environ_buf: WasmPtr<u8, M>,
433) -> Errno {
434 debug!(
435 "wasi::environ_get. Environ: {:?}, environ_buf: {:?}",
436 environ, environ_buf
437 );
438 let env = ctx.data();
439 let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
440 trace!(" -> State envs: {:?}", state.envs);
441
442 write_buffer_array(&memory, &state.envs, environ, environ_buf)
443}
444
445pub fn environ_sizes_get<M: MemorySize>(
453 ctx: FunctionEnvMut<'_, WasiEnv>,
454 environ_count: WasmPtr<M::Offset, M>,
455 environ_buf_size: WasmPtr<M::Offset, M>,
456) -> Errno {
457 trace!("wasi::environ_sizes_get");
458 let env = ctx.data();
459 let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
460
461 let environ_count = environ_count.deref(&memory);
462 let environ_buf_size = environ_buf_size.deref(&memory);
463
464 let env_var_count: M::Offset =
465 wasi_try!(state.envs.len().try_into().map_err(|_| Errno::Overflow));
466 let env_buf_size: usize = state.envs.iter().map(|v| v.len() + 1).sum();
467 let env_buf_size: M::Offset = wasi_try!(env_buf_size.try_into().map_err(|_| Errno::Overflow));
468 wasi_try_mem!(environ_count.write(env_var_count));
469 wasi_try_mem!(environ_buf_size.write(env_buf_size));
470
471 trace!(
472 "env_var_count: {}, env_buf_size: {}",
473 env_var_count,
474 env_buf_size
475 );
476
477 Errno::Success
478}
479
480pub fn fd_advise(
492 ctx: FunctionEnvMut<'_, WasiEnv>,
493 fd: WasiFd,
494 offset: Filesize,
495 len: Filesize,
496 advice: Advice,
497) -> Errno {
498 debug!("wasi::fd_advise: fd={}", fd);
499
500 Errno::Success
503}
504
505pub fn fd_allocate(
515 ctx: FunctionEnvMut<'_, WasiEnv>,
516 fd: WasiFd,
517 offset: Filesize,
518 len: Filesize,
519) -> Errno {
520 debug!("wasi::fd_allocate");
521 let env = ctx.data();
522 let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
523 let fd_entry = wasi_try!(state.fs.get_fd(fd));
524 let inode = fd_entry.inode;
525
526 if !fd_entry.rights.contains(Rights::FD_ALLOCATE) {
527 return Errno::Access;
528 }
529 let new_size = wasi_try!(offset.checked_add(len).ok_or(Errno::Inval));
530 {
531 let mut guard = inodes.arena[inode].write();
532 let deref_mut = guard.deref_mut();
533 match deref_mut {
534 Kind::File { handle, .. } => {
535 if let Some(handle) = handle {
536 wasi_try!(handle.set_len(new_size).map_err(fs_error_into_wasi_err));
537 } else {
538 return Errno::Badf;
539 }
540 }
541 Kind::Socket { .. } => return Errno::Badf,
542 Kind::Pipe { .. } => return Errno::Badf,
543 Kind::Buffer { buffer } => {
544 buffer.resize(new_size as usize, 0);
545 }
546 Kind::Symlink { .. } => return Errno::Badf,
547 Kind::EventNotifications { .. } => return Errno::Badf,
548 Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir,
549 }
550 }
551 inodes.arena[inode].stat.write().unwrap().st_size = new_size;
552 debug!("New file size: {}", new_size);
553
554 Errno::Success
555}
556
557pub fn fd_close(ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Errno {
568 debug!("wasi::fd_close: fd={}", fd);
569 let env = ctx.data();
570 let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
571
572 let fd_entry = wasi_try!(state.fs.get_fd(fd));
573
574 wasi_try!(state.fs.close_fd(inodes.deref(), fd));
575
576 Errno::Success
577}
578
579pub fn fd_datasync(ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Errno {
585 debug!("wasi::fd_datasync");
586 let env = ctx.data();
587 let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
588 let fd_entry = wasi_try!(state.fs.get_fd(fd));
589 if !fd_entry.rights.contains(Rights::FD_DATASYNC) {
590 return Errno::Access;
591 }
592
593 if let Err(e) = state.fs.flush(inodes.deref(), fd) {
594 e
595 } else {
596 Errno::Success
597 }
598}
599
600pub fn fd_fdstat_get<M: MemorySize>(
609 ctx: FunctionEnvMut<'_, WasiEnv>,
610 fd: WasiFd,
611 buf_ptr: WasmPtr<Fdstat, M>,
612) -> Errno {
613 debug!(
614 "wasi::fd_fdstat_get: fd={}, buf_ptr={}",
615 fd,
616 buf_ptr.offset()
617 );
618 let env = ctx.data();
619 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
620 let stat = wasi_try!(state.fs.fdstat(inodes.deref(), fd));
621
622 let buf = buf_ptr.deref(&memory);
623
624 wasi_try_mem!(buf.write(stat));
625
626 Errno::Success
627}
628
629pub fn fd_fdstat_set_flags(ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd, flags: Fdflags) -> Errno {
637 debug!("wasi::fd_fdstat_set_flags");
638 let env = ctx.data();
639 let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
640 let mut fd_map = state.fs.fd_map.write().unwrap();
641 let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
642
643 if !fd_entry.rights.contains(Rights::FD_FDSTAT_SET_FLAGS) {
644 return Errno::Access;
645 }
646
647 fd_entry.flags = flags;
648 Errno::Success
649}
650
651pub fn fd_fdstat_set_rights(
661 ctx: FunctionEnvMut<'_, WasiEnv>,
662 fd: WasiFd,
663 fs_rights_base: Rights,
664 fs_rights_inheriting: Rights,
665) -> Errno {
666 debug!("wasi::fd_fdstat_set_rights");
667 let env = ctx.data();
668 let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
669 let mut fd_map = state.fs.fd_map.write().unwrap();
670 let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
671
672 if fd_entry.rights | fs_rights_base != fd_entry.rights
674 || fd_entry.rights_inheriting | fs_rights_inheriting != fd_entry.rights_inheriting
675 {
676 return Errno::Notcapable;
677 }
678
679 fd_entry.rights = fs_rights_base;
680 fd_entry.rights_inheriting = fs_rights_inheriting;
681
682 Errno::Success
683}
684
685pub fn fd_filestat_get<M: MemorySize>(
694 ctx: FunctionEnvMut<'_, WasiEnv>,
695 fd: WasiFd,
696 buf: WasmPtr<Filestat, M>,
697) -> Errno {
698 debug!("wasi::fd_filestat_get");
699 let env = ctx.data();
700 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
701 let fd_entry = wasi_try!(state.fs.get_fd(fd));
702 if !fd_entry.rights.contains(Rights::FD_FILESTAT_GET) {
703 return Errno::Access;
704 }
705
706 let stat = wasi_try!(state.fs.filestat_fd(inodes.deref(), fd));
707
708 let buf = buf.deref(&memory);
709 wasi_try_mem!(buf.write(stat));
710
711 Errno::Success
712}
713
714pub fn fd_filestat_set_size(
722 ctx: FunctionEnvMut<'_, WasiEnv>,
723 fd: WasiFd,
724 st_size: Filesize,
725) -> Errno {
726 debug!("wasi::fd_filestat_set_size");
727 let env = ctx.data();
728 let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
729 let fd_entry = wasi_try!(state.fs.get_fd(fd));
730 let inode = fd_entry.inode;
731
732 if !fd_entry.rights.contains(Rights::FD_FILESTAT_SET_SIZE) {
733 return Errno::Access;
734 }
735
736 {
737 let mut guard = inodes.arena[inode].write();
738 let deref_mut = guard.deref_mut();
739 match deref_mut {
740 Kind::File { handle, .. } => {
741 if let Some(handle) = handle {
742 wasi_try!(handle.set_len(st_size).map_err(fs_error_into_wasi_err));
743 } else {
744 return Errno::Badf;
745 }
746 }
747 Kind::Buffer { buffer } => {
748 buffer.resize(st_size as usize, 0);
749 }
750 Kind::Socket { .. } => return Errno::Badf,
751 Kind::Pipe { .. } => return Errno::Badf,
752 Kind::Symlink { .. } => return Errno::Badf,
753 Kind::EventNotifications { .. } => return Errno::Badf,
754 Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir,
755 }
756 }
757 inodes.arena[inode].stat.write().unwrap().st_size = st_size;
758
759 Errno::Success
760}
761
762pub fn fd_filestat_set_times(
772 ctx: FunctionEnvMut<'_, WasiEnv>,
773 fd: WasiFd,
774 st_atim: Timestamp,
775 st_mtim: Timestamp,
776 fst_flags: Fstflags,
777) -> Errno {
778 debug!("wasi::fd_filestat_set_times");
779 let env = ctx.data();
780 let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
781 let fd_entry = wasi_try!(state.fs.get_fd(fd));
782
783 if !fd_entry.rights.contains(Rights::FD_FILESTAT_SET_TIMES) {
784 return Errno::Access;
785 }
786
787 if (fst_flags.contains(Fstflags::SET_ATIM) && fst_flags.contains(Fstflags::SET_ATIM_NOW))
788 || (fst_flags.contains(Fstflags::SET_MTIM) && fst_flags.contains(Fstflags::SET_MTIM_NOW))
789 {
790 return Errno::Inval;
791 }
792
793 let inode_idx = fd_entry.inode;
794 let inode = &inodes.arena[inode_idx];
795
796 if fst_flags.contains(Fstflags::SET_ATIM) || fst_flags.contains(Fstflags::SET_ATIM_NOW) {
797 let time_to_set = if fst_flags.contains(Fstflags::SET_ATIM) {
798 st_atim
799 } else {
800 wasi_try!(get_current_time_in_nanos())
801 };
802 inode.stat.write().unwrap().st_atim = time_to_set;
803 }
804
805 if fst_flags.contains(Fstflags::SET_MTIM) || fst_flags.contains(Fstflags::SET_MTIM_NOW) {
806 let time_to_set = if fst_flags.contains(Fstflags::SET_MTIM) {
807 st_mtim
808 } else {
809 wasi_try!(get_current_time_in_nanos())
810 };
811 inode.stat.write().unwrap().st_mtim = time_to_set;
812 }
813
814 Errno::Success
815}
816
817pub fn fd_pread<M: MemorySize>(
833 ctx: FunctionEnvMut<'_, WasiEnv>,
834 fd: WasiFd,
835 iovs: WasmPtr<__wasi_iovec_t<M>, M>,
836 iovs_len: M::Offset,
837 offset: Filesize,
838 nread: WasmPtr<M::Offset, M>,
839) -> Result<Errno, WasiError> {
840 trace!("wasi::fd_pread: fd={}, offset={}", fd, offset);
841 let env = ctx.data();
842 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
843
844 let iovs = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len));
845 let nread_ref = nread.deref(&memory);
846
847 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
848 let bytes_read = match fd {
849 __WASI_STDIN_FILENO => {
850 let mut guard = wasi_try_ok!(
851 inodes
852 .stdin_mut(&state.fs.fd_map)
853 .map_err(fs_error_into_wasi_err),
854 env
855 );
856 if let Some(ref mut stdin) = guard.deref_mut() {
857 wasi_try_ok!(read_bytes(stdin, &memory, iovs), env)
858 } else {
859 return Ok(Errno::Badf);
860 }
861 }
862 __WASI_STDOUT_FILENO => return Ok(Errno::Inval),
863 __WASI_STDERR_FILENO => return Ok(Errno::Inval),
864 _ => {
865 let inode = fd_entry.inode;
866
867 if !fd_entry.rights.contains(Rights::FD_READ | Rights::FD_SEEK) {
868 debug!(
869 "Invalid rights on {:X}: expected READ and SEEK",
870 fd_entry.rights
871 );
872 return Ok(Errno::Access);
873 }
874 let mut guard = inodes.arena[inode].write();
875 let deref_mut = guard.deref_mut();
876 match deref_mut {
877 Kind::File { handle, .. } => {
878 if let Some(h) = handle {
879 wasi_try_ok!(
880 h.seek(std::io::SeekFrom::Start(offset as u64))
881 .map_err(map_io_err),
882 env
883 );
884 wasi_try_ok!(read_bytes(h, &memory, iovs), env)
885 } else {
886 return Ok(Errno::Inval);
887 }
888 }
889 Kind::Socket { socket } => {
890 wasi_try_ok!(socket.recv(&memory, iovs), env)
891 }
892 Kind::Pipe { pipe } => {
893 wasi_try_ok!(pipe.recv(&memory, iovs), env)
894 }
895 Kind::EventNotifications { .. } => return Ok(Errno::Inval),
896 Kind::Dir { .. } | Kind::Root { .. } => return Ok(Errno::Isdir),
897 Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"),
898 Kind::Buffer { buffer } => {
899 wasi_try_ok!(read_bytes(&buffer[(offset as usize)..], &memory, iovs), env)
900 }
901 }
902 }
903 };
904
905 let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
906 wasi_try_mem_ok!(nread_ref.write(bytes_read));
907 debug!("Success: {} bytes read", bytes_read);
908 Ok(Errno::Success)
909}
910
911pub fn fd_prestat_get<M: MemorySize>(
920 ctx: FunctionEnvMut<'_, WasiEnv>,
921 fd: WasiFd,
922 buf: WasmPtr<Prestat, M>,
923) -> Errno {
924 trace!("wasi::fd_prestat_get: fd={}", fd);
925 let env = ctx.data();
926 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
927
928 let prestat_ptr = buf.deref(&memory);
929 wasi_try_mem!(
930 prestat_ptr.write(wasi_try!(state.fs.prestat_fd(inodes.deref(), fd).map_err(
931 |code| {
932 debug!("fd_prestat_get failed (fd={}) - errno={}", fd, code);
933 code
934 }
935 )))
936 );
937
938 Errno::Success
939}
940
941pub fn fd_prestat_dir_name<M: MemorySize>(
942 ctx: FunctionEnvMut<'_, WasiEnv>,
943 fd: WasiFd,
944 path: WasmPtr<u8, M>,
945 path_len: M::Offset,
946) -> Errno {
947 trace!(
948 "wasi::fd_prestat_dir_name: fd={}, path_len={}",
949 fd,
950 path_len
951 );
952 let env = ctx.data();
953 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
954 let path_chars = wasi_try_mem!(path.slice(&memory, path_len));
955
956 let real_inode = wasi_try!(state.fs.get_fd_inode(fd));
957 let inode_val = &inodes.arena[real_inode];
958
959 trace!("=> inode: {:?}", inode_val);
962 let guard = inode_val.read();
963 let deref = guard.deref();
964 match deref {
965 Kind::Dir { .. } | Kind::Root { .. } => {
966 let path_len: u64 = path_len.into();
967 if (inode_val.name.len() as u64) <= path_len {
968 wasi_try_mem!(path_chars
969 .subslice(0..inode_val.name.len() as u64)
970 .write_slice(inode_val.name.as_bytes()));
971
972 trace!("=> result: \"{}\"", inode_val.name);
973
974 Errno::Success
975 } else {
976 Errno::Overflow
977 }
978 }
979 Kind::Symlink { .. }
980 | Kind::Buffer { .. }
981 | Kind::File { .. }
982 | Kind::Socket { .. }
983 | Kind::Pipe { .. }
984 | Kind::EventNotifications { .. } => Errno::Notdir,
985 }
986}
987
988pub fn fd_pwrite<M: MemorySize>(
1003 ctx: FunctionEnvMut<'_, WasiEnv>,
1004 fd: WasiFd,
1005 iovs: WasmPtr<__wasi_ciovec_t<M>, M>,
1006 iovs_len: M::Offset,
1007 offset: Filesize,
1008 nwritten: WasmPtr<M::Offset, M>,
1009) -> Result<Errno, WasiError> {
1010 trace!("wasi::fd_pwrite");
1011 let env = ctx.data();
1013 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
1014 let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len));
1015 let nwritten_ref = nwritten.deref(&memory);
1016
1017 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
1018 let bytes_written = match fd {
1019 __WASI_STDIN_FILENO => return Ok(Errno::Inval),
1020 __WASI_STDOUT_FILENO => {
1021 let mut guard = wasi_try_ok!(
1022 inodes
1023 .stdout_mut(&state.fs.fd_map)
1024 .map_err(fs_error_into_wasi_err),
1025 env
1026 );
1027 if let Some(ref mut stdout) = guard.deref_mut() {
1028 wasi_try_ok!(write_bytes(stdout, &memory, iovs_arr), env)
1029 } else {
1030 return Ok(Errno::Badf);
1031 }
1032 }
1033 __WASI_STDERR_FILENO => {
1034 let mut guard = wasi_try_ok!(
1035 inodes
1036 .stderr_mut(&state.fs.fd_map)
1037 .map_err(fs_error_into_wasi_err),
1038 env
1039 );
1040 if let Some(ref mut stderr) = guard.deref_mut() {
1041 wasi_try_ok!(write_bytes(stderr, &memory, iovs_arr), env)
1042 } else {
1043 return Ok(Errno::Badf);
1044 }
1045 }
1046 _ => {
1047 if !fd_entry.rights.contains(Rights::FD_WRITE | Rights::FD_SEEK) {
1048 return Ok(Errno::Access);
1049 }
1050
1051 let inode_idx = fd_entry.inode;
1052 let inode = &inodes.arena[inode_idx];
1053
1054 let mut guard = inode.write();
1055 let deref_mut = guard.deref_mut();
1056 match deref_mut {
1057 Kind::File { handle, .. } => {
1058 if let Some(handle) = handle {
1059 wasi_try_ok!(
1060 handle
1061 .seek(std::io::SeekFrom::Start(offset as u64))
1062 .map_err(map_io_err),
1063 env
1064 );
1065 wasi_try_ok!(write_bytes(handle, &memory, iovs_arr), env)
1066 } else {
1067 return Ok(Errno::Inval);
1068 }
1069 }
1070 Kind::Socket { socket } => {
1071 wasi_try_ok!(socket.send(&memory, iovs_arr), env)
1072 }
1073 Kind::Pipe { pipe } => {
1074 wasi_try_ok!(pipe.send(&memory, iovs_arr), env)
1075 }
1076 Kind::Dir { .. } | Kind::Root { .. } => {
1077 return Ok(Errno::Isdir);
1079 }
1080 Kind::EventNotifications { .. } => return Ok(Errno::Inval),
1081 Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pwrite"),
1082 Kind::Buffer { buffer } => {
1083 wasi_try_ok!(
1084 write_bytes(&mut buffer[(offset as usize)..], &memory, iovs_arr),
1085 env
1086 )
1087 }
1088 }
1089 }
1090 };
1091
1092 let bytes_written: M::Offset =
1093 wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
1094 wasi_try_mem_ok!(nwritten_ref.write(bytes_written));
1095
1096 Ok(Errno::Success)
1097}
1098
1099pub fn fd_read<M: MemorySize>(
1113 ctx: FunctionEnvMut<'_, WasiEnv>,
1114 fd: WasiFd,
1115 iovs: WasmPtr<__wasi_iovec_t<M>, M>,
1116 iovs_len: M::Offset,
1117 nread: WasmPtr<M::Offset, M>,
1118) -> Result<Errno, WasiError> {
1119 trace!("wasi::fd_read: fd={}", fd);
1120 let env = ctx.data();
1121 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
1122 let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len));
1124 let nread_ref = nread.deref(&memory);
1125
1126 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
1127 let bytes_read = match fd {
1128 __WASI_STDIN_FILENO => {
1129 let mut guard = wasi_try_ok!(
1130 inodes
1131 .stdin_mut(&state.fs.fd_map)
1132 .map_err(fs_error_into_wasi_err),
1133 env
1134 );
1135 if let Some(ref mut stdin) = guard.deref_mut() {
1136 wasi_try_ok!(read_bytes(stdin, &memory, iovs_arr), env)
1137 } else {
1138 return Ok(Errno::Badf);
1139 }
1140 }
1141 __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return Ok(Errno::Inval),
1142 _ => {
1143 if !fd_entry.rights.contains(Rights::FD_READ) {
1144 return Ok(Errno::Access);
1146 }
1147
1148 let is_non_blocking = fd_entry.flags.contains(Fdflags::NONBLOCK);
1149 let offset = fd_entry.offset as usize;
1150 let inode_idx = fd_entry.inode;
1151 let inode = &inodes.arena[inode_idx];
1152
1153 let bytes_read = {
1154 let mut guard = inode.write();
1155 let deref_mut = guard.deref_mut();
1156 match deref_mut {
1157 Kind::File { handle, .. } => {
1158 if let Some(handle) = handle {
1159 wasi_try_ok!(
1160 handle
1161 .seek(std::io::SeekFrom::Start(offset as u64))
1162 .map_err(map_io_err),
1163 env
1164 );
1165 wasi_try_ok!(read_bytes(handle, &memory, iovs_arr), env)
1166 } else {
1167 return Ok(Errno::Inval);
1168 }
1169 }
1170 Kind::Socket { socket } => {
1171 wasi_try_ok!(socket.recv(&memory, iovs_arr), env)
1172 }
1173 Kind::Pipe { pipe } => {
1174 wasi_try_ok!(pipe.recv(&memory, iovs_arr), env)
1175 }
1176 Kind::Dir { .. } | Kind::Root { .. } => {
1177 return Ok(Errno::Isdir);
1179 }
1180 Kind::EventNotifications {
1181 counter,
1182 is_semaphore,
1183 wakers,
1184 } => {
1185 let counter = Arc::clone(counter);
1186 let is_semaphore: bool = *is_semaphore;
1187 let wakers = Arc::clone(wakers);
1188 drop(guard);
1189 drop(inodes);
1190
1191 let (tx, rx) = mpsc::channel();
1192 {
1193 let mut guard = wakers.lock().unwrap();
1194 guard.push_front(tx);
1195 }
1196
1197 let ret;
1198 loop {
1199 let val = counter.load(Ordering::Acquire);
1200 if val > 0 {
1201 let new_val = if is_semaphore { val - 1 } else { 0 };
1202 if counter
1203 .compare_exchange(
1204 val,
1205 new_val,
1206 Ordering::AcqRel,
1207 Ordering::Acquire,
1208 )
1209 .is_ok()
1210 {
1211 let reader = val.to_ne_bytes();
1212 ret = wasi_try_ok!(
1213 read_bytes(&reader[..], &memory, iovs_arr),
1214 env
1215 );
1216 break;
1217 } else {
1218 continue;
1219 }
1220 }
1221
1222 if is_non_blocking {
1224 return Ok(Errno::Again);
1225 }
1226
1227 env.yield_now()?;
1229 if rx.recv_timeout(Duration::from_millis(5)).is_err() {
1230 env.sleep(Duration::from_millis(5))?;
1231 }
1232 }
1233 ret
1234 }
1235 Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
1236 Kind::Buffer { buffer } => {
1237 wasi_try_ok!(read_bytes(&buffer[offset..], &memory, iovs_arr), env)
1238 }
1239 }
1240 };
1241
1242 let mut fd_map = state.fs.fd_map.write().unwrap();
1244 let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
1245 fd_entry.offset += bytes_read as u64;
1246
1247 bytes_read
1248 }
1249 };
1250 let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
1251 wasi_try_mem_ok!(nread_ref.write(bytes_read));
1252
1253 Ok(Errno::Success)
1254}
1255
1256pub fn fd_readdir<M: MemorySize>(
1272 ctx: FunctionEnvMut<'_, WasiEnv>,
1273 fd: WasiFd,
1274 buf: WasmPtr<u8, M>,
1275 buf_len: M::Offset,
1276 cookie: Dircookie,
1277 bufused: WasmPtr<M::Offset, M>,
1278) -> Errno {
1279 trace!("wasi::fd_readdir");
1280 let env = ctx.data();
1281 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
1282 let buf_arr = wasi_try_mem!(buf.slice(&memory, buf_len));
1286 let bufused_ref = bufused.deref(&memory);
1287 let working_dir = wasi_try!(state.fs.get_fd(fd));
1288 let mut cur_cookie = cookie;
1289 let mut buf_idx = 0usize;
1290
1291 let entries: Vec<(String, Filetype, u64)> = {
1292 let guard = inodes.arena[working_dir.inode].read();
1293 let deref = guard.deref();
1294 match deref {
1295 Kind::Dir { path, entries, .. } => {
1296 debug!("Reading dir {:?}", path);
1297 let fs_info = wasi_try!(wasi_try!(state.fs_read_dir(path))
1302 .collect::<Result<Vec<_>, _>>()
1303 .map_err(fs_error_into_wasi_err));
1304 let mut entry_vec = wasi_try!(fs_info
1305 .into_iter()
1306 .map(|entry| {
1307 let filename = entry.file_name().to_string_lossy().to_string();
1308 debug!("Getting file: {:?}", filename);
1309 let filetype = virtual_file_type_to_wasi_file_type(
1310 entry.file_type().map_err(fs_error_into_wasi_err)?,
1311 );
1312 Ok((
1313 filename, filetype, 0, ))
1315 })
1316 .collect::<Result<Vec<(String, Filetype, u64)>, _>>());
1317 entry_vec.extend(
1318 entries
1319 .iter()
1320 .filter(|(_, inode)| inodes.arena[**inode].is_preopened)
1321 .map(|(name, inode)| {
1322 let entry = &inodes.arena[*inode];
1323 let stat = entry.stat.read().unwrap();
1324 (entry.name.to_string(), stat.st_filetype, stat.st_ino)
1325 }),
1326 );
1327 entry_vec.push((".".to_string(), Filetype::Directory, 0));
1330 entry_vec.push(("..".to_string(), Filetype::Directory, 0));
1331 entry_vec.sort_by(|a, b| a.0.cmp(&b.0));
1332 entry_vec
1333 }
1334 Kind::Root { entries } => {
1335 debug!("Reading root");
1336 let sorted_entries = {
1337 let mut entry_vec: Vec<(String, Inode)> =
1338 entries.iter().map(|(a, b)| (a.clone(), *b)).collect();
1339 entry_vec.sort_by(|a, b| a.0.cmp(&b.0));
1340 entry_vec
1341 };
1342 sorted_entries
1343 .into_iter()
1344 .map(|(name, inode)| {
1345 let entry = &inodes.arena[inode];
1346 let stat = entry.stat.read().unwrap();
1347 (format!("/{}", entry.name), stat.st_filetype, stat.st_ino)
1348 })
1349 .collect()
1350 }
1351 Kind::File { .. }
1352 | Kind::Symlink { .. }
1353 | Kind::Buffer { .. }
1354 | Kind::Socket { .. }
1355 | Kind::Pipe { .. }
1356 | Kind::EventNotifications { .. } => return Errno::Notdir,
1357 }
1358 };
1359
1360 for (entry_path_str, wasi_file_type, ino) in entries.iter().skip(cookie as usize) {
1361 cur_cookie += 1;
1362 let namlen = entry_path_str.len();
1363 debug!("Returning dirent for {}", entry_path_str);
1364 let dirent = Dirent {
1365 d_next: cur_cookie,
1366 d_ino: *ino,
1367 d_namlen: namlen as u32,
1368 d_type: *wasi_file_type,
1369 };
1370 let dirent_bytes = dirent_to_le_bytes(&dirent);
1371 let buf_len: u64 = buf_len.into();
1372 let upper_limit = std::cmp::min(
1373 (buf_len - buf_idx as u64) as usize,
1374 std::mem::size_of::<Dirent>(),
1375 );
1376 for (i, b) in dirent_bytes.iter().enumerate().take(upper_limit) {
1377 wasi_try_mem!(buf_arr.index((i + buf_idx) as u64).write(*b));
1378 }
1379 buf_idx += upper_limit;
1380 if upper_limit != std::mem::size_of::<Dirent>() {
1381 break;
1382 }
1383 let upper_limit = std::cmp::min((buf_len - buf_idx as u64) as usize, namlen);
1384 for (i, b) in entry_path_str.bytes().take(upper_limit).enumerate() {
1385 wasi_try_mem!(buf_arr.index((i + buf_idx) as u64).write(b));
1386 }
1387 buf_idx += upper_limit;
1388 if upper_limit != namlen {
1389 break;
1390 }
1391 }
1392
1393 let buf_idx: M::Offset = wasi_try!(buf_idx.try_into().map_err(|_| Errno::Overflow));
1394 wasi_try_mem!(bufused_ref.write(buf_idx));
1395 Errno::Success
1396}
1397
1398pub fn fd_renumber(ctx: FunctionEnvMut<'_, WasiEnv>, from: WasiFd, to: WasiFd) -> Errno {
1406 debug!("wasi::fd_renumber: from={}, to={}", from, to);
1407 let env = ctx.data();
1408 let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
1409
1410 let mut fd_map = state.fs.fd_map.write().unwrap();
1411 let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(Errno::Badf));
1412
1413 let new_fd_entry = Fd {
1414 rights: fd_entry.rights_inheriting,
1416 ..*fd_entry
1417 };
1418
1419 fd_map.insert(to, new_fd_entry);
1420 fd_map.remove(&from);
1421 Errno::Success
1422}
1423
1424pub fn fd_dup<M: MemorySize>(
1433 ctx: FunctionEnvMut<'_, WasiEnv>,
1434 fd: WasiFd,
1435 ret_fd: WasmPtr<WasiFd, M>,
1436) -> Errno {
1437 debug!("wasi::fd_dup");
1438
1439 let env = ctx.data();
1440 let (memory, state) = env.get_memory_and_wasi_state(&ctx, 0);
1441 let fd = wasi_try!(state.fs.clone_fd(fd));
1442
1443 wasi_try_mem!(ret_fd.write(&memory, fd));
1444
1445 Errno::Success
1446}
1447
1448pub fn fd_event<M: MemorySize>(
1451 ctx: FunctionEnvMut<'_, WasiEnv>,
1452 initial_val: u64,
1453 flags: EventFdFlags,
1454 ret_fd: WasmPtr<WasiFd, M>,
1455) -> Errno {
1456 debug!("wasi::fd_event");
1457
1458 let env = ctx.data();
1459 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
1460
1461 let kind = Kind::EventNotifications {
1462 counter: Arc::new(AtomicU64::new(initial_val)),
1463 is_semaphore: flags & EVENT_FD_FLAGS_SEMAPHORE != 0,
1464 wakers: Default::default(),
1465 };
1466
1467 let inode = state.fs.create_inode_with_default_stat(
1468 inodes.deref_mut(),
1469 kind,
1470 false,
1471 "event".to_string(),
1472 );
1473 let rights = Rights::FD_READ | Rights::FD_WRITE | Rights::POLL_FD_READWRITE;
1474 let fd = wasi_try!(state
1475 .fs
1476 .create_fd(rights, rights, Fdflags::empty(), 0, inode));
1477
1478 wasi_try_mem!(ret_fd.write(&memory, fd));
1479
1480 Errno::Success
1481}
1482
1483pub fn fd_seek<M: MemorySize>(
1496 ctx: FunctionEnvMut<'_, WasiEnv>,
1497 fd: WasiFd,
1498 offset: FileDelta,
1499 whence: Whence,
1500 newoffset: WasmPtr<Filesize, M>,
1501) -> Result<Errno, WasiError> {
1502 trace!("wasi::fd_seek: fd={}, offset={}", fd, offset);
1503 let env = ctx.data();
1504 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
1505 let new_offset_ref = newoffset.deref(&memory);
1506 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
1507
1508 if !fd_entry.rights.contains(Rights::FD_SEEK) {
1509 return Ok(Errno::Access);
1510 }
1511
1512 match whence {
1514 Whence::Cur => {
1515 let mut fd_map = state.fs.fd_map.write().unwrap();
1516 let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
1517 fd_entry.offset = (fd_entry.offset as i64 + offset) as u64
1518 }
1519 Whence::End => {
1520 use std::io::SeekFrom;
1521 let inode_idx = fd_entry.inode;
1522 let mut guard = inodes.arena[inode_idx].write();
1523 let deref_mut = guard.deref_mut();
1524 match deref_mut {
1525 Kind::File { ref mut handle, .. } => {
1526 if let Some(handle) = handle {
1527 let end =
1528 wasi_try_ok!(handle.seek(SeekFrom::End(0)).map_err(map_io_err), env);
1529
1530 drop(guard);
1532 let mut fd_map = state.fs.fd_map.write().unwrap();
1533 let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
1534 fd_entry.offset = (end as i64 + offset) as u64;
1535 } else {
1536 return Ok(Errno::Inval);
1537 }
1538 }
1539 Kind::Symlink { .. } => {
1540 unimplemented!("wasi::fd_seek not implemented for symlinks")
1541 }
1542 Kind::Dir { .. }
1543 | Kind::Root { .. }
1544 | Kind::Socket { .. }
1545 | Kind::Pipe { .. }
1546 | Kind::EventNotifications { .. } => {
1547 return Ok(Errno::Inval);
1549 }
1550 Kind::Buffer { .. } => {
1551 return Ok(Errno::Inval);
1554 }
1555 }
1556 }
1557 Whence::Set => {
1558 let mut fd_map = state.fs.fd_map.write().unwrap();
1559 let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
1560 fd_entry.offset = offset as u64
1561 }
1562 _ => return Ok(Errno::Inval),
1563 }
1564 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
1566 wasi_try_mem_ok!(new_offset_ref.write(fd_entry.offset));
1567
1568 Ok(Errno::Success)
1569}
1570
1571pub fn fd_sync(ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Errno {
1581 debug!("wasi::fd_sync");
1582 debug!("=> fd={}", fd);
1583 let env = ctx.data();
1584 let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
1585 let fd_entry = wasi_try!(state.fs.get_fd(fd));
1586 if !fd_entry.rights.contains(Rights::FD_SYNC) {
1587 return Errno::Access;
1588 }
1589 let inode = fd_entry.inode;
1590
1591 {
1593 let mut guard = inodes.arena[inode].write();
1594 let deref_mut = guard.deref_mut();
1595 match deref_mut {
1596 Kind::File { handle, .. } => {
1597 if let Some(h) = handle {
1598 wasi_try!(h.sync_to_disk().map_err(fs_error_into_wasi_err));
1599 } else {
1600 return Errno::Inval;
1601 }
1602 }
1603 Kind::Root { .. } | Kind::Dir { .. } => return Errno::Isdir,
1604 Kind::Buffer { .. }
1605 | Kind::Symlink { .. }
1606 | Kind::Socket { .. }
1607 | Kind::Pipe { .. }
1608 | Kind::EventNotifications { .. } => return Errno::Inval,
1609 }
1610 }
1611
1612 Errno::Success
1613}
1614
1615pub fn fd_tell<M: MemorySize>(
1624 ctx: FunctionEnvMut<'_, WasiEnv>,
1625 fd: WasiFd,
1626 offset: WasmPtr<Filesize, M>,
1627) -> Errno {
1628 debug!("wasi::fd_tell");
1629 let env = ctx.data();
1630 let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
1631 let offset_ref = offset.deref(&memory);
1632
1633 let fd_entry = wasi_try!(state.fs.get_fd(fd));
1634
1635 if !fd_entry.rights.contains(Rights::FD_TELL) {
1636 return Errno::Access;
1637 }
1638
1639 wasi_try_mem!(offset_ref.write(fd_entry.offset));
1640
1641 Errno::Success
1642}
1643
1644pub fn fd_write<M: MemorySize>(
1659 ctx: FunctionEnvMut<'_, WasiEnv>,
1660 fd: WasiFd,
1661 iovs: WasmPtr<__wasi_ciovec_t<M>, M>,
1662 iovs_len: M::Offset,
1663 nwritten: WasmPtr<M::Offset, M>,
1664) -> Result<Errno, WasiError> {
1665 trace!("wasi::fd_write: fd={}", fd);
1666 let env = ctx.data();
1667 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
1668 let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len));
1669 let nwritten_ref = nwritten.deref(&memory);
1670
1671 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
1672 let bytes_written = match fd {
1673 __WASI_STDIN_FILENO => return Ok(Errno::Inval),
1674 __WASI_STDOUT_FILENO => {
1675 let mut guard = wasi_try_ok!(
1676 inodes
1677 .stdout_mut(&state.fs.fd_map)
1678 .map_err(fs_error_into_wasi_err),
1679 env
1680 );
1681 if let Some(ref mut stdout) = guard.deref_mut() {
1682 wasi_try_ok!(write_bytes(stdout, &memory, iovs_arr), env)
1683 } else {
1684 return Ok(Errno::Badf);
1685 }
1686 }
1687 __WASI_STDERR_FILENO => {
1688 let mut guard = wasi_try_ok!(
1689 inodes
1690 .stderr_mut(&state.fs.fd_map)
1691 .map_err(fs_error_into_wasi_err),
1692 env
1693 );
1694 if let Some(ref mut stderr) = guard.deref_mut() {
1695 wasi_try_ok!(write_bytes(stderr, &memory, iovs_arr), env)
1696 } else {
1697 return Ok(Errno::Badf);
1698 }
1699 }
1700 _ => {
1701 if !fd_entry.rights.contains(Rights::FD_WRITE) {
1702 return Ok(Errno::Access);
1703 }
1704
1705 let offset = fd_entry.offset as usize;
1706 let inode_idx = fd_entry.inode;
1707 let inode = &inodes.arena[inode_idx];
1708
1709 let bytes_written = {
1710 let mut guard = inode.write();
1711 let deref_mut = guard.deref_mut();
1712 match deref_mut {
1713 Kind::File { handle, .. } => {
1714 if let Some(handle) = handle {
1715 wasi_try_ok!(
1716 handle
1717 .seek(std::io::SeekFrom::Start(offset as u64))
1718 .map_err(map_io_err),
1719 env
1720 );
1721 wasi_try_ok!(write_bytes(handle, &memory, iovs_arr), env)
1722 } else {
1723 return Ok(Errno::Inval);
1724 }
1725 }
1726 Kind::Socket { socket } => {
1727 wasi_try_ok!(socket.send(&memory, iovs_arr), env)
1728 }
1729 Kind::Pipe { pipe } => {
1730 wasi_try_ok!(pipe.send(&memory, iovs_arr), env)
1731 }
1732 Kind::Dir { .. } | Kind::Root { .. } => {
1733 return Ok(Errno::Isdir);
1735 }
1736 Kind::EventNotifications {
1737 counter, wakers, ..
1738 } => {
1739 let mut val = 0u64.to_ne_bytes();
1740 let written = wasi_try_ok!(write_bytes(&mut val[..], &memory, iovs_arr));
1741 if written != val.len() {
1742 return Ok(Errno::Inval);
1743 }
1744 let val = u64::from_ne_bytes(val);
1745
1746 counter.fetch_add(val, Ordering::AcqRel);
1747 {
1748 let mut guard = wakers.lock().unwrap();
1749 while let Some(wake) = guard.pop_back() {
1750 if wake.send(()).is_ok() {
1751 break;
1752 }
1753 }
1754 }
1755
1756 written
1757 }
1758 Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"),
1759 Kind::Buffer { buffer } => {
1760 wasi_try_ok!(write_bytes(&mut buffer[offset..], &memory, iovs_arr), env)
1761 }
1762 }
1763 };
1764
1765 {
1767 let mut fd_map = state.fs.fd_map.write().unwrap();
1768 let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
1769 fd_entry.offset += bytes_written as u64;
1770 }
1771 wasi_try_ok!(state.fs.filestat_resync_size(inodes.deref(), fd), env);
1772
1773 bytes_written
1774 }
1775 };
1776
1777 let bytes_written: M::Offset =
1778 wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
1779 wasi_try_mem_ok!(nwritten_ref.write(bytes_written));
1780
1781 Ok(Errno::Success)
1782}
1783
1784pub fn fd_pipe<M: MemorySize>(
1792 ctx: FunctionEnvMut<'_, WasiEnv>,
1793 ro_fd1: WasmPtr<WasiFd, M>,
1794 ro_fd2: WasmPtr<WasiFd, M>,
1795) -> Errno {
1796 trace!("wasi::fd_pipe");
1797
1798 let env = ctx.data();
1799 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
1800
1801 let (pipe1, pipe2) = WasiPipe::new();
1802
1803 let inode1 = state.fs.create_inode_with_default_stat(
1804 inodes.deref_mut(),
1805 Kind::Pipe { pipe: pipe1 },
1806 false,
1807 "pipe".to_string(),
1808 );
1809 let inode2 = state.fs.create_inode_with_default_stat(
1810 inodes.deref_mut(),
1811 Kind::Pipe { pipe: pipe2 },
1812 false,
1813 "pipe".to_string(),
1814 );
1815
1816 let rights = Rights::all_socket();
1817 let fd1 = wasi_try!(state
1818 .fs
1819 .create_fd(rights, rights, Fdflags::empty(), 0, inode1));
1820 let fd2 = wasi_try!(state
1821 .fs
1822 .create_fd(rights, rights, Fdflags::empty(), 0, inode2));
1823
1824 wasi_try_mem!(ro_fd1.write(&memory, fd1));
1825 wasi_try_mem!(ro_fd2.write(&memory, fd2));
1826
1827 Errno::Success
1828}
1829
1830pub fn path_create_directory<M: MemorySize>(
1844 ctx: FunctionEnvMut<'_, WasiEnv>,
1845 fd: WasiFd,
1846 path: WasmPtr<u8, M>,
1847 path_len: M::Offset,
1848) -> Errno {
1849 debug!("wasi::path_create_directory");
1850 let env = ctx.data();
1851 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
1852
1853 let working_dir = wasi_try!(state.fs.get_fd(fd));
1854 {
1855 let guard = inodes.arena[working_dir.inode].read();
1856 if let Kind::Root { .. } = guard.deref() {
1857 return Errno::Access;
1858 }
1859 }
1860 if !working_dir.rights.contains(Rights::PATH_CREATE_DIRECTORY) {
1861 return Errno::Access;
1862 }
1863 let path_string = unsafe { get_input_str!(&memory, path, path_len) };
1864 debug!("=> fd: {}, path: {}", fd, &path_string);
1865
1866 let path = std::path::PathBuf::from(&path_string);
1867 let path_vec = wasi_try!(path
1868 .components()
1869 .map(|comp| {
1870 comp.as_os_str()
1871 .to_str()
1872 .map(|inner_str| inner_str.to_string())
1873 .ok_or(Errno::Inval)
1874 })
1875 .collect::<Result<Vec<String>, Errno>>());
1876 if path_vec.is_empty() {
1877 return Errno::Inval;
1878 }
1879
1880 debug!("Looking at components {:?}", &path_vec);
1881
1882 let mut cur_dir_inode = working_dir.inode;
1883 for comp in &path_vec {
1884 debug!("Creating dir {}", comp);
1885 let mut guard = inodes.arena[cur_dir_inode].write();
1886 let deref_mut = guard.deref_mut();
1887 match deref_mut {
1888 Kind::Dir {
1889 ref mut entries,
1890 path,
1891 parent,
1892 } => {
1893 match comp.borrow() {
1894 ".." => {
1895 if let Some(p) = parent {
1896 cur_dir_inode = *p;
1897 continue;
1898 }
1899 }
1900 "." => continue,
1901 _ => (),
1902 }
1903 if let Some(child) = entries.get(comp) {
1904 cur_dir_inode = *child;
1905 } else {
1906 let mut adjusted_path = path.clone();
1907 drop(guard);
1908
1909 adjusted_path.push(comp);
1911 if let Ok(adjusted_path_stat) = path_filestat_get_internal(
1912 &memory,
1913 state,
1914 inodes.deref_mut(),
1915 fd,
1916 0,
1917 &adjusted_path.to_string_lossy(),
1918 ) {
1919 if adjusted_path_stat.st_filetype != Filetype::Directory {
1920 return Errno::Notdir;
1921 }
1922 } else {
1923 wasi_try!(state.fs_create_dir(&adjusted_path));
1924 }
1925 let kind = Kind::Dir {
1926 parent: Some(cur_dir_inode),
1927 path: adjusted_path,
1928 entries: Default::default(),
1929 };
1930 let new_inode = wasi_try!(state.fs.create_inode(
1931 inodes.deref_mut(),
1932 kind,
1933 false,
1934 comp.to_string()
1935 ));
1936
1937 {
1939 let mut guard = inodes.arena[cur_dir_inode].write();
1940 if let Kind::Dir {
1941 ref mut entries, ..
1942 } = guard.deref_mut()
1943 {
1944 entries.insert(comp.to_string(), new_inode);
1945 }
1946 }
1947 cur_dir_inode = new_inode;
1948 }
1949 }
1950 Kind::Root { .. } => return Errno::Access,
1951 _ => return Errno::Notdir,
1952 }
1953 }
1954
1955 Errno::Success
1956}
1957
1958pub fn path_filestat_get<M: MemorySize>(
1973 ctx: FunctionEnvMut<'_, WasiEnv>,
1974 fd: WasiFd,
1975 flags: LookupFlags,
1976 path: WasmPtr<u8, M>,
1977 path_len: M::Offset,
1978 buf: WasmPtr<Filestat, M>,
1979) -> Errno {
1980 debug!("wasi::path_filestat_get (fd={})", fd);
1981 let env = ctx.data();
1982 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
1983
1984 let path_string = unsafe { get_input_str!(&memory, path, path_len) };
1985
1986 let stat = wasi_try!(path_filestat_get_internal(
1987 &memory,
1988 state,
1989 inodes.deref_mut(),
1990 fd,
1991 flags,
1992 &path_string
1993 ));
1994
1995 wasi_try_mem!(buf.deref(&memory).write(stat));
1996
1997 Errno::Success
1998}
1999
2000pub fn path_filestat_get_internal(
2015 memory: &MemoryView,
2016 state: &WasiState,
2017 inodes: &mut crate::WasiInodes,
2018 fd: WasiFd,
2019 flags: LookupFlags,
2020 path_string: &str,
2021) -> Result<Filestat, Errno> {
2022 let root_dir = state.fs.get_fd(fd)?;
2023
2024 if !root_dir.rights.contains(Rights::PATH_FILESTAT_GET) {
2025 return Err(Errno::Access);
2026 }
2027 debug!("=> base_fd: {}, path: {}", fd, path_string);
2028
2029 let file_inode = state.fs.get_inode_at_path(
2030 inodes,
2031 fd,
2032 path_string,
2033 flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
2034 )?;
2035 if inodes.arena[file_inode].is_preopened {
2036 Ok(*inodes.arena[file_inode].stat.read().unwrap().deref())
2037 } else {
2038 let guard = inodes.arena[file_inode].read();
2039 state.fs.get_stat_for_kind(inodes.deref(), guard.deref())
2040 }
2041}
2042
2043pub fn path_filestat_set_times<M: MemorySize>(
2061 ctx: FunctionEnvMut<'_, WasiEnv>,
2062 fd: WasiFd,
2063 flags: LookupFlags,
2064 path: WasmPtr<u8, M>,
2065 path_len: M::Offset,
2066 st_atim: Timestamp,
2067 st_mtim: Timestamp,
2068 fst_flags: Fstflags,
2069) -> Errno {
2070 debug!("wasi::path_filestat_set_times");
2071 let env = ctx.data();
2072 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2073 let fd_entry = wasi_try!(state.fs.get_fd(fd));
2074 let fd_inode = fd_entry.inode;
2075 if !fd_entry.rights.contains(Rights::PATH_FILESTAT_SET_TIMES) {
2076 return Errno::Access;
2077 }
2078 if (fst_flags.contains(Fstflags::SET_ATIM) && fst_flags.contains(Fstflags::SET_ATIM_NOW))
2079 || (fst_flags.contains(Fstflags::SET_MTIM) && fst_flags.contains(Fstflags::SET_MTIM_NOW))
2080 {
2081 return Errno::Inval;
2082 }
2083
2084 let path_string = unsafe { get_input_str!(&memory, path, path_len) };
2085 debug!("=> base_fd: {}, path: {}", fd, &path_string);
2086
2087 let file_inode = wasi_try!(state.fs.get_inode_at_path(
2088 inodes.deref_mut(),
2089 fd,
2090 &path_string,
2091 flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
2092 ));
2093 let stat = {
2094 let guard = inodes.arena[file_inode].read();
2095 wasi_try!(state.fs.get_stat_for_kind(inodes.deref(), guard.deref()))
2096 };
2097
2098 let inode = &inodes.arena[fd_inode];
2099
2100 if fst_flags.contains(Fstflags::SET_ATIM) || fst_flags.contains(Fstflags::SET_ATIM_NOW) {
2101 let time_to_set = if fst_flags.contains(Fstflags::SET_ATIM) {
2102 st_atim
2103 } else {
2104 wasi_try!(get_current_time_in_nanos())
2105 };
2106 inode.stat.write().unwrap().st_atim = time_to_set;
2107 }
2108 if fst_flags.contains(Fstflags::SET_MTIM) || fst_flags.contains(Fstflags::SET_MTIM_NOW) {
2109 let time_to_set = if fst_flags.contains(Fstflags::SET_MTIM) {
2110 st_mtim
2111 } else {
2112 wasi_try!(get_current_time_in_nanos())
2113 };
2114 inode.stat.write().unwrap().st_mtim = time_to_set;
2115 }
2116
2117 Errno::Success
2118}
2119
2120pub fn path_link<M: MemorySize>(
2138 ctx: FunctionEnvMut<'_, WasiEnv>,
2139 old_fd: WasiFd,
2140 old_flags: LookupFlags,
2141 old_path: WasmPtr<u8, M>,
2142 old_path_len: M::Offset,
2143 new_fd: WasiFd,
2144 new_path: WasmPtr<u8, M>,
2145 new_path_len: M::Offset,
2146) -> Errno {
2147 debug!("wasi::path_link");
2148 if old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 {
2149 debug!(" - will follow symlinks when opening path");
2150 }
2151 let env = ctx.data();
2152 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2153 let old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) };
2154 let new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) };
2155 let source_fd = wasi_try!(state.fs.get_fd(old_fd));
2156 let target_fd = wasi_try!(state.fs.get_fd(new_fd));
2157 debug!(
2158 "=> source_fd: {}, source_path: {}, target_fd: {}, target_path: {}",
2159 old_fd, &old_path_str, new_fd, new_path_str
2160 );
2161
2162 if !source_fd.rights.contains(Rights::PATH_LINK_SOURCE)
2163 || !target_fd.rights.contains(Rights::PATH_LINK_TARGET)
2164 {
2165 return Errno::Access;
2166 }
2167
2168 let source_inode = wasi_try!(state.fs.get_inode_at_path(
2169 inodes.deref_mut(),
2170 old_fd,
2171 &old_path_str,
2172 old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
2173 ));
2174 let target_path_arg = std::path::PathBuf::from(&new_path_str);
2175 let (target_parent_inode, new_entry_name) = wasi_try!(state.fs.get_parent_inode_at_path(
2176 inodes.deref_mut(),
2177 new_fd,
2178 &target_path_arg,
2179 false
2180 ));
2181
2182 if inodes.arena[source_inode].stat.write().unwrap().st_nlink == Linkcount::max_value() {
2183 return Errno::Mlink;
2184 }
2185 {
2186 let mut guard = inodes.arena[target_parent_inode].write();
2187 let deref_mut = guard.deref_mut();
2188 match deref_mut {
2189 Kind::Dir { entries, .. } => {
2190 if entries.contains_key(&new_entry_name) {
2191 return Errno::Exist;
2192 }
2193 entries.insert(new_entry_name, source_inode);
2194 }
2195 Kind::Root { .. } => return Errno::Inval,
2196 Kind::File { .. }
2197 | Kind::Symlink { .. }
2198 | Kind::Buffer { .. }
2199 | Kind::Socket { .. }
2200 | Kind::Pipe { .. }
2201 | Kind::EventNotifications { .. } => return Errno::Notdir,
2202 }
2203 }
2204 inodes.arena[source_inode].stat.write().unwrap().st_nlink += 1;
2205
2206 Errno::Success
2207}
2208
2209pub fn path_open<M: MemorySize>(
2234 ctx: FunctionEnvMut<'_, WasiEnv>,
2235 dirfd: WasiFd,
2236 dirflags: LookupFlags,
2237 path: WasmPtr<u8, M>,
2238 path_len: M::Offset,
2239 o_flags: Oflags,
2240 fs_rights_base: Rights,
2241 fs_rights_inheriting: Rights,
2242 fs_flags: Fdflags,
2243 fd: WasmPtr<WasiFd, M>,
2244) -> Errno {
2245 debug!("wasi::path_open");
2246 if dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 {
2247 debug!(" - will follow symlinks when opening path");
2248 }
2249 let env = ctx.data();
2250 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2251 let path_len64: u64 = path_len.into();
2253 if path_len64 > 1024u64 * 1024u64 {
2254 return Errno::Nametoolong;
2255 }
2256
2257 let fd_ref = fd.deref(&memory);
2258
2259 let working_dir = wasi_try!(state.fs.get_fd(dirfd));
2266 let working_dir_rights_inheriting = working_dir.rights_inheriting;
2267
2268 if !working_dir.rights.contains(Rights::PATH_OPEN) {
2270 return Errno::Access;
2271 }
2272
2273 let path_string = unsafe { get_input_str!(&memory, path, path_len) };
2274
2275 debug!("=> path_open(): fd: {}, path: {}", dirfd, &path_string);
2276
2277 let path_arg = std::path::PathBuf::from(&path_string);
2278 let maybe_inode = state.fs.get_inode_at_path(
2279 inodes.deref_mut(),
2280 dirfd,
2281 &path_string,
2282 dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
2283 );
2284
2285 let mut open_flags = 0;
2286 let adjusted_rights = working_dir_rights_inheriting;
2293 let mut open_options = state.fs_new_open_options();
2294
2295 let target_rights = match maybe_inode {
2296 Ok(_) => {
2297 let write_permission = adjusted_rights.contains(Rights::FD_WRITE);
2298
2299 let (append_permission, truncate_permission, create_permission) = if write_permission {
2301 (
2302 fs_flags.contains(Fdflags::APPEND),
2303 o_flags.contains(Oflags::TRUNC),
2304 o_flags.contains(Oflags::CREATE),
2305 )
2306 } else {
2307 (false, false, false)
2308 };
2309
2310 wasmer_vfs::OpenOptionsConfig {
2311 read: fs_rights_base.contains(Rights::FD_READ),
2312 write: write_permission,
2313 create_new: create_permission && o_flags.contains(Oflags::EXCL),
2314 create: create_permission,
2315 append: append_permission,
2316 truncate: truncate_permission,
2317 }
2318 }
2319 Err(_) => wasmer_vfs::OpenOptionsConfig {
2320 append: fs_flags.contains(Fdflags::APPEND),
2321 write: fs_rights_base.contains(Rights::FD_WRITE),
2322 read: fs_rights_base.contains(Rights::FD_READ),
2323 create_new: o_flags.contains(Oflags::CREATE) && o_flags.contains(Oflags::EXCL),
2324 create: o_flags.contains(Oflags::CREATE),
2325 truncate: o_flags.contains(Oflags::TRUNC),
2326 },
2327 };
2328
2329 let parent_rights = wasmer_vfs::OpenOptionsConfig {
2330 read: working_dir.rights.contains(Rights::FD_READ),
2331 write: working_dir.rights.contains(Rights::FD_WRITE),
2332 create_new: true,
2335 create: true,
2336 append: true,
2337 truncate: true,
2338 };
2339
2340 let minimum_rights = target_rights.minimum_rights(&parent_rights);
2341
2342 open_options.options(minimum_rights.clone());
2343
2344 let inode = if let Ok(inode) = maybe_inode {
2345 let mut guard = inodes.arena[inode].write();
2347 let deref_mut = guard.deref_mut();
2348 match deref_mut {
2349 Kind::File {
2350 ref mut handle,
2351 path,
2352 fd,
2353 } => {
2354 if let Some(special_fd) = fd {
2355 assert!(handle.is_some());
2357 wasi_try_mem!(fd_ref.write(*special_fd));
2358 return Errno::Success;
2359 }
2360 if o_flags.contains(Oflags::DIRECTORY) {
2361 return Errno::Notdir;
2362 }
2363 if o_flags.contains(Oflags::EXCL) {
2364 return Errno::Exist;
2365 }
2366
2367 let open_options = open_options
2368 .write(minimum_rights.write)
2369 .create(minimum_rights.create)
2370 .append(minimum_rights.append)
2371 .truncate(minimum_rights.truncate);
2372
2373 if minimum_rights.read {
2374 open_flags |= Fd::READ;
2375 }
2376 if minimum_rights.write {
2377 open_flags |= Fd::WRITE;
2378 }
2379 if minimum_rights.create {
2380 open_flags |= Fd::CREATE;
2381 }
2382 if minimum_rights.truncate {
2383 open_flags |= Fd::TRUNCATE;
2384 }
2385
2386 *handle = Some(wasi_try!(open_options
2387 .open(&path)
2388 .map_err(fs_error_into_wasi_err)));
2389 }
2390 Kind::Buffer { .. } => unimplemented!("wasi::path_open for Buffer type files"),
2391 Kind::Root { .. } => {
2392 if !o_flags.contains(Oflags::DIRECTORY) {
2393 return Errno::Notcapable;
2394 }
2395 }
2396 Kind::Dir { .. }
2397 | Kind::Socket { .. }
2398 | Kind::Pipe { .. }
2399 | Kind::EventNotifications { .. } => {}
2400 Kind::Symlink {
2401 base_po_dir,
2402 path_to_symlink,
2403 relative_path,
2404 } => {
2405 unimplemented!("SYMLINKS IN PATH_OPEN");
2408 }
2409 }
2410 inode
2411 } else {
2412 debug!("Maybe creating file");
2414 if o_flags.contains(Oflags::CREATE) {
2415 if o_flags.contains(Oflags::DIRECTORY) {
2416 return Errno::Notdir;
2417 }
2418 debug!("Creating file");
2419 let (parent_inode, new_entity_name) = wasi_try!(state.fs.get_parent_inode_at_path(
2422 inodes.deref_mut(),
2423 dirfd,
2424 &path_arg,
2425 dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0
2426 ));
2427 let new_file_host_path = {
2428 let guard = inodes.arena[parent_inode].read();
2429 let deref = guard.deref();
2430 match deref {
2431 Kind::Dir { path, .. } => {
2432 let mut new_path = path.clone();
2433 new_path.push(&new_entity_name);
2434 new_path
2435 }
2436 Kind::Root { .. } => {
2437 let mut new_path = std::path::PathBuf::new();
2438 new_path.push(&new_entity_name);
2439 new_path
2440 }
2441 _ => return Errno::Inval,
2442 }
2443 };
2444 let handle = {
2447 let open_options = open_options
2448 .read(minimum_rights.read)
2449 .append(minimum_rights.append)
2450 .write(minimum_rights.write)
2451 .create_new(minimum_rights.create_new);
2452
2453 if minimum_rights.read {
2454 open_flags |= Fd::READ;
2455 }
2456 if minimum_rights.write {
2457 open_flags |= Fd::WRITE;
2458 }
2459 if minimum_rights.create_new {
2460 open_flags |= Fd::CREATE;
2461 }
2462 if minimum_rights.truncate {
2463 open_flags |= Fd::TRUNCATE;
2464 }
2465
2466 Some(wasi_try!(open_options.open(&new_file_host_path).map_err(
2467 |e| {
2468 debug!("Error opening file {}", e);
2469 fs_error_into_wasi_err(e)
2470 }
2471 )))
2472 };
2473
2474 let new_inode = {
2475 let kind = Kind::File {
2476 handle,
2477 path: new_file_host_path,
2478 fd: None,
2479 };
2480 wasi_try!(state.fs.create_inode(
2481 inodes.deref_mut(),
2482 kind,
2483 false,
2484 new_entity_name.clone()
2485 ))
2486 };
2487
2488 {
2489 let mut guard = inodes.arena[parent_inode].write();
2490 if let Kind::Dir {
2491 ref mut entries, ..
2492 } = guard.deref_mut()
2493 {
2494 entries.insert(new_entity_name, new_inode);
2495 }
2496 }
2497
2498 new_inode
2499 } else {
2500 return maybe_inode.unwrap_err();
2501 }
2502 };
2503
2504 {
2505 debug!("inode {:?} value {:#?} found!", inode, inodes.arena[inode]);
2506 }
2507
2508 let out_fd = wasi_try!(state.fs.create_fd(
2511 adjusted_rights,
2512 fs_rights_inheriting,
2513 fs_flags,
2514 open_flags,
2515 inode
2516 ));
2517
2518 wasi_try_mem!(fd_ref.write(out_fd));
2519 debug!("wasi::path_open returning fd {}", out_fd);
2520
2521 Errno::Success
2522}
2523
2524pub fn path_readlink<M: MemorySize>(
2541 ctx: FunctionEnvMut<'_, WasiEnv>,
2542 dir_fd: WasiFd,
2543 path: WasmPtr<u8, M>,
2544 path_len: M::Offset,
2545 buf: WasmPtr<u8, M>,
2546 buf_len: M::Offset,
2547 buf_used: WasmPtr<M::Offset, M>,
2548) -> Errno {
2549 debug!("wasi::path_readlink");
2550 let env = ctx.data();
2551 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2552
2553 let base_dir = wasi_try!(state.fs.get_fd(dir_fd));
2554 if !base_dir.rights.contains(Rights::PATH_READLINK) {
2555 return Errno::Access;
2556 }
2557 let path_str = unsafe { get_input_str!(&memory, path, path_len) };
2558 let inode = wasi_try!(state
2559 .fs
2560 .get_inode_at_path(inodes.deref_mut(), dir_fd, &path_str, false));
2561
2562 {
2563 let guard = inodes.arena[inode].read();
2564 if let Kind::Symlink { relative_path, .. } = guard.deref() {
2565 let rel_path_str = relative_path.to_string_lossy();
2566 debug!("Result => {:?}", rel_path_str);
2567 let buf_len: u64 = buf_len.into();
2568 let bytes = rel_path_str.bytes();
2569 if bytes.len() as u64 >= buf_len {
2570 return Errno::Overflow;
2571 }
2572 let bytes: Vec<_> = bytes.collect();
2573
2574 let out = wasi_try_mem!(buf.slice(&memory, wasi_try!(to_offset::<M>(bytes.len()))));
2575 wasi_try_mem!(out.write_slice(&bytes));
2576 let bytes_len: M::Offset =
2579 wasi_try!(bytes.len().try_into().map_err(|_| Errno::Overflow));
2580 wasi_try_mem!(buf_used.deref(&memory).write(bytes_len));
2581 } else {
2582 return Errno::Inval;
2583 }
2584 }
2585
2586 Errno::Success
2587}
2588
2589pub fn path_remove_directory<M: MemorySize>(
2591 ctx: FunctionEnvMut<'_, WasiEnv>,
2592 fd: WasiFd,
2593 path: WasmPtr<u8, M>,
2594 path_len: M::Offset,
2595) -> Errno {
2596 debug!("wasi::path_remove_directory");
2598 let env = ctx.data();
2599 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2600
2601 let base_dir = wasi_try!(state.fs.get_fd(fd));
2602 let path_str = unsafe { get_input_str!(&memory, path, path_len) };
2603
2604 let inode = wasi_try!(state
2605 .fs
2606 .get_inode_at_path(inodes.deref_mut(), fd, &path_str, false));
2607 let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path(
2608 inodes.deref_mut(),
2609 fd,
2610 std::path::Path::new(&path_str),
2611 false
2612 ));
2613
2614 let host_path_to_remove = {
2615 let guard = inodes.arena[inode].read();
2616 let deref = guard.deref();
2617 match deref {
2618 Kind::Dir { entries, path, .. } => {
2619 if !entries.is_empty() || wasi_try!(state.fs_read_dir(path)).count() != 0 {
2620 return Errno::Notempty;
2621 }
2622 path.clone()
2623 }
2624 Kind::Root { .. } => return Errno::Access,
2625 _ => return Errno::Notdir,
2626 }
2627 };
2628
2629 {
2630 let mut guard = inodes.arena[parent_inode].write();
2631 let deref_mut = guard.deref_mut();
2632 match deref_mut {
2633 Kind::Dir {
2634 ref mut entries, ..
2635 } => {
2636 let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(Errno::Inval));
2637 assert!(inode == removed_inode);
2639 }
2640 Kind::Root { .. } => return Errno::Access,
2641 _ => unreachable!(
2642 "Internal logic error in wasi::path_remove_directory, parent is not a directory"
2643 ),
2644 }
2645 }
2646
2647 if let Err(err) = state.fs_remove_dir(host_path_to_remove) {
2648 let mut guard = inodes.arena[parent_inode].write();
2650 if let Kind::Dir {
2651 ref mut entries, ..
2652 } = guard.deref_mut()
2653 {
2654 entries.insert(childs_name, inode);
2655 }
2656 return err;
2657 }
2658
2659 Errno::Success
2660}
2661
2662pub fn path_rename<M: MemorySize>(
2678 ctx: FunctionEnvMut<'_, WasiEnv>,
2679 old_fd: WasiFd,
2680 old_path: WasmPtr<u8, M>,
2681 old_path_len: M::Offset,
2682 new_fd: WasiFd,
2683 new_path: WasmPtr<u8, M>,
2684 new_path_len: M::Offset,
2685) -> Errno {
2686 debug!(
2687 "wasi::path_rename: old_fd = {}, new_fd = {}",
2688 old_fd, new_fd
2689 );
2690 let env = ctx.data();
2691 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2692 let source_str = unsafe { get_input_str!(&memory, old_path, old_path_len) };
2693 let source_path = std::path::Path::new(&source_str);
2694 let target_str = unsafe { get_input_str!(&memory, new_path, new_path_len) };
2695 let target_path = std::path::Path::new(&target_str);
2696 debug!("=> rename from {} to {}", &source_str, &target_str);
2697
2698 {
2699 let source_fd = wasi_try!(state.fs.get_fd(old_fd));
2700 if !source_fd.rights.contains(Rights::PATH_RENAME_SOURCE) {
2701 return Errno::Access;
2702 }
2703 let target_fd = wasi_try!(state.fs.get_fd(new_fd));
2704 if !target_fd.rights.contains(Rights::PATH_RENAME_TARGET) {
2705 return Errno::Access;
2706 }
2707 }
2708
2709 wasi_try!(state.fs.get_inode_at_path(
2711 inodes.deref_mut(),
2712 old_fd,
2713 source_path.to_str().as_ref().unwrap(),
2714 true
2715 ));
2716 let _ = state.fs.get_inode_at_path(
2718 inodes.deref_mut(),
2719 new_fd,
2720 target_path.to_str().as_ref().unwrap(),
2721 true,
2722 );
2723 let (source_parent_inode, source_entry_name) =
2724 wasi_try!(state
2725 .fs
2726 .get_parent_inode_at_path(inodes.deref_mut(), old_fd, source_path, true));
2727 let (target_parent_inode, target_entry_name) =
2728 wasi_try!(state
2729 .fs
2730 .get_parent_inode_at_path(inodes.deref_mut(), new_fd, target_path, true));
2731 let mut need_create = true;
2732 let host_adjusted_target_path = {
2733 let guard = inodes.arena[target_parent_inode].read();
2734 let deref = guard.deref();
2735 match deref {
2736 Kind::Dir { entries, path, .. } => {
2737 if entries.contains_key(&target_entry_name) {
2738 need_create = false;
2739 }
2740 let mut out_path = path.clone();
2741 out_path.push(std::path::Path::new(&target_entry_name));
2742 out_path
2743 }
2744 Kind::Root { .. } => return Errno::Notcapable,
2745 Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => {
2746 return Errno::Inval
2747 }
2748 Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => {
2749 unreachable!("Fatal internal logic error: parent of inode is not a directory")
2750 }
2751 }
2752 };
2753
2754 let source_entry = {
2755 let mut guard = inodes.arena[source_parent_inode].write();
2756 let deref_mut = guard.deref_mut();
2757 match deref_mut {
2758 Kind::Dir { entries, .. } => {
2759 wasi_try!(entries.remove(&source_entry_name).ok_or(Errno::Noent))
2760 }
2761 Kind::Root { .. } => return Errno::Notcapable,
2762 Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => {
2763 return Errno::Inval
2764 }
2765 Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => {
2766 unreachable!("Fatal internal logic error: parent of inode is not a directory")
2767 }
2768 }
2769 };
2770
2771 {
2772 let mut guard = inodes.arena[source_entry].write();
2773 let deref_mut = guard.deref_mut();
2774 match deref_mut {
2775 Kind::File {
2776 handle, ref path, ..
2777 } => {
2778 let result = if let Some(h) = handle {
2784 drop(guard);
2785 state.fs_rename(&source_path, &host_adjusted_target_path)
2786 } else {
2787 let path_clone = path.clone();
2788 drop(guard);
2789 let out = state.fs_rename(&path_clone, &host_adjusted_target_path);
2790 {
2791 let mut guard = inodes.arena[source_entry].write();
2792 if let Kind::File { ref mut path, .. } = guard.deref_mut() {
2793 *path = host_adjusted_target_path;
2794 } else {
2795 unreachable!()
2796 }
2797 }
2798 out
2799 };
2800 if let Err(e) = result {
2802 let mut guard = inodes.arena[source_parent_inode].write();
2803 if let Kind::Dir { entries, .. } = guard.deref_mut() {
2804 entries.insert(source_entry_name, source_entry);
2805 return e;
2806 }
2807 }
2808 }
2809 Kind::Dir { ref path, .. } => {
2810 let cloned_path = path.clone();
2811 if let Err(e) = state.fs_rename(cloned_path, &host_adjusted_target_path) {
2812 return e;
2813 }
2814 {
2815 drop(guard);
2816 let mut guard = inodes.arena[source_entry].write();
2817 if let Kind::Dir { path, .. } = guard.deref_mut() {
2818 *path = host_adjusted_target_path;
2819 }
2820 }
2821 }
2822 Kind::Buffer { .. } => {}
2823 Kind::Symlink { .. } => {}
2824 Kind::Socket { .. } => {}
2825 Kind::Pipe { .. } => {}
2826 Kind::EventNotifications { .. } => {}
2827 Kind::Root { .. } => unreachable!("The root can not be moved"),
2828 }
2829 }
2830
2831 if need_create {
2832 let mut guard = inodes.arena[target_parent_inode].write();
2833 if let Kind::Dir { entries, .. } = guard.deref_mut() {
2834 let result = entries.insert(target_entry_name, source_entry);
2835 assert!(
2836 result.is_none(),
2837 "Fatal error: race condition on filesystem detected or internal logic error"
2838 );
2839 }
2840 }
2841
2842 Errno::Success
2843}
2844
2845pub fn path_symlink<M: MemorySize>(
2859 ctx: FunctionEnvMut<'_, WasiEnv>,
2860 old_path: WasmPtr<u8, M>,
2861 old_path_len: M::Offset,
2862 fd: WasiFd,
2863 new_path: WasmPtr<u8, M>,
2864 new_path_len: M::Offset,
2865) -> Errno {
2866 debug!("wasi::path_symlink");
2867 let env = ctx.data();
2868 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2869 let old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) };
2870 let new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) };
2871 let base_fd = wasi_try!(state.fs.get_fd(fd));
2872 if !base_fd.rights.contains(Rights::PATH_SYMLINK) {
2873 return Errno::Access;
2874 }
2875
2876 let old_path_path = std::path::Path::new(&old_path_str);
2878 let (source_inode, _) =
2879 wasi_try!(state
2880 .fs
2881 .get_parent_inode_at_path(inodes.deref_mut(), fd, old_path_path, true));
2882 let depth = state
2883 .fs
2884 .path_depth_from_fd(inodes.deref(), fd, source_inode);
2885
2886 let depth = match depth {
2888 Ok(depth) => depth as i32 - 1,
2889 Err(_) => -1,
2890 };
2891
2892 let new_path_path = std::path::Path::new(&new_path_str);
2893 let (target_parent_inode, entry_name) =
2894 wasi_try!(state
2895 .fs
2896 .get_parent_inode_at_path(inodes.deref_mut(), fd, new_path_path, true));
2897
2898 {
2900 let guard = inodes.arena[target_parent_inode].read();
2901 let deref = guard.deref();
2902 match deref {
2903 Kind::Dir { entries, .. } => {
2904 if entries.contains_key(&entry_name) {
2905 return Errno::Exist;
2906 }
2907 }
2908 Kind::Root { .. } => return Errno::Notcapable,
2909 Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => {
2910 return Errno::Inval
2911 }
2912 Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => {
2913 unreachable!("get_parent_inode_at_path returned something other than a Dir or Root")
2914 }
2915 }
2916 }
2917
2918 let mut source_path = std::path::Path::new(&old_path_str);
2919 let mut relative_path = std::path::PathBuf::new();
2920 for _ in 0..depth {
2921 relative_path.push("..");
2922 }
2923 relative_path.push(source_path);
2924 debug!(
2925 "Symlinking {} to {}",
2926 new_path_str,
2927 relative_path.to_string_lossy()
2928 );
2929
2930 let kind = Kind::Symlink {
2931 base_po_dir: fd,
2932 path_to_symlink: std::path::PathBuf::from(new_path_str),
2933 relative_path,
2934 };
2935 let new_inode = state.fs.create_inode_with_default_stat(
2936 inodes.deref_mut(),
2937 kind,
2938 false,
2939 entry_name.clone(),
2940 );
2941
2942 {
2943 let mut guard = inodes.arena[target_parent_inode].write();
2944 if let Kind::Dir {
2945 ref mut entries, ..
2946 } = guard.deref_mut()
2947 {
2948 entries.insert(entry_name, new_inode);
2949 }
2950 }
2951
2952 Errno::Success
2953}
2954
2955pub fn path_unlink_file<M: MemorySize>(
2965 ctx: FunctionEnvMut<'_, WasiEnv>,
2966 fd: WasiFd,
2967 path: WasmPtr<u8, M>,
2968 path_len: M::Offset,
2969) -> Errno {
2970 debug!("wasi::path_unlink_file");
2971 let env = ctx.data();
2972 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
2973
2974 let base_dir = wasi_try!(state.fs.get_fd(fd));
2975 if !base_dir.rights.contains(Rights::PATH_UNLINK_FILE) {
2976 return Errno::Access;
2977 }
2978 let path_str = unsafe { get_input_str!(&memory, path, path_len) };
2979 debug!("Requested file: {}", path_str);
2980
2981 let inode = wasi_try!(state
2982 .fs
2983 .get_inode_at_path(inodes.deref_mut(), fd, &path_str, false));
2984 let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path(
2985 inodes.deref_mut(),
2986 fd,
2987 std::path::Path::new(&path_str),
2988 false
2989 ));
2990
2991 let removed_inode = {
2992 let mut guard = inodes.arena[parent_inode].write();
2993 let deref_mut = guard.deref_mut();
2994 match deref_mut {
2995 Kind::Dir {
2996 ref mut entries, ..
2997 } => {
2998 let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(Errno::Inval));
2999 assert!(inode == removed_inode);
3001 debug_assert!(inodes.arena[inode].stat.read().unwrap().st_nlink > 0);
3002 removed_inode
3003 }
3004 Kind::Root { .. } => return Errno::Access,
3005 _ => unreachable!(
3006 "Internal logic error in wasi::path_unlink_file, parent is not a directory"
3007 ),
3008 }
3009 };
3010
3011 let st_nlink = {
3012 let mut guard = inodes.arena[removed_inode].stat.write().unwrap();
3013 guard.st_nlink -= 1;
3014 guard.st_nlink
3015 };
3016 if st_nlink == 0 {
3017 {
3018 let mut guard = inodes.arena[removed_inode].write();
3019 let deref_mut = guard.deref_mut();
3020 match deref_mut {
3021 Kind::File { handle, path, .. } => {
3022 if let Some(h) = handle {
3023 wasi_try!(h.unlink().map_err(fs_error_into_wasi_err));
3024 } else {
3025 let path = path.clone();
3029 wasi_try!(state.fs_remove_file(path));
3030 }
3031 }
3032 Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir,
3033 Kind::Symlink { .. } => {
3034 }
3036 _ => unimplemented!("wasi::path_unlink_file for Buffer"),
3037 }
3038 }
3039 let fd_is_orphaned = {
3042 let guard = inodes.arena[removed_inode].read();
3043 if let Kind::File { handle, .. } = guard.deref() {
3044 handle.is_some()
3045 } else {
3046 false
3047 }
3048 };
3049 let removed_inode_val = unsafe { state.fs.remove_inode(inodes.deref_mut(), removed_inode) };
3050 assert!(
3051 removed_inode_val.is_some(),
3052 "Inode could not be removed because it doesn't exist"
3053 );
3054
3055 if fd_is_orphaned {
3056 inodes
3057 .orphan_fds
3058 .insert(removed_inode, removed_inode_val.unwrap());
3059 }
3060 }
3061
3062 Errno::Success
3063}
3064
3065pub fn poll_oneoff<M: MemorySize>(
3078 ctx: FunctionEnvMut<'_, WasiEnv>,
3079 in_: WasmPtr<Subscription, M>,
3080 out_: WasmPtr<Event, M>,
3081 nsubscriptions: M::Offset,
3082 nevents: WasmPtr<M::Offset, M>,
3083) -> Result<Errno, WasiError> {
3084 trace!("wasi::poll_oneoff");
3085 trace!(" => nsubscriptions = {}", nsubscriptions);
3086 let env = ctx.data();
3087 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
3088
3089 let subscription_array = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions));
3090 let event_array = wasi_try_mem_ok!(out_.slice(&memory, nsubscriptions));
3091 let mut events_seen: u32 = 0;
3092 let out_ptr = nevents.deref(&memory);
3093
3094 let mut fd_guards = vec![];
3095 let mut clock_subs = vec![];
3096 let mut in_events = vec![];
3097 let mut time_to_sleep = Duration::from_millis(5);
3098
3099 for sub in subscription_array.iter() {
3100 let s: Subscription = wasi_try_mem_ok!(sub.read());
3101 let mut peb = PollEventBuilder::new();
3102
3103 let fd = match s.data {
3104 SubscriptionEnum::Read(SubscriptionFsReadwrite { file_descriptor }) => {
3105 match file_descriptor {
3106 __WASI_STDIN_FILENO | __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => (),
3107 _ => {
3108 let fd_entry = wasi_try_ok!(state.fs.get_fd(file_descriptor), env);
3109 if !fd_entry.rights.contains(Rights::FD_READ) {
3110 return Ok(Errno::Access);
3111 }
3112 }
3113 }
3114 in_events.push(peb.add(PollEvent::PollIn).build());
3115 Some(file_descriptor)
3116 }
3117 SubscriptionEnum::Write(SubscriptionFsReadwrite { file_descriptor }) => {
3118 match file_descriptor {
3119 __WASI_STDIN_FILENO | __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => (),
3120 _ => {
3121 let fd_entry = wasi_try_ok!(state.fs.get_fd(file_descriptor), env);
3122 if !fd_entry.rights.contains(Rights::FD_WRITE) {
3123 return Ok(Errno::Access);
3124 }
3125 }
3126 }
3127 in_events.push(peb.add(PollEvent::PollOut).build());
3128 Some(file_descriptor)
3129 }
3130 SubscriptionEnum::Clock(clock_info) => {
3131 if matches!(clock_info.clock_id, Clockid::Realtime | Clockid::Monotonic) {
3132 time_to_sleep = Duration::from_nanos(clock_info.timeout);
3135 clock_subs.push((clock_info, s.userdata));
3136 None
3137 } else {
3138 unimplemented!("Polling not implemented for clocks yet");
3139 }
3140 }
3141 };
3142
3143 if let Some(fd) = fd {
3144 let wasi_file_ref = match fd {
3145 __WASI_STDERR_FILENO => {
3146 wasi_try_ok!(
3147 inodes
3148 .stderr(&state.fs.fd_map)
3149 .map_err(fs_error_into_wasi_err),
3150 env
3151 )
3152 }
3153 __WASI_STDIN_FILENO => {
3154 wasi_try_ok!(
3155 inodes
3156 .stdin(&state.fs.fd_map)
3157 .map_err(fs_error_into_wasi_err),
3158 env
3159 )
3160 }
3161 __WASI_STDOUT_FILENO => {
3162 wasi_try_ok!(
3163 inodes
3164 .stdout(&state.fs.fd_map)
3165 .map_err(fs_error_into_wasi_err),
3166 env
3167 )
3168 }
3169 _ => {
3170 let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), env);
3171 let inode = fd_entry.inode;
3172 if !fd_entry.rights.contains(Rights::POLL_FD_READWRITE) {
3173 return Ok(Errno::Access);
3174 }
3175
3176 {
3177 let guard = inodes.arena[inode].read();
3178 let deref = guard.deref();
3179 match deref {
3180 Kind::File { handle, .. } => {
3181 if let Some(h) = handle {
3182 crate::state::InodeValFileReadGuard { guard }
3183 } else {
3184 return Ok(Errno::Badf);
3185 }
3186 }
3187 Kind::Socket { .. }
3188 | Kind::Pipe { .. }
3189 | Kind::EventNotifications { .. } => {
3190 return Ok(Errno::Badf);
3191 }
3192 Kind::Dir { .. }
3193 | Kind::Root { .. }
3194 | Kind::Buffer { .. }
3195 | Kind::Symlink { .. } => {
3196 unimplemented!("polling read on non-files not yet supported")
3197 }
3198 }
3199 }
3200 }
3201 };
3202 fd_guards.push(wasi_file_ref);
3203 }
3204 }
3205
3206 #[allow(clippy::significant_drop_in_scrutinee)]
3207 let fds = {
3208 let mut f = vec![];
3209 for fd in fd_guards.iter() {
3210 f.push(wasi_try_ok!(fd.as_ref().ok_or(Errno::Badf)).deref());
3211 }
3212 f
3213 };
3214
3215 let mut seen_events = vec![Default::default(); in_events.len()];
3216
3217 let start = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1_000_000).unwrap() as u128;
3218 let mut triggered = 0;
3219 while triggered == 0 {
3220 let now = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1_000_000).unwrap() as u128;
3221 let delta = match now.checked_sub(start) {
3222 Some(a) => Duration::from_nanos(a as u64),
3223 None => Duration::ZERO,
3224 };
3225 match poll(
3226 fds.as_slice(),
3227 in_events.as_slice(),
3228 seen_events.as_mut_slice(),
3229 Duration::from_millis(1),
3230 ) {
3231 Ok(0) => {
3232 env.yield_now()?;
3233 }
3234 Ok(a) => {
3235 triggered = a;
3236 }
3237 Err(FsError::WouldBlock) => {
3238 env.sleep(Duration::from_millis(1))?;
3239 }
3240 Err(err) => {
3241 return Ok(fs_error_into_wasi_err(err));
3242 }
3243 };
3244 if delta > time_to_sleep {
3245 break;
3246 }
3247 }
3248
3249 for (i, seen_event) in seen_events.into_iter().enumerate() {
3250 let mut flags = Eventrwflags::empty();
3251 let mut error = Errno::Again;
3252 let mut bytes_available = 0;
3253 let event_iter = iterate_poll_events(seen_event);
3254 for event in event_iter {
3255 match event {
3256 PollEvent::PollError => error = Errno::Io,
3257 PollEvent::PollHangUp => flags = Eventrwflags::FD_READWRITE_HANGUP,
3258 PollEvent::PollInvalid => error = Errno::Inval,
3259 PollEvent::PollIn => {
3260 bytes_available = wasi_try_ok!(
3261 fds[i]
3262 .bytes_available_read()
3263 .map_err(fs_error_into_wasi_err),
3264 env
3265 )
3266 .unwrap_or(0usize);
3267 error = Errno::Success;
3268 }
3269 PollEvent::PollOut => {
3270 bytes_available = wasi_try_ok!(
3271 fds[i]
3272 .bytes_available_write()
3273 .map_err(fs_error_into_wasi_err),
3274 env
3275 )
3276 .unwrap_or(0usize);
3277 error = Errno::Success;
3278 }
3279 }
3280 }
3281 let event = Event {
3282 userdata: wasi_try_mem_ok!(subscription_array.index(i as u64).read()).userdata,
3283 error,
3284 data: match wasi_try_mem_ok!(subscription_array.index(i as u64).read()).data {
3285 SubscriptionEnum::Read(d) => EventEnum::FdRead(EventFdReadwrite {
3286 nbytes: bytes_available as u64,
3287 flags,
3288 }),
3289 SubscriptionEnum::Write(d) => EventEnum::FdWrite(EventFdReadwrite {
3290 nbytes: bytes_available as u64,
3291 flags,
3292 }),
3293 SubscriptionEnum::Clock(_) => EventEnum::Clock,
3294 },
3295 };
3296 wasi_try_mem_ok!(event_array.index(events_seen as u64).write(event));
3297 events_seen += 1;
3298 }
3299 if triggered == 0 {
3300 for (clock_info, userdata) in clock_subs {
3301 let event = Event {
3302 userdata,
3303 error: Errno::Success,
3304 data: EventEnum::Clock,
3305 };
3306 wasi_try_mem_ok!(event_array.index(events_seen as u64).write(event));
3307 events_seen += 1;
3308 }
3309 }
3310 let events_seen: M::Offset = wasi_try_ok!(events_seen.try_into().map_err(|_| Errno::Overflow));
3311 wasi_try_mem_ok!(out_ptr.write(events_seen));
3312 Ok(Errno::Success)
3313}
3314
3315pub fn proc_exit(
3323 ctx: FunctionEnvMut<'_, WasiEnv>,
3324 code: __wasi_exitcode_t,
3325) -> Result<(), WasiError> {
3326 debug!("wasi::proc_exit, {}", code);
3327 Err(WasiError::Exit(code))
3328}
3329
3330pub fn proc_raise(ctx: FunctionEnvMut<'_, WasiEnv>, sig: Signal) -> Errno {
3337 debug!("wasi::proc_raise");
3338 unimplemented!("wasi::proc_raise")
3339}
3340
3341pub fn sched_yield(ctx: FunctionEnvMut<'_, WasiEnv>) -> Result<Errno, WasiError> {
3344 trace!("wasi::sched_yield");
3345 let env = ctx.data();
3346 env.yield_now()?;
3347 Ok(Errno::Success)
3348}
3349
3350pub fn random_get<M: MemorySize>(
3358 ctx: FunctionEnvMut<'_, WasiEnv>,
3359 buf: WasmPtr<u8, M>,
3360 buf_len: M::Offset,
3361) -> Errno {
3362 trace!("wasi::random_get buf_len: {}", buf_len);
3363 let env = ctx.data();
3364 let memory = env.memory_view(&ctx);
3365 let buf_len64: u64 = buf_len.into();
3366 let mut u8_buffer = vec![0; buf_len64 as usize];
3367 let res = getrandom::getrandom(&mut u8_buffer);
3368 match res {
3369 Ok(()) => {
3370 let buf = wasi_try_mem!(buf.slice(&memory, buf_len));
3371 wasi_try_mem!(buf.write_slice(&u8_buffer));
3372 Errno::Success
3373 }
3374 Err(_) => Errno::Io,
3375 }
3376}
3377
3378pub fn tty_get<M: MemorySize>(
3381 ctx: FunctionEnvMut<'_, WasiEnv>,
3382 tty_state: WasmPtr<Tty, M>,
3383) -> Errno {
3384 debug!("wasi::tty_stdin");
3385 let env = ctx.data();
3386
3387 let state = env.runtime.tty_get();
3388 let state = Tty {
3389 cols: state.cols,
3390 rows: state.rows,
3391 width: state.width,
3392 height: state.height,
3393 stdin_tty: state.stdin_tty,
3394 stdout_tty: state.stdout_tty,
3395 stderr_tty: state.stderr_tty,
3396 echo: state.echo,
3397 line_buffered: state.line_buffered,
3398 };
3399
3400 let memory = env.memory_view(&ctx);
3401 wasi_try_mem!(tty_state.write(&memory, state));
3402
3403 Errno::Success
3404}
3405
3406pub fn tty_set<M: MemorySize>(
3409 ctx: FunctionEnvMut<'_, WasiEnv>,
3410 tty_state: WasmPtr<Tty, M>,
3411) -> Errno {
3412 debug!("wasi::tty_set");
3413
3414 let env = ctx.data();
3415 let memory = env.memory_view(&ctx);
3416 let state = wasi_try_mem!(tty_state.read(&memory));
3417 let state = super::runtime::WasiTtyState {
3418 cols: state.cols,
3419 rows: state.rows,
3420 width: state.width,
3421 height: state.height,
3422 stdin_tty: state.stdin_tty,
3423 stdout_tty: state.stdout_tty,
3424 stderr_tty: state.stderr_tty,
3425 echo: state.echo,
3426 line_buffered: state.line_buffered,
3427 };
3428
3429 env.runtime.tty_set(state);
3430
3431 Errno::Success
3432}
3433
3434pub fn getcwd<M: MemorySize>(
3439 ctx: FunctionEnvMut<'_, WasiEnv>,
3440 path: WasmPtr<u8, M>,
3441 path_len: WasmPtr<M::Offset, M>,
3442) -> Errno {
3443 debug!("wasi::getcwd");
3444 let env = ctx.data();
3445 let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
3446
3447 let (_, cur_dir) = wasi_try!(state
3448 .fs
3449 .get_current_dir(inodes.deref_mut(), crate::VIRTUAL_ROOT_FD,));
3450
3451 let max_path_len = wasi_try_mem!(path_len.read(&memory));
3452 let path_slice = wasi_try_mem!(path.slice(&memory, max_path_len));
3453 let max_path_len: u64 = max_path_len.into();
3454
3455 let cur_dir = cur_dir.as_bytes();
3456 wasi_try_mem!(path_len.write(&memory, wasi_try!(to_offset::<M>(cur_dir.len()))));
3457 if cur_dir.len() as u64 >= max_path_len {
3458 return Errno::Overflow;
3459 }
3460
3461 let cur_dir = {
3462 let mut u8_buffer = vec![0; max_path_len as usize];
3463 let cur_dir_len = cur_dir.len();
3464 if (cur_dir_len as u64) < max_path_len {
3465 u8_buffer[..cur_dir_len].clone_from_slice(cur_dir);
3466 u8_buffer[cur_dir_len] = 0;
3467 } else {
3468 return Errno::Overflow;
3469 }
3470 u8_buffer
3471 };
3472
3473 wasi_try_mem!(path_slice.write_slice(&cur_dir[..]));
3474 Errno::Success
3475}
3476
3477pub fn chdir<M: MemorySize>(
3480 ctx: FunctionEnvMut<'_, WasiEnv>,
3481 path: WasmPtr<u8, M>,
3482 path_len: M::Offset,
3483) -> Errno {
3484 debug!("wasi::chdir");
3485 let env = ctx.data();
3486 let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
3487 let path = unsafe { get_input_str!(&memory, path, path_len) };
3488
3489 state.fs.set_current_dir(path.as_str());
3490 Errno::Success
3491}
3492
3493pub fn thread_spawn<M: MemorySize>(
3512 ctx: FunctionEnvMut<'_, WasiEnv>,
3513 method: WasmPtr<u8, M>,
3514 method_len: M::Offset,
3515 user_data: u64,
3516 reactor: Bool,
3517 ret_tid: WasmPtr<Tid, M>,
3518) -> Errno {
3519 debug!("wasi::thread_spawn");
3520 let env = ctx.data();
3521 let memory = env.memory_view(&ctx);
3522 let method = unsafe { get_input_str!(&memory, method, method_len) };
3523
3524 if method.as_str() != "_thread_start" {
3526 return Errno::Notcapable;
3527 };
3528 let reactor = match reactor {
3538 Bool::False => false,
3539 Bool::True => true,
3540 _ => return Errno::Inval,
3541 };
3542
3543 let mut sub_env = env.clone();
3545 let mut sub_thread = env.new_thread();
3546 sub_env.id = sub_thread.id;
3547
3548 let child = {
3549 let id = sub_thread.id;
3550 wasi_try!(env
3551 .runtime
3552 .thread_spawn(Box::new(move || {
3553 let thread = {
3568 let mut guard = sub_env.state.threading.lock().unwrap();
3569 let thread = guard.threads.remove(&id);
3570 drop(guard);
3571 thread
3572 };
3573
3574 if let Some(thread) = thread {
3575 let mut thread_guard = thread.exit.lock().unwrap();
3576 thread_guard.take();
3577 }
3578 drop(sub_thread);
3579 }))
3580 .map_err(|err| {
3581 let err: Errno = err.into();
3582 err
3583 }));
3584 id
3585 };
3586 let child: Tid = child.into();
3587
3588 wasi_try_mem!(ret_tid.write(&memory, child));
3589 Errno::Success
3590}
3591
3592pub fn thread_sleep(
3599 ctx: FunctionEnvMut<'_, WasiEnv>,
3600 duration: Timestamp,
3601) -> Result<Errno, WasiError> {
3602 debug!("wasi::thread_sleep");
3603
3604 let env = ctx.data();
3605 let duration = Duration::from_nanos(duration as u64);
3606 env.sleep(duration)?;
3607 Ok(Errno::Success)
3608}
3609
3610pub fn thread_id<M: MemorySize>(
3614 ctx: FunctionEnvMut<'_, WasiEnv>,
3615 ret_tid: WasmPtr<Tid, M>,
3616) -> Errno {
3617 debug!("wasi::thread_id");
3618
3619 let env = ctx.data();
3620 let tid: Tid = env.id.into();
3621 let memory = env.memory_view(&ctx);
3622 wasi_try_mem!(ret_tid.write(&memory, tid));
3623 Errno::Success
3624}
3625
3626pub fn thread_join(ctx: FunctionEnvMut<'_, WasiEnv>, tid: Tid) -> Result<Errno, WasiError> {
3634 debug!("wasi::thread_join");
3635
3636 let env = ctx.data();
3637 let tid: WasiThreadId = tid.into();
3638 let other_thread = {
3639 let guard = env.state.threading.lock().unwrap();
3640 guard.threads.get(&tid).cloned()
3641 };
3642 if let Some(other_thread) = other_thread {
3643 loop {
3644 if other_thread.join(Duration::from_millis(5)) {
3645 break;
3646 }
3647 env.yield_now()?;
3648 }
3649 Ok(Errno::Success)
3650 } else {
3651 Ok(Errno::Success)
3652 }
3653}
3654
3655pub fn thread_parallelism<M: MemorySize>(
3659 ctx: FunctionEnvMut<'_, WasiEnv>,
3660 ret_parallelism: WasmPtr<M::Offset, M>,
3661) -> Errno {
3662 debug!("wasi::thread_parallelism");
3663
3664 let env = ctx.data();
3665 let parallelism = wasi_try!(env.runtime().thread_parallelism().map_err(|err| {
3666 let err: Errno = err.into();
3667 err
3668 }));
3669 let parallelism: M::Offset = wasi_try!(parallelism.try_into().map_err(|_| Errno::Overflow));
3670 let memory = env.memory_view(&ctx);
3671 wasi_try_mem!(ret_parallelism.write(&memory, parallelism));
3672 Errno::Success
3673}
3674
3675pub fn getpid<M: MemorySize>(ctx: FunctionEnvMut<'_, WasiEnv>, ret_pid: WasmPtr<Pid, M>) -> Errno {
3678 debug!("wasi::getpid");
3679
3680 let env = ctx.data();
3681 let pid = env.runtime().getpid();
3682 if let Some(pid) = pid {
3683 let memory = env.memory_view(&ctx);
3684 wasi_try_mem!(ret_pid.write(&memory, pid as Pid));
3685 Errno::Success
3686 } else {
3687 Errno::Notsup
3688 }
3689}
3690
3691pub fn thread_exit(
3701 ctx: FunctionEnvMut<'_, WasiEnv>,
3702 exitcode: __wasi_exitcode_t,
3703) -> Result<Errno, WasiError> {
3704 debug!("wasi::thread_exit");
3705 Err(WasiError::Exit(exitcode))
3706}
3707
3708pub fn process_spawn<M: MemorySize>(
3728 ctx: FunctionEnvMut<'_, WasiEnv>,
3729 name: WasmPtr<u8, M>,
3730 name_len: M::Offset,
3731 chroot: Bool,
3732 args: WasmPtr<u8, M>,
3733 args_len: M::Offset,
3734 preopen: WasmPtr<u8, M>,
3735 preopen_len: M::Offset,
3736 stdin: WasiStdioMode,
3737 stdout: WasiStdioMode,
3738 stderr: WasiStdioMode,
3739 working_dir: WasmPtr<u8, M>,
3740 working_dir_len: M::Offset,
3741 ret_handles: WasmPtr<BusHandles, M>,
3742) -> BusErrno {
3743 let env = ctx.data();
3744 let bus = env.runtime.bus();
3745 let memory = env.memory_view(&ctx);
3746 let name = unsafe { get_input_str_bus!(&memory, name, name_len) };
3747 let args = unsafe { get_input_str_bus!(&memory, args, args_len) };
3748 let preopen = unsafe { get_input_str_bus!(&memory, preopen, preopen_len) };
3749 let working_dir = unsafe { get_input_str_bus!(&memory, working_dir, working_dir_len) };
3750 let chroot = chroot == Bool::True;
3751 debug!("wasi::process_spawn (name={})", name);
3752
3753 let args: Vec<_> = args.split(&['\n', '\r']).map(|a| a.to_string()).collect();
3754
3755 let preopen: Vec<_> = preopen
3756 .split(&['\n', '\r'])
3757 .map(|a| a.to_string())
3758 .collect();
3759
3760 let conv_stdio_mode = |mode: WasiStdioMode| match mode {
3761 WasiStdioMode::Piped => StdioMode::Piped,
3762 WasiStdioMode::Inherit => StdioMode::Inherit,
3763 WasiStdioMode::Log => StdioMode::Log,
3764 _ => StdioMode::Null,
3765 };
3766
3767 let process = wasi_try_bus!(bus
3768 .new_spawn()
3769 .chroot(chroot)
3770 .args(args)
3771 .preopen(preopen)
3772 .stdin_mode(conv_stdio_mode(stdin))
3773 .stdout_mode(conv_stdio_mode(stdout))
3774 .stderr_mode(conv_stdio_mode(stderr))
3775 .working_dir(working_dir)
3776 .spawn(name.as_str())
3777 .map_err(bus_error_into_wasi_err));
3778
3779 let conv_stdio_fd = |a: Option<FileDescriptor>| match a {
3780 Some(fd) => OptionFd {
3781 tag: OptionTag::Some,
3782 fd: fd.into(),
3783 },
3784 None => OptionFd {
3785 tag: OptionTag::None,
3786 fd: 0,
3787 },
3788 };
3789
3790 let stdin = conv_stdio_fd(process.inst.stdin_fd());
3792 let stdout = conv_stdio_fd(process.inst.stdout_fd());
3793 let stderr = conv_stdio_fd(process.inst.stderr_fd());
3794
3795 let bid = {
3797 let mut guard = env.state.threading.lock().unwrap();
3798 guard.process_seed += 1;
3799 let bid = guard.process_seed;
3800 guard.processes.insert(bid.into(), process);
3801 bid
3802 };
3803
3804 let handles = BusHandles {
3805 bid,
3806 stdin,
3807 stdout,
3808 stderr,
3809 };
3810
3811 wasi_try_mem_bus!(ret_handles.write(&memory, handles));
3812
3813 BusErrno::Success
3814}
3815
3816pub fn bus_open_local<M: MemorySize>(
3829 ctx: FunctionEnvMut<'_, WasiEnv>,
3830 name: WasmPtr<u8, M>,
3831 name_len: M::Offset,
3832 reuse: Bool,
3833 ret_bid: WasmPtr<Bid, M>,
3834) -> BusErrno {
3835 let env = ctx.data();
3836 let bus = env.runtime.bus();
3837 let memory = env.memory_view(&ctx);
3838 let name = unsafe { get_input_str_bus!(&memory, name, name_len) };
3839 let reuse = reuse == Bool::True;
3840 debug!("wasi::bus_open_local (name={}, reuse={})", name, reuse);
3841
3842 bus_open_local_internal(ctx, name, reuse, None, None, ret_bid)
3843}
3844
3845pub fn bus_open_remote<M: MemorySize>(
3860 ctx: FunctionEnvMut<'_, WasiEnv>,
3861 name: WasmPtr<u8, M>,
3862 name_len: M::Offset,
3863 reuse: Bool,
3864 instance: WasmPtr<u8, M>,
3865 instance_len: M::Offset,
3866 token: WasmPtr<u8, M>,
3867 token_len: M::Offset,
3868 ret_bid: WasmPtr<Bid, M>,
3869) -> BusErrno {
3870 let env = ctx.data();
3871 let bus = env.runtime.bus();
3872 let memory = env.memory_view(&ctx);
3873 let name = unsafe { get_input_str_bus!(&memory, name, name_len) };
3874 let instance = unsafe { get_input_str_bus!(&memory, instance, instance_len) };
3875 let token = unsafe { get_input_str_bus!(&memory, token, token_len) };
3876 let reuse = reuse == Bool::True;
3877 debug!(
3878 "wasi::bus_open_remote (name={}, reuse={}, instance={})",
3879 name, reuse, instance
3880 );
3881
3882 bus_open_local_internal(ctx, name, reuse, Some(instance), Some(token), ret_bid)
3883}
3884
3885fn bus_open_local_internal<M: MemorySize>(
3886 ctx: FunctionEnvMut<'_, WasiEnv>,
3887 name: String,
3888 reuse: bool,
3889 instance: Option<String>,
3890 token: Option<String>,
3891 ret_bid: WasmPtr<Bid, M>,
3892) -> BusErrno {
3893 let env = ctx.data();
3894 let bus = env.runtime.bus();
3895 let memory = env.memory_view(&ctx);
3896 let name: Cow<'static, str> = name.into();
3897
3898 if reuse {
3900 let guard = env.state.threading.lock().unwrap();
3901 if let Some(bid) = guard.process_reuse.get(&name) {
3902 if guard.processes.contains_key(bid) {
3903 wasi_try_mem_bus!(ret_bid.write(&memory, (*bid).into()));
3904 return BusErrno::Success;
3905 }
3906 }
3907 }
3908
3909 let mut process = bus.new_spawn();
3910 process
3911 .reuse(reuse)
3912 .stdin_mode(StdioMode::Null)
3913 .stdout_mode(StdioMode::Null)
3914 .stderr_mode(StdioMode::Log);
3915
3916 if let Some(instance) = instance {
3917 process.remote_instance(instance);
3918 }
3919
3920 if let Some(token) = token {
3921 process.access_token(token);
3922 }
3923
3924 let process = wasi_try_bus!(process
3925 .spawn(name.as_ref())
3926 .map_err(bus_error_into_wasi_err));
3927
3928 let bid = {
3930 let mut guard = env.state.threading.lock().unwrap();
3931 guard.process_seed += 1;
3932 let bid: WasiBusProcessId = guard.process_seed.into();
3933 guard.processes.insert(bid, process);
3934 guard.process_reuse.insert(name, bid);
3935 bid
3936 };
3937
3938 wasi_try_mem_bus!(ret_bid.write(&memory, bid.into()));
3939
3940 BusErrno::Success
3941}
3942
3943pub fn bus_close(ctx: FunctionEnvMut<'_, WasiEnv>, bid: Bid) -> BusErrno {
3949 trace!("wasi::bus_close (bid={})", bid);
3950 let bid: WasiBusProcessId = bid.into();
3951
3952 let env = ctx.data();
3953 let mut guard = env.state.threading.lock().unwrap();
3954 guard.processes.remove(&bid);
3955
3956 BusErrno::Unsupported
3957}
3958
3959pub fn bus_call<M: MemorySize>(
3971 ctx: FunctionEnvMut<'_, WasiEnv>,
3972 bid: Bid,
3973 keep_alive: Bool,
3974 topic: WasmPtr<u8, M>,
3975 topic_len: M::Offset,
3976 format: BusDataFormat,
3977 buf: WasmPtr<u8, M>,
3978 buf_len: M::Offset,
3979 ret_cid: WasmPtr<Cid, M>,
3980) -> BusErrno {
3981 let env = ctx.data();
3982 let bus = env.runtime.bus();
3983 let memory = env.memory_view(&ctx);
3984 let topic = unsafe { get_input_str_bus!(&memory, topic, topic_len) };
3985 let keep_alive = keep_alive == Bool::True;
3986 trace!(
3987 "wasi::bus_call (bid={}, topic={}, buf_len={})",
3988 bid,
3989 topic,
3990 buf_len
3991 );
3992
3993 BusErrno::Unsupported
3994}
3995
3996pub fn bus_subcall<M: MemorySize>(
4008 ctx: FunctionEnvMut<'_, WasiEnv>,
4009 parent: Cid,
4010 keep_alive: Bool,
4011 topic: WasmPtr<u8, M>,
4012 topic_len: M::Offset,
4013 format: BusDataFormat,
4014 buf: WasmPtr<u8, M>,
4015 buf_len: M::Offset,
4016 ret_cid: WasmPtr<Cid, M>,
4017) -> BusErrno {
4018 let env = ctx.data();
4019 let bus = env.runtime.bus();
4020 let memory = env.memory_view(&ctx);
4021 let topic = unsafe { get_input_str_bus!(&memory, topic, topic_len) };
4022 let keep_alive = keep_alive == Bool::True;
4023 trace!(
4024 "wasi::bus_subcall (parent={}, topic={}, buf_len={})",
4025 parent,
4026 topic,
4027 buf_len
4028 );
4029
4030 BusErrno::Unsupported
4031}
4032
4033pub fn bus_poll<M: MemorySize>(
4048 ctx: FunctionEnvMut<'_, WasiEnv>,
4049 timeout: Timestamp,
4050 events: WasmPtr<u8, M>,
4051 nevents: M::Offset,
4052 malloc: WasmPtr<u8, M>,
4053 malloc_len: M::Offset,
4054 ret_nevents: WasmPtr<M::Offset, M>,
4055) -> BusErrno {
4056 let env = ctx.data();
4057 let bus = env.runtime.bus();
4058 let memory = env.memory_view(&ctx);
4059 let malloc = unsafe { get_input_str_bus!(&memory, malloc, malloc_len) };
4060 trace!("wasi::bus_poll (timeout={}, malloc={})", timeout, malloc);
4061
4062 BusErrno::Unsupported
4063}
4064
4065pub fn call_reply<M: MemorySize>(
4076 ctx: FunctionEnvMut<'_, WasiEnv>,
4077 cid: Cid,
4078 format: BusDataFormat,
4079 buf: WasmPtr<u8, M>,
4080 buf_len: M::Offset,
4081) -> BusErrno {
4082 let env = ctx.data();
4083 let bus = env.runtime.bus();
4084 trace!(
4085 "wasi::call_reply (cid={}, format={}, data_len={})",
4086 cid,
4087 format,
4088 buf_len
4089 );
4090
4091 BusErrno::Unsupported
4092}
4093
4094pub fn call_fault(ctx: FunctionEnvMut<'_, WasiEnv>, cid: Cid, fault: BusErrno) -> BusErrno {
4103 let env = ctx.data();
4104 let bus = env.runtime.bus();
4105 debug!("wasi::call_fault (cid={}, fault={})", cid, fault);
4106
4107 BusErrno::Unsupported
4108}
4109
4110pub fn call_close(ctx: FunctionEnvMut<'_, WasiEnv>, cid: Cid) -> BusErrno {
4116 let env = ctx.data();
4117 let bus = env.runtime.bus();
4118 trace!("wasi::call_close (cid={})", cid);
4119
4120 BusErrno::Unsupported
4121}
4122
4123pub fn ws_connect<M: MemorySize>(
4134 ctx: FunctionEnvMut<'_, WasiEnv>,
4135 url: WasmPtr<u8, M>,
4136 url_len: M::Offset,
4137 ret_sock: WasmPtr<WasiFd, M>,
4138) -> Errno {
4139 debug!("wasi::ws_connect");
4140 let env = ctx.data();
4141 let memory = env.memory_view(&ctx);
4142 let url = unsafe { get_input_str!(&memory, url, url_len) };
4143
4144 let socket = wasi_try!(env
4145 .net()
4146 .ws_connect(url.as_str())
4147 .map_err(net_error_into_wasi_err));
4148
4149 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
4150
4151 let kind = Kind::Socket {
4152 socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)),
4153 };
4154
4155 let inode = state.fs.create_inode_with_default_stat(
4156 inodes.deref_mut(),
4157 kind,
4158 false,
4159 "socket".to_string(),
4160 );
4161 let rights = Rights::all_socket();
4162 let fd = wasi_try!(state
4163 .fs
4164 .create_fd(rights, rights, Fdflags::empty(), 0, inode));
4165
4166 wasi_try_mem!(ret_sock.write(&memory, fd));
4167
4168 Errno::Success
4169}
4170
4171pub fn http_request<M: MemorySize>(
4188 ctx: FunctionEnvMut<'_, WasiEnv>,
4189 url: WasmPtr<u8, M>,
4190 url_len: M::Offset,
4191 method: WasmPtr<u8, M>,
4192 method_len: M::Offset,
4193 headers: WasmPtr<u8, M>,
4194 headers_len: M::Offset,
4195 gzip: Bool,
4196 ret_handles: WasmPtr<HttpHandles, M>,
4197) -> Errno {
4198 debug!("wasi::http_request");
4199 let env = ctx.data();
4200 let memory = env.memory_view(&ctx);
4201 let url = unsafe { get_input_str!(&memory, url, url_len) };
4202 let method = unsafe { get_input_str!(&memory, method, method_len) };
4203 let headers = unsafe { get_input_str!(&memory, headers, headers_len) };
4204
4205 let gzip = match gzip {
4206 Bool::False => false,
4207 Bool::True => true,
4208 _ => return Errno::Inval,
4209 };
4210
4211 let socket = wasi_try!(env
4212 .net()
4213 .http_request(url.as_str(), method.as_str(), headers.as_str(), gzip)
4214 .map_err(net_error_into_wasi_err));
4215 let socket_req = SocketHttpRequest {
4216 request: socket.request,
4217 response: None,
4218 headers: None,
4219 status: socket.status.clone(),
4220 };
4221 let socket_res = SocketHttpRequest {
4222 request: None,
4223 response: socket.response,
4224 headers: None,
4225 status: socket.status.clone(),
4226 };
4227 let socket_hdr = SocketHttpRequest {
4228 request: None,
4229 response: None,
4230 headers: socket.headers,
4231 status: socket.status,
4232 };
4233
4234 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
4235
4236 let kind_req = Kind::Socket {
4237 socket: InodeSocket::new(InodeSocketKind::HttpRequest(
4238 Mutex::new(socket_req),
4239 InodeHttpSocketType::Request,
4240 )),
4241 };
4242 let kind_res = Kind::Socket {
4243 socket: InodeSocket::new(InodeSocketKind::HttpRequest(
4244 Mutex::new(socket_res),
4245 InodeHttpSocketType::Response,
4246 )),
4247 };
4248 let kind_hdr = Kind::Socket {
4249 socket: InodeSocket::new(InodeSocketKind::HttpRequest(
4250 Mutex::new(socket_hdr),
4251 InodeHttpSocketType::Headers,
4252 )),
4253 };
4254
4255 let inode_req = state.fs.create_inode_with_default_stat(
4256 inodes.deref_mut(),
4257 kind_req,
4258 false,
4259 "http_request".to_string(),
4260 );
4261 let inode_res = state.fs.create_inode_with_default_stat(
4262 inodes.deref_mut(),
4263 kind_res,
4264 false,
4265 "http_response".to_string(),
4266 );
4267 let inode_hdr = state.fs.create_inode_with_default_stat(
4268 inodes.deref_mut(),
4269 kind_hdr,
4270 false,
4271 "http_headers".to_string(),
4272 );
4273 let rights = Rights::all_socket();
4274
4275 let handles = HttpHandles {
4276 req: wasi_try!(state
4277 .fs
4278 .create_fd(rights, rights, Fdflags::empty(), 0, inode_req)),
4279 res: wasi_try!(state
4280 .fs
4281 .create_fd(rights, rights, Fdflags::empty(), 0, inode_res)),
4282 hdr: wasi_try!(state
4283 .fs
4284 .create_fd(rights, rights, Fdflags::empty(), 0, inode_hdr)),
4285 };
4286
4287 wasi_try_mem!(ret_handles.write(&memory, handles));
4288
4289 Errno::Success
4290}
4291
4292pub fn http_status<M: MemorySize>(
4301 ctx: FunctionEnvMut<'_, WasiEnv>,
4302 sock: WasiFd,
4303 status: WasmPtr<HttpStatus, M>,
4304) -> Errno {
4305 debug!("wasi::http_status");
4306
4307 let env = ctx.data();
4308 let memory = env.memory_view(&ctx);
4309 let ref_status = status.deref(&memory);
4310
4311 let http_status = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
4312 socket.http_status()
4313 }));
4314
4315 let status = HttpStatus {
4317 ok: Bool::True,
4318 redirect: match http_status.redirected {
4319 true => Bool::True,
4320 false => Bool::False,
4321 },
4322 size: wasi_try!(Ok(http_status.size)),
4323 status: http_status.status,
4324 };
4325
4326 wasi_try_mem!(ref_status.write(status));
4327
4328 Errno::Success
4329}
4330
4331pub fn port_bridge<M: MemorySize>(
4340 ctx: FunctionEnvMut<'_, WasiEnv>,
4341 network: WasmPtr<u8, M>,
4342 network_len: M::Offset,
4343 token: WasmPtr<u8, M>,
4344 token_len: M::Offset,
4345 security: Streamsecurity,
4346) -> Errno {
4347 debug!("wasi::port_bridge");
4348 let env = ctx.data();
4349 let memory = env.memory_view(&ctx);
4350 let network = unsafe { get_input_str!(&memory, network, network_len) };
4351 let token = unsafe { get_input_str!(&memory, token, token_len) };
4352 let security = match security {
4353 Streamsecurity::Unencrypted => StreamSecurity::Unencrypted,
4354 Streamsecurity::AnyEncryption => StreamSecurity::AnyEncyption,
4355 Streamsecurity::ClassicEncryption => StreamSecurity::ClassicEncryption,
4356 Streamsecurity::DoubleEncryption => StreamSecurity::DoubleEncryption,
4357 _ => return Errno::Inval,
4358 };
4359
4360 wasi_try!(env
4361 .net()
4362 .bridge(network.as_str(), token.as_str(), security)
4363 .map_err(net_error_into_wasi_err));
4364 Errno::Success
4365}
4366
4367pub fn port_unbridge(ctx: FunctionEnvMut<'_, WasiEnv>) -> Errno {
4370 debug!("wasi::port_unbridge");
4371 let env = ctx.data();
4372 wasi_try!(env.net().unbridge().map_err(net_error_into_wasi_err));
4373 Errno::Success
4374}
4375
4376pub fn port_dhcp_acquire(ctx: FunctionEnvMut<'_, WasiEnv>) -> Errno {
4379 debug!("wasi::port_dhcp_acquire");
4380 let env = ctx.data();
4381 wasi_try!(env.net().dhcp_acquire().map_err(net_error_into_wasi_err));
4382 Errno::Success
4383}
4384
4385pub fn port_addr_add<M: MemorySize>(
4392 ctx: FunctionEnvMut<'_, WasiEnv>,
4393 ip: WasmPtr<__wasi_cidr_t, M>,
4394) -> Errno {
4395 debug!("wasi::port_addr_add");
4396 let env = ctx.data();
4397 let memory = env.memory_view(&ctx);
4398 let cidr = wasi_try!(super::state::read_cidr(&memory, ip));
4399 wasi_try!(env
4400 .net()
4401 .ip_add(cidr.ip, cidr.prefix)
4402 .map_err(net_error_into_wasi_err));
4403 Errno::Success
4404}
4405
4406pub fn port_addr_remove<M: MemorySize>(
4413 ctx: FunctionEnvMut<'_, WasiEnv>,
4414 ip: WasmPtr<__wasi_addr_t, M>,
4415) -> Errno {
4416 debug!("wasi::port_addr_remove");
4417 let env = ctx.data();
4418 let memory = env.memory_view(&ctx);
4419 let ip = wasi_try!(super::state::read_ip(&memory, ip));
4420 wasi_try!(env.net().ip_remove(ip).map_err(net_error_into_wasi_err));
4421 Errno::Success
4422}
4423
4424pub fn port_addr_clear(ctx: FunctionEnvMut<'_, WasiEnv>) -> Errno {
4427 debug!("wasi::port_addr_clear");
4428 let env = ctx.data();
4429 wasi_try!(env.net().ip_clear().map_err(net_error_into_wasi_err));
4430 Errno::Success
4431}
4432
4433pub fn port_mac<M: MemorySize>(
4436 ctx: FunctionEnvMut<'_, WasiEnv>,
4437 ret_mac: WasmPtr<__wasi_hardwareaddress_t, M>,
4438) -> Errno {
4439 debug!("wasi::port_mac");
4440 let env = ctx.data();
4441 let memory = env.memory_view(&ctx);
4442 let mac = wasi_try!(env.net().mac().map_err(net_error_into_wasi_err));
4443 let mac = __wasi_hardwareaddress_t { octs: mac };
4444 wasi_try_mem!(ret_mac.write(&memory, mac));
4445 Errno::Success
4446}
4447
4448pub fn port_addr_list<M: MemorySize>(
4462 ctx: FunctionEnvMut<'_, WasiEnv>,
4463 addrs: WasmPtr<__wasi_cidr_t, M>,
4464 naddrs: WasmPtr<M::Offset, M>,
4465) -> Errno {
4466 debug!("wasi::port_addr_list");
4467 let env = ctx.data();
4468 let memory = env.memory_view(&ctx);
4469 let max_addrs = wasi_try_mem!(naddrs.read(&memory));
4470 let max_addrs: u64 = wasi_try!(max_addrs.try_into().map_err(|_| Errno::Overflow));
4471 let ref_addrs =
4472 wasi_try_mem!(addrs.slice(&memory, wasi_try!(to_offset::<M>(max_addrs as usize))));
4473
4474 let addrs = wasi_try!(env.net().ip_list().map_err(net_error_into_wasi_err));
4475
4476 let addrs_len: M::Offset = wasi_try!(addrs.len().try_into().map_err(|_| Errno::Overflow));
4477 wasi_try_mem!(naddrs.write(&memory, addrs_len));
4478 if addrs.len() as u64 > max_addrs {
4479 return Errno::Overflow;
4480 }
4481
4482 for n in 0..addrs.len() {
4483 let nip = ref_addrs.index(n as u64);
4484 super::state::write_cidr(&memory, nip.as_ptr::<M>(), *addrs.get(n).unwrap());
4485 }
4486
4487 Errno::Success
4488}
4489
4490pub fn port_gateway_set<M: MemorySize>(
4497 ctx: FunctionEnvMut<'_, WasiEnv>,
4498 ip: WasmPtr<__wasi_addr_t, M>,
4499) -> Errno {
4500 debug!("wasi::port_gateway_set");
4501 let env = ctx.data();
4502 let memory = env.memory_view(&ctx);
4503 let ip = wasi_try!(super::state::read_ip(&memory, ip));
4504
4505 wasi_try!(env.net().gateway_set(ip).map_err(net_error_into_wasi_err));
4506 Errno::Success
4507}
4508
4509pub fn port_route_add<M: MemorySize>(
4512 ctx: FunctionEnvMut<'_, WasiEnv>,
4513 cidr: WasmPtr<__wasi_cidr_t, M>,
4514 via_router: WasmPtr<__wasi_addr_t, M>,
4515 preferred_until: WasmPtr<OptionTimestamp, M>,
4516 expires_at: WasmPtr<OptionTimestamp, M>,
4517) -> Errno {
4518 debug!("wasi::port_route_add");
4519 let env = ctx.data();
4520 let memory = env.memory_view(&ctx);
4521 let cidr = wasi_try!(super::state::read_cidr(&memory, cidr));
4522 let via_router = wasi_try!(super::state::read_ip(&memory, via_router));
4523 let preferred_until = wasi_try_mem!(preferred_until.read(&memory));
4524 let preferred_until = match preferred_until.tag {
4525 OptionTag::None => None,
4526 OptionTag::Some => Some(Duration::from_nanos(preferred_until.u)),
4527 _ => return Errno::Inval,
4528 };
4529 let expires_at = wasi_try_mem!(expires_at.read(&memory));
4530 let expires_at = match expires_at.tag {
4531 OptionTag::None => None,
4532 OptionTag::Some => Some(Duration::from_nanos(expires_at.u)),
4533 _ => return Errno::Inval,
4534 };
4535
4536 wasi_try!(env
4537 .net()
4538 .route_add(cidr, via_router, preferred_until, expires_at)
4539 .map_err(net_error_into_wasi_err));
4540 Errno::Success
4541}
4542
4543pub fn port_route_remove<M: MemorySize>(
4546 ctx: FunctionEnvMut<'_, WasiEnv>,
4547 ip: WasmPtr<__wasi_addr_t, M>,
4548) -> Errno {
4549 debug!("wasi::port_route_remove");
4550 let env = ctx.data();
4551 let memory = env.memory_view(&ctx);
4552 let ip = wasi_try!(super::state::read_ip(&memory, ip));
4553 wasi_try!(env.net().route_remove(ip).map_err(net_error_into_wasi_err));
4554 Errno::Success
4555}
4556
4557pub fn port_route_clear(ctx: FunctionEnvMut<'_, WasiEnv>) -> Errno {
4560 debug!("wasi::port_route_clear");
4561 let env = ctx.data();
4562 wasi_try!(env.net().route_clear().map_err(net_error_into_wasi_err));
4563 Errno::Success
4564}
4565
4566pub fn port_route_list<M: MemorySize>(
4576 ctx: FunctionEnvMut<'_, WasiEnv>,
4577 routes: WasmPtr<Route, M>,
4578 nroutes: WasmPtr<M::Offset, M>,
4579) -> Errno {
4580 debug!("wasi::port_route_list");
4581 let env = ctx.data();
4582 let memory = env.memory_view(&ctx);
4583 let nroutes = nroutes.deref(&memory);
4584 let max_routes: usize = wasi_try!(wasi_try_mem!(nroutes.read())
4585 .try_into()
4586 .map_err(|_| Errno::Inval));
4587 let ref_routes = wasi_try_mem!(routes.slice(&memory, wasi_try!(to_offset::<M>(max_routes))));
4588
4589 let routes = wasi_try!(env.net().route_list().map_err(net_error_into_wasi_err));
4590
4591 let routes_len: M::Offset = wasi_try!(routes.len().try_into().map_err(|_| Errno::Inval));
4592 wasi_try_mem!(nroutes.write(routes_len));
4593 if routes.len() > max_routes {
4594 return Errno::Overflow;
4595 }
4596
4597 for n in 0..routes.len() {
4598 let nroute = ref_routes.index(n as u64);
4599 super::state::write_route(
4600 &memory,
4601 nroute.as_ptr::<M>(),
4602 routes.get(n).unwrap().clone(),
4603 );
4604 }
4605
4606 Errno::Success
4607}
4608
4609pub fn sock_shutdown(ctx: FunctionEnvMut<'_, WasiEnv>, sock: WasiFd, how: SdFlags) -> Errno {
4617 debug!("wasi::sock_shutdown");
4618
4619 let both = __WASI_SHUT_RD | __WASI_SHUT_WR;
4620 let how = match how {
4621 __WASI_SHUT_RD => std::net::Shutdown::Read,
4622 __WASI_SHUT_WR => std::net::Shutdown::Write,
4623 a if a == both => std::net::Shutdown::Both,
4624 _ => return Errno::Inval,
4625 };
4626
4627 wasi_try!(__sock_actor_mut(
4628 &ctx,
4629 sock,
4630 Rights::SOCK_SHUTDOWN,
4631 |socket| { socket.shutdown(how) }
4632 ));
4633
4634 Errno::Success
4635}
4636
4637pub fn sock_status<M: MemorySize>(
4640 ctx: FunctionEnvMut<'_, WasiEnv>,
4641 sock: WasiFd,
4642 ret_status: WasmPtr<Sockstatus, M>,
4643) -> Errno {
4644 debug!("wasi::sock_status");
4645
4646 let status = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
4647 socket.status()
4648 }));
4649
4650 use super::state::WasiSocketStatus;
4651 let status = match status {
4652 WasiSocketStatus::Opening => Sockstatus::Opening,
4653 WasiSocketStatus::Opened => Sockstatus::Opened,
4654 WasiSocketStatus::Closed => Sockstatus::Closed,
4655 WasiSocketStatus::Failed => Sockstatus::Failed,
4656 };
4657
4658 let env = ctx.data();
4659 let memory = env.memory_view(&ctx);
4660 wasi_try_mem!(ret_status.write(&memory, status));
4661
4662 Errno::Success
4663}
4664
4665pub fn sock_addr_local<M: MemorySize>(
4677 ctx: FunctionEnvMut<'_, WasiEnv>,
4678 sock: WasiFd,
4679 ret_addr: WasmPtr<__wasi_addr_port_t, M>,
4680) -> Errno {
4681 debug!("wasi::sock_addr_local");
4682
4683 let addr = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
4684 socket.addr_local()
4685 }));
4686 let memory = ctx.data().memory_view(&ctx);
4687 wasi_try!(super::state::write_ip_port(
4688 &memory,
4689 ret_addr,
4690 addr.ip(),
4691 addr.port()
4692 ));
4693 Errno::Success
4694}
4695
4696pub fn sock_addr_peer<M: MemorySize>(
4708 ctx: FunctionEnvMut<'_, WasiEnv>,
4709 sock: WasiFd,
4710 ro_addr: WasmPtr<__wasi_addr_port_t, M>,
4711) -> Errno {
4712 debug!("wasi::sock_addr_peer");
4713
4714 let env = ctx.data();
4715 let addr = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
4716 socket.addr_peer()
4717 }));
4718 let memory = env.memory_view(&ctx);
4719 wasi_try!(super::state::write_ip_port(
4720 &memory,
4721 ro_addr,
4722 addr.ip(),
4723 addr.port()
4724 ));
4725 Errno::Success
4726}
4727
4728pub fn sock_open<M: MemorySize>(
4748 ctx: FunctionEnvMut<'_, WasiEnv>,
4749 af: Addressfamily,
4750 ty: Socktype,
4751 pt: SockProto,
4752 ro_sock: WasmPtr<WasiFd, M>,
4753) -> Errno {
4754 debug!("wasi::sock_open");
4755
4756 let env = ctx.data();
4757 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
4758
4759 let kind = match ty {
4760 Socktype::Stream | Socktype::Dgram => Kind::Socket {
4761 socket: InodeSocket::new(InodeSocketKind::PreSocket {
4762 family: af,
4763 ty,
4764 pt,
4765 addr: None,
4766 only_v6: false,
4767 reuse_port: false,
4768 reuse_addr: false,
4769 send_buf_size: None,
4770 recv_buf_size: None,
4771 send_timeout: None,
4772 recv_timeout: None,
4773 connect_timeout: None,
4774 accept_timeout: None,
4775 }),
4776 },
4777 _ => return Errno::Notsup,
4778 };
4779
4780 let inode = state.fs.create_inode_with_default_stat(
4781 inodes.deref_mut(),
4782 kind,
4783 false,
4784 "socket".to_string(),
4785 );
4786 let rights = Rights::all_socket();
4787 let fd = wasi_try!(state
4788 .fs
4789 .create_fd(rights, rights, Fdflags::empty(), 0, inode));
4790
4791 wasi_try_mem!(ro_sock.write(&memory, fd));
4792
4793 Errno::Success
4794}
4795
4796pub fn sock_set_opt_flag(
4806 ctx: FunctionEnvMut<'_, WasiEnv>,
4807 sock: WasiFd,
4808 opt: Sockoption,
4809 flag: Bool,
4810) -> Errno {
4811 debug!("wasi::sock_set_opt_flag(ty={})", opt);
4812
4813 let flag = match flag {
4814 Bool::False => false,
4815 Bool::True => true,
4816 _ => return Errno::Inval,
4817 };
4818
4819 let option: super::state::WasiSocketOption = opt.into();
4820 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
4821 socket.set_opt_flag(option, flag)
4822 }));
4823 Errno::Success
4824}
4825
4826pub fn sock_get_opt_flag<M: MemorySize>(
4835 ctx: FunctionEnvMut<'_, WasiEnv>,
4836 sock: WasiFd,
4837 opt: Sockoption,
4838 ret_flag: WasmPtr<Bool, M>,
4839) -> Errno {
4840 debug!("wasi::sock_get_opt_flag(ty={})", opt);
4841 let env = ctx.data();
4842 let memory = env.memory_view(&ctx);
4843
4844 let option: super::state::WasiSocketOption = opt.into();
4845 let flag = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
4846 socket.get_opt_flag(option)
4847 }));
4848 let flag = match flag {
4849 false => Bool::False,
4850 true => Bool::True,
4851 };
4852
4853 wasi_try_mem!(ret_flag.write(&memory, flag));
4854
4855 Errno::Success
4856}
4857
4858pub fn sock_set_opt_time<M: MemorySize>(
4867 ctx: FunctionEnvMut<'_, WasiEnv>,
4868 sock: WasiFd,
4869 opt: Sockoption,
4870 time: WasmPtr<OptionTimestamp, M>,
4871) -> Errno {
4872 debug!("wasi::sock_set_opt_time(ty={})", opt);
4873
4874 let env = ctx.data();
4875 let memory = env.memory_view(&ctx);
4876 let time = wasi_try_mem!(time.read(&memory));
4877 let time = match time.tag {
4878 OptionTag::None => None,
4879 OptionTag::Some => Some(Duration::from_nanos(time.u)),
4880 _ => return Errno::Inval,
4881 };
4882
4883 let ty = match opt {
4884 Sockoption::RecvTimeout => wasmer_vnet::TimeType::ReadTimeout,
4885 Sockoption::SendTimeout => wasmer_vnet::TimeType::WriteTimeout,
4886 Sockoption::ConnectTimeout => wasmer_vnet::TimeType::ConnectTimeout,
4887 Sockoption::AcceptTimeout => wasmer_vnet::TimeType::AcceptTimeout,
4888 Sockoption::Linger => wasmer_vnet::TimeType::Linger,
4889 _ => return Errno::Inval,
4890 };
4891
4892 let option: super::state::WasiSocketOption = opt.into();
4893 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
4894 socket.set_opt_time(ty, time)
4895 }));
4896 Errno::Success
4897}
4898
4899pub fn sock_get_opt_time<M: MemorySize>(
4907 ctx: FunctionEnvMut<'_, WasiEnv>,
4908 sock: WasiFd,
4909 opt: Sockoption,
4910 ret_time: WasmPtr<OptionTimestamp, M>,
4911) -> Errno {
4912 debug!("wasi::sock_get_opt_time(ty={})", opt);
4913 let env = ctx.data();
4914 let memory = env.memory_view(&ctx);
4915
4916 let ty = match opt {
4917 Sockoption::RecvTimeout => wasmer_vnet::TimeType::ReadTimeout,
4918 Sockoption::SendTimeout => wasmer_vnet::TimeType::WriteTimeout,
4919 Sockoption::ConnectTimeout => wasmer_vnet::TimeType::ConnectTimeout,
4920 Sockoption::AcceptTimeout => wasmer_vnet::TimeType::AcceptTimeout,
4921 Sockoption::Linger => wasmer_vnet::TimeType::Linger,
4922 _ => return Errno::Inval,
4923 };
4924
4925 let time = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
4926 socket.opt_time(ty)
4927 }));
4928 let time = match time {
4929 None => OptionTimestamp {
4930 tag: OptionTag::None,
4931 u: 0,
4932 },
4933 Some(timeout) => OptionTimestamp {
4934 tag: OptionTag::Some,
4935 u: timeout.as_nanos() as Timestamp,
4936 },
4937 };
4938
4939 wasi_try_mem!(ret_time.write(&memory, time));
4940
4941 Errno::Success
4942}
4943
4944pub fn sock_set_opt_size(
4954 ctx: FunctionEnvMut<'_, WasiEnv>,
4955 sock: WasiFd,
4956 opt: Sockoption,
4957 size: Filesize,
4958) -> Errno {
4959 debug!("wasi::sock_set_opt_size(ty={})", opt);
4960
4961 let ty = match opt {
4962 Sockoption::RecvTimeout => wasmer_vnet::TimeType::ReadTimeout,
4963 Sockoption::SendTimeout => wasmer_vnet::TimeType::WriteTimeout,
4964 Sockoption::ConnectTimeout => wasmer_vnet::TimeType::ConnectTimeout,
4965 Sockoption::AcceptTimeout => wasmer_vnet::TimeType::AcceptTimeout,
4966 Sockoption::Linger => wasmer_vnet::TimeType::Linger,
4967 _ => return Errno::Inval,
4968 };
4969
4970 let option: super::state::WasiSocketOption = opt.into();
4971 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
4972 match opt {
4973 Sockoption::RecvBufSize => socket.set_recv_buf_size(size as usize),
4974 Sockoption::SendBufSize => socket.set_send_buf_size(size as usize),
4975 Sockoption::Ttl => socket.set_ttl(size as u32),
4976 Sockoption::MulticastTtlV4 => socket.set_multicast_ttl_v4(size as u32),
4977 _ => Err(Errno::Inval),
4978 }
4979 }));
4980 Errno::Success
4981}
4982
4983pub fn sock_get_opt_size<M: MemorySize>(
4992 ctx: FunctionEnvMut<'_, WasiEnv>,
4993 sock: WasiFd,
4994 opt: Sockoption,
4995 ret_size: WasmPtr<Filesize, M>,
4996) -> Errno {
4997 debug!("wasi::sock_get_opt_size(ty={})", opt);
4998 let env = ctx.data();
4999 let memory = env.memory_view(&ctx);
5000
5001 let size = wasi_try!(__sock_actor(&ctx, sock, Rights::empty(), |socket| {
5002 match opt {
5003 Sockoption::RecvBufSize => socket.recv_buf_size().map(|a| a as Filesize),
5004 Sockoption::SendBufSize => socket.send_buf_size().map(|a| a as Filesize),
5005 Sockoption::Ttl => socket.ttl().map(|a| a as Filesize),
5006 Sockoption::MulticastTtlV4 => socket.multicast_ttl_v4().map(|a| a as Filesize),
5007 _ => Err(Errno::Inval),
5008 }
5009 }));
5010 wasi_try_mem!(ret_size.write(&memory, size));
5011
5012 Errno::Success
5013}
5014
5015pub fn sock_join_multicast_v4<M: MemorySize>(
5024 ctx: FunctionEnvMut<'_, WasiEnv>,
5025 sock: WasiFd,
5026 multiaddr: WasmPtr<__wasi_addr_ip4_t, M>,
5027 iface: WasmPtr<__wasi_addr_ip4_t, M>,
5028) -> Errno {
5029 debug!("wasi::sock_join_multicast_v4");
5030
5031 let env = ctx.data();
5032 let memory = env.memory_view(&ctx);
5033 let multiaddr = wasi_try!(super::state::read_ip_v4(&memory, multiaddr));
5034 let iface = wasi_try!(super::state::read_ip_v4(&memory, iface));
5035 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
5036 socket.join_multicast_v4(multiaddr, iface)
5037 }));
5038 Errno::Success
5039}
5040
5041pub fn sock_leave_multicast_v4<M: MemorySize>(
5050 ctx: FunctionEnvMut<'_, WasiEnv>,
5051 sock: WasiFd,
5052 multiaddr: WasmPtr<__wasi_addr_ip4_t, M>,
5053 iface: WasmPtr<__wasi_addr_ip4_t, M>,
5054) -> Errno {
5055 debug!("wasi::sock_leave_multicast_v4");
5056
5057 let env = ctx.data();
5058 let memory = env.memory_view(&ctx);
5059 let multiaddr = wasi_try!(super::state::read_ip_v4(&memory, multiaddr));
5060 let iface = wasi_try!(super::state::read_ip_v4(&memory, iface));
5061 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
5062 socket.leave_multicast_v4(multiaddr, iface)
5063 }));
5064 Errno::Success
5065}
5066
5067pub fn sock_join_multicast_v6<M: MemorySize>(
5076 ctx: FunctionEnvMut<'_, WasiEnv>,
5077 sock: WasiFd,
5078 multiaddr: WasmPtr<__wasi_addr_ip6_t, M>,
5079 iface: u32,
5080) -> Errno {
5081 debug!("wasi::sock_join_multicast_v6");
5082
5083 let env = ctx.data();
5084 let memory = env.memory_view(&ctx);
5085 let multiaddr = wasi_try!(super::state::read_ip_v6(&memory, multiaddr));
5086 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
5087 socket.join_multicast_v6(multiaddr, iface)
5088 }));
5089 Errno::Success
5090}
5091
5092pub fn sock_leave_multicast_v6<M: MemorySize>(
5101 ctx: FunctionEnvMut<'_, WasiEnv>,
5102 sock: WasiFd,
5103 multiaddr: WasmPtr<__wasi_addr_ip6_t, M>,
5104 iface: u32,
5105) -> Errno {
5106 debug!("wasi::sock_leave_multicast_v6");
5107
5108 let env = ctx.data();
5109 let memory = env.memory_view(&ctx);
5110 let multiaddr = wasi_try!(super::state::read_ip_v6(&memory, multiaddr));
5111 wasi_try!(__sock_actor_mut(&ctx, sock, Rights::empty(), |socket| {
5112 socket.leave_multicast_v6(multiaddr, iface)
5113 }));
5114 Errno::Success
5115}
5116
5117pub fn sock_bind<M: MemorySize>(
5126 ctx: FunctionEnvMut<'_, WasiEnv>,
5127 sock: WasiFd,
5128 addr: WasmPtr<__wasi_addr_port_t, M>,
5129) -> Errno {
5130 debug!("wasi::sock_bind");
5131
5132 let env = ctx.data();
5133 let memory = env.memory_view(&ctx);
5134 let addr = wasi_try!(super::state::read_ip_port(&memory, addr));
5135 let addr = SocketAddr::new(addr.0, addr.1);
5136 wasi_try!(__sock_upgrade(&ctx, sock, Rights::SOCK_BIND, |socket| {
5137 socket.bind(env.net(), addr)
5138 }));
5139 Errno::Success
5140}
5141
5142pub fn sock_listen<M: MemorySize>(
5155 ctx: FunctionEnvMut<'_, WasiEnv>,
5156 sock: WasiFd,
5157 backlog: M::Offset,
5158) -> Errno {
5159 debug!("wasi::sock_listen");
5160
5161 let env = ctx.data();
5162 let backlog: usize = wasi_try!(backlog.try_into().map_err(|_| Errno::Inval));
5163 wasi_try!(__sock_upgrade(&ctx, sock, Rights::SOCK_BIND, |socket| {
5164 socket.listen(env.net(), backlog)
5165 }));
5166 Errno::Success
5167}
5168
5169pub fn sock_accept<M: MemorySize>(
5182 ctx: FunctionEnvMut<'_, WasiEnv>,
5183 sock: WasiFd,
5184 fd_flags: Fdflags,
5185 ro_fd: WasmPtr<WasiFd, M>,
5186 ro_addr: WasmPtr<__wasi_addr_port_t, M>,
5187) -> Result<Errno, WasiError> {
5188 debug!("wasi::sock_accept");
5189
5190 let env = ctx.data();
5191 let (child, addr) = {
5192 let mut ret;
5193 let (_, state) = env.get_memory_and_wasi_state(&ctx, 0);
5194 loop {
5195 wasi_try_ok!(
5196 match __sock_actor(&ctx, sock, Rights::SOCK_ACCEPT, |socket| socket
5197 .accept_timeout(fd_flags, Duration::from_millis(5)))
5198 {
5199 Ok(a) => {
5200 ret = a;
5201 break;
5202 }
5203 Err(Errno::Timedout) => {
5204 env.yield_now()?;
5205 continue;
5206 }
5207 Err(Errno::Again) => {
5208 env.sleep(Duration::from_millis(5))?;
5209 continue;
5210 }
5211 Err(err) => Err(err),
5212 }
5213 );
5214 }
5215 ret
5216 };
5217
5218 let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
5219
5220 let kind = Kind::Socket {
5221 socket: InodeSocket::new(InodeSocketKind::TcpStream(child)),
5222 };
5223 let inode = state.fs.create_inode_with_default_stat(
5224 inodes.deref_mut(),
5225 kind,
5226 false,
5227 "socket".to_string(),
5228 );
5229
5230 let rights = Rights::all_socket();
5231 let fd = wasi_try_ok!(state
5232 .fs
5233 .create_fd(rights, rights, Fdflags::empty(), 0, inode));
5234
5235 wasi_try_mem_ok!(ro_fd.write(&memory, fd));
5236 wasi_try_ok!(super::state::write_ip_port(
5237 &memory,
5238 ro_addr,
5239 addr.ip(),
5240 addr.port()
5241 ));
5242
5243 Ok(Errno::Success)
5244}
5245
5246pub fn sock_connect<M: MemorySize>(
5259 ctx: FunctionEnvMut<'_, WasiEnv>,
5260 sock: WasiFd,
5261 addr: WasmPtr<__wasi_addr_port_t, M>,
5262) -> Errno {
5263 debug!("wasi::sock_connect");
5264
5265 let env = ctx.data();
5266 let memory = env.memory_view(&ctx);
5267 let addr = wasi_try!(super::state::read_ip_port(&memory, addr));
5268 let addr = SocketAddr::new(addr.0, addr.1);
5269 wasi_try!(__sock_upgrade(&ctx, sock, Rights::SOCK_CONNECT, |socket| {
5270 socket.connect(env.net(), addr)
5271 }));
5272 Errno::Success
5273}
5274
5275pub fn sock_recv<M: MemorySize>(
5289 ctx: FunctionEnvMut<'_, WasiEnv>,
5290 sock: WasiFd,
5291 ri_data: WasmPtr<__wasi_iovec_t<M>, M>,
5292 ri_data_len: M::Offset,
5293 _ri_flags: RiFlags,
5294 ro_data_len: WasmPtr<M::Offset, M>,
5295 ro_flags: WasmPtr<RoFlags, M>,
5296) -> Result<Errno, WasiError> {
5297 debug!("wasi::sock_recv");
5298
5299 let env = ctx.data();
5300 let memory = env.memory_view(&ctx);
5301 let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len));
5302
5303 let bytes_read = wasi_try_ok!(__sock_actor_mut(&ctx, sock, Rights::SOCK_RECV, |socket| {
5304 socket.recv(&memory, iovs_arr)
5305 }));
5306 let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
5307
5308 wasi_try_mem_ok!(ro_flags.write(&memory, 0));
5309 wasi_try_mem_ok!(ro_data_len.write(&memory, bytes_read));
5310
5311 Ok(Errno::Success)
5312}
5313
5314pub fn sock_recv_from<M: MemorySize>(
5328 ctx: FunctionEnvMut<'_, WasiEnv>,
5329 sock: WasiFd,
5330 ri_data: WasmPtr<__wasi_iovec_t<M>, M>,
5331 ri_data_len: M::Offset,
5332 _ri_flags: RiFlags,
5333 ro_data_len: WasmPtr<M::Offset, M>,
5334 ro_flags: WasmPtr<RoFlags, M>,
5335 ro_addr: WasmPtr<__wasi_addr_port_t, M>,
5336) -> Result<Errno, WasiError> {
5337 debug!("wasi::sock_recv_from");
5338
5339 let env = ctx.data();
5340 let memory = env.memory_view(&ctx);
5341 let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len));
5342
5343 let bytes_read = wasi_try_ok!(__sock_actor_mut(
5344 &ctx,
5345 sock,
5346 Rights::SOCK_RECV_FROM,
5347 |socket| { socket.recv_from(&memory, iovs_arr, ro_addr) }
5348 ));
5349 let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
5350
5351 wasi_try_mem_ok!(ro_flags.write(&memory, 0));
5352 wasi_try_mem_ok!(ro_data_len.write(&memory, bytes_read));
5353
5354 Ok(Errno::Success)
5355}
5356
5357pub fn sock_send<M: MemorySize>(
5371 ctx: FunctionEnvMut<'_, WasiEnv>,
5372 sock: WasiFd,
5373 si_data: WasmPtr<__wasi_ciovec_t<M>, M>,
5374 si_data_len: M::Offset,
5375 _si_flags: SiFlags,
5376 ret_data_len: WasmPtr<M::Offset, M>,
5377) -> Result<Errno, WasiError> {
5378 debug!("wasi::sock_send");
5379 let env = ctx.data();
5380
5381 let memory = env.memory_view(&ctx);
5382 let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
5383
5384 let bytes_written = wasi_try_ok!(__sock_actor_mut(&ctx, sock, Rights::SOCK_SEND, |socket| {
5385 socket.send(&memory, iovs_arr)
5386 }));
5387
5388 let bytes_written: M::Offset =
5389 wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
5390 wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written));
5391
5392 Ok(Errno::Success)
5393}
5394
5395pub fn sock_send_to<M: MemorySize>(
5410 ctx: FunctionEnvMut<'_, WasiEnv>,
5411 sock: WasiFd,
5412 si_data: WasmPtr<__wasi_ciovec_t<M>, M>,
5413 si_data_len: M::Offset,
5414 _si_flags: SiFlags,
5415 addr: WasmPtr<__wasi_addr_port_t, M>,
5416 ret_data_len: WasmPtr<M::Offset, M>,
5417) -> Result<Errno, WasiError> {
5418 debug!("wasi::sock_send_to");
5419 let env = ctx.data();
5420
5421 let memory = env.memory_view(&ctx);
5422 let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
5423
5424 let bytes_written = wasi_try_ok!(__sock_actor_mut(
5425 &ctx,
5426 sock,
5427 Rights::SOCK_SEND_TO,
5428 |socket| { socket.send_to::<M>(&memory, iovs_arr, addr) }
5429 ));
5430
5431 let bytes_written: M::Offset =
5432 wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
5433 wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written as M::Offset));
5434
5435 Ok(Errno::Success)
5436}
5437
5438pub unsafe fn sock_send_file<M: MemorySize>(
5451 mut ctx: FunctionEnvMut<'_, WasiEnv>,
5452 sock: WasiFd,
5453 in_fd: WasiFd,
5454 offset: Filesize,
5455 mut count: Filesize,
5456 ret_sent: WasmPtr<Filesize, M>,
5457) -> Result<Errno, WasiError> {
5458 debug!("wasi::send_file");
5459 let env = ctx.data();
5460 let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
5461
5462 {
5464 let mut fd_map = state.fs.fd_map.write().unwrap();
5465 let fd_entry = wasi_try_ok!(fd_map.get_mut(&in_fd).ok_or(Errno::Badf));
5466 fd_entry.offset = offset as u64;
5467 }
5468
5469 let mut total_written: Filesize = 0;
5471 while (count > 0) {
5472 let mut buf = [0; 4096];
5473 let sub_count = count.min(4096);
5474 count -= sub_count;
5475
5476 let fd_entry = wasi_try_ok!(state.fs.get_fd(in_fd));
5477 let bytes_read = match in_fd {
5478 __WASI_STDIN_FILENO => {
5479 let mut guard = wasi_try_ok!(
5480 inodes
5481 .stdin_mut(&state.fs.fd_map)
5482 .map_err(fs_error_into_wasi_err),
5483 env
5484 );
5485 if let Some(ref mut stdin) = guard.deref_mut() {
5486 wasi_try_ok!(stdin.read(&mut buf).map_err(map_io_err))
5487 } else {
5488 return Ok(Errno::Badf);
5489 }
5490 }
5491 __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return Ok(Errno::Inval),
5492 _ => {
5493 if !fd_entry.rights.contains(Rights::FD_READ) {
5494 return Ok(Errno::Access);
5496 }
5497
5498 let offset = fd_entry.offset as usize;
5499 let inode_idx = fd_entry.inode;
5500 let inode = &inodes.arena[inode_idx];
5501
5502 let bytes_read = {
5503 let mut guard = inode.write();
5504 let deref_mut = guard.deref_mut();
5505 match deref_mut {
5506 Kind::File { handle, .. } => {
5507 if let Some(handle) = handle {
5508 wasi_try_ok!(
5509 handle
5510 .seek(std::io::SeekFrom::Start(offset as u64))
5511 .map_err(map_io_err),
5512 env
5513 );
5514 wasi_try_ok!(handle.read(&mut buf).map_err(map_io_err))
5515 } else {
5516 return Ok(Errno::Inval);
5517 }
5518 }
5519 Kind::Socket { socket } => {
5520 wasi_try_ok!(socket.read(&mut buf).map_err(map_io_err))
5521 }
5522 Kind::Pipe { pipe } => {
5523 wasi_try_ok!(pipe.read(&mut buf).map_err(map_io_err))
5524 }
5525 Kind::Dir { .. } | Kind::Root { .. } => {
5526 return Ok(Errno::Isdir);
5527 }
5528 Kind::EventNotifications { .. } => {
5529 return Ok(Errno::Inval);
5530 }
5531 Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
5532 Kind::Buffer { buffer } => {
5533 let mut buf_read = &buffer[offset..];
5534 wasi_try_ok!(buf_read.read(&mut buf).map_err(map_io_err))
5535 }
5536 }
5537 };
5538
5539 let mut fd_map = state.fs.fd_map.write().unwrap();
5541 let fd_entry = wasi_try_ok!(fd_map.get_mut(&in_fd).ok_or(Errno::Badf));
5542 fd_entry.offset += bytes_read as u64;
5543
5544 bytes_read
5545 }
5546 };
5547
5548 let bytes_written =
5550 wasi_try_ok!(__sock_actor_mut(&ctx, sock, Rights::SOCK_SEND, |socket| {
5551 let buf = (&buf[..]).to_vec();
5552 socket.send_bytes::<M>(Bytes::from(buf))
5553 }));
5554 total_written += bytes_written as u64;
5555 }
5556
5557 wasi_try_mem_ok!(ret_sent.write(&memory, total_written as Filesize));
5558
5559 Ok(Errno::Success)
5560}
5561
5562pub fn resolve<M: MemorySize>(
5581 ctx: FunctionEnvMut<'_, WasiEnv>,
5582 host: WasmPtr<u8, M>,
5583 host_len: M::Offset,
5584 port: u16,
5585 addrs: WasmPtr<__wasi_addr_t, M>,
5586 naddrs: M::Offset,
5587 ret_naddrs: WasmPtr<M::Offset, M>,
5588) -> Errno {
5589 debug!("wasi::resolve");
5590
5591 let naddrs: usize = wasi_try!(naddrs.try_into().map_err(|_| Errno::Inval));
5592 let env = ctx.data();
5593 let memory = env.memory_view(&ctx);
5594 let host_str = unsafe { get_input_str!(&memory, host, host_len) };
5595 let addrs = wasi_try_mem!(addrs.slice(&memory, wasi_try!(to_offset::<M>(naddrs))));
5596
5597 let port = if port > 0 { Some(port) } else { None };
5598
5599 let found_ips = wasi_try!(env
5600 .net()
5601 .resolve(host_str.as_str(), port, None)
5602 .map_err(net_error_into_wasi_err));
5603
5604 let mut idx = 0;
5605 for found_ip in found_ips.iter().take(naddrs) {
5606 super::state::write_ip(&memory, addrs.index(idx).as_ptr::<M>(), *found_ip);
5607 idx += 1;
5608 }
5609
5610 let idx: M::Offset = wasi_try!(idx.try_into().map_err(|_| Errno::Overflow));
5611 wasi_try_mem!(ret_naddrs.write(&memory, idx));
5612
5613 Errno::Success
5614}