]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | #![unstable(reason = "not public", issue = "none", feature = "fd")] |
416331ca XL |
2 | |
3 | use crate::cmp; | |
60c5eb7d | 4 | use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; |
416331ca XL |
5 | use crate::mem; |
6 | use crate::sys::cvt; | |
7 | use crate::sys_common::AsInner; | |
8 | ||
9 | use libc::{self, c_int, c_void, ssize_t}; | |
10 | ||
11 | #[derive(Debug)] | |
12 | pub struct FileDesc { | |
13 | fd: c_int, | |
14 | } | |
15 | ||
3dfed10e XL |
16 | // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, |
17 | // with the man page quoting that if the count of bytes to read is | |
18 | // greater than `SSIZE_MAX` the result is "unspecified". | |
19 | const READ_LIMIT: usize = ssize_t::MAX as usize; | |
416331ca XL |
20 | |
21 | impl FileDesc { | |
22 | pub fn new(fd: c_int) -> FileDesc { | |
23 | FileDesc { fd: fd } | |
24 | } | |
25 | ||
60c5eb7d XL |
26 | pub fn raw(&self) -> c_int { |
27 | self.fd | |
28 | } | |
416331ca | 29 | |
3dfed10e | 30 | /// Extracts the actual file descriptor without closing it. |
416331ca XL |
31 | pub fn into_raw(self) -> c_int { |
32 | let fd = self.fd; | |
33 | mem::forget(self); | |
34 | fd | |
35 | } | |
36 | ||
37 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { | |
38 | let ret = cvt(unsafe { | |
3dfed10e | 39 | libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) |
416331ca XL |
40 | })?; |
41 | Ok(ret as usize) | |
42 | } | |
43 | ||
44 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
45 | let ret = cvt(unsafe { | |
60c5eb7d XL |
46 | libc::readv( |
47 | self.fd, | |
48 | bufs.as_ptr() as *const libc::iovec, | |
f035d41b | 49 | cmp::min(bufs.len(), c_int::MAX as usize) as c_int, |
60c5eb7d | 50 | ) |
416331ca XL |
51 | })?; |
52 | Ok(ret as usize) | |
53 | } | |
54 | ||
f9f354fc | 55 | #[inline] |
1b1a35ee | 56 | pub fn is_read_vectored(&self) -> bool { |
f9f354fc XL |
57 | true |
58 | } | |
59 | ||
416331ca XL |
60 | pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
61 | let mut me = self; | |
62 | (&mut me).read_to_end(buf) | |
63 | } | |
64 | ||
65 | pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { | |
60c5eb7d XL |
66 | unsafe fn cvt_pread( |
67 | fd: c_int, | |
68 | buf: *mut c_void, | |
69 | count: usize, | |
70 | offset: i64, | |
71 | ) -> io::Result<isize> { | |
416331ca XL |
72 | use libc::pread; |
73 | cvt(pread(fd, buf, count, offset)) | |
74 | } | |
75 | ||
76 | unsafe { | |
60c5eb7d XL |
77 | cvt_pread( |
78 | self.fd, | |
416331ca | 79 | buf.as_mut_ptr() as *mut c_void, |
3dfed10e | 80 | cmp::min(buf.len(), READ_LIMIT), |
60c5eb7d XL |
81 | offset as i64, |
82 | ) | |
416331ca XL |
83 | .map(|n| n as usize) |
84 | } | |
85 | } | |
86 | ||
87 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { | |
88 | let ret = cvt(unsafe { | |
3dfed10e | 89 | libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) |
416331ca XL |
90 | })?; |
91 | Ok(ret as usize) | |
92 | } | |
93 | ||
94 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
95 | let ret = cvt(unsafe { | |
60c5eb7d XL |
96 | libc::writev( |
97 | self.fd, | |
98 | bufs.as_ptr() as *const libc::iovec, | |
f035d41b | 99 | cmp::min(bufs.len(), c_int::MAX as usize) as c_int, |
60c5eb7d | 100 | ) |
416331ca XL |
101 | })?; |
102 | Ok(ret as usize) | |
103 | } | |
104 | ||
f9f354fc XL |
105 | #[inline] |
106 | pub fn is_write_vectored(&self) -> bool { | |
107 | true | |
108 | } | |
109 | ||
416331ca | 110 | pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
60c5eb7d XL |
111 | unsafe fn cvt_pwrite( |
112 | fd: c_int, | |
113 | buf: *const c_void, | |
114 | count: usize, | |
115 | offset: i64, | |
116 | ) -> io::Result<isize> { | |
416331ca XL |
117 | use libc::pwrite; |
118 | cvt(pwrite(fd, buf, count, offset)) | |
119 | } | |
120 | ||
121 | unsafe { | |
60c5eb7d XL |
122 | cvt_pwrite( |
123 | self.fd, | |
416331ca | 124 | buf.as_ptr() as *const c_void, |
3dfed10e | 125 | cmp::min(buf.len(), READ_LIMIT), |
60c5eb7d XL |
126 | offset as i64, |
127 | ) | |
128 | .map(|n| n as usize) | |
416331ca XL |
129 | } |
130 | } | |
131 | ||
132 | pub fn get_cloexec(&self) -> io::Result<bool> { | |
60c5eb7d | 133 | unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } |
416331ca XL |
134 | } |
135 | ||
136 | pub fn set_cloexec(&self) -> io::Result<()> { | |
137 | unsafe { | |
138 | let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; | |
139 | let new = previous | libc::FD_CLOEXEC; | |
140 | if new != previous { | |
141 | cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; | |
142 | } | |
143 | Ok(()) | |
144 | } | |
145 | } | |
146 | ||
147 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
148 | unsafe { | |
149 | let v = nonblocking as c_int; | |
150 | cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; | |
151 | Ok(()) | |
152 | } | |
153 | } | |
154 | ||
155 | // refer to pxPipeDrv library documentation. | |
156 | // VxWorks uses fcntl to set O_NONBLOCK to the pipes | |
157 | pub fn set_nonblocking_pipe(&self, nonblocking: bool) -> io::Result<()> { | |
158 | unsafe { | |
159 | let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; | |
60c5eb7d | 160 | flags = if nonblocking { flags | libc::O_NONBLOCK } else { flags & !libc::O_NONBLOCK }; |
416331ca XL |
161 | cvt(libc::fcntl(self.fd, libc::F_SETFL, flags))?; |
162 | Ok(()) | |
163 | } | |
164 | } | |
165 | ||
416331ca XL |
166 | pub fn duplicate(&self) -> io::Result<FileDesc> { |
167 | let fd = self.raw(); | |
168 | match cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }) { | |
60c5eb7d | 169 | Ok(newfd) => Ok(FileDesc::new(newfd)), |
416331ca XL |
170 | Err(e) => return Err(e), |
171 | } | |
172 | } | |
173 | } | |
174 | ||
175 | impl<'a> Read for &'a FileDesc { | |
176 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
177 | (**self).read(buf) | |
178 | } | |
179 | ||
180 | #[inline] | |
181 | unsafe fn initializer(&self) -> Initializer { | |
182 | Initializer::nop() | |
183 | } | |
184 | } | |
185 | ||
186 | impl AsInner<c_int> for FileDesc { | |
60c5eb7d XL |
187 | fn as_inner(&self) -> &c_int { |
188 | &self.fd | |
189 | } | |
416331ca XL |
190 | } |
191 | ||
192 | impl Drop for FileDesc { | |
193 | fn drop(&mut self) { | |
194 | // Note that errors are ignored when closing a file descriptor. The | |
195 | // reason for this is that if an error occurs we don't actually know if | |
196 | // the file descriptor was closed or not, and if we retried (for | |
197 | // something like EINTR), we might close another valid file descriptor | |
198 | // (opened after we closed ours. | |
199 | let _ = unsafe { libc::close(self.fd) }; | |
200 | } | |
201 | } |