1 //! `pipe` and related APIs.
2 //!
3 //! # Safety
4 //!
5 //! `vmsplice` is an unsafe function.
6 
7 #![allow(unsafe_code)]
8 
9 use crate::fd::OwnedFd;
10 use crate::{backend, io};
11 #[cfg(not(any(
12     solarish,
13     windows,
14     target_os = "espidf",
15     target_os = "haiku",
16     target_os = "redox",
17     target_os = "vita",
18     target_os = "wasi",
19 )))]
20 use backend::c;
21 #[cfg(linux_kernel)]
22 use backend::fd::AsFd;
23 
24 #[cfg(not(apple))]
25 pub use backend::pipe::types::PipeFlags;
26 
27 #[cfg(linux_kernel)]
28 pub use backend::pipe::types::{IoSliceRaw, SpliceFlags};
29 
30 /// `PIPE_BUF`—The maximum length at which writes to a pipe are atomic.
31 ///
32 /// # References
33 ///  - [Linux]
34 ///  - [POSIX]
35 ///
36 /// [Linux]: https://man7.org/linux/man-pages/man7/pipe.7.html
37 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
38 #[cfg(not(any(
39     solarish,
40     windows,
41     target_os = "espidf",
42     target_os = "haiku",
43     target_os = "hurd",
44     target_os = "redox",
45     target_os = "vita",
46     target_os = "wasi",
47 )))]
48 pub const PIPE_BUF: usize = c::PIPE_BUF;
49 
50 /// `pipe()`—Creates a pipe.
51 ///
52 /// This function creates a pipe and returns two file descriptors, for the
53 /// reading and writing ends of the pipe, respectively.
54 ///
55 /// # References
56 ///  - [POSIX]
57 ///  - [Linux]
58 ///  - [Apple]
59 ///  - [FreeBSD]
60 ///  - [NetBSD]
61 ///  - [OpenBSD]
62 ///  - [DragonFly BSD]
63 ///  - [illumos]
64 ///  - [glibc]
65 ///
66 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html
67 /// [Linux]: https://man7.org/linux/man-pages/man2/pipe.2.html
68 /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pipe.2.html
69 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pipe&sektion=2
70 /// [NetBSD]: https://man.netbsd.org/pipe.2
71 /// [OpenBSD]: https://man.openbsd.org/pipe.2
72 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pipe&section=2
73 /// [illumos]: https://illumos.org/man/2/pipe
74 /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Creating-a-Pipe.html
75 #[inline]
pipe() -> io::Result<(OwnedFd, OwnedFd)>76 pub fn pipe() -> io::Result<(OwnedFd, OwnedFd)> {
77     backend::pipe::syscalls::pipe()
78 }
79 
80 /// `pipe2(flags)`—Creates a pipe, with flags.
81 ///
82 /// This function creates a pipe and returns two file descriptors, for the
83 /// reading and writing ends of the pipe, respectively.
84 ///
85 /// # References
86 ///  - [Linux]
87 ///  - [FreeBSD]
88 ///  - [NetBSD]
89 ///  - [OpenBSD]
90 ///  - [DragonFly BSD]
91 ///  - [illumos]
92 ///
93 /// [Linux]: https://man7.org/linux/man-pages/man2/pipe2.2.html
94 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pipe2&sektion=2
95 /// [NetBSD]: https://man.netbsd.org/pipe2.2
96 /// [OpenBSD]: https://man.openbsd.org/pipe2.2
97 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pipe2&section=2
98 /// [illumos]: https://illumos.org/man/2/pipe2
99 #[cfg(not(any(
100     apple,
101     target_os = "aix",
102     target_os = "espidf",
103     target_os = "haiku",
104     target_os = "nto"
105 )))]
106 #[inline]
107 #[doc(alias = "pipe2")]
pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)>108 pub fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> {
109     backend::pipe::syscalls::pipe_with(flags)
110 }
111 
112 /// `splice(fd_in, off_in, fd_out, off_out, len, flags)`—Transfer data
113 /// between a file and a pipe.
114 ///
115 /// This function transfers up to `len` bytes of data from the file descriptor
116 /// `fd_in` to the file descriptor `fd_out`, where one of the file descriptors
117 /// must refer to a pipe.
118 ///
119 /// `off_*` must be `None` if the corresponding fd refers to a pipe. Otherwise
120 /// its value points to the starting offset to the file, from which the data is
121 /// read/written. On success, the number of bytes read/written is added to the
122 /// offset.
123 ///
124 /// Passing `None` causes the read/write to start from the file offset, and the
125 /// file offset is adjusted appropriately.
126 ///
127 /// # References
128 ///  - [Linux]
129 ///
130 /// [Linux]: https://man7.org/linux/man-pages/man2/splice.2.html
131 #[cfg(linux_kernel)]
132 #[inline]
splice<FdIn: AsFd, FdOut: AsFd>( fd_in: FdIn, off_in: Option<&mut u64>, fd_out: FdOut, off_out: Option<&mut u64>, len: usize, flags: SpliceFlags, ) -> io::Result<usize>133 pub fn splice<FdIn: AsFd, FdOut: AsFd>(
134     fd_in: FdIn,
135     off_in: Option<&mut u64>,
136     fd_out: FdOut,
137     off_out: Option<&mut u64>,
138     len: usize,
139     flags: SpliceFlags,
140 ) -> io::Result<usize> {
141     backend::pipe::syscalls::splice(fd_in.as_fd(), off_in, fd_out.as_fd(), off_out, len, flags)
142 }
143 
144 /// `vmsplice(fd, bufs, flags)`—Transfer data between memory and a pipe.
145 ///
146 /// If `fd` is the write end of the pipe, the function maps the memory pointer
147 /// at by `bufs` to the pipe.
148 ///
149 /// If `fd` is the read end of the pipe, the function writes data from the pipe
150 /// to said memory.
151 ///
152 /// # Safety
153 ///
154 /// If the memory must not be mutated (such as when `bufs` were originally
155 /// immutable slices), it is up to the caller to ensure that the write end of
156 /// the pipe is placed in `fd`.
157 ///
158 /// Additionally if `SpliceFlags::GIFT` is set, the caller must also ensure
159 /// that the contents of `bufs` in never modified following the call, and that
160 /// all of the pointers in `bufs` are page aligned, and the lengths are
161 /// multiples of a page size in bytes.
162 ///
163 /// # References
164 ///  - [Linux]
165 ///
166 /// [Linux]: https://man7.org/linux/man-pages/man2/vmsplice.2.html
167 #[cfg(linux_kernel)]
168 #[inline]
vmsplice<PipeFd: AsFd>( fd: PipeFd, bufs: &[IoSliceRaw<'_>], flags: SpliceFlags, ) -> io::Result<usize>169 pub unsafe fn vmsplice<PipeFd: AsFd>(
170     fd: PipeFd,
171     bufs: &[IoSliceRaw<'_>],
172     flags: SpliceFlags,
173 ) -> io::Result<usize> {
174     backend::pipe::syscalls::vmsplice(fd.as_fd(), bufs, flags)
175 }
176 
177 /// `tee(fd_in, fd_out, len, flags)`—Copy data between pipes without
178 /// consuming it.
179 ///
180 /// This reads up to `len` bytes from `in_fd` without consuming them, and
181 /// writes them to `out_fd`.
182 ///
183 /// # References
184 ///  - [Linux]
185 ///
186 /// [Linux]: https://man7.org/linux/man-pages/man2/tee.2.html
187 #[cfg(linux_kernel)]
188 #[inline]
tee<FdIn: AsFd, FdOut: AsFd>( fd_in: FdIn, fd_out: FdOut, len: usize, flags: SpliceFlags, ) -> io::Result<usize>189 pub fn tee<FdIn: AsFd, FdOut: AsFd>(
190     fd_in: FdIn,
191     fd_out: FdOut,
192     len: usize,
193     flags: SpliceFlags,
194 ) -> io::Result<usize> {
195     backend::pipe::syscalls::tee(fd_in.as_fd(), fd_out.as_fd(), len, flags)
196 }
197 
198 /// `fnctl(fd, F_GETPIPE_SZ)`—Return the buffer capacity of a pipe.
199 ///
200 /// # References
201 ///  - [Linux]
202 ///
203 /// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
204 #[cfg(linux_kernel)]
205 #[inline]
fcntl_getpipe_size<Fd: AsFd>(fd: Fd) -> io::Result<usize>206 pub fn fcntl_getpipe_size<Fd: AsFd>(fd: Fd) -> io::Result<usize> {
207     backend::pipe::syscalls::fcntl_getpipe_sz(fd.as_fd())
208 }
209 
210 /// `fnctl(fd, F_SETPIPE_SZ)`—Set the buffer capacity of a pipe.
211 ///
212 /// # References
213 ///  - [Linux]
214 ///
215 /// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
216 #[cfg(linux_kernel)]
217 #[inline]
fcntl_setpipe_size<Fd: AsFd>(fd: Fd, size: usize) -> io::Result<()>218 pub fn fcntl_setpipe_size<Fd: AsFd>(fd: Fd, size: usize) -> io::Result<()> {
219     backend::pipe::syscalls::fcntl_setpipe_sz(fd.as_fd(), size)
220 }
221