This file is indexed.

/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