blob: 91a005f71ac4ef0b51408cfaf49f97d7d1b92ec5 [file] [log] [blame]
/**
* @license
* Copyright 2016 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/
mergeInto(LibraryManager.library, {
$PROXYFS__deps: ['$FS', '$PATH', '$ERRNO_CODES'],
$PROXYFS: {
mount: function (mount) {
return PROXYFS.createNode(null, '/', mount.opts.fs.lstat(mount.opts.root).mode, 0);
},
createNode: function (parent, name, mode, dev) {
if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
}
var node = FS.createNode(parent, name, mode);
node.node_ops = PROXYFS.node_ops;
node.stream_ops = PROXYFS.stream_ops;
return node;
},
realPath: function (node) {
var parts = [];
while (node.parent !== node) {
parts.push(node.name);
node = node.parent;
}
parts.push(node.mount.opts.root);
parts.reverse();
return PATH.join.apply(null, parts);
},
node_ops: {
getattr: function(node) {
var path = PROXYFS.realPath(node);
var stat;
try {
stat = node.mount.opts.fs.lstat(path);
} catch (e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
return {
dev: stat.dev,
ino: stat.ino,
mode: stat.mode,
nlink: stat.nlink,
uid: stat.uid,
gid: stat.gid,
rdev: stat.rdev,
size: stat.size,
atime: stat.atime,
mtime: stat.mtime,
ctime: stat.ctime,
blksize: stat.blksize,
blocks: stat.blocks
};
},
setattr: function(node, attr) {
var path = PROXYFS.realPath(node);
try {
if (attr.mode !== undefined) {
node.mount.opts.fs.chmod(path, attr.mode);
// update the common node structure mode as well
node.mode = attr.mode;
}
if (attr.timestamp !== undefined) {
var date = new Date(attr.timestamp);
node.mount.opts.fs.utime(path, date, date);
}
if (attr.size !== undefined) {
node.mount.opts.fs.truncate(path, attr.size);
}
} catch (e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
lookup: function (parent, name) {
try {
var path = PATH.join2(PROXYFS.realPath(parent), name);
var mode = parent.mount.opts.fs.lstat(path).mode;
var node = PROXYFS.createNode(parent, name, mode);
return node;
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
mknod: function (parent, name, mode, dev) {
var node = PROXYFS.createNode(parent, name, mode, dev);
// create the backing node for this in the fs root as well
var path = PROXYFS.realPath(node);
try {
if (FS.isDir(node.mode)) {
node.mount.opts.fs.mkdir(path, node.mode);
} else {
node.mount.opts.fs.writeFile(path, '', { mode: node.mode });
}
} catch (e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
return node;
},
rename: function (oldNode, newDir, newName) {
var oldPath = PROXYFS.realPath(oldNode);
var newPath = PATH.join2(PROXYFS.realPath(newDir), newName);
try {
oldNode.mount.opts.fs.rename(oldPath, newPath);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
unlink: function(parent, name) {
var path = PATH.join2(PROXYFS.realPath(parent), name);
try {
parent.mount.opts.fs.unlink(path);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
rmdir: function(parent, name) {
var path = PATH.join2(PROXYFS.realPath(parent), name);
try {
parent.mount.opts.fs.rmdir(path);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
readdir: function(node) {
var path = PROXYFS.realPath(node);
try {
return node.mount.opts.fs.readdir(path);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
symlink: function(parent, newName, oldPath) {
var newPath = PATH.join2(PROXYFS.realPath(parent), newName);
try {
parent.mount.opts.fs.symlink(oldPath, newPath);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
readlink: function(node) {
var path = PROXYFS.realPath(node);
try {
return node.mount.opts.fs.readlink(path);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
},
stream_ops: {
open: function (stream) {
var path = PROXYFS.realPath(stream.node);
try {
stream.nfd = stream.node.mount.opts.fs.open(path,stream.flags);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
close: function (stream) {
try {
stream.node.mount.opts.fs.close(stream.nfd);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
read: function (stream, buffer, offset, length, position) {
try {
return stream.node.mount.opts.fs.read(stream.nfd, buffer, offset, length, position);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
write: function (stream, buffer, offset, length, position) {
try {
return stream.node.mount.opts.fs.write(stream.nfd, buffer, offset, length, position);
} catch(e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
},
llseek: function (stream, offset, whence) {
var position = offset;
if (whence === {{{ cDefine('SEEK_CUR') }}}) {
position += stream.position;
} else if (whence === {{{ cDefine('SEEK_END') }}}) {
if (FS.isFile(stream.node.mode)) {
try {
var stat = stream.node.mount.opts.fs.fstat(stream.nfd);
position += stat.size;
} catch (e) {
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
}
}
if (position < 0) {
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
}
return position;
}
}
}
});