This file is indexed.

/usr/lib/ruby/vendor_ruby/childprocess/windows/lib.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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
module ChildProcess
  module Windows
    FORMAT_MESSAGE_FROM_SYSTEM            = 0x00001000
    FORMAT_MESSAGE_ARGUMENT_ARRAY         = 0x00002000

    PROCESS_ALL_ACCESS                    = 0x1F0FFF
    PROCESS_QUERY_INFORMATION             = 0x0400
    PROCESS_VM_READ                       = 0x0010
    PROCESS_STILL_ACTIVE                  = 259

    INFINITE                              = 0xFFFFFFFF

    WIN_SIGINT                            = 2
    WIN_SIGBREAK                          = 3
    WIN_SIGKILL                           = 9

    CTRL_C_EVENT                          = 0
    CTRL_BREAK_EVENT                      = 1

    CREATE_BREAKAWAY_FROM_JOB             = 0x01000000
    DETACHED_PROCESS                      = 0x00000008

    STARTF_USESTDHANDLES                  = 0x00000100
    INVALID_HANDLE_VALUE                  = -1
    HANDLE_FLAG_INHERIT                   = 0x00000001

    DUPLICATE_SAME_ACCESS                 = 0x00000002
    CREATE_UNICODE_ENVIRONMENT            = 0x00000400

    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE    = 0x2000
    JOB_OBJECT_EXTENDED_LIMIT_INFORMATION = 9
    JOB_OBJECT_BASIC_LIMIT_INFORMATION    = 2

    module Lib
      enum :wait_status, [
        :wait_object_0,  0,
        :wait_timeout,   0x102,
        :wait_abandoned, 0x80,
        :wait_failed,    0xFFFFFFFF
      ]

      #
      # BOOL WINAPI CreateProcess(
      #   __in_opt     LPCTSTR lpApplicationName,
      #   __inout_opt  LPTSTR lpCommandLine,
      #   __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
      #   __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
      #   __in         BOOL bInheritHandles,
      #   __in         DWORD dwCreationFlags,
      #   __in_opt     LPVOID lpEnvironment,
      #   __in_opt     LPCTSTR lpCurrentDirectory,
      #   __in         LPSTARTUPINFO lpStartupInfo,
      #   __out        LPPROCESS_INFORMATION lpProcessInformation
      # );
      #

      attach_function :create_process, :CreateProcessA, [
        :pointer,
        :pointer,
        :pointer,
        :pointer,
        :bool,
        :ulong,
        :pointer,
        :pointer,
        :pointer,
        :pointer], :bool

      #
      #   DWORD WINAPI FormatMessage(
      #   __in      DWORD dwFlags,
      #   __in_opt  LPCVOID lpSource,
      #   __in      DWORD dwMessageId,
      #   __in      DWORD dwLanguageId,
      #   __out     LPTSTR lpBuffer,
      #   __in      DWORD nSize,
      #   __in_opt  va_list *Arguments
      # );
      #

      attach_function :format_message, :FormatMessageA, [
        :ulong,
        :pointer,
        :ulong,
        :ulong,
        :pointer,
        :ulong,
        :pointer], :ulong


      attach_function :close_handle, :CloseHandle, [:pointer], :bool

      #
      # HANDLE WINAPI OpenProcess(
      #   __in  DWORD dwDesiredAccess,
      #   __in  BOOL bInheritHandle,
      #   __in  DWORD dwProcessId
      # );
      #

      attach_function :open_process, :OpenProcess, [:ulong, :bool, :ulong], :pointer

      #
      # HANDLE WINAPI CreateJobObject(
      #   _In_opt_  LPSECURITY_ATTRIBUTES lpJobAttributes,
      #   _In_opt_  LPCTSTR lpName
      # );
      #

      attach_function :create_job_object, :CreateJobObjectA, [:pointer, :pointer], :pointer

      #
      # BOOL WINAPI AssignProcessToJobObject(
      #   _In_  HANDLE hJob,
      #   _In_  HANDLE hProcess
      # );

      attach_function :assign_process_to_job_object, :AssignProcessToJobObject, [:pointer, :pointer], :bool

      #
      # BOOL WINAPI SetInformationJobObject(
      #   _In_  HANDLE hJob,
      #   _In_  JOBOBJECTINFOCLASS JobObjectInfoClass,
      #   _In_  LPVOID lpJobObjectInfo,
      #   _In_  DWORD cbJobObjectInfoLength
      # );
      #

      attach_function :set_information_job_object, :SetInformationJobObject, [:pointer, :int, :pointer, :ulong], :bool

      #
      #
      # DWORD WINAPI WaitForSingleObject(
      #   __in  HANDLE hHandle,
      #   __in  DWORD dwMilliseconds
      # );
      #

      attach_function :wait_for_single_object, :WaitForSingleObject, [:pointer, :ulong], :wait_status, :blocking => true

      #
      # BOOL WINAPI GetExitCodeProcess(
      #   __in   HANDLE hProcess,
      #   __out  LPDWORD lpExitCode
      # );
      #

      attach_function :get_exit_code, :GetExitCodeProcess, [:pointer, :pointer], :bool

      #
      # BOOL WINAPI GenerateConsoleCtrlEvent(
      #   __in  DWORD dwCtrlEvent,
      #   __in  DWORD dwProcessGroupId
      # );
      #

      attach_function :generate_console_ctrl_event, :GenerateConsoleCtrlEvent, [:ulong, :ulong], :bool

      #
      # BOOL WINAPI TerminateProcess(
      #   __in  HANDLE hProcess,
      #   __in  UINT uExitCode
      # );
      #

      attach_function :terminate_process, :TerminateProcess, [:pointer, :uint], :bool

      #
      # intptr_t _get_osfhandle(
      #    int fd
      # );
      #

      attach_function :get_osfhandle, :_get_osfhandle, [:int], :intptr_t

      #
      # int _open_osfhandle (
      #    intptr_t osfhandle,
      #    int flags
      # );
      #

      attach_function :open_osfhandle, :_open_osfhandle, [:pointer, :int], :int

      # BOOL WINAPI SetHandleInformation(
      #   __in  HANDLE hObject,
      #   __in  DWORD dwMask,
      #   __in  DWORD dwFlags
      # );

      attach_function :set_handle_information, :SetHandleInformation, [:pointer, :ulong, :ulong], :bool

      # BOOL WINAPI GetHandleInformation(
      #   __in   HANDLE hObject,
      #   __out  LPDWORD lpdwFlags
      # );

      attach_function :get_handle_information, :GetHandleInformation, [:pointer, :pointer], :bool

      # BOOL WINAPI CreatePipe(
      #   __out     PHANDLE hReadPipe,
      #   __out     PHANDLE hWritePipe,
      #   __in_opt  LPSECURITY_ATTRIBUTES lpPipeAttributes,
      #   __in      DWORD nSize
      # );

      attach_function :create_pipe, :CreatePipe, [:pointer, :pointer, :pointer, :ulong], :bool

      #
      # HANDLE WINAPI GetCurrentProcess(void);
      #

      attach_function :current_process, :GetCurrentProcess, [], :pointer

      #
      # BOOL WINAPI DuplicateHandle(
      #   __in   HANDLE hSourceProcessHandle,
      #   __in   HANDLE hSourceHandle,
      #   __in   HANDLE hTargetProcessHandle,
      #   __out  LPHANDLE lpTargetHandle,
      #   __in   DWORD dwDesiredAccess,
      #   __in   BOOL bInheritHandle,
      #   __in   DWORD dwOptions
      # );
      #

      attach_function :_duplicate_handle, :DuplicateHandle, [
        :pointer,
        :pointer,
        :pointer,
        :pointer,
        :ulong,
        :bool,
        :ulong
      ], :bool

      class << self
        def kill(signal, *pids)
          case signal
          when 'SIGINT', 'INT', :SIGINT, :INT
            signal = WIN_SIGINT
          when 'SIGBRK', 'BRK', :SIGBREAK, :BRK
            signal = WIN_SIGBREAK
          when 'SIGKILL', 'KILL', :SIGKILL, :KILL
            signal = WIN_SIGKILL
          when 0..9
            # Do nothing
          else
            raise Error, "invalid signal #{signal.inspect}"
          end

          pids.map { |pid| pid if Lib.send_signal(signal, pid) }.compact
        end

        def waitpid(pid, flags = 0)
          wait_for_pid(pid, no_hang?(flags))
        end

        def waitpid2(pid, flags = 0)
          code = wait_for_pid(pid, no_hang?(flags))

          [pid, code] if code
        end

        def dont_inherit(file)
          unless file.respond_to?(:fileno)
            raise ArgumentError, "expected #{file.inspect} to respond to :fileno"
          end

          set_handle_inheritance(handle_for(file.fileno), false)
        end

        def last_error_message
          errnum = FFI.errno

          buf = FFI::MemoryPointer.new :char, 512

          size = format_message(
            FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
            nil, errnum, 0, buf, buf.size, nil
          )

          str = buf.read_string(size).strip
          if errnum == 0
            "Unknown error (Windows says #{str.inspect}, but it did not.)"
          else
            "#{str} (#{errnum})"
          end
        end

        def each_child_of(pid, &blk)
          raise NotImplementedError

          # http://stackoverflow.com/questions/1173342/terminate-a-process-tree-c-for-windows?rq=1

          # for each process entry
          #  if pe.th32ParentProcessID == pid
          #    Handle.open(pe.pe.th32ProcessId, &blk)
          #  end
          #
        end

        def handle_for(fd_or_io)
          if fd_or_io.kind_of?(IO) || fd_or_io.respond_to?(:fileno)
            if ChildProcess.jruby?
              handle = ChildProcess::JRuby.windows_handle_for(fd_or_io)
            else
              handle = get_osfhandle(fd_or_io.fileno)
            end
          elsif fd_or_io.kind_of?(Fixnum)
            handle = get_osfhandle(fd_or_io)
          elsif fd_or_io.respond_to?(:to_io)
            io = fd_or_io.to_io

            unless io.kind_of?(IO)
              raise TypeError, "expected #to_io to return an instance of IO"
            end

            handle = get_osfhandle(io.fileno)
          else
            raise TypeError, "invalid type: #{fd_or_io.inspect}"
          end

          if handle == INVALID_HANDLE_VALUE
            raise Error, last_error_message
          end

          FFI::Pointer.new handle
        end

        def io_for(handle, flags = File::RDONLY)
          fd = open_osfhandle(handle, flags)
          if fd == -1
            raise Error, last_error_message
          end

          FFI::IO.for_fd fd, flags
        end

        def duplicate_handle(handle)
          dup  = FFI::MemoryPointer.new(:pointer)
          proc = current_process

          ok = Lib._duplicate_handle(
            proc,
            handle,
            proc,
            dup,
            0,
            false,
            DUPLICATE_SAME_ACCESS
          )

          check_error ok

          dup.read_pointer
        ensure
          close_handle proc
        end

        def set_handle_inheritance(handle, bool)
          status = set_handle_information(
            handle,
            HANDLE_FLAG_INHERIT,
            bool ? HANDLE_FLAG_INHERIT : 0
          )

          check_error status
        end

        def get_handle_inheritance(handle)
          flags = FFI::MemoryPointer.new(:uint)

          status = get_handle_information(
            handle,
            flags
          )

          check_error status

          flags.read_uint
        end

        def check_error(bool)
          bool or raise Error, last_error_message
        end

        def alive?(pid)
          handle = Lib.open_process(PROCESS_ALL_ACCESS, false, pid)
          if handle.null?
            false
          else
            ptr = FFI::MemoryPointer.new :ulong
            Lib.check_error Lib.get_exit_code(handle, ptr)
            ptr.read_ulong == PROCESS_STILL_ACTIVE
          end
        end

        def no_hang?(flags)
          (flags & Process::WNOHANG) == Process::WNOHANG
        end

        def wait_for_pid(pid, no_hang)
          code = Handle.open(pid) { |handle|
            handle.wait unless no_hang
            handle.exit_code
          }

          code if code != PROCESS_STILL_ACTIVE
        end
      end

    end # Lib
  end # Windows
end # ChildProcess