1use io_uring::{opcode, types::*};
2use rustix::fs::{self, OFlags};
3
4use crate::{IourOpCode as OpCode, OpEntry, sys::op::*};
5
6unsafe impl<S: AsFd> OpCode for OpenFile<S> {
7 type Control = ();
8
9 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
10 opcode::OpenAt::new(Fd(self.dirfd.as_fd().as_raw_fd()), self.path.as_ptr())
11 .flags(self.flags.union(OFlags::CLOEXEC).bits() as _)
12 .mode(self.mode.bits())
13 .build()
14 .into()
15 }
16
17 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
18 self.call(control)
19 }
20
21 unsafe fn set_result(&mut self, _: &mut Self::Control, res: &io::Result<usize>, _: &Extra) {
22 if let Ok(fd) = res {
23 let fd = unsafe { OwnedFd::from_raw_fd(*fd as _) };
25 self.opened_fd = Some(fd);
26 }
27 }
28}
29
30unsafe impl OpCode for CloseFile {
31 type Control = ();
32
33 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
34 opcode::Close::new(Fd(self.fd.as_fd().as_raw_fd()))
35 .build()
36 .into()
37 }
38
39 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
40 self.call(control)
41 }
42}
43
44unsafe impl<T: IoBufMut> OpCode for GetXattr<T> {
45 type Control = ();
46
47 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
48 let slice = self.buffer.sys_slice_mut();
49 opcode::GetXattr::new(
50 self.name.as_ptr(),
51 slice.ptr().cast(),
52 self.path.as_ptr(),
53 slice.len().try_into().unwrap_or(u32::MAX),
54 )
55 .build()
56 .into()
57 }
58
59 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
60 self.call(control)
61 }
62}
63
64unsafe impl<S: AsFd, T: IoBufMut> OpCode for FGetXattr<S, T> {
65 type Control = ();
66
67 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
68 let slice = self.buffer.sys_slice_mut();
69 opcode::FGetXattr::new(
70 Fd(self.fd.as_fd().as_raw_fd()),
71 self.name.as_ptr(),
72 slice.ptr().cast(),
73 slice.len().try_into().unwrap_or(u32::MAX),
74 )
75 .build()
76 .into()
77 }
78
79 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
80 self.call(control)
81 }
82}
83
84unsafe impl<S: AsFd> OpCode for TruncateFile<S> {
85 type Control = ();
86
87 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
88 opcode::Ftruncate::new(Fd(self.fd.as_fd().as_raw_fd()), self.size)
89 .build()
90 .into()
91 }
92
93 fn call_blocking(&mut self, _: &mut Self::Control) -> io::Result<usize> {
94 self.call()
95 }
96}
97
98pub struct FileStat<S> {
100 pub(crate) fd: S,
101 pub(crate) stat: fs::Statx,
102}
103
104impl<S> FileStat<S> {
105 pub fn new(fd: S) -> Self {
107 Self {
108 fd,
109 stat: unsafe { std::mem::zeroed() },
110 }
111 }
112}
113
114unsafe impl<S: AsFd> OpCode for FileStat<S> {
115 type Control = ();
116
117 fn create_entry(&mut self, _control: &mut Self::Control) -> OpEntry {
118 static EMPTY_NAME: &[u8] = b"\0";
119 opcode::Statx::new(
120 Fd(self.fd.as_fd().as_fd().as_raw_fd()),
121 EMPTY_NAME.as_ptr().cast(),
122 &raw mut self.stat as _,
123 )
124 .flags(libc::AT_EMPTY_PATH)
125 .mask(STATX_MASK.bits())
126 .build()
127 .into()
128 }
129
130 fn call_blocking(&mut self, _control: &mut Self::Control) -> io::Result<usize> {
131 self.stat = pal::statx(self.fd.as_fd(), c"", false)?;
132
133 Ok(0)
134 }
135}
136
137impl<S> IntoInner for FileStat<S> {
138 type Inner = FileAttr;
139
140 fn into_inner(self) -> Self::Inner {
141 statx_to_attr(self.stat)
142 }
143}
144
145pub struct PathStat<S: AsFd> {
147 pub(crate) dirfd: S,
148 pub(crate) path: CString,
149 pub(crate) stat: fs::Statx,
150 pub(crate) follow_symlink: bool,
151}
152
153impl<S: AsFd> PathStat<S> {
154 pub fn new(dirfd: S, path: CString, follow_symlink: bool) -> Self {
156 Self {
157 dirfd,
158 path,
159 stat: unsafe { std::mem::zeroed() },
160 follow_symlink,
161 }
162 }
163}
164
165unsafe impl<S: AsFd> OpCode for PathStat<S> {
166 type Control = ();
167
168 fn create_entry(&mut self, _control: &mut Self::Control) -> OpEntry {
169 let mut flags = libc::AT_EMPTY_PATH;
170 if !self.follow_symlink {
171 flags |= libc::AT_SYMLINK_NOFOLLOW;
172 }
173 opcode::Statx::new(
174 Fd(self.dirfd.as_fd().as_raw_fd()),
175 self.path.as_ptr(),
176 &raw mut self.stat as _,
177 )
178 .flags(flags)
179 .mask(STATX_MASK.bits())
180 .build()
181 .into()
182 }
183
184 fn call_blocking(&mut self, _control: &mut Self::Control) -> io::Result<usize> {
185 self.stat = statx(self.dirfd.as_fd(), &self.path, self.follow_symlink)?;
186
187 Ok(0)
188 }
189}
190
191impl<S: AsFd> IntoInner for PathStat<S> {
192 type Inner = FileAttr;
193
194 fn into_inner(self) -> Self::Inner {
195 statx_to_attr(self.stat)
196 }
197}
198
199unsafe impl<S: AsFd> OpCode for Sync<S> {
200 type Control = ();
201
202 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
203 opcode::Fsync::new(Fd(self.fd.as_fd().as_raw_fd()))
204 .flags(if self.datasync {
205 FsyncFlags::DATASYNC
206 } else {
207 FsyncFlags::empty()
208 })
209 .build()
210 .into()
211 }
212}
213
214unsafe impl<S: AsFd> OpCode for Unlink<S> {
215 type Control = ();
216
217 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
218 opcode::UnlinkAt::new(Fd(self.dirfd.as_fd().as_raw_fd()), self.path.as_ptr())
219 .flags(if self.dir { libc::AT_REMOVEDIR } else { 0 })
220 .build()
221 .into()
222 }
223
224 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
225 self.call(control)
226 }
227}
228
229unsafe impl<S: AsFd> OpCode for CreateDir<S> {
230 type Control = ();
231
232 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
233 opcode::MkDirAt::new(Fd(self.dirfd.as_fd().as_raw_fd()), self.path.as_ptr())
234 .mode(self.mode.bits())
235 .build()
236 .into()
237 }
238
239 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
240 self.call(control)
241 }
242}
243
244unsafe impl<S1: AsFd, S2: AsFd> OpCode for Rename<S1, S2> {
245 type Control = ();
246
247 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
248 opcode::RenameAt::new(
249 Fd(self.old_dirfd.as_fd().as_raw_fd()),
250 self.old_path.as_ptr(),
251 Fd(self.new_dirfd.as_fd().as_raw_fd()),
252 self.new_path.as_ptr(),
253 )
254 .build()
255 .into()
256 }
257
258 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
259 self.call(control)
260 }
261}
262
263unsafe impl<S: AsFd> OpCode for Symlink<S> {
264 type Control = ();
265
266 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
267 opcode::SymlinkAt::new(
268 Fd(self.dirfd.as_fd().as_raw_fd()),
269 self.source.as_ptr(),
270 self.target.as_ptr(),
271 )
272 .build()
273 .into()
274 }
275
276 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
277 self.call(control)
278 }
279}
280
281unsafe impl<S1: AsFd, S2: AsFd> OpCode for HardLink<S1, S2> {
282 type Control = ();
283
284 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
285 opcode::LinkAt::new(
286 Fd(self.source_dirfd.as_fd().as_raw_fd()),
287 self.source.as_ptr(),
288 Fd(self.target_dirfd.as_fd().as_raw_fd()),
289 self.target.as_ptr(),
290 )
291 .build()
292 .into()
293 }
294
295 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
296 self.call(control)
297 }
298}
299
300unsafe impl<S1: AsFd, S2: AsFd> OpCode for Splice<S1, S2> {
301 type Control = ();
302
303 fn create_entry(&mut self, _: &mut Self::Control) -> OpEntry {
304 opcode::Splice::new(
305 Fd(self.fd_in.as_fd().as_raw_fd()),
306 self.offset_in,
307 Fd(self.fd_out.as_fd().as_raw_fd()),
308 self.offset_out,
309 self.len.try_into().unwrap_or(u32::MAX),
310 )
311 .flags(self.flags.bits())
312 .build()
313 .into()
314 }
315
316 fn call_blocking(&mut self, control: &mut Self::Control) -> io::Result<usize> {
317 self.call(control)
318 }
319}