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
12 changes: 2 additions & 10 deletions crates/host_env/src/fileutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@
#![allow(non_snake_case)]

#[cfg(not(windows))]
pub use libc::stat as StatStruct;
pub use rustix::fs::Stat as StatStruct;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[cfg(windows)]
pub use windows::{StatStruct, fstat};

#[cfg(not(windows))]
pub fn fstat(fd: crate::crt_fd::Borrowed<'_>) -> std::io::Result<StatStruct> {
let mut stat = core::mem::MaybeUninit::uninit();
unsafe {
let ret = libc::fstat(fd.as_raw(), stat.as_mut_ptr());
if ret == -1 {
Err(crate::os::errno_io_error())
} else {
Ok(stat.assume_init())
}
}
rustix::fs::fstat(fd).map_err(Into::into)
}

#[cfg(windows)]
Expand Down
7 changes: 5 additions & 2 deletions crates/host_env/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
use core::ffi::CStr;
use std::io;

#[cfg(any(unix, target_os = "wasi"))]
use rustix::{fs::FileType, io::Errno};

#[cfg(any(unix, target_os = "wasi"))]
use crate::fileutils;
use crate::{crt_fd, os};
Expand Down Expand Up @@ -148,8 +151,8 @@ pub struct FileTargetInfo {
#[cfg(any(unix, target_os = "wasi"))]
pub fn inspect_file_target(fd: crt_fd::Borrowed<'_>) -> io::Result<FileTargetInfo> {
let status = fileutils::fstat(fd)?;
if (status.st_mode & libc::S_IFMT) == libc::S_IFDIR {
return Err(io::Error::from_raw_os_error(libc::EISDIR));
if FileType::from_raw_mode(status.st_mode).is_dir() {
return Err(io::Error::from(Errno::ISDIR));
}
#[allow(clippy::useless_conversion, reason = "needed for 32-bit platforms")]
let blksize = (status.st_blksize > 1).then(|| i64::from(status.st_blksize));
Expand Down
44 changes: 0 additions & 44 deletions crates/host_env/src/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,50 +304,6 @@ pub fn fchown(fd: BorrowedFd<'_>, uid: Option<u32>, gid: Option<u32>) -> std::io
.map_err(std::io::Error::from)
}

#[cfg(not(windows))]
#[expect(
clippy::std_instead_of_core,
reason = "false positive: core::io::ErrorKind is unstable (core_io)"
)]
pub fn stat_path(
path: &OsStr,
dir_fd: Option<i32>,
follow_symlinks: bool,
) -> std::io::Result<Option<crate::fileutils::StatStruct>> {
use crate::os::ffi::OsStrExt;

let path = match CString::new(path.as_bytes()) {
Ok(path) => path,
Err(_) => return Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)),
};

let mut stat = core::mem::MaybeUninit::uninit();
#[cfg(not(target_os = "redox"))]
if let Some(dir_fd) = dir_fd {
let flags = if follow_symlinks {
0
} else {
libc::AT_SYMLINK_NOFOLLOW
};
let ret = unsafe { libc::fstatat(dir_fd, path.as_ptr(), stat.as_mut_ptr(), flags) };
if ret < 0 {
return Err(std::io::Error::last_os_error());
}
return Ok(Some(unsafe { stat.assume_init() }));
}

let ret = if follow_symlinks {
unsafe { libc::stat(path.as_ptr(), stat.as_mut_ptr()) }
} else {
unsafe { libc::lstat(path.as_ptr(), stat.as_mut_ptr()) }
};
if ret < 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(Some(unsafe { stat.assume_init() }))
}
}

#[cfg(not(windows))]
pub fn stat_fd(fd: crate::crt_fd::Borrowed<'_>) -> std::io::Result<crate::fileutils::StatStruct> {
crate::fileutils::fstat(fd)
Expand Down
23 changes: 21 additions & 2 deletions crates/host_env/src/posix_unix_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

use std::{io, path::Path};

use rustix::{fd::AsFd, fs};
use rustix::{
fd::AsFd,
fs::{self, AtFlags},
};

pub use rustix::fs::RawMode;

use crate::crt_fd;
use crate::{crt_fd, fileutils::StatStruct};

/// https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html
pub fn make_dir(
Expand Down Expand Up @@ -45,3 +48,19 @@ pub fn replace(
) -> io::Result<()> {
rename(from, from_fd, to, to_fd)
}

pub fn stat_path(
path: impl AsRef<Path>,
dir_fd: Option<crt_fd::Borrowed<'_>>,
follow_symlinks: bool,
) -> io::Result<Option<StatStruct>> {
let flags = if follow_symlinks {
AtFlags::empty()
} else {
AtFlags::SYMLINK_NOFOLLOW
};
let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
fs::statat(dir_fd, path.as_ref(), flags)
.map(Option::Some)
.map_err(Into::into)
}
33 changes: 0 additions & 33 deletions crates/host_env/src/posix_wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,6 @@ pub fn remove_dir_at(dir_fd: i32, path: &CStr) -> io::Result<()> {
Ok(())
}

pub fn stat_path(
path: &OsStr,
dir_fd: Option<i32>,
follow_symlinks: bool,
) -> io::Result<Option<crate::fileutils::StatStruct>> {
use crate::os::ffi::OsStrExt;

let path = match CString::new(path.as_bytes()) {
Ok(path) => path,
Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidInput)),
};

let mut stat = core::mem::MaybeUninit::uninit();
if let Some(dir_fd) = dir_fd {
let flags = if follow_symlinks {
0
} else {
libc::AT_SYMLINK_NOFOLLOW
};
unsafe { libc::fstatat(dir_fd, path.as_ptr(), stat.as_mut_ptr(), flags) }
.check_libc_neg()?;
return Ok(Some(unsafe { stat.assume_init() }));
}

let ret = if follow_symlinks {
unsafe { libc::stat(path.as_ptr(), stat.as_mut_ptr()) }
} else {
unsafe { libc::lstat(path.as_ptr(), stat.as_mut_ptr()) }
};
ret.check_libc_neg()?;
Ok(Some(unsafe { stat.assume_init() }))
}

