rustpython_common/
crt_fd.rs1use std::{cmp, ffi, io};
5
6#[cfg(windows)]
7use libc::commit as fsync;
8#[cfg(windows)]
9extern "C" {
10 #[link_name = "_chsize_s"]
11 fn ftruncate(fd: i32, len: i64) -> i32;
12}
13#[cfg(not(windows))]
14use libc::{fsync, ftruncate};
15
16#[cfg(not(windows))]
19pub type Offset = libc::off_t;
20#[cfg(windows)]
21pub type Offset = libc::c_longlong;
22
23#[inline]
24fn cvt<T, I: num_traits::PrimInt>(ret: I, f: impl FnOnce(I) -> T) -> io::Result<T> {
25 if ret < I::zero() {
26 Err(crate::os::last_os_error())
27 } else {
28 Ok(f(ret))
29 }
30}
31
32const MAX_RW: usize = if cfg!(any(windows, target_vendor = "apple")) {
33 i32::MAX as usize
34} else {
35 isize::MAX as usize
36};
37
38#[derive(Copy, Clone, PartialEq, Eq)]
39#[repr(transparent)]
40pub struct Fd(pub i32);
41
42impl Fd {
43 pub fn open(path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Self> {
44 cvt(unsafe { libc::open(path.as_ptr(), flags, mode) }, Fd)
45 }
46
47 #[cfg(windows)]
48 pub fn wopen(path: &widestring::WideCStr, flags: i32, mode: i32) -> io::Result<Self> {
49 cvt(
50 unsafe { suppress_iph!(libc::wopen(path.as_ptr(), flags, mode)) },
51 Fd,
52 )
53 }
54
55 #[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))]
56 pub fn openat(&self, path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Self> {
57 cvt(
58 unsafe { libc::openat(self.0, path.as_ptr(), flags, mode) },
59 Fd,
60 )
61 }
62
63 pub fn fsync(&self) -> io::Result<()> {
64 cvt(unsafe { suppress_iph!(fsync(self.0)) }, drop)
65 }
66
67 pub fn close(&self) -> io::Result<()> {
68 cvt(unsafe { suppress_iph!(libc::close(self.0)) }, drop)
69 }
70
71 pub fn ftruncate(&self, len: Offset) -> io::Result<()> {
72 cvt(unsafe { suppress_iph!(ftruncate(self.0, len)) }, drop)
73 }
74
75 #[cfg(windows)]
76 pub fn to_raw_handle(&self) -> io::Result<std::os::windows::io::RawHandle> {
77 extern "C" {
78 fn _get_osfhandle(fd: i32) -> libc::intptr_t;
79 }
80 let handle = unsafe { suppress_iph!(_get_osfhandle(self.0)) };
81 if handle == -1 {
82 Err(io::Error::last_os_error())
83 } else {
84 Ok(handle as _)
85 }
86 }
87}
88
89impl io::Write for Fd {
90 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
91 let count = cmp::min(buf.len(), MAX_RW);
92 cvt(
93 unsafe { suppress_iph!(libc::write(self.0, buf.as_ptr() as _, count as _)) },
94 |i| i as usize,
95 )
96 }
97
98 #[inline]
99 fn flush(&mut self) -> io::Result<()> {
100 Ok(())
101 }
102}
103
104impl io::Read for Fd {
105 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
106 let count = cmp::min(buf.len(), MAX_RW);
107 cvt(
108 unsafe { suppress_iph!(libc::read(self.0, buf.as_mut_ptr() as _, count as _)) },
109 |i| i as usize,
110 )
111 }
112}