X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=0bc102809b0cb88ac0dda49f5854a35444cb5008;hp=4475795e7ce37418e418c03f27cdd92a97bcbda9;hb=404ead23c2104bbed240370653a5308849b98905;hpb=7ee30b5692515ac602c88745aaa8c71eb82d376c diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index 4475795..0bc1028 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -1,9 +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.*; +// 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 @@ -14,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; } @@ -31,29 +39,31 @@ 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 = getSystemProperty("user.dir"); - cwd = - userdir != null && userdir.startsWith("/") && File.separatorChar == '/' && getSystemProperty("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); + } } - // NOTE: getDisplayName() is a Java2 function private static String posixTZ() { StringBuffer sb = new StringBuffer(); TimeZone zone = TimeZone.getDefault(); int off = zone.getRawOffset() / 1000; - sb.append(zone.getDisplayName(false,TimeZone.SHORT)); + sb.append(Platform.timeZoneGetDisplayName(zone,false,false)); if(off > 0) sb.append("-"); else off = -off; sb.append(off/3600); off = off%3600; if(off > 0) sb.append(":").append(off/60); off=off%60; if(off > 0) sb.append(":").append(off); if(zone.useDaylightTime()) - sb.append(zone.getDisplayName(true,TimeZone.SHORT)); + sb.append(Platform.timeZoneGetDisplayName(zone,true,false)); return sb.toString(); } @@ -64,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]; - if(!envHas("USER",extra) && getSystemProperty("user.name") != null) - defaults[n++] = "USER=" + getSystemProperty("user.name"); - if(!envHas("HOME",extra) && getSystemProperty("user.home") != null) - defaults[n++] = "HOME=" + getSystemProperty("user.home"); + String tmp; + if(!envHas("USER",extra) && Platform.getProperty("user.name") != null) + defaults[n++] = "USER=" + Platform.getProperty("user.name"); + 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]; @@ -93,7 +106,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { synchronized(parent.children) { int i = parent.activeChildren.indexOf(prev); if(i == -1) throw new Error("should never happen"); - parent.activeChildren.set(i,this); + parent.activeChildren.setElementAt(this,i); } } else { int newpid = -1; @@ -135,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); } } @@ -147,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. @@ -163,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; } @@ -194,12 +251,16 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { synchronized(children) { for(;;) { if(pid == -1) { - if(exitedChildren.size() > 0) done = (UnixRuntime)exitedChildren.remove(exitedChildren.size() - 1); + if(exitedChildren.size() > 0) { + done = (UnixRuntime)exitedChildren.elementAt(exitedChildren.size() - 1); + 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) { - if(!exitedChildren.remove(t)) throw new Error("should never happen"); + if(!exitedChildren.removeElement(t)) throw new Error("should never happen"); done = t; } } else { @@ -227,12 +288,12 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { UnixRuntime child = (UnixRuntime) e.nextElement(); gs.tasks[child.pid] = null; } - exitedChildren.clear(); + exitedChildren.removeAllElements(); for(Enumeration e = activeChildren.elements(); e.hasMoreElements(); ) { UnixRuntime child = (UnixRuntime) e.nextElement(); child.parent = null; } - activeChildren.clear(); + activeChildren.removeAllElements(); } UnixRuntime _parent = parent; @@ -243,8 +304,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(parent == null) { gs.tasks[pid] = null; } else { - if(!parent.activeChildren.remove(this)) throw new Error("should never happen _exited: pid: " + pid); - parent.exitedChildren.add(this); + if(!parent.activeChildren.removeElement(this)) throw new Error("should never happen _exited: pid: " + pid); + parent.exitedChildren.addElement(this); parent.children.notify(); } } @@ -261,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 { @@ -287,8 +345,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { activeChildren = new Vector(); exitedChildren = new Vector(); } - activeChildren.add(r); + 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); @@ -330,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; @@ -653,27 +853,26 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { InetAddress inetAddr; try { - inetAddr = InetAddress.getByAddress(ip); + inetAddr = Platform.inetAddressFromBytes(ip); } catch(UnknownHostException e) { 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: { - DatagramSocket s = (DatagramSocket) fd.o; - if(s == null) s = new DatagramSocket(); - s.connect(inetAddr,port); + case SocketFD.TYPE_DGRAM: break; - } default: throw new Error("should never happen"); } @@ -753,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; @@ -763,7 +962,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { copyin(addr+4,ip,4); try { - inetAddr = InetAddress.getByAddress(ip); + inetAddr = Platform.inetAddressFromBytes(ip); } catch(UnknownHostException e) { return -EADDRNOTAVAIL; } @@ -776,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; } @@ -793,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) { @@ -813,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(); @@ -829,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(); @@ -844,13 +1042,13 @@ 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) s.shutdownInput(); - if(how == SHUT_WR || how == SHUT_RDWR) s.shutdownOutput(); + if(how == SHUT_RD || how == SHUT_RDWR) Platform.socketHalfClose(s,false); + if(how == SHUT_WR || how == SHUT_RDWR) Platform.socketHalfClose(s,true); } catch(IOException e) { return -EIO; } @@ -858,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(); @@ -905,62 +1155,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } return 0; } - - - /*public int sys_opensocket(int cstring, int port) throws FaultException, ErrnoException { - String hostname = cstring(cstring); - try { - FD fd = new SocketFD(new Socket(hostname,port)); - int n = addFD(fd); - if(n == -1) fd.close(); - return n; - } catch(IOException e) { - return -EIO; - } - } - - private static class ListenSocketFD extends FD { - ServerSocket s; - public ListenSocketFD(ServerSocket s) { this.s = s; } - public int flags() { return 0; } - // FEATURE: What should these be? - public FStat _fstat() { return new FStat(); } - public void _close() { try { s.close(); } catch(IOException e) { } } - } - - public int sys_listensocket(int port) { - try { - ListenSocketFD fd = new ListenSocketFD(new ServerSocket(port)); - int n = addFD(fd); - if(n == -1) fd.close(); - return n; - } catch(IOException e) { - return -EIO; - } - } - - public int sys_accept(int fdn) { - if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; - if(fds[fdn] == null) return -EBADFD; - if(!(fds[fdn] instanceof ListenSocketFD)) return -EBADFD; - try { - ServerSocket s = ((ListenSocketFD)fds[fdn]).s; - SocketFD fd = new SocketFD(s.accept()); - int n = addFD(fd); - if(n == -1) fd.close(); - return n; - } catch(IOException e) { - return -EIO; - } - }*/ - // 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; @@ -975,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 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; @@ -1010,7 +1208,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { MP[] newMPS = new MP[oldLength + 1]; if(oldLength != 0) System.arraycopy(mps,0,newMPS,0,oldLength); newMPS[oldLength] = new MP(path,fs); - Arrays.sort(newMPS); + Sort.sort(newMPS); mps = newMPS; int highdevno = 0; for(int i=0;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) { @@ -1264,20 +1382,45 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { protected File root; public File getRoot() { return root; } - private static File hostRootDir() { - if(getSystemProperty("nestedvm.root") != null) { - File f = new File(getSystemProperty("nestedvm.root")); + static File hostRootDir() { + if(Platform.getProperty("nestedvm.root") != null) { + File f = new File(Platform.getProperty("nestedvm.root")); if(f.isDirectory()) return f; // fall through to case below } - String cwd = getSystemProperty("user.dir"); + String cwd = Platform.getProperty("user.dir"); File f = new File(cwd != null ? cwd : "."); 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()); + // 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 != '/') { @@ -1298,8 +1441,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { - // FIXME: horrendous, ugly hack needed by TeX... sorry Brian... - path = path.trim(); final File f = hostFile(path); return r.hostFSOpen(f,flags,mode,this); } @@ -1323,21 +1464,32 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(r.sm != null && !r.sm.allowWrite(f)) throw new ErrnoException(EACCES); if(f.exists() && f.isDirectory()) throw new ErrnoException(EEXIST); if(f.exists()) throw new ErrnoException(ENOTDIR); - File parent = f.getParentFile(); + File parent = getParentFile(f); if(parent!=null && (!parent.exists() || !parent.isDirectory())) throw new ErrnoException(ENOTDIR); if(!f.mkdir()) throw new ErrnoException(EIO); } + private static File getParentFile(File f) { + String p = f.getParent(); + return p == null ? null : new File(p); + } + public class HostDirFD extends DirFD { private final File f; private final File[] children; - public HostDirFD(File f) { this.f = f; children = f.listFiles(); } + public HostDirFD(File f) { + this.f = f; + String[] l = f.list(); + children = new File[l.length]; + for(int i=0;i= 0) throw new ErrnoException(EACCES); + return null; + } catch(IOException e) { throw new ErrnoException(EIO); } + } + } }