lib/io/splice.rb in io_splice-2.2.0 vs lib/io/splice.rb in io_splice-2.2.0.18.g3025

- old
+ new

@@ -1,120 +1,114 @@ # -*- encoding: binary -*- require 'io_splice_ext' -class IO +module IO::Splice - module Splice + # the version of IO::Splice, currently 2.2.0 + VERSION = '2.2.0' - # the version of IO::Splice, currently 2.2.0 - VERSION = '2.2.0' + # 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 + n += wr.write_nonblock(buf) + rescue Errno::EAGAIN + break + end while true + wr.close + rd.close + n + end - # 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 - n += wr.write_nonblock(buf) - rescue Errno::EAGAIN - 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 and + # +EOFError+ is raised if fewer than +len+ bytes could be 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) + close = [] + src.kind_of?(String) and close << (src = File.open(src)) + 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) - # 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 Splice.copy_stream(src, dst, len = nil, src_offset = nil) - close = [] - src.kind_of?(String) and close << (src = File.open(src, 'rb')) - dst.kind_of?(String) and close << (dst = File.open(dst, 'wb')) - 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 - else - rv = 0 - begin - rv += partial(src, dst, PIPE_CAPA, select_args) - rescue EOFError - break - end while true + if src.stat.pipe? || dst.stat.pipe? + if len + len -= full(src, dst, len, select_args) until len == 0 + else + rv = 0 + while n = partial(src, dst, PIPE_CAPA, select_args) + rv += n end + end + else + 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) + end else - r, w = tmp = IO.pipe - close.concat(tmp) - if len - while len != 0 - nr = partial(src, w, len, select_args) - len -= full(r, dst, nr, select_args) - end - else - rv = 0 - begin - nr = partial(src, w, PIPE_CAPA, select_args) - rv += full(r, dst, nr, select_args) - rescue EOFError - break - end while true + rv = 0 + while n = partial(src, w, PIPE_CAPA, select_args) + rv += full(r, dst, n, select_args) end end - - rv - ensure - close.each { |io| io.close } end - # splice the full amount specified from +src+ to +dst+ - # Either +dst+ or +src+ must be a pipe. +dst+ and +src+ - # may BOTH be pipes in Linux 2.6.31 or later. - # This will block and wait for IO completion of +len+ - # bytes. Returns the nubmer of bytes actually spliced (always +len+) - # 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 Splice.full(src, dst, len, _select_args = selectable(src, dst)) - nr = len - nr -= partial(src, dst, nr, _select_args) until nr == 0 - len - end + rv + ensure + close.each { |io| io.close } + end - # splice up to +len+ bytes from +src+ to +dst+. - # Either +dst+ or +src+ must be a pipe. +dst+ and +src+ - # may BOTH be pipes in Linux 2.6.31 or later. - # Returns the number of bytes actually spliced. - # Like IO#readpartial, this never returns Errno::EAGAIN - # 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 Splice.partial(src, dst, len, _select_args = selectable(src, dst)) - begin - IO.splice(src, nil, dst, nil, len, F_MOVE) - rescue Errno::EAGAIN - IO.select(*_select_args) - retry - end + # splice the full amount specified from +src+ to +dst+ + # Either +dst+ or +src+ must be a pipe. +dst+ and +src+ + # may BOTH be pipes in Linux 2.6.31 or later. + # This will block and wait for IO completion of +len+ + # Raises +EOFError+ if end of file is reached. + # bytes. Returns the number of bytes actually spliced (always +len+) + # 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)) + nr = len + while nr > 0 + n = partial(src, dst, nr, _select_args) or + raise EOFError, "end of file reached" + nr -= n end + len + end - # returns an array suitable for splat-ing to IO.select for blocking I/O - def Splice.selectable(src, dst) - rv = [] - src.stat.pipe? or rv[0] = [ src ] - dst.stat.pipe? or rv[1] = [ dst ] - rv - end + # splice up to +len+ bytes from +src+ to +dst+. + # Either +dst+ or +src+ must be a pipe. +dst+ and +src+ + # may BOTH be pipes in Linux 2.6.31 or later. + # Returns the number of bytes actually spliced. + # Like IO#readpartial, this never returns Errno::EAGAIN + # 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)) + begin + rv = IO.trysplice(src, nil, dst, nil, len, F_MOVE) + end while rv == :EAGAIN and IO.select(*_select_args) + rv + end + # returns an array suitable for splat-ing to IO.select for blocking I/O + def self.selectable(src, dst) + rv = [] + src.stat.pipe? or rv[0] = [ src ] + dst.stat.pipe? or rv[1] = [ dst ] + rv end end