Skip to content

Commit 40dfeee

Browse files
host_env: os.mkdir for Windows, Redox
Python supports `mkdir` on Windows. I deferred to calling Rust's implementation for now. However, like `rename`, Python's implementation supports additional features that are currently unsupported on RustPython. I added a note for future reference. Redox supports `mkdirat` which significantly cleans up the implementation.
1 parent fe2a7db commit 40dfeee

3 files changed

Lines changed: 45 additions & 46 deletions

File tree

crates/host_env/src/posix.rs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use std::os::fd::FromRawFd;
1010
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd};
1111
use std::path::Path;
1212

13+
use crate::crt_fd;
14+
1315
pub struct UnameInfo {
1416
pub sysname: String,
1517
pub nodename: String,
@@ -174,24 +176,32 @@ pub fn fcopyfile(in_fd: i32, out_fd: i32, flags: u32) -> std::io::Result<()> {
174176
}
175177
}
176178

177-
#[cfg(not(windows))]
178-
pub fn make_dir(path: &CStr, mode: u32) -> std::io::Result<()> {
179-
let ret = unsafe { libc::mkdir(path.as_ptr(), mode as _) };
180-
if ret < 0 {
181-
Err(std::io::Error::last_os_error())
179+
#[cfg(not(unix))]
180+
pub fn make_dir(
181+
dir_fd: Option<crt_fd::Borrowed<'_>>,
182+
path: &Path,
183+
_mode: u32,
184+
) -> std::io::Result<()> {
185+
// TODO: On Windows, Python has an override if the mode is 0o700
186+
if dir_fd.is_none() {
187+
std::fs::create_dir(path)
182188
} else {
183-
Ok(())
189+
core::hint::cold_path();
190+
Err(std::io::Error::new(
191+
std::io::ErrorKind::Unsupported,
192+
"mkdirat is not available on this platform",
193+
))
184194
}
185195
}
186196

187-
#[cfg(all(not(windows), not(target_os = "redox")))]
188-
pub fn make_dir_at(dir_fd: i32, path: &CStr, mode: u32) -> std::io::Result<()> {
189-
let ret = unsafe { libc::mkdirat(dir_fd, path.as_ptr(), mode as _) };
190-
if ret < 0 {
191-
Err(std::io::Error::last_os_error())
192-
} else {
193-
Ok(())
194-
}
197+
#[cfg(unix)]
198+
pub fn make_dir(
199+
dir_fd: Option<crt_fd::Borrowed<'_>>,
200+
path: &Path,
201+
mode: u32,
202+
) -> std::io::Result<()> {
203+
let dir_fd = dir_fd.as_ref().map_or(rustix::fs::CWD, AsFd::as_fd);
204+
rustix::fs::mkdirat(dir_fd, path, mode.into()).map_err(Into::into)
195205
}
196206

197207
#[cfg(unix)]

crates/host_env/src/posix_wasi.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
use alloc::ffi::CString;
22
use core::{ffi::CStr, time::Duration};
3-
use std::{ffi::OsStr, io};
3+
use rustix::fd::AsFd;
4+
use std::{ffi::OsStr, io, path::Path};
45

5-
use crate::os::CheckLibcResult;
6+
use crate::{crt_fd, os::CheckLibcResult};
67

7-
pub fn make_dir(path: &CStr, mode: u32) -> io::Result<()> {
8-
unsafe { libc::mkdir(path.as_ptr(), mode as _) }.check_libc_neg()?;
9-
Ok(())
10-
}
11-
12-
pub fn make_dir_at(dir_fd: i32, path: &CStr, mode: u32) -> io::Result<()> {
13-
unsafe { libc::mkdirat(dir_fd, path.as_ptr(), mode as _) }.check_libc_neg()?;
14-
Ok(())
8+
pub fn make_dir(
9+
dir_fd: Option<crt_fd::Borrowed<'_>>,
10+
path: &Path,
11+
mode: u32,
12+
) -> std::io::Result<()> {
13+
let dir_fd = dir_fd.as_ref().map_or(rustix::fs::CWD, AsFd::as_fd);
14+
rustix::fs::mkdirat(dir_fd, path, mode.into()).map_err(Into::into)
1515
}
1616

1717
pub fn remove_dir_at(dir_fd: i32, path: &CStr) -> io::Result<()> {

crates/vm/src/stdlib/os.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct TargetIsDirectory {
2929
}
3030

3131
cfg_select! {
32-
all(any(unix, target_os = "wasi"), not(target_os = "redox")) => {
32+
any(unix, target_os = "wasi") => {
3333
use libc::AT_FDCWD;
3434
}
3535
_ => {
@@ -181,10 +181,14 @@ pub(super) mod _os {
181181
use rustpython_host_env::nt as host_nt;
182182
#[cfg(all(any(unix, target_os = "wasi"), not(target_os = "redox")))]
183183
use rustpython_host_env::posix as host_posix;
184-
use std::{fs, io, path::PathBuf, time::SystemTime};
184+
use std::{
185+
fs, io,
186+
path::{Path, PathBuf},
187+
time::SystemTime,
188+
};
185189

186190
const OPEN_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
187-
pub(crate) const MKDIR_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
191+
pub(crate) const MKDIR_DIR_FD: bool = cfg!(any(unix, target_os = "wasi"));
188192
const STAT_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
189193
const UTIME_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
190194
pub(crate) const SYMLINK_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
@@ -338,32 +342,17 @@ pub(super) mod _os {
338342
}
339343
}
340344

341-
#[cfg(not(windows))]
342345
#[pyfunction]
343346
fn mkdir(
344347
path: OsPath,
345348
mode: OptionalArg<i32>,
346349
dir_fd: DirFd<'_, { MKDIR_DIR_FD as usize }>,
347350
vm: &VirtualMachine,
348351
) -> PyResult<()> {
349-
let mode = mode.unwrap_or(0o777);
350-
let c_path = path.clone().into_cstring(vm)?;
351-
#[cfg(not(target_os = "redox"))]
352-
if let Some(fd) = dir_fd.raw_opt() {
353-
return if let Err(err) =
354-
crate::host_env::posix::make_dir_at(fd, c_path.as_c_str(), mode as u32)
355-
{
356-
Err(OSErrorBuilder::with_filename(&err, path, vm))
357-
} else {
358-
Ok(())
359-
};
360-
}
361-
#[cfg(target_os = "redox")]
362-
let [] = dir_fd.0;
363-
if let Err(err) = crate::host_env::posix::make_dir(c_path.as_c_str(), mode as u32) {
364-
return Err(OSErrorBuilder::with_filename(&err, path, vm));
365-
}
366-
Ok(())
352+
let mode = mode.unwrap_or(0o777) as u32;
353+
let dir_fd = dir_fd.get_opt();
354+
crate::host_env::posix::make_dir(dir_fd, Path::new(&path.path), mode)
355+
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
367356
}
368357

369358
#[pyfunction]

0 commit comments

Comments
 (0)