+ path = path.substring(1);
+ int p;
+ for(p=0;p<mps.length;p++) if(mps[p].path.equals(path)) break;
+ if(p == mps.length) throw new IllegalArgumentException("mount point doesn't exist");
+ removeMount(p);
+ }
+ }
+
+ private void removeMount(int index) {
+ if(index == -1) { root.owner = null; root = null; return; }
+ MP[] newMPS = new MP[mps.length - 1];
+ System.arraycopy(mps,0,newMPS,0,index);
+ System.arraycopy(mps,0,newMPS,index,mps.length-index-1);
+ mps = newMPS;
+ }
+
+ private Object fsop(int op, UnixRuntime r, String normalizedPath, int arg1, int arg2) throws ErrnoException {
+ int pl = normalizedPath.length();
+ if(pl != 0) {
+ MP[] list;
+ synchronized(this) { list = mps; }
+ for(int i=0;i<list.length;i++) {
+ MP mp = list[i];
+ int mpl = mp.path.length();
+ if(normalizedPath.startsWith(mp.path) && (pl == mpl || (pl < mpl && normalizedPath.charAt(mpl) == '/')))
+ return dispatch(mp.fs,op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2);
+ }
+ }
+ return dispatch(root,op,r,normalizedPath,arg1,arg2);
+ }
+
+ private static Object dispatch(FS fs, int op, UnixRuntime r, String path, int arg1, int arg2) throws ErrnoException {
+ switch(op) {
+ case OPEN: return fs.open(r,path,arg1,arg2);
+ case STAT: return fs.stat(r,path);
+ case LSTAT: return fs.lstat(r,path);
+ case MKDIR: fs.mkdir(r,path,arg1); return null;
+ case UNLINK: fs.unlink(r,path); return null;
+ default: throw new Error("should never happen");
+ }
+ }
+
+ public final FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { return (FD) fsop(OPEN,r,path,flags,mode); }
+ public final FStat stat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(STAT,r,path,0,0); }
+ public final FStat lstat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(LSTAT,r,path,0,0); }
+ public final void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { fsop(MKDIR,r,path,mode,0); }
+ public final void unlink(UnixRuntime r, String path) throws ErrnoException { fsop(UNLINK,r,path,0,0); }
+
+ private Hashtable execCache = new Hashtable();
+ private static class CacheEnt {
+ public final long time;
+ public final long size;
+ public final Object o;
+ public CacheEnt(long time, long size, Object o) { this.time = time; this.size = size; this.o = o; }
+ }
+
+ public synchronized Object exec(UnixRuntime r, String path) throws ErrnoException {
+ // FIXME: Hideous hack to make a standalone busybox possible
+ if(path.equals("bin/busybox") && Boolean.valueOf(getSystemProperty("nestedvm.busyboxhack")).booleanValue())
+ return r.getClass();
+ FStat fstat = stat(r,path);
+ if(fstat == null) return null;
+ long mtime = fstat.mtime();
+ long size = fstat.size();
+ CacheEnt ent = (CacheEnt) execCache.get(path);
+ if(ent != null) {
+ //System.err.println("Found cached entry for " + path);
+ if(ent.time == mtime && ent.size == size) return ent.o;
+ //System.err.println("Cache was out of date");
+ execCache.remove(path);