Add statfs() and fstatfs() to redbean unix module

This commit is contained in:
Justine Tunney 2022-08-17 23:27:17 -07:00
parent 2d479f7b11
commit 30e1c5bca9
3 changed files with 434 additions and 3 deletions

View file

@ -8,7 +8,7 @@ struct statfs { /* cosmo abi */
int64_t f_bsize; /* optimal transfer block size */
int64_t f_blocks; /* total data blocks in filesystem */
int64_t f_bfree; /* free blocks in filesystem */
int64_t f_bavail; /* free blocks available to */
int64_t f_bavail; /* free blocks available to unprivileged users */
int64_t f_files; /* total file nodes in filesystem */
int64_t f_ffree; /* free file nodes in filesystem */
int64_t f_fsid; /* filesystem id */

View file

@ -31,6 +31,7 @@
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/statfs.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
@ -39,6 +40,7 @@
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/bits.h"
#include "libc/log/log.h"
@ -85,6 +87,7 @@
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/consts/st.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/consts/utime.h"
#include "libc/sysv/consts/w.h"
@ -154,6 +157,12 @@ static void LuaPushStat(lua_State *L, struct stat *st) {
*stp = *st;
}
static void LuaPushStatfs(lua_State *L, struct statfs *st) {
struct statfs *stp = lua_newuserdatauv(L, sizeof(*stp), 1);
luaL_setmetatable(L, "unix.Statfs");
*stp = *st;
}
static void LuaPushRusage(lua_State *L, struct rusage *set) {
struct rusage *sp = lua_newuserdatauv(L, sizeof(*sp), 1);
luaL_setmetatable(L, "unix.Rusage");
@ -1112,6 +1121,34 @@ static int LuaUnixFstat(lua_State *L) {
}
}
// unix.statfs(path:str)
// ├─→ unix.Statfs
// └─→ nil, unix.Errno
static int LuaUnixStatfs(lua_State *L) {
struct statfs f;
int olderr = errno;
if (!statfs(luaL_checkstring(L, 1), &f)) {
LuaPushStatfs(L, &f);
return 1;
} else {
return LuaUnixSysretErrno(L, "statfs", olderr);
}
}
// unix.fstatfs(fd:int)
// ├─→ unix.Stat
// └─→ nil, unix.Errno
static int LuaUnixFstatfs(lua_State *L) {
struct statfs f;
int olderr = errno;
if (!fstatfs(luaL_checkinteger(L, 1), &f)) {
LuaPushStatfs(L, &f);
return 1;
} else {
return LuaUnixSysretErrno(L, "fstatfs", olderr);
}
}
static bool IsSockoptBool(int l, int x) {
if (l == SOL_SOCKET) {
return x == SO_TYPE || //
@ -2052,8 +2089,66 @@ static int LuaUnixStatFlags(lua_State *L) {
}
static int LuaUnixStatToString(lua_State *L) {
struct stat *st = GetUnixStat(L);
lua_pushstring(L, "unix.Stat()");
char ibuf[21];
luaL_Buffer b;
struct stat *st;
st = GetUnixStat(L);
luaL_buffinit(L, &b);
luaL_addstring(&b, "unix.Stat({size=");
FormatInt64(ibuf, st->st_size);
luaL_addstring(&b, ibuf);
if (st->st_mode) {
luaL_addstring(&b, ", mode=");
FormatOctal32(ibuf, st->st_mode, 1);
luaL_addstring(&b, ibuf);
}
if (st->st_ino) {
luaL_addstring(&b, ", ino=");
FormatUint64(ibuf, st->st_ino);
luaL_addstring(&b, ibuf);
}
if (st->st_nlink) {
luaL_addstring(&b, ", nlink=");
FormatUint64(ibuf, st->st_nlink);
luaL_addstring(&b, ibuf);
}
if (st->st_uid) {
luaL_addstring(&b, ", uid=");
FormatUint32(ibuf, st->st_uid);
luaL_addstring(&b, ibuf);
}
if (st->st_gid) {
luaL_addstring(&b, ", gid=");
FormatUint32(ibuf, st->st_gid);
luaL_addstring(&b, ibuf);
}
if (st->st_flags) {
luaL_addstring(&b, ", flags=");
FormatUint32(ibuf, st->st_flags);
luaL_addstring(&b, ibuf);
}
if (st->st_dev) {
luaL_addstring(&b, ", dev=");
FormatUint64(ibuf, st->st_dev);
luaL_addstring(&b, ibuf);
}
if (st->st_rdev) {
luaL_addstring(&b, ", rdev=");
FormatUint64(ibuf, st->st_rdev);
luaL_addstring(&b, ibuf);
}
if (st->st_blksize) {
luaL_addstring(&b, ", blksize=");
FormatInt64(ibuf, st->st_blksize);
luaL_addstring(&b, ibuf);
}
if (st->st_blocks) {
luaL_addstring(&b, ", blocks=");
FormatInt64(ibuf, st->st_blocks);
luaL_addstring(&b, ibuf);
}
luaL_addstring(&b, "})");
luaL_pushresult(&b);
return 1;
}
@ -2079,6 +2174,7 @@ static const luaL_Reg kLuaUnixStatMeth[] = {
static const luaL_Reg kLuaUnixStatMeta[] = {
{"__tostring", LuaUnixStatToString}, //
{"__repr", LuaUnixStatToString}, //
{0}, //
};
@ -2091,6 +2187,190 @@ static void LuaUnixStatObj(lua_State *L) {
lua_pop(L, 1);
}
////////////////////////////////////////////////////////////////////////////////
// unix.Statfs object
static struct statfs *GetUnixStatfs(lua_State *L) {
return luaL_checkudata(L, 1, "unix.Statfs");
}
// unix.Statfs:type()
// └─→ bytes:int
static int LuaUnixStatfsType(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_type);
}
// unix.Statfs:bsize()
// └─→ bsize:int
static int LuaUnixStatfsBsize(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_bsize);
}
// unix.Statfs:blocks()
// └─→ blocks:int
static int LuaUnixStatfsBlocks(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_blocks);
}
// unix.Statfs:bfree()
// └─→ bfreedeint
static int LuaUnixStatfsBfree(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_bfree);
}
// unix.Statfs:bavail()
// └─→ count:int
static int LuaUnixStatfsBavail(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_bavail);
}
// unix.Statfs:files()
// └─→ files:int
static int LuaUnixStatfsFiles(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_files);
}
// unix.Statfs:ffree()
// └─→ ffree:int
static int LuaUnixStatfsFfree(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_ffree);
}
// unix.Statfs:fsid()
// └─→ fsid:int
static int LuaUnixStatfsFsid(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_fsid);
}
// unix.Statfs:namelen()
// └─→ count:int
static int LuaUnixStatfsNamelen(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_namelen);
}
// unix.Statfs:frsize()
// └─→ bytes:int
static int LuaUnixStatfsFrsize(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_frsize);
}
// unix.Statfs:flags()
// └─→ bytes:int
static int LuaUnixStatfsFlags(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_flags);
}
// unix.Statfs:owner()
// └─→ bytes:int
static int LuaUnixStatfsOwner(lua_State *L) {
return ReturnInteger(L, GetUnixStatfs(L)->f_owner);
}
// unix.Statfs:fstypename()
// └─→ fstypename:str
static int LuaUnixStatfsFstypename(lua_State *L) {
return ReturnString(L, GetUnixStatfs(L)->f_fstypename);
}
static int LuaUnixStatfsToString(lua_State *L) {
char ibuf[21];
luaL_Buffer b;
struct statfs *f;
f = GetUnixStatfs(L);
luaL_buffinit(L, &b);
luaL_addstring(&b, "unix.Statfs({type=");
FormatInt64(ibuf, f->f_type);
luaL_addstring(&b, ibuf);
luaL_addstring(&b, ", fstypename=\"");
luaL_addstring(&b, f->f_fstypename);
luaL_addstring(&b, "\"");
if (f->f_bsize) {
luaL_addstring(&b, ", bsize=");
FormatInt64(ibuf, f->f_bsize);
luaL_addstring(&b, ibuf);
}
if (f->f_blocks) {
luaL_addstring(&b, ", blocks=");
FormatInt64(ibuf, f->f_blocks);
luaL_addstring(&b, ibuf);
}
if (f->f_bfree) {
luaL_addstring(&b, ", bfree=");
FormatInt64(ibuf, f->f_bfree);
luaL_addstring(&b, ibuf);
}
if (f->f_bavail) {
luaL_addstring(&b, ", bavail=");
FormatInt64(ibuf, f->f_bavail);
luaL_addstring(&b, ibuf);
}
if (f->f_files) {
luaL_addstring(&b, ", files=");
FormatInt64(ibuf, f->f_files);
luaL_addstring(&b, ibuf);
}
if (f->f_ffree) {
luaL_addstring(&b, ", ffree=");
FormatInt64(ibuf, f->f_ffree);
luaL_addstring(&b, ibuf);
}
if (f->f_fsid) {
luaL_addstring(&b, ", fsid=");
FormatUint64(ibuf, f->f_fsid);
luaL_addstring(&b, ibuf);
}
if (f->f_namelen) {
luaL_addstring(&b, ", namelen=");
FormatUint64(ibuf, f->f_namelen);
luaL_addstring(&b, ibuf);
}
if (f->f_flags) {
luaL_addstring(&b, ", flags=");
FormatHex64(ibuf, f->f_flags, 2);
luaL_addstring(&b, ibuf);
}
if (f->f_owner) {
luaL_addstring(&b, ", owner=");
FormatUint32(ibuf, f->f_owner);
luaL_addstring(&b, ibuf);
}
luaL_addstring(&b, "})");
luaL_pushresult(&b);
return 1;
}
static const luaL_Reg kLuaUnixStatfsMeth[] = {
{"type", LuaUnixStatfsType}, //
{"bsize", LuaUnixStatfsBsize}, //
{"blocks", LuaUnixStatfsBlocks}, //
{"bfree", LuaUnixStatfsBfree}, //
{"bavail", LuaUnixStatfsBavail}, //
{"files", LuaUnixStatfsFiles}, //
{"ffree", LuaUnixStatfsFfree}, //
{"fsid", LuaUnixStatfsFsid}, //
{"namelen", LuaUnixStatfsNamelen}, //
{"frsize", LuaUnixStatfsFrsize}, //
{"flags", LuaUnixStatfsFlags}, //
{"owner", LuaUnixStatfsOwner}, //
{"fstypename", LuaUnixStatfsFstypename}, //
{0}, //
};
static const luaL_Reg kLuaUnixStatfsMeta[] = {
{"__tostring", LuaUnixStatfsToString}, //
{"__repr", LuaUnixStatfsToString}, //
{0}, //
};
static void LuaUnixStatfsObj(lua_State *L) {
luaL_newmetatable(L, "unix.Statfs");
luaL_setfuncs(L, kLuaUnixStatfsMeta, 0);
luaL_newlibtable(L, kLuaUnixStatfsMeth);
luaL_setfuncs(L, kLuaUnixStatfsMeth, 0);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
}
////////////////////////////////////////////////////////////////////////////////
// unix.Rusage object
@ -2626,6 +2906,7 @@ static const luaL_Reg kLuaUnix[] = {
{"fdopendir", LuaUnixFdopendir}, // read directory entry list
{"fork", LuaUnixFork}, // make child process via mitosis
{"fstat", LuaUnixFstat}, // get file info from fd
{"fstatfs", LuaUnixFstatfs}, // get filesystem info from fd
{"fsync", LuaUnixFsync}, // flush open file
{"ftruncate", LuaUnixFtruncate}, // shrink or extend file medium
{"futimens", LuaUnixFutimens}, // change access/modified time
@ -2693,6 +2974,7 @@ static const luaL_Reg kLuaUnix[] = {
{"socket", LuaUnixSocket}, // create network communication fd
{"socketpair", LuaUnixSocketpair}, // create bidirectional pipe
{"stat", LuaUnixStat}, // get file info from path
{"statfs", LuaUnixStatfs}, // get filesystem info from path
{"strsignal", LuaUnixStrsignal}, // turn signal into string
{"symlink", LuaUnixSymlink}, // create symbolic link
{"sync", LuaUnixSync}, // flushes files and disks
@ -2724,6 +3006,7 @@ int LuaUnix(lua_State *L) {
luaL_newlib(L, kLuaUnix);
LuaUnixSigsetObj(L);
LuaUnixRusageObj(L);
LuaUnixStatfsObj(L);
LuaUnixErrnoObj(L);
LuaUnixStatObj(L);
LuaUnixDirObj(L);
@ -2896,5 +3179,19 @@ int LuaUnix(lua_State *L) {
LuaSetIntField(L, "PLEDGE_PENALTY_RETURN_EPERM", PLEDGE_PENALTY_RETURN_EPERM);
LuaSetIntField(L, "PLEDGE_STDERR_LOGGING", PLEDGE_STDERR_LOGGING);
// statfs::f_flags
LuaSetIntField(L, "ST_RDONLY", ST_RDONLY);
LuaSetIntField(L, "ST_NOSUID", ST_NOSUID);
LuaSetIntField(L, "ST_NODEV", ST_NODEV);
LuaSetIntField(L, "ST_NOEXEC", ST_NOEXEC);
LuaSetIntField(L, "ST_SYNCHRONOUS", ST_SYNCHRONOUS);
LuaSetIntField(L, "ST_NOATIME", ST_NOATIME);
LuaSetIntField(L, "ST_RELATIME", ST_RELATIME);
LuaSetIntField(L, "ST_APPEND", ST_APPEND);
LuaSetIntField(L, "ST_IMMUTABLE", ST_IMMUTABLE);
LuaSetIntField(L, "ST_MANDLOCK", ST_MANDLOCK);
LuaSetIntField(L, "ST_NODIRATIME", ST_NODIRATIME);
LuaSetIntField(L, "ST_WRITE", ST_WRITE);
return 1;
}

View file

@ -4312,6 +4312,23 @@ UNIX MODULE
Log(kLogInfo, 'hello.txt is %d bytes in size' % {st:size()})
unix.close(fd)
unix.statfs(path:str)
├─→ unix.Statfs
└─→ nil, unix.Errno
Gets information about filesystem.
`path` is the path of a file or directory in the mounted filesystem.
unix.fstatfs(fd:int)
├─→ unix.Statfs
└─→ nil, unix.Errno
Gets information about filesystem.
`fd` is an open() file descriptor of a file or directory in the
mounted filesystem.
unix.opendir(path:str)
├─→ state:unix.Dir
└─→ nil, unix.Errno
@ -4744,6 +4761,123 @@ UNIX MODULE
may be used to extract the device numbers.
────────────────────────────────────────────────────────────────────────────────
UNIX STATFS OBJECT
unix.Statfs objects are created by statfs() or fstatfs(). The
following accessor methods are available.
unix.Statfs:fstypename()
└─→ str
Type of filesystem.
Here's some examples of likely values:
- `"ext"` on Linux
- `"xfs"` on RHEL7
- `"apfs"` on Apple
- `"zfs"` on FreeBSD
- `"ffs"` on NetBSD and OpenBSD
- `"NTFS"` on Windows
unix.Statfs:type()
└─→ int
Type of filesystem.
This is a platform-specific magic number. Consider using the
unix.Statfs:fstypename() method instead. On Windows, this will
actually be a Knuth multiplicative hash of the name.
unix.Statfs:bsize()
└─→ int
Optimal transfer block size.
This field serves two purposes:
1. It tells you how to chunk i/o operations. For local disks,
it'll likely be any value between 512 and 4096 depending on the
operating system. For network filesystems it will likely be a
much larger value, e.g. 512kb.
2. It can be multiplied with the fields `blocks`, `bfree`, and
`bavail` to obtain a byte count.
unix.Statfs:blocks()
└─→ int
Total data blocks in filesystem.
The size of a block is measured as unix.Statfs:bsize().
unix.Statfs:bfree()
└─→ int
Total free blocks in filesystem.
The size of a block is measured as unix.Statfs:bsize().
unix.Statfs:bavail()
└─→ int
Total free blocks available in filesystem to unprivileged users.
The size of a block is measured as unix.Statfs:bsize().
unix.Statfs:files()
└─→ int
Total file nodes in filesystem.
On Windows this is always the maximum integer value.
unix.Statfs:ffree()
└─→ int
Total free file nodes in filesystem.
On Windows this is always the maximum integer value.
unix.Statfs:fsid()
└─→ int
Filesystem id.
unix.Statfs:namelen()
└─→ int
Maximum length of filename components in bytes.
unix.Statfs:flags()
└─→ int
Filesystem flags.
The following flags are defined:
- `ST_RDONLY`: Read-only filesystem (Linux/Windows/XNU/BSDs)
- `ST_NOSUID`: Setuid binaries forbidden (Linux/XNU/BSDs)
- `ST_NODEV`: Device files forbidden (Linux/XNU/BSDs)
- `ST_NOEXEC`: Execution forbidden (Linux/XNU/BSDs)
- `ST_SYNCHRONOUS`: Synchronous (Linux/XNU/BSDs)
- `ST_NOATIME`: No access time (Linux/XNU/BSDs)
- `ST_RELATIME`: Relative access time (Linux/NetBSD)
- `ST_APPEND`: Linux-only
- `ST_IMMUTABLE`: Linux-only
- `ST_MANDLOCK`: Linux-only
- `ST_NODIRATIME`: Linux-only
- `ST_WRITE`: Linux-only
unix.Statfs:owner()
└─→ int
User id of owner of filesystem mount.
On Linux this is always 0 for root. On Windows this is always 0.
────────────────────────────────────────────────────────────────────────────────
UNIX SIGSET OBJECT