/usr/lib/ruby/vendor_ruby/childprocess/windows/process_builder.rb is in ruby-childprocess 0.5.9-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | module ChildProcess
module Windows
class ProcessBuilder
attr_accessor :detach, :duplex, :environment, :stdout, :stderr, :cwd
attr_reader :stdin
def initialize(args)
@args = args
@detach = false
@duplex = false
@environment = nil
@cwd = nil
@stdout = nil
@stderr = nil
@stdin = nil
@flags = 0
@job_ptr = nil
@cmd_ptr = nil
@env_ptr = nil
@cwd_ptr = nil
end
def start
create_command_pointer
create_environment_pointer
create_cwd_pointer
setup_flags
setup_io
pid = create_process
close_handles
pid
end
private
def create_command_pointer
string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join ' '
@cmd_ptr = FFI::MemoryPointer.from_string string
end
def create_environment_pointer
return unless @environment.kind_of?(Hash) && @environment.any?
strings = []
ENV.to_hash.merge(@environment).each do |key, val|
next if val.nil?
if key.to_s =~ /=|\0/ || val.to_s.include?("\0")
raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.inspect}"
end
strings << "#{key}=#{val}\0"
end
strings << "\0" # terminate the env block
env_str = strings.join
@env_ptr = FFI::MemoryPointer.new(:long, env_str.bytesize)
@env_ptr.put_bytes 0, env_str, 0, env_str.bytesize
end
def create_cwd_pointer
@cwd_ptr = FFI::MemoryPointer.from_string(@cwd || Dir.pwd)
end
def create_process
ok = Lib.create_process(
nil, # application name
@cmd_ptr, # command line
nil, # process attributes
nil, # thread attributes
true, # inherit handles
@flags, # creation flags
@env_ptr, # environment
@cwd_ptr, # current directory
startup_info, # startup info
process_info # process info
)
ok or raise LaunchError, Lib.last_error_message
process_info[:dwProcessId]
end
def startup_info
@startup_info ||= StartupInfo.new
end
def process_info
@process_info ||= ProcessInfo.new
end
def setup_flags
@flags |= DETACHED_PROCESS if @detach
end
def setup_io
startup_info[:dwFlags] ||= 0
startup_info[:dwFlags] |= STARTF_USESTDHANDLES
if @stdout
startup_info[:hStdOutput] = std_stream_handle_for(@stdout)
end
if @stderr
startup_info[:hStdError] = std_stream_handle_for(@stderr)
end
if @duplex
read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
sa = SecurityAttributes.new(:inherit => true)
ok = Lib.create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
Lib.check_error ok
@read_pipe = read_pipe_ptr.read_pointer
@write_pipe = write_pipe_ptr.read_pointer
Lib.set_handle_inheritance @read_pipe, true
Lib.set_handle_inheritance @write_pipe, false
startup_info[:hStdInput] = @read_pipe
else
startup_info[:hStdInput] = std_stream_handle_for(STDIN)
end
end
def std_stream_handle_for(io)
handle = Lib.handle_for(io)
begin
Lib.set_handle_inheritance handle, true
rescue ChildProcess::Error
# If the IO was set to close on exec previously, this call will fail.
# That's probably OK, since the user explicitly asked for it to be
# closed (at least I have yet to find other cases where this will
# happen...)
end
handle
end
def close_handles
Lib.close_handle process_info[:hProcess]
Lib.close_handle process_info[:hThread]
if @duplex
@stdin = Lib.io_for(Lib.duplicate_handle(@write_pipe), File::WRONLY)
Lib.close_handle @read_pipe
Lib.close_handle @write_pipe
end
end
def quote_if_necessary(str)
quote = str.start_with?('"') ? "'" : '"'
case str
when /[\s\\'"]/
[quote, str, quote].join
else
str
end
end
end # ProcessBuilder
end # Windows
end # ChildProcess
|