]> git.proxmox.com Git - rustc.git/blame - library/std/src/sys/unix/fd.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / library / std / src / sys / unix / fd.rs
CommitLineData
dfeec247 1#![unstable(reason = "not public", issue = "none", feature = "fd")]
54a0048b 2
1b1a35ee
XL
3#[cfg(test)]
4mod tests;
5
532ac7d7 6use crate::cmp;
a2a8927a 7use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf};
94222f64 8use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
532ac7d7 9use crate::sys::cvt;
94222f64 10use crate::sys_common::{AsInner, FromInner, IntoInner};
532ac7d7 11
3dfed10e 12use libc::{c_int, c_void};
85aaf69f 13
32a655c1 14#[derive(Debug)]
94222f64 15pub struct FileDesc(OwnedFd);
85aaf69f 16
3dfed10e
XL
17// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
18// with the man page quoting that if the count of bytes to read is
19// greater than `SSIZE_MAX` the result is "unspecified".
20//
21// On macOS, however, apparently the 64-bit libc is either buggy or
22// intentionally showing odd behavior by rejecting any read with a size
23// larger than or equal to INT_MAX. To handle both of these the read
24// size is capped on both platforms.
25#[cfg(target_os = "macos")]
26const READ_LIMIT: usize = c_int::MAX as usize - 1;
27#[cfg(not(target_os = "macos"))]
28const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
29
1b1a35ee
XL
30#[cfg(any(
31 target_os = "dragonfly",
32 target_os = "freebsd",
33 target_os = "ios",
34 target_os = "macos",
35 target_os = "netbsd",
36 target_os = "openbsd",
37))]
38const fn max_iov() -> usize {
39 libc::IOV_MAX as usize
40}
3dfed10e 41
1b1a35ee
XL
42#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
43const fn max_iov() -> usize {
44 libc::UIO_MAXIOV as usize
3dfed10e
XL
45}
46
1b1a35ee
XL
47#[cfg(not(any(
48 target_os = "android",
49 target_os = "dragonfly",
50 target_os = "emscripten",
51 target_os = "freebsd",
52 target_os = "ios",
53 target_os = "linux",
54 target_os = "macos",
55 target_os = "netbsd",
56 target_os = "openbsd",
57)))]
58const fn max_iov() -> usize {
3dfed10e 59 16 // The minimum value required by POSIX.
32a655c1
SL
60}
61
85aaf69f 62impl FileDesc {
85aaf69f 63 pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
54a0048b 64 let ret = cvt(unsafe {
94222f64
XL
65 libc::read(
66 self.as_raw_fd(),
67 buf.as_mut_ptr() as *mut c_void,
68 cmp::min(buf.len(), READ_LIMIT),
69 )
54a0048b 70 })?;
85aaf69f
SL
71 Ok(ret as usize)
72 }
73
94222f64 74 #[cfg(not(target_os = "espidf"))]
48663c56 75 pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
9fa01778 76 let ret = cvt(unsafe {
60c5eb7d 77 libc::readv(
94222f64 78 self.as_raw_fd(),
60c5eb7d 79 bufs.as_ptr() as *const libc::iovec,
3dfed10e 80 cmp::min(bufs.len(), max_iov()) as c_int,
60c5eb7d 81 )
9fa01778
XL
82 })?;
83 Ok(ret as usize)
84 }
85
94222f64
XL
86 #[cfg(target_os = "espidf")]
87 pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
88 return crate::io::default_read_vectored(|b| self.read(b), bufs);
89 }
90
f9f354fc
XL
91 #[inline]
92 pub fn is_read_vectored(&self) -> bool {
94222f64 93 cfg!(not(target_os = "espidf"))
f9f354fc
XL
94 }
95
54a0048b
SL
96 pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
97 let mut me = self;
98 (&mut me).read_to_end(buf)
99 }
100
c30ab7b3 101 pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
a2a8927a
XL
102 #[cfg(not(any(target_os = "linux", target_os = "android")))]
103 use libc::pread as pread64;
104 #[cfg(any(target_os = "linux", target_os = "android"))]
105 use libc::pread64;
c30ab7b3
SL
106
107 unsafe {
a2a8927a 108 cvt(pread64(
94222f64 109 self.as_raw_fd(),
60c5eb7d 110 buf.as_mut_ptr() as *mut c_void,
3dfed10e 111 cmp::min(buf.len(), READ_LIMIT),
60c5eb7d 112 offset as i64,
a2a8927a 113 ))
60c5eb7d 114 .map(|n| n as usize)
c30ab7b3
SL
115 }
116 }
117
a2a8927a
XL
118 pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
119 let ret = cvt(unsafe {
120 libc::read(
121 self.as_raw_fd(),
122 buf.unfilled_mut().as_mut_ptr() as *mut c_void,
123 cmp::min(buf.remaining(), READ_LIMIT),
124 )
125 })?;
126
127 // Safety: `ret` bytes were written to the initialized portion of the buffer
128 unsafe {
129 buf.assume_init(ret as usize);
130 }
131 buf.add_filled(ret as usize);
132 Ok(())
133 }
134
85aaf69f 135 pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
54a0048b 136 let ret = cvt(unsafe {
94222f64
XL
137 libc::write(
138 self.as_raw_fd(),
139 buf.as_ptr() as *const c_void,
140 cmp::min(buf.len(), READ_LIMIT),
141 )
54a0048b 142 })?;
85aaf69f
SL
143 Ok(ret as usize)
144 }
9346a6ac 145
94222f64 146 #[cfg(not(target_os = "espidf"))]
48663c56 147 pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
9fa01778 148 let ret = cvt(unsafe {
60c5eb7d 149 libc::writev(
94222f64 150 self.as_raw_fd(),
60c5eb7d 151 bufs.as_ptr() as *const libc::iovec,
3dfed10e 152 cmp::min(bufs.len(), max_iov()) as c_int,
60c5eb7d 153 )
9fa01778
XL
154 })?;
155 Ok(ret as usize)
156 }
157
94222f64
XL
158 #[cfg(target_os = "espidf")]
159 pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
160 return crate::io::default_write_vectored(|b| self.write(b), bufs);
161 }
162
f9f354fc
XL
163 #[inline]
164 pub fn is_write_vectored(&self) -> bool {
94222f64 165 cfg!(not(target_os = "espidf"))
f9f354fc
XL
166 }
167
c30ab7b3 168 pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
a2a8927a
XL
169 #[cfg(not(any(target_os = "linux", target_os = "android")))]
170 use libc::pwrite as pwrite64;
171 #[cfg(any(target_os = "linux", target_os = "android"))]
172 use libc::pwrite64;
c30ab7b3
SL
173
174 unsafe {
a2a8927a 175 cvt(pwrite64(
94222f64 176 self.as_raw_fd(),
60c5eb7d 177 buf.as_ptr() as *const c_void,
3dfed10e 178 cmp::min(buf.len(), READ_LIMIT),
60c5eb7d 179 offset as i64,
a2a8927a 180 ))
60c5eb7d 181 .map(|n| n as usize)
c30ab7b3
SL
182 }
183 }
184
94b46f34
XL
185 #[cfg(target_os = "linux")]
186 pub fn get_cloexec(&self) -> io::Result<bool> {
94222f64 187 unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
94b46f34
XL
188 }
189
60c5eb7d
XL
190 #[cfg(not(any(
191 target_env = "newlib",
192 target_os = "solaris",
ba9703b0 193 target_os = "illumos",
60c5eb7d
XL
194 target_os = "emscripten",
195 target_os = "fuchsia",
196 target_os = "l4re",
197 target_os = "linux",
198 target_os = "haiku",
29967ef6
XL
199 target_os = "redox",
200 target_os = "vxworks"
60c5eb7d 201 )))]
3157f602 202 pub fn set_cloexec(&self) -> io::Result<()> {
9346a6ac 203 unsafe {
94222f64 204 cvt(libc::ioctl(self.as_raw_fd(), libc::FIOCLEX))?;
3157f602 205 Ok(())
92a42be0
SL
206 }
207 }
60c5eb7d 208 #[cfg(any(
94222f64 209 all(target_env = "newlib", not(target_os = "espidf")),
60c5eb7d 210 target_os = "solaris",
ba9703b0 211 target_os = "illumos",
60c5eb7d
XL
212 target_os = "emscripten",
213 target_os = "fuchsia",
214 target_os = "l4re",
215 target_os = "linux",
216 target_os = "haiku",
29967ef6
XL
217 target_os = "redox",
218 target_os = "vxworks"
60c5eb7d 219 ))]
3157f602 220 pub fn set_cloexec(&self) -> io::Result<()> {
92a42be0 221 unsafe {
94222f64 222 let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))?;
8bb4bdeb
XL
223 let new = previous | libc::FD_CLOEXEC;
224 if new != previous {
94222f64 225 cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFD, new))?;
8bb4bdeb 226 }
3157f602 227 Ok(())
9346a6ac
AL
228 }
229 }
94222f64
XL
230 #[cfg(target_os = "espidf")]
231 pub fn set_cloexec(&self) -> io::Result<()> {
232 // FD_CLOEXEC is not supported in ESP-IDF but there's no need to,
233 // because ESP-IDF does not support spawning processes either.
234 Ok(())
235 }
7453a54e 236
8bb4bdeb
XL
237 #[cfg(target_os = "linux")]
238 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
239 unsafe {
240 let v = nonblocking as c_int;
94222f64 241 cvt(libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &v))?;
8bb4bdeb
XL
242 Ok(())
243 }
244 }
245
246 #[cfg(not(target_os = "linux"))]
3157f602 247 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
54a0048b 248 unsafe {
94222f64 249 let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFL))?;
54a0048b
SL
250 let new = if nonblocking {
251 previous | libc::O_NONBLOCK
252 } else {
253 previous & !libc::O_NONBLOCK
254 };
8bb4bdeb 255 if new != previous {
94222f64 256 cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFL, new))?;
8bb4bdeb 257 }
3157f602 258 Ok(())
54a0048b
SL
259 }
260 }
261
5099ac24 262 #[inline]
7453a54e 263 pub fn duplicate(&self) -> io::Result<FileDesc> {
5099ac24 264 Ok(Self(self.0.try_clone()?))
7453a54e 265 }
85aaf69f
SL
266}
267
54a0048b
SL
268impl<'a> Read for &'a FileDesc {
269 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
270 (**self).read(buf)
271 }
54a0048b
SL
272}
273
94222f64
XL
274impl AsInner<OwnedFd> for FileDesc {
275 fn as_inner(&self) -> &OwnedFd {
276 &self.0
277 }
278}
279
280impl IntoInner<OwnedFd> for FileDesc {
281 fn into_inner(self) -> OwnedFd {
282 self.0
283 }
284}
285
286impl FromInner<OwnedFd> for FileDesc {
287 fn from_inner(owned_fd: OwnedFd) -> Self {
288 Self(owned_fd)
289 }
290}
291
292impl AsFd for FileDesc {
293 fn as_fd(&self) -> BorrowedFd<'_> {
294 self.0.as_fd()
295 }
296}
297
298impl AsRawFd for FileDesc {
299 fn as_raw_fd(&self) -> RawFd {
300 self.0.as_raw_fd()
301 }
302}
303
304impl IntoRawFd for FileDesc {
305 fn into_raw_fd(self) -> RawFd {
306 self.0.into_raw_fd()
60c5eb7d 307 }
85aaf69f
SL
308}
309
94222f64
XL
310impl FromRawFd for FileDesc {
311 unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
312 Self(FromRawFd::from_raw_fd(raw_fd))
85aaf69f
SL
313 }
314}