diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-05-01 13:29:51 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-05-01 13:30:17 -0700 |
commit | b5ec116e331c22c064bee46f63145e325785e33f (patch) | |
tree | d51e6693303ba4cc473d13209fc6d27785d3664a | |
parent | b39448e121f8f060c274ee1ee3c473f7b20d92e1 (diff) | |
download | ruby_io_splice-b5ec116e331c22c064bee46f63145e325785e33f.tar.gz |
This is for compatibility with IO.copy_stream and IO#sendfile, both of which use pread()-semantics when given a source file offset. This allows multiple threads/processes to copy from the same file handle.
-rw-r--r-- | lib/io/splice.rb | 22 | ||||
-rw-r--r-- | test/test_io_splice.rb | 10 |
2 files changed, 21 insertions, 11 deletions
diff --git a/lib/io/splice.rb b/lib/io/splice.rb index ab8efaa..2dd88b9 100644 --- a/lib/io/splice.rb +++ b/lib/io/splice.rb @@ -35,15 +35,14 @@ module IO::Splice dst.kind_of?(String) and close << (dst = File.open(dst, "w")) src, dst = src.to_io, dst.to_io rv = len - src.sysseek(src_offset) if src_offset select_args = selectable(src, dst) if src.stat.pipe? || dst.stat.pipe? if len - len -= full(src, dst, len, select_args) until len == 0 + len -= full(src, dst, len, src_offset, select_args) until len == 0 else rv = 0 - while n = partial(src, dst, PIPE_CAPA, select_args) + while n = partial(src, dst, PIPE_CAPA, src_offset, select_args) rv += n end end @@ -51,13 +50,13 @@ module IO::Splice r, w = tmp = IO.pipe close.concat(tmp) if len - while len != 0 && n = partial(src, w, len, select_args) - len -= full(r, dst, n, select_args) + while len != 0 && n = partial(src, w, len, src_offset, select_args) + len -= full(r, dst, n, nil, select_args) end else rv = 0 - while n = partial(src, w, PIPE_CAPA, select_args) - rv += full(r, dst, n, select_args) + while n = partial(src, w, PIPE_CAPA, src_offset, select_args) + rv += full(r, dst, n, nil, select_args) end end end @@ -76,10 +75,10 @@ module IO::Splice # The +_select_args+ parameter is reserved for internal use and # may be removed in future versions. Do not write code that # depends on +_select_args+. - def self.full(src, dst, len, _select_args = selectable(src, dst)) + def self.full(src, dst, len, src_offset, _select_args = selectable(src, dst)) nr = len while nr > 0 - n = partial(src, dst, nr, _select_args) or + n = partial(src, dst, nr, src_offset, _select_args) or raise EOFError, "end of file reached" nr -= n end @@ -94,9 +93,10 @@ module IO::Splice # The +_select_args+ parameter is reserved for internal use and # may be removed in future versions. Do not write code that # depends on +_select_args+. - def self.partial(src, dst, len, _select_args = selectable(src, dst)) + def self.partial(src, dst, len, src_offset, + _select_args = selectable(src, dst)) begin - rv = IO.trysplice(src, nil, dst, nil, len, F_MOVE) + rv = IO.trysplice(src, src_offset, dst, nil, len, F_MOVE) end while rv == :EAGAIN and IO.select(*_select_args) rv end diff --git a/test/test_io_splice.rb b/test/test_io_splice.rb index eb4faeb..6943bf9 100644 --- a/test/test_io_splice.rb +++ b/test/test_io_splice.rb @@ -392,6 +392,16 @@ class Test_IO_Splice < Test::Unit::TestCase assert_equal 'world', b.read end + def test_splice_copy_stream_src_offset_unchanged + a = Tempfile.new('a') + b = Tempfile.new('a') + a.syswrite('hello world') + assert_equal 0, a.sysseek(0, IO::SEEK_SET) + IO::Splice.copy_stream(a, b.path, 5, 6) + assert_equal 'world', b.read + assert_equal 0, a.sysseek(0, IO::SEEK_CUR) + end + def test_copy_stream_nonblock_src server = TCPServer.new('127.0.0.1', 0) port = server.addr[1] |