Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nodefs] Return real values for statvfs via __syscall_statfs64 #22631

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
23 changes: 23 additions & 0 deletions src/library_fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,29 @@ FS.staticInit();
}
return parent.node_ops.mknod(parent, name, mode, dev);
},
statfs(path) {

// NOTE: None of the defaults here are true. We're just returning safe and
// sane values.
var rtn = {
bsize: 4096,
frsize: 4096,
blocks: 1e6,
bfree: 5e5,
bavail: 5e5,
files: FS.nextInode,
ffree: FS.nextInode - 1,
fsid: 42,
flags: 2,
namelen: 255,
};

var parent = FS.lookupPath(path, {follow: true}).node;
if (parent.node_ops.statfs) {
Object.assign(rtn, parent.node_ops.statfs(parent.mount.opts.root));
}
return rtn;
},
// helpers to create specific types of nodes
create(path, mode) {
mode = mode !== undefined ? mode : 438 /* 0666 */;
Expand Down
7 changes: 7 additions & 0 deletions src/library_nodefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ addToLibrary({
var path = NODEFS.realPath(node);
return NODEFS.tryFSOperation(() => fs.readlinkSync(path));
},
statfs(path) {
var stats = NODEFS.tryFSOperation(() => fs.statfsSync(path));
jeroenpf marked this conversation as resolved.
Show resolved Hide resolved
// Node.js doesn't provide frsize (fragment size). Set it to bsize (block size)
// as they're often the same in many file systems. May not be accurate for all.
stats.frsize = stats.bsize;
return stats;
}
},
stream_ops: {
open(stream) {
Expand Down
24 changes: 11 additions & 13 deletions src/library_syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -802,22 +802,20 @@ var SyscallsLibrary = {
},

__syscall_statfs64: (path, size, buf) => {
path = SYSCALLS.getStr(path);
#if ASSERTIONS
assert(size === {{{ C_STRUCTS.statfs.__size__ }}});
#endif
// NOTE: None of the constants here are true. We're just returning safe and
// sane values.
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bsize, '4096', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_frsize, '4096', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_blocks, '1000000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bfree, '500000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bavail, '500000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_files, 'FS.nextInode', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_ffree, '1000000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_fsid, '42', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_flags, '2', 'i32') }}}; // ST_NOSUID
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_namelen, '255', 'i32') }}};
var defaults = FS.statfs(SYSCALLS.getStr(path));
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bsize, 'defaults.bsize', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_frsize, 'defaults.bsize', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_blocks, 'defaults.blocks', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bfree, 'defaults.bfree', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bavail, 'defaults.bavail', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_files, 'defaults.files', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_ffree, 'defaults.ffree', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_fsid, 'defaults.fsid', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_flags, 'defaults.flags', 'i32') }}}; // ST_NOSUID
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_namelen, 'defaults.namelen', 'i32') }}};
return 0;
},
__syscall_fstatfs64__deps: ['__syscall_statfs64'],
Expand Down
7 changes: 5 additions & 2 deletions test/core/test_statvfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
#include <stdio.h>
#include <errno.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>

int main() {
struct statvfs s;

mkdir("/test", S_IRWXU | S_IRWXG | S_IRWXO);
printf("result: %d\n", statvfs("/test", &s));
printf("errno: %d\n", errno);

Expand All @@ -21,8 +24,8 @@ int main() {
printf("f_bfree: %u\n", s.f_bfree);
printf("f_bavail: %u\n", s.f_bavail);
printf("f_files: %d\n", s.f_files > 5);
printf("f_ffree: %u\n", s.f_ffree);
printf("f_favail: %u\n", s.f_favail);
printf("f_ffree: %u\n", s.f_ffree <= s.f_files && s.f_ffree > 0);
printf("f_favail: %u\n", s.f_favail <= s.f_files && s.f_favail > 0);
printf("f_fsid: %lu\n", s.f_fsid);
printf("f_flag: %lu\n", s.f_flag);
printf("f_namemax: %lu\n", s.f_namemax);
Expand Down
4 changes: 2 additions & 2 deletions test/core/test_statvfs.out
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ f_blocks: 1000000
f_bfree: 500000
f_bavail: 500000
f_files: 1
f_ffree: 1000000
f_favail: 1000000
f_ffree: 1
f_favail: 1
f_fsid: 42
f_flag: 2
f_namemax: 255
35 changes: 35 additions & 0 deletions test/fs/test_nodefs_statvfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <assert.h>
#include <stdio.h>
#include <sys/statvfs.h>
#include <emscripten.h>

void test_statvfs(const char *path) {
printf("Testing statfs for path: %s\n", path);
struct statvfs st;
int result = statvfs(path, &st);

assert(result == 0 && "statvfs should succeed");

// Basic sanity checks
assert(st.f_bsize > 0 && "Block size should be positive");
assert(st.f_blocks > 0 && "Total blocks should be positive");
assert(st.f_bfree <= st.f_blocks && "Free blocks should not exceed total blocks");
assert(st.f_bavail <= st.f_bfree && "Available blocks should not exceed free blocks");
assert(st.f_files >= 0 && "Total inodes should be 0 or positive");
assert(st.f_ffree <= st.f_files && "Free inodes should not exceed total inodes");
}

void setup() {
EM_ASM(
FS.mkdir('/working');
FS.mount(NODEFS, { root: '.' }, '/working');
);
}

int main() {
setup();
// Test the root filesystem (which should be MEMFS by default)
test_statvfs("/");
test_statvfs("/working");
puts("success");
}
12 changes: 11 additions & 1 deletion test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5775,10 +5775,20 @@ def test_fs_nodefs_readdir(self):
# externally setup an existing folder structure: existing/a
if self.get_setting('WASMFS'):
self.set_setting('FORCE_FILESYSTEM')
os.makedirs(os.path.join(self.working_dir, 'existing', 'a'))
os.makedirs('existing/a')
self.emcc_args += ['-lnodefs.js']
self.do_runf('fs/test_nodefs_readdir.c', 'success')

@requires_node
jeroenpf marked this conversation as resolved.
Show resolved Hide resolved
@crossplatform
def test_fs_nodefs_statvfs(self):
# externally setup an existing folder structure: existing/a
if self.get_setting('WASMFS'):
self.set_setting('FORCE_FILESYSTEM')
os.makedirs('existing/a')
self.emcc_args += ['-lnodefs.js']
self.do_runf('fs/test_nodefs_statvfs.c', 'success')

@no_windows('no symlink support on windows')
@requires_node
def test_fs_noderawfs_nofollow(self):
Expand Down
Loading