Skip to content

Instantly share code, notes, and snippets.

@karupanerura
Created September 7, 2018 13:35
Show Gist options
  • Select an option

  • Save karupanerura/28566bea0feffaa2f73657d6c3ddfb14 to your computer and use it in GitHub Desktop.

Select an option

Save karupanerura/28566bea0feffaa2f73657d6c3ddfb14 to your computer and use it in GitHub Desktop.
My golang webasm filesystem extension plactice
// 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