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 let fd_entry = wasi_try_ok!(env.state.fs.get_fd(fd));
42 wasi_try_mem_ok!(new_offset_ref.write(new_offset));
43
44 trace!(
45 %new_offset,
46 );
47
48 Ok(Errno::Success)
49}
50
51pub(crate) fn fd_seek_internal(
52 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
53 fd: WasiFd,
54 offset: FileDelta,
55 whence: Whence,
56) -> Result<Result<Filesize, Errno>, WasiError> {
57 let env = ctx.data();
58 let state = env.state.clone();
59 let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
60 let fd_entry = wasi_try_ok_ok!(state.fs.get_fd(fd));
61
62 if !fd_entry.inner.rights.contains(Rights::FD_SEEK) {
63 return Ok(Err(Errno::Access));
64 }
65
66 let new_offset = match whence {
68 Whence::Cur => {
69 let mut fd_map = state.fs.fd_map.write().unwrap();
70 let fd_entry = wasi_try_ok_ok!(fd_map.get_mut(fd).ok_or(Errno::Badf));
71
72 #[allow(clippy::comparison_chain)]
73 if offset > 0 {
74 let offset = offset as u64;
75 fd_entry.offset.fetch_add(offset, Ordering::AcqRel) + offset
76 } else if offset < 0 {
77 let offset = offset.unsigned_abs();
78
79 wasi_try_ok_ok!(
80 fd_entry
81 .offset
82 .fetch_sub(offset, Ordering::AcqRel)
83 .checked_sub(offset)
84 .ok_or(Errno::Inval)
85 )
86 } else {
87 fd_entry.offset.load(Ordering::Acquire)
88 }
89 }
90 Whence::End => {
91 use std::io::SeekFrom;
92 let mut guard = fd_entry.inode.write();
93 let deref_mut = guard.deref_mut();
94 match deref_mut {
95 Kind::File { handle, .. } => {
96 #[allow(clippy::await_holding_lock)]
98 if let Some(handle) = handle {
99 let handle = handle.clone();
100 drop(guard);
101
102 wasi_try_ok_ok!(__asyncify(ctx, None, async move {
103 let mut handle = handle.write().unwrap();
104 let end = handle
105 .seek(SeekFrom::End(offset))
106 .await
107 .map_err(map_io_err)?;
108
109 drop(handle);
111 let mut fd_map = state.fs.fd_map.write().unwrap();
112 let fd_entry = fd_map.get_mut(fd).ok_or(Errno::Badf)?;
113 fd_entry.offset.store(end, Ordering::Release);
114 Ok(())
115 })?);
116 } else {
117 return Ok(Err(Errno::Inval));
118 }
119 }
120 Kind::Symlink { .. } => {
121 unimplemented!("wasi::fd_seek not implemented for symlinks")
122 }
123 Kind::Dir { .. }
124 | Kind::Root { .. }
125 | Kind::Socket { .. }
126 | Kind::PipeRx { .. }
127 | Kind::PipeTx { .. }
128 | Kind::DuplexPipe { .. }
129 | Kind::EventNotifications { .. }
130 | Kind::Epoll { .. } => {
131 return Ok(Err(Errno::Inval));
133 }
134 Kind::Buffer { .. } => {
135 return Ok(Err(Errno::Inval));
138 }
139 }
140 fd_entry.inner.offset.load(Ordering::Acquire)
141 }
142 Whence::Set => {
143 let mut fd_map = state.fs.fd_map.write().unwrap();
144 let fd_entry = wasi_try_ok_ok!(fd_map.get_mut(fd).ok_or(Errno::Badf));
145 let offset: u64 = wasi_try_ok_ok!(u64::try_from(offset).map_err(|_| Errno::Inval));
146
147 fd_entry.offset.store(offset, Ordering::Release);
148 offset
149 }
150 _ => return Ok(Err(Errno::Inval)),
151 };
152
153 Ok(Ok(new_offset))
154}