@@ -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