feat(statvfs): statvfs/fstatvfs (L2 XSI)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
#if VLIBC_LEVEL_GE(2)
|
||||
|
||||
/*
|
||||
* Linux struct statfs (kernel ABI, x86_64; linux/statfs.h). Layout and
|
||||
* sizes are LP64 facts: f_type..f_ffree are longs, f_fsid is an int pair,
|
||||
* then f_namelen/f_frsize/f_flags/f_spare[4] complete the 120 bytes the
|
||||
* kernel copies out (the same layout src/misc/pathconf.c pins for
|
||||
* pathconf()/fpathconf()). The signed kernel longs are non-negative on
|
||||
* every real filesystem, so they convert straight into the unsigned POSIX
|
||||
* counts below.
|
||||
*/
|
||||
struct vlibc_kstatfs
|
||||
{
|
||||
long f_type;
|
||||
long f_bsize;
|
||||
long f_blocks;
|
||||
long f_bfree;
|
||||
long f_bavail;
|
||||
long f_files;
|
||||
long f_ffree;
|
||||
int f_fsid[2];
|
||||
long f_namelen;
|
||||
long f_frsize;
|
||||
long f_flags;
|
||||
long f_spare[4];
|
||||
};
|
||||
|
||||
/* Map one kernel statfs record into the portable POSIX statvfs view. */
|
||||
static void
|
||||
statvfs_fill(struct statvfs *out, const struct vlibc_kstatfs *in)
|
||||
{
|
||||
out->f_bsize = (unsigned long)in->f_bsize;
|
||||
out->f_frsize = in->f_frsize != 0 ? (unsigned long)in->f_frsize : (unsigned long)in->f_bsize;
|
||||
out->f_blocks = (unsigned long)in->f_blocks;
|
||||
out->f_bfree = (unsigned long)in->f_bfree;
|
||||
out->f_bavail = (unsigned long)in->f_bavail;
|
||||
out->f_files = (unsigned long)in->f_files;
|
||||
out->f_ffree = (unsigned long)in->f_ffree;
|
||||
out->f_favail = (unsigned long)in->f_ffree;
|
||||
/* Reconstruct the kernel's 64-bit fsid (val[0] holds the low word on
|
||||
* the little-endian x86_64; the same packing glibc's statvfs reports). */
|
||||
out->f_fsid = ((unsigned long)(unsigned int)in->f_fsid[1] << 32) |
|
||||
(unsigned long)(unsigned int)in->f_fsid[0];
|
||||
out->f_flag = (unsigned long)(in->f_flags & (ST_RDONLY | ST_NOSUID));
|
||||
out->f_namemax = (unsigned long)in->f_namelen;
|
||||
}
|
||||
|
||||
/*
|
||||
* statvfs()/fstatvfs(): filesystem statistics in the portable POSIX shape,
|
||||
* over SYS_statfs/SYS_fstatfs (which share the same kernel struct and the
|
||||
* same mapping). The kernel returns 0 on success after filling all 120
|
||||
* bytes; failures come back as -errno and are translated by syscall_ret.
|
||||
*/
|
||||
int
|
||||
statvfs(const char *restrict path, struct statvfs *restrict buf)
|
||||
{
|
||||
struct vlibc_kstatfs fs;
|
||||
|
||||
if (syscall_ret(__syscall2(SYS_statfs, (long)path, (long)&fs)) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
statvfs_fill(buf, &fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fstatvfs(int fildes, struct statvfs *buf)
|
||||
{
|
||||
struct vlibc_kstatfs fs;
|
||||
|
||||
if (syscall_ret(__syscall2(SYS_fstatfs, fildes, (long)&fs)) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
statvfs_fill(buf, &fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* VLIBC_LEVEL_GE(2) */
|
||||
Reference in New Issue
Block a user