Rework crt_fd to be more aligned with io-safety

This commit is contained in:
Noa committed 2025-08-29 10:59:51 -05:00
1 parent 1c992f84e5
commit 51cbf57470
6 files changed
+541 -230

No files matched your search

+351 -72
View File
@@ -1,112 +1,391 @@
//! A module implementing an io type backed by the C runtime's file descriptors, i.e. what's
//! returned from libc::open, even on windows.
use std::{cmp, ffi, io};
use std::{cmp, ffi, fmt, io};
#[cfg(windows)]
use libc::commit as fsync;
#[cfg(windows)]
unsafe extern "C" {
#[link_name = "_chsize_s"]
fn ftruncate(fd: i32, len: i64) -> i32;
}
#[cfg(not(windows))]
use libc::{fsync, ftruncate};
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::BorrowedHandle;
mod c {
pub(super) use libc::*;
#[cfg(windows)]
pub(super) use libc::commit as fsync;
#[cfg(windows)]
unsafe extern "C" {
#[link_name = "_chsize_s"]
pub(super) fn ftruncate(fd: i32, len: i64) -> i32;
}
}
// this is basically what CPython has for Py_off_t; windows uses long long
// for offsets, other platforms just use off_t
#[cfg(not(windows))]
pub type Offset = libc::off_t;
pub type Offset = c::off_t;
#[cfg(windows)]
pub type Offset = libc::c_longlong;
pub type Offset = c::c_longlong;
#[cfg(not(windows))]
pub type Raw = RawFd;
#[cfg(windows)]
pub type Raw = i32;
#[inline]
fn cvt<T, I: num_traits::PrimInt>(ret: I, f: impl FnOnce(I) -> T) -> io::Result<T> {
fn cvt<I: num_traits::PrimInt>(ret: I) -> io::Result<I> {
if ret < I::zero() {
Err(crate::os::last_os_error())
} else {
Ok(f(ret))
Ok(ret)
}
}
fn cvt_fd(ret: Raw) -> io::Result<Owned> {
cvt(ret).map(|fd| unsafe { Owned::from_raw(fd) })
}
const MAX_RW: usize = if cfg!(any(windows, target_vendor = "apple")) {
i32::MAX as usize
} else {
isize::MAX as usize
};
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Fd(pub i32);
#[cfg(not(windows))]
type OwnedInner = OwnedFd;
#[cfg(not(windows))]
type BorrowedInner<'fd> = BorrowedFd<'fd>;
impl Fd {
pub fn open(path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Self> {
cvt(unsafe { libc::open(path.as_ptr(), flags, mode) }, Fd)
}
#[cfg(windows)]
mod win {
use super::*;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
#[cfg(windows)]
pub fn wopen(path: &widestring::WideCStr, flags: i32, mode: i32) -> io::Result<Self> {
cvt(
unsafe { suppress_iph!(libc::wopen(path.as_ptr(), flags, mode)) },
Fd,
)
}
#[repr(transparent)]
pub(super) struct OwnedInner(i32);
#[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))]
pub fn openat(&self, path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Self> {
cvt(
unsafe { libc::openat(self.0, path.as_ptr(), flags, mode) },
Fd,
)
}
pub fn fsync(&self) -> io::Result<()> {
cvt(unsafe { suppress_iph!(fsync(self.0)) }, drop)
}
pub fn close(&self) -> io::Result<()> {
cvt(unsafe { suppress_iph!(libc::close(self.0)) }, drop)
}
pub fn ftruncate(&self, len: Offset) -> io::Result<()> {
cvt(unsafe { suppress_iph!(ftruncate(self.0, len)) }, drop)
}
#[cfg(windows)]
pub fn to_raw_handle(&self) -> io::Result<std::os::windows::io::RawHandle> {
unsafe extern "C" {
fn _get_osfhandle(fd: i32) -> libc::intptr_t;
impl OwnedInner {
#[inline]
pub unsafe fn from_raw_fd(fd: Raw) -> Self {
Self(fd)
}
let handle = unsafe { suppress_iph!(_get_osfhandle(self.0)) };
if handle == -1 {
Err(io::Error::last_os_error())
} else {
Ok(handle as _)
#[inline]
pub fn as_raw_fd(&self) -> Raw {
self.0
}
#[inline]
pub fn into_raw_fd(self) -> Raw {
let me = ManuallyDrop::new(self);
me.0
}
}
impl Drop for OwnedInner {
#[inline]
fn drop(&mut self) {
let _ = _close(self.0);
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub(super) struct BorrowedInner<'fd> {
fd: Raw,
_marker: PhantomData<&'fd Owned>,
}
impl BorrowedInner<'_> {
#[inline]
pub const unsafe fn borrow_raw(fd: Raw) -> Self {
Self {
fd,
_marker: PhantomData,
}
}
#[inline]
pub fn as_raw_fd(&self) -> Raw {
self.fd
}
}
}
impl io::Write for Fd {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let count = cmp::min(buf.len(), MAX_RW);
cvt(
unsafe { suppress_iph!(libc::write(self.0, buf.as_ptr() as _, count as _)) },
|i| i as usize,
)
#[cfg(windows)]
use self::win::{BorrowedInner, OwnedInner};
#[repr(transparent)]
pub struct Owned {
inner: OwnedInner,
}
impl fmt::Debug for Owned {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("crt_fd::Owned")
.field(&self.as_raw())
.finish()
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Borrowed<'fd> {
inner: BorrowedInner<'fd>,
}
impl<'fd> PartialEq for Borrowed<'fd> {
fn eq(&self, other: &Self) -> bool {
self.as_raw() == other.as_raw()
}
}
impl<'fd> Eq for Borrowed<'fd> {}
impl fmt::Debug for Borrowed<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("crt_fd::Borrowed")
.field(&self.as_raw())
.finish()
}
}
impl Owned {
/// Create a `crt_fd::Owned` from a raw file descriptor.
///
/// # Safety
///
/// `fd` must be a valid file descriptor.
#[inline]
pub unsafe fn from_raw(fd: Raw) -> Self {
let inner = unsafe { OwnedInner::from_raw_fd(fd) };
Self { inner }
}
/// Create a `crt_fd::Owned` from a raw file descriptor.
///
/// Returns an error if `fd` is -1.
///
/// # Safety
///
/// `fd` must be a valid file descriptor.
#[inline]
pub unsafe fn try_from_raw(fd: Raw) -> io::Result<Self> {
if fd == -1 {
Err(ebadf())
} else {
Ok(unsafe { Self::from_raw(fd) })
}
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
pub fn borrow(&self) -> Borrowed<'_> {
unsafe { Borrowed::borrow_raw(self.as_raw()) }
}
#[inline]
pub fn as_raw(&self) -> Raw {
self.inner.as_raw_fd()
}
#[inline]
pub fn into_raw(self) -> Raw {
self.inner.into_raw_fd()
}
}
impl io::Read for Fd {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let count = cmp::min(buf.len(), MAX_RW);
cvt(
unsafe { suppress_iph!(libc::read(self.0, buf.as_mut_ptr() as _, count as _)) },
|i| i as usize,
)
#[cfg(unix)]
impl From<Owned> for OwnedFd {
fn from(fd: Owned) -> Self {
fd.inner
}
}
#[cfg(unix)]
impl From<OwnedFd> for Owned {
fn from(fd: OwnedFd) -> Self {
Self { inner: fd }
}
}
#[cfg(unix)]
impl AsFd for Owned {
fn as_fd(&self) -> BorrowedFd<'_> {
self.inner.as_fd()
}
}
#[cfg(unix)]
impl AsRawFd for Owned {
fn as_raw_fd(&self) -> RawFd {
self.as_raw()
}
}
#[cfg(unix)]
impl FromRawFd for Owned {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
unsafe { Self::from_raw(fd) }
}
}
#[cfg(unix)]
impl IntoRawFd for Owned {
fn into_raw_fd(self) -> RawFd {
self.into_raw()
}
}
impl<'fd> Borrowed<'fd> {
/// Create a `crt_fd::Borrowed` from a raw file descriptor.
///
/// # Safety
///
/// `fd` must be a valid file descriptor.
#[inline]
pub const unsafe fn borrow_raw(fd: Raw) -> Self {
let inner = unsafe { BorrowedInner::borrow_raw(fd) };
Self { inner }
}
/// Create a `crt_fd::Borrowed` from a raw file descriptor.
///
/// Returns an error if `fd` is -1.
///
/// # Safety
///
/// `fd` must be a valid file descriptor.
#[inline]
pub unsafe fn try_borrow_raw(fd: Raw) -> io::Result<Self> {
if fd == -1 {
Err(ebadf())
} else {
Ok(unsafe { Self::borrow_raw(fd) })
}
}
#[inline]
pub fn as_raw(self) -> Raw {
self.inner.as_raw_fd()
}
}
#[cfg(unix)]
impl<'fd> From<Borrowed<'fd>> for BorrowedFd<'fd> {
fn from(fd: Borrowed<'fd>) -> Self {
fd.inner
}
}
#[cfg(unix)]
impl<'fd> From<BorrowedFd<'fd>> for Borrowed<'fd> {
fn from(fd: BorrowedFd<'fd>) -> Self {
Self { inner: fd }
}
}
#[cfg(unix)]
impl AsFd for Borrowed<'_> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.inner.as_fd()
}
}
#[cfg(unix)]
impl AsRawFd for Borrowed<'_> {
fn as_raw_fd(&self) -> RawFd {
self.as_raw()
}
}
#[inline]
fn ebadf() -> io::Error {
io::Error::from_raw_os_error(c::EBADF)
}
pub fn open(path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Owned> {
cvt_fd(unsafe { c::open(path.as_ptr(), flags, mode) })
}
#[cfg(windows)]
pub fn wopen(path: &widestring::WideCStr, flags: i32, mode: i32) -> io::Result<Owned> {
cvt_fd(unsafe { suppress_iph!(c::wopen(path.as_ptr(), flags, mode)) })
}
#[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))]
pub fn openat(dir: Borrowed<'_>, path: &ffi::CStr, flags: i32, mode: i32) -> io::Result<Owned> {
cvt_fd(unsafe { c::openat(dir.as_raw(), path.as_ptr(), flags, mode) })
}
pub fn fsync(fd: Borrowed<'_>) -> io::Result<()> {
cvt(unsafe { suppress_iph!(c::fsync(fd.as_raw())) })?;
Ok(())
}
fn _close(fd: Raw) -> io::Result<()> {
cvt(unsafe { suppress_iph!(c::close(fd)) })?;
Ok(())
}
pub fn close(fd: Owned) -> io::Result<()> {
_close(fd.into_raw())
}
pub fn ftruncate(fd: Borrowed<'_>, len: Offset) -> io::Result<()> {
cvt(unsafe { suppress_iph!(c::ftruncate(fd.as_raw(), len)) })?;
Ok(())
}
#[cfg(windows)]
pub fn as_handle(fd: Borrowed<'_>) -> io::Result<BorrowedHandle<'_>> {
unsafe extern "C" {
fn _get_osfhandle(fd: Borrowed<'_>) -> c::intptr_t;
}
let handle = unsafe { suppress_iph!(_get_osfhandle(fd)) };
if handle == -1 {
Err(io::Error::last_os_error())
} else {
Ok(unsafe { BorrowedHandle::borrow_raw(handle as _) })
}
}
fn _write(fd: Raw, buf: &[u8]) -> io::Result<usize> {
let count = cmp::min(buf.len(), MAX_RW);
let n = cvt(unsafe { suppress_iph!(c::write(fd, buf.as_ptr() as _, count as _)) })?;
Ok(n as usize)
}
fn _read(fd: Raw, buf: &mut [u8]) -> io::Result<usize> {
let count = cmp::min(buf.len(), MAX_RW);
let n = cvt(unsafe { suppress_iph!(libc::read(fd, buf.as_mut_ptr() as _, count as _)) })?;
Ok(n as usize)
}
pub fn write(fd: Borrowed<'_>, buf: &[u8]) -> io::Result<usize> {
_write(fd.as_raw(), buf)
}
pub fn read(fd: Borrowed<'_>, buf: &mut [u8]) -> io::Result<usize> {
_read(fd.as_raw(), buf)
}
macro_rules! impl_rw {
($t:ty) => {
impl io::Write for $t {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
_write(self.as_raw(), buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl io::Read for $t {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
_read(self.as_raw(), buf)
}
}
};
}
impl_rw!(Owned);
impl_rw!(Borrowed<'_>);
+24 -18
View File
@@ -1,7 +1,9 @@
use rustpython_common::crt_fd;
use crate::{
PyObjectRef, PyResult, VirtualMachine,
builtins::PyBaseExceptionRef,
convert::{ToPyException, TryFromObject},
convert::{IntoPyException, ToPyException, ToPyObject, TryFromObject},
function::FsPath,
object::AsObject,
};
@@ -95,32 +97,36 @@ impl TryFromObject for OsPath {
// path_t with allow_fd in CPython
#[derive(Clone)]
pub(crate) enum OsPathOrFd {
pub(crate) enum OsPathOrFd<'fd> {
Path(OsPath),
Fd(i32),
Fd(crt_fd::Borrowed<'fd>),
}
impl TryFromObject for OsPathOrFd {
impl TryFromObject for OsPathOrFd<'_> {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let r = match obj.try_index_opt(vm) {
Some(int) => Self::Fd(int?.try_to_primitive(vm)?),
None => Self::Path(obj.try_into_value(vm)?),
};
Ok(r)
match obj.try_index_opt(vm) {
Some(int) => {
let fd = int?.try_to_primitive(vm)?;
unsafe { crt_fd::Borrowed::try_borrow_raw(fd) }
.map(Self::Fd)
.map_err(|e| e.into_pyexception(vm))
}
None => obj.try_into_value(vm).map(Self::Path),
}
}
}
impl From<OsPath> for OsPathOrFd {
impl From<OsPath> for OsPathOrFd<'_> {
fn from(path: OsPath) -> Self {
Self::Path(path)
}
}
impl OsPathOrFd {
impl OsPathOrFd<'_> {
pub fn filename(&self, vm: &VirtualMachine) -> PyObjectRef {
match self {
Self::Path(path) => path.filename(vm),
Self::Fd(fd) => vm.ctx.new_int(*fd).into(),
Self::Fd(fd) => fd.to_pyobject(vm),
}
}
}
@@ -128,8 +134,8 @@ impl OsPathOrFd {
// TODO: preserve the input `PyObjectRef` of filename and filename2 (Failing check `self.assertIs(err.filename, name, str(func)`)
pub struct IOErrorBuilder<'a> {
error: &'a std::io::Error,
filename: Option<OsPathOrFd>,
filename2: Option<OsPathOrFd>,
filename: Option<OsPathOrFd<'a>>,
filename2: Option<OsPathOrFd<'a>>,
}
impl<'a> IOErrorBuilder<'a> {
@@ -141,13 +147,13 @@ impl<'a> IOErrorBuilder<'a> {
}
}
pub(crate) fn filename(mut self, filename: impl Into<OsPathOrFd>) -> Self {
pub(crate) fn filename(mut self, filename: impl Into<OsPathOrFd<'a>>) -> Self {
let filename = filename.into();
self.filename.replace(filename);
self
}
pub(crate) fn filename2(mut self, filename: impl Into<OsPathOrFd>) -> Self {
pub(crate) fn filename2(mut self, filename: impl Into<OsPathOrFd<'a>>) -> Self {
let filename = filename.into();
self.filename2.replace(filename);
self
@@ -155,10 +161,10 @@ impl<'a> IOErrorBuilder<'a> {
pub(crate) fn with_filename(
error: &'a std::io::Error,
filename: impl Into<OsPathOrFd>,
filename: impl Into<OsPathOrFd<'a>>,
vm: &VirtualMachine,
) -> PyBaseExceptionRef {
let zelf = Self {
let zelf = IOErrorBuilder {
error,
filename: Some(filename.into()),
filename2: None,
+21 -22
View File
@@ -3972,7 +3972,7 @@ mod _io {
// check file descriptor validity
#[cfg(unix)]
if let Ok(crate::ospath::OsPathOrFd::Fd(fd)) = file.clone().try_into_value(vm) {
nix::fcntl::fcntl(fd, nix::fcntl::F_GETFD)
nix::fcntl::fcntl(fd.as_raw(), nix::fcntl::F_GETFD)
.map_err(|_| crate::stdlib::os::errno_err(vm))?;
}
@@ -4131,8 +4131,8 @@ mod fileio {
use crate::{
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
builtins::{PyBaseExceptionRef, PyUtf8Str, PyUtf8StrRef},
common::crt_fd::Fd,
convert::ToPyException,
common::crt_fd,
convert::{IntoPyException, ToPyException},
function::{ArgBytesLike, ArgMemoryBuffer, OptionalArg, OptionalOption},
ospath::{IOErrorBuilder, OsPath, OsPathOrFd},
stdlib::os,
@@ -4303,7 +4303,7 @@ mod fileio {
let (fd, filename) = if let Some(fd) = arg_fd {
zelf.closefd.store(args.closefd);
(fd, OsPathOrFd::Fd(fd))
(fd, None)
} else {
zelf.closefd.store(true);
if !args.closefd {
@@ -4319,28 +4319,27 @@ mod fileio {
if fd < 0 {
return Err(vm.new_value_error(format!("opener returned {fd}")));
}
(
fd,
OsPathOrFd::try_from_object(vm, name.clone()).unwrap_or(OsPathOrFd::Fd(fd)),
)
(fd, None)
} else {
let path = OsPath::try_from_object(vm, name.clone())?;
#[cfg(any(unix, target_os = "wasi"))]
let fd = Fd::open(&path.clone().into_cstring(vm)?, flags, 0o666);
let fd = crt_fd::open(&path.clone().into_cstring(vm)?, flags, 0o666);
#[cfg(windows)]
let fd = Fd::wopen(&path.to_wide_cstring(vm)?, flags, 0o666);
let fd = crt_fd::wopen(&path.to_wide_cstring(vm)?, flags, 0o666);
let filename = OsPathOrFd::Path(path);
match fd {
Ok(fd) => (fd.0, filename),
Ok(fd) => (fd.into_raw(), Some(filename)),
Err(e) => return Err(IOErrorBuilder::with_filename(&e, filename, vm)),
}
}
};
zelf.fd.store(fd);
let fd = unsafe { crt_fd::Borrowed::borrow_raw(fd) };
let filename = filename.unwrap_or(OsPathOrFd::Fd(fd));
// TODO: _Py_set_inheritable
let fd_fstat = crate::common::fileutils::fstat(fd);
let fd_fstat = crate::common::fileutils::fstat(fd.as_raw());
#[cfg(windows)]
{
@@ -4370,7 +4369,7 @@ mod fileio {
zelf.as_object().set_attr("name", name, vm)?;
if mode.contains(Mode::APPENDING) {
let _ = os::lseek(fd as _, 0, libc::SEEK_END, vm);
let _ = os::lseek(fd, 0, libc::SEEK_END, vm);
}
Ok(())
@@ -4435,8 +4434,9 @@ mod fileio {
}
}
fn get_fd(&self, vm: &VirtualMachine) -> PyResult<Fd> {
self.fileno(vm).map(Fd)
fn get_fd(&self, vm: &VirtualMachine) -> PyResult<crt_fd::Borrowed<'_>> {
self.fileno(vm)
.map(|fd| unsafe { crt_fd::Borrowed::borrow_raw(fd) })
}
#[pymethod]
@@ -4554,8 +4554,7 @@ mod fileio {
}
let fd = zelf.fd.swap(-1);
if fd >= 0 {
Fd(fd)
.close()
crt_fd::close(unsafe { crt_fd::Owned::from_raw(fd) })
.map_err(|err| Self::io_error(zelf, err, vm))?;
}
res
@@ -4563,7 +4562,7 @@ mod fileio {
#[pymethod]
fn seekable(&self, vm: &VirtualMachine) -> PyResult<bool> {
let fd = self.fileno(vm)?;
let fd = self.get_fd(vm)?;
Ok(self.seekable.load().unwrap_or_else(|| {
let seekable = os::lseek(fd, 0, libc::SEEK_CUR, vm).is_ok();
self.seekable.store(Some(seekable));
@@ -4579,7 +4578,7 @@ mod fileio {
vm: &VirtualMachine,
) -> PyResult<Offset> {
let how = how.unwrap_or(0);
let fd = self.fileno(vm)?;
let fd = self.get_fd(vm)?;
let offset = get_offset(offset, vm)?;
os::lseek(fd, offset, how, vm)
@@ -4587,18 +4586,18 @@ mod fileio {
#[pymethod]
fn tell(&self, vm: &VirtualMachine) -> PyResult<Offset> {
let fd = self.fileno(vm)?;
let fd = self.get_fd(vm)?;
os::lseek(fd, 0, libc::SEEK_CUR, vm)
}
#[pymethod]
fn truncate(&self, len: OptionalOption, vm: &VirtualMachine) -> PyResult<Offset> {
let fd = self.fileno(vm)?;
let fd = self.get_fd(vm)?;
let len = match len.flatten() {
Some(l) => get_offset(l, vm)?,
None => os::lseek(fd, 0, libc::SEEK_CUR, vm)?,
};
os::ftruncate(fd, len, vm)?;
os::ftruncate(fd, len).map_err(|e| e.into_pyexception(vm))?;
Ok(len)
}
+116 -89
View File
@@ -1,10 +1,10 @@
// spell-checker:disable
use crate::{
AsObject, Py, PyPayload, PyResult, VirtualMachine,
AsObject, Py, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
builtins::{PyBaseExceptionRef, PyModule, PySet},
common::crt_fd::Fd,
convert::ToPyException,
common::crt_fd,
convert::{IntoPyException, ToPyException, ToPyObject},
function::{ArgumentError, FromArgs, FuncArgs},
};
use std::{ffi, fs, io, path::Path};
@@ -54,13 +54,13 @@ cfg_if::cfg_if! {
const AT_FDCWD: i32 = -100;
}
}
const DEFAULT_DIR_FD: Fd = Fd(AT_FDCWD);
const DEFAULT_DIR_FD: crt_fd::Borrowed<'static> = unsafe { crt_fd::Borrowed::borrow_raw(AT_FDCWD) };
// XXX: AVAILABLE should be a bool, but we can't yet have it as a bool and just cast it to usize
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct DirFd<const AVAILABLE: usize>(pub(crate) [Fd; AVAILABLE]);
pub struct DirFd<'fd, const AVAILABLE: usize>(pub(crate) [crt_fd::Borrowed<'fd>; AVAILABLE]);
impl<const AVAILABLE: usize> Default for DirFd<AVAILABLE> {
impl<const AVAILABLE: usize> Default for DirFd<'_, AVAILABLE> {
fn default() -> Self {
Self([DEFAULT_DIR_FD; AVAILABLE])
}
@@ -68,33 +68,30 @@ impl<const AVAILABLE: usize> Default for DirFd<AVAILABLE> {
// not used on all platforms
#[allow(unused)]
impl DirFd<1> {
impl<'fd> DirFd<'fd, 1> {
#[inline(always)]
pub(crate) fn fd_opt(&self) -> Option<Fd> {
self.get_opt().map(Fd)
pub(crate) fn get_opt(self) -> Option<crt_fd::Borrowed<'fd>> {
let [fd] = self.0;
(fd != DEFAULT_DIR_FD).then_some(fd)
}
#[inline]
pub(crate) fn get_opt(&self) -> Option<i32> {
let fd = self.fd();
if fd == DEFAULT_DIR_FD {
None
} else {
Some(fd.0)
}
pub(crate) fn raw_opt(self) -> Option<i32> {
self.get_opt().map(|fd| fd.as_raw())
}
#[inline(always)]
pub(crate) const fn fd(&self) -> Fd {
self.0[0]
pub(crate) const fn get(self) -> crt_fd::Borrowed<'fd> {
let [fd] = self.0;
fd
}
}
impl<const AVAILABLE: usize> FromArgs for DirFd<AVAILABLE> {
impl<const AVAILABLE: usize> FromArgs for DirFd<'_, AVAILABLE> {
fn from_args(vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
let fd = match args.take_keyword("dir_fd") {
Some(o) if vm.is_none(&o) => DEFAULT_DIR_FD,
None => DEFAULT_DIR_FD,
Some(o) if vm.is_none(&o) => Ok(DEFAULT_DIR_FD),
None => Ok(DEFAULT_DIR_FD),
Some(o) => {
let fd = o.try_index_opt(vm).unwrap_or_else(|| {
Err(vm.new_type_error(format!(
@@ -103,14 +100,15 @@ impl<const AVAILABLE: usize> FromArgs for DirFd<AVAILABLE> {
)))
})?;
let fd = fd.try_to_primitive(vm)?;
Fd(fd)
unsafe { crt_fd::Borrowed::try_borrow_raw(fd) }
}
};
if AVAILABLE == 0 && fd != DEFAULT_DIR_FD {
if AVAILABLE == 0 && fd.as_ref().is_ok_and(|&fd| fd != DEFAULT_DIR_FD) {
return Err(vm
.new_not_implemented_error("dir_fd unavailable on this platform")
.into());
}
let fd = fd.map_err(|e| e.to_pyexception(vm))?;
Ok(Self([fd; AVAILABLE]))
}
}
@@ -125,6 +123,32 @@ fn bytes_as_os_str<'a>(b: &'a [u8], vm: &VirtualMachine) -> PyResult<&'a ffi::Os
.map_err(|_| vm.new_unicode_decode_error("can't decode path for utf-8"))
}
impl TryFromObject for crt_fd::Owned {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let fd = crt_fd::Raw::try_from_object(vm, obj)?;
unsafe { crt_fd::Owned::try_from_raw(fd) }.map_err(|e| e.into_pyexception(vm))
}
}
impl TryFromObject for crt_fd::Borrowed<'_> {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let fd = crt_fd::Raw::try_from_object(vm, obj)?;
unsafe { crt_fd::Borrowed::try_borrow_raw(fd) }.map_err(|e| e.into_pyexception(vm))
}
}
impl ToPyObject for crt_fd::Owned {
fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
self.into_raw().to_pyobject(vm)
}
}
impl ToPyObject for crt_fd::Borrowed<'_> {
fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
self.as_raw().to_pyobject(vm)
}
}
#[pymodule(sub)]
pub(super) mod _os {
use super::{DirFd, FollowSymlinks, SupportFunc, errno_err};
@@ -134,7 +158,7 @@ pub(super) mod _os {
PyBytesRef, PyGenericAlias, PyIntRef, PyStrRef, PyTuple, PyTupleRef, PyTypeRef,
},
common::{
crt_fd::{Fd, Offset},
crt_fd,
fileutils::StatStruct,
lock::{OnceCell, PyRwLock},
suppress_iph,
@@ -153,7 +177,7 @@ pub(super) mod _os {
use std::{
env, ffi, fs,
fs::OpenOptions,
io::{self, Read, Write},
io,
path::PathBuf,
time::{Duration, SystemTime},
};
@@ -180,30 +204,32 @@ pub(super) mod _os {
pub(crate) const X_OK: u8 = 1 << 0;
#[pyfunction]
fn close(fileno: i32, vm: &VirtualMachine) -> PyResult<()> {
Fd(fileno).close().map_err(|e| e.into_pyexception(vm))
fn close(fileno: crt_fd::Owned) -> io::Result<()> {
crt_fd::close(fileno)
}
#[pyfunction]
fn closerange(fd_low: i32, fd_high: i32) {
for fileno in fd_low..fd_high {
let _ = Fd(fileno).close();
if let Ok(fd) = unsafe { crt_fd::Owned::try_from_raw(fileno) } {
drop(fd);
}
}
}
#[cfg(any(unix, windows, target_os = "wasi"))]
#[derive(FromArgs)]
struct OpenArgs {
struct OpenArgs<'fd> {
path: OsPath,
flags: i32,
#[pyarg(any, default)]
mode: Option<i32>,
#[pyarg(flatten)]
dir_fd: DirFd<{ OPEN_DIR_FD as usize }>,
dir_fd: DirFd<'fd, { OPEN_DIR_FD as usize }>,
}
#[pyfunction]
fn open(args: OpenArgs, vm: &VirtualMachine) -> PyResult<i32> {
fn open(args: OpenArgs<'_>, vm: &VirtualMachine) -> PyResult<crt_fd::Owned> {
os_open(args.path, args.flags, args.mode, args.dir_fd, vm)
}
@@ -212,9 +238,9 @@ pub(super) mod _os {
name: OsPath,
flags: i32,
mode: Option<i32>,
dir_fd: DirFd<{ OPEN_DIR_FD as usize }>,
dir_fd: DirFd<'_, { OPEN_DIR_FD as usize }>,
vm: &VirtualMachine,
) -> PyResult<i32> {
) -> PyResult<crt_fd::Owned> {
let mode = mode.unwrap_or(0o777);
#[cfg(windows)]
let fd = {
@@ -229,51 +255,42 @@ pub(super) mod _os {
#[cfg(not(target_os = "wasi"))]
let flags = flags | libc::O_CLOEXEC;
#[cfg(not(target_os = "redox"))]
if let Some(dir_fd) = dir_fd.fd_opt() {
dir_fd.openat(&name, flags, mode)
if let Some(dir_fd) = dir_fd.get_opt() {
crt_fd::openat(dir_fd, &name, flags, mode)
} else {
Fd::open(&name, flags, mode)
crt_fd::open(&name, flags, mode)
}
#[cfg(target_os = "redox")]
{
let [] = dir_fd.0;
Fd::open(&name, flags, mode)
crt_fd::open(&name, flags, mode)
}
};
fd.map(|fd| fd.0)
.map_err(|err| IOErrorBuilder::with_filename(&err, name, vm))
fd.map_err(|err| IOErrorBuilder::with_filename(&err, name, vm))
}
#[pyfunction]
fn fsync(fd: i32, vm: &VirtualMachine) -> PyResult<()> {
Fd(fd).fsync().map_err(|err| err.into_pyexception(vm))
fn fsync(fd: crt_fd::Borrowed<'_>) -> io::Result<()> {
crt_fd::fsync(fd)
}
#[pyfunction]
fn read(fd: i32, n: usize, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
fn read(fd: crt_fd::Borrowed<'_>, n: usize, vm: &VirtualMachine) -> io::Result<PyBytesRef> {
let mut buffer = vec![0u8; n];
let mut file = Fd(fd);
let n = file
.read(&mut buffer)
.map_err(|err| err.into_pyexception(vm))?;
let n = crt_fd::read(fd, &mut buffer)?;
buffer.truncate(n);
Ok(vm.ctx.new_bytes(buffer))
}
#[pyfunction]
fn write(fd: i32, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult {
let mut file = Fd(fd);
let written = data
.with_ref(|b| file.write(b))
.map_err(|err| err.into_pyexception(vm))?;
Ok(vm.ctx.new_int(written).into())
fn write(fd: crt_fd::Borrowed<'_>, data: ArgBytesLike) -> io::Result<usize> {
data.with_ref(|b| crt_fd::write(fd, b))
}
#[pyfunction]
#[pyfunction(name = "unlink")]
fn remove(path: OsPath, dir_fd: DirFd<0>, vm: &VirtualMachine) -> PyResult<()> {
fn remove(path: OsPath, dir_fd: DirFd<'_, 0>, vm: &VirtualMachine) -> PyResult<()> {
let [] = dir_fd.0;
let is_junction = cfg!(windows)
&& fs::metadata(&path).is_ok_and(|meta| meta.file_type().is_dir())
@@ -291,13 +308,13 @@ pub(super) mod _os {
fn mkdir(
path: OsPath,
mode: OptionalArg<i32>,
dir_fd: DirFd<{ MKDIR_DIR_FD as usize }>,
dir_fd: DirFd<'_, { MKDIR_DIR_FD as usize }>,
vm: &VirtualMachine,
) -> PyResult<()> {
let mode = mode.unwrap_or(0o777);
let c_path = path.clone().into_cstring(vm)?;
#[cfg(not(target_os = "redox"))]
if let Some(fd) = dir_fd.get_opt() {
if let Some(fd) = dir_fd.raw_opt() {
let res = unsafe { libc::mkdirat(fd, c_path.as_ptr(), mode as _) };
return if res < 0 {
let err = crate::common::os::last_os_error();
@@ -322,7 +339,7 @@ pub(super) mod _os {
}
#[pyfunction]
fn rmdir(path: OsPath, dir_fd: DirFd<0>, vm: &VirtualMachine) -> PyResult<()> {
fn rmdir(path: OsPath, dir_fd: DirFd<'_, 0>, vm: &VirtualMachine) -> PyResult<()> {
let [] = dir_fd.0;
fs::remove_dir(&path).map_err(|err| IOErrorBuilder::with_filename(&err, path, vm))
}
@@ -330,7 +347,10 @@ pub(super) mod _os {
const LISTDIR_FD: bool = cfg!(all(unix, not(target_os = "redox")));
#[pyfunction]
fn listdir(path: OptionalArg<OsPathOrFd>, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
fn listdir(
path: OptionalArg<OsPathOrFd<'_>>,
vm: &VirtualMachine,
) -> PyResult<Vec<PyObjectRef>> {
let path = path.unwrap_or_else(|| OsPathOrFd::Path(OsPath::new_str(".")));
let list = match path {
OsPathOrFd::Path(path) => {
@@ -358,7 +378,8 @@ pub(super) mod _os {
#[cfg(all(unix, not(target_os = "redox")))]
{
use rustpython_common::os::ffi::OsStrExt;
let new_fd = nix::unistd::dup(fno).map_err(|e| e.into_pyexception(vm))?;
let new_fd =
nix::unistd::dup(fno.as_raw()).map_err(|e| e.into_pyexception(vm))?;
let mut dir =
nix::dir::Dir::from_fd(new_fd).map_err(|e| e.into_pyexception(vm))?;
dir.iter()
@@ -430,7 +451,7 @@ pub(super) mod _os {
}
#[pyfunction]
fn readlink(path: OsPath, dir_fd: DirFd<0>, vm: &VirtualMachine) -> PyResult {
fn readlink(path: OsPath, dir_fd: DirFd<'_, 0>, vm: &VirtualMachine) -> PyResult {
let mode = path.mode;
let [] = dir_fd.0;
let path =
@@ -515,7 +536,7 @@ pub(super) mod _os {
#[pymethod]
fn stat(
&self,
dir_fd: DirFd<{ STAT_DIR_FD as usize }>,
dir_fd: DirFd<'_, { STAT_DIR_FD as usize }>,
follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
) -> PyResult {
@@ -847,8 +868,8 @@ pub(super) mod _os {
#[cfg(not(windows))]
fn stat_inner(
file: OsPathOrFd,
dir_fd: DirFd<{ STAT_DIR_FD as usize }>,
file: OsPathOrFd<'_>,
dir_fd: DirFd<'_, { STAT_DIR_FD as usize }>,
follow_symlinks: FollowSymlinks,
) -> io::Result<Option<StatStruct>> {
let mut stat = std::mem::MaybeUninit::uninit();
@@ -862,7 +883,7 @@ pub(super) mod _os {
};
#[cfg(not(target_os = "redox"))]
let fstatat_ret = dir_fd.get_opt().map(|dir_fd| {
let fstatat_ret = dir_fd.raw_opt().map(|dir_fd| {
let flags = if follow_symlinks.0 {
0
} else {
@@ -881,7 +902,7 @@ pub(super) mod _os {
}
})
}
OsPathOrFd::Fd(fd) => unsafe { libc::fstat(fd, stat.as_mut_ptr()) },
OsPathOrFd::Fd(fd) => unsafe { libc::fstat(fd.as_raw(), stat.as_mut_ptr()) },
};
if ret < 0 {
return Err(io::Error::last_os_error());
@@ -892,8 +913,8 @@ pub(super) mod _os {
#[pyfunction]
#[pyfunction(name = "fstat")]
fn stat(
file: OsPathOrFd,
dir_fd: DirFd<{ STAT_DIR_FD as usize }>,
file: OsPathOrFd<'_>,
dir_fd: DirFd<'_, { STAT_DIR_FD as usize }>,
follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
) -> PyResult {
@@ -905,8 +926,8 @@ pub(super) mod _os {
#[pyfunction]
fn lstat(
file: OsPathOrFd,
dir_fd: DirFd<{ STAT_DIR_FD as usize }>,
file: OsPathOrFd<'_>,
dir_fd: DirFd<'_, { STAT_DIR_FD as usize }>,
vm: &VirtualMachine,
) -> PyResult {
stat(file, dir_fd, FollowSymlinks(false), vm)
@@ -996,16 +1017,22 @@ pub(super) mod _os {
}
#[pyfunction]
pub fn lseek(fd: i32, position: Offset, how: i32, vm: &VirtualMachine) -> PyResult<Offset> {
pub fn lseek(
fd: crt_fd::Borrowed<'_>,
position: crt_fd::Offset,
how: i32,
vm: &VirtualMachine,
) -> PyResult<crt_fd::Offset> {
#[cfg(not(windows))]
let res = unsafe { suppress_iph!(libc::lseek(fd, position, how)) };
let res = unsafe { suppress_iph!(libc::lseek(fd.as_raw(), position, how)) };
#[cfg(windows)]
let res = unsafe {
use std::os::windows::io::AsRawHandle;
use windows_sys::Win32::Storage::FileSystem;
let handle = Fd(fd).to_raw_handle().map_err(|e| e.into_pyexception(vm))?;
let handle = crt_fd::as_handle(fd).map_err(|e| e.into_pyexception(vm))?;
let mut distance_to_move: [i32; 2] = std::mem::transmute(position);
let ret = FileSystem::SetFilePointer(
handle as _,
handle.as_raw_handle(),
distance_to_move[0],
&mut distance_to_move[1],
how as _,
@@ -1039,20 +1066,20 @@ pub(super) mod _os {
}
#[derive(FromArgs)]
struct UtimeArgs {
struct UtimeArgs<'fd> {
path: OsPath,
#[pyarg(any, default)]
times: Option<PyTupleRef>,
#[pyarg(named, default)]
ns: Option<PyTupleRef>,
#[pyarg(flatten)]
dir_fd: DirFd<{ UTIME_DIR_FD as usize }>,
dir_fd: DirFd<'fd, { UTIME_DIR_FD as usize }>,
#[pyarg(flatten)]
follow_symlinks: FollowSymlinks,
}
#[pyfunction]
fn utime(args: UtimeArgs, vm: &VirtualMachine) -> PyResult<()> {
fn utime(args: UtimeArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
let parse_tup = |tup: &Py<PyTuple>| -> Option<(PyObjectRef, PyObjectRef)> {
if tup.len() != 2 {
None
@@ -1108,7 +1135,7 @@ pub(super) mod _os {
path: OsPath,
acc: Duration,
modif: Duration,
dir_fd: DirFd<{ UTIME_DIR_FD as usize }>,
dir_fd: DirFd<'_, { UTIME_DIR_FD as usize }>,
_follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -1126,7 +1153,7 @@ pub(super) mod _os {
let ret = unsafe {
libc::utimensat(
dir_fd.fd().0,
dir_fd.get().as_raw(),
path.as_ptr(),
times.as_ptr(),
if _follow_symlinks.0 {
@@ -1273,22 +1300,22 @@ pub(super) mod _os {
#[cfg(target_os = "linux")]
#[derive(FromArgs)]
struct CopyFileRangeArgs {
struct CopyFileRangeArgs<'fd> {
#[pyarg(positional)]
src: i32,
src: crt_fd::Borrowed<'fd>,
#[pyarg(positional)]
dst: i32,
dst: crt_fd::Borrowed<'fd>,
#[pyarg(positional)]
count: i64,
#[pyarg(any, default)]
offset_src: Option<Offset>,
offset_src: Option<crt_fd::Offset>,
#[pyarg(any, default)]
offset_dst: Option<Offset>,
offset_dst: Option<crt_fd::Offset>,
}
#[cfg(target_os = "linux")]
#[pyfunction]
fn copy_file_range(args: CopyFileRangeArgs, vm: &VirtualMachine) -> PyResult<usize> {
fn copy_file_range(args: CopyFileRangeArgs<'_>, vm: &VirtualMachine) -> PyResult<usize> {
let p_offset_src = args.offset_src.as_ref().map_or_else(std::ptr::null, |x| x);
let p_offset_dst = args.offset_dst.as_ref().map_or_else(std::ptr::null, |x| x);
let count: usize = args
@@ -1328,14 +1355,14 @@ pub(super) mod _os {
}
#[pyfunction]
pub fn ftruncate(fd: i32, length: Offset, vm: &VirtualMachine) -> PyResult<()> {
Fd(fd).ftruncate(length).map_err(|e| e.into_pyexception(vm))
pub fn ftruncate(fd: crt_fd::Borrowed<'_>, length: crt_fd::Offset) -> io::Result<()> {
crt_fd::ftruncate(fd, length)
}
#[pyfunction]
fn truncate(path: PyObjectRef, length: Offset, vm: &VirtualMachine) -> PyResult<()> {
if let Ok(fd) = path.try_to_value(vm) {
return ftruncate(fd, length, vm);
fn truncate(path: PyObjectRef, length: crt_fd::Offset, vm: &VirtualMachine) -> PyResult<()> {
if let Ok(fd) = path.clone().try_into_value(vm) {
return ftruncate(fd, length).map_err(|e| e.into_pyexception(vm));
}
#[cold]
+26 -26
View File
@@ -355,22 +355,22 @@ pub mod module {
}
#[derive(FromArgs)]
pub(super) struct SymlinkArgs {
pub(super) struct SymlinkArgs<'fd> {
src: OsPath,
dst: OsPath,
#[pyarg(flatten)]
_target_is_directory: TargetIsDirectory,
#[pyarg(flatten)]
dir_fd: DirFd<{ _os::SYMLINK_DIR_FD as usize }>,
dir_fd: DirFd<'fd, { _os::SYMLINK_DIR_FD as usize }>,
}
#[pyfunction]
pub(super) fn symlink(args: SymlinkArgs, vm: &VirtualMachine) -> PyResult<()> {
pub(super) fn symlink(args: SymlinkArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
let src = args.src.into_cstring(vm)?;
let dst = args.dst.into_cstring(vm)?;
#[cfg(not(target_os = "redox"))]
{
nix::unistd::symlinkat(&*src, args.dir_fd.get_opt(), &*dst)
nix::unistd::symlinkat(&*src, args.dir_fd.raw_opt(), &*dst)
.map_err(|err| err.into_pyexception(vm))
}
#[cfg(target_os = "redox")]
@@ -403,10 +403,10 @@ pub mod module {
#[cfg(not(target_os = "redox"))]
#[pyfunction]
fn chown(
path: OsPathOrFd,
path: OsPathOrFd<'_>,
uid: isize,
gid: isize,
dir_fd: DirFd<1>,
dir_fd: DirFd<'_, 1>,
follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
) -> PyResult<()> {
@@ -432,12 +432,12 @@ pub mod module {
nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW
};
let dir_fd = dir_fd.get_opt();
let dir_fd = dir_fd.raw_opt();
match path {
OsPathOrFd::Path(ref p) => {
nix::unistd::fchownat(dir_fd, p.path.as_os_str(), uid, gid, flag)
}
OsPathOrFd::Fd(fd) => nix::unistd::fchown(fd, uid, gid),
OsPathOrFd::Fd(fd) => nix::unistd::fchown(fd.as_raw(), uid, gid),
}
.map_err(|err| {
// Use `From<nix::Error> for io::Error` when it is available
@@ -461,9 +461,9 @@ pub mod module {
#[cfg(not(target_os = "redox"))]
#[pyfunction]
fn fchown(fd: i32, uid: isize, gid: isize, vm: &VirtualMachine) -> PyResult<()> {
fn fchown(fd: BorrowedFd<'_>, uid: isize, gid: isize, vm: &VirtualMachine) -> PyResult<()> {
chown(
OsPathOrFd::Fd(fd),
OsPathOrFd::Fd(fd.into()),
uid,
gid,
DirFd::default(),
@@ -590,7 +590,7 @@ pub mod module {
#[cfg(not(target_os = "redox"))]
#[derive(FromArgs)]
struct MknodArgs {
struct MknodArgs<'fd> {
#[pyarg(any)]
path: OsPath,
#[pyarg(any)]
@@ -598,11 +598,11 @@ pub mod module {
#[pyarg(any)]
device: libc::dev_t,
#[pyarg(flatten)]
dir_fd: DirFd<{ MKNOD_DIR_FD as usize }>,
dir_fd: DirFd<'fd, { MKNOD_DIR_FD as usize }>,
}
#[cfg(not(target_os = "redox"))]
impl MknodArgs {
impl MknodArgs<'_> {
fn _mknod(self, vm: &VirtualMachine) -> PyResult<i32> {
Ok(unsafe {
libc::mknod(
@@ -615,7 +615,7 @@ pub mod module {
#[cfg(not(target_vendor = "apple"))]
fn mknod(self, vm: &VirtualMachine) -> PyResult<()> {
let ret = match self.dir_fd.get_opt() {
let ret = match self.dir_fd.raw_opt() {
None => self._mknod(vm)?,
Some(non_default_fd) => unsafe {
libc::mknodat(
@@ -639,7 +639,7 @@ pub mod module {
#[cfg(not(target_os = "redox"))]
#[pyfunction]
fn mknod(args: MknodArgs, vm: &VirtualMachine) -> PyResult<()> {
fn mknod(args: MknodArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
args.mknod(vm)
}
@@ -920,7 +920,7 @@ pub mod module {
fn _chmod(
path: OsPath,
dir_fd: DirFd<0>,
dir_fd: DirFd<'_, 0>,
mode: u32,
follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
@@ -938,9 +938,9 @@ pub mod module {
}
#[cfg(not(target_os = "redox"))]
fn _fchmod(fd: RawFd, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
fn _fchmod(fd: BorrowedFd<'_>, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
nix::sys::stat::fchmod(
fd,
fd.as_raw_fd(),
nix::sys::stat::Mode::from_bits(mode as libc::mode_t).unwrap(),
)
.map_err(|err| err.into_pyexception(vm))
@@ -949,8 +949,8 @@ pub mod module {
#[cfg(not(target_os = "redox"))]
#[pyfunction]
fn chmod(
path: OsPathOrFd,
dir_fd: DirFd<0>,
path: OsPathOrFd<'_>,
dir_fd: DirFd<'_, 0>,
mode: u32,
follow_symlinks: FollowSymlinks,
vm: &VirtualMachine,
@@ -963,7 +963,7 @@ pub mod module {
}
_chmod(path, dir_fd, mode, follow_symlinks, vm)
}
OsPathOrFd::Fd(fd) => _fchmod(fd, mode, vm),
OsPathOrFd::Fd(fd) => _fchmod(fd.into(), mode, vm),
}
}
@@ -981,7 +981,7 @@ pub mod module {
#[cfg(not(target_os = "redox"))]
#[pyfunction]
fn fchmod(fd: RawFd, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
fn fchmod(fd: BorrowedFd<'_>, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
_fchmod(fd, mode, vm)
}
@@ -2065,7 +2065,7 @@ pub mod module {
#[cfg(unix)]
#[pyfunction]
fn pathconf(
path: OsPathOrFd,
path: OsPathOrFd<'_>,
PathconfName(name): PathconfName,
vm: &VirtualMachine,
) -> PyResult<Option<libc::c_long>> {
@@ -2078,7 +2078,7 @@ pub mod module {
let path = path.clone().into_cstring(vm)?;
unsafe { libc::pathconf(path.as_ptr(), name) }
}
OsPathOrFd::Fd(fd) => unsafe { libc::fpathconf(*fd, name) },
OsPathOrFd::Fd(fd) => unsafe { libc::fpathconf(fd.as_raw(), name) },
};
if raw == -1 {
@@ -2098,11 +2098,11 @@ pub mod module {
#[pyfunction]
fn fpathconf(
fd: i32,
fd: BorrowedFd<'_>,
name: PathconfName,
vm: &VirtualMachine,
) -> PyResult<Option<libc::c_long>> {
pathconf(OsPathOrFd::Fd(fd), name, vm)
pathconf(OsPathOrFd::Fd(fd.into()), name, vm)
}
#[pyattr]
+3 -3
View File
@@ -26,17 +26,17 @@ pub(crate) mod module {
#[derive(FromArgs)]
#[allow(unused)]
pub(super) struct SymlinkArgs {
pub(super) struct SymlinkArgs<'a> {
src: OsPath,
dst: OsPath,
#[pyarg(flatten)]
_target_is_directory: TargetIsDirectory,
#[pyarg(flatten)]
_dir_fd: DirFd<{ _os::SYMLINK_DIR_FD as usize }>,
_dir_fd: DirFd<'a, { _os::SYMLINK_DIR_FD as usize }>,
}
#[pyfunction]
pub(super) fn symlink(_args: SymlinkArgs, vm: &VirtualMachine) -> PyResult<()> {
pub(super) fn symlink(_args: SymlinkArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
os_unimpl("os.symlink", vm)
}