X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=0bc102809b0cb88ac0dda49f5854a35444cb5008;hp=ec2b58bfb183e8447fa5f8ce54134109f3b727f7;hb=404ead23c2104bbed240370653a5308849b98905;hpb=095d6d46361db8b4b69790305c0310ea114d3813 diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index ec2b58b..0bc1028 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -1,11 +1,16 @@ +// Copyright 2000-2005 the Contributors, as shown in the revision logs. +// Licensed under the Apache Public Source License 2.0 ("the License"). +// You may not use this file except in compliance with the License. + package org.ibex.nestedvm; import org.ibex.nestedvm.util.*; -// FEATURE: This is ugly, this stuff needs to be in org.ibex.util or something +// HACK: This is ugly, this stuff needs to be in org.ibex.util or something import org.ibex.classgen.util.Sort; import java.io.*; import java.util.*; import java.net.*; +import java.lang.reflect.*; // For lazily linked RuntimeCompiler // FEATURE: vfork @@ -16,9 +21,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public final int getPid() { return pid; } private static final GlobalState defaultGS = new GlobalState(); - private GlobalState gs = defaultGS; + private GlobalState gs; public void setGlobalState(GlobalState gs) { if(state != STOPPED) throw new IllegalStateException("can't change GlobalState when running"); + if(gs == null) throw new NullPointerException("gs is null"); this.gs = gs; } @@ -33,14 +39,17 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private Vector activeChildren; private Vector exitedChildren; - protected UnixRuntime(int pageSize, int totalPages) { - super(pageSize,totalPages); + protected UnixRuntime(int pageSize, int totalPages) { this(pageSize,totalPages,false); } + protected UnixRuntime(int pageSize, int totalPages, boolean exec) { + super(pageSize,totalPages,exec); - // FEATURE: Do the proper mangling for non-unix hosts - String userdir = Platform.getProperty("user.dir"); - cwd = - userdir != null && userdir.startsWith("/") && File.separatorChar == '/' && Platform.getProperty("nestedvm.root") == null - ? userdir.substring(1) : ""; + if(!exec) { + gs = defaultGS; + String userdir = Platform.getProperty("user.dir"); + cwd = (userdir == null || Platform.getProperty("nestedvm.root") != null) ? null : HostFS.reverseMap(userdir); + if(cwd == null) cwd = "/"; + cwd = cwd.substring(1); + } } private static String posixTZ() { @@ -65,15 +74,18 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } String[] createEnv(String[] extra) { - String[] defaults = new String[6]; + String[] defaults = new String[7]; int n=0; if(extra == null) extra = new String[0]; + String tmp; if(!envHas("USER",extra) && Platform.getProperty("user.name") != null) defaults[n++] = "USER=" + Platform.getProperty("user.name"); - if(!envHas("HOME",extra) && Platform.getProperty("user.home") != null) - defaults[n++] = "HOME=" + Platform.getProperty("user.home"); + if(!envHas("HOME",extra) && (tmp=Platform.getProperty("user.home")) != null && (tmp=HostFS.reverseMap(tmp)) != null) + defaults[n++] = "HOME=" + tmp; + if(!envHas("TMPDIR",extra) && (tmp=Platform.getProperty("java.io.tmpdir")) != null && (tmp=HostFS.reverseMap(tmp)) != null) + defaults[n++] = "TMPDIR=" + tmp; if(!envHas("SHELL",extra)) defaults[n++] = "SHELL=/bin/sh"; - if(!envHas("TERM",extra)) defaults[n++] = "TERM=vt100"; + if(!envHas("TERM",extra) && !win32Hacks) defaults[n++] = "TERM=vt100"; if(!envHas("TZ",extra)) defaults[n++] = "TZ=" + posixTZ(); if(!envHas("PATH",extra)) defaults[n++] = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"; String[] env = new String[extra.length+n]; @@ -136,7 +148,18 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case SYS_accept: return sys_accept(a,b,c); case SYS_shutdown: return sys_shutdown(a,b); case SYS_sysctl: return sys_sysctl(a,b,c,d,e,f); - + case SYS_sendto: return sys_sendto(a,b,c,d,e,f); + case SYS_recvfrom: return sys_recvfrom(a,b,c,d,e,f); + case SYS_select: return sys_select(a,b,c,d,e); + case SYS_access: return sys_access(a,b); + case SYS_realpath: return sys_realpath(a,b); + case SYS_chown: return sys_chown(a,b,c); + case SYS_lchown: return sys_chown(a,b,c); + case SYS_fchown: return sys_fchown(a,b,c); + case SYS_chmod: return sys_chmod(a,b,c); + case SYS_fchmod: return sys_fchmod(a,b,c); + case SYS_umask: return sys_umask(a); + default: return super._syscall(syscall,a,b,c,d,e,f); } } @@ -148,7 +171,43 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_getppid() { return parent == null ? 1 : parent.pid; } + + private int sys_chown(int fileAddr, int uid, int gid) { + return 0; + } + private int sys_lchown(int fileAddr, int uid, int gid) { + return 0; + } + private int sys_fchown(int fd, int uid, int gid) { + return 0; + } + private int sys_chmod(int fileAddr, int uid, int gid) { + return 0; + } + private int sys_fchmod(int fd, int uid, int gid) { + return 0; + } + private int sys_umask(int mask) { + return 0; + } + + private int sys_access(int cstring, int mode) throws ErrnoException, ReadFaultException { + // FEATURE: sys_access + return gs.stat(this,cstring(cstring)) == null ? -ENOENT : 0; + } + + private int sys_realpath(int inAddr, int outAddr) throws FaultException { + String s = normalizePath(cstring(inAddr)); + byte[] b = getNullTerminatedBytes(s); + if(b.length > PATH_MAX) return -ERANGE; + copyout(b,outAddr,b.length); + return 0; + } + // FEATURE: Signal handling + // check flag only on backwards jumps to basic blocks without compulsatory checks + // (see A Portable Research Framework for the Execution of Java Bytecode - Etienne Gagnon, Chapter 2) + /** The kill syscall. SIGSTOP, SIGTSTO, SIGTTIN, and SIGTTOUT pause the process. SIGCONT, SIGCHLD, SIGIO, and SIGWINCH are ignored. @@ -164,16 +223,13 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case 18: // SIGTSTP case 21: // SIGTTIN case 22: // SIGTTOU - state = PAUSED; - break; case 19: // SIGCONT case 20: // SIGCHLD case 23: // SIGIO case 28: // SIGWINCH break; default: - // FEATURE: This is ugly, make a clean interface to sys_exit - return syscall(SYS_exit,128+signal,0,0,0,0,0); + exit(128+signal, true); } return 0; } @@ -200,6 +256,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { exitedChildren.removeElementAt(exitedChildren.size() - 1); } } else if(pid > 0) { + if(pid >= gs.tasks.length) return -ECHILD; UnixRuntime t = gs.tasks[pid]; if(t.parent != this) return -ECHILD; if(t.state == EXITED) { @@ -265,9 +322,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } private int sys_fork() { - CPUState state = new CPUState(); - getCPUState(state); - int sp = state.r[SP]; final UnixRuntime r; try { @@ -293,6 +347,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } activeChildren.addElement(r); + CPUState state = new CPUState(); + getCPUState(state); state.r[V0] = 0; // return 0 to child state.pc += 4; // skip over syscall instruction r.setCPUState(state); @@ -334,42 +390,156 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_exec(int cpath, int cargv, int cenvp) throws ErrnoException, FaultException { return exec(normalizePath(cstring(cpath)),readStringArray(cargv),readStringArray(cenvp)); } + + private final static Method runtimeCompilerCompile; + static { + Method m; + try { + m = Class.forName("org.ibex.nestedvm.RuntimeCompiler").getMethod("compile",new Class[]{Seekable.class,String.class,String.class}); + } catch(NoSuchMethodException e) { + m = null; + } catch(ClassNotFoundException e) { + m = null; + } + runtimeCompilerCompile = m; + } + + public Class runtimeCompile(Seekable s, String sourceName) throws IOException { + if(runtimeCompilerCompile == null) { + if(STDERR_DIAG) System.err.println("WARNING: Exec attempted but RuntimeCompiler not found!"); + return null; + } + + try { + return (Class) runtimeCompilerCompile.invoke(null,new Object[]{s,"unixruntime,maxinsnpermethod=256,lessconstants",sourceName}); + } catch(IllegalAccessException e) { + e.printStackTrace(); + return null; + } catch(InvocationTargetException e) { + Throwable t = e.getTargetException(); + if(t instanceof IOException) throw (IOException) t; + if(t instanceof RuntimeException) throw (RuntimeException) t; + if(t instanceof Error) throw (Error) t; + if(STDERR_DIAG) t.printStackTrace(); + return null; + } + } - private int exec(String normalizedPath, String[] argv, String[] envp) throws ErrnoException { + private int exec(String path, String[] argv, String[] envp) throws ErrnoException { if(argv.length == 0) argv = new String[]{""}; - + // HACK: Hideous hack to make a standalone busybox possible + if(path.equals("bin/busybox") && getClass().getName().endsWith("BusyBox")) + return execClass(getClass(),argv,envp); + // NOTE: For this little hack to work nestedvm.root MUST be "." /*try { System.err.println("Execing normalized path: " + normalizedPath); if(true) return exec(new Interpreter(normalizedPath),argv,envp); } catch(IOException e) { throw new Error(e); }*/ - Object o = gs.exec(this,normalizedPath); - if(o == null) return -ENOENT; - - if(o instanceof Class) { - Class c = (Class) o; - try { - return exec((UnixRuntime) c.newInstance(),argv,envp); - } catch(Exception e) { - e.printStackTrace(); - return -ENOEXEC; + FStat fstat = gs.stat(this,path); + if(fstat == null) return -ENOENT; + GlobalState.CacheEnt ent = (GlobalState.CacheEnt) gs.execCache.get(path); + long mtime = fstat.mtime(); + long size = fstat.size(); + if(ent != null) { + //System.err.println("Found cached entry for " + path); + if(ent.time ==mtime && ent.size == size) { + if(ent.o instanceof Class) + return execClass((Class) ent.o,argv,envp); + if(ent.o instanceof String[]) + return execScript(path,(String[]) ent.o,argv,envp); + throw new Error("should never happen"); } - } else { - String[] command = (String[]) o; - String[] newArgv = new String[argv.length + command[1] != null ? 2 : 1]; - int p = command[0].lastIndexOf('/'); - newArgv[0] = p == -1 ? command[0] : command[0].substring(p+1); - p = 1; - if(command[1] != null) newArgv[p++] = command[1]; - newArgv[p++] = "/" + normalizedPath; - for(int i=1;i>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; int port = word1 & 0xffff; @@ -668,22 +858,21 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return -EADDRNOTAVAIL; } + fd.connectAddr = inetAddr; + fd.connectPort = port; + try { switch(fd.type()) { case SocketFD.TYPE_STREAM: { Socket s = new Socket(inetAddr,port); - fd.o = s; + fd.s = s; fd.setOptions(); fd.is = s.getInputStream(); fd.os = s.getOutputStream(); break; } - case SocketFD.TYPE_DGRAM: { - if(fd.dp == null) fd.dp = new DatagramPacket(null,0); - fd.dp.setAddress(inetAddr); - fd.dp.setPort(port); + case SocketFD.TYPE_DGRAM: break; - } default: throw new Error("should never happen"); } @@ -763,7 +952,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_bind(int fdn, int addr, int namelen) throws FaultException, ErrnoException { SocketFD fd = getSocketFD(fdn); - if(fd.type() == SocketFD.TYPE_STREAM && fd.o != null) return -EISCONN; + if(fd.type() == SocketFD.TYPE_STREAM && (fd.s != null || fd.ss != null)) return -EISCONN; int word1 = memRead(addr); if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; int port = word1 & 0xffff; @@ -786,10 +975,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } case SocketFD.TYPE_DGRAM: { - DatagramSocket s = (DatagramSocket) fd.o; - if(s != null) s.close(); + if(fd.ds != null) fd.ds.close(); try { - fd.o = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); + fd.ds = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); } catch(IOException e) { return -EADDRINUSE; } @@ -803,11 +991,11 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_listen(int fdn, int backlog) throws ErrnoException { SocketFD fd = getSocketFD(fdn); if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP; - if(fd.o != null) return -EISCONN; + if(fd.ss != null || fd.s != null) return -EISCONN; if(fd.bindPort < 0) return -EOPNOTSUPP; try { - fd.o = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); + fd.ss = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); fd.flags |= SocketFD.LISTEN; return 0; } catch(IOException e) { @@ -823,7 +1011,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { int size = memRead(lenaddr); - ServerSocket s = (ServerSocket) fd.o; + ServerSocket s = fd.ss; Socket client; try { client = s.accept(); @@ -839,7 +1027,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } SocketFD clientFD = new SocketFD(SocketFD.TYPE_STREAM); - clientFD.o = client; + clientFD.s = client; try { clientFD.is = client.getInputStream(); clientFD.os = client.getOutputStream(); @@ -854,9 +1042,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_shutdown(int fdn, int how) throws ErrnoException { SocketFD fd = getSocketFD(fdn); if(fd.type() != SocketFD.TYPE_STREAM || fd.listen()) return -EOPNOTSUPP; - if(fd.o == null) return -ENOTCONN; + if(fd.s == null) return -ENOTCONN; - Socket s = (Socket) fd.o; + Socket s = fd.s; try { if(how == SHUT_RD || how == SHUT_RDWR) Platform.socketHalfClose(s,false); @@ -868,6 +1056,58 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } + private int sys_sendto(int fdn, int addr, int count, int flags, int destAddr, int socklen) throws ErrnoException,ReadFaultException { + SocketFD fd = getSocketFD(fdn); + if(flags != 0) throw new ErrnoException(EINVAL); + + int word1 = memRead(destAddr); + if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; + int port = word1 & 0xffff; + InetAddress inetAddr; + byte[] ip = new byte[4]; + copyin(destAddr+4,ip,4); + try { + inetAddr = Platform.inetAddressFromBytes(ip); + } catch(UnknownHostException e) { + return -EADDRNOTAVAIL; + } + + count = Math.min(count,MAX_CHUNK); + byte[] buf = byteBuf(count); + copyin(addr,buf,count); + try { + return fd.sendto(buf,0,count,inetAddr,port); + } catch(ErrnoException e) { + if(e.errno == EPIPE) exit(128+13,true); + throw e; + } + } + + private int sys_recvfrom(int fdn, int addr, int count, int flags, int sourceAddr, int socklenAddr) throws ErrnoException, FaultException { + SocketFD fd = getSocketFD(fdn); + if(flags != 0) throw new ErrnoException(EINVAL); + + InetAddress[] inetAddr = sourceAddr == 0 ? null : new InetAddress[1]; + int[] port = sourceAddr == 0 ? null : new int[1]; + + count = Math.min(count,MAX_CHUNK); + byte[] buf = byteBuf(count); + int n = fd.recvfrom(buf,0,count,inetAddr,port); + copyout(buf,addr,n); + + if(sourceAddr != 0) { + memWrite(sourceAddr,(AF_INET << 16) | port[0]); + byte[] ip = inetAddr[0].getAddress(); + copyout(ip,sourceAddr+4,4); + } + + return n; + } + + private int sys_select(int n, int readFDs, int writeFDs, int exceptFDs, int timevalAddr) throws ReadFaultException, ErrnoException { + return -ENOSYS; + } + private static String hostName() { try { return InetAddress.getLocalHost().getHostName(); @@ -916,13 +1156,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } - // FEATURE: Run through the fork/wait stuff one more time - public static class GlobalState { - protected static final int OPEN = 1; - protected static final int STAT = 2; - protected static final int LSTAT = 3; - protected static final int MKDIR = 4; - protected static final int UNLINK = 5; + public static final class GlobalState { + Hashtable execCache = new Hashtable(); final UnixRuntime[] tasks; int nextPID = 1; @@ -937,10 +1172,11 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(defaultMounts) { addMount("/",new HostFS()); addMount("/dev",new DevFS()); + addMount("/resource",new ResourceFS()); } } - private static class MP implements Sort.Comparable { + static class MP implements Sort.Comparable { public MP(String path, FS fs) { this.path = path; this.fs = fs; } public String path; public FS fs; @@ -1005,7 +1241,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { mps = newMPS; } - // FEATURE: We shouldn't need to special case the root dir, it should work in the MP array private Object fsop(int op, UnixRuntime r, String normalizedPath, int arg1, int arg2) throws ErrnoException { int pl = normalizedPath.length(); if(pl != 0) { @@ -1015,136 +1250,47 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { MP mp = list[i]; int mpl = mp.path.length(); if(normalizedPath.startsWith(mp.path) && (pl == mpl || normalizedPath.charAt(mpl) == '/')) - return dispatch(mp.fs,op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2); + return mp.fs.dispatch(op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2); } } - return dispatch(root,op,r,normalizedPath,arg1,arg2); + return root.dispatch(op,r,normalizedPath,arg1,arg2); } - // FEATURE: move this into FS so some filesystem can override it directly (devfs) - 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); } + public final FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { return (FD) fsop(FS.OPEN,r,path,flags,mode); } + public final FStat stat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(FS.STAT,r,path,0,0); } + public final FStat lstat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(FS.LSTAT,r,path,0,0); } + public final void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { fsop(FS.MKDIR,r,path,mode,0); } + public final void unlink(UnixRuntime r, String path) throws ErrnoException { fsop(FS.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 { - // HACK: Hideous hack to make a standalone busybox possible - if(path.equals("bin/busybox") && Boolean.valueOf(Platform.getProperty("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); - } - FD fd = open(r,path,RD_ONLY,0); - if(fd == null) return null; - Seekable s = fd.seekable(); - - String[] command = null; - - if(s == null) throw new ErrnoException(EACCES); - byte[] buf = new byte[4096]; - - try { - int n = s.read(buf,0,buf.length); - if(n == -1) throw new ErrnoException(ENOEXEC); - - switch(buf[0]) { - case '\177': // possible ELF - if(n < 4 && s.tryReadFully(buf,n,4-n) != 4-n) throw new ErrnoException(ENOEXEC); - if(buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') throw new ErrnoException(ENOEXEC); - break; - case '#': - if(n == 1) { - int n2 = s.read(buf,1,buf.length-1); - if(n2 == -1) throw new ErrnoException(ENOEXEC); - n += n2; - } - if(buf[1] != '!') throw new ErrnoException(ENOEXEC); - int p = 2; - n -= 2; - OUTER: for(;;) { - for(int i=p;i 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 + ")"); - return new String(out,0,outp); + int outStart = out[0] == '/' ? 1 : 0; + return new String(out,outStart,outp - outStart); } FStat hostFStat(final File f, Object data) { @@ -1228,7 +1382,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { protected File root; public File getRoot() { return root; } - private static File hostRootDir() { + static File hostRootDir() { if(Platform.getProperty("nestedvm.root") != null) { File f = new File(Platform.getProperty("nestedvm.root")); if(f.isDirectory()) return f; @@ -1239,11 +1393,34 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(!f.exists()) throw new Error("Couldn't get File for cwd"); f = new File(f.getAbsolutePath()); while(f.getParent() != null) f = new File(f.getParent()); - // HACK: This works around a bug in some versions of ClassPath + // This works around a bug in some versions of ClassPath if(f.getPath().length() == 0) f = new File("/"); return f; } + static String reverseMap(String f) { + if(f.startsWith("/") && File.separatorChar == '/') return f; + + Vector vec = new Vector(); + File root = HostFS.hostRootDir(); + String s = new File(f).getAbsolutePath(); + File d = new File(s); + System.err.println(s); + System.err.println(d); + while(!d.equals(root)) { + vec.addElement(d.getName()); + if((s = d.getParent()) == null) break; + d = new File(s); + } + String ret = null; + if(s != null) { + ret="/"; + for(int i=vec.size()-1;i>=0;i--) ret += (String) vec.elementAt(i) + (i==0?"":"/"); + } + System.err.println("reverseMap: " + f + " => " + ret); + return ret; + } + private File hostFile(String path) { char sep = File.separatorChar; if(sep != '/') { @@ -1294,7 +1471,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private static File getParentFile(File f) { String p = f.getParent(); - return p == null ? null : new File(f,p); + return p == null ? null : new File(p); } public class HostDirFD extends DirFD { @@ -1311,7 +1488,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public int inode(int n) { return inodes.get(children[n].getAbsolutePath()); } public int parentInode() { File parent = getParentFile(f); - return parent == null ? -1 : inodes.get(parent.getAbsolutePath()); + // HACK: myInode() isn't really correct if we're not the root + return parent == null ? myInode() : inodes.get(parent.getAbsolutePath()); } public int myInode() { return inodes.get(f.getAbsolutePath()); } public int myDev() { return devno; } @@ -1332,9 +1510,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { protected abstract String name(int n); protected abstract int inode(int n); protected abstract int myDev(); - protected int parentInode() { return -1; } - protected int myInode() { return -1; } - + protected abstract int parentInode(); + protected abstract int myInode(); + public int flags() { return O_RDONLY; } + public int getdents(byte[] buf, int off, int len) { int ooff = off; int ino; @@ -1385,11 +1564,12 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private static final int FD_INODE = 4; private static final int FD_INODES = 32; - private class DevFStat extends FStat { + private abstract class DevFStat extends FStat { public int dev() { return devno; } public int mode() { return 0666; } public int type() { return S_IFCHR; } public int nlink() { return 1; } + public abstract int inode(); } private abstract class DevDirFD extends DirFD { @@ -1405,12 +1585,14 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public int write(byte[] a, int off, int length) { return length; } public int seek(int n, int whence) { return 0; } public FStat _fstat() { return new DevFStat(){ public int inode() { return ZERO_INODE; } }; } + public int flags() { return O_RDWR; } }; private FD devNullFD = new FD() { public int read(byte[] a, int off, int length) { return 0; } public int write(byte[] a, int off, int length) { return length; } public int seek(int n, int whence) { return 0; } public FStat _fstat() { return new DevFStat(){ public int inode() { return NULL_INODE; } }; } + public int flags() { return O_RDWR; } }; public FD open(UnixRuntime r, String path, int mode, int flags) throws ErrnoException { @@ -1444,8 +1626,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(path.equals("")) { return new DevDirFD() { public int myInode() { return ROOT_INODE; } - // FEATURE: Get the real parent inode somehow - public int parentInode() { return -1; } + // HACK: We don't have any clean way to get the parent inode + public int parentInode() { return ROOT_INODE; } public int inode(int n) { switch(n) { case 0: return NULL_INODE; @@ -1483,13 +1665,62 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(r.fds[n] == null) return null; return r.fds[n].fstat(); } - // FEATURE: inode stuff - if(path.equals("fd")) return new FStat() { public int type() { return S_IFDIR; } public int mode() { return 0444; }}; - if(path.equals("")) return new FStat() { public int type() { return S_IFDIR; } public int mode() { return 0444; }}; + if(path.equals("fd")) return new FStat() { public int inode() { return FD_INODE; } public int dev() { return devno; } public int type() { return S_IFDIR; } public int mode() { return 0444; }}; + if(path.equals("")) return new FStat() { public int inode() { return ROOT_INODE; } public int dev() { return devno; } public int type() { return S_IFDIR; } public int mode() { return 0444; }}; return null; } public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { throw new ErrnoException(EROFS); } public void unlink(UnixRuntime r, String path) throws ErrnoException { throw new ErrnoException(EROFS); } - } + } + + + public static class ResourceFS extends FS { + final InodeCache inodes = new InodeCache(500); + + public FStat lstat(UnixRuntime r, String path) throws ErrnoException { return stat(r,path); } + public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { throw new ErrnoException(EROFS); } + public void unlink(UnixRuntime r, String path) throws ErrnoException { throw new ErrnoException(EROFS); } + + FStat connFStat(final URLConnection conn) { + return new FStat() { + public int type() { return S_IFREG; } + public int nlink() { return 1; } + public int mode() { return 0444; } + public int size() { return conn.getContentLength(); } + public int mtime() { return (int)(conn.getDate() / 1000); } + public int inode() { return inodes.get(conn.getURL().toString()); } + public int dev() { return devno; } + }; + } + + public FStat stat(UnixRuntime r, String path) throws ErrnoException { + URL url = r.getClass().getResource("/" + path); + if(url == null) return null; + try { + return connFStat(url.openConnection()); + } catch(IOException e) { + throw new ErrnoException(EIO); + } + } + + public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { + if((flags & ~3) != 0) { + if(STDERR_DIAG) + System.err.println("WARNING: Unsupported flags passed to ResourceFS.open(\"" + path + "\"): " + toHex(flags & ~3)); + throw new ErrnoException(ENOTSUP); + } + if((flags&3) != RD_ONLY) throw new ErrnoException(EROFS); + URL url = r.getClass().getResource("/" + path); + if(url == null) return null; + try { + final URLConnection conn = url.openConnection(); + Seekable.InputStream si = new Seekable.InputStream(conn.getInputStream()); + return new SeekableFD(si,flags) { protected FStat _fstat() { return connFStat(conn); } }; + } catch(FileNotFoundException e) { + if(e.getMessage() != null && e.getMessage().indexOf("Permission denied") >= 0) throw new ErrnoException(EACCES); + return null; + } catch(IOException e) { throw new ErrnoException(EIO); } + } + } }