compio_driver/unix/
op.rs

1use std::{ffi::CString, marker::PhantomPinned, net::Shutdown, os::fd::OwnedFd};
2
3use compio_buf::{
4    IntoInner, IoBuf, IoBufMut, IoSlice, IoSliceMut, IoVectoredBuf, IoVectoredBufMut,
5};
6use libc::{sockaddr_storage, socklen_t};
7use socket2::SockAddr;
8
9use crate::{SharedFd, op::*};
10
11/// Open or create a file with flags and mode.
12pub struct OpenFile {
13    pub(crate) path: CString,
14    pub(crate) flags: i32,
15    pub(crate) mode: libc::mode_t,
16}
17
18impl OpenFile {
19    /// Create [`OpenFile`].
20    pub fn new(path: CString, flags: i32, mode: libc::mode_t) -> Self {
21        Self { path, flags, mode }
22    }
23}
24
25#[cfg(gnulinux)]
26pub(crate) type Statx = libc::statx;
27
28#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
29#[repr(C)]
30pub(crate) struct StatxTimestamp {
31    pub tv_sec: i64,
32    pub tv_nsec: u32,
33    pub __statx_timestamp_pad1: [i32; 1],
34}
35
36#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
37#[repr(C)]
38pub(crate) struct Statx {
39    pub stx_mask: u32,
40    pub stx_blksize: u32,
41    pub stx_attributes: u64,
42    pub stx_nlink: u32,
43    pub stx_uid: u32,
44    pub stx_gid: u32,
45    pub stx_mode: u16,
46    __statx_pad1: [u16; 1],
47    pub stx_ino: u64,
48    pub stx_size: u64,
49    pub stx_blocks: u64,
50    pub stx_attributes_mask: u64,
51    pub stx_atime: StatxTimestamp,
52    pub stx_btime: StatxTimestamp,
53    pub stx_ctime: StatxTimestamp,
54    pub stx_mtime: StatxTimestamp,
55    pub stx_rdev_major: u32,
56    pub stx_rdev_minor: u32,
57    pub stx_dev_major: u32,
58    pub stx_dev_minor: u32,
59    pub stx_mnt_id: u64,
60    pub stx_dio_mem_align: u32,
61    pub stx_dio_offset_align: u32,
62    __statx_pad3: [u64; 12],
63}
64
65#[cfg(target_os = "linux")]
66pub(crate) const fn statx_to_stat(statx: Statx) -> libc::stat {
67    let mut stat: libc::stat = unsafe { std::mem::zeroed() };
68    stat.st_dev = libc::makedev(statx.stx_dev_major, statx.stx_dev_minor);
69    stat.st_ino = statx.stx_ino;
70    stat.st_nlink = statx.stx_nlink as _;
71    stat.st_mode = statx.stx_mode as _;
72    stat.st_uid = statx.stx_uid;
73    stat.st_gid = statx.stx_gid;
74    stat.st_rdev = libc::makedev(statx.stx_rdev_major, statx.stx_rdev_minor);
75    stat.st_size = statx.stx_size as _;
76    stat.st_blksize = statx.stx_blksize as _;
77    stat.st_blocks = statx.stx_blocks as _;
78    stat.st_atime = statx.stx_atime.tv_sec;
79    stat.st_atime_nsec = statx.stx_atime.tv_nsec as _;
80    stat.st_mtime = statx.stx_mtime.tv_sec;
81    stat.st_mtime_nsec = statx.stx_mtime.tv_nsec as _;
82    stat.st_ctime = statx.stx_btime.tv_sec;
83    stat.st_ctime_nsec = statx.stx_btime.tv_nsec as _;
84    stat
85}
86
87/// Read a file at specified position into vectored buffer.
88pub struct ReadVectoredAt<T: IoVectoredBufMut, S> {
89    pub(crate) fd: SharedFd<S>,
90    pub(crate) offset: u64,
91    pub(crate) buffer: T,
92    pub(crate) slices: Vec<IoSliceMut>,
93    #[cfg(freebsd)]
94    pub(crate) aiocb: libc::aiocb,
95    _p: PhantomPinned,
96}
97
98impl<T: IoVectoredBufMut, S> ReadVectoredAt<T, S> {
99    /// Create [`ReadVectoredAt`].
100    pub fn new(fd: SharedFd<S>, offset: u64, buffer: T) -> Self {
101        Self {
102            fd,
103            offset,
104            buffer,
105            slices: vec![],
106            #[cfg(freebsd)]
107            aiocb: unsafe { std::mem::zeroed() },
108            _p: PhantomPinned,
109        }
110    }
111}
112
113impl<T: IoVectoredBufMut, S> IntoInner for ReadVectoredAt<T, S> {
114    type Inner = T;
115
116    fn into_inner(self) -> Self::Inner {
117        self.buffer
118    }
119}
120
121/// Write a file at specified position from vectored buffer.
122pub struct WriteVectoredAt<T: IoVectoredBuf, S> {
123    pub(crate) fd: SharedFd<S>,
124    pub(crate) offset: u64,
125    pub(crate) buffer: T,
126    pub(crate) slices: Vec<IoSlice>,
127    #[cfg(freebsd)]
128    pub(crate) aiocb: libc::aiocb,
129    _p: PhantomPinned,
130}
131
132impl<T: IoVectoredBuf, S> WriteVectoredAt<T, S> {
133    /// Create [`WriteVectoredAt`]
134    pub fn new(fd: SharedFd<S>, offset: u64, buffer: T) -> Self {
135        Self {
136            fd,
137            offset,
138            buffer,
139            slices: vec![],
140            #[cfg(freebsd)]
141            aiocb: unsafe { std::mem::zeroed() },
142            _p: PhantomPinned,
143        }
144    }
145}
146
147impl<T: IoVectoredBuf, S> IntoInner for WriteVectoredAt<T, S> {
148    type Inner = T;
149
150    fn into_inner(self) -> Self::Inner {
151        self.buffer
152    }
153}
154
155/// Remove file or directory.
156pub struct Unlink {
157    pub(crate) path: CString,
158    pub(crate) dir: bool,
159}
160
161impl Unlink {
162    /// Create [`Unlink`].
163    pub fn new(path: CString, dir: bool) -> Self {
164        Self { path, dir }
165    }
166}
167
168/// Create a directory.
169pub struct CreateDir {
170    pub(crate) path: CString,
171    pub(crate) mode: libc::mode_t,
172}
173
174impl CreateDir {
175    /// Create [`CreateDir`].
176    pub fn new(path: CString, mode: libc::mode_t) -> Self {
177        Self { path, mode }
178    }
179}
180
181/// Rename a file or directory.
182pub struct Rename {
183    pub(crate) old_path: CString,
184    pub(crate) new_path: CString,
185}
186
187impl Rename {
188    /// Create [`Rename`].
189    pub fn new(old_path: CString, new_path: CString) -> Self {
190        Self { old_path, new_path }
191    }
192}
193
194/// Create a symlink.
195pub struct Symlink {
196    pub(crate) source: CString,
197    pub(crate) target: CString,
198}
199
200impl Symlink {
201    /// Create [`Symlink`]. `target` is a symlink to `source`.
202    pub fn new(source: CString, target: CString) -> Self {
203        Self { source, target }
204    }
205}
206
207/// Create a hard link.
208pub struct HardLink {
209    pub(crate) source: CString,
210    pub(crate) target: CString,
211}
212
213impl HardLink {
214    /// Create [`HardLink`]. `target` is a hard link to `source`.
215    pub fn new(source: CString, target: CString) -> Self {
216        Self { source, target }
217    }
218}
219
220/// Create a socket.
221pub struct CreateSocket {
222    pub(crate) domain: i32,
223    pub(crate) socket_type: i32,
224    pub(crate) protocol: i32,
225}
226
227impl CreateSocket {
228    /// Create [`CreateSocket`].
229    pub fn new(domain: i32, socket_type: i32, protocol: i32) -> Self {
230        Self {
231            domain,
232            socket_type,
233            protocol,
234        }
235    }
236}
237
238impl<S> ShutdownSocket<S> {
239    pub(crate) fn how(&self) -> i32 {
240        match self.how {
241            Shutdown::Write => libc::SHUT_WR,
242            Shutdown::Read => libc::SHUT_RD,
243            Shutdown::Both => libc::SHUT_RDWR,
244        }
245    }
246}
247
248/// Accept a connection.
249pub struct Accept<S> {
250    pub(crate) fd: SharedFd<S>,
251    pub(crate) buffer: sockaddr_storage,
252    pub(crate) addr_len: socklen_t,
253    pub(crate) accepted_fd: Option<OwnedFd>,
254    _p: PhantomPinned,
255}
256
257impl<S> Accept<S> {
258    /// Create [`Accept`].
259    pub fn new(fd: SharedFd<S>) -> Self {
260        Self {
261            fd,
262            buffer: unsafe { std::mem::zeroed() },
263            addr_len: std::mem::size_of::<sockaddr_storage>() as _,
264            accepted_fd: None,
265            _p: PhantomPinned,
266        }
267    }
268
269    /// Get the remote address from the inner buffer.
270    pub fn into_addr(mut self) -> SockAddr {
271        std::mem::forget(self.accepted_fd.take());
272        unsafe { SockAddr::new(self.buffer, self.addr_len) }
273    }
274}
275
276/// Receive data from remote.
277pub struct Recv<T: IoBufMut, S> {
278    pub(crate) fd: SharedFd<S>,
279    pub(crate) buffer: T,
280    _p: PhantomPinned,
281}
282
283impl<T: IoBufMut, S> Recv<T, S> {
284    /// Create [`Recv`].
285    pub fn new(fd: SharedFd<S>, buffer: T) -> Self {
286        Self {
287            fd,
288            buffer,
289            _p: PhantomPinned,
290        }
291    }
292}
293
294impl<T: IoBufMut, S> IntoInner for Recv<T, S> {
295    type Inner = T;
296
297    fn into_inner(self) -> Self::Inner {
298        self.buffer
299    }
300}
301
302/// Receive data from remote into vectored buffer.
303pub struct RecvVectored<T: IoVectoredBufMut, S> {
304    pub(crate) fd: SharedFd<S>,
305    pub(crate) buffer: T,
306    pub(crate) slices: Vec<IoSliceMut>,
307    _p: PhantomPinned,
308}
309
310impl<T: IoVectoredBufMut, S> RecvVectored<T, S> {
311    /// Create [`RecvVectored`].
312    pub fn new(fd: SharedFd<S>, buffer: T) -> Self {
313        Self {
314            fd,
315            buffer,
316            slices: vec![],
317            _p: PhantomPinned,
318        }
319    }
320}
321
322impl<T: IoVectoredBufMut, S> IntoInner for RecvVectored<T, S> {
323    type Inner = T;
324
325    fn into_inner(self) -> Self::Inner {
326        self.buffer
327    }
328}
329
330/// Send data to remote.
331pub struct Send<T: IoBuf, S> {
332    pub(crate) fd: SharedFd<S>,
333    pub(crate) buffer: T,
334    _p: PhantomPinned,
335}
336
337impl<T: IoBuf, S> Send<T, S> {
338    /// Create [`Send`].
339    pub fn new(fd: SharedFd<S>, buffer: T) -> Self {
340        Self {
341            fd,
342            buffer,
343            _p: PhantomPinned,
344        }
345    }
346}
347
348impl<T: IoBuf, S> IntoInner for Send<T, S> {
349    type Inner = T;
350
351    fn into_inner(self) -> Self::Inner {
352        self.buffer
353    }
354}
355
356/// Send data to remote from vectored buffer.
357pub struct SendVectored<T: IoVectoredBuf, S> {
358    pub(crate) fd: SharedFd<S>,
359    pub(crate) buffer: T,
360    pub(crate) slices: Vec<IoSlice>,
361    _p: PhantomPinned,
362}
363
364impl<T: IoVectoredBuf, S> SendVectored<T, S> {
365    /// Create [`SendVectored`].
366    pub fn new(fd: SharedFd<S>, buffer: T) -> Self {
367        Self {
368            fd,
369            buffer,
370            slices: vec![],
371            _p: PhantomPinned,
372        }
373    }
374}
375
376impl<T: IoVectoredBuf, S> IntoInner for SendVectored<T, S> {
377    type Inner = T;
378
379    fn into_inner(self) -> Self::Inner {
380        self.buffer
381    }
382}
383
384/// Receive data and source address with ancillary data into vectored buffer.
385pub struct RecvMsg<T: IoVectoredBufMut, C: IoBufMut, S> {
386    pub(crate) msg: libc::msghdr,
387    pub(crate) addr: sockaddr_storage,
388    pub(crate) fd: SharedFd<S>,
389    pub(crate) buffer: T,
390    pub(crate) control: C,
391    pub(crate) slices: Vec<IoSliceMut>,
392    _p: PhantomPinned,
393}
394
395impl<T: IoVectoredBufMut, C: IoBufMut, S> RecvMsg<T, C, S> {
396    /// Create [`RecvMsg`].
397    ///
398    /// # Panics
399    ///
400    /// This function will panic if the control message buffer is misaligned.
401    pub fn new(fd: SharedFd<S>, buffer: T, control: C) -> Self {
402        assert!(
403            control.as_buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
404            "misaligned control message buffer"
405        );
406        Self {
407            addr: unsafe { std::mem::zeroed() },
408            msg: unsafe { std::mem::zeroed() },
409            fd,
410            buffer,
411            control,
412            slices: vec![],
413            _p: PhantomPinned,
414        }
415    }
416
417    pub(crate) unsafe fn set_msg(&mut self) {
418        self.slices = self.buffer.io_slices_mut();
419
420        self.msg.msg_name = std::ptr::addr_of_mut!(self.addr) as _;
421        self.msg.msg_namelen = std::mem::size_of_val(&self.addr) as _;
422        self.msg.msg_iov = self.slices.as_mut_ptr() as _;
423        self.msg.msg_iovlen = self.slices.len() as _;
424        self.msg.msg_control = self.control.as_buf_mut_ptr() as _;
425        self.msg.msg_controllen = self.control.buf_capacity() as _;
426    }
427}
428
429impl<T: IoVectoredBufMut, C: IoBufMut, S> IntoInner for RecvMsg<T, C, S> {
430    type Inner = ((T, C), sockaddr_storage, socklen_t, usize);
431
432    fn into_inner(self) -> Self::Inner {
433        (
434            (self.buffer, self.control),
435            self.addr,
436            self.msg.msg_namelen,
437            self.msg.msg_controllen as _,
438        )
439    }
440}
441
442/// Send data to specified address accompanied by ancillary data from vectored
443/// buffer.
444pub struct SendMsg<T: IoVectoredBuf, C: IoBuf, S> {
445    pub(crate) msg: libc::msghdr,
446    pub(crate) fd: SharedFd<S>,
447    pub(crate) buffer: T,
448    pub(crate) control: C,
449    pub(crate) addr: SockAddr,
450    pub(crate) slices: Vec<IoSlice>,
451    _p: PhantomPinned,
452}
453
454impl<T: IoVectoredBuf, C: IoBuf, S> SendMsg<T, C, S> {
455    /// Create [`SendMsg`].
456    ///
457    /// # Panics
458    ///
459    /// This function will panic if the control message buffer is misaligned.
460    pub fn new(fd: SharedFd<S>, buffer: T, control: C, addr: SockAddr) -> Self {
461        assert!(
462            control.as_buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
463            "misaligned control message buffer"
464        );
465        Self {
466            msg: unsafe { std::mem::zeroed() },
467            fd,
468            buffer,
469            control,
470            addr,
471            slices: vec![],
472            _p: PhantomPinned,
473        }
474    }
475
476    pub(crate) unsafe fn set_msg(&mut self) {
477        self.slices = self.buffer.io_slices();
478
479        self.msg.msg_name = self.addr.as_ptr() as _;
480        self.msg.msg_namelen = self.addr.len();
481        self.msg.msg_iov = self.slices.as_ptr() as _;
482        self.msg.msg_iovlen = self.slices.len() as _;
483        self.msg.msg_control = self.control.as_buf_ptr() as _;
484        self.msg.msg_controllen = self.control.buf_len() as _;
485    }
486}
487
488impl<T: IoVectoredBuf, C: IoBuf, S> IntoInner for SendMsg<T, C, S> {
489    type Inner = (T, C);
490
491    fn into_inner(self) -> Self::Inner {
492        (self.buffer, self.control)
493    }
494}
495
496/// The interest to poll a file descriptor.
497#[derive(Debug, Clone, Copy, PartialEq, Eq)]
498pub enum Interest {
499    /// Represents a read operation.
500    Readable,
501    /// Represents a write operation.
502    Writable,
503}
504
505/// Poll a file descriptor for specified [`Interest`].
506pub struct PollOnce<S> {
507    pub(crate) fd: SharedFd<S>,
508    pub(crate) interest: Interest,
509}
510
511impl<S> PollOnce<S> {
512    /// Create [`PollOnce`].
513    pub fn new(fd: SharedFd<S>, interest: Interest) -> Self {
514        Self { fd, interest }
515    }
516}