return i;
}
- /** Hook for subclasses to do something when the process closes an FD */
- void _closedFD(FD fd) { }
+ /** Hooks for subclasses before and after the process closes an FD */
+ void _preCloseFD(FD fd) { }
+ void _postCloseFD(FD fd) { }
/** Closes file descriptor <i>fdn</i> and removes it from the file descriptor table */
public final boolean closeFD(int fdn) {
if(state == EXITED || state == EXECED) throw new IllegalStateException("closeFD called in inappropriate state");
if(fdn < 0 || fdn >= OPEN_MAX) return false;
if(fds[fdn] == null) return false;
-
- _closedFD(fds[fdn]);
-
+ _preCloseFD(fds[fdn]);
fds[fdn].close();
+ _postCloseFD(fds[fdn]);
fds[fdn] = null;
return true;
}
/** File Descriptor class */
public static abstract class FD {
private int refCount = 1;
+ private String normalizedPath = null;
+ private boolean deleteOnClose = false;
+
+ public void setNormalizedPath(String path) { normalizedPath = path; }
+ public String getNormalizedPath() { return normalizedPath; }
+
+ public void markDeleteOnClose() { deleteOnClose = true; }
+ public boolean isMarkedForDeleteOnClose() { return deleteOnClose; }
/** 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 ErrnoException { throw new ErrnoException(EBADFD); }
}
FD _open(String path, int flags, int mode) throws ErrnoException {
- return gs.open(this,normalizePath(path),flags,mode);
+ path = normalizePath(path);
+ FD fd = gs.open(this,path,flags,mode);
+ if (fd != null && path != null) fd.setNormalizedPath(path);
+ return fd;
}
private int sys_getppid() {
return n;
}
- void _closedFD(FD fd) {
+ void _preCloseFD(FD fd) {
// release all fcntl locks on this file
Seekable s = fd.seekable();
if (s == null) return;
} catch (IOException e) { throw new RuntimeException(e); }
}
+ void _postCloseFD(FD fd) {
+ if (fd.isMarkedForDeleteOnClose()) {
+ try { gs.unlink(this, fd.getNormalizedPath()); }
+ catch (Throwable t) {}
+ }
+ }
+
/** Implements the F_GETLK and F_SETLK cases of fcntl syscall.
* If l_start = 0 and l_len = 0 the lock refers to the entire file.
* Uses GlobalState to ensure locking across processes in the same JVM.
File f = hostFile(path);
if(r.sm != null && !r.sm.allowUnlink(f)) throw new ErrnoException(EPERM);
if(!f.exists()) throw new ErrnoException(ENOENT);
- if(!f.delete()) throw new ErrnoException(EPERM);
+ if(!f.delete()) {
+ // Can't delete file immediately, so mark for
+ // delete on close all matching FDs
+ boolean marked = false;
+ for(int i=0;i<OPEN_MAX;i++) {
+ if(r.fds[i] != null) {
+ String fdpath = r.fds[i].getNormalizedPath();
+ if(fdpath != null && fdpath.equals(path)) {
+ r.fds[i].markDeleteOnClose();
+ marked = true;
+ }
+ }
+ }
+ if(!marked) throw new ErrnoException(EPERM);
+ }
}
public FStat stat(UnixRuntime r, String path) throws ErrnoException {