1 /*
2  * Support routines from the Windows API
3  *
4  * This module was originally created by merging PC/_subprocess.c with
5  * Modules/_multiprocessing/win32_functions.c.
6  *
7  * Copyright (c) 2004 by Fredrik Lundh <fredrik@pythonware.com>
8  * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com
9  * Copyright (c) 2004 by Peter Astrand <astrand@lysator.liu.se>
10  *
11  * By obtaining, using, and/or copying this software and/or its
12  * associated documentation, you agree that you have read, understood,
13  * and will comply with the following terms and conditions:
14  *
15  * Permission to use, copy, modify, and distribute this software and
16  * its associated documentation for any purpose and without fee is
17  * hereby granted, provided that the above copyright notice appears in
18  * all copies, and that both that copyright notice and this permission
19  * notice appear in supporting documentation, and that the name of the
20  * authors not be used in advertising or publicity pertaining to
21  * distribution of the software without specific, written prior
22  * permission.
23  *
24  * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
25  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
26  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
27  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
28  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
29  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
30  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31  *
32  */
33 
34 /* Licensed to PSF under a Contributor Agreement. */
35 /* See http://www.python.org/2.4/license for licensing details. */
36 
37 #include "Python.h"
38 #include "structmember.h"         // PyMemberDef
39 
40 #define WINDOWS_LEAN_AND_MEAN
41 #include "windows.h"
42 #include <crtdbg.h>
43 #include "winreparse.h"
44 
45 #if defined(MS_WIN32) && !defined(MS_WIN64)
46 #define HANDLE_TO_PYNUM(handle) \
47     PyLong_FromUnsignedLong((unsigned long) handle)
48 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
49 #define F_POINTER "k"
50 #define T_POINTER T_ULONG
51 #else
52 #define HANDLE_TO_PYNUM(handle) \
53     PyLong_FromUnsignedLongLong((unsigned long long) handle)
54 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLongLong(obj))
55 #define F_POINTER "K"
56 #define T_POINTER T_ULONGLONG
57 #endif
58 
59 #define F_HANDLE F_POINTER
60 #define F_DWORD "k"
61 
62 #define T_HANDLE T_POINTER
63 
64 /* Grab CancelIoEx dynamically from kernel32 */
65 static int has_CancelIoEx = -1;
66 static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED);
67 
68 static int
check_CancelIoEx()69 check_CancelIoEx()
70 {
71     if (has_CancelIoEx == -1)
72     {
73         HINSTANCE hKernel32 = GetModuleHandle("KERNEL32");
74         * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32,
75                                                       "CancelIoEx");
76         has_CancelIoEx = (Py_CancelIoEx != NULL);
77     }
78     return has_CancelIoEx;
79 }
80 
81 
82 /*
83  * A Python object wrapping an OVERLAPPED structure and other useful data
84  * for overlapped I/O
85  */
86 
87 typedef struct {
88     PyObject_HEAD
89     OVERLAPPED overlapped;
90     /* For convenience, we store the file handle too */
91     HANDLE handle;
92     /* Whether there's I/O in flight */
93     int pending;
94     /* Whether I/O completed successfully */
95     int completed;
96     /* Buffer used for reading (optional) */
97     PyObject *read_buffer;
98     /* Buffer used for writing (optional) */
99     Py_buffer write_buffer;
100 } OverlappedObject;
101 
102 static void
overlapped_dealloc(OverlappedObject * self)103 overlapped_dealloc(OverlappedObject *self)
104 {
105     DWORD bytes;
106     int err = GetLastError();
107 
108     if (self->pending) {
109         if (check_CancelIoEx() &&
110             Py_CancelIoEx(self->handle, &self->overlapped) &&
111             GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE))
112         {
113             /* The operation is no longer pending -- nothing to do. */
114         }
115         else if (_Py_IsFinalizing())
116         {
117             /* The operation is still pending -- give a warning.  This
118                will probably only happen on Windows XP. */
119             PyErr_SetString(PyExc_RuntimeError,
120                             "I/O operations still in flight while destroying "
121                             "Overlapped object, the process may crash");
122             PyErr_WriteUnraisable(NULL);
123         }
124         else
125         {
126             /* The operation is still pending, but the process is
127                probably about to exit, so we need not worry too much
128                about memory leaks.  Leaking self prevents a potential
129                crash.  This can happen when a daemon thread is cleaned
130                up at exit -- see #19565.  We only expect to get here
131                on Windows XP. */
132             CloseHandle(self->overlapped.hEvent);
133             SetLastError(err);
134             return;
135         }
136     }
137 
138     CloseHandle(self->overlapped.hEvent);
139     SetLastError(err);
140     if (self->write_buffer.obj)
141         PyBuffer_Release(&self->write_buffer);
142     Py_CLEAR(self->read_buffer);
143     PyObject_Del(self);
144 }
145 
146 /*[clinic input]
147 module _winapi
148 class _winapi.Overlapped "OverlappedObject *" "&OverlappedType"
149 [clinic start generated code]*/
150 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c13d3f5fd1dabb84]*/
151 
152 /*[python input]
153 def create_converter(type_, format_unit):
154     name = type_ + '_converter'
155     # registered upon creation by CConverter's metaclass
156     type(name, (CConverter,), {'type': type_, 'format_unit': format_unit})
157 
158 # format unit differs between platforms for these
159 create_converter('HANDLE', '" F_HANDLE "')
160 create_converter('HMODULE', '" F_HANDLE "')
161 create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "')
162 create_converter('LPCVOID', '" F_POINTER "')
163 
164 create_converter('BOOL', 'i') # F_BOOL used previously (always 'i')
165 create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter)
166 create_converter('LPCTSTR', 's')
167 create_converter('LPCWSTR', 'u')
168 create_converter('LPWSTR', 'u')
169 create_converter('UINT', 'I') # F_UINT used previously (always 'I')
170 
171 class HANDLE_return_converter(CReturnConverter):
172     type = 'HANDLE'
173 
174     def render(self, function, data):
175         self.declare(data)
176         self.err_occurred_if("_return_value == INVALID_HANDLE_VALUE", data)
177         data.return_conversion.append(
178             'if (_return_value == NULL) {\n    Py_RETURN_NONE;\n}\n')
179         data.return_conversion.append(
180             'return_value = HANDLE_TO_PYNUM(_return_value);\n')
181 
182 class DWORD_return_converter(CReturnConverter):
183     type = 'DWORD'
184 
185     def render(self, function, data):
186         self.declare(data)
187         self.err_occurred_if("_return_value == PY_DWORD_MAX", data)
188         data.return_conversion.append(
189             'return_value = Py_BuildValue("k", _return_value);\n')
190 
191 class LPVOID_return_converter(CReturnConverter):
192     type = 'LPVOID'
193 
194     def render(self, function, data):
195         self.declare(data)
196         self.err_occurred_if("_return_value == NULL", data)
197         data.return_conversion.append(
198             'return_value = HANDLE_TO_PYNUM(_return_value);\n')
199 [python start generated code]*/
200 /*[python end generated code: output=da39a3ee5e6b4b0d input=79464c61a31ae932]*/
201 
202 #include "clinic/_winapi.c.h"
203 
204 /*[clinic input]
205 _winapi.Overlapped.GetOverlappedResult
206 
207     wait: bool
208     /
209 [clinic start generated code]*/
210 
211 static PyObject *
_winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject * self,int wait)212 _winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject *self, int wait)
213 /*[clinic end generated code: output=bdd0c1ed6518cd03 input=194505ee8e0e3565]*/
214 {
215     BOOL res;
216     DWORD transferred = 0;
217     DWORD err;
218 
219     Py_BEGIN_ALLOW_THREADS
220     res = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
221                               wait != 0);
222     Py_END_ALLOW_THREADS
223 
224     err = res ? ERROR_SUCCESS : GetLastError();
225     switch (err) {
226         case ERROR_SUCCESS:
227         case ERROR_MORE_DATA:
228         case ERROR_OPERATION_ABORTED:
229             self->completed = 1;
230             self->pending = 0;
231             break;
232         case ERROR_IO_INCOMPLETE:
233             break;
234         default:
235             self->pending = 0;
236             return PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
237     }
238     if (self->completed && self->read_buffer != NULL) {
239         assert(PyBytes_CheckExact(self->read_buffer));
240         if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
241             _PyBytes_Resize(&self->read_buffer, transferred))
242             return NULL;
243     }
244     return Py_BuildValue("II", (unsigned) transferred, (unsigned) err);
245 }
246 
247 /*[clinic input]
248 _winapi.Overlapped.getbuffer
249 [clinic start generated code]*/
250 
251 static PyObject *
_winapi_Overlapped_getbuffer_impl(OverlappedObject * self)252 _winapi_Overlapped_getbuffer_impl(OverlappedObject *self)
253 /*[clinic end generated code: output=95a3eceefae0f748 input=347fcfd56b4ceabd]*/
254 {
255     PyObject *res;
256     if (!self->completed) {
257         PyErr_SetString(PyExc_ValueError,
258                         "can't get read buffer before GetOverlappedResult() "
259                         "signals the operation completed");
260         return NULL;
261     }
262     res = self->read_buffer ? self->read_buffer : Py_None;
263     Py_INCREF(res);
264     return res;
265 }
266 
267 /*[clinic input]
268 _winapi.Overlapped.cancel
269 [clinic start generated code]*/
270 
271 static PyObject *
_winapi_Overlapped_cancel_impl(OverlappedObject * self)272 _winapi_Overlapped_cancel_impl(OverlappedObject *self)
273 /*[clinic end generated code: output=fcb9ab5df4ebdae5 input=cbf3da142290039f]*/
274 {
275     BOOL res = TRUE;
276 
277     if (self->pending) {
278         Py_BEGIN_ALLOW_THREADS
279         if (check_CancelIoEx())
280             res = Py_CancelIoEx(self->handle, &self->overlapped);
281         else
282             res = CancelIo(self->handle);
283         Py_END_ALLOW_THREADS
284     }
285 
286     /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
287     if (!res && GetLastError() != ERROR_NOT_FOUND)
288         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
289     self->pending = 0;
290     Py_RETURN_NONE;
291 }
292 
293 static PyMethodDef overlapped_methods[] = {
294     _WINAPI_OVERLAPPED_GETOVERLAPPEDRESULT_METHODDEF
295     _WINAPI_OVERLAPPED_GETBUFFER_METHODDEF
296     _WINAPI_OVERLAPPED_CANCEL_METHODDEF
297     {NULL}
298 };
299 
300 static PyMemberDef overlapped_members[] = {
301     {"event", T_HANDLE,
302      offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
303      READONLY, "overlapped event handle"},
304     {NULL}
305 };
306 
307 PyTypeObject OverlappedType = {
308     PyVarObject_HEAD_INIT(NULL, 0)
309     /* tp_name           */ "_winapi.Overlapped",
310     /* tp_basicsize      */ sizeof(OverlappedObject),
311     /* tp_itemsize       */ 0,
312     /* tp_dealloc        */ (destructor) overlapped_dealloc,
313     /* tp_vectorcall_offset */ 0,
314     /* tp_getattr        */ 0,
315     /* tp_setattr        */ 0,
316     /* tp_as_async       */ 0,
317     /* tp_repr           */ 0,
318     /* tp_as_number      */ 0,
319     /* tp_as_sequence    */ 0,
320     /* tp_as_mapping     */ 0,
321     /* tp_hash           */ 0,
322     /* tp_call           */ 0,
323     /* tp_str            */ 0,
324     /* tp_getattro       */ 0,
325     /* tp_setattro       */ 0,
326     /* tp_as_buffer      */ 0,
327     /* tp_flags          */ Py_TPFLAGS_DEFAULT,
328     /* tp_doc            */ "OVERLAPPED structure wrapper",
329     /* tp_traverse       */ 0,
330     /* tp_clear          */ 0,
331     /* tp_richcompare    */ 0,
332     /* tp_weaklistoffset */ 0,
333     /* tp_iter           */ 0,
334     /* tp_iternext       */ 0,
335     /* tp_methods        */ overlapped_methods,
336     /* tp_members        */ overlapped_members,
337     /* tp_getset         */ 0,
338     /* tp_base           */ 0,
339     /* tp_dict           */ 0,
340     /* tp_descr_get      */ 0,
341     /* tp_descr_set      */ 0,
342     /* tp_dictoffset     */ 0,
343     /* tp_init           */ 0,
344     /* tp_alloc          */ 0,
345     /* tp_new            */ 0,
346 };
347 
348 static OverlappedObject *
new_overlapped(HANDLE handle)349 new_overlapped(HANDLE handle)
350 {
351     OverlappedObject *self;
352 
353     self = PyObject_New(OverlappedObject, &OverlappedType);
354     if (!self)
355         return NULL;
356     self->handle = handle;
357     self->read_buffer = NULL;
358     self->pending = 0;
359     self->completed = 0;
360     memset(&self->overlapped, 0, sizeof(OVERLAPPED));
361     memset(&self->write_buffer, 0, sizeof(Py_buffer));
362     /* Manual reset, initially non-signalled */
363     self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
364     return self;
365 }
366 
367 /* -------------------------------------------------------------------- */
368 /* windows API functions */
369 
370 /*[clinic input]
371 _winapi.CloseHandle
372 
373     handle: HANDLE
374     /
375 
376 Close handle.
377 [clinic start generated code]*/
378 
379 static PyObject *
_winapi_CloseHandle_impl(PyObject * module,HANDLE handle)380 _winapi_CloseHandle_impl(PyObject *module, HANDLE handle)
381 /*[clinic end generated code: output=7ad37345f07bd782 input=7f0e4ac36e0352b8]*/
382 {
383     BOOL success;
384 
385     Py_BEGIN_ALLOW_THREADS
386     success = CloseHandle(handle);
387     Py_END_ALLOW_THREADS
388 
389     if (!success)
390         return PyErr_SetFromWindowsErr(0);
391 
392     Py_RETURN_NONE;
393 }
394 
395 /*[clinic input]
396 _winapi.ConnectNamedPipe
397 
398     handle: HANDLE
399     overlapped as use_overlapped: bool(accept={int}) = False
400 [clinic start generated code]*/
401 
402 static PyObject *
_winapi_ConnectNamedPipe_impl(PyObject * module,HANDLE handle,int use_overlapped)403 _winapi_ConnectNamedPipe_impl(PyObject *module, HANDLE handle,
404                               int use_overlapped)
405 /*[clinic end generated code: output=335a0e7086800671 input=34f937c1c86e5e68]*/
406 {
407     BOOL success;
408     OverlappedObject *overlapped = NULL;
409 
410     if (use_overlapped) {
411         overlapped = new_overlapped(handle);
412         if (!overlapped)
413             return NULL;
414     }
415 
416     Py_BEGIN_ALLOW_THREADS
417     success = ConnectNamedPipe(handle,
418                                overlapped ? &overlapped->overlapped : NULL);
419     Py_END_ALLOW_THREADS
420 
421     if (overlapped) {
422         int err = GetLastError();
423         /* Overlapped ConnectNamedPipe never returns a success code */
424         assert(success == 0);
425         if (err == ERROR_IO_PENDING)
426             overlapped->pending = 1;
427         else if (err == ERROR_PIPE_CONNECTED)
428             SetEvent(overlapped->overlapped.hEvent);
429         else {
430             Py_DECREF(overlapped);
431             return PyErr_SetFromWindowsErr(err);
432         }
433         return (PyObject *) overlapped;
434     }
435     if (!success)
436         return PyErr_SetFromWindowsErr(0);
437 
438     Py_RETURN_NONE;
439 }
440 
441 /*[clinic input]
442 _winapi.CreateFile -> HANDLE
443 
444     file_name: LPCTSTR
445     desired_access: DWORD
446     share_mode: DWORD
447     security_attributes: LPSECURITY_ATTRIBUTES
448     creation_disposition: DWORD
449     flags_and_attributes: DWORD
450     template_file: HANDLE
451     /
452 [clinic start generated code]*/
453 
454 static HANDLE
_winapi_CreateFile_impl(PyObject * module,LPCTSTR file_name,DWORD desired_access,DWORD share_mode,LPSECURITY_ATTRIBUTES security_attributes,DWORD creation_disposition,DWORD flags_and_attributes,HANDLE template_file)455 _winapi_CreateFile_impl(PyObject *module, LPCTSTR file_name,
456                         DWORD desired_access, DWORD share_mode,
457                         LPSECURITY_ATTRIBUTES security_attributes,
458                         DWORD creation_disposition,
459                         DWORD flags_and_attributes, HANDLE template_file)
460 /*[clinic end generated code: output=417ddcebfc5a3d53 input=6423c3e40372dbd5]*/
461 {
462     HANDLE handle;
463 
464     if (PySys_Audit("_winapi.CreateFile", "uIIII",
465                     file_name, desired_access, share_mode,
466                     creation_disposition, flags_and_attributes) < 0) {
467         return INVALID_HANDLE_VALUE;
468     }
469 
470     Py_BEGIN_ALLOW_THREADS
471     handle = CreateFile(file_name, desired_access,
472                         share_mode, security_attributes,
473                         creation_disposition,
474                         flags_and_attributes, template_file);
475     Py_END_ALLOW_THREADS
476 
477     if (handle == INVALID_HANDLE_VALUE)
478         PyErr_SetFromWindowsErr(0);
479 
480     return handle;
481 }
482 
483 /*[clinic input]
484 _winapi.CreateFileMapping -> HANDLE
485 
486     file_handle: HANDLE
487     security_attributes: LPSECURITY_ATTRIBUTES
488     protect: DWORD
489     max_size_high: DWORD
490     max_size_low: DWORD
491     name: LPCWSTR
492     /
493 [clinic start generated code]*/
494 
495 static HANDLE
_winapi_CreateFileMapping_impl(PyObject * module,HANDLE file_handle,LPSECURITY_ATTRIBUTES security_attributes,DWORD protect,DWORD max_size_high,DWORD max_size_low,LPCWSTR name)496 _winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle,
497                                LPSECURITY_ATTRIBUTES security_attributes,
498                                DWORD protect, DWORD max_size_high,
499                                DWORD max_size_low, LPCWSTR name)
500 /*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=3dc5cf762a74dee8]*/
501 {
502     HANDLE handle;
503 
504     Py_BEGIN_ALLOW_THREADS
505     handle = CreateFileMappingW(file_handle, security_attributes,
506                                 protect, max_size_high, max_size_low,
507                                 name);
508     Py_END_ALLOW_THREADS
509 
510     if (handle == NULL) {
511         PyObject *temp = PyUnicode_FromWideChar(name, -1);
512         PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
513         Py_XDECREF(temp);
514         handle = INVALID_HANDLE_VALUE;
515     }
516 
517     return handle;
518 }
519 
520 /*[clinic input]
521 _winapi.CreateJunction
522 
523     src_path: LPWSTR
524     dst_path: LPWSTR
525     /
526 [clinic start generated code]*/
527 
528 static PyObject *
_winapi_CreateJunction_impl(PyObject * module,LPWSTR src_path,LPWSTR dst_path)529 _winapi_CreateJunction_impl(PyObject *module, LPWSTR src_path,
530                             LPWSTR dst_path)
531 /*[clinic end generated code: output=66b7eb746e1dfa25 input=8cd1f9964b6e3d36]*/
532 {
533     /* Privilege adjustment */
534     HANDLE token = NULL;
535     TOKEN_PRIVILEGES tp;
536 
537     /* Reparse data buffer */
538     const USHORT prefix_len = 4;
539     USHORT print_len = 0;
540     USHORT rdb_size = 0;
541     _Py_PREPARSE_DATA_BUFFER rdb = NULL;
542 
543     /* Junction point creation */
544     HANDLE junction = NULL;
545     DWORD ret = 0;
546 
547     if (src_path == NULL || dst_path == NULL)
548         return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
549 
550     if (wcsncmp(src_path, L"\\??\\", prefix_len) == 0)
551         return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
552 
553     if (PySys_Audit("_winapi.CreateJunction", "uu", src_path, dst_path) < 0) {
554         return NULL;
555     }
556 
557     /* Adjust privileges to allow rewriting directory entry as a
558        junction point. */
559     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
560         goto cleanup;
561 
562     if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid))
563         goto cleanup;
564 
565     tp.PrivilegeCount = 1;
566     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
567     if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
568                                NULL, NULL))
569         goto cleanup;
570 
571     if (GetFileAttributesW(src_path) == INVALID_FILE_ATTRIBUTES)
572         goto cleanup;
573 
574     /* Store the absolute link target path length in print_len. */
575     print_len = (USHORT)GetFullPathNameW(src_path, 0, NULL, NULL);
576     if (print_len == 0)
577         goto cleanup;
578 
579     /* NUL terminator should not be part of print_len. */
580     --print_len;
581 
582     /* REPARSE_DATA_BUFFER usage is heavily under-documented, especially for
583        junction points. Here's what I've learned along the way:
584        - A junction point has two components: a print name and a substitute
585          name. They both describe the link target, but the substitute name is
586          the physical target and the print name is shown in directory listings.
587        - The print name must be a native name, prefixed with "\??\".
588        - Both names are stored after each other in the same buffer (the
589          PathBuffer) and both must be NUL-terminated.
590        - There are four members defining their respective offset and length
591          inside PathBuffer: SubstituteNameOffset, SubstituteNameLength,
592          PrintNameOffset and PrintNameLength.
593        - The total size we need to allocate for the REPARSE_DATA_BUFFER, thus,
594          is the sum of:
595          - the fixed header size (REPARSE_DATA_BUFFER_HEADER_SIZE)
596          - the size of the MountPointReparseBuffer member without the PathBuffer
597          - the size of the prefix ("\??\") in bytes
598          - the size of the print name in bytes
599          - the size of the substitute name in bytes
600          - the size of two NUL terminators in bytes */
601     rdb_size = _Py_REPARSE_DATA_BUFFER_HEADER_SIZE +
602         sizeof(rdb->MountPointReparseBuffer) -
603         sizeof(rdb->MountPointReparseBuffer.PathBuffer) +
604         /* Two +1's for NUL terminators. */
605         (prefix_len + print_len + 1 + print_len + 1) * sizeof(WCHAR);
606     rdb = (_Py_PREPARSE_DATA_BUFFER)PyMem_RawCalloc(1, rdb_size);
607     if (rdb == NULL)
608         goto cleanup;
609 
610     rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
611     rdb->ReparseDataLength = rdb_size - _Py_REPARSE_DATA_BUFFER_HEADER_SIZE;
612     rdb->MountPointReparseBuffer.SubstituteNameOffset = 0;
613     rdb->MountPointReparseBuffer.SubstituteNameLength =
614         (prefix_len + print_len) * sizeof(WCHAR);
615     rdb->MountPointReparseBuffer.PrintNameOffset =
616         rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
617     rdb->MountPointReparseBuffer.PrintNameLength = print_len * sizeof(WCHAR);
618 
619     /* Store the full native path of link target at the substitute name
620        offset (0). */
621     wcscpy(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
622     if (GetFullPathNameW(src_path, print_len + 1,
623                          rdb->MountPointReparseBuffer.PathBuffer + prefix_len,
624                          NULL) == 0)
625         goto cleanup;
626 
627     /* Copy everything but the native prefix to the print name offset. */
628     wcscpy(rdb->MountPointReparseBuffer.PathBuffer +
629              prefix_len + print_len + 1,
630              rdb->MountPointReparseBuffer.PathBuffer + prefix_len);
631 
632     /* Create a directory for the junction point. */
633     if (!CreateDirectoryW(dst_path, NULL))
634         goto cleanup;
635 
636     junction = CreateFileW(dst_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
637         OPEN_EXISTING,
638         FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
639     if (junction == INVALID_HANDLE_VALUE)
640         goto cleanup;
641 
642     /* Make the directory entry a junction point. */
643     if (!DeviceIoControl(junction, FSCTL_SET_REPARSE_POINT, rdb, rdb_size,
644                          NULL, 0, &ret, NULL))
645         goto cleanup;
646 
647 cleanup:
648     ret = GetLastError();
649 
650     CloseHandle(token);
651     CloseHandle(junction);
652     PyMem_RawFree(rdb);
653 
654     if (ret != 0)
655         return PyErr_SetFromWindowsErr(ret);
656 
657     Py_RETURN_NONE;
658 }
659 
660 /*[clinic input]
661 _winapi.CreateNamedPipe -> HANDLE
662 
663     name: LPCTSTR
664     open_mode: DWORD
665     pipe_mode: DWORD
666     max_instances: DWORD
667     out_buffer_size: DWORD
668     in_buffer_size: DWORD
669     default_timeout: DWORD
670     security_attributes: LPSECURITY_ATTRIBUTES
671     /
672 [clinic start generated code]*/
673 
674 static HANDLE
_winapi_CreateNamedPipe_impl(PyObject * module,LPCTSTR name,DWORD open_mode,DWORD pipe_mode,DWORD max_instances,DWORD out_buffer_size,DWORD in_buffer_size,DWORD default_timeout,LPSECURITY_ATTRIBUTES security_attributes)675 _winapi_CreateNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD open_mode,
676                              DWORD pipe_mode, DWORD max_instances,
677                              DWORD out_buffer_size, DWORD in_buffer_size,
678                              DWORD default_timeout,
679                              LPSECURITY_ATTRIBUTES security_attributes)
680 /*[clinic end generated code: output=80f8c07346a94fbc input=5a73530b84d8bc37]*/
681 {
682     HANDLE handle;
683 
684     if (PySys_Audit("_winapi.CreateNamedPipe", "uII",
685                     name, open_mode, pipe_mode) < 0) {
686         return INVALID_HANDLE_VALUE;
687     }
688 
689     Py_BEGIN_ALLOW_THREADS
690     handle = CreateNamedPipe(name, open_mode, pipe_mode,
691                              max_instances, out_buffer_size,
692                              in_buffer_size, default_timeout,
693                              security_attributes);
694     Py_END_ALLOW_THREADS
695 
696     if (handle == INVALID_HANDLE_VALUE)
697         PyErr_SetFromWindowsErr(0);
698 
699     return handle;
700 }
701 
702 /*[clinic input]
703 _winapi.CreatePipe
704 
705     pipe_attrs: object
706         Ignored internally, can be None.
707     size: DWORD
708     /
709 
710 Create an anonymous pipe.
711 
712 Returns a 2-tuple of handles, to the read and write ends of the pipe.
713 [clinic start generated code]*/
714 
715 static PyObject *
_winapi_CreatePipe_impl(PyObject * module,PyObject * pipe_attrs,DWORD size)716 _winapi_CreatePipe_impl(PyObject *module, PyObject *pipe_attrs, DWORD size)
717 /*[clinic end generated code: output=1c4411d8699f0925 input=c4f2cfa56ef68d90]*/
718 {
719     HANDLE read_pipe;
720     HANDLE write_pipe;
721     BOOL result;
722 
723     if (PySys_Audit("_winapi.CreatePipe", NULL) < 0) {
724         return NULL;
725     }
726 
727     Py_BEGIN_ALLOW_THREADS
728     result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
729     Py_END_ALLOW_THREADS
730 
731     if (! result)
732         return PyErr_SetFromWindowsErr(GetLastError());
733 
734     return Py_BuildValue(
735         "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe));
736 }
737 
738 /* helpers for createprocess */
739 
740 static unsigned long
getulong(PyObject * obj,const char * name)741 getulong(PyObject* obj, const char* name)
742 {
743     PyObject* value;
744     unsigned long ret;
745 
746     value = PyObject_GetAttrString(obj, name);
747     if (! value) {
748         PyErr_Clear(); /* FIXME: propagate error? */
749         return 0;
750     }
751     ret = PyLong_AsUnsignedLong(value);
752     Py_DECREF(value);
753     return ret;
754 }
755 
756 static HANDLE
gethandle(PyObject * obj,const char * name)757 gethandle(PyObject* obj, const char* name)
758 {
759     PyObject* value;
760     HANDLE ret;
761 
762     value = PyObject_GetAttrString(obj, name);
763     if (! value) {
764         PyErr_Clear(); /* FIXME: propagate error? */
765         return NULL;
766     }
767     if (value == Py_None)
768         ret = NULL;
769     else
770         ret = PYNUM_TO_HANDLE(value);
771     Py_DECREF(value);
772     return ret;
773 }
774 
775 static wchar_t *
getenvironment(PyObject * environment)776 getenvironment(PyObject* environment)
777 {
778     Py_ssize_t i, envsize, totalsize;
779     wchar_t *buffer = NULL, *p, *end;
780     PyObject *keys, *values;
781 
782     /* convert environment dictionary to windows environment string */
783     if (! PyMapping_Check(environment)) {
784         PyErr_SetString(
785             PyExc_TypeError, "environment must be dictionary or None");
786         return NULL;
787     }
788 
789     keys = PyMapping_Keys(environment);
790     if (!keys) {
791         return NULL;
792     }
793     values = PyMapping_Values(environment);
794     if (!values) {
795         goto error;
796     }
797 
798     envsize = PyList_GET_SIZE(keys);
799     if (PyList_GET_SIZE(values) != envsize) {
800         PyErr_SetString(PyExc_RuntimeError,
801             "environment changed size during iteration");
802         goto error;
803     }
804 
805     totalsize = 1; /* trailing null character */
806     for (i = 0; i < envsize; i++) {
807         PyObject* key = PyList_GET_ITEM(keys, i);
808         PyObject* value = PyList_GET_ITEM(values, i);
809         Py_ssize_t size;
810 
811         if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
812             PyErr_SetString(PyExc_TypeError,
813                 "environment can only contain strings");
814             goto error;
815         }
816         if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
817             PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
818         {
819             PyErr_SetString(PyExc_ValueError, "embedded null character");
820             goto error;
821         }
822         /* Search from index 1 because on Windows starting '=' is allowed for
823            defining hidden environment variables. */
824         if (PyUnicode_GET_LENGTH(key) == 0 ||
825             PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
826         {
827             PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
828             goto error;
829         }
830 
831         size = PyUnicode_AsWideChar(key, NULL, 0);
832         assert(size > 1);
833         if (totalsize > PY_SSIZE_T_MAX - size) {
834             PyErr_SetString(PyExc_OverflowError, "environment too long");
835             goto error;
836         }
837         totalsize += size;    /* including '=' */
838 
839         size = PyUnicode_AsWideChar(value, NULL, 0);
840         assert(size > 0);
841         if (totalsize > PY_SSIZE_T_MAX - size) {
842             PyErr_SetString(PyExc_OverflowError, "environment too long");
843             goto error;
844         }
845         totalsize += size;  /* including trailing '\0' */
846     }
847 
848     buffer = PyMem_NEW(wchar_t, totalsize);
849     if (! buffer) {
850         PyErr_NoMemory();
851         goto error;
852     }
853     p = buffer;
854     end = buffer + totalsize;
855 
856     for (i = 0; i < envsize; i++) {
857         PyObject* key = PyList_GET_ITEM(keys, i);
858         PyObject* value = PyList_GET_ITEM(values, i);
859         Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
860         assert(1 <= size && size < end - p);
861         p += size;
862         *p++ = L'=';
863         size = PyUnicode_AsWideChar(value, p, end - p);
864         assert(0 <= size && size < end - p);
865         p += size + 1;
866     }
867 
868     /* add trailing null character */
869     *p++ = L'\0';
870     assert(p == end);
871 
872  error:
873     Py_XDECREF(keys);
874     Py_XDECREF(values);
875     return buffer;
876 }
877 
878 static LPHANDLE
gethandlelist(PyObject * mapping,const char * name,Py_ssize_t * size)879 gethandlelist(PyObject *mapping, const char *name, Py_ssize_t *size)
880 {
881     LPHANDLE ret = NULL;
882     PyObject *value_fast = NULL;
883     PyObject *value;
884     Py_ssize_t i;
885 
886     value = PyMapping_GetItemString(mapping, name);
887     if (!value) {
888         PyErr_Clear();
889         return NULL;
890     }
891 
892     if (value == Py_None) {
893         goto cleanup;
894     }
895 
896     value_fast = PySequence_Fast(value, "handle_list must be a sequence or None");
897     if (value_fast == NULL)
898         goto cleanup;
899 
900     *size = PySequence_Fast_GET_SIZE(value_fast) * sizeof(HANDLE);
901 
902     /* Passing an empty array causes CreateProcess to fail so just don't set it */
903     if (*size == 0) {
904         goto cleanup;
905     }
906 
907     ret = PyMem_Malloc(*size);
908     if (ret == NULL)
909         goto cleanup;
910 
911     for (i = 0; i < PySequence_Fast_GET_SIZE(value_fast); i++) {
912         ret[i] = PYNUM_TO_HANDLE(PySequence_Fast_GET_ITEM(value_fast, i));
913         if (ret[i] == (HANDLE)-1 && PyErr_Occurred()) {
914             PyMem_Free(ret);
915             ret = NULL;
916             goto cleanup;
917         }
918     }
919 
920 cleanup:
921     Py_DECREF(value);
922     Py_XDECREF(value_fast);
923     return ret;
924 }
925 
926 typedef struct {
927     LPPROC_THREAD_ATTRIBUTE_LIST attribute_list;
928     LPHANDLE handle_list;
929 } AttributeList;
930 
931 static void
freeattributelist(AttributeList * attribute_list)932 freeattributelist(AttributeList *attribute_list)
933 {
934     if (attribute_list->attribute_list != NULL) {
935         DeleteProcThreadAttributeList(attribute_list->attribute_list);
936         PyMem_Free(attribute_list->attribute_list);
937     }
938 
939     PyMem_Free(attribute_list->handle_list);
940 
941     memset(attribute_list, 0, sizeof(*attribute_list));
942 }
943 
944 static int
getattributelist(PyObject * obj,const char * name,AttributeList * attribute_list)945 getattributelist(PyObject *obj, const char *name, AttributeList *attribute_list)
946 {
947     int ret = 0;
948     DWORD err;
949     BOOL result;
950     PyObject *value;
951     Py_ssize_t handle_list_size;
952     DWORD attribute_count = 0;
953     SIZE_T attribute_list_size = 0;
954 
955     value = PyObject_GetAttrString(obj, name);
956     if (!value) {
957         PyErr_Clear(); /* FIXME: propagate error? */
958         return 0;
959     }
960 
961     if (value == Py_None) {
962         ret = 0;
963         goto cleanup;
964     }
965 
966     if (!PyMapping_Check(value)) {
967         ret = -1;
968         PyErr_Format(PyExc_TypeError, "%s must be a mapping or None", name);
969         goto cleanup;
970     }
971 
972     attribute_list->handle_list = gethandlelist(value, "handle_list", &handle_list_size);
973     if (attribute_list->handle_list == NULL && PyErr_Occurred()) {
974         ret = -1;
975         goto cleanup;
976     }
977 
978     if (attribute_list->handle_list != NULL)
979         ++attribute_count;
980 
981     /* Get how many bytes we need for the attribute list */
982     result = InitializeProcThreadAttributeList(NULL, attribute_count, 0, &attribute_list_size);
983     if (result || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
984         ret = -1;
985         PyErr_SetFromWindowsErr(GetLastError());
986         goto cleanup;
987     }
988 
989     attribute_list->attribute_list = PyMem_Malloc(attribute_list_size);
990     if (attribute_list->attribute_list == NULL) {
991         ret = -1;
992         goto cleanup;
993     }
994 
995     result = InitializeProcThreadAttributeList(
996         attribute_list->attribute_list,
997         attribute_count,
998         0,
999         &attribute_list_size);
1000     if (!result) {
1001         err = GetLastError();
1002 
1003         /* So that we won't call DeleteProcThreadAttributeList */
1004         PyMem_Free(attribute_list->attribute_list);
1005         attribute_list->attribute_list = NULL;
1006 
1007         ret = -1;
1008         PyErr_SetFromWindowsErr(err);
1009         goto cleanup;
1010     }
1011 
1012     if (attribute_list->handle_list != NULL) {
1013         result = UpdateProcThreadAttribute(
1014             attribute_list->attribute_list,
1015             0,
1016             PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1017             attribute_list->handle_list,
1018             handle_list_size,
1019             NULL,
1020             NULL);
1021         if (!result) {
1022             ret = -1;
1023             PyErr_SetFromWindowsErr(GetLastError());
1024             goto cleanup;
1025         }
1026     }
1027 
1028 cleanup:
1029     Py_DECREF(value);
1030 
1031     if (ret < 0)
1032         freeattributelist(attribute_list);
1033 
1034     return ret;
1035 }
1036 
1037 /*[clinic input]
1038 _winapi.CreateProcess
1039 
1040     application_name: Py_UNICODE(accept={str, NoneType})
1041     command_line: object
1042         Can be str or None
1043     proc_attrs: object
1044         Ignored internally, can be None.
1045     thread_attrs: object
1046         Ignored internally, can be None.
1047     inherit_handles: BOOL
1048     creation_flags: DWORD
1049     env_mapping: object
1050     current_directory: Py_UNICODE(accept={str, NoneType})
1051     startup_info: object
1052     /
1053 
1054 Create a new process and its primary thread.
1055 
1056 The return value is a tuple of the process handle, thread handle,
1057 process ID, and thread ID.
1058 [clinic start generated code]*/
1059 
1060 static PyObject *
_winapi_CreateProcess_impl(PyObject * module,const Py_UNICODE * application_name,PyObject * command_line,PyObject * proc_attrs,PyObject * thread_attrs,BOOL inherit_handles,DWORD creation_flags,PyObject * env_mapping,const Py_UNICODE * current_directory,PyObject * startup_info)1061 _winapi_CreateProcess_impl(PyObject *module,
1062                            const Py_UNICODE *application_name,
1063                            PyObject *command_line, PyObject *proc_attrs,
1064                            PyObject *thread_attrs, BOOL inherit_handles,
1065                            DWORD creation_flags, PyObject *env_mapping,
1066                            const Py_UNICODE *current_directory,
1067                            PyObject *startup_info)
1068 /*[clinic end generated code: output=9b2423a609230132 input=42ac293eaea03fc4]*/
1069 {
1070     PyObject *ret = NULL;
1071     BOOL result;
1072     PROCESS_INFORMATION pi;
1073     STARTUPINFOEXW si;
1074     wchar_t *wenvironment = NULL;
1075     wchar_t *command_line_copy = NULL;
1076     AttributeList attribute_list = {0};
1077 
1078     if (PySys_Audit("_winapi.CreateProcess", "uuu", application_name,
1079                     command_line, current_directory) < 0) {
1080         return NULL;
1081     }
1082 
1083     PyInterpreterState *interp = PyInterpreterState_Get();
1084     const PyConfig *config = _PyInterpreterState_GetConfig(interp);
1085     if (config->_isolated_interpreter) {
1086         PyErr_SetString(PyExc_RuntimeError,
1087                         "subprocess not supported for isolated subinterpreters");
1088         return NULL;
1089     }
1090 
1091     ZeroMemory(&si, sizeof(si));
1092     si.StartupInfo.cb = sizeof(si);
1093 
1094     /* note: we only support a small subset of all SI attributes */
1095     si.StartupInfo.dwFlags = getulong(startup_info, "dwFlags");
1096     si.StartupInfo.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
1097     si.StartupInfo.hStdInput = gethandle(startup_info, "hStdInput");
1098     si.StartupInfo.hStdOutput = gethandle(startup_info, "hStdOutput");
1099     si.StartupInfo.hStdError = gethandle(startup_info, "hStdError");
1100     if (PyErr_Occurred())
1101         goto cleanup;
1102 
1103     if (env_mapping != Py_None) {
1104         wenvironment = getenvironment(env_mapping);
1105         if (wenvironment == NULL) {
1106             goto cleanup;
1107         }
1108     }
1109 
1110     if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
1111         goto cleanup;
1112 
1113     si.lpAttributeList = attribute_list.attribute_list;
1114     if (PyUnicode_Check(command_line)) {
1115         command_line_copy = PyUnicode_AsWideCharString(command_line, NULL);
1116         if (command_line_copy == NULL) {
1117             goto cleanup;
1118         }
1119     }
1120     else if (command_line != Py_None) {
1121         PyErr_Format(PyExc_TypeError,
1122                      "CreateProcess() argument 2 must be str or None, not %s",
1123                      Py_TYPE(command_line)->tp_name);
1124         goto cleanup;
1125     }
1126 
1127 
1128     Py_BEGIN_ALLOW_THREADS
1129     result = CreateProcessW(application_name,
1130                            command_line_copy,
1131                            NULL,
1132                            NULL,
1133                            inherit_handles,
1134                            creation_flags | EXTENDED_STARTUPINFO_PRESENT |
1135                            CREATE_UNICODE_ENVIRONMENT,
1136                            wenvironment,
1137                            current_directory,
1138                            (LPSTARTUPINFOW)&si,
1139                            &pi);
1140     Py_END_ALLOW_THREADS
1141 
1142     if (!result) {
1143         PyErr_SetFromWindowsErr(GetLastError());
1144         goto cleanup;
1145     }
1146 
1147     ret = Py_BuildValue("NNkk",
1148                         HANDLE_TO_PYNUM(pi.hProcess),
1149                         HANDLE_TO_PYNUM(pi.hThread),
1150                         pi.dwProcessId,
1151                         pi.dwThreadId);
1152 
1153 cleanup:
1154     PyMem_Free(command_line_copy);
1155     PyMem_Free(wenvironment);
1156     freeattributelist(&attribute_list);
1157 
1158     return ret;
1159 }
1160 
1161 /*[clinic input]
1162 _winapi.DuplicateHandle -> HANDLE
1163 
1164     source_process_handle: HANDLE
1165     source_handle: HANDLE
1166     target_process_handle: HANDLE
1167     desired_access: DWORD
1168     inherit_handle: BOOL
1169     options: DWORD = 0
1170     /
1171 
1172 Return a duplicate handle object.
1173 
1174 The duplicate handle refers to the same object as the original
1175 handle. Therefore, any changes to the object are reflected
1176 through both handles.
1177 [clinic start generated code]*/
1178 
1179 static HANDLE
_winapi_DuplicateHandle_impl(PyObject * module,HANDLE source_process_handle,HANDLE source_handle,HANDLE target_process_handle,DWORD desired_access,BOOL inherit_handle,DWORD options)1180 _winapi_DuplicateHandle_impl(PyObject *module, HANDLE source_process_handle,
1181                              HANDLE source_handle,
1182                              HANDLE target_process_handle,
1183                              DWORD desired_access, BOOL inherit_handle,
1184                              DWORD options)
1185 /*[clinic end generated code: output=ad9711397b5dcd4e input=b933e3f2356a8c12]*/
1186 {
1187     HANDLE target_handle;
1188     BOOL result;
1189 
1190     Py_BEGIN_ALLOW_THREADS
1191     result = DuplicateHandle(
1192         source_process_handle,
1193         source_handle,
1194         target_process_handle,
1195         &target_handle,
1196         desired_access,
1197         inherit_handle,
1198         options
1199     );
1200     Py_END_ALLOW_THREADS
1201 
1202     if (! result) {
1203         PyErr_SetFromWindowsErr(GetLastError());
1204         return INVALID_HANDLE_VALUE;
1205     }
1206 
1207     return target_handle;
1208 }
1209 
1210 /*[clinic input]
1211 _winapi.ExitProcess
1212 
1213     ExitCode: UINT
1214     /
1215 
1216 [clinic start generated code]*/
1217 
1218 static PyObject *
_winapi_ExitProcess_impl(PyObject * module,UINT ExitCode)1219 _winapi_ExitProcess_impl(PyObject *module, UINT ExitCode)
1220 /*[clinic end generated code: output=a387deb651175301 input=4f05466a9406c558]*/
1221 {
1222     #if defined(Py_DEBUG)
1223         SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
1224                      SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
1225         _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
1226     #endif
1227 
1228     ExitProcess(ExitCode);
1229 
1230     return NULL;
1231 }
1232 
1233 /*[clinic input]
1234 _winapi.GetCurrentProcess -> HANDLE
1235 
1236 Return a handle object for the current process.
1237 [clinic start generated code]*/
1238 
1239 static HANDLE
_winapi_GetCurrentProcess_impl(PyObject * module)1240 _winapi_GetCurrentProcess_impl(PyObject *module)
1241 /*[clinic end generated code: output=ddeb4dd2ffadf344 input=b213403fd4b96b41]*/
1242 {
1243     return GetCurrentProcess();
1244 }
1245 
1246 /*[clinic input]
1247 _winapi.GetExitCodeProcess -> DWORD
1248 
1249     process: HANDLE
1250     /
1251 
1252 Return the termination status of the specified process.
1253 [clinic start generated code]*/
1254 
1255 static DWORD
_winapi_GetExitCodeProcess_impl(PyObject * module,HANDLE process)1256 _winapi_GetExitCodeProcess_impl(PyObject *module, HANDLE process)
1257 /*[clinic end generated code: output=b4620bdf2bccf36b input=61b6bfc7dc2ee374]*/
1258 {
1259     DWORD exit_code;
1260     BOOL result;
1261 
1262     result = GetExitCodeProcess(process, &exit_code);
1263 
1264     if (! result) {
1265         PyErr_SetFromWindowsErr(GetLastError());
1266         exit_code = PY_DWORD_MAX;
1267     }
1268 
1269     return exit_code;
1270 }
1271 
1272 /*[clinic input]
1273 _winapi.GetLastError -> DWORD
1274 [clinic start generated code]*/
1275 
1276 static DWORD
_winapi_GetLastError_impl(PyObject * module)1277 _winapi_GetLastError_impl(PyObject *module)
1278 /*[clinic end generated code: output=8585b827cb1a92c5 input=62d47fb9bce038ba]*/
1279 {
1280     return GetLastError();
1281 }
1282 
1283 /*[clinic input]
1284 _winapi.GetModuleFileName
1285 
1286     module_handle: HMODULE
1287     /
1288 
1289 Return the fully-qualified path for the file that contains module.
1290 
1291 The module must have been loaded by the current process.
1292 
1293 The module parameter should be a handle to the loaded module
1294 whose path is being requested. If this parameter is 0,
1295 GetModuleFileName retrieves the path of the executable file
1296 of the current process.
1297 [clinic start generated code]*/
1298 
1299 static PyObject *
_winapi_GetModuleFileName_impl(PyObject * module,HMODULE module_handle)1300 _winapi_GetModuleFileName_impl(PyObject *module, HMODULE module_handle)
1301 /*[clinic end generated code: output=85b4b728c5160306 input=6d66ff7deca5d11f]*/
1302 {
1303     BOOL result;
1304     WCHAR filename[MAX_PATH];
1305 
1306     Py_BEGIN_ALLOW_THREADS
1307     result = GetModuleFileNameW(module_handle, filename, MAX_PATH);
1308     filename[MAX_PATH-1] = '\0';
1309     Py_END_ALLOW_THREADS
1310 
1311     if (! result)
1312         return PyErr_SetFromWindowsErr(GetLastError());
1313 
1314     return PyUnicode_FromWideChar(filename, wcslen(filename));
1315 }
1316 
1317 /*[clinic input]
1318 _winapi.GetStdHandle -> HANDLE
1319 
1320     std_handle: DWORD
1321         One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE.
1322     /
1323 
1324 Return a handle to the specified standard device.
1325 
1326 The integer associated with the handle object is returned.
1327 [clinic start generated code]*/
1328 
1329 static HANDLE
_winapi_GetStdHandle_impl(PyObject * module,DWORD std_handle)1330 _winapi_GetStdHandle_impl(PyObject *module, DWORD std_handle)
1331 /*[clinic end generated code: output=0e613001e73ab614 input=07016b06a2fc8826]*/
1332 {
1333     HANDLE handle;
1334 
1335     Py_BEGIN_ALLOW_THREADS
1336     handle = GetStdHandle(std_handle);
1337     Py_END_ALLOW_THREADS
1338 
1339     if (handle == INVALID_HANDLE_VALUE)
1340         PyErr_SetFromWindowsErr(GetLastError());
1341 
1342     return handle;
1343 }
1344 
1345 /*[clinic input]
1346 _winapi.GetVersion -> long
1347 
1348 Return the version number of the current operating system.
1349 [clinic start generated code]*/
1350 
1351 static long
_winapi_GetVersion_impl(PyObject * module)1352 _winapi_GetVersion_impl(PyObject *module)
1353 /*[clinic end generated code: output=e41f0db5a3b82682 input=e21dff8d0baeded2]*/
1354 /* Disable deprecation warnings about GetVersionEx as the result is
1355    being passed straight through to the caller, who is responsible for
1356    using it correctly. */
1357 #pragma warning(push)
1358 #pragma warning(disable:4996)
1359 
1360 {
1361     return GetVersion();
1362 }
1363 
1364 #pragma warning(pop)
1365 
1366 /*[clinic input]
1367 _winapi.MapViewOfFile -> LPVOID
1368 
1369     file_map: HANDLE
1370     desired_access: DWORD
1371     file_offset_high: DWORD
1372     file_offset_low: DWORD
1373     number_bytes: size_t
1374     /
1375 [clinic start generated code]*/
1376 
1377 static LPVOID
_winapi_MapViewOfFile_impl(PyObject * module,HANDLE file_map,DWORD desired_access,DWORD file_offset_high,DWORD file_offset_low,size_t number_bytes)1378 _winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map,
1379                            DWORD desired_access, DWORD file_offset_high,
1380                            DWORD file_offset_low, size_t number_bytes)
1381 /*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/
1382 {
1383     LPVOID address;
1384 
1385     Py_BEGIN_ALLOW_THREADS
1386     address = MapViewOfFile(file_map, desired_access, file_offset_high,
1387                             file_offset_low, number_bytes);
1388     Py_END_ALLOW_THREADS
1389 
1390     if (address == NULL)
1391         PyErr_SetFromWindowsErr(0);
1392 
1393     return address;
1394 }
1395 
1396 /*[clinic input]
1397 _winapi.OpenFileMapping -> HANDLE
1398 
1399     desired_access: DWORD
1400     inherit_handle: BOOL
1401     name: LPCWSTR
1402     /
1403 [clinic start generated code]*/
1404 
1405 static HANDLE
_winapi_OpenFileMapping_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1406 _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access,
1407                              BOOL inherit_handle, LPCWSTR name)
1408 /*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/
1409 {
1410     HANDLE handle;
1411 
1412     Py_BEGIN_ALLOW_THREADS
1413     handle = OpenFileMappingW(desired_access, inherit_handle, name);
1414     Py_END_ALLOW_THREADS
1415 
1416     if (handle == NULL) {
1417         PyObject *temp = PyUnicode_FromWideChar(name, -1);
1418         PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
1419         Py_XDECREF(temp);
1420         handle = INVALID_HANDLE_VALUE;
1421     }
1422 
1423     return handle;
1424 }
1425 
1426 /*[clinic input]
1427 _winapi.OpenProcess -> HANDLE
1428 
1429     desired_access: DWORD
1430     inherit_handle: BOOL
1431     process_id: DWORD
1432     /
1433 [clinic start generated code]*/
1434 
1435 static HANDLE
_winapi_OpenProcess_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,DWORD process_id)1436 _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access,
1437                          BOOL inherit_handle, DWORD process_id)
1438 /*[clinic end generated code: output=b42b6b81ea5a0fc3 input=ec98c4cf4ea2ec36]*/
1439 {
1440     HANDLE handle;
1441 
1442     if (PySys_Audit("_winapi.OpenProcess", "II",
1443                     process_id, desired_access) < 0) {
1444         return INVALID_HANDLE_VALUE;
1445     }
1446 
1447     Py_BEGIN_ALLOW_THREADS
1448     handle = OpenProcess(desired_access, inherit_handle, process_id);
1449     Py_END_ALLOW_THREADS
1450     if (handle == NULL) {
1451         PyErr_SetFromWindowsErr(GetLastError());
1452         handle = INVALID_HANDLE_VALUE;
1453     }
1454 
1455     return handle;
1456 }
1457 
1458 /*[clinic input]
1459 _winapi.PeekNamedPipe
1460 
1461     handle: HANDLE
1462     size: int = 0
1463     /
1464 [clinic start generated code]*/
1465 
1466 static PyObject *
_winapi_PeekNamedPipe_impl(PyObject * module,HANDLE handle,int size)1467 _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
1468 /*[clinic end generated code: output=d0c3e29e49d323dd input=c7aa53bfbce69d70]*/
1469 {
1470     PyObject *buf = NULL;
1471     DWORD nread, navail, nleft;
1472     BOOL ret;
1473 
1474     if (size < 0) {
1475         PyErr_SetString(PyExc_ValueError, "negative size");
1476         return NULL;
1477     }
1478 
1479     if (size) {
1480         buf = PyBytes_FromStringAndSize(NULL, size);
1481         if (!buf)
1482             return NULL;
1483         Py_BEGIN_ALLOW_THREADS
1484         ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1485                             &navail, &nleft);
1486         Py_END_ALLOW_THREADS
1487         if (!ret) {
1488             Py_DECREF(buf);
1489             return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1490         }
1491         if (_PyBytes_Resize(&buf, nread))
1492             return NULL;
1493         return Py_BuildValue("NII", buf, navail, nleft);
1494     }
1495     else {
1496         Py_BEGIN_ALLOW_THREADS
1497         ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1498         Py_END_ALLOW_THREADS
1499         if (!ret) {
1500             return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1501         }
1502         return Py_BuildValue("II", navail, nleft);
1503     }
1504 }
1505 
1506 /*[clinic input]
1507 _winapi.ReadFile
1508 
1509     handle: HANDLE
1510     size: DWORD
1511     overlapped as use_overlapped: bool(accept={int}) = False
1512 [clinic start generated code]*/
1513 
1514 static PyObject *
_winapi_ReadFile_impl(PyObject * module,HANDLE handle,DWORD size,int use_overlapped)1515 _winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
1516                       int use_overlapped)
1517 /*[clinic end generated code: output=d3d5b44a8201b944 input=08c439d03a11aac5]*/
1518 {
1519     DWORD nread;
1520     PyObject *buf;
1521     BOOL ret;
1522     DWORD err;
1523     OverlappedObject *overlapped = NULL;
1524 
1525     buf = PyBytes_FromStringAndSize(NULL, size);
1526     if (!buf)
1527         return NULL;
1528     if (use_overlapped) {
1529         overlapped = new_overlapped(handle);
1530         if (!overlapped) {
1531             Py_DECREF(buf);
1532             return NULL;
1533         }
1534         /* Steals reference to buf */
1535         overlapped->read_buffer = buf;
1536     }
1537 
1538     Py_BEGIN_ALLOW_THREADS
1539     ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
1540                    overlapped ? &overlapped->overlapped : NULL);
1541     Py_END_ALLOW_THREADS
1542 
1543     err = ret ? 0 : GetLastError();
1544 
1545     if (overlapped) {
1546         if (!ret) {
1547             if (err == ERROR_IO_PENDING)
1548                 overlapped->pending = 1;
1549             else if (err != ERROR_MORE_DATA) {
1550                 Py_DECREF(overlapped);
1551                 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1552             }
1553         }
1554         return Py_BuildValue("NI", (PyObject *) overlapped, err);
1555     }
1556 
1557     if (!ret && err != ERROR_MORE_DATA) {
1558         Py_DECREF(buf);
1559         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1560     }
1561     if (_PyBytes_Resize(&buf, nread))
1562         return NULL;
1563     return Py_BuildValue("NI", buf, err);
1564 }
1565 
1566 /*[clinic input]
1567 _winapi.SetNamedPipeHandleState
1568 
1569     named_pipe: HANDLE
1570     mode: object
1571     max_collection_count: object
1572     collect_data_timeout: object
1573     /
1574 [clinic start generated code]*/
1575 
1576 static PyObject *
_winapi_SetNamedPipeHandleState_impl(PyObject * module,HANDLE named_pipe,PyObject * mode,PyObject * max_collection_count,PyObject * collect_data_timeout)1577 _winapi_SetNamedPipeHandleState_impl(PyObject *module, HANDLE named_pipe,
1578                                      PyObject *mode,
1579                                      PyObject *max_collection_count,
1580                                      PyObject *collect_data_timeout)
1581 /*[clinic end generated code: output=f2129d222cbfa095 input=9142d72163d0faa6]*/
1582 {
1583     PyObject *oArgs[3] = {mode, max_collection_count, collect_data_timeout};
1584     DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
1585     int i;
1586     BOOL b;
1587 
1588     for (i = 0 ; i < 3 ; i++) {
1589         if (oArgs[i] != Py_None) {
1590             dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
1591             if (PyErr_Occurred())
1592                 return NULL;
1593             pArgs[i] = &dwArgs[i];
1594         }
1595     }
1596 
1597     Py_BEGIN_ALLOW_THREADS
1598     b = SetNamedPipeHandleState(named_pipe, pArgs[0], pArgs[1], pArgs[2]);
1599     Py_END_ALLOW_THREADS
1600 
1601     if (!b)
1602         return PyErr_SetFromWindowsErr(0);
1603 
1604     Py_RETURN_NONE;
1605 }
1606 
1607 
1608 /*[clinic input]
1609 _winapi.TerminateProcess
1610 
1611     handle: HANDLE
1612     exit_code: UINT
1613     /
1614 
1615 Terminate the specified process and all of its threads.
1616 [clinic start generated code]*/
1617 
1618 static PyObject *
_winapi_TerminateProcess_impl(PyObject * module,HANDLE handle,UINT exit_code)1619 _winapi_TerminateProcess_impl(PyObject *module, HANDLE handle,
1620                               UINT exit_code)
1621 /*[clinic end generated code: output=f4e99ac3f0b1f34a input=d6bc0aa1ee3bb4df]*/
1622 {
1623     BOOL result;
1624 
1625     if (PySys_Audit("_winapi.TerminateProcess", "nI",
1626                     (Py_ssize_t)handle, exit_code) < 0) {
1627         return NULL;
1628     }
1629 
1630     result = TerminateProcess(handle, exit_code);
1631 
1632     if (! result)
1633         return PyErr_SetFromWindowsErr(GetLastError());
1634 
1635     Py_RETURN_NONE;
1636 }
1637 
1638 /*[clinic input]
1639 _winapi.VirtualQuerySize -> size_t
1640 
1641     address: LPCVOID
1642     /
1643 [clinic start generated code]*/
1644 
1645 static size_t
_winapi_VirtualQuerySize_impl(PyObject * module,LPCVOID address)1646 _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address)
1647 /*[clinic end generated code: output=40c8e0ff5ec964df input=6b784a69755d0bb6]*/
1648 {
1649     SIZE_T size_of_buf;
1650     MEMORY_BASIC_INFORMATION mem_basic_info;
1651     SIZE_T region_size;
1652 
1653     Py_BEGIN_ALLOW_THREADS
1654     size_of_buf = VirtualQuery(address, &mem_basic_info, sizeof(mem_basic_info));
1655     Py_END_ALLOW_THREADS
1656 
1657     if (size_of_buf == 0)
1658         PyErr_SetFromWindowsErr(0);
1659 
1660     region_size = mem_basic_info.RegionSize;
1661     return region_size;
1662 }
1663 
1664 /*[clinic input]
1665 _winapi.WaitNamedPipe
1666 
1667     name: LPCTSTR
1668     timeout: DWORD
1669     /
1670 [clinic start generated code]*/
1671 
1672 static PyObject *
_winapi_WaitNamedPipe_impl(PyObject * module,LPCTSTR name,DWORD timeout)1673 _winapi_WaitNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD timeout)
1674 /*[clinic end generated code: output=c2866f4439b1fe38 input=36fc781291b1862c]*/
1675 {
1676     BOOL success;
1677 
1678     Py_BEGIN_ALLOW_THREADS
1679     success = WaitNamedPipe(name, timeout);
1680     Py_END_ALLOW_THREADS
1681 
1682     if (!success)
1683         return PyErr_SetFromWindowsErr(0);
1684 
1685     Py_RETURN_NONE;
1686 }
1687 
1688 /*[clinic input]
1689 _winapi.WaitForMultipleObjects
1690 
1691     handle_seq: object
1692     wait_flag: BOOL
1693     milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
1694     /
1695 [clinic start generated code]*/
1696 
1697 static PyObject *
_winapi_WaitForMultipleObjects_impl(PyObject * module,PyObject * handle_seq,BOOL wait_flag,DWORD milliseconds)1698 _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq,
1699                                     BOOL wait_flag, DWORD milliseconds)
1700 /*[clinic end generated code: output=295e3f00b8e45899 input=36f76ca057cd28a0]*/
1701 {
1702     DWORD result;
1703     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1704     HANDLE sigint_event = NULL;
1705     Py_ssize_t nhandles, i;
1706 
1707     if (!PySequence_Check(handle_seq)) {
1708         PyErr_Format(PyExc_TypeError,
1709                      "sequence type expected, got '%s'",
1710                      Py_TYPE(handle_seq)->tp_name);
1711         return NULL;
1712     }
1713     nhandles = PySequence_Length(handle_seq);
1714     if (nhandles == -1)
1715         return NULL;
1716     if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) {
1717         PyErr_Format(PyExc_ValueError,
1718                      "need at most %zd handles, got a sequence of length %zd",
1719                      MAXIMUM_WAIT_OBJECTS - 1, nhandles);
1720         return NULL;
1721     }
1722     for (i = 0; i < nhandles; i++) {
1723         HANDLE h;
1724         PyObject *v = PySequence_GetItem(handle_seq, i);
1725         if (v == NULL)
1726             return NULL;
1727         if (!PyArg_Parse(v, F_HANDLE, &h)) {
1728             Py_DECREF(v);
1729             return NULL;
1730         }
1731         handles[i] = h;
1732         Py_DECREF(v);
1733     }
1734     /* If this is the main thread then make the wait interruptible
1735        by Ctrl-C unless we are waiting for *all* handles */
1736     if (!wait_flag && _PyOS_IsMainThread()) {
1737         sigint_event = _PyOS_SigintEvent();
1738         assert(sigint_event != NULL);
1739         handles[nhandles++] = sigint_event;
1740     }
1741 
1742     Py_BEGIN_ALLOW_THREADS
1743     if (sigint_event != NULL)
1744         ResetEvent(sigint_event);
1745     result = WaitForMultipleObjects((DWORD) nhandles, handles,
1746                                     wait_flag, milliseconds);
1747     Py_END_ALLOW_THREADS
1748 
1749     if (result == WAIT_FAILED)
1750         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1751     else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
1752         errno = EINTR;
1753         return PyErr_SetFromErrno(PyExc_OSError);
1754     }
1755 
1756     return PyLong_FromLong((int) result);
1757 }
1758 
1759 /*[clinic input]
1760 _winapi.WaitForSingleObject -> long
1761 
1762     handle: HANDLE
1763     milliseconds: DWORD
1764     /
1765 
1766 Wait for a single object.
1767 
1768 Wait until the specified object is in the signaled state or
1769 the time-out interval elapses. The timeout value is specified
1770 in milliseconds.
1771 [clinic start generated code]*/
1772 
1773 static long
_winapi_WaitForSingleObject_impl(PyObject * module,HANDLE handle,DWORD milliseconds)1774 _winapi_WaitForSingleObject_impl(PyObject *module, HANDLE handle,
1775                                  DWORD milliseconds)
1776 /*[clinic end generated code: output=3c4715d8f1b39859 input=443d1ab076edc7b1]*/
1777 {
1778     DWORD result;
1779 
1780     Py_BEGIN_ALLOW_THREADS
1781     result = WaitForSingleObject(handle, milliseconds);
1782     Py_END_ALLOW_THREADS
1783 
1784     if (result == WAIT_FAILED) {
1785         PyErr_SetFromWindowsErr(GetLastError());
1786         return -1;
1787     }
1788 
1789     return result;
1790 }
1791 
1792 /*[clinic input]
1793 _winapi.WriteFile
1794 
1795     handle: HANDLE
1796     buffer: object
1797     overlapped as use_overlapped: bool(accept={int}) = False
1798 [clinic start generated code]*/
1799 
1800 static PyObject *
_winapi_WriteFile_impl(PyObject * module,HANDLE handle,PyObject * buffer,int use_overlapped)1801 _winapi_WriteFile_impl(PyObject *module, HANDLE handle, PyObject *buffer,
1802                        int use_overlapped)
1803 /*[clinic end generated code: output=2ca80f6bf3fa92e3 input=11eae2a03aa32731]*/
1804 {
1805     Py_buffer _buf, *buf;
1806     DWORD len, written;
1807     BOOL ret;
1808     DWORD err;
1809     OverlappedObject *overlapped = NULL;
1810 
1811     if (use_overlapped) {
1812         overlapped = new_overlapped(handle);
1813         if (!overlapped)
1814             return NULL;
1815         buf = &overlapped->write_buffer;
1816     }
1817     else
1818         buf = &_buf;
1819 
1820     if (!PyArg_Parse(buffer, "y*", buf)) {
1821         Py_XDECREF(overlapped);
1822         return NULL;
1823     }
1824 
1825     Py_BEGIN_ALLOW_THREADS
1826     len = (DWORD)Py_MIN(buf->len, PY_DWORD_MAX);
1827     ret = WriteFile(handle, buf->buf, len, &written,
1828                     overlapped ? &overlapped->overlapped : NULL);
1829     Py_END_ALLOW_THREADS
1830 
1831     err = ret ? 0 : GetLastError();
1832 
1833     if (overlapped) {
1834         if (!ret) {
1835             if (err == ERROR_IO_PENDING)
1836                 overlapped->pending = 1;
1837             else {
1838                 Py_DECREF(overlapped);
1839                 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1840             }
1841         }
1842         return Py_BuildValue("NI", (PyObject *) overlapped, err);
1843     }
1844 
1845     PyBuffer_Release(buf);
1846     if (!ret)
1847         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1848     return Py_BuildValue("II", written, err);
1849 }
1850 
1851 /*[clinic input]
1852 _winapi.GetACP
1853 
1854 Get the current Windows ANSI code page identifier.
1855 [clinic start generated code]*/
1856 
1857 static PyObject *
_winapi_GetACP_impl(PyObject * module)1858 _winapi_GetACP_impl(PyObject *module)
1859 /*[clinic end generated code: output=f7ee24bf705dbb88 input=1433c96d03a05229]*/
1860 {
1861     return PyLong_FromUnsignedLong(GetACP());
1862 }
1863 
1864 /*[clinic input]
1865 _winapi.GetFileType -> DWORD
1866 
1867     handle: HANDLE
1868 [clinic start generated code]*/
1869 
1870 static DWORD
_winapi_GetFileType_impl(PyObject * module,HANDLE handle)1871 _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
1872 /*[clinic end generated code: output=92b8466ac76ecc17 input=0058366bc40bbfbf]*/
1873 {
1874     DWORD result;
1875 
1876     Py_BEGIN_ALLOW_THREADS
1877     result = GetFileType(handle);
1878     Py_END_ALLOW_THREADS
1879 
1880     if (result == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) {
1881         PyErr_SetFromWindowsErr(0);
1882         return -1;
1883     }
1884 
1885     return result;
1886 }
1887 
1888 
1889 static PyMethodDef winapi_functions[] = {
1890     _WINAPI_CLOSEHANDLE_METHODDEF
1891     _WINAPI_CONNECTNAMEDPIPE_METHODDEF
1892     _WINAPI_CREATEFILE_METHODDEF
1893     _WINAPI_CREATEFILEMAPPING_METHODDEF
1894     _WINAPI_CREATENAMEDPIPE_METHODDEF
1895     _WINAPI_CREATEPIPE_METHODDEF
1896     _WINAPI_CREATEPROCESS_METHODDEF
1897     _WINAPI_CREATEJUNCTION_METHODDEF
1898     _WINAPI_DUPLICATEHANDLE_METHODDEF
1899     _WINAPI_EXITPROCESS_METHODDEF
1900     _WINAPI_GETCURRENTPROCESS_METHODDEF
1901     _WINAPI_GETEXITCODEPROCESS_METHODDEF
1902     _WINAPI_GETLASTERROR_METHODDEF
1903     _WINAPI_GETMODULEFILENAME_METHODDEF
1904     _WINAPI_GETSTDHANDLE_METHODDEF
1905     _WINAPI_GETVERSION_METHODDEF
1906     _WINAPI_MAPVIEWOFFILE_METHODDEF
1907     _WINAPI_OPENFILEMAPPING_METHODDEF
1908     _WINAPI_OPENPROCESS_METHODDEF
1909     _WINAPI_PEEKNAMEDPIPE_METHODDEF
1910     _WINAPI_READFILE_METHODDEF
1911     _WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF
1912     _WINAPI_TERMINATEPROCESS_METHODDEF
1913     _WINAPI_VIRTUALQUERYSIZE_METHODDEF
1914     _WINAPI_WAITNAMEDPIPE_METHODDEF
1915     _WINAPI_WAITFORMULTIPLEOBJECTS_METHODDEF
1916     _WINAPI_WAITFORSINGLEOBJECT_METHODDEF
1917     _WINAPI_WRITEFILE_METHODDEF
1918     _WINAPI_GETACP_METHODDEF
1919     _WINAPI_GETFILETYPE_METHODDEF
1920     {NULL, NULL}
1921 };
1922 
1923 static struct PyModuleDef winapi_module = {
1924     PyModuleDef_HEAD_INIT,
1925     "_winapi",
1926     NULL,
1927     -1,
1928     winapi_functions,
1929     NULL,
1930     NULL,
1931     NULL,
1932     NULL
1933 };
1934 
1935 #define WINAPI_CONSTANT(fmt, con) \
1936     PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1937 
1938 PyMODINIT_FUNC
PyInit__winapi(void)1939 PyInit__winapi(void)
1940 {
1941     PyObject *d;
1942     PyObject *m;
1943 
1944     if (PyType_Ready(&OverlappedType) < 0)
1945         return NULL;
1946 
1947     m = PyModule_Create(&winapi_module);
1948     if (m == NULL)
1949         return NULL;
1950     d = PyModule_GetDict(m);
1951 
1952     PyDict_SetItemString(d, "Overlapped", (PyObject *) &OverlappedType);
1953 
1954     /* constants */
1955     WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
1956     WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
1957     WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
1958     WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
1959     WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
1960     WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
1961     WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1962     WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1963     WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1964     WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
1965     WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1966     WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1967     WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
1968     WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
1969     WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
1970     WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
1971     WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
1972     WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
1973     WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
1974     WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
1975     WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
1976     WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
1977     WINAPI_CONSTANT(F_DWORD, FILE_MAP_ALL_ACCESS);
1978     WINAPI_CONSTANT(F_DWORD, FILE_MAP_COPY);
1979     WINAPI_CONSTANT(F_DWORD, FILE_MAP_EXECUTE);
1980     WINAPI_CONSTANT(F_DWORD, FILE_MAP_READ);
1981     WINAPI_CONSTANT(F_DWORD, FILE_MAP_WRITE);
1982     WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
1983     WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
1984     WINAPI_CONSTANT(F_DWORD, INFINITE);
1985     WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1986     WINAPI_CONSTANT(F_DWORD, MEM_COMMIT);
1987     WINAPI_CONSTANT(F_DWORD, MEM_FREE);
1988     WINAPI_CONSTANT(F_DWORD, MEM_IMAGE);
1989     WINAPI_CONSTANT(F_DWORD, MEM_MAPPED);
1990     WINAPI_CONSTANT(F_DWORD, MEM_PRIVATE);
1991     WINAPI_CONSTANT(F_DWORD, MEM_RESERVE);
1992     WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
1993     WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
1994     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE);
1995     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READ);
1996     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READWRITE);
1997     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_WRITECOPY);
1998     WINAPI_CONSTANT(F_DWORD, PAGE_GUARD);
1999     WINAPI_CONSTANT(F_DWORD, PAGE_NOACCESS);
2000     WINAPI_CONSTANT(F_DWORD, PAGE_NOCACHE);
2001     WINAPI_CONSTANT(F_DWORD, PAGE_READONLY);
2002     WINAPI_CONSTANT(F_DWORD, PAGE_READWRITE);
2003     WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOMBINE);
2004     WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOPY);
2005     WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
2006     WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
2007     WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
2008     WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
2009     WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
2010     WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
2011     WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
2012     WINAPI_CONSTANT(F_DWORD, SYNCHRONIZE);
2013     WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
2014     WINAPI_CONSTANT(F_DWORD, SEC_COMMIT);
2015     WINAPI_CONSTANT(F_DWORD, SEC_IMAGE);
2016     WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES);
2017     WINAPI_CONSTANT(F_DWORD, SEC_NOCACHE);
2018     WINAPI_CONSTANT(F_DWORD, SEC_RESERVE);
2019     WINAPI_CONSTANT(F_DWORD, SEC_WRITECOMBINE);
2020     WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
2021     WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
2022     WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
2023     WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
2024     WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
2025     WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
2026     WINAPI_CONSTANT(F_DWORD, SW_HIDE);
2027     WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
2028     WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
2029     WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
2030 
2031     WINAPI_CONSTANT(F_DWORD, ABOVE_NORMAL_PRIORITY_CLASS);
2032     WINAPI_CONSTANT(F_DWORD, BELOW_NORMAL_PRIORITY_CLASS);
2033     WINAPI_CONSTANT(F_DWORD, HIGH_PRIORITY_CLASS);
2034     WINAPI_CONSTANT(F_DWORD, IDLE_PRIORITY_CLASS);
2035     WINAPI_CONSTANT(F_DWORD, NORMAL_PRIORITY_CLASS);
2036     WINAPI_CONSTANT(F_DWORD, REALTIME_PRIORITY_CLASS);
2037 
2038     WINAPI_CONSTANT(F_DWORD, CREATE_NO_WINDOW);
2039     WINAPI_CONSTANT(F_DWORD, DETACHED_PROCESS);
2040     WINAPI_CONSTANT(F_DWORD, CREATE_DEFAULT_ERROR_MODE);
2041     WINAPI_CONSTANT(F_DWORD, CREATE_BREAKAWAY_FROM_JOB);
2042 
2043     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_UNKNOWN);
2044     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_DISK);
2045     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_CHAR);
2046     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_PIPE);
2047     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_REMOTE);
2048 
2049     WINAPI_CONSTANT("i", NULL);
2050 
2051     return m;
2052 }
2053