Skip to content

Commit b70d6f9

Browse files
authored
[WasmFS] Fix OPFS getSize when file is not opened (#17027)
The `getSize` implementation in the OPFS backend previously depended on having an AccessHandle to the corresponding file, but that's only the case for open files. `getSize` can also be called on files that have not been opened, for example in the implementation of the `stat` syscall. Fix the bug in this case by using an alternative code path that gets the size of the file using the Blob API, which does not require having an AccessHandle.
1 parent 04cc344 commit b70d6f9

File tree

3 files changed

+47
-13
lines changed

3 files changed

+47
-13
lines changed

src/library_wasmfs_opfs.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,22 @@ mergeInto(LibraryManager.library, {
236236
return accessHandle.write(data, {at: pos});
237237
},
238238

239-
_wasmfs_opfs_get_size__deps: ['$wasmfsOPFSAccesses'],
240-
_wasmfs_opfs_get_size: async function(ctx, accessID, sizePtr) {
239+
_wasmfs_opfs_get_size_access__deps: ['$wasmfsOPFSAccesses'],
240+
_wasmfs_opfs_get_size_access: async function(ctx, accessID, sizePtr) {
241241
let accessHandle = wasmfsOPFSAccesses.get(accessID);
242242
let size = await accessHandle.getSize();
243243
{{{ makeSetValue('sizePtr', 0, 'size', 'i32') }}};
244244
_emscripten_proxy_finish(ctx);
245245
},
246246

247+
_wasmfs_opfs_get_size_blob__deps: ['$wasmfsOPFSFiles'],
248+
_wasmfs_opfs_get_size_blob: async function(ctx, fileID, sizePtr) {
249+
let fileHandle = wasmfsOPFSFiles.get(fileID);
250+
let size = (await fileHandle.getFile()).size;
251+
{{{ makeSetValue('sizePtr', 0, 'size', 'i32') }}};
252+
_emscripten_proxy_finish(ctx);
253+
},
254+
247255
_wasmfs_opfs_set_size__deps: ['$wasmfsOPFSAccesses'],
248256
_wasmfs_opfs_set_size: async function(ctx, accessID, size) {
249257
let accessHandle = wasmfsOPFSAccesses.get(accessID);

system/lib/wasmfs/backends/opfs_backend.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,15 @@ int _wasmfs_opfs_write(int access_id,
6969
uint32_t len,
7070
uint32_t pos);
7171

72-
void _wasmfs_opfs_get_size(em_proxying_ctx* ctx, int access_id, uint32_t* size);
72+
// Get the size via an AccessHandle.
73+
void _wasmfs_opfs_get_size_access(em_proxying_ctx* ctx,
74+
int access_id,
75+
uint32_t* size);
76+
77+
// Get the size via a File Blob.
78+
void _wasmfs_opfs_get_size_blob(em_proxying_ctx* ctx,
79+
int access_id,
80+
uint32_t* size);
7381

7482
void _wasmfs_opfs_set_size(em_proxying_ctx* ctx, int access_id, uint32_t size);
7583

@@ -106,7 +114,14 @@ class OPFSFile : public DataFile {
106114
private:
107115
size_t getSize() override {
108116
uint32_t size;
109-
proxy([&](auto ctx) { _wasmfs_opfs_get_size(ctx.ctx, accessID, &size); });
117+
if (accessID == -1) {
118+
proxy(
119+
[&](auto ctx) { _wasmfs_opfs_get_size_blob(ctx.ctx, fileID, &size); });
120+
} else {
121+
proxy([&](auto ctx) {
122+
_wasmfs_opfs_get_size_access(ctx.ctx, accessID, &size);
123+
});
124+
}
110125
return size_t(size);
111126
}
112127

tests/wasmfs/wasmfs_opfs.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,27 +69,27 @@ int main(int argc, char* argv[]) {
6969
fdatasync(fd);
7070
emscripten_console_log("flushed");
7171

72-
struct stat stat;
73-
err = fstat(fd, &stat);
72+
struct stat stat_buf;
73+
err = fstat(fd, &stat_buf);
7474
assert(err == 0);
75-
assert(stat.st_size == strlen(msg));
75+
assert(stat_buf.st_size == strlen(msg));
7676
emscripten_console_log("statted");
7777

7878
#ifndef WASMFS_SETUP
7979

8080
err = ftruncate(fd, 100);
8181
assert(err == 0);
82-
err = fstat(fd, &stat);
82+
err = fstat(fd, &stat_buf);
8383
assert(err == 0);
84-
assert(stat.st_size == 100);
84+
assert(stat_buf.st_size == 100);
8585
emscripten_console_log("truncated to 100");
8686

87-
err = ftruncate(fd, 0);
87+
err = ftruncate(fd, 1);
8888
assert(err == 0);
89-
err = fstat(fd, &stat);
89+
err = fstat(fd, &stat_buf);
9090
assert(err == 0);
91-
assert(stat.st_size == 0);
92-
emscripten_console_log("truncated to 0");
91+
assert(stat_buf.st_size == 1);
92+
emscripten_console_log("truncated to 1");
9393

9494
struct dirent** entries;
9595
int nentries = scandir("/opfs/working", &entries, NULL, alphasort);
@@ -118,6 +118,11 @@ int main(int argc, char* argv[]) {
118118
assert(err == 0);
119119
emscripten_console_log("closed file");
120120

121+
err = stat("/opfs/working/foo.txt", &stat_buf);
122+
assert(err == 0);
123+
assert(stat_buf.st_size == 1);
124+
emscripten_console_log("statted");
125+
121126
err = rename("/opfs/working/foo.txt", "/opfs/foo.txt");
122127
assert(err == 0);
123128
err = access("/opfs/working/foo.txt", F_OK);
@@ -144,7 +149,13 @@ int main(int argc, char* argv[]) {
144149
}
145150

146151
void cleanup(void) {
152+
printf("cleaning up\n");
153+
147154
unlink("/opfs/working/foo.txt");
148155
rmdir("/opfs/working");
149156
unlink("/opfs/foo.txt");
157+
158+
assert(access("/opfs/working/foo.txt", F_OK) != 0);
159+
assert(access("/opfs/working", F_OK) != 0);
160+
assert(access("/opfs/foo.txt", F_OK) != 0);
150161
}

0 commit comments

Comments
 (0)