Skip to content

Commit 1566bbe

Browse files
committed
fs: add statvfs function
Expose useful functionality to query filesystem properties, such as free size, total size, and various other block properties made available via https://www.man7.org/linux/man-pages/man3/statvfs.3.html If the host runs Linux, we also expose the `type` property, which provides the FS type magic number. Complete jsdoc is provided for the new object and function. Run-tested on macOS and OpenWRT 25.12-rc5 Signed-off-by: Paul Donald <newtwen+github@gmail.com>
1 parent d810e57 commit 1566bbe

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

lib/fs.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@
6060
#include <fnmatch.h>
6161
#include <limits.h>
6262
#include <fcntl.h>
63+
#include <sys/statvfs.h> /* statvfs(3) */
6364

6465
#if defined(__linux__)
66+
#include <sys/statfs.h> /* statfs() for f_type */
6567
#define HAS_IOCTL
6668
#endif
6769

@@ -1779,6 +1781,89 @@ uc_fs_lstat(uc_vm_t *vm, size_t nargs)
17791781
return uc_fs_stat_common(vm, nargs, true);
17801782
}
17811783

1784+
/**
1785+
* @typedef {Object} module:fs.StatVFSResult
1786+
* @property {number} bsize file system block size
1787+
* @property {number} frsize fragment size
1788+
* @property {number} blocks total blocks
1789+
* @property {number} bfree free blocks
1790+
* @property {number} bavail free blocks available to unprivileged users
1791+
* @property {number} files total file nodes (inodes)
1792+
* @property {number} ffree free file nodes
1793+
* @property {number} favail free nodes available to unprivileged users
1794+
* @property {number} fsid file system id
1795+
* @property {number} flag mount flags
1796+
* @property {number} namemax maximum filename length
1797+
* @property {number} freesize free space in bytes (calculated as `frsize * bfree`)
1798+
* @property {number} totalsize total size of the filesystem (calculated as `frsize * blocks`)
1799+
* @property {number} type (Linux only) magic number of the filesystem, obtained from `statfs`
1800+
*/
1801+
1802+
/**
1803+
* Query filesystem statistics for a given pathname.
1804+
*
1805+
* The returned object mirrors the members of `struct statvfs`.
1806+
* Convenience properties `freesize` and `totalsize` are added,
1807+
* which are calculated as:
1808+
* - `frsize * bfree` to provide the free space in bytes and
1809+
* - `frsize * blocks` to provide the total size of the filesystem.
1810+
*
1811+
* On Linux an additional `type` field (magic number from `statfs`) is
1812+
* provided if the call succeeds.
1813+
*
1814+
* Returns `null` on failure (and sets `fs.last_error`).
1815+
*
1816+
* @function module:fs#statvfs
1817+
*
1818+
* @param {string} path
1819+
* The path to the directory or file with which to query the filesystem.
1820+
*
1821+
* @returns {?module:fs.StatVFSResult}
1822+
*
1823+
* @example
1824+
* // Get filesystem statistics for a path
1825+
* const stats = statvfs('path/to/directory');
1826+
* print(stats.bsize); // file system block size
1827+
*/
1828+
static uc_value_t *
1829+
uc_fs_statvfs(uc_vm_t *vm, size_t nargs)
1830+
{
1831+
uc_value_t *path = uc_fn_arg(0);
1832+
struct statvfs sv;
1833+
1834+
if (ucv_type(path) != UC_STRING)
1835+
err_return(EINVAL);
1836+
1837+
if (statvfs(ucv_string_get(path), &sv) == -1)
1838+
err_return(errno);
1839+
1840+
uc_value_t *o = ucv_object_new(vm);
1841+
1842+
ucv_object_add(o, "bsize", ucv_int64_new(sv.f_bsize));
1843+
ucv_object_add(o, "frsize", ucv_int64_new(sv.f_frsize));
1844+
ucv_object_add(o, "blocks", ucv_int64_new(sv.f_blocks));
1845+
ucv_object_add(o, "bfree", ucv_int64_new(sv.f_bfree));
1846+
ucv_object_add(o, "bavail", ucv_int64_new(sv.f_bavail));
1847+
ucv_object_add(o, "files", ucv_int64_new(sv.f_files));
1848+
ucv_object_add(o, "ffree", ucv_int64_new(sv.f_ffree));
1849+
ucv_object_add(o, "favail", ucv_int64_new(sv.f_favail));
1850+
ucv_object_add(o, "fsid", ucv_int64_new(sv.f_fsid));
1851+
ucv_object_add(o, "flag", ucv_int64_new(sv.f_flag));
1852+
ucv_object_add(o, "namemax", ucv_int64_new(sv.f_namemax));
1853+
ucv_object_add(o, "freesize", ucv_int64_new(sv.f_frsize * sv.f_bfree));
1854+
ucv_object_add(o, "totalsize",ucv_int64_new(sv.f_frsize * sv.f_blocks));
1855+
1856+
#ifdef __linux__
1857+
/* Call statfs to expose the magic number (`f_type`) */
1858+
struct statfs sf;
1859+
if (statfs(ucv_string_get(path), &sf) == 0) {
1860+
ucv_object_add(o, "type", ucv_int64_new(sf.f_type));
1861+
}
1862+
#endif
1863+
1864+
return o;
1865+
}
1866+
17821867
/**
17831868
* Creates a new directory.
17841869
*
@@ -3024,6 +3109,7 @@ static const uc_function_list_t global_fns[] = {
30243109
{ "popen", uc_fs_popen },
30253110
{ "readlink", uc_fs_readlink },
30263111
{ "stat", uc_fs_stat },
3112+
{ "statvfs", uc_fs_statvfs },
30273113
{ "lstat", uc_fs_lstat },
30283114
{ "mkdir", uc_fs_mkdir },
30293115
{ "rmdir", uc_fs_rmdir },

0 commit comments

Comments
 (0)