Skip to content

Commit 62419ec

Browse files
host_env: Simplify stat, fstatat with Rustix
According to POSIX, `time_t` should be 64 bits. `musl` changed its `time_t` to an `i64` over five years ago. `glibc` provides compatibility features that declare `time_t` as either `i32` or `i64`. Rustix uses the raw Linux syscall for stat which returns an `i64`. For our purposes, an `i64` makes sense because it's modern and avoids the year 2038 problem. It also reduces our dependency on what `libc` defines. Sources: * https://www.man7.org/linux/man-pages/man3/time_t.3type.html * https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html
1 parent 1c7759c commit 62419ec

6 files changed

Lines changed: 47 additions & 116 deletions

File tree

‎crates/host_env/src/fileutils.rs‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,14 @@
22
#![allow(non_snake_case)]
33

44
#[cfg(not(windows))]
5-
pub use libc::stat as StatStruct;
5+
pub use rustix::fs::Stat as StatStruct;
66

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

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

2315
#[cfg(windows)]

‎crates/host_env/src/io.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
use core::ffi::CStr;
33
use std::io;
44

5+
#[cfg(any(unix, target_os = "wasi"))]
6+
use rustix::{fs::FileType, io::Errno};
7+
58
#[cfg(any(unix, target_os = "wasi"))]
69
use crate::fileutils;
710
use crate::{crt_fd, os};
@@ -148,8 +151,8 @@ pub struct FileTargetInfo {
148151
#[cfg(any(unix, target_os = "wasi"))]
149152
pub fn inspect_file_target(fd: crt_fd::Borrowed<'_>) -> io::Result<FileTargetInfo> {
150153
let status = fileutils::fstat(fd)?;
151-
if (status.st_mode & libc::S_IFMT) == libc::S_IFDIR {
152-
return Err(io::Error::from_raw_os_error(libc::EISDIR));
154+
if FileType::from_raw_mode(status.st_mode).is_dir() {
155+
return Err(io::Error::from(Errno::ISDIR));
153156
}
154157
#[allow(clippy::useless_conversion, reason = "needed for 32-bit platforms")]
155158
let blksize = (status.st_blksize > 1).then(|| i64::from(status.st_blksize));

‎crates/host_env/src/posix.rs‎

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -304,50 +304,6 @@ pub fn fchown(fd: BorrowedFd<'_>, uid: Option<u32>, gid: Option<u32>) -> std::io
304304
.map_err(std::io::Error::from)
305305
}
306306

307-
#[cfg(not(windows))]
308-
#[expect(
309-
clippy::std_instead_of_core,
310-
reason = "false positive: core::io::ErrorKind is unstable (core_io)"
311-
)]
312-
pub fn stat_path(
313-
path: &OsStr,
314-
dir_fd: Option<i32>,
315-
follow_symlinks: bool,
316-
) -> std::io::Result<Option<crate::fileutils::StatStruct>> {
317-
use crate::os::ffi::OsStrExt;
318-
319-
let path = match CString::new(path.as_bytes()) {
320-
Ok(path) => path,
321-
Err(_) => return Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)),
322-
};
323-
324-
let mut stat = core::mem::MaybeUninit::uninit();
325-
#[cfg(not(target_os = "redox"))]
326-
if let Some(dir_fd) = dir_fd {
327-
let flags = if follow_symlinks {
328-
0
329-
} else {
330-
libc::AT_SYMLINK_NOFOLLOW
331-
};
332-
let ret = unsafe { libc::fstatat(dir_fd, path.as_ptr(), stat.as_mut_ptr(), flags) };
333-
if ret < 0 {
334-
return Err(std::io::Error::last_os_error());
335-
}
336-
return Ok(Some(unsafe { stat.assume_init() }));
337-
}
338-
339-
let ret = if follow_symlinks {
340-
unsafe { libc::stat(path.as_ptr(), stat.as_mut_ptr()) }
341-
} else {
342-
unsafe { libc::lstat(path.as_ptr(), stat.as_mut_ptr()) }
343-
};
344-
if ret < 0 {
345-
Err(std::io::Error::last_os_error())
346-
} else {
347-
Ok(Some(unsafe { stat.assume_init() }))
348-
}
349-
}
350-
351307
#[cfg(not(windows))]
352308
pub fn stat_fd(fd: crate::crt_fd::Borrowed<'_>) -> std::io::Result<crate::fileutils::StatStruct> {
353309
crate::fileutils::fstat(fd)

‎crates/host_env/src/posix_unix_like.rs‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
33
use std::{io, path::Path};
44

5-
use rustix::{fd::AsFd, fs};
5+
use rustix::{
6+
fd::AsFd,
7+
fs::{self, AtFlags},
8+
};
69

710
pub use rustix::fs::RawMode;
811

9-
use crate::crt_fd;
12+
use crate::{crt_fd, fileutils::StatStruct};
1013

1114
/// https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html
1215
pub fn make_dir(
@@ -45,3 +48,19 @@ pub fn replace(
4548
) -> io::Result<()> {
4649
rename(from, from_fd, to, to_fd)
4750
}
51+
52+
pub fn stat_path(
53+
path: impl AsRef<Path>,
54+
dir_fd: Option<crt_fd::Borrowed<'_>>,
55+
follow_symlinks: bool,
56+
) -> io::Result<Option<StatStruct>> {
57+
let flags = if follow_symlinks {
58+
AtFlags::empty()
59+
} else {
60+
AtFlags::SYMLINK_NOFOLLOW
61+
};
62+
let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
63+
fs::statat(dir_fd, path.as_ref(), flags)
64+
.map(Option::Some)
65+
.map_err(Into::into)
66+
}

‎crates/host_env/src/posix_wasi.rs‎

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,6 @@ pub fn remove_dir_at(dir_fd: i32, path: &CStr) -> io::Result<()> {
1212
Ok(())
1313
}
1414

15-
pub fn stat_path(
16-
path: &OsStr,
17-
dir_fd: Option<i32>,
18-
follow_symlinks: bool,
19-
) -> io::Result<Option<crate::fileutils::StatStruct>> {
20-
use crate::os::ffi::OsStrExt;
21-
22-
let path = match CString::new(path.as_bytes()) {
23-
Ok(path) => path,
24-
Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidInput)),
25-
};
26-
27-
let mut stat = core::mem::MaybeUninit::uninit();
28-
if let Some(dir_fd) = dir_fd {
29-
let flags = if follow_symlinks {
30-
0
31-
} else {
32-
libc::AT_SYMLINK_NOFOLLOW
33-
};
34-
unsafe { libc::fstatat(dir_fd, path.as_ptr(), stat.as_mut_ptr(), flags) }
35-
.check_libc_neg()?;
36-
return Ok(Some(unsafe { stat.assume_init() }));
37-
}
38-
39-
let ret = if follow_symlinks {
40-
unsafe { libc::stat(path.as_ptr(), stat.as_mut_ptr()) }
41-
} else {
42-
unsafe { libc::lstat(path.as_ptr(), stat.as_mut_ptr()) }
43-
};
44-
ret.check_libc_neg()?;
45-
Ok(Some(unsafe { stat.assume_init() }))
46-
}
47-
4815
pub fn stat_fd(fd: crate::crt_fd::Borrowed<'_>) -> io::Result<crate::fileutils::StatStruct> {
4916
crate::fileutils::fstat(fd)
5017
}

