Skip to content

Commit

Permalink
Fix IO.copy_stream with a Tempfile destination
Browse files Browse the repository at this point in the history
* Fixes #3280
  • Loading branch information
eregon committed Oct 2, 2023
1 parent c6e6162 commit fdd4610
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ New features:
Bug fixes:

* Fix `rb_enc_left_char_head()` so it is not always `ArgumentError` (#3267, @eregon).
* Fix `IO.copy_stream` with a `Tempfile` destination (#3280, @eregon).

Compatibility:

Expand Down
33 changes: 27 additions & 6 deletions spec/ruby/core/io/copy_stream_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,12 @@
end

it "raises an IOError if the destination IO is not open for writing" do
@to_io.close
@to_io = new_io @to_name, "r"
-> { IO.copy_stream @object.from, @to_io }.should raise_error(IOError)
to_io = new_io __FILE__, "r"
begin
-> { IO.copy_stream @object.from, to_io }.should raise_error(IOError)
ensure
to_io.close
end
end

it "does not close the destination IO" do
Expand Down Expand Up @@ -109,7 +112,8 @@
end

after :each do
rm_r @to_name, @from_bigfile
rm_r @to_name if @to_name
rm_r @from_bigfile
end

describe "from an IO" do
Expand Down Expand Up @@ -164,6 +168,25 @@
it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
end

describe "to a Tempfile" do
before :all do
require 'tempfile'
end

before :each do
@to_io = Tempfile.new("rubyspec_copy_stream", encoding: Encoding::BINARY, mode: File::RDONLY)
@to_name = @to_io.path
end

after :each do
@to_io.close!
@to_name = nil # do not rm_r it, already done by Tempfile#close!
end

it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
end
end

describe "from a file name" do
Expand Down Expand Up @@ -277,10 +300,8 @@
@io.should_not_receive(:pos)
IO.copy_stream(@io, @to_name)
end

end


describe "with a destination that does partial reads" do
before do
@from_out, @from_in = IO.pipe
Expand Down
25 changes: 10 additions & 15 deletions src/main/ruby/truffleruby/core/io.rb
Original file line number Diff line number Diff line change
Expand Up @@ -356,24 +356,19 @@ def initialize(from, to, length, offset)
@method = read_method @from
end

# From copy_stream_body in io.c in CRuby
# The first element is true if obj can be used as an IO directly
def to_io(obj, mode)
if Primitive.is_a?(obj, IO)
flag = true
io = obj
io = IO.try_convert(obj)
if io
[true, io]
elsif Primitive.is_a?(obj, String) or obj.respond_to? :to_path
path = Truffle::Type.coerce_to obj, String, :to_path
io = File.open path, mode
[false, io]
else
flag = false

if Primitive.is_a?(obj, String)
io = File.open obj, mode
elsif obj.respond_to? :to_path
path = Truffle::Type.coerce_to obj, String, :to_path
io = File.open path, mode
else
io = obj
end
[false, obj]
end

[flag, io]
end

def read_method(obj)
Expand Down

0 comments on commit fdd4610

Please sign in to comment.