Skip to content

Commit 48298d9

Browse files
authored
[WasmFS] Support resizing unopened files in the OPFS backend (#17200)
In #17192 we updated WasmFS to open files before truncating them since the OPFS backend did not support truncating unopened files. However, `truncate` can be called on unopened files so the OPFS backend needs to support these truncations anyway. Implement truncation of unopened files using the older, async WritableStream Blob API.
1 parent b1dbe13 commit 48298d9

File tree

4 files changed

+46
-9
lines changed

4 files changed

+46
-9
lines changed

src/library_wasmfs_opfs.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ mergeInto(LibraryManager.library, {
252252
_emscripten_proxy_finish(ctx);
253253
},
254254

255-
_wasmfs_opfs_get_size_blob__deps: ['$wasmfsOPFSFileHandles'],
256-
_wasmfs_opfs_get_size_blob: async function(ctx, fileID, sizePtr) {
255+
_wasmfs_opfs_get_size_file__deps: ['$wasmfsOPFSFileHandles'],
256+
_wasmfs_opfs_get_size_file: async function(ctx, fileID, sizePtr) {
257257
let fileHandle = wasmfsOPFSFileHandles.get(fileID);
258258
let size = (await fileHandle.getFile()).size;
259259
{{{ makeSetValue('sizePtr', 0, 'size', 'i32') }}};
@@ -267,6 +267,20 @@ mergeInto(LibraryManager.library, {
267267
_emscripten_proxy_finish(ctx);
268268
},
269269

270+
_wasmfs_opfs_set_size_file__deps: ['$wasmfsOPFSFileHandles'],
271+
_wasmfs_opfs_set_size_file: async function(ctx, fileID, size, errPtr) {
272+
let fileHandle = wasmfsOPFSFileHandles.get(fileID);
273+
try {
274+
let writable = await fileHandle.createWritable();
275+
await writable.truncate(size);
276+
await writable.close();
277+
{{{ makeSetValue('errPtr', 0, '0', 'i32') }}};
278+
} catch {
279+
{{{ makeSetValue('errPtr', 0, '1', 'i32') }}};
280+
}
281+
_emscripten_proxy_finish(ctx);
282+
},
283+
270284
_wasmfs_opfs_flush_access__deps: ['$wasmfsOPFSAccessHandles'],
271285
_wasmfs_opfs_flush_access: async function(ctx, accessID) {
272286
let accessHandle = wasmfsOPFSAccessHandles.get(accessID);

system/lib/wasmfs/backends/opfs_backend.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,20 @@ void _wasmfs_opfs_get_size_access(em_proxying_ctx* ctx,
7979
int access_id,
8080
uint32_t* size);
8181

82-
// Get the size via a File Blob.
83-
void _wasmfs_opfs_get_size_blob(em_proxying_ctx* ctx,
84-
int access_id,
82+
// Get the size of a file handle via a File Blob.
83+
void _wasmfs_opfs_get_size_file(em_proxying_ctx* ctx,
84+
int file_id,
8585
uint32_t* size);
8686

8787
void _wasmfs_opfs_set_size_access(em_proxying_ctx* ctx,
8888
int access_id,
8989
uint32_t size);
9090

91+
void _wasmfs_opfs_set_size_file(em_proxying_ctx* ctx,
92+
int file_id,
93+
uint32_t size,
94+
int* err);
95+
9196
void _wasmfs_opfs_flush_access(em_proxying_ctx* ctx, int access_id);
9297

9398
} // extern "C"
@@ -123,7 +128,7 @@ class OPFSFile : public DataFile {
123128
uint32_t size;
124129
if (accessID == -1) {
125130
proxy(
126-
[&](auto ctx) { _wasmfs_opfs_get_size_blob(ctx.ctx, fileID, &size); });
131+
[&](auto ctx) { _wasmfs_opfs_get_size_file(ctx.ctx, fileID, &size); });
127132
} else {
128133
proxy([&](auto ctx) {
129134
_wasmfs_opfs_get_size_access(ctx.ctx, accessID, &size);
@@ -133,8 +138,17 @@ class OPFSFile : public DataFile {
133138
}
134139

135140
void setSize(size_t size) override {
136-
proxy(
137-
[&](auto ctx) { _wasmfs_opfs_set_size_access(ctx.ctx, accessID, size); });
141+
if (accessID == -1) {
142+
int err;
143+
proxy([&](auto ctx) {
144+
_wasmfs_opfs_set_size_file(ctx.ctx, fileID, size, &err);
145+
});
146+
assert(err == 0 && "TODO: better error handling");
147+
} else {
148+
proxy([&](auto ctx) {
149+
_wasmfs_opfs_set_size_access(ctx.ctx, accessID, size);
150+
});
151+
}
138152
}
139153

140154
void open(oflags_t flags) override {

system/lib/wasmfs/syscalls.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ static __wasi_fd_t doOpen(path::ParsedParent parsed,
466466
}
467467

468468
// Note that we open the file before truncating it because some backends may
469-
// depend on that (e.g. OPFS).
469+
// truncate opened files more efficiently (e.g. OPFS).
470470
auto openFile = std::make_shared<OpenFileState>(0, flags, child);
471471

472472
// If O_TRUNC, truncate the file if possible.

tests/wasmfs/wasmfs_opfs.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ int main(int argc, char* argv[]) {
123123
assert(stat_buf.st_size == 1);
124124
emscripten_console_log("statted while closed");
125125

126+
err = truncate("/opfs/working/foo.txt", 42);
127+
assert(err == 0);
128+
emscripten_console_log("resized while closed");
129+
130+
err = stat("/opfs/working/foo.txt", &stat_buf);
131+
assert(err == 0);
132+
assert(stat_buf.st_size == 42);
133+
emscripten_console_log("statted while closed again");
134+
126135
fd = open("/opfs/working/foo.txt", O_RDONLY | O_TRUNC);
127136
assert(fd > 0);
128137
emscripten_console_log("truncated while opening");

0 commit comments

Comments
 (0)