+ public abstract static class FS {
+ static final int OPEN = 1;
+ static final int STAT = 2;
+ static final int LSTAT = 3;
+ static final int MKDIR = 4;
+ static final int UNLINK = 5;
+
+ GlobalState owner;
+ int devno;
+
+ Object dispatch(int op, UnixRuntime r, String path, int arg1, int arg2) throws ErrnoException {
+ switch(op) {
+ case OPEN: return open(r,path,arg1,arg2);
+ case STAT: return stat(r,path);
+ case LSTAT: return lstat(r,path);
+ case MKDIR: mkdir(r,path,arg1); return null;
+ case UNLINK: unlink(r,path); return null;
+ default: throw new Error("should never happen");
+ }
+ }
+
+ public FStat lstat(UnixRuntime r, String path) throws ErrnoException { return stat(r,path); }
+
+ // If this returns null it'll be truned into an ENOENT
+ public abstract FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException;
+ // If this returns null it'll be turned into an ENOENT
+ public abstract FStat stat(UnixRuntime r, String path) throws ErrnoException;
+ public abstract void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException;
+ public abstract void unlink(UnixRuntime r, String path) throws ErrnoException;
+ }
+
+ // chroot support should go in here if it is ever implemented
+ private String normalizePath(String path) {
+ boolean absolute = path.startsWith("/");
+ int cwdl = cwd.length();
+
+ // NOTE: This isn't just a fast path, it handles cases the code below doesn't
+ if(!path.startsWith(".") && path.indexOf("./") == -1 && path.indexOf("//") == -1 && !path.endsWith("."))
+ return absolute ? path.substring(1) : cwdl == 0 ? path : path.length() == 0 ? cwd : cwd + "/" + path;
+
+ char[] in = new char[path.length()+1];
+ char[] out = new char[in.length + (absolute ? -1 : cwd.length())];
+ path.getChars(0,path.length(),in,0);
+ int inp=0, outp=0;
+
+ if(absolute) {
+ do { inp++; } while(in[inp] == '/');
+ } else if(cwdl != 0) {
+ cwd.getChars(0,cwdl,out,0);
+ outp = cwdl;
+ }
+
+ while(in[inp] != 0) {
+ if(inp != 0) {
+ while(in[inp] != 0 && in[inp] != '/') { out[outp++] = in[inp++]; }
+ if(in[inp] == '\0') break;
+ while(in[inp] == '/') inp++;
+ }
+
+ // Just read a /
+ if(in[inp] == '\0') break;
+ if(in[inp] != '.') { out[outp++] = '/'; out[outp++] = in[inp++]; continue; }
+ // Just read a /.
+ if(in[inp+1] == '\0' || in[inp+1] == '/') { inp++; continue; }
+ if(in[inp+1] == '.' && (in[inp+2] == '\0' || in[inp+2] == '/')) { // ..
+ // Just read a /..{$,/}
+ inp += 2;
+ if(outp > 0) outp--;
+ while(outp > 0 && out[outp] != '/') outp--;
+ //System.err.println("After ..: " + new String(out,0,outp));
+ continue;
+ }
+ // Just read a /.[^.] or /..[^/$]
+ inp++;
+ out[outp++] = '/';
+ out[outp++] = '.';
+ }
+ if(outp > 0 && out[outp-1] == '/') outp--;
+ //System.err.println("normalize: " + path + " -> " + new String(out,0,outp) + " (cwd: " + cwd + ")");
+ int outStart = out[0] == '/' ? 1 : 0;
+ return new String(out,outStart,outp - outStart);
+ }
+
+ FStat hostFStat(final File f, Object data) {
+ boolean e = false;
+ try {
+ FileInputStream fis = new FileInputStream(f);
+ switch(fis.read()) {
+ case '\177': e = fis.read() == 'E' && fis.read() == 'L' && fis.read() == 'F'; break;
+ case '#': e = fis.read() == '!';
+ }
+ fis.close();
+ } catch(IOException e2) { }
+ HostFS fs = (HostFS) data;
+ final int inode = fs.inodes.get(f.getAbsolutePath());
+ final int devno = fs.devno;
+ return new HostFStat(f,e) {
+ public int inode() { return inode; }
+ public int dev() { return devno; }
+ };
+ }
+
+ FD hostFSDirFD(File f, Object _fs) {
+ HostFS fs = (HostFS) _fs;
+ return fs.new HostDirFD(f);
+ }
+