Skip to content
This repository

Bunch of fixes for IO.copy_stream #466

Merged
merged 5 commits into from over 1 year ago

2 participants

Alex Tambellini Thomas E Enebo
Alex Tambellini
Collaborator

No description provided.

Alex Tambellini
Collaborator

@BanzaiMan, anything blocking this from being merged?

Deleted user

I gave everything a cursory glance, and it seems ok. I think some of the changes in that last commit are a bit ... smelly.

Thomas E Enebo enebo merged commit 5fae685 into from
Thomas E Enebo enebo closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
30 spec/tags/1.9/ruby/core/io/copy_stream_tags.txt
... ... @@ -1,32 +1,2 @@
1   -fails:IO.copy_stream from an IO raises an IOError if the source IO is not open for reading
2   -fails:IO.copy_stream from an IO does not close the source IO
3   -fails:IO.copy_stream from an IO does not change the IO offset when an offset is specified
4   -fails:IO.copy_stream from an IO does change the IO offset when an offset is not specified
5   -fails:IO.copy_stream from an IO to a file name copies the entire IO contents to the file
6   -fails:IO.copy_stream from an IO to a file name returns the number of bytes copied
7   -fails:IO.copy_stream from an IO to a file name copies only length bytes when specified
8   -fails:IO.copy_stream from an IO to a file name copies only length bytes from the offset
9   -fails:IO.copy_stream from an IO to a file name calls #to_path to convert on object to a file name
10   -fails:IO.copy_stream from an IO to a file name raises a TypeError if #to_path does not return a String
11   -fails:IO.copy_stream from an IO to an IO copies the entire IO contents to the IO
12   -fails:IO.copy_stream from an IO to an IO returns the number of bytes copied
13 1 fails:IO.copy_stream from an IO to an IO starts writing at the destination IO's current position
14   -fails:IO.copy_stream from an IO to an IO leaves the destination IO position at the last write
15   -fails:IO.copy_stream from an IO to an IO raises an IOError if the destination IO is not open for writing
16   -fails:IO.copy_stream from an IO to an IO does not close the destination IO
17   -fails:IO.copy_stream from an IO to an IO copies only length bytes when specified
18   -fails:IO.copy_stream from an IO to an IO copies only length bytes from the offset
19   -fails:IO.copy_stream from a file name calls #to_path to convert on object to a file name
20   -fails:IO.copy_stream from a file name raises a TypeError if #to_path does not return a String
21   -fails:IO.copy_stream from a file name to a file name copies only length bytes when specified
22   -fails:IO.copy_stream from a file name to a file name copies only length bytes from the offset
23   -fails:IO.copy_stream from a file name to a file name calls #to_path to convert on object to a file name
24   -fails:IO.copy_stream from a file name to a file name raises a TypeError if #to_path does not return a String
25   -fails:IO.copy_stream from a file name to an IO copies the entire IO contents to the IO
26   -fails:IO.copy_stream from a file name to an IO returns the number of bytes copied
27 2 fails:IO.copy_stream from a file name to an IO starts writing at the destination IO's current position
28   -fails:IO.copy_stream from a file name to an IO leaves the destination IO position at the last write
29   -fails:IO.copy_stream from a file name to an IO raises an IOError if the destination IO is not open for writing
30   -fails:IO.copy_stream from a file name to an IO does not close the destination IO
31   -fails:IO.copy_stream from a file name to an IO copies only length bytes when specified
32   -fails:IO.copy_stream from a file name to an IO copies only length bytes from the offset
58 src/org/jruby/RubyIO.java
@@ -4136,37 +4136,56 @@ public static IRubyObject pipe19(ThreadContext context, IRubyObject recv, IRubyO
4136 4136 return pipe19(context, recv, modes);
4137 4137 }
4138 4138
4139   - @JRubyMethod(name = "copy_stream", meta = true, compat = RUBY1_9)
  4139 + @JRubyMethod(name = "copy_stream", required = 2, optional = 2, meta = true, compat = RUBY1_9)
