if (ios.openFile == this.openFile) {
return this;
}
OpenFile originalFile = ios.getOpenFileChecked();
OpenFile selfFile = getOpenFileChecked();
long pos = 0;
if (originalFile.isReadable()) {
pos = originalFile.getMainStream().fgetpos();
}
if (originalFile.getPipeStream() != null) {
originalFile.getPipeStream().fflush();
} else if (originalFile.isWritable()) {
originalFile.getMainStream().fflush();
}
if (selfFile.isWritable()) {
selfFile.getWriteStream().fflush();
}
selfFile.setMode(originalFile.getMode());
selfFile.setProcess(originalFile.getProcess());
selfFile.setLineNumber(originalFile.getLineNumber());
selfFile.setPath(originalFile.getPath());
selfFile.setFinalizer(originalFile.getFinalizer());
ChannelDescriptor selfDescriptor = selfFile.getMainStream().getDescriptor();
ChannelDescriptor originalDescriptor = originalFile.getMainStream().getDescriptor();
// confirm we're not reopening self's channel
if (selfDescriptor.getChannel() != originalDescriptor.getChannel()) {
// check if we're a stdio IO, and ensure we're not badly mutilated
if (selfDescriptor.getFileno() >=0 && selfDescriptor.getFileno() <= 2) {
selfFile.getMainStream().clearerr();
// dup2 new fd into self to preserve fileno and references to it
originalDescriptor.dup2Into(selfDescriptor);
// re-register, since fileno points at something new now
registerDescriptor(selfDescriptor);
} else {
Stream pipeFile = selfFile.getPipeStream();
int mode = selfFile.getMode();
selfFile.getMainStream().fclose();
selfFile.setPipeStream(null);
// TODO: turn off readable? am I reading this right?
// This only seems to be used while duping below, since modes gets
// reset to actual modes afterward
//fptr->mode &= (m & FMODE_READABLE) ? ~FMODE_READABLE : ~FMODE_WRITABLE;
if (pipeFile != null) {
selfFile.setMainStream(ChannelStream.fdopen(runtime, originalDescriptor, new ModeFlags()));
selfFile.setPipeStream(pipeFile);
} else {
selfFile.setMainStream(
new ChannelStream(
runtime,
originalDescriptor.dup2(selfDescriptor.getFileno())));
// re-register the descriptor
registerDescriptor(selfFile.getMainStream().getDescriptor());
// since we're not actually duping the incoming channel into our handler, we need to
// copy the original sync behavior from the other handler
selfFile.getMainStream().setSync(selfFile.getMainStream().isSync());
}
selfFile.setMode(mode);
}
// TODO: anything threads attached to original fd are notified of the close...
// see rb_thread_fd_close
if (originalFile.isReadable() && pos >= 0) {
selfFile.seek(pos, Stream.SEEK_SET);
originalFile.seek(pos, Stream.SEEK_SET);
}
}
if (selfFile.getPipeStream() != null && selfDescriptor.getFileno() != selfFile.getPipeStream().getDescriptor().getFileno()) {
int fd = selfFile.getPipeStream().getDescriptor().getFileno();
if (originalFile.getPipeStream() == null) {
selfFile.getPipeStream().fclose();
selfFile.setPipeStream(null);
} else if (fd != originalFile.getPipeStream().getDescriptor().getFileno()) {
selfFile.getPipeStream().fclose();
ChannelDescriptor newFD2 = originalFile.getPipeStream().getDescriptor().dup2(fd);
selfFile.setPipeStream(ChannelStream.fdopen(runtime, newFD2, getIOModes(runtime, "w")));
// re-register, since fileno points at something new now
registerDescriptor(newFD2);
}
}
// TODO: restore binary mode
// if (fptr->mode & FMODE_BINMODE) {
// rb_io_binmode(io);
// }
// TODO: set our metaclass to target's class (i.e. scary!)
} catch (IOException ex) { // TODO: better error handling
throw runtime.newIOError("could not reopen: " + ex.getMessage());
} catch (BadDescriptorException ex) {
throw runtime.newIOError("could not reopen: " + ex.getMessage());
} catch (PipeException ex) {
throw runtime.newIOError("could not reopen: " + ex.getMessage());
}
} else {
IRubyObject pathString = args[0].convertToString();
// TODO: check safe, taint on incoming string
if (openFile == null) {
openFile = new OpenFile();
}
try {
ModeFlags modes;
if (args.length > 1) {