Skip to content

Commit bce64c4

Browse files
committed
Merge branch 'main' into enotdir
2 parents 349d1e8 + 06cebfc commit bce64c4

File tree

10 files changed

+122
-40
lines changed

10 files changed

+122
-40
lines changed

ChangeLog.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ to browse the changes between the tags.
1818

1919
See docs/process.md for more on how version tagging works.
2020

21-
3.1.73 (in development)
21+
3.1.74 (in development)
2222
-----------------------
23+
24+
3.1.73 - 11/28/24
25+
-----------------
2326
- libunwind was updated to LLVM 19.1.4. (#22394)
2427
- mimalloc was updated to 2.1.7. (#21548)
2528

emscripten-version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.1.73-git
1+
3.1.74-git

src/library_fs.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,29 @@ FS.staticInit();
669669
}
670670
return parent.node_ops.mknod(parent, name, mode, dev);
671671
},
672+
statfs(path) {
673+
674+
// NOTE: None of the defaults here are true. We're just returning safe and
675+
// sane values.
676+
var rtn = {
677+
bsize: 4096,
678+
frsize: 4096,
679+
blocks: 1e6,
680+
bfree: 5e5,
681+
bavail: 5e5,
682+
files: FS.nextInode,
683+
ffree: FS.nextInode - 1,
684+
fsid: 42,
685+
flags: 2,
686+
namelen: 255,
687+
};
688+
689+
var parent = FS.lookupPath(path, {follow: true}).node;
690+
if (parent?.node_ops.statfs) {
691+
Object.assign(rtn, parent.node_ops.statfs(parent.mount.opts.root));
692+
}
693+
return rtn;
694+
},
672695
// helpers to create specific types of nodes
673696
create(path, mode = 0o666) {
674697
mode &= {{{ cDefs.S_IALLUGO }}};
@@ -810,7 +833,7 @@ FS.staticInit();
810833
// do the underlying fs rename
811834
try {
812835
old_dir.node_ops.rename(old_node, new_dir, new_name);
813-
// update old node (we do this here to avoid each backend
836+
// update old node (we do this here to avoid each backend
814837
// needing to)
815838
old_node.parent = new_dir;
816839
} catch (e) {

src/library_nodefs.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ addToLibrary({
219219
var path = NODEFS.realPath(node);
220220
return NODEFS.tryFSOperation(() => fs.readlinkSync(path));
221221
},
222+
statfs(path) {
223+
var stats = NODEFS.tryFSOperation(() => fs.statfsSync(path));
224+
// Node.js doesn't provide frsize (fragment size). Set it to bsize (block size)
225+
// as they're often the same in many file systems. May not be accurate for all.
226+
stats.frsize = stats.bsize;
227+
return stats;
228+
}
222229
},
223230
stream_ops: {
224231
open(stream) {

src/library_sdl.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,11 +2762,13 @@ var LibrarySDL = {
27622762
27632763
if (bytes !== undefined && SDL.webAudioAvailable() && canPlayWithWebAudio) {
27642764
audio = undefined;
2765-
webAudio = {};
2766-
// The audio decoding process is asynchronous, which gives trouble if user code plays the audio data back immediately
2767-
// after loading. Therefore prepare an array of callback handlers to run when this audio decoding is complete, which
2768-
// will then start the playback (with some delay).
2769-
webAudio.onDecodeComplete = []; // While this member array exists, decoding hasn't finished yet.
2765+
webAudio = {
2766+
// The audio decoding process is asynchronous, which gives trouble if user
2767+
// code plays the audio data back immediately after loading. Therefore
2768+
// prepare an array of callback handlers to run when this audio decoding
2769+
// is complete, which will then start the playback (with some delay).
2770+
onDecodeComplete: [], // While this member array exists, decoding hasn't finished yet.
2771+
}
27702772
var onDecodeComplete = (data) => {
27712773
webAudio.decodedBuffer = data;
27722774
// Call all handlers that were waiting for this decode to finish, and clear the handler list.
@@ -2815,8 +2817,7 @@ var LibrarySDL = {
28152817
}
28162818
28172819
if (SDL.webAudioAvailable()) {
2818-
webAudio = {};
2819-
webAudio.decodedBuffer = buffer;
2820+
webAudio = { decodedBuffer: buffer };
28202821
} else {
28212822
audio = new Audio();
28222823
audio.mozAudioChannelType = 'content'; // bugzilla 910340
@@ -2873,13 +2874,14 @@ var LibrarySDL = {
28732874
var audio;
28742875
if (info.webAudio) {
28752876
// Create an instance of the WebAudio object.
2876-
audio = {};
2877-
audio.resource = info; // This new object is an instance that refers to this existing resource.
2878-
audio.paused = false;
2879-
audio.currentPosition = 0;
28802877
// Make our instance look similar to the instance of a <media> to make api simple.
2881-
audio.play = function() { SDL.playWebAudio(this); }
2882-
audio.pause = function() { SDL.pauseWebAudio(this); }
2878+
audio = {
2879+
resource: info, // This new object is an instance that refers to this existing resource.
2880+
paused: false,
2881+
currentPosition: 0,
2882+
play() { SDL.playWebAudio(this); },
2883+
pause() { SDL.pauseWebAudio(this); },
2884+
};
28832885
} else {
28842886
// We clone the audio node to utilize the preloaded audio buffer, since
28852887
// the browser has already preloaded the audio file.
@@ -2964,12 +2966,13 @@ var LibrarySDL = {
29642966
var audio;
29652967
if (info.webAudio) { // Play via Web Audio API
29662968
// Create an instance of the WebAudio object.
2967-
audio = {};
2968-
audio.resource = info; // This new webAudio object is an instance that refers to this existing resource.
2969-
audio.paused = false;
2970-
audio.currentPosition = 0;
2971-
audio.play = function() { SDL.playWebAudio(this); }
2972-
audio.pause = function() { SDL.pauseWebAudio(this); }
2969+
audio = {
2970+
resource: info, // This new webAudio object is an instance that refers to this existing resource.
2971+
paused: false,
2972+
currentPosition: 0,
2973+
play() { SDL.playWebAudio(this); },
2974+
pause() { SDL.pauseWebAudio(this); },
2975+
};
29732976
} else if (info.audio) { // Play via the <audio> element
29742977
audio = info.audio;
29752978
}

src/library_syscall.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -790,22 +790,20 @@ var SyscallsLibrary = {
790790
},
791791
792792
__syscall_statfs64: (path, size, buf) => {
793-
path = SYSCALLS.getStr(path);
794793
#if ASSERTIONS
795794
assert(size === {{{ C_STRUCTS.statfs.__size__ }}});
796795
#endif
797-
// NOTE: None of the constants here are true. We're just returning safe and
798-
// sane values.
799-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bsize, '4096', 'i32') }}};
800-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_frsize, '4096', 'i32') }}};
801-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_blocks, '1000000', 'i32') }}};
802-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bfree, '500000', 'i32') }}};
803-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bavail, '500000', 'i32') }}};
804-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_files, 'FS.nextInode', 'i32') }}};
805-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_ffree, '1000000', 'i32') }}};
806-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_fsid, '42', 'i32') }}};
807-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_flags, '2', 'i32') }}}; // ST_NOSUID
808-
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_namelen, '255', 'i32') }}};
796+
var stats = FS.statfs(SYSCALLS.getStr(path));
797+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bsize, 'stats.bsize', 'i32') }}};
798+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_frsize, 'stats.bsize', 'i32') }}};
799+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_blocks, 'stats.blocks', 'i32') }}};
800+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bfree, 'stats.bfree', 'i32') }}};
801+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_bavail, 'stats.bavail', 'i32') }}};
802+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_files, 'stats.files', 'i32') }}};
803+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_ffree, 'stats.ffree', 'i32') }}};
804+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_fsid, 'stats.fsid', 'i32') }}};
805+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_flags, 'stats.flags', 'i32') }}}; // ST_NOSUID
806+
{{{ makeSetValue('buf', C_STRUCTS.statfs.f_namelen, 'stats.namelen', 'i32') }}};
809807
return 0;
810808
},
811809
__syscall_fstatfs64__deps: ['__syscall_statfs64'],

