diff --git a/src/org/jruby/RubyFile.java b/src/org/jruby/RubyFile.java index 4453aa0ca05..80d4dc25689 100644 --- a/src/org/jruby/RubyFile.java +++ b/src/org/jruby/RubyFile.java @@ -331,7 +331,19 @@ public IRubyObject initialize19(ThreadContext context, IRubyObject[] args, Block } } - return openFile19(context, args); + RubyBoolean hasOffset = context.runtime.newBoolean(false); + if (args[args.length - 1] instanceof RubyBoolean) { + hasOffset = (RubyBoolean) args[args.length - 1]; + IRubyObject[] newArgs = new IRubyObject[args.length - 1]; + System.arraycopy(args, 0, newArgs, 0, newArgs.length); + args = newArgs; + } + + if(hasOffset.isTrue()) { + return openFile19(context, args, true); + } else { + return openFile19(context, args, false); + } } @JRubyMethod(required = 1) @@ -1104,8 +1116,11 @@ public void setEncoding(Encoding encoding) { // :) } - // mri: rb_open_file + rb_scan_open_args private IRubyObject openFile19(ThreadContext context, IRubyObject args[]) { + return openFile19(context, args, false); + } + // mri: rb_open_file + rb_scan_open_args + private IRubyObject openFile19(ThreadContext context, IRubyObject args[], boolean hasOffeset) { Ruby runtime = context.runtime; RubyString filename = get_path(context, args[0]); @@ -1147,7 +1162,7 @@ private IRubyObject openFile19(ThreadContext context, IRubyObject args[]) { int perm = (pm[EncodingUtils.PERM] != null && !pm[EncodingUtils.PERM].isNil()) ? RubyNumeric.num2int(pm[EncodingUtils.PERM]) : 0666; - sysopenInternal(path, ModeFlags.createModeFlags(oflags), perm); + sysopenInternal(path, ModeFlags.createModeFlags(oflags), perm, hasOffeset); return this; } @@ -1184,8 +1199,12 @@ private int getFilePermissions(IRubyObject[] args) { return (args.length > 2 && !args[2].isNil()) ? RubyNumeric.num2int(args[2]) : 438; } - // mri: rb_file_open_generic protected void sysopenInternal(String path, ModeFlags modes, int perm) { + sysopenInternal(path, modes, perm, false); + } + + // mri: rb_file_open_generic + protected void sysopenInternal(String path, ModeFlags modes, int perm, boolean hasOffset) { if (path.startsWith("jar:")) path = path.substring(4); openFile = new OpenFile(); @@ -1196,7 +1215,7 @@ protected void sysopenInternal(String path, ModeFlags modes, int perm) { int umask = getUmaskSafe( getRuntime() ); perm = perm - (perm & umask); - ChannelDescriptor descriptor = sysopen(path, modes, perm); + ChannelDescriptor descriptor = sysopen(path, modes, perm, hasOffset); openFile.setMainStream(fdopen(descriptor, modes)); if (hasBom) { // FIXME: Wonky that we acquire RubyEncoding to pass these encodings through @@ -1238,6 +1257,10 @@ protected void openInternal(String path, String modeString) { } private ChannelDescriptor sysopen(String path, ModeFlags modes, int perm) { + return sysopen(path,modes,perm,false); + } + + private ChannelDescriptor sysopen(String path, ModeFlags modes, int perm, boolean hasOffset) { try { ChannelDescriptor descriptor = ChannelDescriptor.open( getRuntime().getCurrentDirectory(), @@ -1245,7 +1268,8 @@ private ChannelDescriptor sysopen(String path, ModeFlags modes, int perm) { modes, perm, getRuntime().getPosix(), - getRuntime().getJRubyClassLoader()); + getRuntime().getJRubyClassLoader(), + hasOffset); // TODO: check if too many open files, GC and try again diff --git a/src/org/jruby/RubyIO.java b/src/org/jruby/RubyIO.java index dab48ee571b..71a0fbd19ab 100644 --- a/src/org/jruby/RubyIO.java +++ b/src/org/jruby/RubyIO.java @@ -3605,11 +3605,17 @@ private static IRubyObject read19(ThreadContext context, IRubyObject recv, IRuby */ private static IRubyObject write19(ThreadContext context, IRubyObject recv, IRubyObject path, IRubyObject str, IRubyObject offset, RubyHash options) { // FIXME: process options + Ruby runtime = context.runtime; + + IRubyObject hasOffset = runtime.getNil(); + + if (!offset.isNil()) hasOffset = runtime.newBoolean(true); + else hasOffset = runtime.newBoolean(false); RubyString pathStr = RubyFile.get_path(context, path); - Ruby runtime = context.runtime; + failIfDirectory(runtime, pathStr); - RubyIO file = newFile(context, recv, pathStr, context.runtime.newString("w")); + RubyIO file = newFile(context, recv, pathStr, context.runtime.newString("w"), hasOffset); try { if (!offset.isNil()) file.seek(context, offset); diff --git a/src/org/jruby/util/io/ChannelDescriptor.java b/src/org/jruby/util/io/ChannelDescriptor.java index e8762cf78bd..2c92f1bf2fc 100644 --- a/src/org/jruby/util/io/ChannelDescriptor.java +++ b/src/org/jruby/util/io/ChannelDescriptor.java @@ -790,6 +790,10 @@ public static ChannelDescriptor open(String cwd, String path, ModeFlags flags, i * @throws java.io.IOException if there is an exception during IO */ public static ChannelDescriptor open(String cwd, String path, ModeFlags flags, int perm, POSIX posix, ClassLoader classLoader) throws FileNotFoundException, DirectoryAsFileException, FileExistsException, IOException { + return open(cwd, path, flags, perm, posix, classLoader, false); + } + + public static ChannelDescriptor open(String cwd, String path, ModeFlags flags, int perm, POSIX posix, ClassLoader classLoader, boolean hasOffset) throws FileNotFoundException, DirectoryAsFileException, FileExistsException, IOException { boolean fileCreated = false; if (path.equals("/dev/null") || path.equalsIgnoreCase("nul:") || path.equalsIgnoreCase("nul")) { Channel nullChannel = new NullChannel(); @@ -865,7 +869,7 @@ public static ChannelDescriptor open(String cwd, String path, ModeFlags flags, i FileChannel fileChannel; boolean isInAppendMode; if (flags.isWritable() && !flags.isReadable()) { - FileOutputStream fos = new FileOutputStream(theFile, flags.isAppendable()); + RandomAccessFile fos = new RandomAccessFile(theFile, flags.toJavaModeString()); fileChannel = fos.getChannel(); fileDescriptor = fos.getFD(); isInAppendMode = true; @@ -887,7 +891,7 @@ public static ChannelDescriptor open(String cwd, String path, ModeFlags flags, i } try { - if (flags.isTruncate()) fileChannel.truncate(0); + if (flags.isTruncate() && !hasOffset) fileChannel.truncate(0); } catch (IOException ioe) { if (ioe.getMessage().equals("Illegal seek")) { // ignore; it's a pipe or fifo that can't be truncated