diff --git a/crates/host_env/src/posix.rs b/crates/host_env/src/posix.rs index f10e99ac938..ef3a430a7ed 100644 --- a/crates/host_env/src/posix.rs +++ b/crates/host_env/src/posix.rs @@ -10,6 +10,8 @@ use std::os::fd::FromRawFd; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd}; use std::path::Path; +use crate::crt_fd; + pub struct UnameInfo { pub sysname: String, pub nodename: String, @@ -174,24 +176,32 @@ pub fn fcopyfile(in_fd: i32, out_fd: i32, flags: u32) -> std::io::Result<()> { } } -#[cfg(not(windows))] -pub fn make_dir(path: &CStr, mode: u32) -> std::io::Result<()> { - let ret = unsafe { libc::mkdir(path.as_ptr(), mode as _) }; - if ret < 0 { - Err(std::io::Error::last_os_error()) +#[cfg(not(unix))] +pub fn make_dir( + dir_fd: Option>, + path: &Path, + _mode: u32, +) -> std::io::Result<()> { + // TODO: On Windows, Python has an override if the mode is 0o700 + if dir_fd.is_none() { + std::fs::create_dir(path) } else { - Ok(()) + core::hint::cold_path(); + Err(std::io::Error::new( + std::io::ErrorKind::Unsupported, + "mkdirat is not available on this platform", + )) } } -#[cfg(all(not(windows), not(target_os = "redox")))] -pub fn make_dir_at(dir_fd: i32, path: &CStr, mode: u32) -> std::io::Result<()> { - let ret = unsafe { libc::mkdirat(dir_fd, path.as_ptr(), mode as _) }; - if ret < 0 { - Err(std::io::Error::last_os_error()) - } else { - Ok(()) - } +#[cfg(unix)] +pub fn make_dir( + dir_fd: Option>, + path: &Path, + mode: u32, +) -> std::io::Result<()> { + let dir_fd = dir_fd.as_ref().map_or(rustix::fs::CWD, AsFd::as_fd); + rustix::fs::mkdirat(dir_fd, path, mode.into()).map_err(Into::into) } #[cfg(unix)] diff --git a/crates/host_env/src/posix_wasi.rs b/crates/host_env/src/posix_wasi.rs index d4eff8c6866..7649753a0f4 100644 --- a/crates/host_env/src/posix_wasi.rs +++ b/crates/host_env/src/posix_wasi.rs @@ -1,17 +1,17 @@ use alloc::ffi::CString; use core::{ffi::CStr, time::Duration}; -use std::{ffi::OsStr, io}; +use rustix::fd::AsFd; +use std::{ffi::OsStr, io, path::Path}; -use crate::os::CheckLibcResult; +use crate::{crt_fd, os::CheckLibcResult}; -pub fn make_dir(path: &CStr, mode: u32) -> io::Result<()> { - unsafe { libc::mkdir(path.as_ptr(), mode as _) }.check_libc_neg()?; - Ok(()) -} - -pub fn make_dir_at(dir_fd: i32, path: &CStr, mode: u32) -> io::Result<()> { - unsafe { libc::mkdirat(dir_fd, path.as_ptr(), mode as _) }.check_libc_neg()?; - Ok(()) +pub fn make_dir( + dir_fd: Option>, + path: &Path, + mode: u32, +) -> std::io::Result<()> { + let dir_fd = dir_fd.as_ref().map_or(rustix::fs::CWD, AsFd::as_fd); + rustix::fs::mkdirat(dir_fd, path, mode.into()).map_err(Into::into) } pub fn remove_dir_at(dir_fd: i32, path: &CStr) -> io::Result<()> { diff --git a/crates/vm/src/stdlib/os.rs b/crates/vm/src/stdlib/os.rs index 4a1cbe2aecd..5de59206352 100644 --- a/crates/vm/src/stdlib/os.rs +++ b/crates/vm/src/stdlib/os.rs @@ -29,7 +29,7 @@ pub struct TargetIsDirectory { } cfg_select! { - all(any(unix, target_os = "wasi"), not(target_os = "redox")) => { + any(unix, target_os = "wasi") => { use libc::AT_FDCWD; } _ => { @@ -181,10 +181,14 @@ pub(super) mod _os { use rustpython_host_env::nt as host_nt; #[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))] use rustpython_host_env::posix as host_posix; - use std::{fs, io, path::PathBuf, time::SystemTime}; + use std::{ + fs, io, + path::{Path, PathBuf}, + time::SystemTime, + }; const OPEN_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox"))); - pub(crate) const MKDIR_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox"))); + pub(crate) const MKDIR_DIR_FD: bool = cfg!(any(unix, target_os = "wasi")); const STAT_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox"))); const UTIME_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox"))); pub(crate) const SYMLINK_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox"))); @@ -338,7 +342,6 @@ pub(super) mod _os { } } - #[cfg(not(windows))] #[pyfunction] fn mkdir( path: OsPath, @@ -346,24 +349,10 @@ pub(super) mod _os { 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.raw_opt() { - return if let Err(err) = - crate::host_env::posix::make_dir_at(fd, c_path.as_c_str(), mode as u32) - { - Err(OSErrorBuilder::with_filename(&err, path, vm)) - } else { - Ok(()) - }; - } - #[cfg(target_os = "redox")] - let [] = dir_fd.0; - if let Err(err) = crate::host_env::posix::make_dir(c_path.as_c_str(), mode as u32) { - return Err(OSErrorBuilder::with_filename(&err, path, vm)); - } - Ok(()) + let mode = mode.unwrap_or(0o777) as u32; + let dir_fd = dir_fd.get_opt(); + crate::host_env::posix::make_dir(dir_fd, Path::new(&path.path), mode) + .map_err(|err| OSErrorBuilder::with_filename(&err, path, vm)) } #[pyfunction]