1*cda5da8dSAndroid Build Coastguard Worker"""Various Windows specific bits and pieces.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Workerimport sys 4*cda5da8dSAndroid Build Coastguard Worker 5*cda5da8dSAndroid Build Coastguard Workerif sys.platform != 'win32': # pragma: no cover 6*cda5da8dSAndroid Build Coastguard Worker raise ImportError('win32 only') 7*cda5da8dSAndroid Build Coastguard Worker 8*cda5da8dSAndroid Build Coastguard Workerimport _winapi 9*cda5da8dSAndroid Build Coastguard Workerimport itertools 10*cda5da8dSAndroid Build Coastguard Workerimport msvcrt 11*cda5da8dSAndroid Build Coastguard Workerimport os 12*cda5da8dSAndroid Build Coastguard Workerimport subprocess 13*cda5da8dSAndroid Build Coastguard Workerimport tempfile 14*cda5da8dSAndroid Build Coastguard Workerimport warnings 15*cda5da8dSAndroid Build Coastguard Worker 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Worker__all__ = 'pipe', 'Popen', 'PIPE', 'PipeHandle' 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard Worker# Constants/globals 21*cda5da8dSAndroid Build Coastguard Worker 22*cda5da8dSAndroid Build Coastguard Worker 23*cda5da8dSAndroid Build Coastguard WorkerBUFSIZE = 8192 24*cda5da8dSAndroid Build Coastguard WorkerPIPE = subprocess.PIPE 25*cda5da8dSAndroid Build Coastguard WorkerSTDOUT = subprocess.STDOUT 26*cda5da8dSAndroid Build Coastguard Worker_mmap_counter = itertools.count() 27*cda5da8dSAndroid Build Coastguard Worker 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker# Replacement for os.pipe() using handles instead of fds 30*cda5da8dSAndroid Build Coastguard Worker 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard Workerdef pipe(*, duplex=False, overlapped=(True, True), bufsize=BUFSIZE): 33*cda5da8dSAndroid Build Coastguard Worker """Like os.pipe() but with overlapped support and using handles not fds.""" 34*cda5da8dSAndroid Build Coastguard Worker address = tempfile.mktemp( 35*cda5da8dSAndroid Build Coastguard Worker prefix=r'\\.\pipe\python-pipe-{:d}-{:d}-'.format( 36*cda5da8dSAndroid Build Coastguard Worker os.getpid(), next(_mmap_counter))) 37*cda5da8dSAndroid Build Coastguard Worker 38*cda5da8dSAndroid Build Coastguard Worker if duplex: 39*cda5da8dSAndroid Build Coastguard Worker openmode = _winapi.PIPE_ACCESS_DUPLEX 40*cda5da8dSAndroid Build Coastguard Worker access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE 41*cda5da8dSAndroid Build Coastguard Worker obsize, ibsize = bufsize, bufsize 42*cda5da8dSAndroid Build Coastguard Worker else: 43*cda5da8dSAndroid Build Coastguard Worker openmode = _winapi.PIPE_ACCESS_INBOUND 44*cda5da8dSAndroid Build Coastguard Worker access = _winapi.GENERIC_WRITE 45*cda5da8dSAndroid Build Coastguard Worker obsize, ibsize = 0, bufsize 46*cda5da8dSAndroid Build Coastguard Worker 47*cda5da8dSAndroid Build Coastguard Worker openmode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE 48*cda5da8dSAndroid Build Coastguard Worker 49*cda5da8dSAndroid Build Coastguard Worker if overlapped[0]: 50*cda5da8dSAndroid Build Coastguard Worker openmode |= _winapi.FILE_FLAG_OVERLAPPED 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker if overlapped[1]: 53*cda5da8dSAndroid Build Coastguard Worker flags_and_attribs = _winapi.FILE_FLAG_OVERLAPPED 54*cda5da8dSAndroid Build Coastguard Worker else: 55*cda5da8dSAndroid Build Coastguard Worker flags_and_attribs = 0 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Worker h1 = h2 = None 58*cda5da8dSAndroid Build Coastguard Worker try: 59*cda5da8dSAndroid Build Coastguard Worker h1 = _winapi.CreateNamedPipe( 60*cda5da8dSAndroid Build Coastguard Worker address, openmode, _winapi.PIPE_WAIT, 61*cda5da8dSAndroid Build Coastguard Worker 1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL) 62*cda5da8dSAndroid Build Coastguard Worker 63*cda5da8dSAndroid Build Coastguard Worker h2 = _winapi.CreateFile( 64*cda5da8dSAndroid Build Coastguard Worker address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING, 65*cda5da8dSAndroid Build Coastguard Worker flags_and_attribs, _winapi.NULL) 66*cda5da8dSAndroid Build Coastguard Worker 67*cda5da8dSAndroid Build Coastguard Worker ov = _winapi.ConnectNamedPipe(h1, overlapped=True) 68*cda5da8dSAndroid Build Coastguard Worker ov.GetOverlappedResult(True) 69*cda5da8dSAndroid Build Coastguard Worker return h1, h2 70*cda5da8dSAndroid Build Coastguard Worker except: 71*cda5da8dSAndroid Build Coastguard Worker if h1 is not None: 72*cda5da8dSAndroid Build Coastguard Worker _winapi.CloseHandle(h1) 73*cda5da8dSAndroid Build Coastguard Worker if h2 is not None: 74*cda5da8dSAndroid Build Coastguard Worker _winapi.CloseHandle(h2) 75*cda5da8dSAndroid Build Coastguard Worker raise 76*cda5da8dSAndroid Build Coastguard Worker 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Worker# Wrapper for a pipe handle 79*cda5da8dSAndroid Build Coastguard Worker 80*cda5da8dSAndroid Build Coastguard Worker 81*cda5da8dSAndroid Build Coastguard Workerclass PipeHandle: 82*cda5da8dSAndroid Build Coastguard Worker """Wrapper for an overlapped pipe handle which is vaguely file-object like. 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker The IOCP event loop can use these instead of socket objects. 85*cda5da8dSAndroid Build Coastguard Worker """ 86*cda5da8dSAndroid Build Coastguard Worker def __init__(self, handle): 87*cda5da8dSAndroid Build Coastguard Worker self._handle = handle 88*cda5da8dSAndroid Build Coastguard Worker 89*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 90*cda5da8dSAndroid Build Coastguard Worker if self._handle is not None: 91*cda5da8dSAndroid Build Coastguard Worker handle = f'handle={self._handle!r}' 92*cda5da8dSAndroid Build Coastguard Worker else: 93*cda5da8dSAndroid Build Coastguard Worker handle = 'closed' 94*cda5da8dSAndroid Build Coastguard Worker return f'<{self.__class__.__name__} {handle}>' 95*cda5da8dSAndroid Build Coastguard Worker 96*cda5da8dSAndroid Build Coastguard Worker @property 97*cda5da8dSAndroid Build Coastguard Worker def handle(self): 98*cda5da8dSAndroid Build Coastguard Worker return self._handle 99*cda5da8dSAndroid Build Coastguard Worker 100*cda5da8dSAndroid Build Coastguard Worker def fileno(self): 101*cda5da8dSAndroid Build Coastguard Worker if self._handle is None: 102*cda5da8dSAndroid Build Coastguard Worker raise ValueError("I/O operation on closed pipe") 103*cda5da8dSAndroid Build Coastguard Worker return self._handle 104*cda5da8dSAndroid Build Coastguard Worker 105*cda5da8dSAndroid Build Coastguard Worker def close(self, *, CloseHandle=_winapi.CloseHandle): 106*cda5da8dSAndroid Build Coastguard Worker if self._handle is not None: 107*cda5da8dSAndroid Build Coastguard Worker CloseHandle(self._handle) 108*cda5da8dSAndroid Build Coastguard Worker self._handle = None 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Worker def __del__(self, _warn=warnings.warn): 111*cda5da8dSAndroid Build Coastguard Worker if self._handle is not None: 112*cda5da8dSAndroid Build Coastguard Worker _warn(f"unclosed {self!r}", ResourceWarning, source=self) 113*cda5da8dSAndroid Build Coastguard Worker self.close() 114*cda5da8dSAndroid Build Coastguard Worker 115*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 116*cda5da8dSAndroid Build Coastguard Worker return self 117*cda5da8dSAndroid Build Coastguard Worker 118*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, t, v, tb): 119*cda5da8dSAndroid Build Coastguard Worker self.close() 120*cda5da8dSAndroid Build Coastguard Worker 121*cda5da8dSAndroid Build Coastguard Worker 122*cda5da8dSAndroid Build Coastguard Worker# Replacement for subprocess.Popen using overlapped pipe handles 123*cda5da8dSAndroid Build Coastguard Worker 124*cda5da8dSAndroid Build Coastguard Worker 125*cda5da8dSAndroid Build Coastguard Workerclass Popen(subprocess.Popen): 126*cda5da8dSAndroid Build Coastguard Worker """Replacement for subprocess.Popen using overlapped pipe handles. 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker The stdin, stdout, stderr are None or instances of PipeHandle. 129*cda5da8dSAndroid Build Coastguard Worker """ 130*cda5da8dSAndroid Build Coastguard Worker def __init__(self, args, stdin=None, stdout=None, stderr=None, **kwds): 131*cda5da8dSAndroid Build Coastguard Worker assert not kwds.get('universal_newlines') 132*cda5da8dSAndroid Build Coastguard Worker assert kwds.get('bufsize', 0) == 0 133*cda5da8dSAndroid Build Coastguard Worker stdin_rfd = stdout_wfd = stderr_wfd = None 134*cda5da8dSAndroid Build Coastguard Worker stdin_wh = stdout_rh = stderr_rh = None 135*cda5da8dSAndroid Build Coastguard Worker if stdin == PIPE: 136*cda5da8dSAndroid Build Coastguard Worker stdin_rh, stdin_wh = pipe(overlapped=(False, True), duplex=True) 137*cda5da8dSAndroid Build Coastguard Worker stdin_rfd = msvcrt.open_osfhandle(stdin_rh, os.O_RDONLY) 138*cda5da8dSAndroid Build Coastguard Worker else: 139*cda5da8dSAndroid Build Coastguard Worker stdin_rfd = stdin 140*cda5da8dSAndroid Build Coastguard Worker if stdout == PIPE: 141*cda5da8dSAndroid Build Coastguard Worker stdout_rh, stdout_wh = pipe(overlapped=(True, False)) 142*cda5da8dSAndroid Build Coastguard Worker stdout_wfd = msvcrt.open_osfhandle(stdout_wh, 0) 143*cda5da8dSAndroid Build Coastguard Worker else: 144*cda5da8dSAndroid Build Coastguard Worker stdout_wfd = stdout 145*cda5da8dSAndroid Build Coastguard Worker if stderr == PIPE: 146*cda5da8dSAndroid Build Coastguard Worker stderr_rh, stderr_wh = pipe(overlapped=(True, False)) 147*cda5da8dSAndroid Build Coastguard Worker stderr_wfd = msvcrt.open_osfhandle(stderr_wh, 0) 148*cda5da8dSAndroid Build Coastguard Worker elif stderr == STDOUT: 149*cda5da8dSAndroid Build Coastguard Worker stderr_wfd = stdout_wfd 150*cda5da8dSAndroid Build Coastguard Worker else: 151*cda5da8dSAndroid Build Coastguard Worker stderr_wfd = stderr 152*cda5da8dSAndroid Build Coastguard Worker try: 153*cda5da8dSAndroid Build Coastguard Worker super().__init__(args, stdin=stdin_rfd, stdout=stdout_wfd, 154*cda5da8dSAndroid Build Coastguard Worker stderr=stderr_wfd, **kwds) 155*cda5da8dSAndroid Build Coastguard Worker except: 156*cda5da8dSAndroid Build Coastguard Worker for h in (stdin_wh, stdout_rh, stderr_rh): 157*cda5da8dSAndroid Build Coastguard Worker if h is not None: 158*cda5da8dSAndroid Build Coastguard Worker _winapi.CloseHandle(h) 159*cda5da8dSAndroid Build Coastguard Worker raise 160*cda5da8dSAndroid Build Coastguard Worker else: 161*cda5da8dSAndroid Build Coastguard Worker if stdin_wh is not None: 162*cda5da8dSAndroid Build Coastguard Worker self.stdin = PipeHandle(stdin_wh) 163*cda5da8dSAndroid Build Coastguard Worker if stdout_rh is not None: 164*cda5da8dSAndroid Build Coastguard Worker self.stdout = PipeHandle(stdout_rh) 165*cda5da8dSAndroid Build Coastguard Worker if stderr_rh is not None: 166*cda5da8dSAndroid Build Coastguard Worker self.stderr = PipeHandle(stderr_rh) 167*cda5da8dSAndroid Build Coastguard Worker finally: 168*cda5da8dSAndroid Build Coastguard Worker if stdin == PIPE: 169*cda5da8dSAndroid Build Coastguard Worker os.close(stdin_rfd) 170*cda5da8dSAndroid Build Coastguard Worker if stdout == PIPE: 171*cda5da8dSAndroid Build Coastguard Worker os.close(stdout_wfd) 172*cda5da8dSAndroid Build Coastguard Worker if stderr == PIPE: 173*cda5da8dSAndroid Build Coastguard Worker os.close(stderr_wfd) 174