Skip to main content

compio_driver/sys/
unix_op.rs

1use std::{
2    ffi::CString,
3    io,
4    marker::PhantomPinned,
5    net::Shutdown,
6    os::fd::{AsFd, AsRawFd, OwnedFd},
7    pin::Pin,
8};
9
10use compio_buf::{IntoInner, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
11#[cfg(not(gnulinux))]
12use libc::open;
13#[cfg(gnulinux)]
14use libc::open64 as open;
15#[cfg(not(any(
16    all(target_os = "linux", not(target_env = "musl")),
17    target_os = "android",
18    target_os = "l4re",
19    target_os = "hurd"
20)))]
21use libc::{ftruncate as ftruncate64, off_t as off64_t};
22#[cfg(any(
23    all(target_os = "linux", not(target_env = "musl")),
24    target_os = "android",
25    target_os = "l4re",
26    target_os = "hurd"
27))]
28use libc::{ftruncate64, off64_t};
29use pin_project_lite::pin_project;
30use socket2::{SockAddr, SockAddrStorage, socklen_t};
31
32use crate::{op::*, sys::aio::*, sys_slice::*, syscall};
33
34/// Open or create a file with flags and mode.
35pub struct OpenFile {
36    pub(crate) path: CString,
37    pub(crate) flags: i32,
38    pub(crate) mode: libc::mode_t,
39}
40
41impl OpenFile {
42    /// Create [`OpenFile`].
43    pub fn new(path: CString, flags: i32, mode: libc::mode_t) -> Self {
44        Self { path, flags, mode }
45    }
46
47    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
48        Ok(syscall!(open(
49            self.path.as_ptr(),
50            self.flags | libc::O_CLOEXEC,
51            self.mode as libc::c_int
52        ))? as _)
53    }
54}
55
56impl CloseFile {
57    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
58        Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
59    }
60}
61
62#[derive(Debug)]
63///  Truncates or extends the underlying file, updating the size of this file to
64/// become `size`.
65pub struct TruncateFile<S: AsFd> {
66    pub(crate) fd: S,
67    pub(crate) size: u64,
68}
69
70impl<S: AsFd> TruncateFile<S> {
71    /// Create [`TruncateFile`].
72    pub fn new(fd: S, size: u64) -> Self {
73        Self { fd, size }
74    }
75
76    pub(crate) fn call(&self) -> io::Result<usize> {
77        let size: off64_t = self
78            .size
79            .try_into()
80            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
81        crate::syscall!(ftruncate64(self.fd.as_fd().as_raw_fd(), size)).map(|v| v as _)
82    }
83}
84
85#[cfg(not(gnulinux))]
86pub use libc::stat as Stat;
87#[cfg(gnulinux)]
88pub use libc::stat64 as Stat;
89#[cfg(gnulinux)]
90pub(crate) use libc::statx as Statx;
91
92#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
93#[repr(C)]
94pub(crate) struct StatxTimestamp {
95    pub tv_sec: i64,
96    pub tv_nsec: u32,
97    pub __statx_timestamp_pad1: [i32; 1],
98}
99
100#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
101#[repr(C)]
102pub(crate) struct Statx {
103    pub stx_mask: u32,
104    pub stx_blksize: u32,
105    pub stx_attributes: u64,
106    pub stx_nlink: u32,
107    pub stx_uid: u32,
108    pub stx_gid: u32,
109    pub stx_mode: u16,
110    __statx_pad1: [u16; 1],
111    pub stx_ino: u64,
112    pub stx_size: u64,
113    pub stx_blocks: u64,
114    pub stx_attributes_mask: u64,
115    pub stx_atime: StatxTimestamp,
116    pub stx_btime: StatxTimestamp,
117    pub stx_ctime: StatxTimestamp,
118    pub stx_mtime: StatxTimestamp,
119    pub stx_rdev_major: u32,
120    pub stx_rdev_minor: u32,
121    pub stx_dev_major: u32,
122    pub stx_dev_minor: u32,
123    pub stx_mnt_id: u64,
124    pub stx_dio_mem_align: u32,
125    pub stx_dio_offset_align: u32,
126    __statx_pad3: [u64; 12],
127}
128
129#[cfg(target_os = "linux")]
130pub(crate) const fn statx_mask() -> u32 {
131    // Set mask to ensure all known fields are filled
132    libc::STATX_TYPE
133        | libc::STATX_MODE
134        | libc::STATX_NLINK
135        | libc::STATX_UID
136        | libc::STATX_GID
137        | libc::STATX_ATIME
138        | libc::STATX_MTIME
139        | libc::STATX_CTIME
140        | libc::STATX_INO
141        | libc::STATX_SIZE
142        | libc::STATX_BLOCKS
143        | libc::STATX_BTIME
144        | libc::STATX_MNT_ID
145        | libc::STATX_DIOALIGN
146}
147
148#[cfg(target_os = "linux")]
149pub(crate) const fn statx_to_stat(statx: Statx) -> Stat {
150    let mut stat: Stat = unsafe { std::mem::zeroed() };
151    stat.st_dev = libc::makedev(statx.stx_dev_major, statx.stx_dev_minor) as _;
152    stat.st_ino = statx.stx_ino as _;
153    stat.st_nlink = statx.stx_nlink as _;
154    stat.st_mode = statx.stx_mode as _;
155    stat.st_uid = statx.stx_uid as _;
156    stat.st_gid = statx.stx_gid as _;
157    stat.st_rdev = libc::makedev(statx.stx_rdev_major, statx.stx_rdev_minor) as _;
158    stat.st_size = statx.stx_size as _;
159    stat.st_blksize = statx.stx_blksize as _;
160    stat.st_blocks = statx.stx_blocks as _;
161    stat.st_atime = statx.stx_atime.tv_sec as _;
162    stat.st_atime_nsec = statx.stx_atime.tv_nsec as _;
163    stat.st_mtime = statx.stx_mtime.tv_sec as _;
164    stat.st_mtime_nsec = statx.stx_mtime.tv_nsec as _;
165    stat.st_ctime = statx.stx_btime.tv_sec as _;
166    stat.st_ctime_nsec = statx.stx_btime.tv_nsec as _;
167    stat
168}
169
170pin_project! {
171    /// Read a file at specified position into vectored buffer.
172    pub struct ReadVectoredAt<T: IoVectoredBufMut, S> {
173        pub(crate) fd: S,
174        pub(crate) offset: u64,
175        #[pin]
176        pub(crate) buffer: T,
177        pub(crate) slices: Vec<SysSlice>,
178        pub(crate) aiocb: aiocb,
179        _p: PhantomPinned,
180    }
181}
182
183impl<T: IoVectoredBufMut, S> ReadVectoredAt<T, S> {
184    /// Create [`ReadVectoredAt`].
185    pub fn new(fd: S, offset: u64, buffer: T) -> Self {
186        Self {
187            fd,
188            offset,
189            buffer,
190            slices: vec![],
191            aiocb: new_aiocb(),
192            _p: PhantomPinned,
193        }
194    }
195}
196
197impl<T: IoVectoredBufMut, S> IntoInner for ReadVectoredAt<T, S> {
198    type Inner = T;
199
200    fn into_inner(self) -> Self::Inner {
201        self.buffer
202    }
203}
204
205pin_project! {
206    /// Write a file at specified position from vectored buffer.
207    pub struct WriteVectoredAt<T: IoVectoredBuf, S> {
208        pub(crate) fd: S,
209        pub(crate) offset: u64,
210        #[pin]
211        pub(crate) buffer: T,
212        pub(crate) slices: Vec<SysSlice>,
213        pub(crate) aiocb: aiocb,
214        _p: PhantomPinned,
215    }
216}
217impl<T: IoVectoredBuf, S> WriteVectoredAt<T, S> {
218    /// Create [`WriteVectoredAt`]
219    pub fn new(fd: S, offset: u64, buffer: T) -> Self {
220        Self {
221            fd,
222            offset,
223            buffer,
224            slices: vec![],
225            aiocb: new_aiocb(),
226            _p: PhantomPinned,
227        }
228    }
229}
230
231impl<T: IoVectoredBuf, S> IntoInner for WriteVectoredAt<T, S> {
232    type Inner = T;
233
234    fn into_inner(self) -> Self::Inner {
235        self.buffer
236    }
237}
238
239pin_project! {
240    /// Receive a file into vectored buffer.
241    pub struct ReadVectored<T: IoVectoredBufMut, S> {
242        pub(crate) fd: S,
243        #[pin]
244        pub(crate) buffer: T,
245        pub(crate) slices: Vec<SysSlice>,
246        _p: PhantomPinned,
247    }
248}
249
250impl<T: IoVectoredBufMut, S> ReadVectored<T, S> {
251    /// Create [`ReadVectored`].
252    pub fn new(fd: S, buffer: T) -> Self {
253        Self {
254            fd,
255            buffer,
256            slices: vec![],
257            _p: PhantomPinned,
258        }
259    }
260}
261
262impl<T: IoVectoredBufMut, S> IntoInner for ReadVectored<T, S> {
263    type Inner = T;
264
265    fn into_inner(self) -> Self::Inner {
266        self.buffer
267    }
268}
269
270pin_project! {
271    /// Send to a file from vectored buffer.
272    pub struct WriteVectored<T: IoVectoredBuf, S> {
273        pub(crate) fd: S,
274        #[pin]
275        pub(crate) buffer: T,
276        pub(crate) slices: Vec<SysSlice>,
277        _p: PhantomPinned,
278    }
279}
280
281impl<T: IoVectoredBuf, S> WriteVectored<T, S> {
282    /// Create [`WriteVectored`].
283    pub fn new(fd: S, buffer: T) -> Self {
284        Self {
285            fd,
286            buffer,
287            slices: vec![],
288            _p: PhantomPinned,
289        }
290    }
291}
292
293impl<T: IoVectoredBuf, S> IntoInner for WriteVectored<T, S> {
294    type Inner = T;
295
296    fn into_inner(self) -> Self::Inner {
297        self.buffer
298    }
299}
300
301/// Remove file or directory.
302pub struct Unlink {
303    pub(crate) path: CString,
304    pub(crate) dir: bool,
305}
306
307impl Unlink {
308    /// Create [`Unlink`].
309    pub fn new(path: CString, dir: bool) -> Self {
310        Self { path, dir }
311    }
312
313    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
314        if self.dir {
315            Ok(syscall!(libc::rmdir(self.path.as_ptr()))? as _)
316        } else {
317            Ok(syscall!(libc::unlink(self.path.as_ptr()))? as _)
318        }
319    }
320}
321
322/// Create a directory.
323pub struct CreateDir {
324    pub(crate) path: CString,
325    pub(crate) mode: libc::mode_t,
326}
327
328impl CreateDir {
329    /// Create [`CreateDir`].
330    pub fn new(path: CString, mode: libc::mode_t) -> Self {
331        Self { path, mode }
332    }
333
334    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
335        Ok(syscall!(libc::mkdir(self.path.as_ptr(), self.mode))? as _)
336    }
337}
338
339/// Rename a file or directory.
340pub struct Rename {
341    pub(crate) old_path: CString,
342    pub(crate) new_path: CString,
343}
344
345impl Rename {
346    /// Create [`Rename`].
347    pub fn new(old_path: CString, new_path: CString) -> Self {
348        Self { old_path, new_path }
349    }
350
351    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
352        Ok(syscall!(libc::rename(self.old_path.as_ptr(), self.new_path.as_ptr()))? as _)
353    }
354}
355
356/// Create a symlink.
357pub struct Symlink {
358    pub(crate) source: CString,
359    pub(crate) target: CString,
360}
361
362impl Symlink {
363    /// Create [`Symlink`]. `target` is a symlink to `source`.
364    pub fn new(source: CString, target: CString) -> Self {
365        Self { source, target }
366    }
367
368    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
369        Ok(syscall!(libc::symlink(self.source.as_ptr(), self.target.as_ptr()))? as _)
370    }
371}
372
373/// Create a hard link.
374pub struct HardLink {
375    pub(crate) source: CString,
376    pub(crate) target: CString,
377}
378
379impl HardLink {
380    /// Create [`HardLink`]. `target` is a hard link to `source`.
381    pub fn new(source: CString, target: CString) -> Self {
382        Self { source, target }
383    }
384
385    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
386        Ok(syscall!(libc::link(self.source.as_ptr(), self.target.as_ptr()))? as _)
387    }
388}
389
390/// Create a socket.
391pub struct CreateSocket {
392    pub(crate) domain: i32,
393    pub(crate) socket_type: i32,
394    pub(crate) protocol: i32,
395}
396
397impl CreateSocket {
398    /// Create [`CreateSocket`].
399    pub fn new(domain: i32, socket_type: i32, protocol: i32) -> Self {
400        Self {
401            domain,
402            socket_type,
403            protocol,
404        }
405    }
406}
407
408impl<S: AsFd> ShutdownSocket<S> {
409    pub(crate) fn how(&self) -> i32 {
410        match self.how {
411            Shutdown::Write => libc::SHUT_WR,
412            Shutdown::Read => libc::SHUT_RD,
413            Shutdown::Both => libc::SHUT_RDWR,
414        }
415    }
416
417    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
418        Ok(syscall!(libc::shutdown(self.fd.as_fd().as_raw_fd(), self.how()))? as _)
419    }
420}
421
422impl CloseSocket {
423    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
424        Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
425    }
426}
427
428pin_project! {
429    /// Accept a connection.
430    pub struct Accept<S> {
431        pub(crate) fd: S,
432        pub(crate) buffer: SockAddrStorage,
433        pub(crate) addr_len: socklen_t,
434        pub(crate) accepted_fd: Option<OwnedFd>,
435        _p: PhantomPinned,
436    }
437}
438
439impl<S> Accept<S> {
440    /// Create [`Accept`].
441    pub fn new(fd: S) -> Self {
442        let buffer = SockAddrStorage::zeroed();
443        let addr_len = buffer.size_of();
444        Self {
445            fd,
446            buffer,
447            addr_len,
448            accepted_fd: None,
449            _p: PhantomPinned,
450        }
451    }
452
453    /// Get the remote address from the inner buffer.
454    pub fn into_addr(mut self) -> SockAddr {
455        std::mem::forget(self.accepted_fd.take());
456        unsafe { SockAddr::new(self.buffer, self.addr_len) }
457    }
458}
459
460pin_project! {
461    /// Receive data from remote.
462    ///
463    /// It is only used for socket operations. If you want to read from a pipe, use
464    /// [`Read`].
465    pub struct Recv<T: IoBufMut, S> {
466        pub(crate) fd: S,
467        #[pin]
468        pub(crate) buffer: T,
469        pub(crate) flags: i32,
470        _p: PhantomPinned,
471    }
472}
473
474impl<T: IoBufMut, S> Recv<T, S> {
475    /// Create [`Recv`].
476    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
477        Self {
478            fd,
479            buffer,
480            flags,
481            _p: PhantomPinned,
482        }
483    }
484}
485
486impl<T: IoBufMut, S> IntoInner for Recv<T, S> {
487    type Inner = T;
488
489    fn into_inner(self) -> Self::Inner {
490        self.buffer
491    }
492}
493
494pin_project! {
495    /// Send data to remote.
496    ///
497    /// It is only used for socket operations. If you want to write to a pipe, use
498    /// [`Write`].
499    pub struct Send<T: IoBuf, S> {
500        pub(crate) fd: S,
501        #[pin]
502        pub(crate) buffer: T,
503        pub(crate) flags: i32,
504        _p: PhantomPinned,
505    }
506}
507
508impl<T: IoBuf, S> Send<T, S> {
509    /// Create [`Send`].
510    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
511        Self {
512            fd,
513            buffer,
514            flags,
515            _p: PhantomPinned,
516        }
517    }
518}
519
520impl<T: IoBuf, S> IntoInner for Send<T, S> {
521    type Inner = T;
522
523    fn into_inner(self) -> Self::Inner {
524        self.buffer
525    }
526}
527
528pin_project! {
529    /// Receive data from remote into vectored buffer.
530    pub struct RecvVectored<T: IoVectoredBufMut, S> {
531        pub(crate) msg: libc::msghdr,
532        pub(crate) fd: S,
533        #[pin]
534        pub(crate) buffer: T,
535        pub(crate) slices: Vec<SysSlice>,
536        pub(crate) flags: i32,
537        _p: PhantomPinned,
538    }
539}
540
541impl<T: IoVectoredBufMut, S> RecvVectored<T, S> {
542    /// Create [`RecvVectored`].
543    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
544        Self {
545            msg: unsafe { std::mem::zeroed() },
546            fd,
547            buffer,
548            slices: vec![],
549            flags,
550            _p: PhantomPinned,
551        }
552    }
553
554    pub(crate) fn set_msg(self: Pin<&mut Self>) {
555        let this = self.project();
556
557        *this.slices = this.buffer.sys_slices_mut();
558        this.msg.msg_iov = this.slices.as_mut_ptr() as _;
559        this.msg.msg_iovlen = this.slices.len() as _;
560    }
561}
562
563impl<T: IoVectoredBufMut, S> IntoInner for RecvVectored<T, S> {
564    type Inner = T;
565
566    fn into_inner(self) -> Self::Inner {
567        self.buffer
568    }
569}
570
571pin_project! {
572    /// Send data to remote from vectored buffer.
573    pub struct SendVectored<T: IoVectoredBuf, S> {
574        pub(crate) msg: libc::msghdr,
575        pub(crate) fd: S,
576        #[pin]
577        pub(crate) buffer: T,
578        pub(crate) slices: Vec<SysSlice>,
579        pub(crate) flags: i32,
580        _p: PhantomPinned,
581    }
582}
583
584impl<T: IoVectoredBuf, S> SendVectored<T, S> {
585    /// Create [`SendVectored`].
586    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
587        Self {
588            msg: unsafe { std::mem::zeroed() },
589            fd,
590            buffer,
591            slices: vec![],
592            flags,
593            _p: PhantomPinned,
594        }
595    }
596
597    pub(crate) fn set_msg(self: Pin<&mut Self>) {
598        let this = self.project();
599
600        *this.slices = this.buffer.as_ref().sys_slices();
601        this.msg.msg_iov = this.slices.as_mut_ptr() as _;
602        this.msg.msg_iovlen = this.slices.len() as _;
603    }
604}
605
606impl<T: IoVectoredBuf, S> IntoInner for SendVectored<T, S> {
607    type Inner = T;
608
609    fn into_inner(self) -> Self::Inner {
610        self.buffer
611    }
612}
613
614pin_project! {
615    /// Receive data and source address with ancillary data into vectored buffer.
616    pub struct RecvMsg<T: IoVectoredBufMut, C: IoBufMut, S> {
617        pub(crate) msg: libc::msghdr,
618        pub(crate) addr: SockAddrStorage,
619        pub(crate) fd: S,
620        #[pin]
621        pub(crate) buffer: T,
622        pub(crate) control: C,
623        pub(crate) slices: Vec<SysSlice>,
624        pub(crate) flags: i32,
625        _p: PhantomPinned,
626    }
627}
628
629impl<T: IoVectoredBufMut, C: IoBufMut, S> RecvMsg<T, C, S> {
630    /// Create [`RecvMsg`].
631    ///
632    /// # Panics
633    ///
634    /// This function will panic if the control message buffer is misaligned.
635    pub fn new(fd: S, buffer: T, control: C, flags: i32) -> Self {
636        assert!(
637            control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
638            "misaligned control message buffer"
639        );
640        Self {
641            msg: unsafe { std::mem::zeroed() },
642            addr: SockAddrStorage::zeroed(),
643            fd,
644            buffer,
645            control,
646            slices: vec![],
647            flags,
648            _p: PhantomPinned,
649        }
650    }
651
652    pub(crate) fn set_msg(self: Pin<&mut Self>) {
653        let this = self.project();
654        *this.slices = this.buffer.sys_slices_mut();
655
656        this.msg.msg_name = this.addr as *mut _ as _;
657        this.msg.msg_namelen = this.addr.size_of() as _;
658        this.msg.msg_iov = this.slices.as_mut_ptr() as _;
659        this.msg.msg_iovlen = this.slices.len() as _;
660        this.msg.msg_control = this.control.buf_mut_ptr() as _;
661        this.msg.msg_controllen = this.control.buf_capacity() as _;
662    }
663}
664
665impl<T: IoVectoredBufMut, C: IoBufMut, S> IntoInner for RecvMsg<T, C, S> {
666    type Inner = ((T, C), SockAddrStorage, socklen_t, usize);
667
668    fn into_inner(self) -> Self::Inner {
669        (
670            (self.buffer, self.control),
671            self.addr,
672            self.msg.msg_namelen,
673            self.msg.msg_controllen as _,
674        )
675    }
676}
677
678pin_project! {
679    /// Send data to specified address accompanied by ancillary data from vectored
680    /// buffer.
681    pub struct SendMsg<T: IoVectoredBuf, C: IoBuf, S> {
682        pub(crate) msg: libc::msghdr,
683        pub(crate) fd: S,
684        #[pin]
685        pub(crate) buffer: T,
686        #[pin]
687        pub(crate) control: C,
688        pub(crate) addr: SockAddr,
689        pub(crate) slices: Vec<SysSlice>,
690        pub(crate) flags: i32,
691        _p: PhantomPinned,
692    }
693}
694
695impl<T: IoVectoredBuf, C: IoBuf, S> SendMsg<T, C, S> {
696    /// Create [`SendMsg`].
697    ///
698    /// # Panics
699    ///
700    /// This function will panic if the control message buffer is misaligned.
701    pub fn new(fd: S, buffer: T, control: C, addr: SockAddr, flags: i32) -> Self {
702        assert!(
703            control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
704            "misaligned control message buffer"
705        );
706        Self {
707            msg: unsafe { std::mem::zeroed() },
708            fd,
709            buffer,
710            control,
711            addr,
712            slices: vec![],
713            flags,
714            _p: PhantomPinned,
715        }
716    }
717
718    pub(crate) fn set_msg(self: Pin<&mut Self>) {
719        let this = self.project();
720        *this.slices = this.buffer.as_ref().sys_slices();
721        this.msg.msg_name = this.addr.as_ptr() as _;
722        this.msg.msg_namelen = this.addr.len();
723        this.msg.msg_iov = this.slices.as_ptr() as _;
724        this.msg.msg_iovlen = this.slices.len() as _;
725        this.msg.msg_control = this.control.buf_ptr() as _;
726        this.msg.msg_controllen = this.control.buf_len() as _;
727    }
728}
729
730impl<T: IoVectoredBuf, C: IoBuf, S> IntoInner for SendMsg<T, C, S> {
731    type Inner = (T, C);
732
733    fn into_inner(self) -> Self::Inner {
734        (self.buffer, self.control)
735    }
736}
737
738/// The interest to poll a file descriptor.
739#[derive(Debug, Clone, Copy, PartialEq, Eq)]
740pub enum Interest {
741    /// Represents a read operation.
742    Readable,
743    /// Represents a write operation.
744    Writable,
745}
746
747/// Poll a file descriptor for specified [`Interest`].
748pub struct PollOnce<S> {
749    pub(crate) fd: S,
750    pub(crate) interest: Interest,
751}
752
753impl<S> PollOnce<S> {
754    /// Create [`PollOnce`].
755    pub fn new(fd: S, interest: Interest) -> Self {
756        Self { fd, interest }
757    }
758}
759
760/// Splice data between two file descriptors.
761#[cfg(linux_all)]
762pub struct Splice<S1, S2> {
763    pub(crate) fd_in: S1,
764    pub(crate) offset_in: i64,
765    pub(crate) fd_out: S2,
766    pub(crate) offset_out: i64,
767    pub(crate) len: usize,
768    pub(crate) flags: u32,
769}
770
771#[cfg(linux_all)]
772impl<S1, S2> Splice<S1, S2> {
773    /// Create [`Splice`].
774    ///
775    /// `offset_in` and `offset_out` specify the offset to read from and write
776    /// to. Use `-1` for pipe ends or to use/update the current file
777    /// position.
778    pub fn new(
779        fd_in: S1,
780        offset_in: i64,
781        fd_out: S2,
782        offset_out: i64,
783        len: usize,
784        flags: u32,
785    ) -> Self {
786        Self {
787            fd_in,
788            offset_in,
789            fd_out,
790            offset_out,
791            len,
792            flags,
793        }
794    }
795}