Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion crates/host_env/src/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use core::ffi::CStr;
use core::str::Utf8Error;
#[cfg(windows)]
use core::time::Duration;
#[cfg(unix)]
use rustix::fd::AsFd;
use std::{
env,
ffi::{OsStr, OsString},
Expand Down Expand Up @@ -266,11 +268,36 @@ pub fn copy_file_range(
rustix::fs::copy_file_range(src, offset_src, dst, offset_dst, count)
}

#[cfg(not(unix))]
pub fn rename(
from: impl AsRef<std::path::Path>,
from_fd: Option<crt_fd::Borrowed<'_>>,
to: impl AsRef<std::path::Path>,
to_fd: Option<crt_fd::Borrowed<'_>>,
) -> io::Result<()> {
if from_fd.is_none() && to_fd.is_none() {
// TODO: Rust's implementation always overwrites the file so ensure consistency between
// operating systems. We need to use windows-sys directly to distinguish between
// os.rename and os.replace.
std::fs::rename(from, to)
} else {
core::hint::cold_path();
Err(io::Error::other("renameat is not available on this platform"))
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[cfg(unix)]
pub fn rename(
from: impl AsRef<std::path::Path>,
from_fd: Option<crt_fd::Borrowed<'_>>,
to: impl AsRef<std::path::Path>,
to_fd: Option<crt_fd::Borrowed<'_>>,
) -> io::Result<()> {
std::fs::rename(from, to)
let from = from.as_ref();
let from_fd = from_fd.as_ref().map_or(rustix::fs::CWD, AsFd::as_fd);
let to = to.as_ref();
let to_fd = to_fd.as_ref().map_or(rustix::fs::CWD, AsFd::as_fd);
rustix::fs::renameat(from_fd, from, to_fd, to).map_err(Into::into)
}

#[cfg(windows)]
Expand Down
31 changes: 25 additions & 6 deletions crates/vm/src/stdlib/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ pub(super) mod _os {
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")));
pub(crate) const UNLINK_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
const RENAME_DIR_FD: bool = cfg!(not(windows));
const RMDIR_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
const SCANDIR_FD: bool = cfg!(all(unix, not(target_os = "redox")));

Expand Down Expand Up @@ -1377,19 +1378,37 @@ pub(super) mod _os {
FsPath::try_from_path_like(path, false, vm)
}

#[derive(FromArgs)]
struct RenameArgs<'fd> {
#[pyarg(positional)]
src: PyObjectRef,
#[pyarg(positional)]
dst: PyObjectRef,
#[pyarg(any, default)]
src_dir_fd: OptionalArg<crt_fd::Borrowed<'fd>>,
#[pyarg(any, default)]
dst_dir_fd: OptionalArg<crt_fd::Borrowed<'fd>>,
}

#[pyfunction]
#[pyfunction(name = "replace")]
fn rename(src: PyObjectRef, dst: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn rename(args: RenameArgs<'_>, vm: &VirtualMachine) -> PyResult<()> {
let src = PathConverter::new()
.function("rename")
.argument("src")
.try_path(src, vm)?;
.try_path(args.src, vm)?;
let dst = PathConverter::new()
.function("rename")
.argument("dst")
.try_path(dst, vm)?;
.try_path(args.dst, vm)?;

crate::host_env::os::rename(&src.path, &dst.path).map_err(|err| {
crate::host_env::os::rename(
&src,
args.src_dir_fd.into_option(),
&dst,
args.dst_dir_fd.into_option(),
)
.map_err(|err| {
let builder = err.to_os_error_builder(vm);
let builder = builder.filename(src.filename(vm));
let builder = builder.filename2(dst.filename(vm));
Expand Down Expand Up @@ -1932,8 +1951,8 @@ pub(super) mod _os {
SupportFunc::new("readlink", Some(false), None, Some(false)),
SupportFunc::new("remove", Some(false), Some(UNLINK_DIR_FD), Some(false)),
SupportFunc::new("unlink", Some(false), Some(UNLINK_DIR_FD), Some(false)),
SupportFunc::new("rename", Some(false), None, Some(false)),
SupportFunc::new("replace", Some(false), None, Some(false)), // TODO: Fix replace
SupportFunc::new("rename", Some(false), Some(RENAME_DIR_FD), Some(false)),
SupportFunc::new("replace", Some(false), Some(RENAME_DIR_FD), Some(false)), // TODO: Fix replace
SupportFunc::new("rmdir", Some(false), Some(RMDIR_DIR_FD), Some(false)),
SupportFunc::new("scandir", Some(SCANDIR_FD), Some(false), Some(false)),
SupportFunc::new("stat", Some(true), Some(STAT_DIR_FD), Some(true)),
Expand Down
Loading