Skip to content

Commit

Permalink
Showing 2 changed files with 84 additions and 19 deletions.
19 changes: 0 additions & 19 deletions spec/truffle/tags/core/io/reopen_tags.txt
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
fails:IO#reopen calls #to_io to convert an object
fails:IO#reopen changes the class of the instance to the class of the object returned by #to_io
fails:IO#reopen raises an IOError if the object returned by #to_io is closed
fails:IO#reopen raises a TypeError if #to_io does not return an IO instance
fails:IO#reopen raises an IOError when called on a closed stream with an object
fails:IO#reopen raises an IOError if the IO argument is closed
fails:IO#reopen raises an IOError when called on a closed stream with an IO
fails:IO#reopen with a String does not raise an exception when called on a closed stream with a path
fails:IO#reopen with a String returns self
fails:IO#reopen with a String positions a newly created instance at the beginning of the new stream
fails:IO#reopen with a String positions an instance that has been read from at the beginning of the new stream
fails:IO#reopen with a String passes all mode flags through
fails:IO#reopen with a String effects exec/system/fork performed after it
fails:IO#reopen with a String calls #to_path on non-String arguments
fails:IO#reopen with a String opens a path after writing to the original file descriptor
fails:IO#reopen with a String creates the file if it doesn't exist if the IO is opened in write mode
fails:IO#reopen with a String raises an Errno::ENOENT if the file does not exist and the IO is not opened in write mode
fails:IO#reopen with an IO does not call #to_io
fails:IO#reopen with an IO does not change the object_id
fails:IO#reopen with an IO reads from the beginning if the other IO has not been read from
fails:IO#reopen with an IO reads from the current position of the other IO's stream
fails:IO#reopen with an IO associates the IO instance with the other IO's stream
fails:IO#reopen with an IO may change the class of the instance
fails:IO#reopen with an IO sets path equals to the other IO's path if other IO is File
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import jnr.constants.platform.Errno;
import jnr.constants.platform.Fcntl;

import org.jruby.RubyEncoding;
@@ -231,6 +232,89 @@ public RubyBasicObject ensureOpen(VirtualFrame frame, RubyBasicObject file) {

}

@RubiniusPrimitive(name = "io_reopen")
public static abstract class IOReopenPrimitiveNode extends RubiniusPrimitiveNode {

public IOReopenPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Specialization
public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject io) {
final int fd = (int) rubyWithSelf(frame, file, "@descriptor");
final int fdOther = (int) rubyWithSelf(frame, io, "@descriptor");

final int result = posix().dup2(fd, fdOther);
if (result == -1) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this));
}

final int mode = posix().fcntl(fd, Fcntl.F_GETFL);
if (mode < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this));
}
rubyWithSelf(frame, file, "@mode = mode", "mode", mode);

rubyWithSelf(frame, io, "reset_buffering");

return nil();
}

}

@RubiniusPrimitive(name = "io_reopen_path")
public static abstract class IOReopenPathPrimitiveNode extends RubiniusPrimitiveNode {

public IOReopenPathPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Specialization
public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyString path, int mode) {
int fd = (int) rubyWithSelf(frame, file, "@descriptor");
final String pathString = path.toString();

int otherFd = posix().open(pathString, mode, 666);
if (otherFd < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this));
}

final int result = posix().dup2(otherFd, fd);
if (result == -1) {
final int errno = posix().errno();
if (errno == Errno.EBADF.intValue()) {
rubyWithSelf(frame, file, "@descriptor = desc", "desc", otherFd);
fd = otherFd;
} else {
if (otherFd > 0) {
posix().close(otherFd);
}
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().errnoError(errno, this));
}

} else {
posix().close(otherFd);
}


final int newMode = posix().fcntl(fd, Fcntl.F_GETFL);
if (newMode < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this));
}
rubyWithSelf(frame, file, "@mode = mode", "mode", newMode);

rubyWithSelf(frame, file, "reset_buffering");

return nil();
}

}

@RubiniusPrimitive(name = "io_write")
public static abstract class IOWritePrimitiveNode extends RubiniusPrimitiveNode {

0 comments on commit 6465d03

Please sign in to comment.