rustpython_common/
crt_fd.rs1use alloc::fmt;
5use core::cmp;
6use std::{ffi, io};
7
8#[cfg(unix)]
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
27#[cfg(not(windows))]
30pub type Offset = c::off_t;
31#[cfg(windows)]
32pub type Offset = c::c_longlong;
33
34#[cfg(not(windows))]
35pub type Raw = RawFd;
36#[cfg(windows)]
37pub type Raw = i32;
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 unsafe fn from_raw_fd(fd: Raw) -> Self {
76 Self(fd)
77 }
78 #[inline]
79 pub fn as_raw_fd(&self) -> Raw {
80 self.0
81 }
82 #[inline]
83 pub fn into_raw_fd(self) -> Raw {
84 let me = ManuallyDrop::new(self);
85 me.0
86 }
87 }
88
89 impl Drop for OwnedInner {
90 #[inline]
91 fn drop(&mut self) {
92 let _ = _close(self.0);
93 }
94 }
95
96 #[derive(Copy, Clone)]
97 #[repr(transparent)]
98 pub(super) struct BorrowedInner<'fd> {
99 fd: Raw,
100 _marker: PhantomData<&'fd Owned>,
101 }
102
103 impl BorrowedInner<'_> {
104 #[inline]
105 pub const unsafe fn borrow_raw(fd: Raw) -> Self {
106 Self {
107 fd,
108 _marker: PhantomData,
109 }
110 }
111 #[inline]
112 pub fn as_raw_fd(&self) -> Raw {
113 self.fd
114 }
115 }
116}
117
118#[cfg(windows)]
119use self::win::{BorrowedInner, OwnedInner};
120
121#[repr(transparent)]
122pub struct Owned {
123 inner: OwnedInner,
124}
125
126impl fmt::Debug for Owned {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.debug_tuple("crt_fd::Owned")
129 .field(&self.as_raw())
130 .finish()
131 }
132}
133
134#[derive(Copy, Clone)]
135#[repr(transparent)]
136pub struct Borrowed<'fd> {
137 inner: BorrowedInner<'fd>,
138}
139
140impl<'fd> PartialEq for Borrowed<'fd> {
141 fn eq(&self, other: &Self) -> bool {
142 self.as_raw() == other.as_raw()
143 }
144}
145impl<'fd> Eq for Borrowed<'fd> {}
146
147impl fmt::Debug for Borrowed<'_> {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 f.debug_tuple("crt_fd::Borrowed")
150 .field(&self.as_raw())
151 .finish()
152 }
153}
154
155impl Owned {
156 #[inline]
162 pub unsafe fn from_raw(fd: Raw) -> Self {
163 let inner = unsafe { OwnedInner::from_raw_fd(fd) };
164 Self { inner }
165 }
166
167 #[inline]
175 pub unsafe fn try_from_raw(fd: Raw) -> io::Result<Self> {
176 if fd == -1 {
177 Err(ebadf())
178 } else {
179 Ok(unsafe { Self::from_raw(fd) })
180 }
181 }
182
183 #[inline]
184 pub fn borrow(&self) -> Borrowed<'_> {
185 unsafe { Borrowed::borrow_raw(self.as_raw()) }
186 }
187
188 #[inline]
189 pub fn as_raw(&self) -> Raw {
190 self.inner.as_raw_fd()
191 }
192
193 #[inline]
194 pub fn into_raw(self) -> Raw {
195 self.inner.into_raw_fd()
196 }
197
198 pub fn leak<'fd>(self) -> Borrowed<'fd> {
199 unsafe { Borrowed::borrow_raw(self.into_raw()) }
200 }
201}
202
203#[cfg(unix)]
204impl From<Owned> for OwnedFd {
205 fn from(fd: Owned) -> Self {
206 fd.inner
207 }
208}
209
210#[cfg(unix)]
211impl From<OwnedFd> for Owned {
212 fn from(fd: OwnedFd) -> Self {
213 Self { inner: fd }
214 }
215}
216
217#[cfg(unix)]
218impl AsFd for Owned {
219 fn as_fd(&self) -> BorrowedFd<'_> {
220 self.inner.as_fd()
221 }
222}
223
224#[cfg(unix)]
225impl AsRawFd for Owned {
226 fn as_raw_fd(&self) -> RawFd {
227 self.as_raw()
228 }
229}
230
231#[cfg(unix)]
232impl FromRawFd for Owned {
233 unsafe fn from_raw_fd(fd: RawFd) -> Self {
234 unsafe { Self::from_raw(fd) }
235 }
236}
237
238#[cfg(unix)]
239impl IntoRawFd for Owned {
240 fn into_raw_fd(self) -> RawFd {
241 self.into_raw()
242 }
243}
244
245impl<'fd> Borrowed<'fd> {
246 #[inline]
252 pub const unsafe fn borrow_raw(fd: Raw) -> Self {
253 let inner = unsafe { BorrowedInner::borrow_raw(fd) };
254 Self { inner }
255 }
256
257 #[inline]
265 pub unsafe fn try_borrow_raw(fd: Raw) -> io::Result<Self> {
266 if fd == -1 {
267 Err(ebadf())
268 } else {
269 Ok(unsafe { Self::borrow_raw(fd) })
270 }
271 }
272
273 #[inline]
274 pub fn as_raw(self) -> Raw {
275 self.inner.as_raw_fd()
276 }
277}
278
279#[cfg(unix)]
280impl<'fd> From<Borrowed<'fd>> for BorrowedFd<'fd> {
281 fn from(fd: Borrowed<'fd>) -> Self {
282 fd.inner
283 }
284}
285
286#[cfg(unix)]
287impl<'fd> From<BorrowedFd<'fd>> for Borrowed<'fd> {
288 fn from(fd: BorrowedFd<'fd>) -> Self {
289 Self { inner: fd }
290 }
291}
292
293#[cfg(unix)]
294impl AsFd for Borrowed<'_> {
295 fn as_fd(&self) -> BorrowedFd<'_> {
296 self.inner.as_fd()
297 }
298}
299
300#[cfg(unix)]
301impl AsRawFd for Borrowed<'_> {
302 fn as_raw_fd(&self) -> RawFd {
303 self.as_raw()
304 }
305}
306
307#[inline]
308fn ebadf() -> io::Error {
309 io::Error::from_raw_os_error(c::EBADF)
310}
311
312pub fn open(path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Owned> {
313 cvt_fd(unsafe { c::open(path.as_ptr(), flags, mode) })
314}
315
316#[cfg(windows)]
317pub fn wopen(path: &widestring::WideCStr, flags: i32, mode: i32) -> io::Result<Owned> {
318 cvt_fd(unsafe { suppress_iph!(c::wopen(path.as_ptr(), flags, mode)) })
319}
320
321#[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))]
322pub fn openat(dir: Borrowed<'_>, path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Owned> {
323 cvt_fd(unsafe { c::openat(dir.as_raw(), path.as_ptr(), flags, mode) })
324}
325
326pub fn fsync(fd: Borrowed<'_>) -> io::Result<()> {
327 cvt(unsafe { suppress_iph!(c::fsync(fd.as_raw())) })?;
328 Ok(())
329}
330
331fn _close(fd: Raw) -> io::Result<()> {
332 cvt(unsafe { suppress_iph!(c::close(fd)) })?;
333 Ok(())
334}
335
336pub fn close(fd: Owned) -> io::Result<()> {
337 _close(fd.into_raw())
338}
339
340pub fn ftruncate(fd: Borrowed<'_>, len: Offset) -> io::Result<()> {
341 let ret = unsafe { suppress_iph!(c::ftruncate(fd.as_raw(), len)) };
342 #[cfg(windows)]
345 {
346 if ret != 0 {
347 let winerror = crate::os::errno_to_winerror(ret);
349 return Err(io::Error::from_raw_os_error(winerror));
350 }
351 }
352 #[cfg(not(windows))]
353 {
354 cvt(ret)?;
355 }
356 Ok(())
357}
358
359#[cfg(windows)]
360pub fn as_handle(fd: Borrowed<'_>) -> io::Result<BorrowedHandle<'_>> {
361 use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
362 unsafe extern "C" {
363 fn _get_osfhandle(fd: Borrowed<'_>) -> c::intptr_t;
364 }
365 let handle = unsafe { suppress_iph!(_get_osfhandle(fd)) };
366 if handle as HANDLE == INVALID_HANDLE_VALUE {
367 Err(crate::os::errno_io_error())
369 } else {
370 Ok(unsafe { BorrowedHandle::borrow_raw(handle as _) })
371 }
372}
373
374fn _write(fd: Raw, buf: &[u8]) -> io::Result<usize> {
375 let count = cmp::min(buf.len(), MAX_RW);
376 let n = cvt(unsafe { suppress_iph!(c::write(fd, buf.as_ptr() as _, count as _)) })?;
377 Ok(n as usize)
378}
379
380fn _read(fd: Raw, buf: &mut [u8]) -> io::Result<usize> {
381 let count = cmp::min(buf.len(), MAX_RW);
382 let n = cvt(unsafe { suppress_iph!(libc::read(fd, buf.as_mut_ptr() as _, count as _)) })?;
383 Ok(n as usize)
384}
385
386pub fn write(fd: Borrowed<'_>, buf: &[u8]) -> io::Result<usize> {
387 _write(fd.as_raw(), buf)
388}
389
390pub fn read(fd: Borrowed<'_>, buf: &mut [u8]) -> io::Result<usize> {
391 _read(fd.as_raw(), buf)
392}
393
394macro_rules! impl_rw {
395 ($t:ty) => {
396 impl io::Write for $t {
397 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
398 _write(self.as_raw(), buf)
399 }
400
401 #[inline]
402 fn flush(&mut self) -> io::Result<()> {
403 Ok(())
404 }
405 }
406
407 impl io::Read for $t {
408 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
409 _read(self.as_raw(), buf)
410 }
411 }
412 };
413}
414
415impl_rw!(Owned);
416impl_rw!(Borrowed<'_>);