1 # -*- encoding: binary -*-
2 require 'io_splice_ext'
6 # The maximum default capacity of the pipe in bytes.
7 # Under stock Linux, this is 65536 bytes as of 2.6.11, and 4096 before
8 # We detect this at runtime as it is easy to recompile the kernel
10 # Starting with Linux 2.6.35, pipe capacity will be tunable
11 # and this will only represent the default capacity of a
18 n += wr.write_nonblock(buf)
27 # copies the contents of the IO object given by +src+ to +dst+
28 # If +len+ is specified, then only +len+ bytes are copied and
29 # +EOFError+ is raised if fewer than +len+ bytes could be copied.
30 # Otherwise the copy will be until EOF is reached on the +src+.
31 # +src+ and +dst+ must be IO objects or respond to +to_io+
33 # This is nearly a drop-in replacement for IO.copy_stream (in Ruby 1.9)
34 # but does not take into account userspace I/O buffers nor IO-like
35 # objects with no underlying file descriptor (e.g. StringIO).
36 def self.copy_stream(src, dst, len = nil, src_offset = nil)
38 src.kind_of?(String) and close << (src = File.open(src))
39 dst.kind_of?(String) and close << (dst = File.open(dst, "w"))
40 src, dst = src.to_io, dst.to_io
42 select_args = selectable(src, dst)
44 if src.stat.pipe? || dst.stat.pipe?
46 len -= full(src, dst, len, src_offset, select_args) until len == 0
49 while n = partial(src, dst, PIPE_CAPA, src_offset, select_args)
57 while len != 0 && n = partial(src, w, len, src_offset, select_args)
58 len -= full(r, dst, n, nil, select_args)
62 while n = partial(src, w, PIPE_CAPA, src_offset, select_args)
63 rv += full(r, dst, n, nil, select_args)
70 close.each { |io| io.close }
73 # splice the full amount specified from +src+ to +dst+
74 # Either +dst+ or +src+ must be a pipe. +dst+ and +src+
75 # may BOTH be pipes in Linux 2.6.31 or later.
76 # This will block and wait for IO completion of +len+
77 # Raises +EOFError+ if end of file is reached.
78 # bytes. Returns the number of bytes actually spliced (always +len+)
79 # The +_select_args+ parameter is reserved for internal use and
80 # may be removed in future versions. Do not write code that
81 # depends on +_select_args+.
82 def self.full(src, dst, len, src_offset, _select_args = selectable(src, dst))
85 n = partial(src, dst, nr, src_offset, _select_args) or
86 raise EOFError, "end of file reached"
92 # splice up to +len+ bytes from +src+ to +dst+.
93 # Either +dst+ or +src+ must be a pipe. +dst+ and +src+
94 # may BOTH be pipes in Linux 2.6.31 or later.
95 # Returns the number of bytes actually spliced.
96 # Like IO#readpartial, this never returns Errno::EAGAIN
97 # The +_select_args+ parameter is reserved for internal use and
98 # may be removed in future versions. Do not write code that
99 # depends on +_select_args+.
100 def self.partial(src, dst, len, src_offset,
101 _select_args = selectable(src, dst))
103 rv = IO.trysplice(src, src_offset, dst, nil, len, F_MOVE)
104 end while rv == :EAGAIN and IO.select(*_select_args)
108 # returns an array suitable for splat-ing to IO.select for blocking I/O
109 def self.selectable(src, dst) # :nodoc:
111 src.stat.pipe? or rv[0] = [ src ]
112 dst.stat.pipe? or rv[1] = [ dst ]