blob: 3ab75035e464d83661e102894fbae6fa260882f8 [file] [edit]
/**
* @license
* Copyright 2022 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/
mergeInto(LibraryManager.library, {
// TODO: Generate these ID pools from a common utility.
$wasmfsOPFSDirectories: {
allocated: [],
free: [],
get: function(i) {
assert(this.allocated[i] !== undefined);
return this.allocated[i];
}
},
$wasmfsOPFSFiles: {
allocated: [],
free: [],
get: function(i) {
assert(this.allocated[i] !== undefined);
return this.allocated[i];
}
},
$wasmfsOPFSAccesses: {
allocated: [],
free: [],
get: function(i) {
assert(this.allocated[i] !== undefined);
return this.allocated[i];
}
},
$wasmfsOPFSAllocate: function(ids, handle) {
let id;
if (ids.free.length > 0) {
id = ids.free.pop();
ids.allocated[id] = handle;
} else {
id = ids.allocated.length;
ids.allocated.push(handle);
}
return id;
},
$wasmfsOPFSFree: function(ids, id) {
delete ids.allocated[id];
ids.free.push(id);
},
_wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectories'],
_wasmfs_opfs_init_root_directory: async function(ctx) {
if (wasmfsOPFSDirectories.allocated.length == 0) {
// Directory 0 is reserved as the root
let root = await navigator.storage.getDirectory();
wasmfsOPFSDirectories.allocated.push(root);
}
_emscripten_proxy_finish(ctx);
},
// Return the file ID for the file with `name` under `parent`, creating it if
// it doesn't exist and `create` or otherwise return one of the following
// error codes:
//
// -1: file does not exist.
// -2: file exists but it is actually a directory.
// -3: file exists but an access handle cannot be created for it.
$wasmfsOPFSGetOrCreateFile__deps: ['$wasmfsOPFSAllocate',
'$wasmfsOPFSDirectories',
'$wasmfsOPFSFiles'],
$wasmfsOPFSGetOrCreateFile: async function(parent, name, create) {
let parentHandle = wasmfsOPFSDirectories.get(parent);
let fileHandle;
try {
fileHandle = await parentHandle.getFileHandle(name, {create: create});
} catch (e) {
if (e.name === "NotFoundError") {
return -1;
}
if (e.name === "TypeMismatchError") {
return -2;
}
throw e;
}
return wasmfsOPFSAllocate(wasmfsOPFSFiles, fileHandle);
},
// Return the file ID for the directory with `name` under `parent`, creating
// it if it doesn't exist and `create` or otherwise one of the following error
// codes:
//
// -1: directory does not exist.
// -2: directory exists but is actually a data file.
$wasmfsOPFSGetOrCreateDir__deps: ['$wasmfsOPFSAllocate',
'$wasmfsOPFSDirectories'],
$wasmfsOPFSGetOrCreateDir: async function(parent, name, create) {
let parentHandle = wasmfsOPFSDirectories.get(parent);
let childHandle;
try {
childHandle =
await parentHandle.getDirectoryHandle(name, {create: create});
} catch (e) {
if (e.name === "NotFoundError") {
return -1;
}
if (e.name === "TypeMismatchError") {
return -2;
}
throw e;
}
return wasmfsOPFSAllocate(wasmfsOPFSDirectories, childHandle);
},
_wasmfs_opfs_get_child__deps: ['$wasmfsOPFSGetOrCreateFile',
'$wasmfsOPFSGetOrCreateDir'],
_wasmfs_opfs_get_child:
async function(ctx, parent, namePtr, childTypePtr, childIDPtr) {
let name = UTF8ToString(namePtr);
let childType = 1;
let childID = await wasmfsOPFSGetOrCreateFile(parent, name, false);
if (childID == -2) {
childType = 2;
childID = await wasmfsOPFSGetOrCreateDir(parent, name, false);
}
{{{ makeSetValue('childTypePtr', 0, 'childType', 'i32') }}};
{{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}};
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_get_entries__deps: [],
_wasmfs_opfs_get_entries: async function(ctx, dirID, entries) {
let dirHandle = wasmfsOPFSDirectories.get(dirID);
for await (let [name, child] of dirHandle.entries()) {
withStackSave(() => {
let namePtr = allocateUTF8OnStack(name);
let type = child.kind == "file" ?
{{{ cDefine('File::DataFileKind') }}} :
{{{ cDefine('File::DirectoryKind') }}};
__wasmfs_opfs_record_entry(entries, namePtr, type)
});
}
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_insert_file__deps: ['$wasmfsOPFSGetOrCreateFile'],
_wasmfs_opfs_insert_file: async function(ctx, parent, namePtr, childIDPtr) {
let name = UTF8ToString(namePtr);
let childID = await wasmfsOPFSGetOrCreateFile(parent, name, true);
{{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}};
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_insert_directory__deps: ['$wasmfsOPFSGetOrCreateDir'],
_wasmfs_opfs_insert_directory: async function(ctx, parent, namePtr, childIDPtr) {
let name = UTF8ToString(namePtr);
let childID = await wasmfsOPFSGetOrCreateDir(parent, name, true);
{{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}};
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_move__deps: ['$wasmfsOPFSFiles', '$wasmfsOPFSDirectories'],
_wasmfs_opfs_move: async function(ctx, fileID, newDirID, namePtr) {
let name = UTF8ToString(namePtr);
let fileHandle = wasmfsOPFSFiles.get(fileID);
let newDirHandle = wasmfsOPFSDirectories.get(newDirID);
await fileHandle.move(newDirHandle, name);
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_remove_child__deps: ['$wasmfsOPFSFree', '$wasmfsOPFSDirectories'],
_wasmfs_opfs_remove_child: async function(ctx, dirID, namePtr) {
let name = UTF8ToString(namePtr);
let dirHandle = wasmfsOPFSDirectories.get(dirID);
await dirHandle.removeEntry(name);
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_free_file__deps: ['$wasmfsOPFSFree', '$wasmfsOPFSFiles'],
_wasmfs_opfs_free_file: function(fileID) {
wasmfsOPFSFree(wasmfsOPFSFiles, fileID);
},
_wasmfs_opfs_free_directory__deps: ['$wasmfsOPFSFree',
'$wasmfsOPFSDirectories'],
_wasmfs_opfs_free_directory: function(dirID) {
wasmfsOPFSFree(wasmfsOPFSDirectories, dirID);
},
_wasmfs_opfs_open__deps: ['$wasmfsOPFSAllocate',
'$wasmfsOPFSFiles',
'$wasmfsOPFSAccesses'],
_wasmfs_opfs_open: async function(ctx, fileID, accessIDPtr) {
let fileHandle = wasmfsOPFSFiles.get(fileID);
let accessID;
try {
let accessHandle;
// TODO: Remove this once the Access Handles API has settled.
if (FileSystemFileHandle.prototype.createSyncAccessHandle.length == 0) {
accessHandle = await fileHandle.createSyncAccessHandle();
} else {
accessHandle = await fileHandle.createSyncAccessHandle(
{mode: "in-place"});
}
accessID = wasmfsOPFSAllocate(wasmfsOPFSAccesses, accessHandle);
} catch (e) {
if (e.name === "InvalidStateError") {
accessID = -1;
}
throw e;
}
{{{ makeSetValue('accessIDPtr', 0, 'accessID', 'i32') }}};
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_close__deps: ['$wasmfsOPFSFree', '$wasmfsOPFSAccesses'],
_wasmfs_opfs_close: async function(ctx, accessID) {
let accessHandle = wasmfsOPFSAccesses.get(accessID);
await accessHandle.close();
wasmfsOPFSFree(wasmfsOPFSAccesses, accessID);
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_read__deps: ['$wasmfsOPFSAccesses'],
_wasmfs_opfs_read: function(accessID, bufPtr, len, pos) {
let accessHandle = wasmfsOPFSAccesses.get(accessID);
let data = HEAPU8.subarray(bufPtr, bufPtr + len);
return accessHandle.read(data, {at: pos});
},
_wasmfs_opfs_write__deps: ['$wasmfsOPFSAccesses'],
_wasmfs_opfs_write: function(accessID, bufPtr, len, pos, nwrittenPtr) {
let accessHandle = wasmfsOPFSAccesses.get(accessID);
let data = HEAPU8.subarray(bufPtr, bufPtr + len);
return accessHandle.write(data, {at: pos});
},
_wasmfs_opfs_get_size_access__deps: ['$wasmfsOPFSAccesses'],
_wasmfs_opfs_get_size_access: async function(ctx, accessID, sizePtr) {
let accessHandle = wasmfsOPFSAccesses.get(accessID);
let size = await accessHandle.getSize();
{{{ makeSetValue('sizePtr', 0, 'size', 'i32') }}};
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_get_size_blob__deps: ['$wasmfsOPFSFiles'],
_wasmfs_opfs_get_size_blob: async function(ctx, fileID, sizePtr) {
let fileHandle = wasmfsOPFSFiles.get(fileID);
let size = (await fileHandle.getFile()).size;
{{{ makeSetValue('sizePtr', 0, 'size', 'i32') }}};
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_set_size__deps: ['$wasmfsOPFSAccesses'],
_wasmfs_opfs_set_size: async function(ctx, accessID, size) {
let accessHandle = wasmfsOPFSAccesses.get(accessID);
await accessHandle.truncate(size);
_emscripten_proxy_finish(ctx);
},
_wasmfs_opfs_flush__deps: ['$wasmfsOPFSAccesses'],
_wasmfs_opfs_flush: async function(ctx, accessID) {
let accessHandle = wasmfsOPFSAccesses.get(accessID);
await accessHandle.flush();
_emscripten_proxy_finish(ctx);
}
});