os.statvfs
statvfs and fstatvfs are Unix only; the ST_* flags for f_flag are Unix (ST_RDONLY, ST_NOSUID) or Linux only (the rest). Windows has the statvfs_result type but no function returning it, so the examples build a result by hand or use shutil.disk_usage, which works everywhere.
Common call
st = os.statvfs("/"); st.f_bavail * st.f_frsize
Returns
statvfs_result (block counts, not bytes)
Replaces
Parsing df output
Watch out
Multiply counts by f_frsize; use f_bavail, not f_bfree, for "free to me"
os.statvfs(path) / os.fstatvfs(fd)
→ os.statvfs_result
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | str | bytes | PathLike | int | yes | statvfs: any path on the filesystem (or an open file descriptor, 3.3+). |
| fd | int | yes | fstatvfs: an open file descriptor. Same as os.statvfs(fd). |
Return value
os.statvfs_result — A 10-item named tuple: f_bsize, f_frsize, f_blocks, f_bfree, f_bavail, f_files, f_ffree, f_favail, f_flag, f_namemax, plus the attribute-only f_fsid.
Common patterns
Free space for the current user (Unix)
f_bavail excludes the blocks reserved for root.
import os st = os.statvfs('/var/data') free_bytes = st.f_bavail * st.f_frsize total_bytes = st.f_blocks * st.f_frsize
Is the filesystem mounted read-only?
Test the ST_RDONLY bit of f_flag before trying to write.
import os read_only = bool(os.statvfs(path).f_flag & os.ST_RDONLY)
Portable disk usage
shutil.disk_usage works on Windows too and returns bytes directly.
import shutil total, used, free = shutil.disk_usage('.') print(f'{free / 2**30:.1f} GiB free')
Longest allowed file name
f_namemax is the per-component limit of that filesystem.
import os max_name = os.statvfs('.').f_namemax
Examples
1. A result built by hand
import os
st = os.statvfs_result((4096, 4096, 1000, 500, 400, 100, 50, 40, 0, 255))
(st.f_bavail * st.f_frsize, st.f_namemax)
Returns
(1638400, 255)2. A tuple with 10 items
import os
st = os.statvfs_result((4096, 4096, 1000, 500, 400, 100, 50, 40, 0, 255))
(len(st), issubclass(os.statvfs_result, tuple), st.f_fsid)
Returns
(10, True, None)3. Percent available
import os
st = os.statvfs_result((4096, 4096, 1000, 500, 400, 100, 50, 40, 0, 255))
round(100 * st.f_bavail / st.f_blocks, 1)
Returns
40.04. Decode f_flag (Linux bit values)
LINUX_ST = {'ST_RDONLY': 1, 'ST_NOSUID': 2, 'ST_NODEV': 4, 'ST_NOEXEC': 8, 'ST_RELATIME': 4096}
f_flag = 4096 | 2 | 1
[name for name, bit in LINUX_ST.items() if f_flag & bit]
Returns
['ST_RDONLY', 'ST_NOSUID', 'ST_RELATIME']5. Portable: shutil.disk_usage
import shutil
u = shutil.disk_usage('.')
(u._fields, u.used + u.free <= u.total)
Returns
(('total', 'used', 'free'), True)Pitfalls
1. Using f_bfree for "free space"
f_bfree includes blocks reserved for root. What a normal user can still write is f_bavail.
f_bfree
import os st = os.statvfs_result((4096, 4096, 1000, 500, 400, 100, 50, 40, 0, 255)) st.f_bfree * st.f_frsize
2048000
f_bavail
import os st = os.statvfs_result((4096, 4096, 1000, 500, 400, 100, 50, 40, 0, 255)) st.f_bavail * st.f_frsize
1638400
2. Multiplying by f_bsize
The block counts are in units of f_frsize (the fragment size). f_bsize is the preferred I/O size and can differ.
f_bsize
import os st = os.statvfs_result((65536, 4096, 1000, 500, 400, 100, 50, 40, 0, 255)) st.f_blocks * st.f_bsize
65536000
f_frsize
import os st = os.statvfs_result((65536, 4096, 1000, 500, 400, 100, 50, 40, 0, 255)) st.f_blocks * st.f_frsize
4096000
When to use
Use it
- Free-space checks before large writes on Linux/macOS servers
- Detecting read-only or noexec mounts (f_flag with ST_RDONLY, ST_NOEXEC)
- Inode exhaustion checks (f_files, f_ffree, f_favail)
Reach for something else
- Cross-platform free space → shutil.disk_usage
- Size of one file → os.stat(path).st_size
Notes
CPython impl
statvfs(3) / fstatvfs(3) in Modules/posixmodule.c. statvfs_result is a struct sequence: 10 tuple fields (n_sequence_fields 10, n_fields 11) - f_fsid is attribute-only and None when the result is built from a 10-tuple
Availability
statvfs, fstatvfs: Unix. ST_RDONLY, ST_NOSUID: Unix (3.2+). ST_NODEV, ST_NOEXEC, ST_SYNCHRONOUS, ST_MANDLOCK, ST_WRITE, ST_APPEND, ST_NOATIME, ST_NODIRATIME, ST_RELATIME: Linux (3.4+). The statvfs_result type itself also exists on Windows
Linux flag values
ST_RDONLY 1, ST_NOSUID 2, ST_NODEV 4, ST_NOEXEC 8, ST_SYNCHRONOUS 16, ST_MANDLOCK 64, ST_WRITE 128, ST_APPEND 256, ST_NOATIME 1024, ST_NODIRATIME 2048, ST_RELATIME 4096 (CPython 3.12 on Linux)
Fields
f_bsize block size; f_frsize fragment size; f_blocks total in f_frsize units; f_bfree free; f_bavail free for unprivileged users; f_files / f_ffree / f_favail the same for inodes; f_flag mount flags; f_namemax max file name length; f_fsid filesystem id (3.7+)
FAQ
It wraps the POSIX statvfs() call, which Windows does not have - it is Unix only (the result type exists, the functions do not). That is also why this page builds statvfs_result objects by hand. Use shutil.disk_usage(path) for free space on every OS.