wasmer_wasix/syscalls/wasi/
fd_seek.rs1use super::*;
2use crate::syscalls::*;
3
4#[instrument(level = "trace", skip_all, fields(%fd, %offset, ?whence), ret)]
17pub fn fd_seek<M: MemorySize>(
18 mut ctx: FunctionEnvMut<'_, WasiEnv>,
19 fd: WasiFd,
20 offset: FileDelta,
21 whence: Whence,
22 newoffset: WasmPtr<Filesize, M>,
23) -> Result<Errno, WasiError> {
24 WasiEnv::do_pending_operations(&mut ctx)?;
25
26 let new_offset = wasi_try_ok!(fd_seek_internal(&mut ctx, fd, offset, whence)?);
27 let env = ctx.data();
28
29 #[cfg(feature = "journal")]
30 if env.enable_journal {
31 JournalEffector::save_fd_seek(&mut ctx, fd, offset, whence).map_err(|err| {
32 tracing::error!("failed to save file descriptor seek event - {}", err);
33 WasiError::Exit(ExitCode::from(Errno::Fault))
34 })?;
35 }
36
37 let env = ctx.data();
39 let memory = unsafe { env.memory_view(&ctx) };
40 let new_offset_ref = newoffset.deref(&memory);
41 wasi_try_mem_ok!(new_offset_ref.write(new_offset));
42
43 trace!(
44 %new_offset,
45 );
46
47 Ok(Errno::Success)
48}
49
50pub(crate) fn fd_seek_internal(
51 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
52 fd: WasiFd,
53 offset: FileDelta,
54 whence: Whence,
55) -> Result<Result<Filesize, Errno>, WasiError> {
56 let env = ctx.data();
57 let state = env.state.clone();
58 let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
59 let fd_entry = wasi_try_ok_ok!(state.fs.get_fd(fd));
60
61 if !fd_entry.inner.rights.contains(Rights::FD_SEEK) {
62 return Ok(Err(Errno::Access));
63 }
64
65 let new_offset = match whence {
67 Whence::Cur => {
68 let fd_offset = &fd_entry.inner.offset;
69
70 #[allow(clippy::comparison_chain)]
71 if offset > 0 {
72 let offset = offset as u64;
73 fd_offset.fetch_add(offset, Ordering::AcqRel) + offset
74 } else if offset < 0 {
75 let offset = offset.unsigned_abs();
76
77 wasi_try_ok_ok!(
78 fd_offset
79 .fetch_sub(offset, Ordering::AcqRel)
80 .checked_sub(offset)
81 .ok_or(Errno::Inval)
82 )
83 } else {
84 fd_offset.load(Ordering::Acquire)
85 }
86 }
87 Whence::End => {
88 use std::io::SeekFrom;
89 let mut guard = fd_entry.inode.write();
90 let deref_mut = guard.deref_mut();
91 match deref_mut {
92 Kind::File { handle, .. } => {
93 #[allow(clippy::await_holding_lock)]
95 if let Some(handle) = handle {
96 let handle = handle.clone();
97 let fd_offset = fd_entry.inner.offset.clone();
98 drop(guard);
99
100 wasi_try_ok_ok!(__asyncify(ctx, None, async move {
101 let mut handle = handle.write().unwrap();
102 let end = handle
103 .seek(SeekFrom::End(offset))
104 .await
105 .map_err(map_io_err)?;
106
107 fd_offset.store(end, Ordering::Release);
110 Ok(())
111 })?);
112 } else {
113 return Ok(Err(Errno::Inval));
114 }
115 }
116 Kind::Symlink { .. } => {
117 unimplemented!("wasi::fd_seek not implemented for symlinks")
118 }
119 Kind::Dir { .. }
120 | Kind::Root { .. }
121 | Kind::Socket { .. }
122 | Kind::PipeRx { .. }
123 | Kind::PipeTx { .. }
124 | Kind::DuplexPipe { .. }
125 | Kind::EventNotifications { .. }
126 | Kind::Epoll { .. } => {
127 return Ok(Err(Errno::Inval));
129 }
130 Kind::Buffer { .. } => {
131 return Ok(Err(Errno::Inval));
134 }
135 }
136 fd_entry.inner.offset.load(Ordering::Acquire)
137 }
138 Whence::Set => {
139 let offset: u64 = wasi_try_ok_ok!(u64::try_from(offset).map_err(|_| Errno::Inval));
140
141 fd_entry.inner.offset.store(offset, Ordering::Release);
142 offset
143 }
144 _ => return Ok(Err(Errno::Inval)),
145 };
146
147 Ok(Ok(new_offset))
148}