Skip to content

Commit be5631e

Browse files
committed
fix os.statvfs
1 parent 78cf8d6 commit be5631e

File tree

1 file changed

+102
-0
lines changed
  • crates/vm/src/stdlib

1 file changed

+102
-0
lines changed

crates/vm/src/stdlib/os.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,15 @@ pub(super) mod _os {
202202
#[pyattr]
203203
pub(crate) const X_OK: u8 = 1 << 0;
204204

205+
// ST_RDONLY and ST_NOSUID flags for statvfs
206+
#[cfg(all(unix, not(target_os = "redox")))]
207+
#[pyattr]
208+
const ST_RDONLY: libc::c_ulong = libc::ST_RDONLY;
209+
210+
#[cfg(all(unix, not(target_os = "redox")))]
211+
#[pyattr]
212+
const ST_NOSUID: libc::c_ulong = libc::ST_NOSUID;
213+
205214
#[pyfunction]
206215
fn close(fileno: crt_fd::Owned) -> io::Result<()> {
207216
crt_fd::close(fileno)
@@ -1701,6 +1710,99 @@ pub(super) mod _os {
17011710
#[pyclass(with(PyStructSequence))]
17021711
impl PyUnameResult {}
17031712

1713+
// statvfs_result: Result from statvfs or fstatvfs.
1714+
// = statvfs_result_fields
1715+
#[cfg(all(unix, not(target_os = "redox")))]
1716+
#[derive(Debug)]
1717+
#[pystruct_sequence_data]
1718+
pub(crate) struct StatvfsResultData {
1719+
pub f_bsize: libc::c_ulong, // filesystem block size
1720+
pub f_frsize: libc::c_ulong, // fragment size
1721+
pub f_blocks: libc::fsblkcnt_t, // size of fs in f_frsize units
1722+
pub f_bfree: libc::fsblkcnt_t, // free blocks
1723+
pub f_bavail: libc::fsblkcnt_t, // free blocks for unprivileged users
1724+
pub f_files: libc::fsfilcnt_t, // inodes
1725+
pub f_ffree: libc::fsfilcnt_t, // free inodes
1726+
pub f_favail: libc::fsfilcnt_t, // free inodes for unprivileged users
1727+
pub f_flag: libc::c_ulong, // mount flags
1728+
pub f_namemax: libc::c_ulong, // maximum filename length
1729+
#[pystruct_sequence(skip)]
1730+
pub f_fsid: libc::c_ulong, // filesystem ID (not in tuple but accessible as attribute)
1731+
}
1732+
1733+
#[cfg(all(unix, not(target_os = "redox")))]
1734+
#[pyattr]
1735+
#[pystruct_sequence(name = "statvfs_result", module = "os", data = "StatvfsResultData")]
1736+
pub(crate) struct PyStatvfsResult;
1737+
1738+
#[cfg(all(unix, not(target_os = "redox")))]
1739+
#[pyclass(with(PyStructSequence))]
1740+
impl PyStatvfsResult {
1741+
#[pyslot]
1742+
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1743+
let seq: PyObjectRef = args.bind(vm)?;
1744+
crate::types::struct_sequence_new(cls, seq, vm)
1745+
}
1746+
}
1747+
1748+
#[cfg(all(unix, not(target_os = "redox")))]
1749+
impl StatvfsResultData {
1750+
fn from_statvfs(st: libc::statvfs) -> Self {
1751+
// Handle f_fsid which may be a struct on some platforms
1752+
// On most Unix systems, we just use 0 or try to get the value
1753+
let f_fsid = {
1754+
// Use pointer cast to get raw bytes from fsid struct
1755+
let ptr = std::ptr::addr_of!(st.f_fsid) as *const u8;
1756+
let size = std::mem::size_of_val(&st.f_fsid);
1757+
if size >= 8 {
1758+
let bytes = unsafe { std::slice::from_raw_parts(ptr, 8) };
1759+
u64::from_ne_bytes([
1760+
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
1761+
bytes[7],
1762+
]) as libc::c_ulong
1763+
} else if size >= 4 {
1764+
let bytes = unsafe { std::slice::from_raw_parts(ptr, 4) };
1765+
u32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as libc::c_ulong
1766+
} else {
1767+
0
1768+
}
1769+
};
1770+
1771+
Self {
1772+
f_bsize: st.f_bsize,
1773+
f_frsize: st.f_frsize,
1774+
f_blocks: st.f_blocks,
1775+
f_bfree: st.f_bfree,
1776+
f_bavail: st.f_bavail,
1777+
f_files: st.f_files,
1778+
f_ffree: st.f_ffree,
1779+
f_favail: st.f_favail,
1780+
f_flag: st.f_flag,
1781+
f_namemax: st.f_namemax,
1782+
f_fsid,
1783+
}
1784+
}
1785+
}
1786+
1787+
/// Perform a statvfs system call on the given path.
1788+
#[cfg(all(unix, not(target_os = "redox")))]
1789+
#[pyfunction]
1790+
#[pyfunction(name = "fstatvfs")]
1791+
fn statvfs(path: OsPathOrFd<'_>, vm: &VirtualMachine) -> PyResult {
1792+
let mut st: libc::statvfs = unsafe { std::mem::zeroed() };
1793+
let ret = match path {
1794+
OsPathOrFd::Path(path) => {
1795+
let cpath = path.into_cstring(vm)?;
1796+
unsafe { libc::statvfs(cpath.as_ptr(), &mut st) }
1797+
}
1798+
OsPathOrFd::Fd(fd) => unsafe { libc::fstatvfs(fd.as_raw(), &mut st) },
1799+
};
1800+
if ret != 0 {
1801+
return Err(io::Error::last_os_error().into_pyexception(vm));
1802+
}
1803+
Ok(StatvfsResultData::from_statvfs(st).to_pyobject(vm))
1804+
}
1805+
17041806
pub(super) fn support_funcs() -> Vec<SupportFunc> {
17051807
let mut supports = super::platform::module::support_funcs();
17061808
supports.extend(vec![

0 commit comments

Comments
 (0)