Buckets:
| /** | |
| * @license | |
| * Copyright 2022 The Emscripten Authors | |
| * SPDX-License-Identifier: MIT | |
| */ | |
| addToLibrary({ | |
| $wasmfsOPFSDirectoryHandles__deps: ['$HandleAllocator'], | |
| $wasmfsOPFSDirectoryHandles: "new HandleAllocator()", | |
| $wasmfsOPFSFileHandles__deps: ['$HandleAllocator'], | |
| $wasmfsOPFSFileHandles: "new HandleAllocator()", | |
| $wasmfsOPFSAccessHandles__deps: ['$HandleAllocator'], | |
| $wasmfsOPFSAccessHandles: "new HandleAllocator()", | |
| $wasmfsOPFSBlobs__deps: ["$HandleAllocator"], | |
| $wasmfsOPFSBlobs: "new HandleAllocator()", | |
| #if !PTHREADS | |
| // OPFS will only be used on modern browsers that supports JS classes. | |
| $FileSystemAsyncAccessHandle: class { | |
| // This class implements the same interface as the sync version, but has | |
| // async reads and writes. Hopefully this will one day be implemented by the | |
| // platform so we can remove it. | |
| constructor(handle) { | |
| this.handle = handle; | |
| } | |
| async close() {} | |
| async flush() {} | |
| async getSize() { | |
| let file = await this.handle.getFile(); | |
| return file.size; | |
| } | |
| async read(buffer, options = { at: 0 }) { | |
| let file = await this.handle.getFile(); | |
| // The end position may be past the end of the file, but slice truncates | |
| // it. | |
| let slice = await file.slice(options.at, options.at + buffer.length); | |
| let fileBuffer = await slice.arrayBuffer(); | |
| let array = new Uint8Array(fileBuffer); | |
| buffer.set(array); | |
| return array.length; | |
| } | |
| async write(buffer, options = { at: 0 }) { | |
| let writable = await this.handle.createWritable({keepExistingData: true}); | |
| await writable.write({ type: 'write', position: options.at, data: buffer }); | |
| await writable.close(); | |
| return buffer.length; | |
| } | |
| async truncate(size) { | |
| let writable = await this.handle.createWritable({keepExistingData: true}); | |
| await writable.truncate(size); | |
| await writable.close(); | |
| } | |
| }, | |
| $wasmfsOPFSCreateAsyncAccessHandle__deps: ['$FileSystemAsyncAccessHandle'], | |
| $wasmfsOPFSCreateAsyncAccessHandle: (fileHandle) => new FileSystemAsyncAccessHandle(fileHandle), | |
| #endif | |
| #if PTHREADS | |
| $wasmfsOPFSProxyFinish__deps: ['emscripten_proxy_finish'], | |
| #endif | |
| $wasmfsOPFSProxyFinish: (ctx) => { | |
| // When using pthreads the proxy needs to know when the work is finished. | |
| // When used with JSPI the work will be executed in an async block so there | |
| // is no need to notify when done. | |
| #if PTHREADS | |
| _emscripten_proxy_finish(ctx); | |
| #endif | |
| }, | |
| _wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_init_root_directory__async: 'auto', | |
| _wasmfs_opfs_init_root_directory: async (ctx) => { | |
| // allocated.length starts off as 1 since 0 is a reserved handle | |
| if (wasmfsOPFSDirectoryHandles.allocated.length == 1) { | |
| // Closure compiler errors on this as it does not recognize the OPFS | |
| // API yet, it seems. Unfortunately an existing annotation for this is in | |
| // the closure compiler codebase, and cannot be overridden in user code | |
| // (it complains on a duplicate type annotation), so just suppress it. | |
| /** @suppress {checkTypes} */ | |
| let root = await navigator.storage.getDirectory(); | |
| wasmfsOPFSDirectoryHandles.allocated.push(root); | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| // Return the file ID for the file with `name` under `parent`, creating it if | |
| // it doesn't exist and `create` or otherwise return a negative error code | |
| // corresponding to the error. | |
| $wasmfsOPFSGetOrCreateFile__deps: ['$wasmfsOPFSDirectoryHandles', | |
| '$wasmfsOPFSFileHandles'], | |
| $wasmfsOPFSGetOrCreateFile: async (parent, name, create) => { | |
| let parentHandle = wasmfsOPFSDirectoryHandles.get(parent); | |
| let fileHandle; | |
| try { | |
| fileHandle = await parentHandle.getFileHandle(name, {create: create}); | |
| } catch (e) { | |
| if (e.name === "NotFoundError") { | |
| return -{{{ cDefs.EEXIST }}}; | |
| } | |
| if (e.name === "TypeMismatchError") { | |
| return -{{{ cDefs.EISDIR }}}; | |
| } | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| return -{{{ cDefs.EIO }}}; | |
| } | |
| return wasmfsOPFSFileHandles.allocate(fileHandle); | |
| }, | |
| // Return the file ID for the directory with `name` under `parent`, creating | |
| // it if it doesn't exist and `create` or otherwise return a negative error | |
| // code corresponding to the error. | |
| $wasmfsOPFSGetOrCreateDir__deps: ['$wasmfsOPFSDirectoryHandles'], | |
| $wasmfsOPFSGetOrCreateDir: async (parent, name, create) => { | |
| let parentHandle = wasmfsOPFSDirectoryHandles.get(parent); | |
| let childHandle; | |
| try { | |
| childHandle = | |
| await parentHandle.getDirectoryHandle(name, {create: create}); | |
| } catch (e) { | |
| if (e.name === "NotFoundError") { | |
| return -{{{ cDefs.EEXIST }}}; | |
| } | |
| if (e.name === "TypeMismatchError") { | |
| return -{{{ cDefs.ENOTDIR }}}; | |
| } | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| return -{{{ cDefs.EIO }}}; | |
| } | |
| return wasmfsOPFSDirectoryHandles.allocate(childHandle); | |
| }, | |
| _wasmfs_opfs_get_child__deps: ['$wasmfsOPFSGetOrCreateFile', | |
| '$wasmfsOPFSGetOrCreateDir', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_get_child__async: 'auto', | |
| _wasmfs_opfs_get_child: async (ctx, parent, namePtr, childTypePtr, childIDPtr) => { | |
| let name = UTF8ToString(namePtr); | |
| let childType = 1; | |
| let childID = await wasmfsOPFSGetOrCreateFile(parent, name, false); | |
| if (childID == -{{{ cDefs.EISDIR }}}) { | |
| childType = 2; | |
| childID = await wasmfsOPFSGetOrCreateDir(parent, name, false); | |
| } | |
| {{{ makeSetValue('childTypePtr', 0, 'childType', 'i32') }}}; | |
| {{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_get_entries__deps: [ | |
| '$wasmfsOPFSProxyFinish', | |
| '$stackSave', | |
| '$stackRestore', | |
| '_wasmfs_opfs_record_entry', | |
| ], | |
| _wasmfs_opfs_get_entries__async: 'auto', | |
| _wasmfs_opfs_get_entries: async (ctx, dirID, entriesPtr, errPtr) => { | |
| let dirHandle = wasmfsOPFSDirectoryHandles.get(dirID); | |
| // TODO: Use 'for await' once Acorn supports that. | |
| try { | |
| let iter = dirHandle.entries(); | |
| for (let entry; entry = await iter.next(), !entry.done;) { | |
| let [name, child] = entry.value; | |
| let sp = stackSave(); | |
| let namePtr = stringToUTF8OnStack(name); | |
| let type = child.kind == "file" ? | |
| {{{ cDefs['File::DataFileKind'] }}} : | |
| {{{ cDefs['File::DirectoryKind'] }}}; | |
| __wasmfs_opfs_record_entry(entriesPtr, namePtr, type) | |
| stackRestore(sp); | |
| } | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_insert_file__deps: ['$wasmfsOPFSGetOrCreateFile', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_insert_file__async: 'auto', | |
| _wasmfs_opfs_insert_file: async (ctx, parent, namePtr, childIDPtr) => { | |
| let name = UTF8ToString(namePtr); | |
| let childID = await wasmfsOPFSGetOrCreateFile(parent, name, true); | |
| {{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_insert_directory__deps: ['$wasmfsOPFSGetOrCreateDir', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_insert_directory__async: 'auto', | |
| _wasmfs_opfs_insert_directory: async (ctx, parent, namePtr, childIDPtr) => { | |
| let name = UTF8ToString(namePtr); | |
| let childID = await wasmfsOPFSGetOrCreateDir(parent, name, true); | |
| {{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_move_file__deps: ['$wasmfsOPFSFileHandles', | |
| '$wasmfsOPFSDirectoryHandles', | |
| '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_move_file__async: 'auto', | |
| _wasmfs_opfs_move_file: async (ctx, fileID, newParentID, namePtr, errPtr) => { | |
| let name = UTF8ToString(namePtr); | |
| let fileHandle = wasmfsOPFSFileHandles.get(fileID); | |
| let newDirHandle = wasmfsOPFSDirectoryHandles.get(newParentID); | |
| try { | |
| await fileHandle.move(newDirHandle, name); | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_remove_child__deps: ['$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_remove_child__async: 'auto', | |
| _wasmfs_opfs_remove_child: async (ctx, dirID, namePtr, errPtr) => { | |
| let name = UTF8ToString(namePtr); | |
| let dirHandle = wasmfsOPFSDirectoryHandles.get(dirID); | |
| try { | |
| await dirHandle.removeEntry(name); | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_free_file__deps: ['$wasmfsOPFSFileHandles'], | |
| _wasmfs_opfs_free_file: (fileID) => { | |
| wasmfsOPFSFileHandles.free(fileID); | |
| }, | |
| _wasmfs_opfs_free_directory__deps: ['$wasmfsOPFSDirectoryHandles'], | |
| _wasmfs_opfs_free_directory: (dirID) => { | |
| wasmfsOPFSDirectoryHandles.free(dirID); | |
| }, | |
| _wasmfs_opfs_open_access__deps: ['$wasmfsOPFSFileHandles', | |
| '$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish', | |
| #if !PTHREADS | |
| '$wasmfsOPFSCreateAsyncAccessHandle' | |
| #endif | |
| ], | |
| _wasmfs_opfs_open_access__async: 'auto', | |
| _wasmfs_opfs_open_access: async (ctx, fileID, accessIDPtr) => { | |
| let fileHandle = wasmfsOPFSFileHandles.get(fileID); | |
| let accessID; | |
| try { | |
| let accessHandle; | |
| #if PTHREADS | |
| // TODO: Remove this once the Access Handles API has settled. | |
| // TODO: Closure is confused by this code that supports two versions of | |
| // the same API, so suppress type checking on it. | |
| /** @suppress {checkTypes} */ | |
| var len = FileSystemFileHandle.prototype.createSyncAccessHandle.length; | |
| if (len == 0) { | |
| accessHandle = await fileHandle.createSyncAccessHandle(); | |
| } else { | |
| accessHandle = await fileHandle.createSyncAccessHandle( | |
| {mode: "in-place"}); | |
| } | |
| #else | |
| accessHandle = await wasmfsOPFSCreateAsyncAccessHandle(fileHandle); | |
| #endif | |
| accessID = wasmfsOPFSAccessHandles.allocate(accessHandle); | |
| } catch (e) { | |
| // TODO: Presumably only one of these will appear in the final API? | |
| if (e.name === "InvalidStateError" || | |
| e.name === "NoModificationAllowedError") { | |
| accessID = -{{{ cDefs.EACCES }}}; | |
| } else { | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| accessID = -{{{ cDefs.EIO }}}; | |
| } | |
| } | |
| {{{ makeSetValue('accessIDPtr', 0, 'accessID', 'i32') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_open_blob__deps: ['$wasmfsOPFSFileHandles', | |
| '$wasmfsOPFSBlobs', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_open_blob__async: 'auto', | |
| _wasmfs_opfs_open_blob: async (ctx, fileID, blobIDPtr) => { | |
| let fileHandle = wasmfsOPFSFileHandles.get(fileID); | |
| let blobID; | |
| try { | |
| let blob = await fileHandle.getFile(); | |
| blobID = wasmfsOPFSBlobs.allocate(blob); | |
| } catch (e) { | |
| if (e.name === "NotAllowedError") { | |
| blobID = -{{{ cDefs.EACCES }}}; | |
| } else { | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| blobID = -{{{ cDefs.EIO }}}; | |
| } | |
| } | |
| {{{ makeSetValue('blobIDPtr', 0, 'blobID', 'i32') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_close_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_close_access__async: 'auto', | |
| _wasmfs_opfs_close_access: async (ctx, accessID, errPtr) => { | |
| let accessHandle = wasmfsOPFSAccessHandles.get(accessID); | |
| try { | |
| await accessHandle.close(); | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSAccessHandles.free(accessID); | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_close_blob__deps: ['$wasmfsOPFSBlobs'], | |
| _wasmfs_opfs_close_blob: (blobID) => { | |
| wasmfsOPFSBlobs.free(blobID); | |
| }, | |
| _wasmfs_opfs_read_access__i53abi: true, | |
| _wasmfs_opfs_read_access__deps: ['$wasmfsOPFSAccessHandles'], | |
| _wasmfs_opfs_read_access__async: 'auto', | |
| _wasmfs_opfs_read_access: {{{ asyncIf(!PTHREADS) }}}(accessID, bufPtr, len, pos) => { | |
| let accessHandle = wasmfsOPFSAccessHandles.get(accessID); | |
| let data = HEAPU8.subarray(bufPtr, bufPtr + len); | |
| try { | |
| return {{{ awaitIf(!PTHREADS) }}}accessHandle.read(data, {at: pos}); | |
| } catch (e) { | |
| if (e.name == "TypeError") { | |
| return -{{{ cDefs.EINVAL }}}; | |
| } | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| return -{{{ cDefs.EIO }}}; | |
| } | |
| }, | |
| _wasmfs_opfs_read_blob__i53abi: true, | |
| _wasmfs_opfs_read_blob__deps: ['$wasmfsOPFSBlobs', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_read_blob__async: 'auto', | |
| _wasmfs_opfs_read_blob: async (ctx, blobID, bufPtr, len, pos, nreadPtr) => { | |
| let blob = wasmfsOPFSBlobs.get(blobID); | |
| let slice = blob.slice(pos, pos + len); | |
| let nread = 0; | |
| try { | |
| // TODO: Use ReadableStreamBYOBReader once | |
| // https://bugs.chromium.org/p/chromium/issues/detail?id=1189621 is | |
| // resolved. | |
| let buf = await slice.arrayBuffer(); | |
| let data = new Uint8Array(buf); | |
| HEAPU8.set(data, bufPtr); | |
| nread += data.length; | |
| } catch (e) { | |
| if (e instanceof RangeError) { | |
| nread = -{{{ cDefs.EFAULT }}}; | |
| } else { | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| nread = -{{{ cDefs.EIO }}}; | |
| } | |
| } | |
| {{{ makeSetValue('nreadPtr', 0, 'nread', 'i32') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_write_access__i53abi: true, | |
| _wasmfs_opfs_write_access__deps: ['$wasmfsOPFSAccessHandles'], | |
| _wasmfs_opfs_write_access__async: 'auto', | |
| _wasmfs_opfs_write_access: {{{ asyncIf(!PTHREADS) }}}(accessID, bufPtr, len, pos) => { | |
| let accessHandle = wasmfsOPFSAccessHandles.get(accessID); | |
| let data = HEAPU8.subarray(bufPtr, bufPtr + len); | |
| try { | |
| return {{{ awaitIf(!PTHREADS) }}}accessHandle.write(data, {at: pos}); | |
| } catch (e) { | |
| if (e.name == "TypeError") { | |
| return -{{{ cDefs.EINVAL }}}; | |
| } | |
| #if ASSERTIONS | |
| err('unexpected error:', e, e.stack); | |
| #endif | |
| return -{{{ cDefs.EIO }}}; | |
| } | |
| }, | |
| _wasmfs_opfs_get_size_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_get_size_access__async: 'auto', | |
| _wasmfs_opfs_get_size_access: async (ctx, accessID, sizePtr) => { | |
| let accessHandle = wasmfsOPFSAccessHandles.get(accessID); | |
| let size; | |
| try { | |
| size = await accessHandle.getSize(); | |
| } catch { | |
| size = -{{{ cDefs.EIO }}}; | |
| } | |
| {{{ makeSetValue('sizePtr', 0, 'size', 'i64') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_get_size_blob__i53abi: true, | |
| _wasmfs_opfs_get_size_blob__deps: ['$wasmfsOPFSBlobs'], | |
| _wasmfs_opfs_get_size_blob: (blobID) => { | |
| // This cannot fail. | |
| return wasmfsOPFSBlobs.get(blobID).size; | |
| }, | |
| _wasmfs_opfs_get_size_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_get_size_file__async: 'auto', | |
| _wasmfs_opfs_get_size_file: async (ctx, fileID, sizePtr) => { | |
| let fileHandle = wasmfsOPFSFileHandles.get(fileID); | |
| let size; | |
| try { | |
| size = (await fileHandle.getFile()).size; | |
| } catch { | |
| size = -{{{ cDefs.EIO }}}; | |
| } | |
| {{{ makeSetValue('sizePtr', 0, 'size', 'i64') }}}; | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_set_size_access__i53abi: true, | |
| _wasmfs_opfs_set_size_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_set_size_access__async: 'auto', | |
| _wasmfs_opfs_set_size_access: async (ctx, accessID, size, errPtr) => { | |
| let accessHandle = wasmfsOPFSAccessHandles.get(accessID); | |
| try { | |
| await accessHandle.truncate(size); | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_set_size_file__i53abi: true, | |
| _wasmfs_opfs_set_size_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_set_size_file__async: 'auto', | |
| _wasmfs_opfs_set_size_file: async (ctx, fileID, size, errPtr) => { | |
| let fileHandle = wasmfsOPFSFileHandles.get(fileID); | |
| try { | |
| let writable = await fileHandle.createWritable({keepExistingData: true}); | |
| await writable.truncate(size); | |
| await writable.close(); | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| }, | |
| _wasmfs_opfs_flush_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], | |
| _wasmfs_opfs_flush_access__async: 'auto', | |
| _wasmfs_opfs_flush_access: async (ctx, accessID, errPtr) => { | |
| let accessHandle = wasmfsOPFSAccessHandles.get(accessID); | |
| try { | |
| await accessHandle.flush(); | |
| } catch { | |
| let err = -{{{ cDefs.EIO }}}; | |
| {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; | |
| } | |
| wasmfsOPFSProxyFinish(ctx); | |
| } | |
| }); | |
Xet Storage Details
- Size:
- 17.2 kB
- Xet hash:
- 6dce5d0822e3ec48081251eea41261b7bd9e5e0fb6e39a89051bc93d3eb5004d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.