pub fn stat_fd(fd: crate::crt_fd::Borrowed<'_>) -> io::Result<crate::fileutils::StatStruct> {
crate::fileutils::fstat(fd)
}
Expand Down
44 changes: 19 additions & 25 deletions crates/vm/src/stdlib/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,18 +1183,15 @@ pub(super) mod _os {
pub st_gid: PyIntRef,
pub st_size: PyIntRef,
// Indices 7-9: integer seconds
#[cfg_attr(target_env = "musl", allow(deprecated))]
#[pyarg(positional, default)]
#[pystruct_sequence(unnamed)]
pub st_atime_int: libc::time_t,
#[cfg_attr(target_env = "musl", allow(deprecated))]
pub st_atime_int: i64,
#[pyarg(positional, default)]
#[pystruct_sequence(unnamed)]
pub st_mtime_int: libc::time_t,
#[cfg_attr(target_env = "musl", allow(deprecated))]
pub st_mtime_int: i64,
#[pyarg(positional, default)]
#[pystruct_sequence(unnamed)]
pub st_ctime_int: libc::time_t,
pub st_ctime_int: i64,
// Float time attributes
#[pyarg(any, default)]
#[pystruct_sequence(skip)]
Expand All @@ -1219,11 +1216,11 @@ pub(super) mod _os {
#[cfg(not(windows))]
#[pyarg(any, default)]
#[pystruct_sequence(skip)]
pub st_blksize: i64,
pub st_blksize: u64,
#[cfg(not(windows))]
#[pyarg(any, default)]
#[pystruct_sequence(skip)]
pub st_blocks: i64,
pub st_blocks: u64,
#[cfg(windows)]
#[pyarg(any, default)]
#[pystruct_sequence(skip)]
Expand All @@ -1237,19 +1234,12 @@ pub(super) mod _os {
impl StatResultData {
fn from_stat(stat: &StatStruct, vm: &VirtualMachine) -> Self {
let (atime, mtime, ctime);
#[cfg(any(unix, windows))]
#[cfg(not(any(target_os = "netbsd", target_os = "wasi")))]
#[cfg(all(any(unix, windows), not(target_os = "wasi")))]
{
atime = (stat.st_atime, stat.st_atime_nsec);
mtime = (stat.st_mtime, stat.st_mtime_nsec);
ctime = (stat.st_ctime, stat.st_ctime_nsec);
}
#[cfg(target_os = "netbsd")]
{
atime = (stat.st_atime, stat.st_atimensec);
mtime = (stat.st_mtime, stat.st_mtimensec);
ctime = (stat.st_ctime, stat.st_ctimensec);
}
#[cfg(target_os = "wasi")]
{
atime = (stat.st_atim.tv_sec, stat.st_atim.tv_nsec);
Expand All @@ -1274,12 +1264,18 @@ pub(super) mod _os {
let st_ino = stat.st_ino;

#[cfg(not(windows))]
#[allow(clippy::useless_conversion, reason = "needed for 32-bit platforms")]
let st_blksize = i64::from(stat.st_blksize);
#[allow(
clippy::useless_conversion,
reason = "signedness differs between platforms"
)]
let st_blksize = stat.st_blksize.try_into().unwrap_or(4096);

#[cfg(not(windows))]
#[allow(clippy::useless_conversion, reason = "needed for 32-bit platforms")]
let st_blocks = i64::from(stat.st_blocks);
#[allow(
clippy::useless_conversion,
reason = "signedness differs between platforms"
)]
let st_blocks = stat.st_blocks.try_into().unwrap_or_default();

Self {
st_mode: vm.ctx.new_pyref(stat.st_mode),
Expand Down Expand Up @@ -1360,11 +1356,9 @@ pub(super) mod _os {
follow_symlinks: FollowSymlinks,
) -> io::Result<Option<StatStruct>> {
match file {
OsPathOrFd::Path(path) => host_posix::stat_path(
path.as_ref().as_os_str(),
dir_fd.raw_opt(),
follow_symlinks.0,
),
OsPathOrFd::Path(path) => {
host_posix::stat_path(path, dir_fd.get_opt(), follow_symlinks.0)
}
OsPathOrFd::Fd(fd) => host_posix::stat_fd(fd).map(Some),
}
}
Expand Down
Loading