def _spawnAsBatch(self, processProtocol, executable, args, env, path, usePTY): """A cheat that routes around the impedance mismatch between twisted and cmd.exe with respect to escaping quotes""" tf = NamedTemporaryFile(dir='.', suffix=".bat", delete=False) # echo off hides this cheat from the log files. tf.write("@echo off\n") if type(self.command) in types.StringTypes: tf.write(self.command) else: def maybe_escape_pipes(arg): if arg != '|': return arg.replace('|', '^|') else: return '|' cmd = [maybe_escape_pipes(arg) for arg in self.command] tf.write(quoteArguments(cmd)) tf.close() argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args if '/c' not in argv: argv += ['/c'] argv += [tf.name] def unlink_temp(result): os.unlink(tf.name) return result self.deferred.addBoth(unlink_temp) return reactor.spawnProcess(processProtocol, executable, argv, env, path, usePTY=usePTY)
def escape_arg(arg): arg = bytes2NativeString(arg, unicode_encoding) arg = quoteArguments([arg]) # escape shell special characters arg = re.sub(r'[@()^"<>&|]', r'^\g<0>', arg) # prevent variable expansion return arg.replace('%', '%%')
def _spawnAsBatch(self, processProtocol, executable, args, env, path, usePTY): """A cheat that routes around the impedance mismatch between twisted and cmd.exe with respect to escaping quotes""" tf = NamedTemporaryFile(dir='.',suffix=".bat",delete=False) #echo off hides this cheat from the log files. tf.write( "@echo off\n" ) if type(self.command) in types.StringTypes: tf.write( self.command ) else: def maybe_escape_pipes(arg): if arg != '|': return arg.replace('|','^|') else: return '|' cmd = [maybe_escape_pipes(arg) for arg in self.command] tf.write( quoteArguments(cmd) ) tf.close() argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args if '/c' not in argv: argv += ['/c'] argv += [tf.name] def unlink_temp(result): os.unlink(tf.name) return result self.deferred.addBoth(unlink_temp) return reactor.spawnProcess(processProtocol, executable, argv, env, path, usePTY=usePTY)
def escape_arg(arg): if arg == '|': return arg arg = quoteArguments([arg]) # escape shell special characters arg = re.sub(r'[@()^"<>&|]', r'^\g<0>', arg) # prevent variable expansion return arg.replace('%', '%%')
def escape_arg(arg): if arg == "|": return arg arg = quoteArguments([arg]) # escape shell special characters arg = re.sub(r'[@()^"<>&|]', r"^\g<0>", arg) # prevent variable expansion return arg.replace("%", "%%")
def __init__(self, reactor, protocol, command, args, environment, path): """ Create a new child process. """ _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) env = { os.fsdecode(key): os.fsdecode(value) for key, value in env.items() } # Make sure all the arguments are Unicode. args = [os.fsdecode(x) for x in args] cmdline = quoteArguments(args) # The command, too, needs to be Unicode, if it is a value. command = os.fsdecode(command) if command else command path = os.fsdecode(path) if path else path # TODO: error detection here. See #2787 and #4184. def doCreate(): flags = win32con.CREATE_NO_WINDOW self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, flags, env, path, StartupInfo) try: doCreate() except pywintypes.error as pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError("%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error as pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError("%r has an invalid shebang line: " "%r is not a valid executable" % (origcmd, sheb)) raise OSError(pwte2) # close handles which only the child will use win32file.CloseHandle(hStderrW) win32file.CloseHandle(hStdoutW) win32file.CloseHandle(hStdinR) # set up everything self.stdout = _pollingfile._PollableReadPipe( self.hStdoutR, lambda data: self.proto.childDataReceived(1, data), self.outConnectionLost, ) self.stderr = _pollingfile._PollableReadPipe( self.hStderrR, lambda data: self.proto.childDataReceived(2, data), self.errConnectionLost, ) self.stdin = _pollingfile._PollableWritePipe(self.hStdinW, self.inConnectionLost) for pipewatcher in self.stdout, self.stderr, self.stdin: self._addPollableResource(pipewatcher) # notify protocol self.proto.makeConnection(self) self._addPollableResource(_Reaper(self))
def __init__(self, reactor, protocol, command, args, environment, path): _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) cmdline = quoteArguments(args) # TODO: error detection here. def doCreate(): self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, 0, env, path, StartupInfo) try: doCreate() except pywintypes.error, pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError( "%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error, pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % ( origcmd, sheb)) raise OSError(pwte2)
def __init__(self, reactor, protocol, command, args, environment, path): """ Create a new child process. """ _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) newenv = {} for key, value in items(env): key = _fsdecode(key) value = _fsdecode(value) newenv[key] = value env = newenv # Make sure all the arguments are Unicode. args = [_fsdecode(x) for x in args] cmdline = quoteArguments(args) # The command, too, needs to be Unicode, if it is a value. command = _fsdecode(command) if command else command path = _fsdecode(path) if path else path # TODO: error detection here. See #2787 and #4184. def doCreate(): flags = win32con.CREATE_NO_WINDOW self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, flags, env, path, StartupInfo) try: doCreate() except pywintypes.error as pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError( "%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error as pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % ( origcmd, sheb)) raise OSError(pwte2) # close handles which only the child will use win32file.CloseHandle(hStderrW) win32file.CloseHandle(hStdoutW) win32file.CloseHandle(hStdinR) # set up everything self.stdout = _pollingfile._PollableReadPipe( self.hStdoutR, lambda data: self.proto.childDataReceived(1, data), self.outConnectionLost) self.stderr = _pollingfile._PollableReadPipe( self.hStderrR, lambda data: self.proto.childDataReceived(2, data), self.errConnectionLost) self.stdin = _pollingfile._PollableWritePipe( self.hStdinW, self.inConnectionLost) for pipewatcher in self.stdout, self.stderr, self.stdin: self._addPollableResource(pipewatcher) # notify protocol self.proto.makeConnection(self) self._addPollableResource(_Reaper(self))
def __new_init__(self, reactor, protocol, command, args, environment, path): _pollingfile._PollingTimer.__init__(self, reactor) self.proto = protocol self.protocol = protocol # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) cmdline = quoteArguments(args) # TODO: error detection here. def doCreate(): for key in env.keys(): if type(env[key]) == type(u"string"): env[key] = env[key].encode('MBCS') self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, win32process.CREATE_NO_WINDOW, env, path, StartupInfo) try: doCreate() except pywintypes.error, pwte: if not twisted.internet._dumbwin32proc._invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = twisted.internet._dumbwin32proc._findShebang(command) if sheb is None: raise OSError( "%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error, pwte2: # d'oh, failed again! if twisted.internet._dumbwin32proc._invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % ( origcmd, sheb)) raise OSError(pwte2)
def __init__(self, reactor, protocol, command, args, environment, path): """ Create a new child process. """ _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) cmdline = quoteArguments(args) # TODO: error detection here. See #2787 and #4184. def doCreate(): self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, 0, env, path, StartupInfo) try: try: doCreate() except TypeError, e: # win32process.CreateProcess cannot deal with mixed # str/unicode environment, so we make it all Unicode if e.args != ('All dictionary items must be strings, or ' 'all must be unicode',): raise newenv = {} for key, value in env.items(): newenv[unicode(key)] = unicode(value) env = newenv doCreate() except pywintypes.error, pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError( "%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error, pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % ( origcmd, sheb)) raise OSError(pwte2)
def __init__(self, reactor, protocol, command, args, environment, path): self.reactor = reactor self.protocol = protocol self.outBuffer = reactor.AllocateReadBuffer(self.bufferSize) self.errBuffer = reactor.AllocateReadBuffer(self.bufferSize) # This is the buffer for *reading* stdin, which is only done to # determine if the other end of the pipe was closed. self.inBuffer = reactor.AllocateReadBuffer(self.bufferSize) # IO operation classes self.readOutOp = ops.ReadOutOp(self) self.readErrOp = ops.ReadErrOp(self) self.readInOp = ops.ReadInOp(self) self.writeInOp = ops.WriteInOp(self) self.writeBuffer = "" self.writing = False self.finished = False self.offset = 0 self.writeBufferedSize = 0 self.closingStdin = False self.closedStdin = False self.closedStdout = False self.closedStderr = False # Stdio handles self.hChildStdinRd = None self.hChildStdinWr = None self.hChildStdinWrDup = None self.hChildStdoutRd = None self.hChildStdoutWr = None self.hChildStdoutRdDup = None self.hChildStderrRd = None self.hChildStderrWr = None self.hChildStderrRdDup = None self.closedNotifies = 0 # increments to 3 (for stdin, stdout, stderr) self.closed = False # set to true when all 3 handles close self.exited = False # set to true when WFMO thread gets signalled proc handle. See doWaitForProcessExit. # Set the bInheritHandle flag so pipe handles are inherited. saAttr = win32security.SECURITY_ATTRIBUTES() saAttr.bInheritHandle = 1 currentPid = win32api.GetCurrentProcess( ) # -1 which stands for current process self.pid = os.getpid() # unique pid for pipe naming # Create a pipe for the child process's STDOUT. self.stdoutPipeName = r"\\.\pipe\twisted-iocp-stdout-%d-%d-%d" % ( self.pid, counter.next(), time.time()) self.hChildStdoutRd = win32pipe.CreateNamedPipe( self.stdoutPipeName, win32con.PIPE_ACCESS_INBOUND | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStdoutWr = win32file.CreateFile( self.stdoutPipeName, win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0) # Create noninheritable read handle and close the inheritable read # handle. self.hChildStdoutRdDup = win32api.DuplicateHandle( currentPid, self.hChildStdoutRd, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStdoutRd) self.hChildStdoutRd = self.hChildStdoutRdDup # Create a pipe for the child process's STDERR. self.stderrPipeName = r"\\.\pipe\twisted-iocp-stderr-%d-%d-%d" % ( self.pid, counter.next(), time.time()) self.hChildStderrRd = win32pipe.CreateNamedPipe( self.stderrPipeName, win32con.PIPE_ACCESS_INBOUND | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStderrWr = win32file.CreateFile( self.stderrPipeName, win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0) # Create noninheritable read handle and close the inheritable read # handle. self.hChildStderrRdDup = win32api.DuplicateHandle( currentPid, self.hChildStderrRd, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStderrRd) self.hChildStderrRd = self.hChildStderrRdDup # Create a pipe for the child process's STDIN. This one is opened # in duplex mode so we can read from it too in order to detect when # the child closes their end of the pipe. self.stdinPipeName = r"\\.\pipe\twisted-iocp-stdin-%d-%d-%d" % ( self.pid, counter.next(), time.time()) self.hChildStdinWr = win32pipe.CreateNamedPipe( self.stdinPipeName, win32con.PIPE_ACCESS_DUPLEX | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStdinRd = win32file.CreateFile( self.stdinPipeName, win32con.GENERIC_READ, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0) # Duplicate the write handle to the pipe so it is not inherited. self.hChildStdinWrDup = win32api.DuplicateHandle( currentPid, self.hChildStdinWr, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStdinWr) self.hChildStdinWr = self.hChildStdinWrDup # set the info structure for the new process. This is where # we tell the process to use the pipes for stdout/err/in. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = self.hChildStdoutWr StartupInfo.hStdError = self.hChildStderrWr StartupInfo.hStdInput = self.hChildStdinRd StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # create the process cmdline = quoteArguments(args) self.hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( command, # name cmdline, # command line None, # process security attributes None, # primary thread security attributes 1, # handles are inherited 0, # creation flags environment, # if NULL, use parent environment path, # current directory StartupInfo) # STARTUPINFO pointer # close handles which only the child will use win32file.CloseHandle(self.hChildStderrWr) win32file.CloseHandle(self.hChildStdoutWr) win32file.CloseHandle(self.hChildStdinRd) # Begin reading on stdout and stderr, before we have output on them. self.readOutOp.initiateOp(self.hChildStdoutRd, self.outBuffer) self.readErrOp.initiateOp(self.hChildStderrRd, self.errBuffer) # Read stdin which was opened in duplex mode so we can detect when # the child closed their end of the pipe. self.readInOp.initiateOp(self.hChildStdinWr, self.inBuffer) # When the process is done, call connectionLost(). # This function returns right away. Note I call this after # protocol.makeConnection to ensure that the protocol doesn't # have processEnded called before protocol.makeConnection. self.reactor.processWaiter.beginWait(self.reactor, self.hProcess, self) # notify protocol by calling protocol.makeConnection and specifying # ourself as the transport. self.protocol.makeConnection(self)
def __init__(self, reactor, protocol, command, args, environment, path): self.reactor = reactor self.protocol = protocol self.outBuffer = reactor.AllocateReadBuffer(self.bufferSize) self.errBuffer = reactor.AllocateReadBuffer(self.bufferSize) # This is the buffer for *reading* stdin, which is only done to # determine if the other end of the pipe was closed. self.inBuffer = reactor.AllocateReadBuffer(self.bufferSize) # IO operation classes self.readOutOp = ops.ReadOutOp(self) self.readErrOp = ops.ReadErrOp(self) self.readInOp = ops.ReadInOp(self) self.writeInOp = ops.WriteInOp(self) self.writeBuffer = "" self.writing = False self.finished = False self.offset = 0 self.writeBufferedSize = 0 self.closingStdin = False self.closedStdin = False self.closedStdout = False self.closedStderr = False # Stdio handles self.hChildStdinRd = None self.hChildStdinWr = None self.hChildStdinWrDup = None self.hChildStdoutRd = None self.hChildStdoutWr = None self.hChildStdoutRdDup = None self.hChildStderrRd = None self.hChildStderrWr = None self.hChildStderrRdDup = None self.closedNotifies = 0 # increments to 3 (for stdin, stdout, stderr) self.closed = False # set to true when all 3 handles close self.exited = False # set to true when WFMO thread gets signalled proc handle. See doWaitForProcessExit. # Set the bInheritHandle flag so pipe handles are inherited. saAttr = win32security.SECURITY_ATTRIBUTES() saAttr.bInheritHandle = 1 currentPid = win32api.GetCurrentProcess() # -1 which stands for current process self.pid = os.getpid() # unique pid for pipe naming # Create a pipe for the child process's STDOUT. self.stdoutPipeName = r"\\.\pipe\twisted-iocp-stdout-%d-%d-%d" % (self.pid, counter.next(), time.time()) self.hChildStdoutRd = win32pipe.CreateNamedPipe( self.stdoutPipeName, win32con.PIPE_ACCESS_INBOUND | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStdoutWr = win32file.CreateFile( self.stdoutPipeName, win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0); # Create noninheritable read handle and close the inheritable read # handle. self.hChildStdoutRdDup = win32api.DuplicateHandle( currentPid, self.hChildStdoutRd, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStdoutRd); self.hChildStdoutRd = self.hChildStdoutRdDup # Create a pipe for the child process's STDERR. self.stderrPipeName = r"\\.\pipe\twisted-iocp-stderr-%d-%d-%d" % (self.pid, counter.next(), time.time()) self.hChildStderrRd = win32pipe.CreateNamedPipe( self.stderrPipeName, win32con.PIPE_ACCESS_INBOUND | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStderrWr = win32file.CreateFile( self.stderrPipeName, win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0); # Create noninheritable read handle and close the inheritable read # handle. self.hChildStderrRdDup = win32api.DuplicateHandle( currentPid, self.hChildStderrRd, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStderrRd) self.hChildStderrRd = self.hChildStderrRdDup # Create a pipe for the child process's STDIN. This one is opened # in duplex mode so we can read from it too in order to detect when # the child closes their end of the pipe. self.stdinPipeName = r"\\.\pipe\twisted-iocp-stdin-%d-%d-%d" % (self.pid, counter.next(), time.time()) self.hChildStdinWr = win32pipe.CreateNamedPipe( self.stdinPipeName, win32con.PIPE_ACCESS_DUPLEX | win32con.FILE_FLAG_OVERLAPPED, # open mode win32con.PIPE_TYPE_BYTE, # pipe mode 1, # max instances self.pipeBufferSize, # out buffer size self.pipeBufferSize, # in buffer size 0, # timeout saAttr) self.hChildStdinRd = win32file.CreateFile( self.stdinPipeName, win32con.GENERIC_READ, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, saAttr, win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, 0); # Duplicate the write handle to the pipe so it is not inherited. self.hChildStdinWrDup = win32api.DuplicateHandle( currentPid, self.hChildStdinWr, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32api.CloseHandle(self.hChildStdinWr) self.hChildStdinWr = self.hChildStdinWrDup # set the info structure for the new process. This is where # we tell the process to use the pipes for stdout/err/in. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = self.hChildStdoutWr StartupInfo.hStdError = self.hChildStderrWr StartupInfo.hStdInput = self.hChildStdinRd StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # create the process cmdline = quoteArguments(args) self.hProcess, hThread, dwPid, dwTid = win32process.CreateProcess( command, # name cmdline, # command line None, # process security attributes None, # primary thread security attributes 1, # handles are inherited 0, # creation flags environment, # if NULL, use parent environment path, # current directory StartupInfo) # STARTUPINFO pointer # close handles which only the child will use win32file.CloseHandle(self.hChildStderrWr) win32file.CloseHandle(self.hChildStdoutWr) win32file.CloseHandle(self.hChildStdinRd) # Begin reading on stdout and stderr, before we have output on them. self.readOutOp.initiateOp(self.hChildStdoutRd, self.outBuffer) self.readErrOp.initiateOp(self.hChildStderrRd, self.errBuffer) # Read stdin which was opened in duplex mode so we can detect when # the child closed their end of the pipe. self.readInOp.initiateOp(self.hChildStdinWr, self.inBuffer) # When the process is done, call connectionLost(). # This function returns right away. Note I call this after # protocol.makeConnection to ensure that the protocol doesn't # have processEnded called before protocol.makeConnection. self.reactor.processWaiter.beginWait(self.reactor, self.hProcess, self) # notify protocol by calling protocol.makeConnection and specifying # ourself as the transport. self.protocol.makeConnection(self)