if(pc == -1) throw new Exn("pc modifying insn in delay slot");
int target = (pc&0xf0000000)|(jumpTarget << 2);
emitInstruction(-1,nextInsn,-1);
- // FIXME: Have a memcpy syscall and just override memcpy in libnestedvm
- if(optimizedMemcpy && (target == memcpy || target == memset)) {
- a(InstructionConstants.ALOAD_0);
- pushRegZ(R+4);
- pushRegZ(R+5);
- pushRegZ(R+6);
- a(fac.createInvoke(fullClassName,target==memcpy ? "memcpy" : "memset", Type.VOID, new Type[]{Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
- preSetReg(R+2);
- pushReg(R+4);
- setReg();
- branch(pc,pc+8);
- } else {
- preSetReg(R+RA);
- pushConst(pc+8);
- setReg();
- branch(pc, target);
- }
+ preSetReg(R+RA);
+ pushConst(pc+8);
+ setReg();
+ branch(pc, target);
unreachable = true;
break;
}
protected boolean assumeTailCalls = true;
- protected boolean optimizedMemcpy = true;
-
// True to insert some code in the output to help diagnore compiler problems
protected boolean debugCompiler = false;
while(pageSize>>>pageShift != 1) pageShift++;
}
- /** The address of the memcpy function in the binary (used for optimizedMemcpy) */
- protected int memcpy;
-
- /** The address of the memset function in the binary (used for optimizedMemcpy) */
- protected int memset;
-
/** A set of all addresses that can be jumped too (only available if pruneCases == true) */
protected Set jumpableAddresses;
if(symtab == null) throw new Exn("Binary has no symtab (did you strip it?)");
ELF.Symbol sym;
- // Check for some functions we can override
- sym = symtab.getGlobalSymbol("memcpy");
- memcpy = sym == null ? -1 : sym.addr;
-
- sym = symtab.getGlobalSymbol("memset");
- memset = sym == null ? -1 : sym.addr;
-
userInfo = symtab.getGlobalSymbol("user_info");
gp = symtab.getGlobalSymbol("_gp");
if(gp == null) throw new Exn("no _gp symbol (did you strip the binary?)");
if(pc == -1) throw new Error("pc modifying insn in delay slot");
int target = (pc&0xf0000000)|(jumpTarget << 2);
emitInstruction(-1,nextInsn,-1);
- if(optimizedMemcpy && (target == memcpy || target == memset)) {
- if(target == memcpy)
- p("memcpy(r4,r5,r6);");
- else if(target == memset)
- p("memset(r4,r5,r6);");
- p("r2 = r4;");
- branch(pc,pc+8);
- } else {
- p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
- branch(pc, target);
- }
+ p("r" + RA + "=" + constant(pc+8 /*skip this insn and delay slot*/) + ";");
+ branch(pc, target);
unreachable = true;
break;
}
private byte[] _byteBuf;
/** Max size of temporary buffer
@see Runtime#_byteBuf */
- private final static int MAX_CHUNK = 16*1024*1024 - 1024;
+ final static int MAX_CHUNK = 16*1024*1024 - 1024;
/** Subclasses should actually execute program in this method. They should continue
executing until state != RUNNING. Only syscall() can modify state. It is safe
public final void memcpy(int dst, int src, int count) throws FaultException {
int pageWords = (1<<pageShift)>>>2;
int pageWordMask = pageWords - 1;
-
if((dst&3) == 0 && (src&3)==0) {
if((count&~3) != 0) {
int c = count>>2;
public static final int O_TRUNC = 0x0400;
public static final int O_NONBLOCK = 0x4000;
- FD hostFSOpen(final File f, int flags, int mode) throws ErrnoException {
+ FD hostFSOpen(final File f, int flags, int mode, final Object data) throws ErrnoException {
if((flags & ~(3|O_CREAT|O_EXCL|O_APPEND|O_TRUNC)) != 0) {
System.err.println("WARNING: Unsupported flags passed to open(): " + toHex(flags & ~(3|O_CREAT|O_EXCL|O_APPEND|O_TRUNC)));
throw new ErrnoException(ENOTSUP);
}
- boolean write = mode!=RD_ONLY;
+ boolean write = (flags&3) != RD_ONLY;
if(sm != null && !(write ? sm.allowWrite(f) : sm.allowRead(f))) throw new ErrnoException(EACCES);
} else if(!f.exists()) {
if((flags&O_CREAT)==0) return null;
} else if(f.isDirectory()) {
- return hostFSDirFD(f);
+ return hostFSDirFD(f,data);
}
final Seekable.File sf;
return null;
} catch(IOException e) { throw new ErrnoException(EIO); }
- return new SeekableFD(sf,flags) { protected FStat _fstat() { return hostFStat(f); } };
+ return new SeekableFD(sf,flags) { protected FStat _fstat() { return hostFStat(f,data); } };
}
- FStat hostFStat(File f) { return new HostFStat(f); }
- FD hostFSDirFD(File f) { return null; }
+ FStat hostFStat(File f, Object data) { return new HostFStat(f); }
+
+ FD hostFSDirFD(File f, Object data) { return null; }
FD _open(String path, int flags, int mode) throws ErrnoException {
- return hostFSOpen(new File(path),flags,mode);
+ return hostFSOpen(new File(path),flags,mode,null);
}
/** The open syscall */
}
/** The write syscall */
- private int sys_write(int fdn, int addr, int count) throws FaultException {
+
+ // FIXME: Handle pipe closed exception
+ private int sys_write(int fdn, int addr, int count) throws FaultException, ErrnoException {
count = Math.min(count,MAX_CHUNK);
if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
- if(fds[fdn] == null || !fds[fdn].writable()) return -EBADFD;
- try {
- byte[] buf = byteBuf(count);
- copyin(addr,buf,count);
- return fds[fdn].write(buf,0,count);
- } catch(IOException e) {
- // NOTE: This should really send a SIGPIPE
- if(e.getMessage().equals("Pipe closed")) return sys_exit(128+13);
- return -EIO;
- }
+ if(fds[fdn] == null) return -EBADFD;
+ byte[] buf = byteBuf(count);
+ copyin(addr,buf,count);
+ return fds[fdn].write(buf,0,count);
}
/** The read syscall */
- private int sys_read(int fdn, int addr, int count) throws FaultException {
+ private int sys_read(int fdn, int addr, int count) throws FaultException, ErrnoException {
count = Math.min(count,MAX_CHUNK);
if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
- if(fds[fdn] == null || !fds[fdn].readable()) return -EBADFD;
- try {
- byte[] buf = byteBuf(count);
- int n = fds[fdn].read(buf,0,count);
- copyout(buf,addr,n);
- return n;
- } catch(IOException e) {
- return -EIO;
- }
+ if(fds[fdn] == null) return -EBADFD;
+ byte[] buf = byteBuf(count);
+ int n = fds[fdn].read(buf,0,count);
+ copyout(buf,addr,n);
+ return n;
}
/** The close syscall */
/** The seek syscall */
- private int sys_lseek(int fdn, int offset, int whence) {
+ private int sys_lseek(int fdn, int offset, int whence) throws ErrnoException {
if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
if(fds[fdn] == null) return -EBADFD;
if(whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) return -EINVAL;
- try {
- int n = fds[fdn].seek(offset,whence);
- return n < 0 ? -ESPIPE : n;
- } catch(IOException e) {
- return -ESPIPE;
- }
+ int n = fds[fdn].seek(offset,whence);
+ return n < 0 ? -ESPIPE : n;
}
/** The stat/fstat syscall helper */
private int sys_getpagesize() { return writePages.length == 1 ? 4096 : (1<<pageShift); }
- private int sys_isatty(int fdn) {
- if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
- if(fds[fdn] == null) return -EBADFD;
- return fds[fdn].isatty() ? 1 : 0;
- }
-
-
/** Hook for subclasses to do something when the process exits */
void _exited() { }
fds[i] = fd.dup();
return 0;
case F_GETFL:
- int flags = 0;
- if(fd.writable() && fd.readable()) flags = 2;
- else if(fd.writable()) flags = 1;
- return flags;
+ return fd.flags();
case F_SETFD:
closeOnExec[fdn] = arg != 0;
return 0;
case SYS_sleep: return sys_sleep(a);
case SYS_times: return sys_times(a);
case SYS_getpagesize: return sys_getpagesize();
- case SYS_isatty: return sys_isatty(a);
case SYS_fcntl: return sys_fcntl(a,b,c);
case SYS_sysconf: return sys_sysconf(a);
+
+ case SYS_memcpy: memcpy(a,b,c); return a;
+ case SYS_memset: memset(a,b,c); return a;
case SYS_kill:
case SYS_fork:
/** File Descriptor class */
public static abstract class FD {
private int refCount = 1;
-
- /** returns true if the fd is readable */
- public boolean readable() { return false; }
- /** returns true if the fd is writable */
- public boolean writable() { return false; }
/** Read some bytes. Should return the number of bytes read, 0 on EOF, or throw an IOException on error */
- public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
+ public int read(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); }
/** Write. Should return the number of bytes written or throw an IOException on error */
- public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
+ public int write(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); }
/** Seek in the filedescriptor. Whence is SEEK_SET, SEEK_CUR, or SEEK_END. Should return -1 on error or the new position. */
- public int seek(int n, int whence) throws IOException { return -1; }
+ public int seek(int n, int whence) throws ErrnoException { return -1; }
+
+ public int getdents(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); }
+
+ public int flags() { return O_RDONLY; }
/** Return a Seekable object representing this file descriptor (can be read only)
This is required for exec() */
Seekable seekable() { return null; }
- /** Should return true if this is a tty */
- // FIXME: get rid of the isatty syscall and just do with newlib's dumb isatty.c
- public boolean isatty() { return false; }
-
private FStat cachedFStat = null;
public final FStat fstat() {
if(cachedFStat == null) cachedFStat = _fstat();
public abstract static class SeekableFD extends FD {
private final int flags;
private final Seekable data;
- public boolean readable() { return (flags&3) != WR_ONLY; }
- public boolean writable() { return (flags&3) != RD_ONLY; }
SeekableFD(Seekable data, int flags) { this.data = data; this.flags = flags; }
protected abstract FStat _fstat();
+ public int flags() { return flags; }
Seekable seekable() { return data; }
- public int seek(int n, int whence) throws IOException {
- switch(whence) {
- case SEEK_SET: break;
- case SEEK_CUR: n += data.pos(); break;
- case SEEK_END: n += data.length(); break;
- default: return -1;
+ public int seek(int n, int whence) throws ErrnoException {
+ try {
+ switch(whence) {
+ case SEEK_SET: break;
+ case SEEK_CUR: n += data.pos(); break;
+ case SEEK_END: n += data.length(); break;
+ default: return -1;
+ }
+ data.seek(n);
+ return n;
+ } catch(IOException e) {
+ throw new ErrnoException(ESPIPE);
}
- data.seek(n);
- return n;
}
- public int write(byte[] a, int off, int length) throws IOException {
+ public int write(byte[] a, int off, int length) throws ErrnoException {
+ if((flags&3) == RD_ONLY) throw new ErrnoException(EBADFD);
// NOTE: There is race condition here but we can't fix it in pure java
if((flags&O_APPEND) != 0) seek(0,SEEK_END);
- return data.write(a,off,length);
+ try {
+ return data.write(a,off,length);
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
}
- public int read(byte[] a, int off, int length) throws IOException {
- int n = data.read(a,off,length);
- return n < 0 ? 0 : n;
+ public int read(byte[] a, int off, int length) throws ErrnoException {
+ if((flags&3) == WR_ONLY) throw new ErrnoException(EBADFD);
+ try {
+ int n = data.read(a,off,length);
+ return n < 0 ? 0 : n;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
}
protected void _close() { try { data.close(); } catch(IOException e) { /*ignore*/ } }
public static class OutputStreamFD extends FD {
private OutputStream os;
- public boolean writable() { return true; }
+ public int flags() { return O_WRONLY; }
public OutputStreamFD(OutputStream os) { this.os = os; }
- public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; }
+ public int write(byte[] a, int off, int length) throws ErrnoException {
+ try {
+ os.write(a,off,length);
+ return length;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
public void _close() { try { os.close(); } catch(IOException e) { /*ignore*/ } }
public FStat _fstat() { return new FStat(); }
}
public static class InputStreamFD extends FD {
private InputStream is;
- public boolean readable() { return true; }
+ public int flags() { return O_RDONLY; }
public InputStreamFD(InputStream is) { this.is = is; }
- public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; }
+ public int read(byte[] a, int off, int length) throws ErrnoException {
+ try {
+ int n = is.read(a,off,length);
+ return n < 0 ? 0 : n;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
public void _close() { try { is.close(); } catch(IOException e) { /*ignore*/ } }
public FStat _fstat() { return new FStat(); }
}
public StdinFD(InputStream is) { super(is); }
public void _close() { /* noop */ }
public FStat _fstat() { return new FStat() { public int type() { return S_IFCHR; } }; }
- public boolean isatty() { return true; }
}
static class StdoutFD extends OutputStreamFD {
public StdoutFD(OutputStream os) { super(os); }
public void _close() { /* noop */ }
public FStat _fstat() { return new FStat() { public int type() { return S_IFCHR; } }; }
- public boolean isatty() { return true; }
}
public static class FStat {
public static final int S_IFDIR = 0040000;
public static final int S_IFREG = 0100000;
- public int dev() { return -1; }
- // FIXME: inode numbers are calculated inconsistently throught the runtime
- public int inode() { return hashCode() & 0xfffff; }
+ public int dev() { return 1; }
+ public int inode() { return hashCode() & 0x7fff; }
public int mode() { return 0; }
public int type() { return S_IFIFO; }
public int nlink() { return 0; }
}
// Utility functions
- private byte[] byteBuf(int size) {
+ byte[] byteBuf(int size) {
if(_byteBuf==null) _byteBuf = new byte[size];
else if(_byteBuf.length < size)
_byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK)];
import org.ibex.nestedvm.util.*;
// FEATURE: This need a lot of work to support binaries spanned across many classes
-public class RuntimeCompiler {
- private static final SingleClassLoader singleClassLoader = new SingleClassLoader();
+public class RuntimeCompiler {
+ // FEATURE: Do we need to periodicly create a new classloader to allow old clases to be GCed?
+ private static SingleClassLoader singleClassLoader = new SingleClassLoader();
// FEATURE: Is it ok if this overflows?
private static long nextID = 1;
private static synchronized String uniqueID() { return Long.toString(nextID++); }
import java.io.*;
import java.util.*;
-// FIXME: Fix readdir in support_aux.c
// FIXME: Make plain old "mips-unknown-elf-gcc -o foo foo.c" work (modify spec file or whatever)
// FEATURE: Remove System.{out,err}.printlns and throw Errors where applicable
-// FIXME: BusyBox's ASH doesn't like \r\n at the end of lines
-// is ash just broken or are many apps like this? if so workaround in nestedvm
-
public abstract class UnixRuntime extends Runtime implements Cloneable {
/** The pid of this "process" */
private int pid;
case SYS_getcwd: return sys_getcwd(a,b);
case SYS_chdir: return sys_chdir(a);
case SYS_exec: return sys_exec(a,b,c);
+ case SYS_getdents: return sys_getdents(a,b,c,d);
default: return super._syscall(syscall,a,b,c,d);
}
return 0;
}
-
private int sys_getcwd(int addr, int size) throws FaultException, ErrnoException {
byte[] b = getBytes(cwd);
if(size == 0) return -EINVAL;
return 0;
}
+ private int sys_getdents(int fdn, int addr, int count, int seekptr) throws FaultException, ErrnoException {
+ count = Math.min(count,MAX_CHUNK);
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ byte[] buf = byteBuf(count);
+ int n = fds[fdn].getdents(buf,0,count);
+ copyout(buf,addr,n);
+ return n;
+ }
+
// FEATURE: Run through the fork/wait stuff one more time
public static class GlobalState {
protected static final int OPEN = 1;
final UnixRuntime[] tasks;
int nextPID = 1;
- private final MP[][] mps = new MP[128][];
+ private MP[] mps = new MP[0];
private FS root;
public GlobalState() { this(255); }
public GlobalState(int maxProcs, boolean defaultMounts) {
tasks = new UnixRuntime[maxProcs+1];
if(defaultMounts) {
- root = new HostFS();
+ addMount("/",new HostFS());
addMount("/dev",new DevFS());
}
}
if(!path.startsWith("/")) throw new IllegalArgumentException("Mount point doesn't start with a /");
if(path.equals("/")) return root;
path = path.substring(1);
- int f = path.charAt(0) & 0x7f;
- for(int i=0;mps[f] != null && i < mps[f].length;i++)
- if(mps[f][i].path.equals(path)) return mps[f][i].fs;
+ for(int i=0;i<mps.length;i++)
+ if(mps[i].path.equals(path)) return mps[i].fs;
return null;
}
public synchronized void addMount(String path, FS fs) {
if(getMount(path) != null) throw new IllegalArgumentException("mount point already exists");
if(!path.startsWith("/")) throw new IllegalArgumentException("Mount point doesn't start with a /");
- if(path.equals("/")) { root = fs; return; }
+
+ if(fs.owner != null) fs.owner.removeMount(fs);
+ fs.owner = this;
+
+ if(path.equals("/")) { root = fs; fs.devno = 1; return; }
path = path.substring(1);
- int f = path.charAt(0) & 0x7f;
- int oldLength = mps[f] == null ? 0 : mps[f].length;
- MP[] newList = new MP[oldLength + 1];
- if(oldLength != 0) System.arraycopy(mps[f],0,newList,0,oldLength);
- newList[oldLength] = new MP(path,fs);
- Arrays.sort(newList);
- mps[f] = newList;
+ int oldLength = mps.length;
+ 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);
+ mps = newMPS;
+ int highdevno = 0;
+ for(int i=0;i<mps.length;i++) highdevno = max(highdevno,mps[i].fs.devno);
+ fs.devno = highdevno + 2;
+ }
+
+ public synchronized void removeMount(FS fs) {
+ for(int i=0;i<mps.length;i++) if(mps[i].fs == fs) { removeMount(i); return; }
+ throw new IllegalArgumentException("mount point doesn't exist");
}
public synchronized void removeMount(String path) {
- if(getMount(path) == null) throw new IllegalArgumentException("mount point doesn't exist");
if(!path.startsWith("/")) throw new IllegalArgumentException("Mount point doesn't start with a /");
- if(path.equals("/")) { root = null; return; }
- path = path.substring(1);
- int f = path.charAt(0) & 0x7f;
- MP[] oldList = mps[f];
- MP[] newList = new MP[oldList.length - 1];
- int p = 0;
- for(p=0;p<oldList.length;p++) if(oldList[p].path.equals(path)) break;
- if(p == oldList.length) throw new Error("should never happen");
- System.arraycopy(oldList,0,newList,0,p);
- System.arraycopy(oldList,0,newList,p,oldList.length-p-1);
- mps[f] = newList;
- }
-
- private Object fsop(int op, UnixRuntime r, String path, int arg1, int arg2) throws ErrnoException {
- int pl = path.length();
+ if(path.equals("/")) {
+ removeMount(-1);
+ } else {
+ 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 Error("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 = mps[path.charAt(0) & 0x7f];
- if(list != null) {
- for(int i=0;i<list.length;i++) {
- MP mp = list[i];
- int mpl = mp.path.length();
- if(path.startsWith(mp.path) && (pl == mpl || (pl < mpl && path.charAt(mpl) == '/')))
- return dispatch(mp.fs,op,r,pl == mpl ? "" : path.substring(mpl+1),arg1,arg2);
- }
+ 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,path,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 {
return ent.o;
}
}
-
+
public abstract static class FS {
- // FIXME: inode stuff
- protected static FD directoryFD(String[] files, int hashCode) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- try {
- for(int i=0;i<files.length;i++) {
- byte[] b = getBytes(files[i]);
- int inode = (files[i].hashCode() ^ hashCode) & 0xfffff;
- dos.writeInt(inode);
- dos.writeInt(b.length);
- dos.write(b,0,b.length);
- }
- } catch(IOException e) {
- return null;
- }
- final byte[] data = bos.toByteArray();
- return new SeekableFD(new Seekable.ByteArray(data,false),RD_ONLY) {
- protected FStat _fstat() { return new FStat() {
- public int length() { return data.length; }
- public int type() { return S_IFDIR; }
- }; }
- };
- }
-
+ GlobalState owner;
+ int devno;
+
public FStat lstat(UnixRuntime r, String path) throws ErrnoException { return stat(r,path); }
// If this returns null it'll be truned into an ENOENT
return new String(out,0,outp);
}
- FStat hostFStat(final File f) {
+ FStat hostFStat(final File f, Object data) {
boolean e = false;
try {
FileInputStream fis = new FileInputStream(f);
}
fis.close();
} catch(IOException e2) { }
- return new HostFStat(f,e);
+ 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; }
+ };
}
- // FIXME: inode stuff
- FD hostFSDirFD(File f) { return FS.directoryFD(f.list(),f.hashCode()); }
+ FD hostFSDirFD(File f, Object _fs) {
+ HostFS fs = (HostFS) _fs;
+ return fs.new HostDirFD(f);
+ }
public static class HostFS extends FS {
+ InodeCache inodes = new InodeCache(4096);
protected File root;
public File getRoot() { return root; }
public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException {
final File f = hostFile(path);
- return r.hostFSOpen(f,flags,mode);
+ return r.hostFSOpen(f,flags,mode,this);
}
public FStat stat(UnixRuntime r, String path) throws ErrnoException {
File f = hostFile(path);
if(r.sm != null && !r.sm.allowStat(f)) throw new ErrnoException(EACCES);
if(!f.exists()) return null;
- return r.hostFStat(f);
+ return r.hostFStat(f,this);
}
public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException {
if(parent!=null && (!parent.exists() || !parent.isDirectory())) throw new ErrnoException(ENOTDIR);
if(!f.mkdir()) throw new ErrnoException(EIO);
}
+
+ public class HostDirFD extends DirFD {
+ private final File f;
+ private final File[] children;
+ public HostDirFD(File f) { this.f = f; children = f.listFiles(); }
+ public int size() { return children.length; }
+ public String name(int n) { return children[n].getName(); }
+ public int inode(int n) { return inodes.get(children[n].getAbsolutePath()); }
+ public int parentInode() {
+ File parent = f.getParentFile();
+ return parent == null ? -1 : inodes.get(parent.getAbsolutePath());
+ }
+ public int myInode() { return inodes.get(f.getAbsolutePath()); }
+ public int myDev() { return devno; }
+ }
+ }
+
+ private static void putInt(byte[] buf, int off, int n) {
+ buf[off+0] = (byte)((n>>>24)&0xff);
+ buf[off+1] = (byte)((n>>>16)&0xff);
+ buf[off+2] = (byte)((n>>> 8)&0xff);
+ buf[off+3] = (byte)((n>>> 0)&0xff);
+ }
+
+ public static abstract class DirFD extends FD {
+ private int pos = -2;
+
+ protected abstract int size();
+ 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; }
+
+ public int getdents(byte[] buf, int off, int len) {
+ int ooff = off;
+ int ino;
+ int reclen;
+ OUTER: for(;len > 0 && pos < size();pos++){
+ switch(pos) {
+ case -2:
+ case -1:
+ ino = pos == -1 ? parentInode() : myInode();
+ if(ino == -1) continue;
+ reclen = 9 + (pos == -1 ? 2 : 1);
+ if(reclen > len) break OUTER;
+ buf[off+8] = '.';
+ if(pos == -1) buf[off+9] = '.';
+ break;
+ default: {
+ String f = name(pos);
+ byte[] fb = getBytes(f);
+ reclen = fb.length + 9;
+ if(reclen > len) break OUTER;
+ ino = inode(pos);
+ System.arraycopy(fb,0,buf,off+8,fb.length);
+ }
+ }
+ buf[off+reclen-1] = 0; // null terminate
+ reclen = (reclen + 3) & ~3; // add padding
+ putInt(buf,off,reclen);
+ putInt(buf,off+4,ino);
+ off += reclen;
+ len -= reclen;
+ }
+ return off-ooff;
+ }
+
+ protected FStat _fstat() {
+ return new FStat() {
+ public int type() { return S_IFDIR; }
+ public int inode() { return myInode(); }
+ public int dev() { return myDev(); }
+ };
+ }
}
public static class DevFS extends FS {
- private static class DevFStat extends FStat {
- public int dev() { return 1; }
+ private static final int ROOT_INODE = 1;
+ private static final int NULL_INODE = 2;
+ private static final int ZERO_INODE = 3;
+ private static final int FD_INODE = 4;
+ private static final int FD_INODES = 32;
+
+ private 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; }
}
- private static FD devZeroFD = new FD() {
+
+ private abstract class DevDirFD extends DirFD {
+ public int myDev() { return devno; }
+ }
+
+ private FD devZeroFD = new FD() {
public boolean readable() { return true; }
public boolean writable() { return true; }
public int read(byte[] a, int off, int length) { Arrays.fill(a,off,off+length,(byte)0); return length; }
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 FStat _fstat() { return new DevFStat(){ public int inode() { return ZERO_INODE; } }; }
};
- private static FD devNullFD = new FD() {
+ private FD devNullFD = new FD() {
public boolean readable() { return true; }
public boolean writable() { return true; }
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 FStat _fstat() { return new DevFStat(){ public int inode() { return NULL_INODE; } }; }
};
public FD open(UnixRuntime r, String path, int mode, int flags) throws ErrnoException {
}
if(path.equals("fd")) {
int count=0;
- for(int i=0;i<OPEN_MAX;i++) if(r.fds[i] != null) count++;
- String[] files = new String[count];
+ for(int i=0;i<OPEN_MAX;i++) if(r.fds[i] != null) { count++; }
+ final int[] files = new int[count];
count = 0;
- for(int i=0;i<OPEN_MAX;i++) if(r.fds[i] != null) files[count++] = Integer.toString(i);
- return directoryFD(files,hashCode());
+ for(int i=0;i<OPEN_MAX;i++) if(r.fds[i] != null) files[count++] = i;
+ return new DevDirFD() {
+ public int myInode() { return FD_INODE; }
+ public int parentInode() { return ROOT_INODE; }
+ public int inode(int n) { return FD_INODES + n; }
+ public String name(int n) { return Integer.toString(files[n]); }
+ public int size() { return files.length; }
+ };
}
if(path.equals("")) {
- String[] files = { "null", "zero", "fd" };
- return directoryFD(files,hashCode());
+ return new DevDirFD() {
+ public int myInode() { return ROOT_INODE; }
+ // FEATURE: Get the real parent inode somehow
+ public int parentInode() { return -1; }
+ public int inode(int n) {
+ switch(n) {
+ case 0: return NULL_INODE;
+ case 1: return ZERO_INODE;
+ case 2: return FD_INODE;
+ default: return -1;
+ }
+ }
+
+ public String name(int n) {
+ switch(n) {
+ case 0: return "null";
+ case 1: return "zero";
+ case 2: return "fd";
+ default: return null;
+ }
+ }
+ public int size() { return 3; }
+ };
}
return null;
}
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; }};
return null;
public static final int SYS_write = 6;
public static final int SYS_sbrk = 7;
public static final int SYS_fstat = 8;
- public static final int SYS_isatty = 9;
public static final int SYS_lseek = 10;
public static final int SYS_kill = 11;
public static final int SYS_getpid = 12;
public static final int SYS_lstat = 33;
public static final int SYS_symlink = 34;
public static final int SYS_link = 35;
+ public static final int SYS_getdents = 36;
+ public static final int SYS_memcpy = 37;
+ public static final int SYS_memset = 38;
public static final int EPERM = 1; /* Not super-user */
public static final int ENOENT = 2; /* No such file or directory */
public static final int ESRCH = 3; /* No such process */
SYSCALL_R(write)
SYSCALL_R(sbrk)
SYSCALL_R(fstat)
-SYSCALL(isatty)
SYSCALL_R(lseek)
SYSCALL_R(kill)
SYSCALL_R(getpid)
SYSCALL_R(dup2)
SYSCALL_R(fork)
SYSCALL_R(waitpid)
-SYSCALL_R(getcwd)
+SYSCALL_R2(__getcwd_r,SYS_getcwd)
SYSCALL_R2(__execve_r,SYS_exec)
SYSCALL_R(fcntl)
SYSCALL_R(rmdir)
SYSCALL_R(lstat)
SYSCALL_R(symlink)
SYSCALL_R(link)
+SYSCALL_R(getdents)
+SYSCALL(memcpy)
+SYSCALL(memset)
rt f(t1 a, t2 b, t3 c) { return _##f##_r(_REENT,a,b,c); }
#define REENT_WRAPPER3(f,t1,t2,t3) REENT_WRAPPER3R(f,int,t1,t2,t3)
+#define REENT_WRAPPER4R(f,rt,t1,t2,t3,t4) \
+extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d); \
+rt f(t1 a, t2 b, t3 c, t4 d) { return _##f##_r(_REENT,a,b,c,d); }
+#define REENT_WRAPPER4(f,t1,t2,t3,t4) REENT_WRAPPER4R(f,int,t1,t2,t3,t4)
+
REENT_WRAPPER2(mkdir,const char *,mode_t)
REENT_WRAPPER2(access,const char *,int)
REENT_WRAPPER1(rmdir,const char *)
REENT_WRAPPER2(dup2,int,int)
REENT_WRAPPER3(waitpid,pid_t,int *,int)
REENT_WRAPPER2R(getcwd,char *,char *,size_t)
+REENT_WRAPPER2R(_getcwd,char *,char *,size_t)
REENT_WRAPPER2(symlink,const char *,const char *)
REENT_WRAPPER3(readlink,const char *, char *,int)
REENT_WRAPPER3(chown,const char *,uid_t,gid_t)
REENT_WRAPPER2(chmod,const char *,mode_t)
REENT_WRAPPER2(fchmod,int,mode_t)
REENT_WRAPPER2(lstat,const char *,struct stat *)
+REENT_WRAPPER4(getdents,int, char *, size_t,long *)
extern int __execve_r(struct _reent *ptr, const char *path, char *const argv[], char *const envp[]);
int _execve(const char *path, char *const argv[], char *const envp[]) {
return __execve_r(_REENT,path,argv,envp);
}
-static int read_fully(int fd, void *buf, size_t size) {
- int n;
- while(size) {
- n = read(fd,buf,size);
- if(n <= 0) return -1;
- size -= n;
- buf += n;
+char *_getcwd_r(struct _reent *ptr, char *buf, size_t size) {
+ if(buf != NULL) {
+ buf = __getcwd_r(ptr,buf,size);
+ return (long)buf == -1 ? NULL : buf;
+ }
+
+ size = 256;
+ for(;;) {
+ buf = malloc(size);
+ char *ret = __getcwd_r(ptr,buf,size);
+ if((long)ret != -1) return ret;
+ free(buf);
+ size *= 2;
+ if(ptr->_errno != ERANGE) return NULL;
}
- return 0;
}
DIR *opendir(const char *path) {
return NULL;
}
dir->dd_fd = fd;
- //dir->dd_pos = 0;
+ dir->dd_buf = malloc(sizeof(struct dirent));
+ dir->dd_size = sizeof(struct dirent);
+ if(dir->dd_buf == NULL) {
+ close(fd);
+ free(dir);
+ return NULL;
+ }
+ dir->dd_loc = 0;
+ dir->dd_len = 0;
return dir;
}
-int readdir_r(DIR *dir,struct dirent *entry, struct dirent **result) {
- struct {
- int inode;
- int name_len;
- } h;
- if(dir->dd_fd < 0) return -1;
-again:
- if(read_fully(dir->dd_fd,&h,sizeof(h)) < 0) goto fail;
- if(h.name_len < 0 || h.name_len >= sizeof(entry->d_name)-1) goto fail;
-
- entry->d_ino = h.inode;
- if(read_fully(dir->dd_fd,entry->d_name,h.name_len) < 0) goto fail;
-
- entry->d_name[h.name_len] = '\0';
- //dir->dd_pos += h.name_len + 8;
-
- if(result) *result = entry;
- return 0;
-fail:
- if(result) *result = NULL;
- return -1;
+struct dirent *readdir(DIR *dir) {
+ struct dirent *dp;
+ errno = 0;
+ if(dir->dd_loc == 0 || dir->dd_loc == dir->dd_len) {
+ dir->dd_len = getdents(dir->dd_fd,dir->dd_buf,dir->dd_size,NULL);
+ dir->dd_loc = 0;
+ if(dir->dd_len <= 0) { dir->dd_len = 0; return NULL; }
+ }
+ dp = (struct dirent*) (dir->dd_buf + dir->dd_loc);
+ if(dp->d_reclen == 0 || dp->d_reclen > dir->dd_len - dir->dd_loc) return NULL;
+ dir->dd_loc += dp->d_reclen;
+ return dp;
}
-// FIXME: Rewrite all this dirent stuff in terms of a getdirentries syscall
-static struct dirent static_dir_ent;
-
-struct dirent *readdir(DIR *dir) { return readdir_r(dir,&static_dir_ent,NULL) == 0 ? &static_dir_ent : NULL; }
-
int closedir(DIR *dir) {
- close(dir->dd_fd);
+ int fd = dir->dd_fd;
+ free(dir->dd_buf);
free(dir);
- return 0;
+ return close(fd);
}
#define SYS_write 6
#define SYS_sbrk 7
#define SYS_fstat 8
-#define SYS_isatty 9
#define SYS_lseek 10
#define SYS_kill 11
#define SYS_getpid 12
#define SYS_lstat 33
#define SYS_symlink 34
#define SYS_link 35
+#define SYS_getdents 36
+#define SYS_memcpy 37
+#define SYS_memset 38
printf("Trying to opendir .\n");
dir = opendir(".");
if(dir) {
- while((dent=readdir(dir))!=NULL)
- printf("\t[%s] %lu\n",dent->d_name,dent->d_ino);
+ printf("Success!\n");
+ while((dent=readdir(dir))!=NULL) {
+ struct stat statbuf;
+ stat(dent->d_name,&statbuf);
+ printf("\t[%s] %lu %i %i\n",dent->d_name,dent->d_ino,statbuf.st_ino,statbuf.st_dev);
+ }
+ if(errno != 0) { fprintf(stderr,"readdir errno: %d\n",errno); perror("readdir"); }
closedir(dir);
} else {
perror("opendir");
}
}
+ {
+ char buf[1024];
+ memcpy(buf,"Hello, World",sizeof("Hello, World"));
+ printf("%s\n",buf);
+ }
+ printf("cwd: %s\n",getcwd(NULL,0));
+ printf("isatty(0): %d\n",isatty(0));
printf("exiting\n");
return 0;
}