Created
September 7, 2018 13:35
-
-
Save karupanerura/28566bea0feffaa2f73657d6c3ddfb14 to your computer and use it in GitHub Desktop.
My golang webasm filesystem extension plactice
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // override filesystem | |
| global.fs = (() => { | |
| class Locks { | |
| constructor() { | |
| this.rw = null; | |
| this.ro = []; | |
| } | |
| getLock() { | |
| if (this.rw !== null) { | |
| return null; | |
| } else if (this.ro.length !== 0) { | |
| return null; | |
| } | |
| const lock = Symbol('rw-lock'); | |
| this.rw = lock; | |
| return lock; | |
| } | |
| releaseLock(lock) { | |
| if (this.rw !== null) { | |
| throw 'Assertion failure: the rw lock is already released'; | |
| } else if (this.rw !== lock) { | |
| throw 'Assertion failure: the rw lock is by another lock context'; | |
| } | |
| this.rw = null; | |
| } | |
| getReadOnlyLock() { | |
| if (this.rw !== null) { | |
| return null; | |
| } | |
| const lock = Symbol('ro-lock'); | |
| this.ro.push(lock); | |
| return lock; | |
| } | |
| releaseReadOnlyLock(lock) { | |
| const i = this.ro.indexOf(lock); | |
| if (i === -1) { | |
| throw 'Assertion failure: the ro lock is already released'; | |
| } | |
| this.ro.splice(i, 1); | |
| } | |
| } | |
| const inode = []; | |
| const root = {}; | |
| let currentDir = '/'; | |
| let lastInodeId = 0; | |
| const normalizePath = path => { | |
| return path.replace(/\/{2,}/g, '/').replace(/(\/|^)\.(?=\/)/g, '').replace(/[^\/]+\/\.\.\/?/g, '').replace(/\/$/, ''); | |
| }; | |
| const find = (rawPath, options) => { | |
| options = (options || {}); | |
| const isRoot = rawPath.indexOf('/') === 0; | |
| if (!isRoot) { | |
| rawPath = currentDir + '/' + rawPath; | |
| } | |
| const path = normalizePath(rawPath); | |
| let current = root; | |
| const parts = path.split('/').slice(1); | |
| for (const [i, part] of parts.entries()) { | |
| if (part in current) { | |
| current = current[part]; | |
| } else if (options.createIfNotFound && i === parts.length-1) { | |
| const inodeId = lastInodeId++; | |
| current[part] = inodeId; | |
| const locks = new Locks(); | |
| const obj = { | |
| locks: locks, | |
| blob: null, | |
| }; | |
| inode[inodeId] = obj; | |
| return { | |
| type: 'f', | |
| ptr: obj, | |
| }; | |
| } else { | |
| throw "No such file or directory: "+path; | |
| } | |
| } | |
| if (typeof current === "object") { | |
| return { | |
| type: 'd', | |
| ptr: current, | |
| }; | |
| } | |
| const obj = inode[current]; | |
| return { | |
| type: 'f', | |
| ptr: obj, | |
| }; | |
| }; | |
| let lastOpenFd = 3; | |
| const openedFd = { | |
| 0: { | |
| file: null, | |
| lock: null, | |
| builder: { | |
| buf: [], | |
| append(b) { | |
| this.buf.push(b); | |
| }, | |
| }, | |
| }, | |
| 1: { | |
| file: null, | |
| lock: null, | |
| builder: { | |
| buf: [], | |
| append(b) { | |
| const decoder = new TextDecoder("utf-8"); | |
| this.buf.push(decoder.decode(b)); | |
| }, | |
| }, | |
| }, | |
| 2: { | |
| file: null, | |
| lock: null, | |
| builder: { | |
| buf: [], | |
| append(b) { | |
| const decoder = new TextDecoder("utf-8"); | |
| this.buf.push(decoder.decode(b)); | |
| console.log("stderr:" + this.buf.join('')); | |
| }, | |
| }, | |
| }, | |
| }; | |
| const openFile = obj => { | |
| if (obj.type !== 'f') { | |
| throw "Unsupported type: "+obj.type; | |
| } | |
| const f = obj.ptr; | |
| const lock = f.locks.getReadOnlyLock(); | |
| const fd = lastOpenFd++; | |
| openedFd[fd] = { | |
| file: f, | |
| lock: lock, | |
| builder: null, | |
| }; | |
| return fd; | |
| }; | |
| return { | |
| constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused | |
| readFileBlobSync(path, options) { | |
| const obj = find(path); | |
| if (obj.type !== 'f') { | |
| throw "Unsupported type: "+obj.type; | |
| } | |
| return obj.ptr.blob; | |
| }, | |
| readFile(path, options, callback) { | |
| throw 'not yet iplemented'; | |
| }, | |
| writeSync(fd, buf) { | |
| const fp = openedFd[fd]; | |
| if (fp.builder === null) { | |
| fp.builder = { | |
| buf: [], | |
| append(b) { | |
| this.buf.push(b); | |
| }, | |
| }; | |
| } | |
| fp.builder.append(buf); | |
| return buf.length; | |
| }, | |
| fstatSync() { | |
| return { | |
| isDirectory() { | |
| return false; | |
| } | |
| }; | |
| }, | |
| openSync(path, flags, mode) { | |
| const obj = find(path, { createIfNotFound: true }); | |
| if (obj.type !== 'f') { | |
| throw "Unsupported type: "+obj.type; | |
| } | |
| const fd = openFile(obj); | |
| return fd; | |
| }, | |
| closeSync(fd) { | |
| const fp = openedFd[fd]; | |
| if (fp.builder !== null) { | |
| fp.file.blob = fp.builder.buf; | |
| } | |
| if (fp.lock !== null) { | |
| fp.file.locks.releaseReadOnlyLock(fp.lock); | |
| } | |
| delete openedFd[fd]; | |
| }, | |
| }; | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment