aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc96
-rwxr-xr-xemscripten.py26
-rw-r--r--src/headlessCanvas.js1
-rw-r--r--src/jsifier.js46
-rw-r--r--src/library.js3
-rw-r--r--src/library_fs.js181
-rw-r--r--src/library_html5.js19
-rw-r--r--src/library_idbfs.js324
-rw-r--r--src/library_sdl.js27
-rw-r--r--src/settings.js14
-rw-r--r--src/struct_info.json4
-rw-r--r--system/include/X11/XKBlib.h1149
-rw-r--r--system/include/X11/Xfuncs.h69
-rw-r--r--system/include/X11/XlibConf.h38
-rw-r--r--system/include/X11/Xlibint.h1387
-rw-r--r--system/include/X11/Xmd.h185
-rw-r--r--system/include/X11/Xproto.h2157
-rw-r--r--system/include/X11/Xprotostr.h77
-rw-r--r--system/include/X11/cursorfont.h111
-rw-r--r--system/include/X11/extensions/XKB.h786
-rw-r--r--system/include/X11/extensions/XKBstr.h613
-rw-r--r--system/include/X11/extensions/XShm.h135
-rw-r--r--system/include/X11/extensions/Xext.h53
-rw-r--r--system/include/X11/extensions/extutil.h190
-rw-r--r--system/include/X11/extensions/shm.h44
-rw-r--r--system/include/emscripten/emscripten.h8
-rw-r--r--tests/cases/bigdouble.ll17
-rw-r--r--tests/cases/bigdouble.txt1
-rw-r--r--tests/cases/fuzz6_ta2.ll (renamed from tests/cases/fuzz6.ll)0
-rw-r--r--tests/cases/fuzz6_ta2.txt (renamed from tests/cases/fuzz6.txt)0
-rw-r--r--tests/codemods.cpp21
-rw-r--r--tests/core/test_memcpy3.c51
-rw-r--r--tests/core/test_memcpy3.out81
-rw-r--r--tests/core/test_sscanf.in1
-rw-r--r--tests/core/test_sscanf_6.in14
-rw-r--r--tests/core/test_sscanf_6.out1
-rw-r--r--tests/fs/test_mount.c60
-rw-r--r--tests/test_browser.py33
-rw-r--r--tests/test_core.py99
-rw-r--r--tests/test_minmax.c89
-rw-r--r--tests/test_other.py24
-rw-r--r--tools/js-optimizer.js18
-rw-r--r--tools/parse_unaligned.py17
-rw-r--r--tools/shared.py2
-rw-r--r--tools/test-js-optimizer-asm-last-output.js2
-rw-r--r--tools/test-js-optimizer-asm-pre-f32.js11
-rw-r--r--tools/test-js-optimizer-asm-pre-output-f32.js11
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js19
-rw-r--r--tools/test-js-optimizer-asm-pre.js22
50 files changed, 8037 insertions, 301 deletions
diff --git a/AUTHORS b/AUTHORS
index 2c292dde..fc947687 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -120,3 +120,4 @@ a license to everyone to use it as detailed in LICENSE.)
* Jari Vetoniemi <mailroxas@gmail.com>
* Sindre Sorhus <sindresorhus@gmail.com>
* James S Urquhart <jamesu@gmail.com>
+* Boris Gjenero <boris.gjenero@gmail.com>
diff --git a/emcc b/emcc
index 83ce4529..6bf74707 100755
--- a/emcc
+++ b/emcc
@@ -1206,8 +1206,10 @@ try:
jcache = False
fastcomp_opts = ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt']
- if not shared.Settings.DISABLE_EXCEPTION_CATCHING:
+ if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1:
fastcomp_opts += ['-enable-emscripten-cxx-exceptions']
+ if len(shared.Settings.EXCEPTION_CATCHING_WHITELIST) > 0:
+ fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST)]
if shared.Settings.ASM_JS:
assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above'
@@ -1960,27 +1962,36 @@ try:
# It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing
js_optimizer_queue = []
js_optimizer_extra_info = {}
+ js_optimizer_queue_history = []
def flush_js_optimizer_queue():
- global final, js_optimizer_queue, js_optimizer_extra_info
+ global final, js_optimizer_queue, js_optimizer_extra_info, js_optimizer_queue_history
if len(js_optimizer_extra_info) == 0:
js_optimizer_extra_info = None
if len(js_optimizer_queue) > 0 and not(not shared.Settings.ASM_JS and len(js_optimizer_queue) == 1 and js_optimizer_queue[0] == 'last'):
- if DEBUG != '2':
+
+ def add_opt_args(args):
if shared.Settings.ASM_JS:
- js_optimizer_queue = ['asm'] + js_optimizer_queue
+ args = ['asm'] + args
+ if shared.Settings.PRECISE_F32:
+ args = ['asmPreciseF32'] + args
+ return args
+
+ if DEBUG != '2':
+ js_optimizer_queue = add_opt_args(js_optimizer_queue)
logging.debug('applying js optimization passes: %s', js_optimizer_queue)
final = shared.Building.js_optimizer(final, js_optimizer_queue, jcache, debug_level >= 4, js_optimizer_extra_info)
js_transform_tempfiles.append(final)
if DEBUG: save_intermediate('js_opts')
else:
for name in js_optimizer_queue:
- passes = [name]
+ passes = add_opt_args([name])
if shared.Settings.ASM_JS:
passes = ['asm'] + passes
logging.debug('applying js optimization pass: %s', passes)
final = shared.Building.js_optimizer(final, passes, jcache, debug_level >= 4, js_optimizer_extra_info)
js_transform_tempfiles.append(final)
save_intermediate(name)
+ js_optimizer_queue_history += js_optimizer_queue
js_optimizer_queue = []
js_optimizer_extra_info = {}
@@ -2066,15 +2077,78 @@ try:
html.write(shell.replace('{{{ SCRIPT }}}', '<script>' + open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', target_basename) + '</script>'))
shutil.move(final, js_target)
elif not Compression.on:
+ # Normal code generation path
if debug_level >= 4:
generate_source_map(target)
shutil.move(final, js_target)
- # TODO: use an async blob, which would allow code rewriting on the client:
- # var blob = new Blob([codeString]);
- # var script = document.createElement('script');
- # script.src = URL.createObjectURL(blob);
- # document.body.appendChild(script);
- script_tag = '''<script async type="text/javascript" src="%s"></script>''' % base_js_target
+ need_mods = shared.Settings.PRECISE_F32 == 2
+ if not need_mods:
+ # Non-modifiable code, just load the code directly
+ script_tag = '''<script async type="text/javascript" src="%s"></script>''' % base_js_target
+ else:
+ # Potentially-modifiable code, load as text, modify, then execute. This lets you
+ # patch the code on the client machine right before it is executed, perhaps based
+ # on information about the client.
+ checks = []
+ mods = []
+ if shared.Settings.PRECISE_F32 == 2:
+ checks.append('!Math.fround')
+ if 'minifyNames' not in js_optimizer_queue_history:
+ # simple dumb replace
+ mods.append('''
+console.log('optimizing out Math.fround calls');
+code = code.replace(/Math_fround\(/g, '(').replace("'use asm'", "'almost asm'")
+''')
+ else:
+ # minified, not quite so simple - TODO
+ mods.append('''
+try {
+ console.log('optimizing out Math.fround calls');
+ var m = /var ([^=]+)=global\.Math\.fround;/.exec(code);
+ var minified = m[1];
+ if (!minified) throw 'fail';
+ var startAsm = code.indexOf('// EMSCRIPTEN_START_FUNCS');
+ var endAsm = code.indexOf('// EMSCRIPTEN_END_FUNCS');
+ var asm = code.substring(startAsm, endAsm);
+ do {
+ var moar = false; // we need to re-do, as x(x( will not be fixed
+ asm = asm.replace(new RegExp('[^a-zA-Z0-9\\\\$\\\\_]' + minified + '\\\\(', 'g'), function(s) { moar = true; return s[0] + '(' });
+ } while (moar);
+ code = code.substring(0, startAsm) + asm + code.substring(endAsm);
+ code = code.replace("'use asm'", "'almost asm'");
+} catch(e) { console.log('failed to optimize out Math.fround calls ' + e) }
+''')
+
+ fixes = ''
+ for i in range(len(checks)):
+ fixes += 'if (' + checks[i] + ') { ' + mods[i] + ' }\n'
+
+ # if all the checks are negative, just emit a script tag normally, that's better.
+ # otherwise, do an xhr to get the code as text, modify, and load asynchronously
+ code = 'if (!(' + ' || '.join(checks) + ''')) {
+ var script = document.createElement('script');
+ script.src = "''' + base_js_target + '''";
+ document.body.appendChild(script);
+} else {
+ var codeXHR = new XMLHttpRequest();
+ codeXHR.open('GET', '%s', true);
+ codeXHR.onload = function() {
+ var code = codeXHR.responseText;
+ %s
+ var blob = new Blob([code], { type: 'text/javascript' });
+ codeXHR = null;
+ var src = URL.createObjectURL(blob);
+ var script = document.createElement('script');
+ script.src = URL.createObjectURL(blob);
+ script.onload = function() {
+ URL.revokeObjectURL(script.src);
+ };
+ document.body.appendChild(script);
+ };
+ codeXHR.send(null);
+}
+''' % (base_js_target, fixes)
+ script_tag = '''<script>%s</script>''' % code
html.write(shell.replace('{{{ SCRIPT }}}', script_tag))
else:
# Compress the main code
diff --git a/emscripten.py b/emscripten.py
index 77082aee..c96c56a0 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -737,14 +737,17 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
# * Run compiler.js on the metadata to emit the shell js code, pre/post-ambles,
# JS library dependencies, etc.
- if DEBUG:
- logging.debug('emscript: llvm backend')
- t = time.time()
-
temp_js = temp_files.get('.4.js').name
backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc')
- shared.jsrun.timeout_run(subprocess.Popen([backend_compiler, infile, '-march=js', '-filetype=asm', '-o', temp_js], stdout=subprocess.PIPE))
-
+ backend_args = [backend_compiler, infile, '-march=js', '-filetype=asm', '-o', temp_js]
+ if settings['PRECISE_F32']:
+ backend_args += ['-emscripten-precise-f32']
+ if settings['WARN_UNALIGNED']:
+ backend_args += ['-emscripten-warn-unaligned']
+ if DEBUG:
+ logging.debug('emscript: llvm backend: ' + ' '.join(backend_args))
+ t = time.time()
+ shared.jsrun.timeout_run(subprocess.Popen(backend_args, stdout=subprocess.PIPE))
if DEBUG:
logging.debug(' emscript: llvm backend took %s seconds' % (time.time() - t))
t = time.time()
@@ -862,15 +865,13 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
pre = parts[0]
funcs_js.append(parts[1])
- # calculations on merged forwarded data TODO
-
# merge forwarded data
assert settings.get('ASM_JS'), 'fastcomp is asm.js only'
settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS']
all_exported_functions = set(settings['EXPORTED_FUNCTIONS']) # both asm.js and otherwise
for additional_export in settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE']: # additional functions to export from asm, if they are implemented
all_exported_functions.add('_' + additional_export)
- exported_implemented_functions = set()
+ exported_implemented_functions = set(metadata['exports'])
export_bindings = settings['EXPORT_BINDINGS']
export_all = settings['EXPORT_ALL']
for key in metadata['implementedFunctions'] + forwarded_json['Functions']['implementedFunctions'].keys(): # XXX perf
@@ -908,12 +909,15 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
else:
pre_tables = ''
+ def unfloat(s):
+ return 'd' if s == 'f' else s # lower float to double for ffis
+
def make_table(sig, raw):
i = Counter.i
Counter.i += 1
bad = 'b' + str(i)
params = ','.join(['p%d' % p for p in range(len(sig)-1)])
- coerced_params = ','.join([shared.JS.make_coercion('p%d', sig[p+1], settings) % p for p in range(len(sig)-1)])
+ coerced_params = ','.join([shared.JS.make_coercion('p%d', unfloat(sig[p+1]), settings) % p for p in range(len(sig)-1)])
coercions = ';'.join(['p%d = %s' % (p, shared.JS.make_coercion('p%d' % p, sig[p+1], settings)) for p in range(len(sig)-1)]) + ';'
def make_func(name, code):
return 'function %s(%s) { %s %s }' % (name, params, coercions, code)
@@ -937,6 +941,8 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
if not call_ident.startswith('_') and not call_ident.startswith('Math_'): call_ident = '_' + call_ident
code = call_ident + '(' + coerced_params + ')'
if sig[0] != 'v':
+ # ffis cannot return float
+ if sig[0] == 'f': code = '+' + code
code = 'return ' + shared.JS.make_coercion(code, sig[0], settings)
code += ';'
Counter.pre.append(make_func(item + '__wrapper', code))
diff --git a/src/headlessCanvas.js b/src/headlessCanvas.js
index 6b0f9d47..4bd17a7b 100644
--- a/src/headlessCanvas.js
+++ b/src/headlessCanvas.js
@@ -446,6 +446,7 @@ function headlessCanvas() {
case /* GL_MAX_FRAGMENT_UNIFORM_VECTORS */ 0x8DFD: return 4096;
case /* GL_MAX_VARYING_VECTORS */ 0x8DFC: return 32;
case /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS */ 0x8B4D: return 32;
+ case /* GL_ARRAY_BUFFER_BINDING */ 0x8894: return 0;
default: console.log('getParameter ' + pname + '?'); return 0;
}
},
diff --git a/src/jsifier.js b/src/jsifier.js
index ab5440f7..ab10f455 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -224,6 +224,7 @@ function JSify(data, functionsOnly) {
// globalVariable
function globalVariableHandler(item) {
+
function needsPostSet(value) {
if (typeof value !== 'string') return false;
// (' is ok, as it is something we can indexize later into a concrete int: ('{{ FI_ ...
@@ -274,7 +275,9 @@ function JSify(data, functionsOnly) {
constant = Runtime.alignMemory(calcAllocatedSize(item.type));
} else {
if (item.external) {
- if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
+ if (LibraryManager.library[item.ident.slice(1)]) {
+ constant = LibraryManager.library[item.ident.slice(1)];
+ } else if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
constant = zeros(Runtime.getNativeFieldSize(item.type));
} else {
constant = makeEmptyStruct(item.type);
@@ -282,22 +285,23 @@ function JSify(data, functionsOnly) {
} else {
constant = parseConst(item.value, item.type, item.ident);
}
- assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
// This is a flattened object. We need to find its idents, so they can be assigned to later
- var structTypes = null;
- constant.forEach(function(value, i) {
- if (needsPostSet(value)) { // ident, or expression containing an ident
- if (!structTypes) structTypes = generateStructTypes(item.type);
- itemsDict.GlobalVariablePostSet.push({
- intertype: 'GlobalVariablePostSet',
- JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
- });
- constant[i] = '0';
- } else {
- if (typeof value === 'string') constant[i] = deParenCarefully(value);
- }
- });
+ if (typeof constant === 'object') {
+ var structTypes = null;
+ constant.forEach(function(value, i) {
+ if (needsPostSet(value)) { // ident, or expression containing an ident
+ if (!structTypes) structTypes = generateStructTypes(item.type);
+ itemsDict.GlobalVariablePostSet.push({
+ intertype: 'GlobalVariablePostSet',
+ JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
+ });
+ constant[i] = '0';
+ } else {
+ if (typeof value === 'string') constant[i] = deParenCarefully(value);
+ }
+ });
+ }
if (item.external) {
// External variables in shared libraries should not be declared as
@@ -312,14 +316,18 @@ function JSify(data, functionsOnly) {
}
// ensure alignment
- var extra = Runtime.alignMemory(constant.length) - constant.length;
- if (item.ident.substr(0, 5) == '__ZTV') extra += Runtime.alignMemory(QUANTUM_SIZE);
- while (extra-- > 0) constant.push(0);
+ if (typeof constant === 'object') {
+ var extra = Runtime.alignMemory(constant.length) - constant.length;
+ if (item.ident.substr(0, 5) == '__ZTV') extra += Runtime.alignMemory(QUANTUM_SIZE);
+ while (extra-- > 0) constant.push(0);
+ }
}
// NOTE: This is the only place that could potentially create static
// allocations in a shared library.
- constant = makePointer(constant, null, allocator, item.type, index);
+ if (typeof constant === 'object') {
+ constant = makePointer(constant, null, allocator, item.type, index);
+ }
var js = (index !== null ? '' : item.ident + '=') + constant;
if (js) js += ';';
diff --git a/src/library.js b/src/library.js
index 30453137..26ce8457 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1641,6 +1641,7 @@ LibraryManager.library = {
for (var i = 0; i < maxx; i++) {
next = get();
{{{ makeSetValue('argPtr++', 0, 'next', 'i8') }}};
+ if (next === 0) return i > 0 ? fields : fields-1; // we failed to read the full length of this field
}
formatIndex += nextC - formatIndex + 1;
continue;
@@ -3457,7 +3458,7 @@ LibraryManager.library = {
rand_r: function(seedp) {
seedp = seedp|0;
var val = 0;
- val = (Math_imul({{{ makeGetValueAsm('seedp', 0, 'i32') }}}, 31010991)|0) + 0x676e6177 | 0;
+ val = ((Math_imul({{{ makeGetValueAsm('seedp', 0, 'i32') }}}, 31010991)|0) + 0x676e6177 ) & {{{ cDefine('RAND_MAX') }}}; // assumes RAND_MAX is in bit mask form (power of 2 minus 1)
{{{ makeSetValueAsm('seedp', 0, 'val', 'i32') }}};
return val|0;
},
diff --git a/src/library_fs.js b/src/library_fs.js
index e6b060f6..c30876f5 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -40,7 +40,17 @@ mergeInto(LibraryManager.library, {
//
lookupPath: function(path, opts) {
path = PATH.resolve(FS.cwd(), path);
- opts = opts || { recurse_count: 0 };
+ opts = opts || {};
+
+ var defaults = {
+ follow_mount: true,
+ recurse_count: 0
+ };
+ for (var key in defaults) {
+ if (opts[key] === undefined) {
+ opts[key] = defaults[key];
+ }
+ }
if (opts.recurse_count > 8) { // max recursive lookup of 8
throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
@@ -67,10 +77,11 @@ mergeInto(LibraryManager.library, {
// jump to the mount's root node if this is a mountpoint
if (FS.isMountpoint(current)) {
- current = current.mount.root;
+ if (!islast || (islast && opts.follow_mount)) {
+ current = current.mounted.root;
+ }
}
- // follow symlinks
// by default, lookupPath will not follow a symlink if it is the final path component.
// setting opts.follow = true will override this behavior.
if (!islast || opts.follow) {
@@ -163,28 +174,26 @@ mergeInto(LibraryManager.library, {
createNode: function(parent, name, mode, rdev) {
if (!FS.FSNode) {
FS.FSNode = function(parent, name, mode, rdev) {
+ if (!parent) {
+ parent = this; // root node sets parent to itself
+ }
+ this.parent = parent;
+ this.mount = parent.mount;
+ this.mounted = null;
this.id = FS.nextInode++;
this.name = name;
this.mode = mode;
this.node_ops = {};
this.stream_ops = {};
this.rdev = rdev;
- this.parent = null;
- this.mount = null;
- if (!parent) {
- parent = this; // root node sets parent to itself
- }
- this.parent = parent;
- this.mount = parent.mount;
- FS.hashAddNode(this);
};
+ FS.FSNode.prototype = {};
+
// compatibility
var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
var writeMode = {{{ cDefine('S_IWUGO') }}};
- FS.FSNode.prototype = {};
-
// NOTE we must use Object.defineProperties instead of individual calls to
// Object.defineProperty in order to make closure compiler happy
Object.defineProperties(FS.FSNode.prototype, {
@@ -204,7 +213,12 @@ mergeInto(LibraryManager.library, {
},
});
}
- return new FS.FSNode(parent, name, mode, rdev);
+
+ var node = new FS.FSNode(parent, name, mode, rdev);
+
+ FS.hashAddNode(node);
+
+ return node;
},
destroyNode: function(node) {
FS.hashRemoveNode(node);
@@ -213,7 +227,7 @@ mergeInto(LibraryManager.library, {
return node === node.parent;
},
isMountpoint: function(node) {
- return node.mounted;
+ return !!node.mounted;
},
isFile: function(mode) {
return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFREG') }}};
@@ -441,61 +455,131 @@ mergeInto(LibraryManager.library, {
//
// core
//
+ getMounts: function(mount) {
+ var mounts = [];
+ var check = [mount];
+
+ while (check.length) {
+ var m = check.pop();
+
+ mounts.push(m);
+
+ check.push.apply(check, m.mounts);
+ }
+
+ return mounts;
+ },
syncfs: function(populate, callback) {
if (typeof(populate) === 'function') {
callback = populate;
populate = false;
}
+ var mounts = FS.getMounts(FS.root.mount);
var completed = 0;
- var total = FS.mounts.length;
+
function done(err) {
if (err) {
- return callback(err);
+ if (!done.errored) {
+ done.errored = true;
+ return callback(err);
+ }
+ return;
}
- if (++completed >= total) {
+ if (++completed >= mounts.length) {
callback(null);
}
};
// sync all mounts
- for (var i = 0; i < FS.mounts.length; i++) {
- var mount = FS.mounts[i];
+ mounts.forEach(function (mount) {
if (!mount.type.syncfs) {
- done(null);
- continue;
+ return done(null);
}
mount.type.syncfs(mount, populate, done);
- }
+ });
},
mount: function(type, opts, mountpoint) {
- var lookup;
- if (mountpoint) {
- lookup = FS.lookupPath(mountpoint, { follow: false });
+ var root = mountpoint === '/';
+ var pseudo = !mountpoint;
+ var node;
+
+ if (root && FS.root) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ } else if (!root && !pseudo) {
+ var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
mountpoint = lookup.path; // use the absolute path
+ node = lookup.node;
+
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+
+ if (!FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+ }
}
+
var mount = {
type: type,
opts: opts,
mountpoint: mountpoint,
- root: null
+ mounts: []
};
+
// create a root node for the fs
- var root = type.mount(mount);
- root.mount = mount;
- mount.root = root;
- // assign the mount info to the mountpoint's node
- if (lookup) {
- lookup.node.mount = mount;
- lookup.node.mounted = true;
- // compatibility update FS.root if we mount to /
- if (mountpoint === '/') {
- FS.root = mount.root;
+ var mountRoot = type.mount(mount);
+ mountRoot.mount = mount;
+ mount.root = mountRoot;
+
+ if (root) {
+ FS.root = mountRoot;
+ } else if (node) {
+ // set as a mountpoint
+ node.mounted = mount;
+
+ // add the new mount to the current mount's children
+ if (node.mount) {
+ node.mount.mounts.push(mount);
}
}
- // add to our cached list of mounts
- FS.mounts.push(mount);
- return root;
+
+ return mountRoot;
+ },
+ unmount: function (mountpoint) {
+ var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+ if (!FS.isMountpoint(lookup.node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+
+ // destroy the nodes for this mount, and all its child mounts
+ var node = lookup.node;
+ var mount = node.mounted;
+ var m