4140 4140 public static IRubyObject copy_stream(ThreadContext context, IRubyObject recv,
4141   - IRubyObject arg1, IRubyObject arg2) {
  4141 + IRubyObject[] args) {
4142 4142 Ruby runtime = context.runtime;
4143 4143
  4144 + IRubyObject arg1 = args[0];
  4145 + IRubyObject arg2 = args[1];
  4146 +
  4147 + RubyInteger length = null;
  4148 + RubyInteger offset = null;
  4149 +
4144 4150 RubyIO io1 = null;
4145 4151 RubyIO io2 = null;
4146 4152
  4153 + if (args.length >= 3) {
  4154 + length = args[2].convertToInteger();
  4155 + if (args.length == 4) {
  4156 + offset = args[3].convertToInteger();
  4157 + }
  4158 + }
  4159 +
4147 4160 try {
4148 4161 if (arg1 instanceof RubyString) {
4149 4162 io1 = (RubyIO) RubyFile.open(context, runtime.getFile(), new IRubyObject[] {arg1}, Block.NULL_BLOCK);
4150 4163 } else if (arg1 instanceof RubyIO) {
4151 4164 io1 = (RubyIO) arg1;
  4165 + } else if (arg1.respondsTo("to_path")) {
  4166 + RubyString path = (RubyString) TypeConverter.convertToType19(arg1, runtime.getString(), "to_path");
  4167 + io1 = (RubyIO) RubyFile.open(context, runtime.getFile(), new IRubyObject[] {path}, Block.NULL_BLOCK);
4152 4168 } else {
4153   - throw runtime.newTypeError("Should be String or IO");
  4169 + throw runtime.newArgumentError("Should be String or IO");
4154 4170 }
4155 4171
4156 4172 if (arg2 instanceof RubyString) {
4157 4173 io2 = (RubyIO) RubyFile.open(context, runtime.getFile(), new IRubyObject[] {arg2, runtime.newString("w")}, Block.NULL_BLOCK);
4158 4174 } else if (arg2 instanceof RubyIO) {
4159 4175 io2 = (RubyIO) arg2;
  4176 + } else if (arg2.respondsTo("to_path")) {
  4177 + RubyString path = (RubyString) TypeConverter.convertToType19(arg2, runtime.getString(), "to_path");
  4178 + io2 = (RubyIO) RubyFile.open(context, runtime.getFile(), new IRubyObject[] {path, runtime.newString("w")}, Block.NULL_BLOCK);
4160 4179 } else {
4161   - throw runtime.newTypeError("Should be String or IO");
  4180 + throw runtime.newArgumentError("Should be String or IO");
4162 4181 }
4163 4182
  4183 + if (!io1.openFile.isReadable()) throw runtime.newIOError("from IO is not readable");
  4184 + if (!io2.openFile.isWritable()) throw runtime.newIOError("to IO is not writable");
  4185 +
4164 4186 ChannelDescriptor d1 = io1.openFile.getMainStreamSafe().getDescriptor();
4165 4187 ChannelDescriptor d2 = io2.openFile.getMainStreamSafe().getDescriptor();
4166 4188
4167   - if (!d1.isReadable()) throw runtime.newIOError("from IO is not readable");
4168   - if (!d2.isWritable()) throw runtime.newIOError("from IO is not writable");
4169   -
4170 4189 try {
4171 4190 long size = 0;
4172 4191 if (!d1.isSeekable()) {
@@ -4182,7 +4201,7 @@ public static IRubyObject copy_stream(ThreadContext context, IRubyObject recv,
4182 4201 FileChannel from = (FileChannel)d1.getChannel();
4183 4202 WritableByteChannel to = (WritableByteChannel)d2.getChannel();
4184 4203
4185   - size = transfer(from, to);
  4204 + size = transfer(from, to, length, offset);
4186 4205 }
4187 4206
4188 4207 return context.runtime.newFixnum(size);
@@ -4191,16 +4210,6 @@ public static IRubyObject copy_stream(ThreadContext context, IRubyObject recv,
4191 4210 }
4192 4211 } catch (BadDescriptorException e) {
4193 4212 throw runtime.newErrnoEBADFError();
4194   - } finally {
4195   - try {
4196   - if (io1 != null) {
4197   - io1.close();
4198   - }
4199   - } finally {
4200   - if (io2 != null) {
4201   - io2.close();
4202   - }
4203   - }
4204 4213 }
4205 4214 }
4206 4215
@@ -4214,14 +4223,11 @@ private static long transfer(ReadableByteChannel from, FileChannel to) throws IO
4214 4223 return transferred;
4215 4224 }
4216 4225
4217   - private static long transfer(FileChannel from, WritableByteChannel to) throws IOException {
4218   -
4219   -
  4226 + private static long transfer(FileChannel from, WritableByteChannel to, RubyInteger length, RubyInteger offset) throws IOException {
4220 4227 // handle large files on 32-bit JVMs
4221 4228 long chunkSize = 128 * 1024 * 1024;
4222   - long size = from.size();
4223   - long remaining = size;
4224   - long position = from.position();
  4229 + long remaining = length == null ? from.size() : length.getLongValue();
  4230 + long position = offset == null? from.position() : offset.getLongValue();
4225 4231 long transferred = 0;
4226 4232
4227 4233 while (remaining > 0) {
@@ -4235,6 +4241,10 @@ private static long transfer(FileChannel from, WritableByteChannel to) throws IO
4235 4241 remaining -= n;
4236 4242 transferred += n;
4237 4243 }
  4244 +
  4245 + if (offset == null) {
  4246 + from.position(from.position() + transferred);
  4247 + }
4238 4248
4239 4249 return transferred;
4240 4250 }

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.