lib/io/splice.rb in io_splice-1.0.0 vs lib/io/splice.rb in io_splice-2.0.0

- old
+ new

@@ -3,17 +3,20 @@ class IO module Splice - # the version of IO::Splice, currently 0.1.0 - VERSION = '1.0.0' + # the version of IO::Splice, currently 2.0.0 + VERSION = '2.0.0' - # The maximum capacity of the pipe in bytes. + # The maximum default capacity of the pipe in bytes. # Under stock Linux, this is 65536 bytes as of 2.6.11, and 4096 before # We detect this at runtime as it is easy to recompile the kernel # and set a new value. + # Starting with Linux 2.6.35, pipe capacity will be tunable + # and this will only represent the default capacity of a + # newly-created pipe. PIPE_CAPA = begin rd, wr = IO.pipe buf = ' ' * PIPE_BUF n = 0 begin @@ -22,9 +25,73 @@ break end while true wr.close rd.close n + end + + # copies the contents of the IO object given by +src+ to +dst+ + # If len is specified, then only len bytes are copied. Otherwise + # the copy will be until EOF is reached on the +src+. + # +src+ and +dst+ must be IO objects or respond to +to_io+ + def self.copy_stream(src, dst, len = nil, src_offset = nil) + src.kind_of?(String) and src = File.open(src, 'rb') + dst.kind_of?(String) and dst = File.open(dst, 'wb') + src, dst = src.to_io, dst.to_io + rv = len + src.sysseek(src_offset) if src_offset + if src.stat.pipe? || dst.stat.pipe? + if len + while len > 0 + nr = len > PIPE_CAPA ? PIPE_CAPA : len + nr = IO.splice(src, nil, dst, nil, nr, F_MOVE) + if nr == 0 + raise EOFError, "unexpected EOF with #{len} bytes left" + end + len -= nr + end + else + rv = 0 + begin + nr = IO.splice(src, nil, dst, nil, PIPE_CAPA, F_MOVE) + rv += nr + rescue EOFError + break + end while true + end + else + begin + r, w = IO.pipe + if len + while len > 0 + nr = len > PIPE_CAPA ? PIPE_CAPA : len + nr_src = copy_stream(src, w, nr) + nr_src == nr or + raise RuntimeError, "short splice from: #{nr_src} != #{nr}" + nr_dst = copy_stream(r, dst, nr) + nr_dst == nr or + raise RuntimeError, "short splice to: #{nr_dst} != #{nr}" + len -= nr + end + else + rv = 0 + begin + nr = IO.splice(src, nil, w, nil, PIPE_CAPA, F_MOVE) + rv += nr + begin + nr -= IO.splice(r, nil, dst, nil, nr, F_MOVE) + end while nr > 0 + rescue EOFError + break + end while true + end + ensure + r.close + w.close + end + end + + rv end end end