‎crates/vm/src/stdlib/os.rs‎

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,18 +1183,15 @@ pub(super) mod _os {
11831183
pub st_gid: PyIntRef,
11841184
pub st_size: PyIntRef,
11851185
// Indices 7-9: integer seconds
1186-
#[cfg_attr(target_env = "musl", allow(deprecated))]
11871186
#[pyarg(positional, default)]
11881187
#[pystruct_sequence(unnamed)]
1189-
pub st_atime_int: libc::time_t,
1190-
#[cfg_attr(target_env = "musl", allow(deprecated))]
1188+
pub st_atime_int: i64,
11911189
#[pyarg(positional, default)]
11921190
#[pystruct_sequence(unnamed)]
1193-
pub st_mtime_int: libc::time_t,
1194-
#[cfg_attr(target_env = "musl", allow(deprecated))]
1191+
pub st_mtime_int: i64,
11951192
#[pyarg(positional, default)]
11961193
#[pystruct_sequence(unnamed)]
1197-
pub st_ctime_int: libc::time_t,
1194+
pub st_ctime_int: i64,
11981195
// Float time attributes
11991196
#[pyarg(any, default)]
12001197
#[pystruct_sequence(skip)]
@@ -1219,11 +1216,11 @@ pub(super) mod _os {
12191216
#[cfg(not(windows))]
12201217
#[pyarg(any, default)]
12211218
#[pystruct_sequence(skip)]
1222-
pub st_blksize: i64,
1219+
pub st_blksize: u64,
12231220
#[cfg(not(windows))]
12241221
#[pyarg(any, default)]
12251222
#[pystruct_sequence(skip)]
1226-
pub st_blocks: i64,
1223+
pub st_blocks: u64,
12271224
#[cfg(windows)]
12281225
#[pyarg(any, default)]
12291226
#[pystruct_sequence(skip)]
@@ -1237,19 +1234,12 @@ pub(super) mod _os {
12371234
impl StatResultData {
12381235
fn from_stat(stat: &StatStruct, vm: &VirtualMachine) -> Self {
12391236
let (atime, mtime, ctime);
1240-
#[cfg(any(unix, windows))]
1241-
#[cfg(not(any(target_os = "netbsd", target_os = "wasi")))]
1237+
#[cfg(all(any(unix, windows), not(target_os = "wasi")))]
12421238
{
12431239
atime = (stat.st_atime, stat.st_atime_nsec);
12441240
mtime = (stat.st_mtime, stat.st_mtime_nsec);
12451241
ctime = (stat.st_ctime, stat.st_ctime_nsec);
12461242
}
1247-
#[cfg(target_os = "netbsd")]
1248-
{
1249-
atime = (stat.st_atime, stat.st_atimensec);
1250-
mtime = (stat.st_mtime, stat.st_mtimensec);
1251-
ctime = (stat.st_ctime, stat.st_ctimensec);
1252-
}
12531243
#[cfg(target_os = "wasi")]
12541244
{
12551245
atime = (stat.st_atim.tv_sec, stat.st_atim.tv_nsec);
@@ -1274,12 +1264,18 @@ pub(super) mod _os {
12741264
let st_ino = stat.st_ino;
12751265

12761266
#[cfg(not(windows))]
1277-
#[allow(clippy::useless_conversion, reason = "needed for 32-bit platforms")]
1278-
let st_blksize = i64::from(stat.st_blksize);
1267+
#[allow(
1268+
clippy::useless_conversion,
1269+
reason = "signedness differs between platforms"
1270+
)]
1271+
let st_blksize = stat.st_blksize.try_into().unwrap_or(4096);
12791272

12801273
#[cfg(not(windows))]
1281-
#[allow(clippy::useless_conversion, reason = "needed for 32-bit platforms")]
1282-
let st_blocks = i64::from(stat.st_blocks);
1274+
#[allow(
1275+
clippy::useless_conversion,
1276+
reason = "signedness differs between platforms"
1277+
)]
1278+
let st_blocks = stat.st_blocks.try_into().unwrap_or_default();
12831279

12841280
Self {
12851281
st_mode: vm.ctx.new_pyref(stat.st_mode),
@@ -1360,11 +1356,9 @@ pub(super) mod _os {
13601356
follow_symlinks: FollowSymlinks,
13611357
) -> io::Result<Option<StatStruct>> {
13621358
match file {
1363-
OsPathOrFd::Path(path) => host_posix::stat_path(
1364-
path.as_ref().as_os_str(),
1365-
dir_fd.raw_opt(),
1366-
follow_symlinks.0,
1367-
),
1359+
OsPathOrFd::Path(path) => {
1360+
host_posix::stat_path(path, dir_fd.get_opt(), follow_symlinks.0)
1361+
}
13681362
OsPathOrFd::Fd(fd) => host_posix::stat_fd(fd).map(Some),
13691363
}
13701364
}

0 commit comments

Comments
 (0)