rustpython_host_env/
crt_fd.rs1use alloc::fmt;
5use core::cmp;
6use std::{ffi, io};
7
8#[cfg(any(unix, target_os = "wasi"))]
9use std::os::fd::AsFd;
10#[cfg(not(windows))]
11use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
12#[cfg(windows)]
13use std::os::windows::io::BorrowedHandle;
14
15mod c {
16 pub(super) use libc::*;
17
18 #[cfg(windows)]
19 pub(super) use libc::commit as fsync;
20 #[cfg(windows)]
21 unsafe extern "C" {
22 #[link_name = "_chsize_s"]
23 pub(super) fn ftruncate(fd: i32, len: i64) -> i32;
24 }
25}
26
27pub type Offset = cfg_select! {
30 windows => c::c_longlong,
31 _ => c::off_t,
32};
33
34pub type Raw = cfg_select! {
35 windows => i32,
36 _ => RawFd,
37};
38
39#[inline]
40fn cvt<I: num_traits::PrimInt>(ret: I) -> io::Result<I> {
41 if ret < I::zero() {
42 Err(crate::os::errno_io_error())
44 } else {
45 Ok(ret)
46 }
47}
48
49fn cvt_fd(ret: Raw) -> io::Result<Owned> {
50 cvt(ret).map(|fd| unsafe { Owned::from_raw(fd) })
51}
52
53const MAX_RW: usize = if cfg!(any(windows, target_vendor = "apple")) {
54 i32::MAX as usize
55} else {
56 isize::MAX as usize
57};
58
59#[cfg(not(windows))]
60type OwnedInner = OwnedFd;
61#[cfg(not(windows))]
62type BorrowedInner<'fd> = BorrowedFd<'fd>;
63
64#[cfg(windows)]
65mod win {
66 use super::*;
67 use core::marker::PhantomData;
68 use core::mem::ManuallyDrop;
69
70 #[repr(transparent)]
71 pub(super) struct OwnedInner(i32);
72
73 impl OwnedInner {
74 #[inline]
75 pub(super) unsafe fn from_raw_fd(fd: Raw) -> Self {
76 Self(fd)
77 }
78
79 #[inline]
80 pub(super) fn as_raw_fd(&self) -> Raw {
81 self.0
82 }
83
84 #[inline]
85 pub(super) fn into_raw_fd(self) -> Raw {
86 let me = ManuallyDrop::new(self);
87 me.0
88 }
89 }
90
91 impl Drop for OwnedInner {
92 #[inline]
93 fn drop(&mut self) {
94 let _ = _close(self.0);
95 }
96 }
97
98 #[derive(Copy, Clone)]
99 #[repr(transparent)]
100 pub(super) struct BorrowedInner<'fd> {
101 fd: Raw,
102 _marker: PhantomData<&'fd Owned>,
103 }
104
105 impl BorrowedInner<'_> {
106 #[inline]
107 pub(super) const unsafe fn borrow_raw(fd: Raw) -> Self {
108 Self {
109 fd,
110 _marker: PhantomData,
111 }
112 }
113
114 #[inline]
115 pub(super) fn as_raw_fd(self) -> Raw {
116 self.fd
117 }
118 }
119}
120
121#[cfg(windows)]
122use self::win::{BorrowedInner, OwnedInner};
123
124#[repr(transparent)]
125pub struct Owned {
126 inner: OwnedInner,
127}
128
129impl fmt::Debug for Owned {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 f.debug_tuple("crt_fd::Owned")
132 .field(&self.as_raw())
133 .finish()
134 }
135}
136
137#[derive(Copy, Clone)]
138#[repr(transparent)]
139pub struct Borrowed<'fd> {
140 inner: BorrowedInner<'fd>,
141}
142
143impl PartialEq for Borrowed<'_> {
144 fn eq(&self, other: &Self) -> bool {
145 self.as_raw() == other.as_raw()
146 }
147}
148
149impl Eq for Borrowed<'_> {}
150
151impl fmt::Debug for Borrowed<'_> {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 f.debug_tuple("crt_fd::Borrowed")
154 .field(&self.as_raw())
155 .finish()
156 }
157}
158
159impl Owned {
160 #[inline]
166 #[must_use]
167 pub unsafe fn from_raw(fd: Raw) -> Self {
168 let inner = unsafe { OwnedInner::from_raw_fd(fd) };
169 Self { inner }
170 }
171
172 #[inline]
180 pub unsafe fn try_from_raw(fd: Raw) -> io::Result<Self> {
181 if fd == -1 {
182 Err(ebadf())
183 } else {
184 Ok(unsafe { Self::from_raw(fd) })
185 }
186 }
187
188 #[inline]
189 #[must_use]
190 pub fn borrow(&self) -> Borrowed<'_> {
191 unsafe { Borrowed::borrow_raw(self.as_raw()) }
192 }
193
194 #[inline]
195 #[must_use]
196 pub fn as_raw(&self) -> Raw {
197 self.inner.as_raw_fd()
198 }
199
200 #[inline]
201 #[must_use]
202 pub fn into_raw(self) -> Raw {
203 self.inner.into_raw_fd()
204 }
205
206 #[must_use]
207 pub fn leak<'fd>(self) -> Borrowed<'fd> {
208 unsafe { Borrowed::borrow_raw(self.into_raw()) }
209 }
210}
211
212#[cfg(any(unix, target_os = "wasi"))]
213impl From<Owned> for OwnedFd {
214 fn from(fd: Owned) -> Self {
215 fd.inner
216 }
217}
218
219#[cfg(any(unix, target_os = "wasi"))]
220impl From<OwnedFd> for Owned {
221 fn from(fd: OwnedFd) -> Self {
222 Self { inner: fd }
223 }
224}
225
226#[cfg(any(unix, target_os = "wasi"))]
227impl AsFd for Owned {
228 fn as_fd(&self) -> BorrowedFd<'_> {
229 self.inner.as_fd()
230 }
231}
232
233#[cfg(any(unix, target_os = "wasi"))]
234impl AsRawFd for Owned {
235 fn as_raw_fd(&self) -> RawFd {
236 self.as_raw()
237 }
238}
239
240#[cfg(any(unix, target_os = "wasi"))]
241impl FromRawFd for Owned {
242 unsafe fn from_raw_fd(fd: RawFd) -> Self {
243 unsafe { Self::from_raw(fd) }
244 }
245}
246
247#[cfg(any(unix, target_os = "wasi"))]
248impl IntoRawFd for Owned {
249 fn into_raw_fd(self) -> RawFd {
250 self.into_raw()
251 }
252}
253
254impl Borrowed<'_> {
255 #[inline]
261 #[must_use]
262 pub const unsafe fn borrow_raw(fd: Raw) -> Self {
263 let inner = unsafe { BorrowedInner::borrow_raw(fd) };
264 Self { inner }
265 }
266
267 #[inline]
275 pub unsafe fn try_borrow_raw(fd: Raw) -> io::Result<Self> {
276 if fd == -1 {
277 Err(ebadf())
278 } else {
279 Ok(unsafe { Self::borrow_raw(fd) })
280 }
281 }
282
283 #[inline]
284 #[must_use]
285 pub fn as_raw(self) -> Raw {
286 self.inner.as_raw_fd()
287 }
288}
289
290#[cfg(any(unix, target_os = "wasi"))]
291impl<'fd> From<Borrowed<'fd>> for BorrowedFd<'fd> {
292 fn from(fd: Borrowed<'fd>) -> Self {
293 fd.inner
294 }
295}
296
297#[cfg(any(unix, target_os = "wasi"))]
298impl<'fd> From<BorrowedFd<'fd>> for Borrowed<'fd> {
299 fn from(fd: BorrowedFd<'fd>) -> Self {
300 Self { inner: fd }
301 }
302}
303
304#[cfg(any(unix, target_os = "wasi"))]
305impl AsFd for Borrowed<'_> {
306 fn as_fd(&self) -> BorrowedFd<'_> {
307 self.inner.as_fd()
308 }
309}
310
311#[cfg(any(unix, target_os = "wasi"))]
312impl AsRawFd for Borrowed<'_> {
313 fn as_raw_fd(&self) -> RawFd {
314 self.as_raw()
315 }
316}
317
318#[inline]
319fn ebadf() -> io::Error {
320 io::Error::from_raw_os_error(c::EBADF)
321}
322
323pub fn open(path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Owned> {
324 cvt_fd(unsafe { c::open(path.as_ptr(), flags, mode) })
325}
326
327#[cfg(windows)]
328pub fn wopen(path: &widestring::WideCStr, flags: i32, mode: i32) -> io::Result<Owned> {
329 cvt_fd(unsafe { suppress_iph!(c::wopen(path.as_ptr(), flags, mode)) })
330}
331
332#[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))]
333pub fn openat(dir: Borrowed<'_>, path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Owned> {
334 cvt_fd(unsafe { c::openat(dir.as_raw(), path.as_ptr(), flags, mode) })
335}
336
337pub fn fsync(fd: Borrowed<'_>) -> io::Result<()> {
338 cvt(unsafe { suppress_iph!(c::fsync(fd.as_raw())) })?;
339 Ok(())
340}
341
342fn _close(fd: Raw) -> io::Result<()> {
343 cvt(unsafe { suppress_iph!(c::close(fd)) })?;
344 Ok(())
345}
346
347pub fn close(fd: Owned) -> io::Result<()> {
348 _close(fd.into_raw())
349}
350
351pub fn ftruncate(fd: Borrowed<'_>, len: Offset) -> io::Result<()> {
352 let ret = unsafe { suppress_iph!(c::ftruncate(fd.as_raw(), len)) };
353 cfg_select! {
356 windows => {
357 if ret != 0 {
358 return Err(crate::os::io_error_from_errno(ret));
360 }
361 }
362 _ => cvt(ret)?,
363 };
364 Ok(())
365}
366
367#[cfg(windows)]
368pub fn as_handle(fd: Borrowed<'_>) -> io::Result<BorrowedHandle<'_>> {
369 use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
370 unsafe extern "C" {
371 fn _get_osfhandle(fd: Borrowed<'_>) -> c::intptr_t;
372 }
373 let handle = unsafe { suppress_iph!(_get_osfhandle(fd)) };
374 if handle as HANDLE == INVALID_HANDLE_VALUE {
375 Err(crate::os::errno_io_error())
377 } else {
378 Ok(unsafe { BorrowedHandle::borrow_raw(handle as _) })
379 }
380}
381
382fn _write(fd: Raw, buf: &[u8]) -> io::Result<usize> {
383 let count = cmp::min(buf.len(), MAX_RW);
384 let n = cvt(unsafe { suppress_iph!(c::write(fd, buf.as_ptr() as _, count as _)) })?;
385 Ok(n as usize)
386}
387
388fn _read(fd: Raw, buf: &mut [u8]) -> io::Result<usize> {
389 let count = cmp::min(buf.len(), MAX_RW);
390 let n = cvt(unsafe { suppress_iph!(libc::read(fd, buf.as_mut_ptr() as _, count as _)) })?;
391 Ok(n as usize)
392}
393
394pub fn write(fd: Borrowed<'_>, buf: &[u8]) -> io::Result<usize> {
395 _write(fd.as_raw(), buf)
396}
397
398pub fn read(fd: Borrowed<'_>, buf: &mut [u8]) -> io::Result<usize> {
399 _read(fd.as_raw(), buf)
400}
401
402macro_rules! impl_rw {
403 ($t:ty) => {
404 impl io::Write for $t {
405 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
406 _write(self.as_raw(), buf)
407 }
408
409 #[inline]
410 fn flush(&mut self) -> io::Result<()> {
411 Ok(())
412 }
413 }
414
415 impl io::Read for $t {
416 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
417 _read(self.as_raw(), buf)
418 }
419 }
420 };
421}
422
423impl_rw!(Owned);
424impl_rw!(Borrowed<'_>);