Files
vlibc/src/stat/statvfs.c
T

89 lines
2.6 KiB
C

#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) */