test/core/test_statvfs.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
#include <stdio.h>
99
#include <errno.h>
1010
#include <sys/statvfs.h>
11+
#include <sys/types.h>
12+
#include <sys/stat.h>
1113

1214
int main() {
1315
struct statvfs s;
1416

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

@@ -21,8 +24,8 @@ int main() {
2124
printf("f_bfree: %u\n", s.f_bfree);
2225
printf("f_bavail: %u\n", s.f_bavail);
2326
printf("f_files: %d\n", s.f_files > 5);
24-
printf("f_ffree: %u\n", s.f_ffree);
25-
printf("f_favail: %u\n", s.f_favail);
27+
printf("f_ffree: %u\n", s.f_ffree <= s.f_files && s.f_ffree > 0);
28+
printf("f_favail: %u\n", s.f_favail <= s.f_files && s.f_favail > 0);
2629
printf("f_fsid: %lu\n", s.f_fsid);
2730
printf("f_flag: %lu\n", s.f_flag);
2831
printf("f_namemax: %lu\n", s.f_namemax);

test/core/test_statvfs.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ f_blocks: 1000000
66
f_bfree: 500000
77
f_bavail: 500000
88
f_files: 1
9-
f_ffree: 1000000
10-
f_favail: 1000000
9+
f_ffree: 1
10+
f_favail: 1
1111
f_fsid: 42
1212
f_flag: 2
1313
f_namemax: 255

test/fs/test_nodefs_statvfs.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <assert.h>
2+
#include <stdio.h>
3+
#include <sys/statvfs.h>
4+
#include <emscripten.h>
5+
6+
void test_statvfs(const char *path) {
7+
printf("Testing statfs for path: %s\n", path);
8+
struct statvfs st;
9+
int result = statvfs(path, &st);
10+
11+
assert(result == 0 && "statvfs should succeed");
12+
13+
// Basic sanity checks
14+
assert(st.f_bsize > 0 && "Block size should be positive");
15+
assert(st.f_blocks > 0 && "Total blocks should be positive");
16+
assert(st.f_bfree <= st.f_blocks && "Free blocks should not exceed total blocks");
17+
assert(st.f_bavail <= st.f_bfree && "Available blocks should not exceed free blocks");
18+
assert(st.f_files >= 0 && "Total inodes should be 0 or positive");
19+
assert(st.f_ffree <= st.f_files && "Free inodes should not exceed total inodes");
20+
}
21+
22+
void setup() {
23+
EM_ASM(
24+
FS.mkdir('/working');
25+
FS.mount(NODEFS, { root: '.' }, '/working');
26+
);
27+
}
28+
29+
int main() {
30+
setup();
31+
// Test the root filesystem (which should be MEMFS by default)
32+
test_statvfs("/");
33+
test_statvfs("/working");
34+
puts("success");
35+
}

test/test_core.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5784,10 +5784,20 @@ def test_fs_nodefs_readdir(self):
57845784
# externally setup an existing folder structure: existing/a
57855785
if self.get_setting('WASMFS'):
57865786
self.set_setting('FORCE_FILESYSTEM')
5787-
os.makedirs(os.path.join(self.working_dir, 'existing', 'a'))
5787+
os.makedirs('existing/a')
57885788
self.emcc_args += ['-lnodefs.js']
57895789
self.do_runf('fs/test_nodefs_readdir.c', 'success')
57905790

5791+
@requires_node
5792+
@crossplatform
5793+
def test_fs_nodefs_statvfs(self):
5794+
# externally setup an existing folder structure: existing/a
5795+
if self.get_setting('WASMFS'):
5796+
self.set_setting('FORCE_FILESYSTEM')
5797+
os.makedirs('existing/a')
5798+
self.emcc_args += ['-lnodefs.js']
5799+
self.do_runf('fs/test_nodefs_statvfs.c', 'success')
5800+
57915801
@no_windows('no symlink support on windows')
57925802
@requires_node
57935803
def test_fs_noderawfs_nofollow(self):

0 commit comments

Comments
 (0)