• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 https://www.python.org/2.4/license for licensing details. */
36 
37 #include "Python.h"
38 #include "pycore_moduleobject.h"  // _PyModule_GetState()
39 #include "pycore_pylifecycle.h"   // _Py_IsInterpreterFinalizing()
40 #include "pycore_pystate.h"       // _PyInterpreterState_GET
41 
42 
43 
44 #ifndef WINDOWS_LEAN_AND_MEAN
45 #define WINDOWS_LEAN_AND_MEAN
46 #endif
47 #include "windows.h"
48 #include <winioctl.h>
49 #include <crtdbg.h>
50 #include "winreparse.h"
51 
52 #if defined(MS_WIN32) && !defined(MS_WIN64)
53 #define HANDLE_TO_PYNUM(handle) \
54     PyLong_FromUnsignedLong((unsigned long) handle)
55 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
56 #define F_POINTER "k"
57 #define T_POINTER Py_T_ULONG
58 #else
59 #define HANDLE_TO_PYNUM(handle) \
60     PyLong_FromUnsignedLongLong((unsigned long long) handle)
61 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLongLong(obj))
62 #define F_POINTER "K"
63 #define T_POINTER Py_T_ULONGLONG
64 #endif
65 
66 #define F_HANDLE F_POINTER
67 #define F_DWORD "k"
68 
69 #define T_HANDLE T_POINTER
70 
71 // winbase.h limits the STARTF_* flags to the desktop API as of 10.0.19041.
72 #ifndef STARTF_USESHOWWINDOW
73 #define STARTF_USESHOWWINDOW 0x00000001
74 #endif
75 #ifndef STARTF_USESIZE
76 #define STARTF_USESIZE 0x00000002
77 #endif
78 #ifndef STARTF_USEPOSITION
79 #define STARTF_USEPOSITION 0x00000004
80 #endif
81 #ifndef STARTF_USECOUNTCHARS
82 #define STARTF_USECOUNTCHARS 0x00000008
83 #endif
84 #ifndef STARTF_USEFILLATTRIBUTE
85 #define STARTF_USEFILLATTRIBUTE 0x00000010
86 #endif
87 #ifndef STARTF_RUNFULLSCREEN
88 #define STARTF_RUNFULLSCREEN 0x00000020
89 #endif
90 #ifndef STARTF_FORCEONFEEDBACK
91 #define STARTF_FORCEONFEEDBACK 0x00000040
92 #endif
93 #ifndef STARTF_FORCEOFFFEEDBACK
94 #define STARTF_FORCEOFFFEEDBACK 0x00000080
95 #endif
96 #ifndef STARTF_USESTDHANDLES
97 #define STARTF_USESTDHANDLES 0x00000100
98 #endif
99 #ifndef STARTF_USEHOTKEY
100 #define STARTF_USEHOTKEY 0x00000200
101 #endif
102 #ifndef STARTF_TITLEISLINKNAME
103 #define STARTF_TITLEISLINKNAME 0x00000800
104 #endif
105 #ifndef STARTF_TITLEISAPPID
106 #define STARTF_TITLEISAPPID 0x00001000
107 #endif
108 #ifndef STARTF_PREVENTPINNING
109 #define STARTF_PREVENTPINNING 0x00002000
110 #endif
111 #ifndef STARTF_UNTRUSTEDSOURCE
112 #define STARTF_UNTRUSTEDSOURCE 0x00008000
113 #endif
114 
115 typedef struct {
116     PyTypeObject *overlapped_type;
117 } WinApiState;
118 
119 static inline WinApiState*
winapi_get_state(PyObject * module)120 winapi_get_state(PyObject *module)
121 {
122     void *state = _PyModule_GetState(module);
123     assert(state != NULL);
124     return (WinApiState *)state;
125 }
126 
127 /*
128  * A Python object wrapping an OVERLAPPED structure and other useful data
129  * for overlapped I/O
130  */
131 
132 typedef struct {
133     PyObject_HEAD
134     OVERLAPPED overlapped;
135     /* For convenience, we store the file handle too */
136     HANDLE handle;
137     /* Whether there's I/O in flight */
138     int pending;
139     /* Whether I/O completed successfully */
140     int completed;
141     /* Buffer used for reading (optional) */
142     PyObject *read_buffer;
143     /* Buffer used for writing (optional) */
144     Py_buffer write_buffer;
145 } OverlappedObject;
146 
147 /*
148 Note: tp_clear (overlapped_clear) is not implemented because it
149 requires cancelling the IO operation if it's pending and the cancellation is
150 quite complex and can fail (see: overlapped_dealloc).
151 */
152 static int
overlapped_traverse(OverlappedObject * self,visitproc visit,void * arg)153 overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
154 {
155     Py_VISIT(self->read_buffer);
156     Py_VISIT(self->write_buffer.obj);
157     Py_VISIT(Py_TYPE(self));
158     return 0;
159 }
160 
161 static void
overlapped_dealloc(OverlappedObject * self)162 overlapped_dealloc(OverlappedObject *self)
163 {
164     DWORD bytes;
165     int err = GetLastError();
166 
167     PyObject_GC_UnTrack(self);
168     if (self->pending) {
169         if (CancelIoEx(self->handle, &self->overlapped) &&
170             GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE))
171         {
172             /* The operation is no longer pending -- nothing to do. */
173         }
174         else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET()))
175         {
176             /* The operation is still pending -- give a warning.  This
177                will probably only happen on Windows XP. */
178             PyErr_SetString(PyExc_PythonFinalizationError,
179                             "I/O operations still in flight while destroying "
180                             "Overlapped object, the process may crash");
181             PyErr_WriteUnraisable(NULL);
182         }
183         else
184         {
185             /* The operation is still pending, but the process is
186                probably about to exit, so we need not worry too much
187                about memory leaks.  Leaking self prevents a potential
188                crash.  This can happen when a daemon thread is cleaned
189                up at exit -- see #19565.  We only expect to get here
190                on Windows XP. */
191             CloseHandle(self->overlapped.hEvent);
192             SetLastError(err);
193             return;
194         }
195     }
196 
197     CloseHandle(self->overlapped.hEvent);
198     SetLastError(err);
199     if (self->write_buffer.obj)
200         PyBuffer_Release(&self->write_buffer);
201     Py_CLEAR(self->read_buffer);
202     PyTypeObject *tp = Py_TYPE(self);
203     tp->tp_free(self);
204     Py_DECREF(tp);
205 }
206 
207 /*[clinic input]
208 module _winapi
209 class _winapi.Overlapped "OverlappedObject *" "&OverlappedType"
210 [clinic start generated code]*/
211 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c13d3f5fd1dabb84]*/
212 
213 /*[python input]
214 def create_converter(type_, format_unit):
215     name = type_ + '_converter'
216     # registered upon creation by CConverter's metaclass
217     type(name, (CConverter,), {'type': type_, 'format_unit': format_unit})
218 
219 # format unit differs between platforms for these
220 create_converter('HANDLE', '" F_HANDLE "')
221 create_converter('HMODULE', '" F_HANDLE "')
222 create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "')
223 create_converter('LPCVOID', '" F_POINTER "')
224 
225 create_converter('BOOL', 'i') # F_BOOL used previously (always 'i')
226 create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter)
227 create_converter('UINT', 'I') # F_UINT used previously (always 'I')
228 
229 class LPCWSTR_converter(Py_UNICODE_converter):
230     type = 'LPCWSTR'
231 
232 class HANDLE_return_converter(CReturnConverter):
233     type = 'HANDLE'
234 
235     def render(self, function, data):
236         self.declare(data)
237         self.err_occurred_if("_return_value == INVALID_HANDLE_VALUE", data)
238         data.return_conversion.append(
239             'if (_return_value == NULL) {\n    Py_RETURN_NONE;\n}\n')
240         data.return_conversion.append(
241             'return_value = HANDLE_TO_PYNUM(_return_value);\n')
242 
243 class DWORD_return_converter(CReturnConverter):
244     type = 'DWORD'
245 
246     def render(self, function, data):
247         self.declare(data)
248         self.err_occurred_if("_return_value == PY_DWORD_MAX", data)
249         data.return_conversion.append(
250             'return_value = PyLong_FromUnsignedLong(_return_value);\n')
251 
252 class LPVOID_return_converter(CReturnConverter):
253     type = 'LPVOID'
254 
255     def render(self, function, data):
256         self.declare(data)
257         self.err_occurred_if("_return_value == NULL", data)
258         data.return_conversion.append(
259             'return_value = HANDLE_TO_PYNUM(_return_value);\n')
260 [python start generated code]*/
261 /*[python end generated code: output=da39a3ee5e6b4b0d input=da0a4db751936ee7]*/
262 
263 #include "clinic/_winapi.c.h"
264 
265 /*[clinic input]
266 _winapi.Overlapped.GetOverlappedResult
267 
268     wait: bool
269     /
270 [clinic start generated code]*/
271 
272 static PyObject *
_winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject * self,int wait)273 _winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject *self, int wait)
274 /*[clinic end generated code: output=bdd0c1ed6518cd03 input=194505ee8e0e3565]*/
275 {
276     BOOL res;
277     DWORD transferred = 0;
278     DWORD err;
279 
280     Py_BEGIN_ALLOW_THREADS
281     res = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
282                               wait != 0);
283     Py_END_ALLOW_THREADS
284 
285     err = res ? ERROR_SUCCESS : GetLastError();
286     switch (err) {
287         case ERROR_SUCCESS:
288         case ERROR_MORE_DATA:
289         case ERROR_OPERATION_ABORTED:
290             self->completed = 1;
291             self->pending = 0;
292             break;
293         case ERROR_IO_INCOMPLETE:
294             break;
295         default:
296             self->pending = 0;
297             return PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
298     }
299     if (self->completed && self->read_buffer != NULL) {
300         assert(PyBytes_CheckExact(self->read_buffer));
301         if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
302             _PyBytes_Resize(&self->read_buffer, transferred))
303             return NULL;
304     }
305     return Py_BuildValue("II", (unsigned) transferred, (unsigned) err);
306 }
307 
308 /*[clinic input]
309 _winapi.Overlapped.getbuffer
310 [clinic start generated code]*/
311 
312 static PyObject *
_winapi_Overlapped_getbuffer_impl(OverlappedObject * self)313 _winapi_Overlapped_getbuffer_impl(OverlappedObject *self)
314 /*[clinic end generated code: output=95a3eceefae0f748 input=347fcfd56b4ceabd]*/
315 {
316     PyObject *res;
317     if (!self->completed) {
318         PyErr_SetString(PyExc_ValueError,
319                         "can't get read buffer before GetOverlappedResult() "
320                         "signals the operation completed");
321         return NULL;
322     }
323     res = self->read_buffer ? self->read_buffer : Py_None;
324     return Py_NewRef(res);
325 }
326 
327 /*[clinic input]
328 _winapi.Overlapped.cancel
329 [clinic start generated code]*/
330 
331 static PyObject *
_winapi_Overlapped_cancel_impl(OverlappedObject * self)332 _winapi_Overlapped_cancel_impl(OverlappedObject *self)
333 /*[clinic end generated code: output=fcb9ab5df4ebdae5 input=cbf3da142290039f]*/
334 {
335     BOOL res = TRUE;
336 
337     if (self->pending) {
338         Py_BEGIN_ALLOW_THREADS
339         res = CancelIoEx(self->handle, &self->overlapped);
340         Py_END_ALLOW_THREADS
341     }
342 
343     /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
344     if (!res && GetLastError() != ERROR_NOT_FOUND)
345         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
346     self->pending = 0;
347     Py_RETURN_NONE;
348 }
349 
350 static PyMethodDef overlapped_methods[] = {
351     _WINAPI_OVERLAPPED_GETOVERLAPPEDRESULT_METHODDEF
352     _WINAPI_OVERLAPPED_GETBUFFER_METHODDEF
353     _WINAPI_OVERLAPPED_CANCEL_METHODDEF
354     {NULL}
355 };
356 
357 static PyMemberDef overlapped_members[] = {
358     {"event", T_HANDLE,
359      offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
360      Py_READONLY, "overlapped event handle"},
361     {NULL}
362 };
363 
364 static PyType_Slot winapi_overlapped_type_slots[] = {
365     {Py_tp_traverse, overlapped_traverse},
366     {Py_tp_dealloc, overlapped_dealloc},
367     {Py_tp_doc, "OVERLAPPED structure wrapper"},
368     {Py_tp_methods, overlapped_methods},
369     {Py_tp_members, overlapped_members},
370     {0,0}
371 };
372 
373 static PyType_Spec winapi_overlapped_type_spec = {
374     .name = "_winapi.Overlapped",
375     .basicsize = sizeof(OverlappedObject),
376     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
377               Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
378     .slots = winapi_overlapped_type_slots,
379 };
380 
381 static OverlappedObject *
new_overlapped(PyObject * module,HANDLE handle)382 new_overlapped(PyObject *module, HANDLE handle)
383 {
384     WinApiState *st = winapi_get_state(module);
385     OverlappedObject *self = PyObject_GC_New(OverlappedObject, st->overlapped_type);
386     if (!self)
387         return NULL;
388 
389     self->handle = handle;
390     self->read_buffer = NULL;
391     self->pending = 0;
392     self->completed = 0;
393     memset(&self->overlapped, 0, sizeof(OVERLAPPED));
394     memset(&self->write_buffer, 0, sizeof(Py_buffer));
395     /* Manual reset, initially non-signalled */
396     self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
397 
398     PyObject_GC_Track(self);
399     return self;
400 }
401 
402 /* -------------------------------------------------------------------- */
403 /* windows API functions */
404 
405 /*[clinic input]
406 _winapi.CloseHandle
407 
408     handle: HANDLE
409     /
410 
411 Close handle.
412 [clinic start generated code]*/
413 
414 static PyObject *
_winapi_CloseHandle_impl(PyObject * module,HANDLE handle)415 _winapi_CloseHandle_impl(PyObject *module, HANDLE handle)
416 /*[clinic end generated code: output=7ad37345f07bd782 input=7f0e4ac36e0352b8]*/
417 {
418     BOOL success;
419 
420     Py_BEGIN_ALLOW_THREADS
421     success = CloseHandle(handle);
422     Py_END_ALLOW_THREADS
423 
424     if (!success)
425         return PyErr_SetFromWindowsErr(0);
426 
427     Py_RETURN_NONE;
428 }
429 
430 /*[clinic input]
431 _winapi.ConnectNamedPipe
432 
433     handle: HANDLE
434     overlapped as use_overlapped: bool = False
435 [clinic start generated code]*/
436 
437 static PyObject *
_winapi_ConnectNamedPipe_impl(PyObject * module,HANDLE handle,int use_overlapped)438 _winapi_ConnectNamedPipe_impl(PyObject *module, HANDLE handle,
439                               int use_overlapped)
440 /*[clinic end generated code: output=335a0e7086800671 input=a80e56e8bd370e31]*/
441 {
442     BOOL success;
443     OverlappedObject *overlapped = NULL;
444 
445     if (use_overlapped) {
446         overlapped = new_overlapped(module, handle);
447         if (!overlapped)
448             return NULL;
449     }
450 
451     Py_BEGIN_ALLOW_THREADS
452     success = ConnectNamedPipe(handle,
453                                overlapped ? &overlapped->overlapped : NULL);
454     Py_END_ALLOW_THREADS
455 
456     if (overlapped) {
457         int err = GetLastError();
458         /* Overlapped ConnectNamedPipe never returns a success code */
459         assert(success == 0);
460         if (err == ERROR_IO_PENDING)
461             overlapped->pending = 1;
462         else if (err == ERROR_PIPE_CONNECTED)
463             SetEvent(overlapped->overlapped.hEvent);
464         else {
465             Py_DECREF(overlapped);
466             return PyErr_SetFromWindowsErr(err);
467         }
468         return (PyObject *) overlapped;
469     }
470     if (!success)
471         return PyErr_SetFromWindowsErr(0);
472 
473     Py_RETURN_NONE;
474 }
475 
476 /*[clinic input]
477 _winapi.CreateEventW -> HANDLE
478 
479     security_attributes: LPSECURITY_ATTRIBUTES
480     manual_reset: BOOL
481     initial_state: BOOL
482     name: LPCWSTR(accept={str, NoneType})
483 [clinic start generated code]*/
484 
485 static HANDLE
_winapi_CreateEventW_impl(PyObject * module,LPSECURITY_ATTRIBUTES security_attributes,BOOL manual_reset,BOOL initial_state,LPCWSTR name)486 _winapi_CreateEventW_impl(PyObject *module,
487                           LPSECURITY_ATTRIBUTES security_attributes,
488                           BOOL manual_reset, BOOL initial_state,
489                           LPCWSTR name)
490 /*[clinic end generated code: output=2d4c7d5852ecb298 input=4187cee28ac763f8]*/
491 {
492     HANDLE handle;
493 
494     if (PySys_Audit("_winapi.CreateEventW", "bbu", manual_reset, initial_state, name) < 0) {
495         return INVALID_HANDLE_VALUE;
496     }
497 
498     Py_BEGIN_ALLOW_THREADS
499     handle = CreateEventW(security_attributes, manual_reset, initial_state, name);
500     Py_END_ALLOW_THREADS
501 
502     if (handle == INVALID_HANDLE_VALUE) {
503         PyErr_SetFromWindowsErr(0);
504     }
505 
506     return handle;
507 }
508 
509 /*[clinic input]
510 _winapi.CreateFile -> HANDLE
511 
512     file_name: LPCWSTR
513     desired_access: DWORD
514     share_mode: DWORD
515     security_attributes: LPSECURITY_ATTRIBUTES
516     creation_disposition: DWORD
517     flags_and_attributes: DWORD
518     template_file: HANDLE
519     /
520 [clinic start generated code]*/
521 
522 static HANDLE
_winapi_CreateFile_impl(PyObject * module,LPCWSTR file_name,DWORD desired_access,DWORD share_mode,LPSECURITY_ATTRIBUTES security_attributes,DWORD creation_disposition,DWORD flags_and_attributes,HANDLE template_file)523 _winapi_CreateFile_impl(PyObject *module, LPCWSTR file_name,
524                         DWORD desired_access, DWORD share_mode,
525                         LPSECURITY_ATTRIBUTES security_attributes,
526                         DWORD creation_disposition,
527                         DWORD flags_and_attributes, HANDLE template_file)
528 /*[clinic end generated code: output=818c811e5e04d550 input=1fa870ed1c2e3d69]*/
529 {
530     HANDLE handle;
531 
532     if (PySys_Audit("_winapi.CreateFile", "ukkkk",
533                     file_name, desired_access, share_mode,
534                     creation_disposition, flags_and_attributes) < 0) {
535         return INVALID_HANDLE_VALUE;
536     }
537 
538     Py_BEGIN_ALLOW_THREADS
539     handle = CreateFileW(file_name, desired_access,
540                          share_mode, security_attributes,
541                          creation_disposition,
542                          flags_and_attributes, template_file);
543     Py_END_ALLOW_THREADS
544 
545     if (handle == INVALID_HANDLE_VALUE) {
546         PyErr_SetFromWindowsErr(0);
547     }
548 
549     return handle;
550 }
551 
552 /*[clinic input]
553 _winapi.CreateFileMapping -> HANDLE
554 
555     file_handle: HANDLE
556     security_attributes: LPSECURITY_ATTRIBUTES
557     protect: DWORD
558     max_size_high: DWORD
559     max_size_low: DWORD
560     name: LPCWSTR
561     /
562 [clinic start generated code]*/
563 
564 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)565 _winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle,
566                                LPSECURITY_ATTRIBUTES security_attributes,
567                                DWORD protect, DWORD max_size_high,
568                                DWORD max_size_low, LPCWSTR name)
569 /*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=3dc5cf762a74dee8]*/
570 {
571     HANDLE handle;
572 
573     Py_BEGIN_ALLOW_THREADS
574     handle = CreateFileMappingW(file_handle, security_attributes,
575                                 protect, max_size_high, max_size_low,
576                                 name);
577     Py_END_ALLOW_THREADS
578 
579     if (handle == NULL) {
580         PyObject *temp = PyUnicode_FromWideChar(name, -1);
581         PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
582         Py_XDECREF(temp);
583         handle = INVALID_HANDLE_VALUE;
584     }
585 
586     return handle;
587 }
588 
589 /*[clinic input]
590 _winapi.CreateJunction
591 
592     src_path: LPCWSTR
593     dst_path: LPCWSTR
594     /
595 [clinic start generated code]*/
596 
597 static PyObject *
_winapi_CreateJunction_impl(PyObject * module,LPCWSTR src_path,LPCWSTR dst_path)598 _winapi_CreateJunction_impl(PyObject *module, LPCWSTR src_path,
599                             LPCWSTR dst_path)
600 /*[clinic end generated code: output=44b3f5e9bbcc4271 input=963d29b44b9384a7]*/
601 {
602     /* Privilege adjustment */
603     HANDLE token = NULL;
604     struct {
605         TOKEN_PRIVILEGES base;
606         /* overallocate by a few array elements */
607         LUID_AND_ATTRIBUTES privs[4];
608     } tp, previousTp;
609     int previousTpSize = 0;
610 
611     /* Reparse data buffer */
612     const USHORT prefix_len = 4;
613     USHORT print_len = 0;
614     USHORT rdb_size = 0;
615     _Py_PREPARSE_DATA_BUFFER rdb = NULL;
616 
617     /* Junction point creation */
618     HANDLE junction = NULL;
619     DWORD ret = 0;
620 
621     if (src_path == NULL || dst_path == NULL)
622         return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
623 
624     if (wcsncmp(src_path, L"\\??\\", prefix_len) == 0)
625         return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
626 
627     if (PySys_Audit("_winapi.CreateJunction", "uu", src_path, dst_path) < 0) {
628         return NULL;
629     }
630 
631     /* Adjust privileges to allow rewriting directory entry as a
632        junction point. */
633     if (!OpenProcessToken(GetCurrentProcess(),
634                           TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
635         goto cleanup;
636     }
637 
638     if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.base.Privileges[0].Luid)) {
639         goto cleanup;
640     }
641 
642     tp.base.PrivilegeCount = 1;
643     tp.base.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
644     if (!AdjustTokenPrivileges(token, FALSE, &tp.base, sizeof(previousTp),
645                                &previousTp.base, &previousTpSize)) {
646         goto cleanup;
647     }
648 
649     if (GetFileAttributesW(src_path) == INVALID_FILE_ATTRIBUTES)
650         goto cleanup;
651 
652     /* Store the absolute link target path length in print_len. */
653     print_len = (USHORT)GetFullPathNameW(src_path, 0, NULL, NULL);
654     if (print_len == 0)
655         goto cleanup;
656 
657     /* NUL terminator should not be part of print_len. */
658     --print_len;
659 
660     /* REPARSE_DATA_BUFFER usage is heavily under-documented, especially for
661        junction points. Here's what I've learned along the way:
662        - A junction point has two components: a print name and a substitute
663          name. They both describe the link target, but the substitute name is
664          the physical target and the print name is shown in directory listings.
665        - The print name must be a native name, prefixed with "\??\".
666        - Both names are stored after each other in the same buffer (the
667          PathBuffer) and both must be NUL-terminated.
668        - There are four members defining their respective offset and length
669          inside PathBuffer: SubstituteNameOffset, SubstituteNameLength,
670          PrintNameOffset and PrintNameLength.
671        - The total size we need to allocate for the REPARSE_DATA_BUFFER, thus,
672          is the sum of:
673          - the fixed header size (REPARSE_DATA_BUFFER_HEADER_SIZE)
674          - the size of the MountPointReparseBuffer member without the PathBuffer
675          - the size of the prefix ("\??\") in bytes
676          - the size of the print name in bytes
677          - the size of the substitute name in bytes
678          - the size of two NUL terminators in bytes */
679     rdb_size = _Py_REPARSE_DATA_BUFFER_HEADER_SIZE +
680         sizeof(rdb->MountPointReparseBuffer) -
681         sizeof(rdb->MountPointReparseBuffer.PathBuffer) +
682         /* Two +1's for NUL terminators. */
683         (prefix_len + print_len + 1 + print_len + 1) * sizeof(WCHAR);
684     rdb = (_Py_PREPARSE_DATA_BUFFER)PyMem_RawCalloc(1, rdb_size);
685     if (rdb == NULL)
686         goto cleanup;
687 
688     rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
689     rdb->ReparseDataLength = rdb_size - _Py_REPARSE_DATA_BUFFER_HEADER_SIZE;
690     rdb->MountPointReparseBuffer.SubstituteNameOffset = 0;
691     rdb->MountPointReparseBuffer.SubstituteNameLength =
692         (prefix_len + print_len) * sizeof(WCHAR);
693     rdb->MountPointReparseBuffer.PrintNameOffset =
694         rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
695     rdb->MountPointReparseBuffer.PrintNameLength = print_len * sizeof(WCHAR);
696 
697     /* Store the full native path of link target at the substitute name
698        offset (0). */
699     wcscpy(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
700     if (GetFullPathNameW(src_path, print_len + 1,
701                          rdb->MountPointReparseBuffer.PathBuffer + prefix_len,
702                          NULL) == 0)
703         goto cleanup;
704 
705     /* Copy everything but the native prefix to the print name offset. */
706     wcscpy(rdb->MountPointReparseBuffer.PathBuffer +
707              prefix_len + print_len + 1,
708              rdb->MountPointReparseBuffer.PathBuffer + prefix_len);
709 
710     /* Create a directory for the junction point. */
711     if (!CreateDirectoryW(dst_path, NULL))
712         goto cleanup;
713 
714     junction = CreateFileW(dst_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
715         OPEN_EXISTING,
716         FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
717     if (junction == INVALID_HANDLE_VALUE)
718         goto cleanup;
719 
720     /* Make the directory entry a junction point. */
721     if (!DeviceIoControl(junction, FSCTL_SET_REPARSE_POINT, rdb, rdb_size,
722                          NULL, 0, &ret, NULL))
723         goto cleanup;
724 
725 cleanup:
726     ret = GetLastError();
727 
728     if (previousTpSize) {
729         AdjustTokenPrivileges(token, FALSE, &previousTp.base, previousTpSize,
730                               NULL, NULL);
731     }
732 
733     if (token != NULL)
734         CloseHandle(token);
735     if (junction != NULL)
736         CloseHandle(junction);
737     PyMem_RawFree(rdb);
738 
739     if (ret != 0)
740         return PyErr_SetFromWindowsErr(ret);
741 
742     Py_RETURN_NONE;
743 }
744 
745 /*[clinic input]
746 _winapi.CreateMutexW -> HANDLE
747 
748     security_attributes: LPSECURITY_ATTRIBUTES
749     initial_owner: BOOL
750     name: LPCWSTR(accept={str, NoneType})
751 [clinic start generated code]*/
752 
753 static HANDLE
_winapi_CreateMutexW_impl(PyObject * module,LPSECURITY_ATTRIBUTES security_attributes,BOOL initial_owner,LPCWSTR name)754 _winapi_CreateMutexW_impl(PyObject *module,
755                           LPSECURITY_ATTRIBUTES security_attributes,
756                           BOOL initial_owner, LPCWSTR name)
757 /*[clinic end generated code: output=31b9ee8fc37e49a5 input=7d54b921e723254a]*/
758 {
759     HANDLE handle;
760 
761     if (PySys_Audit("_winapi.CreateMutexW", "bu", initial_owner, name) < 0) {
762         return INVALID_HANDLE_VALUE;
763     }
764 
765     Py_BEGIN_ALLOW_THREADS
766     handle = CreateMutexW(security_attributes, initial_owner, name);
767     Py_END_ALLOW_THREADS
768 
769     if (handle == INVALID_HANDLE_VALUE) {
770         PyErr_SetFromWindowsErr(0);
771     }
772 
773     return handle;
774 }
775 
776 /*[clinic input]
777 _winapi.CreateNamedPipe -> HANDLE
778 
779     name: LPCWSTR
780     open_mode: DWORD
781     pipe_mode: DWORD
782     max_instances: DWORD
783     out_buffer_size: DWORD
784     in_buffer_size: DWORD
785     default_timeout: DWORD
786     security_attributes: LPSECURITY_ATTRIBUTES
787     /
788 [clinic start generated code]*/
789 
790 static HANDLE
_winapi_CreateNamedPipe_impl(PyObject * module,LPCWSTR 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)791 _winapi_CreateNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD open_mode,
792                              DWORD pipe_mode, DWORD max_instances,
793                              DWORD out_buffer_size, DWORD in_buffer_size,
794                              DWORD default_timeout,
795                              LPSECURITY_ATTRIBUTES security_attributes)
796 /*[clinic end generated code: output=7d6fde93227680ba input=5bd4e4a55639ee02]*/
797 {
798     HANDLE handle;
799 
800     if (PySys_Audit("_winapi.CreateNamedPipe", "ukk",
801                     name, open_mode, pipe_mode) < 0) {
802         return INVALID_HANDLE_VALUE;
803     }
804 
805     Py_BEGIN_ALLOW_THREADS
806     handle = CreateNamedPipeW(name, open_mode, pipe_mode,
807                               max_instances, out_buffer_size,
808                               in_buffer_size, default_timeout,
809                               security_attributes);
810     Py_END_ALLOW_THREADS
811 
812     if (handle == INVALID_HANDLE_VALUE)
813         PyErr_SetFromWindowsErr(0);
814 
815     return handle;
816 }
817 
818 /*[clinic input]
819 _winapi.CreatePipe
820 
821     pipe_attrs: object
822         Ignored internally, can be None.
823     size: DWORD
824     /
825 
826 Create an anonymous pipe.
827 
828 Returns a 2-tuple of handles, to the read and write ends of the pipe.
829 [clinic start generated code]*/
830 
831 static PyObject *
_winapi_CreatePipe_impl(PyObject * module,PyObject * pipe_attrs,DWORD size)832 _winapi_CreatePipe_impl(PyObject *module, PyObject *pipe_attrs, DWORD size)
833 /*[clinic end generated code: output=1c4411d8699f0925 input=c4f2cfa56ef68d90]*/
834 {
835     HANDLE read_pipe;
836     HANDLE write_pipe;
837     BOOL result;
838 
839     if (PySys_Audit("_winapi.CreatePipe", NULL) < 0) {
840         return NULL;
841     }
842 
843     Py_BEGIN_ALLOW_THREADS
844     result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
845     Py_END_ALLOW_THREADS
846 
847     if (! result)
848         return PyErr_SetFromWindowsErr(GetLastError());
849 
850     return Py_BuildValue(
851         "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe));
852 }
853 
854 /* helpers for createprocess */
855 
856 static unsigned long
getulong(PyObject * obj,const char * name)857 getulong(PyObject* obj, const char* name)
858 {
859     PyObject* value;
860     unsigned long ret;
861 
862     value = PyObject_GetAttrString(obj, name);
863     if (! value) {
864         PyErr_Clear(); /* FIXME: propagate error? */
865         return 0;
866     }
867     ret = PyLong_AsUnsignedLong(value);
868     Py_DECREF(value);
869     return ret;
870 }
871 
872 static HANDLE
gethandle(PyObject * obj,const char * name)873 gethandle(PyObject* obj, const char* name)
874 {
875     PyObject* value;
876     HANDLE ret;
877 
878     value = PyObject_GetAttrString(obj, name);
879     if (! value) {
880         PyErr_Clear(); /* FIXME: propagate error? */
881         return NULL;
882     }
883     if (value == Py_None)
884         ret = NULL;
885     else
886         ret = PYNUM_TO_HANDLE(value);
887     Py_DECREF(value);
888     return ret;
889 }
890 
891 static PyObject *
sortenvironmentkey(PyObject * module,PyObject * item)892 sortenvironmentkey(PyObject *module, PyObject *item)
893 {
894     return _winapi_LCMapStringEx_impl(NULL, LOCALE_NAME_INVARIANT,
895                                       LCMAP_UPPERCASE, item);
896 }
897 
898 static PyMethodDef sortenvironmentkey_def = {
899     "sortenvironmentkey", _PyCFunction_CAST(sortenvironmentkey), METH_O, "",
900 };
901 
902 static int
sort_environment_keys(PyObject * keys)903 sort_environment_keys(PyObject *keys)
904 {
905     PyObject *keyfunc = PyCFunction_New(&sortenvironmentkey_def, NULL);
906     if (keyfunc == NULL) {
907         return -1;
908     }
909     PyObject *kwnames = Py_BuildValue("(s)", "key");
910     if (kwnames == NULL) {
911         Py_DECREF(keyfunc);
912         return -1;
913     }
914     PyObject *args[] = { keys, keyfunc };
915     PyObject *ret = PyObject_VectorcallMethod(&_Py_ID(sort), args, 1, kwnames);
916     Py_DECREF(keyfunc);
917     Py_DECREF(kwnames);
918     if (ret == NULL) {
919         return -1;
920     }
921     Py_DECREF(ret);
922 
923     return 0;
924 }
925 
926 static int
compare_string_ordinal(PyObject * str1,PyObject * str2,int * result)927 compare_string_ordinal(PyObject *str1, PyObject *str2, int *result)
928 {
929     wchar_t *s1 = PyUnicode_AsWideCharString(str1, NULL);
930     if (s1 == NULL) {
931         return -1;
932     }
933     wchar_t *s2 = PyUnicode_AsWideCharString(str2, NULL);
934     if (s2 == NULL) {
935         PyMem_Free(s1);
936         return -1;
937     }
938     *result = CompareStringOrdinal(s1, -1, s2, -1, TRUE);
939     PyMem_Free(s1);
940     PyMem_Free(s2);
941     return 0;
942 }
943 
944 static PyObject *
dedup_environment_keys(PyObject * keys)945 dedup_environment_keys(PyObject *keys)
946 {
947     PyObject *result = PyList_New(0);
948     if (result == NULL) {
949         return NULL;
950     }
951 
952     // Iterate over the pre-ordered keys, check whether the current key is equal
953     // to the next key (ignoring case), if different, insert the current value
954     // into the result list. If they are equal, do nothing because we always
955     // want to keep the last inserted one.
956     for (Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); i++) {
957         PyObject *key = PyList_GET_ITEM(keys, i);
958 
959         // The last key will always be kept.
960         if (i + 1 == PyList_GET_SIZE(keys)) {
961             if (PyList_Append(result, key) < 0) {
962                 Py_DECREF(result);
963                 return NULL;
964             }
965             continue;
966         }
967 
968         PyObject *next_key = PyList_GET_ITEM(keys, i + 1);
969         int compare_result;
970         if (compare_string_ordinal(key, next_key, &compare_result) < 0) {
971             Py_DECREF(result);
972             return NULL;
973         }
974         if (compare_result == CSTR_EQUAL) {
975             continue;
976         }
977         if (PyList_Append(result, key) < 0) {
978             Py_DECREF(result);
979             return NULL;
980         }
981     }
982 
983     return result;
984 }
985 
986 static PyObject *
normalize_environment(PyObject * environment)987 normalize_environment(PyObject *environment)
988 {
989     PyObject *keys = PyMapping_Keys(environment);
990     if (keys == NULL) {
991         return NULL;
992     }
993 
994     if (sort_environment_keys(keys) < 0) {
995         Py_DECREF(keys);
996         return NULL;
997     }
998 
999     PyObject *normalized_keys = dedup_environment_keys(keys);
1000     Py_DECREF(keys);
1001     if (normalized_keys == NULL) {
1002         return NULL;
1003     }
1004 
1005     PyObject *result = PyDict_New();
1006     if (result == NULL) {
1007         Py_DECREF(normalized_keys);
1008         return NULL;
1009     }
1010 
1011     for (int i = 0; i < PyList_GET_SIZE(normalized_keys); i++) {
1012         PyObject *key = PyList_GET_ITEM(normalized_keys, i);
1013         PyObject *value = PyObject_GetItem(environment, key);
1014         if (value == NULL) {
1015             Py_DECREF(normalized_keys);
1016             Py_DECREF(result);
1017             return NULL;
1018         }
1019 
1020         int ret = PyObject_SetItem(result, key, value);
1021         Py_DECREF(value);
1022         if (ret < 0) {
1023             Py_DECREF(normalized_keys);
1024             Py_DECREF(result);
1025             return NULL;
1026         }
1027     }
1028 
1029     Py_DECREF(normalized_keys);
1030 
1031     return result;
1032 }
1033 
1034 static wchar_t *
getenvironment(PyObject * environment)1035 getenvironment(PyObject* environment)
1036 {
1037     Py_ssize_t i, envsize, totalsize;
1038     wchar_t *buffer = NULL, *p, *end;
1039     PyObject *normalized_environment = NULL;
1040     PyObject *keys = NULL;
1041     PyObject *values = NULL;
1042 
1043     /* convert environment dictionary to windows environment string */
1044     if (! PyMapping_Check(environment)) {
1045         PyErr_SetString(
1046             PyExc_TypeError, "environment must be dictionary or None");
1047         return NULL;
1048     }
1049 
1050     normalized_environment = normalize_environment(environment);
1051     if (normalize_environment == NULL) {
1052         return NULL;
1053     }
1054 
1055     keys = PyMapping_Keys(normalized_environment);
1056     if (!keys) {
1057         goto error;
1058     }
1059     values = PyMapping_Values(normalized_environment);
1060     if (!values) {
1061         goto error;
1062     }
1063 
1064     envsize = PyList_GET_SIZE(keys);
1065 
1066     if (envsize == 0) {
1067         // A environment block must be terminated by two null characters --
1068         // one for the last string and one for the block.
1069         buffer = PyMem_Calloc(2, sizeof(wchar_t));
1070         if (!buffer) {
1071             PyErr_NoMemory();
1072         }
1073         goto cleanup;
1074     }
1075 
1076     if (PyList_GET_SIZE(values) != envsize) {
1077         PyErr_SetString(PyExc_RuntimeError,
1078             "environment changed size during iteration");
1079         goto error;
1080     }
1081 
1082     totalsize = 1; /* trailing null character */
1083     for (i = 0; i < envsize; i++) {
1084         PyObject* key = PyList_GET_ITEM(keys, i);
1085         PyObject* value = PyList_GET_ITEM(values, i);
1086         Py_ssize_t size;
1087 
1088         if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
1089             PyErr_SetString(PyExc_TypeError,
1090                 "environment can only contain strings");
1091             goto error;
1092         }
1093         if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
1094             PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
1095         {
1096             PyErr_SetString(PyExc_ValueError, "embedded null character");
1097             goto error;
1098         }
1099         /* Search from index 1 because on Windows starting '=' is allowed for
1100            defining hidden environment variables. */
1101         if (PyUnicode_GET_LENGTH(key) == 0 ||
1102             PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
1103         {
1104             PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
1105             goto error;
1106         }
1107 
1108         size = PyUnicode_AsWideChar(key, NULL, 0);
1109         assert(size > 1);
1110         if (totalsize > PY_SSIZE_T_MAX - size) {
1111             PyErr_SetString(PyExc_OverflowError, "environment too long");
1112             goto error;
1113         }
1114         totalsize += size;    /* including '=' */
1115 
1116         size = PyUnicode_AsWideChar(value, NULL, 0);
1117         assert(size > 0);
1118         if (totalsize > PY_SSIZE_T_MAX - size) {
1119             PyErr_SetString(PyExc_OverflowError, "environment too long");
1120             goto error;
1121         }
1122         totalsize += size;  /* including trailing '\0' */
1123     }
1124 
1125     buffer = PyMem_NEW(wchar_t, totalsize);
1126     if (! buffer) {
1127         PyErr_NoMemory();
1128         goto error;
1129     }
1130     p = buffer;
1131     end = buffer + totalsize;
1132 
1133     for (i = 0; i < envsize; i++) {
1134         PyObject* key = PyList_GET_ITEM(keys, i);
1135         PyObject* value = PyList_GET_ITEM(values, i);
1136         Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
1137         assert(1 <= size && size < end - p);
1138         p += size;
1139         *p++ = L'=';
1140         size = PyUnicode_AsWideChar(value, p, end - p);
1141         assert(0 <= size && size < end - p);
1142         p += size + 1;
1143     }
1144 
1145     /* add trailing null character */
1146     *p++ = L'\0';
1147     assert(p == end);
1148 
1149 cleanup:
1150 error:
1151     Py_XDECREF(normalized_environment);
1152     Py_XDECREF(keys);
1153     Py_XDECREF(values);
1154     return buffer;
1155 }
1156 
1157 static LPHANDLE
gethandlelist(PyObject * mapping,const char * name,Py_ssize_t * size)1158 gethandlelist(PyObject *mapping, const char *name, Py_ssize_t *size)
1159 {
1160     LPHANDLE ret = NULL;
1161     PyObject *value_fast = NULL;
1162     PyObject *value;
1163     Py_ssize_t i;
1164 
1165     value = PyMapping_GetItemString(mapping, name);
1166     if (!value) {
1167         PyErr_Clear();
1168         return NULL;
1169     }
1170 
1171     if (value == Py_None) {
1172         goto cleanup;
1173     }
1174 
1175     value_fast = PySequence_Fast(value, "handle_list must be a sequence or None");
1176     if (value_fast == NULL)
1177         goto cleanup;
1178 
1179     *size = PySequence_Fast_GET_SIZE(value_fast) * sizeof(HANDLE);
1180 
1181     /* Passing an empty array causes CreateProcess to fail so just don't set it */
1182     if (*size == 0) {
1183         goto cleanup;
1184     }
1185 
1186     ret = PyMem_Malloc(*size);
1187     if (ret == NULL)
1188         goto cleanup;
1189 
1190     for (i = 0; i < PySequence_Fast_GET_SIZE(value_fast); i++) {
1191         ret[i] = PYNUM_TO_HANDLE(PySequence_Fast_GET_ITEM(value_fast, i));
1192         if (ret[i] == (HANDLE)-1 && PyErr_Occurred()) {
1193             PyMem_Free(ret);
1194             ret = NULL;
1195             goto cleanup;
1196         }
1197     }
1198 
1199 cleanup:
1200     Py_DECREF(value);
1201     Py_XDECREF(value_fast);
1202     return ret;
1203 }
1204 
1205 typedef struct {
1206     LPPROC_THREAD_ATTRIBUTE_LIST attribute_list;
1207     LPHANDLE handle_list;
1208 } AttributeList;
1209 
1210 static void
freeattributelist(AttributeList * attribute_list)1211 freeattributelist(AttributeList *attribute_list)
1212 {
1213     if (attribute_list->attribute_list != NULL) {
1214         DeleteProcThreadAttributeList(attribute_list->attribute_list);
1215         PyMem_Free(attribute_list->attribute_list);
1216     }
1217 
1218     PyMem_Free(attribute_list->handle_list);
1219 
1220     memset(attribute_list, 0, sizeof(*attribute_list));
1221 }
1222 
1223 static int
getattributelist(PyObject * obj,const char * name,AttributeList * attribute_list)1224 getattributelist(PyObject *obj, const char *name, AttributeList *attribute_list)
1225 {
1226     int ret = 0;
1227     DWORD err;
1228     BOOL result;
1229     PyObject *value;
1230     Py_ssize_t handle_list_size;
1231     DWORD attribute_count = 0;
1232     SIZE_T attribute_list_size = 0;
1233 
1234     value = PyObject_GetAttrString(obj, name);
1235     if (!value) {
1236         PyErr_Clear(); /* FIXME: propagate error? */
1237         return 0;
1238     }
1239 
1240     if (value == Py_None) {
1241         ret = 0;
1242         goto cleanup;
1243     }
1244 
1245     if (!PyMapping_Check(value)) {
1246         ret = -1;
1247         PyErr_Format(PyExc_TypeError, "%s must be a mapping or None", name);
1248         goto cleanup;
1249     }
1250 
1251     attribute_list->handle_list = gethandlelist(value, "handle_list", &handle_list_size);
1252     if (attribute_list->handle_list == NULL && PyErr_Occurred()) {
1253         ret = -1;
1254         goto cleanup;
1255     }
1256 
1257     if (attribute_list->handle_list != NULL)
1258         ++attribute_count;
1259 
1260     /* Get how many bytes we need for the attribute list */
1261     result = InitializeProcThreadAttributeList(NULL, attribute_count, 0, &attribute_list_size);
1262     if (result || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1263         ret = -1;
1264         PyErr_SetFromWindowsErr(GetLastError());
1265         goto cleanup;
1266     }
1267 
1268     attribute_list->attribute_list = PyMem_Malloc(attribute_list_size);
1269     if (attribute_list->attribute_list == NULL) {
1270         ret = -1;
1271         goto cleanup;
1272     }
1273 
1274     result = InitializeProcThreadAttributeList(
1275         attribute_list->attribute_list,
1276         attribute_count,
1277         0,
1278         &attribute_list_size);
1279     if (!result) {
1280         err = GetLastError();
1281 
1282         /* So that we won't call DeleteProcThreadAttributeList */
1283         PyMem_Free(attribute_list->attribute_list);
1284         attribute_list->attribute_list = NULL;
1285 
1286         ret = -1;
1287         PyErr_SetFromWindowsErr(err);
1288         goto cleanup;
1289     }
1290 
1291     if (attribute_list->handle_list != NULL) {
1292         result = UpdateProcThreadAttribute(
1293             attribute_list->attribute_list,
1294             0,
1295             PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1296             attribute_list->handle_list,
1297             handle_list_size,
1298             NULL,
1299             NULL);
1300         if (!result) {
1301             ret = -1;
1302             PyErr_SetFromWindowsErr(GetLastError());
1303             goto cleanup;
1304         }
1305     }
1306 
1307 cleanup:
1308     Py_DECREF(value);
1309 
1310     if (ret < 0)
1311         freeattributelist(attribute_list);
1312 
1313     return ret;
1314 }
1315 
1316 /*[clinic input]
1317 _winapi.CreateProcess
1318 
1319     application_name: Py_UNICODE(accept={str, NoneType})
1320     command_line: object
1321         Can be str or None
1322     proc_attrs: object
1323         Ignored internally, can be None.
1324     thread_attrs: object
1325         Ignored internally, can be None.
1326     inherit_handles: BOOL
1327     creation_flags: DWORD
1328     env_mapping: object
1329     current_directory: Py_UNICODE(accept={str, NoneType})
1330     startup_info: object
1331     /
1332 
1333 Create a new process and its primary thread.
1334 
1335 The return value is a tuple of the process handle, thread handle,
1336 process ID, and thread ID.
1337 [clinic start generated code]*/
1338 
1339 static PyObject *
_winapi_CreateProcess_impl(PyObject * module,const wchar_t * application_name,PyObject * command_line,PyObject * proc_attrs,PyObject * thread_attrs,BOOL inherit_handles,DWORD creation_flags,PyObject * env_mapping,const wchar_t * current_directory,PyObject * startup_info)1340 _winapi_CreateProcess_impl(PyObject *module, const wchar_t *application_name,
1341                            PyObject *command_line, PyObject *proc_attrs,
1342                            PyObject *thread_attrs, BOOL inherit_handles,
1343                            DWORD creation_flags, PyObject *env_mapping,
1344                            const wchar_t *current_directory,
1345                            PyObject *startup_info)
1346 /*[clinic end generated code: output=a25c8e49ea1d6427 input=42ac293eaea03fc4]*/
1347 {
1348     PyObject *ret = NULL;
1349     BOOL result;
1350     PROCESS_INFORMATION pi;
1351     STARTUPINFOEXW si;
1352     wchar_t *wenvironment = NULL;
1353     wchar_t *command_line_copy = NULL;
1354     AttributeList attribute_list = {0};
1355 
1356     if (PySys_Audit("_winapi.CreateProcess", "uuu", application_name,
1357                     command_line, current_directory) < 0) {
1358         return NULL;
1359     }
1360 
1361     ZeroMemory(&si, sizeof(si));
1362     si.StartupInfo.cb = sizeof(si);
1363 
1364     /* note: we only support a small subset of all SI attributes */
1365     si.StartupInfo.dwFlags = getulong(startup_info, "dwFlags");
1366     si.StartupInfo.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
1367     si.StartupInfo.hStdInput = gethandle(startup_info, "hStdInput");
1368     si.StartupInfo.hStdOutput = gethandle(startup_info, "hStdOutput");
1369     si.StartupInfo.hStdError = gethandle(startup_info, "hStdError");
1370     if (PyErr_Occurred())
1371         goto cleanup;
1372 
1373     if (env_mapping != Py_None) {
1374         wenvironment = getenvironment(env_mapping);
1375         if (wenvironment == NULL) {
1376             goto cleanup;
1377         }
1378     }
1379 
1380     if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
1381         goto cleanup;
1382 
1383     si.lpAttributeList = attribute_list.attribute_list;
1384     if (PyUnicode_Check(command_line)) {
1385         command_line_copy = PyUnicode_AsWideCharString(command_line, NULL);
1386         if (command_line_copy == NULL) {
1387             goto cleanup;
1388         }
1389     }
1390     else if (command_line != Py_None) {
1391         PyErr_Format(PyExc_TypeError,
1392                      "CreateProcess() argument 2 must be str or None, not %s",
1393                      Py_TYPE(command_line)->tp_name);
1394         goto cleanup;
1395     }
1396 
1397 
1398     Py_BEGIN_ALLOW_THREADS
1399     result = CreateProcessW(application_name,
1400                            command_line_copy,
1401                            NULL,
1402                            NULL,
1403                            inherit_handles,
1404                            creation_flags | EXTENDED_STARTUPINFO_PRESENT |
1405                            CREATE_UNICODE_ENVIRONMENT,
1406                            wenvironment,
1407                            current_directory,
1408                            (LPSTARTUPINFOW)&si,
1409                            &pi);
1410     Py_END_ALLOW_THREADS
1411 
1412     if (!result) {
1413         PyErr_SetFromWindowsErr(GetLastError());
1414         goto cleanup;
1415     }
1416 
1417     ret = Py_BuildValue("NNkk",
1418                         HANDLE_TO_PYNUM(pi.hProcess),
1419                         HANDLE_TO_PYNUM(pi.hThread),
1420                         pi.dwProcessId,
1421                         pi.dwThreadId);
1422 
1423 cleanup:
1424     PyMem_Free(command_line_copy);
1425     PyMem_Free(wenvironment);
1426     freeattributelist(&attribute_list);
1427 
1428     return ret;
1429 }
1430 
1431 /*[clinic input]
1432 _winapi.DuplicateHandle -> HANDLE
1433 
1434     source_process_handle: HANDLE
1435     source_handle: HANDLE
1436     target_process_handle: HANDLE
1437     desired_access: DWORD
1438     inherit_handle: BOOL
1439     options: DWORD = 0
1440     /
1441 
1442 Return a duplicate handle object.
1443 
1444 The duplicate handle refers to the same object as the original
1445 handle. Therefore, any changes to the object are reflected
1446 through both handles.
1447 [clinic start generated code]*/
1448 
1449 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)1450 _winapi_DuplicateHandle_impl(PyObject *module, HANDLE source_process_handle,
1451                              HANDLE source_handle,
1452                              HANDLE target_process_handle,
1453                              DWORD desired_access, BOOL inherit_handle,
1454                              DWORD options)
1455 /*[clinic end generated code: output=ad9711397b5dcd4e input=b933e3f2356a8c12]*/
1456 {
1457     HANDLE target_handle;
1458     BOOL result;
1459 
1460     Py_BEGIN_ALLOW_THREADS
1461     result = DuplicateHandle(
1462         source_process_handle,
1463         source_handle,
1464         target_process_handle,
1465         &target_handle,
1466         desired_access,
1467         inherit_handle,
1468         options
1469     );
1470     Py_END_ALLOW_THREADS
1471 
1472     if (! result) {
1473         PyErr_SetFromWindowsErr(GetLastError());
1474         return INVALID_HANDLE_VALUE;
1475     }
1476 
1477     return target_handle;
1478 }
1479 
1480 /*[clinic input]
1481 _winapi.ExitProcess
1482 
1483     ExitCode: UINT
1484     /
1485 
1486 [clinic start generated code]*/
1487 
1488 static PyObject *
_winapi_ExitProcess_impl(PyObject * module,UINT ExitCode)1489 _winapi_ExitProcess_impl(PyObject *module, UINT ExitCode)
1490 /*[clinic end generated code: output=a387deb651175301 input=4f05466a9406c558]*/
1491 {
1492     #if defined(Py_DEBUG)
1493 #ifdef MS_WINDOWS_DESKTOP
1494         SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
1495                      SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
1496 #endif
1497         _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
1498     #endif
1499 
1500     ExitProcess(ExitCode);
1501 
1502     return NULL;
1503 }
1504 
1505 /*[clinic input]
1506 _winapi.GetCurrentProcess -> HANDLE
1507 
1508 Return a handle object for the current process.
1509 [clinic start generated code]*/
1510 
1511 static HANDLE
_winapi_GetCurrentProcess_impl(PyObject * module)1512 _winapi_GetCurrentProcess_impl(PyObject *module)
1513 /*[clinic end generated code: output=ddeb4dd2ffadf344 input=b213403fd4b96b41]*/
1514 {
1515     return GetCurrentProcess();
1516 }
1517 
1518 /*[clinic input]
1519 _winapi.GetExitCodeProcess -> DWORD
1520 
1521     process: HANDLE
1522     /
1523 
1524 Return the termination status of the specified process.
1525 [clinic start generated code]*/
1526 
1527 static DWORD
_winapi_GetExitCodeProcess_impl(PyObject * module,HANDLE process)1528 _winapi_GetExitCodeProcess_impl(PyObject *module, HANDLE process)
1529 /*[clinic end generated code: output=b4620bdf2bccf36b input=61b6bfc7dc2ee374]*/
1530 {
1531     DWORD exit_code;
1532     BOOL result;
1533 
1534     result = GetExitCodeProcess(process, &exit_code);
1535 
1536     if (! result) {
1537         PyErr_SetFromWindowsErr(GetLastError());
1538         exit_code = PY_DWORD_MAX;
1539     }
1540 
1541     return exit_code;
1542 }
1543 
1544 /*[clinic input]
1545 _winapi.GetLastError -> DWORD
1546 [clinic start generated code]*/
1547 
1548 static DWORD
_winapi_GetLastError_impl(PyObject * module)1549 _winapi_GetLastError_impl(PyObject *module)
1550 /*[clinic end generated code: output=8585b827cb1a92c5 input=62d47fb9bce038ba]*/
1551 {
1552     return GetLastError();
1553 }
1554 
1555 
1556 /*[clinic input]
1557 _winapi.GetLongPathName
1558 
1559     path: LPCWSTR
1560 
1561 Return the long version of the provided path.
1562 
1563 If the path is already in its long form, returns the same value.
1564 
1565 The path must already be a 'str'. If the type is not known, use
1566 os.fsdecode before calling this function.
1567 [clinic start generated code]*/
1568 
1569 static PyObject *
_winapi_GetLongPathName_impl(PyObject * module,LPCWSTR path)1570 _winapi_GetLongPathName_impl(PyObject *module, LPCWSTR path)
1571 /*[clinic end generated code: output=c4774b080275a2d0 input=9872e211e3a4a88f]*/
1572 {
1573     DWORD cchBuffer;
1574     PyObject *result = NULL;
1575 
1576     Py_BEGIN_ALLOW_THREADS
1577     cchBuffer = GetLongPathNameW(path, NULL, 0);
1578     Py_END_ALLOW_THREADS
1579     if (cchBuffer) {
1580         WCHAR *buffer = (WCHAR *)PyMem_Malloc(cchBuffer * sizeof(WCHAR));
1581         if (buffer) {
1582             Py_BEGIN_ALLOW_THREADS
1583             cchBuffer = GetLongPathNameW(path, buffer, cchBuffer);
1584             Py_END_ALLOW_THREADS
1585             if (cchBuffer) {
1586                 result = PyUnicode_FromWideChar(buffer, cchBuffer);
1587             } else {
1588                 PyErr_SetFromWindowsErr(0);
1589             }
1590             PyMem_Free((void *)buffer);
1591         }
1592     } else {
1593         PyErr_SetFromWindowsErr(0);
1594     }
1595     return result;
1596 }
1597 
1598 /*[clinic input]
1599 _winapi.GetModuleFileName
1600 
1601     module_handle: HMODULE
1602     /
1603 
1604 Return the fully-qualified path for the file that contains module.
1605 
1606 The module must have been loaded by the current process.
1607 
1608 The module parameter should be a handle to the loaded module
1609 whose path is being requested. If this parameter is 0,
1610 GetModuleFileName retrieves the path of the executable file
1611 of the current process.
1612 [clinic start generated code]*/
1613 
1614 static PyObject *
_winapi_GetModuleFileName_impl(PyObject * module,HMODULE module_handle)1615 _winapi_GetModuleFileName_impl(PyObject *module, HMODULE module_handle)
1616 /*[clinic end generated code: output=85b4b728c5160306 input=6d66ff7deca5d11f]*/
1617 {
1618     BOOL result;
1619     WCHAR filename[MAX_PATH];
1620 
1621     Py_BEGIN_ALLOW_THREADS
1622     result = GetModuleFileNameW(module_handle, filename, MAX_PATH);
1623     filename[MAX_PATH-1] = '\0';
1624     Py_END_ALLOW_THREADS
1625 
1626     if (! result)
1627         return PyErr_SetFromWindowsErr(GetLastError());
1628 
1629     return PyUnicode_FromWideChar(filename, wcslen(filename));
1630 }
1631 
1632 /*[clinic input]
1633 _winapi.GetShortPathName
1634 
1635     path: LPCWSTR
1636 
1637 Return the short version of the provided path.
1638 
1639 If the path is already in its short form, returns the same value.
1640 
1641 The path must already be a 'str'. If the type is not known, use
1642 os.fsdecode before calling this function.
1643 [clinic start generated code]*/
1644 
1645 static PyObject *
_winapi_GetShortPathName_impl(PyObject * module,LPCWSTR path)1646 _winapi_GetShortPathName_impl(PyObject *module, LPCWSTR path)
1647 /*[clinic end generated code: output=dab6ae494c621e81 input=43fa349aaf2ac718]*/
1648 {
1649     DWORD cchBuffer;
1650     PyObject *result = NULL;
1651 
1652     Py_BEGIN_ALLOW_THREADS
1653     cchBuffer = GetShortPathNameW(path, NULL, 0);
1654     Py_END_ALLOW_THREADS
1655     if (cchBuffer) {
1656         WCHAR *buffer = (WCHAR *)PyMem_Malloc(cchBuffer * sizeof(WCHAR));
1657         if (buffer) {
1658             Py_BEGIN_ALLOW_THREADS
1659             cchBuffer = GetShortPathNameW(path, buffer, cchBuffer);
1660             Py_END_ALLOW_THREADS
1661             if (cchBuffer) {
1662                 result = PyUnicode_FromWideChar(buffer, cchBuffer);
1663             } else {
1664                 PyErr_SetFromWindowsErr(0);
1665             }
1666             PyMem_Free((void *)buffer);
1667         }
1668     } else {
1669         PyErr_SetFromWindowsErr(0);
1670     }
1671     return result;
1672 }
1673 
1674 /*[clinic input]
1675 _winapi.GetStdHandle -> HANDLE
1676 
1677     std_handle: DWORD
1678         One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE.
1679     /
1680 
1681 Return a handle to the specified standard device.
1682 
1683 The integer associated with the handle object is returned.
1684 [clinic start generated code]*/
1685 
1686 static HANDLE
_winapi_GetStdHandle_impl(PyObject * module,DWORD std_handle)1687 _winapi_GetStdHandle_impl(PyObject *module, DWORD std_handle)
1688 /*[clinic end generated code: output=0e613001e73ab614 input=07016b06a2fc8826]*/
1689 {
1690     HANDLE handle;
1691 
1692     Py_BEGIN_ALLOW_THREADS
1693     handle = GetStdHandle(std_handle);
1694     Py_END_ALLOW_THREADS
1695 
1696     if (handle == INVALID_HANDLE_VALUE)
1697         PyErr_SetFromWindowsErr(GetLastError());
1698 
1699     return handle;
1700 }
1701 
1702 /*[clinic input]
1703 _winapi.GetVersion -> long
1704 
1705 Return the version number of the current operating system.
1706 [clinic start generated code]*/
1707 
1708 static long
_winapi_GetVersion_impl(PyObject * module)1709 _winapi_GetVersion_impl(PyObject *module)
1710 /*[clinic end generated code: output=e41f0db5a3b82682 input=e21dff8d0baeded2]*/
1711 /* Disable deprecation warnings about GetVersionEx as the result is
1712    being passed straight through to the caller, who is responsible for
1713    using it correctly. */
1714 #pragma warning(push)
1715 #pragma warning(disable:4996)
1716 
1717 {
1718     return GetVersion();
1719 }
1720 
1721 #pragma warning(pop)
1722 
1723 /*[clinic input]
1724 _winapi.MapViewOfFile -> LPVOID
1725 
1726     file_map: HANDLE
1727     desired_access: DWORD
1728     file_offset_high: DWORD
1729     file_offset_low: DWORD
1730     number_bytes: size_t
1731     /
1732 [clinic start generated code]*/
1733 
1734 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)1735 _winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map,
1736                            DWORD desired_access, DWORD file_offset_high,
1737                            DWORD file_offset_low, size_t number_bytes)
1738 /*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/
1739 {
1740     LPVOID address;
1741 
1742     Py_BEGIN_ALLOW_THREADS
1743     address = MapViewOfFile(file_map, desired_access, file_offset_high,
1744                             file_offset_low, number_bytes);
1745     Py_END_ALLOW_THREADS
1746 
1747     if (address == NULL)
1748         PyErr_SetFromWindowsErr(0);
1749 
1750     return address;
1751 }
1752 
1753 /*[clinic input]
1754 _winapi.UnmapViewOfFile
1755 
1756     address: LPCVOID
1757     /
1758 [clinic start generated code]*/
1759 
1760 static PyObject *
_winapi_UnmapViewOfFile_impl(PyObject * module,LPCVOID address)1761 _winapi_UnmapViewOfFile_impl(PyObject *module, LPCVOID address)
1762 /*[clinic end generated code: output=4f7e18ac75d19744 input=8c4b6119ad9288a3]*/
1763 {
1764     BOOL success;
1765 
1766     Py_BEGIN_ALLOW_THREADS
1767     success = UnmapViewOfFile(address);
1768     Py_END_ALLOW_THREADS
1769 
1770     if (!success) {
1771         return PyErr_SetFromWindowsErr(0);
1772     }
1773 
1774     Py_RETURN_NONE;
1775 }
1776 
1777 /*[clinic input]
1778 _winapi.OpenEventW -> HANDLE
1779 
1780     desired_access: DWORD
1781     inherit_handle: BOOL
1782     name: LPCWSTR
1783 [clinic start generated code]*/
1784 
1785 static HANDLE
_winapi_OpenEventW_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1786 _winapi_OpenEventW_impl(PyObject *module, DWORD desired_access,
1787                         BOOL inherit_handle, LPCWSTR name)
1788 /*[clinic end generated code: output=c4a45e95545a4bd2 input=dec26598748d35aa]*/
1789 {
1790     HANDLE handle;
1791 
1792     if (PySys_Audit("_winapi.OpenEventW", "ku", desired_access, name) < 0) {
1793         return INVALID_HANDLE_VALUE;
1794     }
1795 
1796     Py_BEGIN_ALLOW_THREADS
1797     handle = OpenEventW(desired_access, inherit_handle, name);
1798     Py_END_ALLOW_THREADS
1799 
1800     if (handle == INVALID_HANDLE_VALUE) {
1801         PyErr_SetFromWindowsErr(0);
1802     }
1803 
1804     return handle;
1805 }
1806 
1807 
1808 /*[clinic input]
1809 _winapi.OpenMutexW -> HANDLE
1810 
1811     desired_access: DWORD
1812     inherit_handle: BOOL
1813     name: LPCWSTR
1814 [clinic start generated code]*/
1815 
1816 static HANDLE
_winapi_OpenMutexW_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1817 _winapi_OpenMutexW_impl(PyObject *module, DWORD desired_access,
1818                         BOOL inherit_handle, LPCWSTR name)
1819 /*[clinic end generated code: output=dda39d7844397bf0 input=f3a7b466c5307712]*/
1820 {
1821     HANDLE handle;
1822 
1823     if (PySys_Audit("_winapi.OpenMutexW", "ku", desired_access, name) < 0) {
1824         return INVALID_HANDLE_VALUE;
1825     }
1826 
1827     Py_BEGIN_ALLOW_THREADS
1828     handle = OpenMutexW(desired_access, inherit_handle, name);
1829     Py_END_ALLOW_THREADS
1830 
1831     if (handle == INVALID_HANDLE_VALUE) {
1832         PyErr_SetFromWindowsErr(0);
1833     }
1834 
1835     return handle;
1836 }
1837 
1838 /*[clinic input]
1839 _winapi.OpenFileMapping -> HANDLE
1840 
1841     desired_access: DWORD
1842     inherit_handle: BOOL
1843     name: LPCWSTR
1844     /
1845 [clinic start generated code]*/
1846 
1847 static HANDLE
_winapi_OpenFileMapping_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1848 _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access,
1849                              BOOL inherit_handle, LPCWSTR name)
1850 /*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/
1851 {
1852     HANDLE handle;
1853 
1854     Py_BEGIN_ALLOW_THREADS
1855     handle = OpenFileMappingW(desired_access, inherit_handle, name);
1856     Py_END_ALLOW_THREADS
1857 
1858     if (handle == NULL) {
1859         PyObject *temp = PyUnicode_FromWideChar(name, -1);
1860         PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
1861         Py_XDECREF(temp);
1862         handle = INVALID_HANDLE_VALUE;
1863     }
1864 
1865     return handle;
1866 }
1867 
1868 /*[clinic input]
1869 _winapi.OpenProcess -> HANDLE
1870 
1871     desired_access: DWORD
1872     inherit_handle: BOOL
1873     process_id: DWORD
1874     /
1875 [clinic start generated code]*/
1876 
1877 static HANDLE
_winapi_OpenProcess_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,DWORD process_id)1878 _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access,
1879                          BOOL inherit_handle, DWORD process_id)
1880 /*[clinic end generated code: output=b42b6b81ea5a0fc3 input=ec98c4cf4ea2ec36]*/
1881 {
1882     HANDLE handle;
1883 
1884     if (PySys_Audit("_winapi.OpenProcess", "kk",
1885                     process_id, desired_access) < 0) {
1886         return INVALID_HANDLE_VALUE;
1887     }
1888 
1889     Py_BEGIN_ALLOW_THREADS
1890     handle = OpenProcess(desired_access, inherit_handle, process_id);
1891     Py_END_ALLOW_THREADS
1892     if (handle == NULL) {
1893         PyErr_SetFromWindowsErr(GetLastError());
1894         handle = INVALID_HANDLE_VALUE;
1895     }
1896 
1897     return handle;
1898 }
1899 
1900 /*[clinic input]
1901 _winapi.PeekNamedPipe
1902 
1903     handle: HANDLE
1904     size: int = 0
1905     /
1906 [clinic start generated code]*/
1907 
1908 static PyObject *
_winapi_PeekNamedPipe_impl(PyObject * module,HANDLE handle,int size)1909 _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
1910 /*[clinic end generated code: output=d0c3e29e49d323dd input=c7aa53bfbce69d70]*/
1911 {
1912     PyObject *buf = NULL;
1913     DWORD nread, navail, nleft;
1914     BOOL ret;
1915 
1916     if (size < 0) {
1917         PyErr_SetString(PyExc_ValueError, "negative size");
1918         return NULL;
1919     }
1920 
1921     if (size) {
1922         buf = PyBytes_FromStringAndSize(NULL, size);
1923         if (!buf)
1924             return NULL;
1925         Py_BEGIN_ALLOW_THREADS
1926         ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1927                             &navail, &nleft);
1928         Py_END_ALLOW_THREADS
1929         if (!ret) {
1930             Py_DECREF(buf);
1931             return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1932         }
1933         if (_PyBytes_Resize(&buf, nread))
1934             return NULL;
1935         return Py_BuildValue("NII", buf, navail, nleft);
1936     }
1937     else {
1938         Py_BEGIN_ALLOW_THREADS
1939         ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1940         Py_END_ALLOW_THREADS
1941         if (!ret) {
1942             return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1943         }
1944         return Py_BuildValue("II", navail, nleft);
1945     }
1946 }
1947 
1948 /*[clinic input]
1949 _winapi.LCMapStringEx
1950 
1951     locale: LPCWSTR
1952     flags: DWORD
1953     src: unicode
1954 
1955 [clinic start generated code]*/
1956 
1957 static PyObject *
_winapi_LCMapStringEx_impl(PyObject * module,LPCWSTR locale,DWORD flags,PyObject * src)1958 _winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
1959                            PyObject *src)
1960 /*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/
1961 {
1962     if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV |
1963                  LCMAP_SORTKEY)) {
1964         return PyErr_Format(PyExc_ValueError, "unsupported flags");
1965     }
1966 
1967     Py_ssize_t src_size;
1968     wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size);
1969     if (!src_) {
1970         return NULL;
1971     }
1972     if (src_size > INT_MAX) {
1973         PyMem_Free(src_);
1974         PyErr_SetString(PyExc_OverflowError, "input string is too long");
1975         return NULL;
1976     }
1977 
1978     int dest_size = LCMapStringEx(locale, flags, src_, (int)src_size, NULL, 0,
1979                                   NULL, NULL, 0);
1980     if (dest_size <= 0) {
1981         DWORD error = GetLastError();
1982         PyMem_Free(src_);
1983         return PyErr_SetFromWindowsErr(error);
1984     }
1985 
1986     wchar_t* dest = PyMem_NEW(wchar_t, dest_size);
1987     if (dest == NULL) {
1988         PyMem_Free(src_);
1989         return PyErr_NoMemory();
1990     }
1991 
1992     int nmapped = LCMapStringEx(locale, flags, src_, (int)src_size, dest, dest_size,
1993                                 NULL, NULL, 0);
1994     if (nmapped <= 0) {
1995         DWORD error = GetLastError();
1996         PyMem_Free(src_);
1997         PyMem_DEL(dest);
1998         return PyErr_SetFromWindowsErr(error);
1999     }
2000 
2001     PyMem_Free(src_);
2002     PyObject *ret = PyUnicode_FromWideChar(dest, nmapped);
2003     PyMem_DEL(dest);
2004 
2005     return ret;
2006 }
2007 
2008 /*[clinic input]
2009 _winapi.ReadFile
2010 
2011     handle: HANDLE
2012     size: DWORD
2013     overlapped as use_overlapped: bool = False
2014 [clinic start generated code]*/
2015 
2016 static PyObject *
_winapi_ReadFile_impl(PyObject * module,HANDLE handle,DWORD size,int use_overlapped)2017 _winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
2018                       int use_overlapped)
2019 /*[clinic end generated code: output=d3d5b44a8201b944 input=4f82f8e909ad91ad]*/
2020 {
2021     DWORD nread;
2022     PyObject *buf;
2023     BOOL ret;
2024     DWORD err;
2025     OverlappedObject *overlapped = NULL;
2026 
2027     buf = PyBytes_FromStringAndSize(NULL, size);
2028     if (!buf)
2029         return NULL;
2030     if (use_overlapped) {
2031         overlapped = new_overlapped(module, handle);
2032         if (!overlapped) {
2033             Py_DECREF(buf);
2034             return NULL;
2035         }
2036         /* Steals reference to buf */
2037         overlapped->read_buffer = buf;
2038     }
2039 
2040     Py_BEGIN_ALLOW_THREADS
2041     ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
2042                    overlapped ? &overlapped->overlapped : NULL);
2043     Py_END_ALLOW_THREADS
2044 
2045     err = ret ? 0 : GetLastError();
2046 
2047     if (overlapped) {
2048         if (!ret) {
2049             if (err == ERROR_IO_PENDING)
2050                 overlapped->pending = 1;
2051             else if (err != ERROR_MORE_DATA) {
2052                 Py_DECREF(overlapped);
2053                 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2054             }
2055         }
2056         return Py_BuildValue("NI", (PyObject *) overlapped, err);
2057     }
2058 
2059     if (!ret && err != ERROR_MORE_DATA) {
2060         Py_DECREF(buf);
2061         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2062     }
2063     if (_PyBytes_Resize(&buf, nread))
2064         return NULL;
2065     return Py_BuildValue("NI", buf, err);
2066 }
2067 
2068 /*[clinic input]
2069 _winapi.ReleaseMutex
2070 
2071     mutex: HANDLE
2072 [clinic start generated code]*/
2073 
2074 static PyObject *
_winapi_ReleaseMutex_impl(PyObject * module,HANDLE mutex)2075 _winapi_ReleaseMutex_impl(PyObject *module, HANDLE mutex)
2076 /*[clinic end generated code: output=5b9001a72dd8af37 input=49e9d20de3559d84]*/
2077 {
2078     int err = 0;
2079 
2080     Py_BEGIN_ALLOW_THREADS
2081     if (!ReleaseMutex(mutex)) {
2082         err = GetLastError();
2083     }
2084     Py_END_ALLOW_THREADS
2085     if (err) {
2086         return PyErr_SetFromWindowsErr(err);
2087     }
2088     Py_RETURN_NONE;
2089 }
2090 
2091 /*[clinic input]
2092 _winapi.ResetEvent
2093 
2094     event: HANDLE
2095 [clinic start generated code]*/
2096 
2097 static PyObject *
_winapi_ResetEvent_impl(PyObject * module,HANDLE event)2098 _winapi_ResetEvent_impl(PyObject *module, HANDLE event)
2099 /*[clinic end generated code: output=81c8501d57c0530d input=e2d42d990322e87a]*/
2100 {
2101     int err = 0;
2102 
2103     Py_BEGIN_ALLOW_THREADS
2104     if (!ResetEvent(event)) {
2105         err = GetLastError();
2106     }
2107     Py_END_ALLOW_THREADS
2108     if (err) {
2109         return PyErr_SetFromWindowsErr(err);
2110     }
2111     Py_RETURN_NONE;
2112 }
2113 
2114 /*[clinic input]
2115 _winapi.SetEvent
2116 
2117     event: HANDLE
2118 [clinic start generated code]*/
2119 
2120 static PyObject *
_winapi_SetEvent_impl(PyObject * module,HANDLE event)2121 _winapi_SetEvent_impl(PyObject *module, HANDLE event)
2122 /*[clinic end generated code: output=c18ba09eb9aa774d input=e660e830a37c09f8]*/
2123 {
2124     int err = 0;
2125 
2126     Py_BEGIN_ALLOW_THREADS
2127     if (!SetEvent(event)) {
2128         err = GetLastError();
2129     }
2130     Py_END_ALLOW_THREADS
2131     if (err) {
2132         return PyErr_SetFromWindowsErr(err);
2133     }
2134     Py_RETURN_NONE;
2135 }
2136 
2137 /*[clinic input]
2138 _winapi.SetNamedPipeHandleState
2139 
2140     named_pipe: HANDLE
2141     mode: object
2142     max_collection_count: object
2143     collect_data_timeout: object
2144     /
2145 [clinic start generated code]*/
2146 
2147 static PyObject *
_winapi_SetNamedPipeHandleState_impl(PyObject * module,HANDLE named_pipe,PyObject * mode,PyObject * max_collection_count,PyObject * collect_data_timeout)2148 _winapi_SetNamedPipeHandleState_impl(PyObject *module, HANDLE named_pipe,
2149                                      PyObject *mode,
2150                                      PyObject *max_collection_count,
2151                                      PyObject *collect_data_timeout)
2152 /*[clinic end generated code: output=f2129d222cbfa095 input=9142d72163d0faa6]*/
2153 {
2154     PyObject *oArgs[3] = {mode, max_collection_count, collect_data_timeout};
2155     DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
2156     int i;
2157     BOOL b;
2158 
2159     for (i = 0 ; i < 3 ; i++) {
2160         if (oArgs[i] != Py_None) {
2161             dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
2162             if (PyErr_Occurred())
2163                 return NULL;
2164             pArgs[i] = &dwArgs[i];
2165         }
2166     }
2167 
2168     Py_BEGIN_ALLOW_THREADS
2169     b = SetNamedPipeHandleState(named_pipe, pArgs[0], pArgs[1], pArgs[2]);
2170     Py_END_ALLOW_THREADS
2171 
2172     if (!b)
2173         return PyErr_SetFromWindowsErr(0);
2174 
2175     Py_RETURN_NONE;
2176 }
2177 
2178 
2179 /*[clinic input]
2180 _winapi.TerminateProcess
2181 
2182     handle: HANDLE
2183     exit_code: UINT
2184     /
2185 
2186 Terminate the specified process and all of its threads.
2187 [clinic start generated code]*/
2188 
2189 static PyObject *
_winapi_TerminateProcess_impl(PyObject * module,HANDLE handle,UINT exit_code)2190 _winapi_TerminateProcess_impl(PyObject *module, HANDLE handle,
2191                               UINT exit_code)
2192 /*[clinic end generated code: output=f4e99ac3f0b1f34a input=d6bc0aa1ee3bb4df]*/
2193 {
2194     BOOL result;
2195 
2196     if (PySys_Audit("_winapi.TerminateProcess", "nI",
2197                     (Py_ssize_t)handle, exit_code) < 0) {
2198         return NULL;
2199     }
2200 
2201     result = TerminateProcess(handle, exit_code);
2202 
2203     if (! result)
2204         return PyErr_SetFromWindowsErr(GetLastError());
2205 
2206     Py_RETURN_NONE;
2207 }
2208 
2209 /*[clinic input]
2210 _winapi.VirtualQuerySize -> size_t
2211 
2212     address: LPCVOID
2213     /
2214 [clinic start generated code]*/
2215 
2216 static size_t
_winapi_VirtualQuerySize_impl(PyObject * module,LPCVOID address)2217 _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address)
2218 /*[clinic end generated code: output=40c8e0ff5ec964df input=6b784a69755d0bb6]*/
2219 {
2220     SIZE_T size_of_buf;
2221     MEMORY_BASIC_INFORMATION mem_basic_info;
2222     SIZE_T region_size;
2223 
2224     Py_BEGIN_ALLOW_THREADS
2225     size_of_buf = VirtualQuery(address, &mem_basic_info, sizeof(mem_basic_info));
2226     Py_END_ALLOW_THREADS
2227 
2228     if (size_of_buf == 0)
2229         PyErr_SetFromWindowsErr(0);
2230 
2231     region_size = mem_basic_info.RegionSize;
2232     return region_size;
2233 }
2234 
2235 /*[clinic input]
2236 _winapi.WaitNamedPipe
2237 
2238     name: LPCWSTR
2239     timeout: DWORD
2240     /
2241 [clinic start generated code]*/
2242 
2243 static PyObject *
_winapi_WaitNamedPipe_impl(PyObject * module,LPCWSTR name,DWORD timeout)2244 _winapi_WaitNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD timeout)
2245 /*[clinic end generated code: output=e161e2e630b3e9c2 input=099a4746544488fa]*/
2246 {
2247     BOOL success;
2248 
2249     Py_BEGIN_ALLOW_THREADS
2250     success = WaitNamedPipeW(name, timeout);
2251     Py_END_ALLOW_THREADS
2252 
2253     if (!success)
2254         return PyErr_SetFromWindowsErr(0);
2255 
2256     Py_RETURN_NONE;
2257 }
2258 
2259 
2260 typedef struct {
2261     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2262     HANDLE cancel_event;
2263     DWORD handle_base;
2264     DWORD handle_count;
2265     HANDLE thread;
2266     volatile DWORD result;
2267 } BatchedWaitData;
2268 
2269 static DWORD WINAPI
_batched_WaitForMultipleObjects_thread(LPVOID param)2270 _batched_WaitForMultipleObjects_thread(LPVOID param)
2271 {
2272     BatchedWaitData *data = (BatchedWaitData *)param;
2273     data->result = WaitForMultipleObjects(
2274         data->handle_count,
2275         data->handles,
2276         FALSE,
2277         INFINITE
2278     );
2279     if (data->result == WAIT_FAILED) {
2280         DWORD err = GetLastError();
2281         SetEvent(data->cancel_event);
2282         return err;
2283     } else if (data->result >= WAIT_ABANDONED_0 && data->result < WAIT_ABANDONED_0 + MAXIMUM_WAIT_OBJECTS) {
2284         data->result = WAIT_FAILED;
2285         SetEvent(data->cancel_event);
2286         return ERROR_ABANDONED_WAIT_0;
2287     }
2288     return 0;
2289 }
2290 
2291 /*[clinic input]
2292 _winapi.BatchedWaitForMultipleObjects
2293 
2294     handle_seq: object
2295     wait_all: BOOL
2296     milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
2297 
2298 Supports a larger number of handles than WaitForMultipleObjects
2299 
2300 Note that the handles may be waited on other threads, which could cause
2301 issues for objects like mutexes that become associated with the thread
2302 that was waiting for them. Objects may also be left signalled, even if
2303 the wait fails.
2304 
2305 It is recommended to use WaitForMultipleObjects whenever possible, and
2306 only switch to BatchedWaitForMultipleObjects for scenarios where you
2307 control all the handles involved, such as your own thread pool or
2308 files, and all wait objects are left unmodified by a wait (for example,
2309 manual reset events, threads, and files/pipes).
2310 
2311 Overlapped handles returned from this module use manual reset events.
2312 [clinic start generated code]*/
2313 
2314 static PyObject *
_winapi_BatchedWaitForMultipleObjects_impl(PyObject * module,PyObject * handle_seq,BOOL wait_all,DWORD milliseconds)2315 _winapi_BatchedWaitForMultipleObjects_impl(PyObject *module,
2316                                            PyObject *handle_seq,
2317                                            BOOL wait_all, DWORD milliseconds)
2318 /*[clinic end generated code: output=d21c1a4ad0a252fd input=7e196f29005dc77b]*/
2319 {
2320     Py_ssize_t thread_count = 0, handle_count = 0, i;
2321     Py_ssize_t nhandles;
2322     BatchedWaitData *thread_data[MAXIMUM_WAIT_OBJECTS];
2323     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2324     HANDLE sigint_event = NULL;
2325     HANDLE cancel_event = NULL;
2326     DWORD result;
2327 
2328     const Py_ssize_t _MAXIMUM_TOTAL_OBJECTS = (MAXIMUM_WAIT_OBJECTS - 1) * (MAXIMUM_WAIT_OBJECTS - 1);
2329 
2330     if (!PySequence_Check(handle_seq)) {
2331         PyErr_Format(PyExc_TypeError,
2332                      "sequence type expected, got '%s'",
2333                      Py_TYPE(handle_seq)->tp_name);
2334         return NULL;
2335     }
2336     nhandles = PySequence_Length(handle_seq);
2337     if (nhandles == -1) {
2338         return NULL;
2339     }
2340     if (nhandles == 0) {
2341         return wait_all ? Py_NewRef(Py_None) : PyList_New(0);
2342     }
2343 
2344     /* If this is the main thread then make the wait interruptible
2345        by Ctrl-C. When waiting for *all* handles, it is only checked
2346        in between batches. */
2347     if (_PyOS_IsMainThread()) {
2348         sigint_event = _PyOS_SigintEvent();
2349         assert(sigint_event != NULL);
2350     }
2351 
2352     if (nhandles < 0 || nhandles > _MAXIMUM_TOTAL_OBJECTS) {
2353         PyErr_Format(PyExc_ValueError,
2354                      "need at most %zd handles, got a sequence of length %zd",
2355                      _MAXIMUM_TOTAL_OBJECTS, nhandles);
2356         return NULL;
2357     }
2358 
2359     if (!wait_all) {
2360         cancel_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2361         if (!cancel_event) {
2362             PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2363             return NULL;
2364         }
2365     }
2366 
2367     i = 0;
2368     while (i < nhandles) {
2369         BatchedWaitData *data = (BatchedWaitData*)PyMem_Malloc(sizeof(BatchedWaitData));
2370         if (!data) {
2371             goto error;
2372         }
2373         thread_data[thread_count++] = data;
2374         data->thread = NULL;
2375         data->cancel_event = cancel_event;
2376         data->handle_base = Py_SAFE_DOWNCAST(i, Py_ssize_t, DWORD);
2377         data->handle_count = Py_SAFE_DOWNCAST(nhandles - i, Py_ssize_t, DWORD);
2378         if (data->handle_count > MAXIMUM_WAIT_OBJECTS - 1) {
2379             data->handle_count = MAXIMUM_WAIT_OBJECTS - 1;
2380         }
2381         for (DWORD j = 0; j < data->handle_count; ++i, ++j) {
2382             PyObject *v = PySequence_GetItem(handle_seq, i);
2383             if (!v || !PyArg_Parse(v, F_HANDLE, &data->handles[j])) {
2384                 Py_XDECREF(v);
2385                 goto error;
2386             }
2387             Py_DECREF(v);
2388         }
2389         if (!wait_all) {
2390             data->handles[data->handle_count++] = cancel_event;
2391         }
2392     }
2393 
2394     DWORD err = 0;
2395 
2396     /* We need to use different strategies when waiting for ALL handles
2397        as opposed to ANY handle. This is because there is no way to
2398        (safely) interrupt a thread that is waiting for all handles in a
2399        group. So for ALL handles, we loop over each set and wait. For
2400        ANY handle, we use threads and wait on them. */
2401     if (wait_all) {
2402         Py_BEGIN_ALLOW_THREADS
2403         long long deadline = 0;
2404         if (milliseconds != INFINITE) {
2405             deadline = (long long)GetTickCount64() + milliseconds;
2406         }
2407 
2408         for (i = 0; !err && i < thread_count; ++i) {
2409             DWORD timeout = milliseconds;
2410             if (deadline) {
2411                 long long time_to_deadline = deadline - GetTickCount64();
2412                 if (time_to_deadline <= 0) {
2413                     err = WAIT_TIMEOUT;
2414                     break;
2415                 } else if (time_to_deadline < UINT_MAX) {
2416                     timeout = (DWORD)time_to_deadline;
2417                 }
2418             }
2419             result = WaitForMultipleObjects(thread_data[i]->handle_count,
2420                                             thread_data[i]->handles, TRUE, timeout);
2421             // ABANDONED is not possible here because we own all the handles
2422             if (result == WAIT_FAILED) {
2423                 err = GetLastError();
2424             } else if (result == WAIT_TIMEOUT) {
2425                 err = WAIT_TIMEOUT;
2426             }
2427 
2428             if (!err && sigint_event) {
2429                 result = WaitForSingleObject(sigint_event, 0);
2430                 if (result == WAIT_OBJECT_0) {
2431                     err = ERROR_CONTROL_C_EXIT;
2432                 } else if (result == WAIT_FAILED) {
2433                     err = GetLastError();
2434                 }
2435             }
2436         }
2437 
2438         CloseHandle(cancel_event);
2439 
2440         Py_END_ALLOW_THREADS
2441     } else {
2442         Py_BEGIN_ALLOW_THREADS
2443 
2444         for (i = 0; i < thread_count; ++i) {
2445             BatchedWaitData *data = thread_data[i];
2446             data->thread = CreateThread(
2447                 NULL,
2448                 1,  // smallest possible initial stack
2449                 _batched_WaitForMultipleObjects_thread,
2450                 (LPVOID)data,
2451                 CREATE_SUSPENDED,
2452                 NULL
2453             );
2454             if (!data->thread) {
2455                 err = GetLastError();
2456                 break;
2457             }
2458             handles[handle_count++] = data->thread;
2459         }
2460         Py_END_ALLOW_THREADS
2461 
2462         if (err) {
2463             PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
2464             goto error;
2465         }
2466         if (handle_count > MAXIMUM_WAIT_OBJECTS - 1) {
2467             // basically an assert, but stronger
2468             PyErr_SetString(PyExc_SystemError, "allocated too many wait objects");
2469             goto error;
2470         }
2471 
2472         Py_BEGIN_ALLOW_THREADS
2473 
2474         // Once we start resuming threads, can no longer "goto error"
2475         for (i = 0; i < thread_count; ++i) {
2476             ResumeThread(thread_data[i]->thread);
2477         }
2478         if (sigint_event) {
2479             handles[handle_count++] = sigint_event;
2480         }
2481         result = WaitForMultipleObjects((DWORD)handle_count, handles, wait_all, milliseconds);
2482         // ABANDONED is not possible here because we own all the handles
2483         if (result == WAIT_FAILED) {
2484             err = GetLastError();
2485         } else if (result == WAIT_TIMEOUT) {
2486             err = WAIT_TIMEOUT;
2487         } else if (sigint_event && result == WAIT_OBJECT_0 + handle_count) {
2488             err = ERROR_CONTROL_C_EXIT;
2489         }
2490 
2491         SetEvent(cancel_event);
2492 
2493         // Wait for all threads to finish before we start freeing their memory
2494         if (sigint_event) {
2495             handle_count -= 1;
2496         }
2497         WaitForMultipleObjects((DWORD)handle_count, handles, TRUE, INFINITE);
2498 
2499         for (i = 0; i < thread_count; ++i) {
2500             if (!err && thread_data[i]->result == WAIT_FAILED) {
2501                 if (!GetExitCodeThread(thread_data[i]->thread, &err)) {
2502                     err = GetLastError();
2503                 }
2504             }
2505             CloseHandle(thread_data[i]->thread);
2506         }
2507 
2508         CloseHandle(cancel_event);
2509 
2510         Py_END_ALLOW_THREADS
2511 
2512     }
2513 
2514     PyObject *triggered_indices;
2515     if (sigint_event != NULL && err == ERROR_CONTROL_C_EXIT) {
2516         errno = EINTR;
2517         PyErr_SetFromErrno(PyExc_OSError);
2518         triggered_indices = NULL;
2519     } else if (err) {
2520         PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
2521         triggered_indices = NULL;
2522     } else if (wait_all) {
2523         triggered_indices = Py_NewRef(Py_None);
2524     } else {
2525         triggered_indices = PyList_New(0);
2526         if (triggered_indices) {
2527             for (i = 0; i < thread_count; ++i) {
2528                 Py_ssize_t triggered = (Py_ssize_t)thread_data[i]->result - WAIT_OBJECT_0;
2529                 if (triggered >= 0 && (size_t)triggered < thread_data[i]->handle_count - 1) {
2530                     PyObject *v = PyLong_FromSsize_t(thread_data[i]->handle_base + triggered);
2531                     if (!v || PyList_Append(triggered_indices, v) < 0) {
2532                         Py_XDECREF(v);
2533                         Py_CLEAR(triggered_indices);
2534                         break;
2535                     }
2536                     Py_DECREF(v);
2537                 }
2538             }
2539         }
2540     }
2541 
2542     for (i = 0; i < thread_count; ++i) {
2543         PyMem_Free((void *)thread_data[i]);
2544     }
2545 
2546     return triggered_indices;
2547 
2548 error:
2549     // We should only enter here before any threads start running.
2550     // Once we start resuming threads, different cleanup is required
2551     CloseHandle(cancel_event);
2552     while (--thread_count >= 0) {
2553         HANDLE t = thread_data[thread_count]->thread;
2554         if (t) {
2555             TerminateThread(t, WAIT_ABANDONED_0);
2556             CloseHandle(t);
2557         }
2558         PyMem_Free((void *)thread_data[thread_count]);
2559     }
2560     return NULL;
2561 }
2562 
2563 /*[clinic input]
2564 _winapi.WaitForMultipleObjects
2565 
2566     handle_seq: object
2567     wait_flag: BOOL
2568     milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
2569     /
2570 [clinic start generated code]*/
2571 
2572 static PyObject *
_winapi_WaitForMultipleObjects_impl(PyObject * module,PyObject * handle_seq,BOOL wait_flag,DWORD milliseconds)2573 _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq,
2574                                     BOOL wait_flag, DWORD milliseconds)
2575 /*[clinic end generated code: output=295e3f00b8e45899 input=36f76ca057cd28a0]*/
2576 {
2577     DWORD result;
2578     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2579     HANDLE sigint_event = NULL;
2580     Py_ssize_t nhandles, i;
2581 
2582     if (!PySequence_Check(handle_seq)) {
2583         PyErr_Format(PyExc_TypeError,
2584                      "sequence type expected, got '%s'",
2585                      Py_TYPE(handle_seq)->tp_name);
2586         return NULL;
2587     }
2588     nhandles = PySequence_Length(handle_seq);
2589     if (nhandles == -1)
2590         return NULL;
2591     if (nhandles < 0 || nhandles > MAXIMUM_WAIT_OBJECTS - 1) {
2592         PyErr_Format(PyExc_ValueError,
2593                      "need at most %zd handles, got a sequence of length %zd",
2594                      MAXIMUM_WAIT_OBJECTS - 1, nhandles);
2595         return NULL;
2596     }
2597     for (i = 0; i < nhandles; i++) {
2598         HANDLE h;
2599         PyObject *v = PySequence_GetItem(handle_seq, i);
2600         if (v == NULL)
2601             return NULL;
2602         if (!PyArg_Parse(v, F_HANDLE, &h)) {
2603             Py_DECREF(v);
2604             return NULL;
2605         }
2606         handles[i] = h;
2607         Py_DECREF(v);
2608     }
2609     /* If this is the main thread then make the wait interruptible
2610        by Ctrl-C unless we are waiting for *all* handles */
2611     if (!wait_flag && _PyOS_IsMainThread()) {
2612         sigint_event = _PyOS_SigintEvent();
2613         assert(sigint_event != NULL);
2614         handles[nhandles++] = sigint_event;
2615     }
2616 
2617     Py_BEGIN_ALLOW_THREADS
2618     if (sigint_event != NULL)
2619         ResetEvent(sigint_event);
2620     result = WaitForMultipleObjects((DWORD) nhandles, handles,
2621                                     wait_flag, milliseconds);
2622     Py_END_ALLOW_THREADS
2623 
2624     if (result == WAIT_FAILED)
2625         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2626     else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
2627         errno = EINTR;
2628         return PyErr_SetFromErrno(PyExc_OSError);
2629     }
2630 
2631     return PyLong_FromLong((int) result);
2632 }
2633 
2634 /*[clinic input]
2635 _winapi.WaitForSingleObject -> long
2636 
2637     handle: HANDLE
2638     milliseconds: DWORD
2639     /
2640 
2641 Wait for a single object.
2642 
2643 Wait until the specified object is in the signaled state or
2644 the time-out interval elapses. The timeout value is specified
2645 in milliseconds.
2646 [clinic start generated code]*/
2647 
2648 static long
_winapi_WaitForSingleObject_impl(PyObject * module,HANDLE handle,DWORD milliseconds)2649 _winapi_WaitForSingleObject_impl(PyObject *module, HANDLE handle,
2650                                  DWORD milliseconds)
2651 /*[clinic end generated code: output=3c4715d8f1b39859 input=443d1ab076edc7b1]*/
2652 {
2653     DWORD result;
2654 
2655     Py_BEGIN_ALLOW_THREADS
2656     result = WaitForSingleObject(handle, milliseconds);
2657     Py_END_ALLOW_THREADS
2658 
2659     if (result == WAIT_FAILED) {
2660         PyErr_SetFromWindowsErr(GetLastError());
2661         return -1;
2662     }
2663 
2664     return result;
2665 }
2666 
2667 /*[clinic input]
2668 _winapi.WriteFile
2669 
2670     handle: HANDLE
2671     buffer: object
2672     overlapped as use_overlapped: bool = False
2673 [clinic start generated code]*/
2674 
2675 static PyObject *
_winapi_WriteFile_impl(PyObject * module,HANDLE handle,PyObject * buffer,int use_overlapped)2676 _winapi_WriteFile_impl(PyObject *module, HANDLE handle, PyObject *buffer,
2677                        int use_overlapped)
2678 /*[clinic end generated code: output=2ca80f6bf3fa92e3 input=2badb008c8a2e2a0]*/
2679 {
2680     Py_buffer _buf, *buf;
2681     DWORD len, written;
2682     BOOL ret;
2683     DWORD err;
2684     OverlappedObject *overlapped = NULL;
2685 
2686     if (use_overlapped) {
2687         overlapped = new_overlapped(module, handle);
2688         if (!overlapped)
2689             return NULL;
2690         buf = &overlapped->write_buffer;
2691     }
2692     else
2693         buf = &_buf;
2694 
2695     if (!PyArg_Parse(buffer, "y*", buf)) {
2696         Py_XDECREF(overlapped);
2697         return NULL;
2698     }
2699 
2700     Py_BEGIN_ALLOW_THREADS
2701     len = (DWORD)Py_MIN(buf->len, PY_DWORD_MAX);
2702     ret = WriteFile(handle, buf->buf, len, &written,
2703                     overlapped ? &overlapped->overlapped : NULL);
2704     Py_END_ALLOW_THREADS
2705 
2706     err = ret ? 0 : GetLastError();
2707 
2708     if (overlapped) {
2709         if (!ret) {
2710             if (err == ERROR_IO_PENDING)
2711                 overlapped->pending = 1;
2712             else {
2713                 Py_DECREF(overlapped);
2714                 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2715             }
2716         }
2717         return Py_BuildValue("NI", (PyObject *) overlapped, err);
2718     }
2719 
2720     PyBuffer_Release(buf);
2721     if (!ret)
2722         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2723     return Py_BuildValue("II", written, err);
2724 }
2725 
2726 /*[clinic input]
2727 _winapi.GetACP
2728 
2729 Get the current Windows ANSI code page identifier.
2730 [clinic start generated code]*/
2731 
2732 static PyObject *
_winapi_GetACP_impl(PyObject * module)2733 _winapi_GetACP_impl(PyObject *module)
2734 /*[clinic end generated code: output=f7ee24bf705dbb88 input=1433c96d03a05229]*/
2735 {
2736     return PyLong_FromUnsignedLong(GetACP());
2737 }
2738 
2739 /*[clinic input]
2740 _winapi.GetFileType -> DWORD
2741 
2742     handle: HANDLE
2743 [clinic start generated code]*/
2744 
2745 static DWORD
_winapi_GetFileType_impl(PyObject * module,HANDLE handle)2746 _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
2747 /*[clinic end generated code: output=92b8466ac76ecc17 input=0058366bc40bbfbf]*/
2748 {
2749     DWORD result;
2750 
2751     Py_BEGIN_ALLOW_THREADS
2752     result = GetFileType(handle);
2753     Py_END_ALLOW_THREADS
2754 
2755     if (result == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) {
2756         PyErr_SetFromWindowsErr(0);
2757         return -1;
2758     }
2759 
2760     return result;
2761 }
2762 
2763 
2764 /*[clinic input]
2765 _winapi._mimetypes_read_windows_registry
2766 
2767     on_type_read: object
2768 
2769 Optimized function for reading all known MIME types from the registry.
2770 
2771 *on_type_read* is a callable taking *type* and *ext* arguments, as for
2772 MimeTypes.add_type.
2773 [clinic start generated code]*/
2774 
2775 static PyObject *
_winapi__mimetypes_read_windows_registry_impl(PyObject * module,PyObject * on_type_read)2776 _winapi__mimetypes_read_windows_registry_impl(PyObject *module,
2777                                               PyObject *on_type_read)
2778 /*[clinic end generated code: output=20829f00bebce55b input=cd357896d6501f68]*/
2779 {
2780 #define CCH_EXT 128
2781 #define CB_TYPE 510
2782     struct {
2783         wchar_t ext[CCH_EXT];
2784         wchar_t type[CB_TYPE / sizeof(wchar_t) + 1];
2785     } entries[64];
2786     int entry = 0;
2787     HKEY hkcr = NULL;
2788     LRESULT err;
2789 
2790     Py_BEGIN_ALLOW_THREADS
2791     err = RegOpenKeyExW(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hkcr);
2792     for (DWORD i = 0; err == ERROR_SUCCESS || err == ERROR_MORE_DATA; ++i) {
2793         LPWSTR ext = entries[entry].ext;
2794         LPWSTR type = entries[entry].type;
2795         DWORD cchExt = CCH_EXT;
2796         DWORD cbType = CB_TYPE;
2797         HKEY subkey;
2798         DWORD regType;
2799 
2800         err = RegEnumKeyExW(hkcr, i, ext, &cchExt, NULL, NULL, NULL, NULL);
2801         if (err != ERROR_SUCCESS || (cchExt && ext[0] != L'.')) {
2802             continue;
2803         }
2804 
2805         err = RegOpenKeyExW(hkcr, ext, 0, KEY_READ, &subkey);
2806         if (err == ERROR_FILE_NOT_FOUND || err == ERROR_ACCESS_DENIED) {
2807             err = ERROR_SUCCESS;
2808             continue;
2809         } else if (err != ERROR_SUCCESS) {
2810             continue;
2811         }
2812 
2813         err = RegQueryValueExW(subkey, L"Content Type", NULL,
2814                               &regType, (LPBYTE)type, &cbType);
2815         RegCloseKey(subkey);
2816         if (err == ERROR_FILE_NOT_FOUND) {
2817             err = ERROR_SUCCESS;
2818             continue;
2819         } else if (err != ERROR_SUCCESS) {
2820             continue;
2821         } else if (regType != REG_SZ || !cbType) {
2822             continue;
2823         }
2824         type[cbType / sizeof(wchar_t)] = L'\0';
2825 
2826         entry += 1;
2827 
2828         /* Flush our cached entries if we are full */
2829         if (entry == sizeof(entries) / sizeof(entries[0])) {
2830             Py_BLOCK_THREADS
2831             for (int j = 0; j < entry; ++j) {
2832                 PyObject *r = PyObject_CallFunction(
2833                     on_type_read, "uu", entries[j].type, entries[j].ext
2834                 );
2835                 if (!r) {
2836                     /* We blocked threads, so safe to return from here */
2837                     RegCloseKey(hkcr);
2838                     return NULL;
2839                 }
2840                 Py_DECREF(r);
2841             }
2842             Py_UNBLOCK_THREADS
2843             entry = 0;
2844         }
2845     }
2846     if (hkcr) {
2847         RegCloseKey(hkcr);
2848     }
2849     Py_END_ALLOW_THREADS
2850 
2851     if (err != ERROR_SUCCESS && err != ERROR_NO_MORE_ITEMS) {
2852         PyErr_SetFromWindowsErr((int)err);
2853         return NULL;
2854     }
2855 
2856     for (int j = 0; j < entry; ++j) {
2857         PyObject *r = PyObject_CallFunction(
2858             on_type_read, "uu", entries[j].type, entries[j].ext
2859         );
2860         if (!r) {
2861             return NULL;
2862         }
2863         Py_DECREF(r);
2864     }
2865 
2866     Py_RETURN_NONE;
2867 #undef CCH_EXT
2868 #undef CB_TYPE
2869 }
2870 
2871 /*[clinic input]
2872 _winapi.NeedCurrentDirectoryForExePath -> bool
2873 
2874     exe_name: LPCWSTR
2875     /
2876 [clinic start generated code]*/
2877 
2878 static int
_winapi_NeedCurrentDirectoryForExePath_impl(PyObject * module,LPCWSTR exe_name)2879 _winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module,
2880                                             LPCWSTR exe_name)
2881 /*[clinic end generated code: output=a65ec879502b58fc input=972aac88a1ec2f00]*/
2882 {
2883     BOOL result;
2884 
2885     Py_BEGIN_ALLOW_THREADS
2886     result = NeedCurrentDirectoryForExePathW(exe_name);
2887     Py_END_ALLOW_THREADS
2888 
2889     return result;
2890 }
2891 
2892 
2893 /*[clinic input]
2894 _winapi.CopyFile2
2895 
2896     existing_file_name: LPCWSTR
2897     new_file_name: LPCWSTR
2898     flags: DWORD
2899     progress_routine: object = None
2900 
2901 Copies a file from one name to a new name.
2902 
2903 This is implemented using the CopyFile2 API, which preserves all stat
2904 and metadata information apart from security attributes.
2905 
2906 progress_routine is reserved for future use, but is currently not
2907 implemented. Its value is ignored.
2908 [clinic start generated code]*/
2909 
2910 static PyObject *
_winapi_CopyFile2_impl(PyObject * module,LPCWSTR existing_file_name,LPCWSTR new_file_name,DWORD flags,PyObject * progress_routine)2911 _winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name,
2912                        LPCWSTR new_file_name, DWORD flags,
2913                        PyObject *progress_routine)
2914 /*[clinic end generated code: output=43d960d9df73d984 input=fb976b8d1492d130]*/
2915 {
2916     HRESULT hr;
2917     COPYFILE2_EXTENDED_PARAMETERS params = { sizeof(COPYFILE2_EXTENDED_PARAMETERS) };
2918 
2919     if (PySys_Audit("_winapi.CopyFile2", "uuk",
2920                     existing_file_name, new_file_name, flags) < 0) {
2921         return NULL;
2922     }
2923 
2924     params.dwCopyFlags = flags;
2925     /* For future implementation. We ignore the value for now so that
2926        users only have to test for 'CopyFile2' existing and not whether
2927        the additional parameter exists.
2928     if (progress_routine != Py_None) {
2929         params.pProgressRoutine = _winapi_CopyFile2ProgressRoutine;
2930         params.pvCallbackContext = Py_NewRef(progress_routine);
2931     }
2932     */
2933     Py_BEGIN_ALLOW_THREADS;
2934     hr = CopyFile2(existing_file_name, new_file_name, &params);
2935     Py_END_ALLOW_THREADS;
2936     /* For future implementation.
2937     if (progress_routine != Py_None) {
2938         Py_DECREF(progress_routine);
2939     }
2940     */
2941     if (FAILED(hr)) {
2942         if ((hr & 0xFFFF0000) == 0x80070000) {
2943             PyErr_SetFromWindowsErr(hr & 0xFFFF);
2944         } else {
2945             PyErr_SetFromWindowsErr(hr);
2946         }
2947         return NULL;
2948     }
2949     Py_RETURN_NONE;
2950 }
2951 
2952 
2953 static PyMethodDef winapi_functions[] = {
2954     _WINAPI_CLOSEHANDLE_METHODDEF
2955     _WINAPI_CONNECTNAMEDPIPE_METHODDEF
2956     _WINAPI_CREATEEVENTW_METHODDEF
2957     _WINAPI_CREATEFILE_METHODDEF
2958     _WINAPI_CREATEFILEMAPPING_METHODDEF
2959     _WINAPI_CREATEMUTEXW_METHODDEF
2960     _WINAPI_CREATENAMEDPIPE_METHODDEF
2961     _WINAPI_CREATEPIPE_METHODDEF
2962     _WINAPI_CREATEPROCESS_METHODDEF
2963     _WINAPI_CREATEJUNCTION_METHODDEF
2964     _WINAPI_DUPLICATEHANDLE_METHODDEF
2965     _WINAPI_EXITPROCESS_METHODDEF
2966     _WINAPI_GETCURRENTPROCESS_METHODDEF
2967     _WINAPI_GETEXITCODEPROCESS_METHODDEF
2968     _WINAPI_GETLASTERROR_METHODDEF
2969     _WINAPI_GETLONGPATHNAME_METHODDEF
2970     _WINAPI_GETMODULEFILENAME_METHODDEF
2971     _WINAPI_GETSHORTPATHNAME_METHODDEF
2972     _WINAPI_GETSTDHANDLE_METHODDEF
2973     _WINAPI_GETVERSION_METHODDEF
2974     _WINAPI_MAPVIEWOFFILE_METHODDEF
2975     _WINAPI_OPENEVENTW_METHODDEF
2976     _WINAPI_OPENFILEMAPPING_METHODDEF
2977     _WINAPI_OPENMUTEXW_METHODDEF
2978     _WINAPI_OPENPROCESS_METHODDEF
2979     _WINAPI_PEEKNAMEDPIPE_METHODDEF
2980     _WINAPI_LCMAPSTRINGEX_METHODDEF
2981     _WINAPI_READFILE_METHODDEF
2982     _WINAPI_RELEASEMUTEX_METHODDEF
2983     _WINAPI_RESETEVENT_METHODDEF
2984     _WINAPI_SETEVENT_METHODDEF
2985     _WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF
2986     _WINAPI_TERMINATEPROCESS_METHODDEF
2987     _WINAPI_UNMAPVIEWOFFILE_METHODDEF
2988     _WINAPI_VIRTUALQUERYSIZE_METHODDEF
2989     _WINAPI_WAITNAMEDPIPE_METHODDEF
2990     _WINAPI_WAITFORMULTIPLEOBJECTS_METHODDEF
2991     _WINAPI_BATCHEDWAITFORMULTIPLEOBJECTS_METHODDEF
2992     _WINAPI_WAITFORSINGLEOBJECT_METHODDEF
2993     _WINAPI_WRITEFILE_METHODDEF
2994     _WINAPI_GETACP_METHODDEF
2995     _WINAPI_GETFILETYPE_METHODDEF
2996     _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
2997     _WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
2998     _WINAPI_COPYFILE2_METHODDEF
2999     {NULL, NULL}
3000 };
3001 
3002 #define WINAPI_CONSTANT(fmt, con) \
3003     do { \
3004         PyObject *value = Py_BuildValue(fmt, con); \
3005         if (value == NULL) { \
3006             return -1; \
3007         } \
3008         if (PyDict_SetItemString(d, #con, value) < 0) { \
3009             Py_DECREF(value); \
3010             return -1; \
3011         } \
3012         Py_DECREF(value); \
3013     } while (0)
3014 
winapi_exec(PyObject * m)3015 static int winapi_exec(PyObject *m)
3016 {
3017     WinApiState *st = winapi_get_state(m);
3018 
3019     st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &winapi_overlapped_type_spec, NULL);
3020     if (st->overlapped_type == NULL) {
3021         return -1;
3022     }
3023 
3024     if (PyModule_AddType(m, st->overlapped_type) < 0) {
3025         return -1;
3026     }
3027 
3028     PyObject *d = PyModule_GetDict(m);
3029 
3030     /* constants */
3031     WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
3032     WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
3033     WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
3034     WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
3035     WINAPI_CONSTANT(F_DWORD, ERROR_ACCESS_DENIED);
3036     WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
3037     WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
3038     WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
3039     WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
3040     WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
3041     WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
3042     WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
3043     WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
3044     WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
3045     WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
3046     WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
3047     WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
3048     WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
3049     WINAPI_CONSTANT(F_DWORD, ERROR_PRIVILEGE_NOT_HELD);
3050     WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
3051     WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
3052     WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
3053     WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
3054     WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
3055     WINAPI_CONSTANT(F_DWORD, FILE_MAP_ALL_ACCESS);
3056     WINAPI_CONSTANT(F_DWORD, FILE_MAP_COPY);
3057     WINAPI_CONSTANT(F_DWORD, FILE_MAP_EXECUTE);
3058     WINAPI_CONSTANT(F_DWORD, FILE_MAP_READ);
3059     WINAPI_CONSTANT(F_DWORD, FILE_MAP_WRITE);
3060     WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
3061     WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
3062     WINAPI_CONSTANT(F_DWORD, INFINITE);
3063     WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
3064     WINAPI_CONSTANT(F_DWORD, MEM_COMMIT);
3065     WINAPI_CONSTANT(F_DWORD, MEM_FREE);
3066     WINAPI_CONSTANT(F_DWORD, MEM_IMAGE);
3067     WINAPI_CONSTANT(F_DWORD, MEM_MAPPED);
3068     WINAPI_CONSTANT(F_DWORD, MEM_PRIVATE);
3069     WINAPI_CONSTANT(F_DWORD, MEM_RESERVE);
3070     WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
3071     WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
3072     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE);
3073     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READ);
3074     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READWRITE);
3075     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_WRITECOPY);
3076     WINAPI_CONSTANT(F_DWORD, PAGE_GUARD);
3077     WINAPI_CONSTANT(F_DWORD, PAGE_NOACCESS);
3078     WINAPI_CONSTANT(F_DWORD, PAGE_NOCACHE);
3079     WINAPI_CONSTANT(F_DWORD, PAGE_READONLY);
3080     WINAPI_CONSTANT(F_DWORD, PAGE_READWRITE);
3081     WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOMBINE);
3082     WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOPY);
3083     WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
3084     WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
3085     WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
3086     WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
3087     WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
3088     WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
3089     WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
3090     WINAPI_CONSTANT(F_DWORD, SYNCHRONIZE);
3091     WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
3092     WINAPI_CONSTANT(F_DWORD, SEC_COMMIT);
3093     WINAPI_CONSTANT(F_DWORD, SEC_IMAGE);
3094     WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES);
3095     WINAPI_CONSTANT(F_DWORD, SEC_NOCACHE);
3096     WINAPI_CONSTANT(F_DWORD, SEC_RESERVE);
3097     WINAPI_CONSTANT(F_DWORD, SEC_WRITECOMBINE);
3098     WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
3099     WINAPI_CONSTANT(F_DWORD, STARTF_USESIZE);
3100     WINAPI_CONSTANT(F_DWORD, STARTF_USEPOSITION);
3101     WINAPI_CONSTANT(F_DWORD, STARTF_USECOUNTCHARS);
3102     WINAPI_CONSTANT(F_DWORD, STARTF_USEFILLATTRIBUTE);
3103     WINAPI_CONSTANT(F_DWORD, STARTF_RUNFULLSCREEN);
3104     WINAPI_CONSTANT(F_DWORD, STARTF_FORCEONFEEDBACK);
3105     WINAPI_CONSTANT(F_DWORD, STARTF_FORCEOFFFEEDBACK);
3106     WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
3107     WINAPI_CONSTANT(F_DWORD, STARTF_USEHOTKEY);
3108     WINAPI_CONSTANT(F_DWORD, STARTF_TITLEISLINKNAME);
3109     WINAPI_CONSTANT(F_DWORD, STARTF_TITLEISAPPID);
3110     WINAPI_CONSTANT(F_DWORD, STARTF_PREVENTPINNING);
3111     WINAPI_CONSTANT(F_DWORD, STARTF_UNTRUSTEDSOURCE);
3112     WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
3113     WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
3114     WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
3115     WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
3116     WINAPI_CONSTANT(F_DWORD, SW_HIDE);
3117     WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
3118     WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
3119     WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
3120 
3121     WINAPI_CONSTANT(F_DWORD, ABOVE_NORMAL_PRIORITY_CLASS);
3122     WINAPI_CONSTANT(F_DWORD, BELOW_NORMAL_PRIORITY_CLASS);
3123     WINAPI_CONSTANT(F_DWORD, HIGH_PRIORITY_CLASS);
3124     WINAPI_CONSTANT(F_DWORD, IDLE_PRIORITY_CLASS);
3125     WINAPI_CONSTANT(F_DWORD, NORMAL_PRIORITY_CLASS);
3126     WINAPI_CONSTANT(F_DWORD, REALTIME_PRIORITY_CLASS);
3127 
3128     WINAPI_CONSTANT(F_DWORD, CREATE_NO_WINDOW);
3129     WINAPI_CONSTANT(F_DWORD, DETACHED_PROCESS);
3130     WINAPI_CONSTANT(F_DWORD, CREATE_DEFAULT_ERROR_MODE);
3131     WINAPI_CONSTANT(F_DWORD, CREATE_BREAKAWAY_FROM_JOB);
3132 
3133     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_UNKNOWN);
3134     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_DISK);
3135     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_CHAR);
3136     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_PIPE);
3137     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_REMOTE);
3138 
3139     WINAPI_CONSTANT("u", LOCALE_NAME_INVARIANT);
3140     WINAPI_CONSTANT(F_DWORD, LOCALE_NAME_MAX_LENGTH);
3141     WINAPI_CONSTANT("u", LOCALE_NAME_SYSTEM_DEFAULT);
3142     WINAPI_CONSTANT("u", LOCALE_NAME_USER_DEFAULT);
3143 
3144     WINAPI_CONSTANT(F_DWORD, LCMAP_FULLWIDTH);
3145     WINAPI_CONSTANT(F_DWORD, LCMAP_HALFWIDTH);
3146     WINAPI_CONSTANT(F_DWORD, LCMAP_HIRAGANA);
3147     WINAPI_CONSTANT(F_DWORD, LCMAP_KATAKANA);
3148     WINAPI_CONSTANT(F_DWORD, LCMAP_LINGUISTIC_CASING);
3149     WINAPI_CONSTANT(F_DWORD, LCMAP_LOWERCASE);
3150     WINAPI_CONSTANT(F_DWORD, LCMAP_SIMPLIFIED_CHINESE);
3151     WINAPI_CONSTANT(F_DWORD, LCMAP_TITLECASE);
3152     WINAPI_CONSTANT(F_DWORD, LCMAP_TRADITIONAL_CHINESE);
3153     WINAPI_CONSTANT(F_DWORD, LCMAP_UPPERCASE);
3154 
3155     WINAPI_CONSTANT(F_DWORD, COPY_FILE_ALLOW_DECRYPTED_DESTINATION);
3156     WINAPI_CONSTANT(F_DWORD, COPY_FILE_COPY_SYMLINK);
3157     WINAPI_CONSTANT(F_DWORD, COPY_FILE_FAIL_IF_EXISTS);
3158     WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_BUFFERING);
3159     WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_OFFLOAD);
3160     WINAPI_CONSTANT(F_DWORD, COPY_FILE_OPEN_SOURCE_FOR_WRITE);
3161     WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESTARTABLE);
3162     WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_SECURITY_PRIVILEGES);
3163     WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESUME_FROM_PAUSE);
3164 #ifndef COPY_FILE_REQUEST_COMPRESSED_TRAFFIC
3165     // Only defined in newer WinSDKs
3166     #define COPY_FILE_REQUEST_COMPRESSED_TRAFFIC 0x10000000
3167 #endif
3168     WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_COMPRESSED_TRAFFIC);
3169 
3170     WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_STARTED);
3171     WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_FINISHED);
3172     WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_STARTED);
3173     WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_FINISHED);
3174     WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_POLL_CONTINUE);
3175     WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_ERROR);
3176 
3177     WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CONTINUE);
3178     WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CANCEL);
3179     WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_STOP);
3180     WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_QUIET);
3181     WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_PAUSE);
3182 
3183     WINAPI_CONSTANT("i", NULL);
3184 
3185     return 0;
3186 }
3187 
3188 static PyModuleDef_Slot winapi_slots[] = {
3189     {Py_mod_exec, winapi_exec},
3190     {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
3191     {Py_mod_gil, Py_MOD_GIL_NOT_USED},
3192     {0, NULL}
3193 };
3194 
3195 static int
winapi_traverse(PyObject * module,visitproc visit,void * arg)3196 winapi_traverse(PyObject *module, visitproc visit, void *arg)
3197 {
3198     WinApiState *st = winapi_get_state(module);
3199     Py_VISIT(st->overlapped_type);
3200     return 0;
3201 }
3202 
3203 static int
winapi_clear(PyObject * module)3204 winapi_clear(PyObject *module)
3205 {
3206     WinApiState *st = winapi_get_state(module);
3207     Py_CLEAR(st->overlapped_type);
3208     return 0;
3209 }
3210 
3211 static void
winapi_free(void * module)3212 winapi_free(void *module)
3213 {
3214     winapi_clear((PyObject *)module);
3215 }
3216 
3217 static struct PyModuleDef winapi_module = {
3218     PyModuleDef_HEAD_INIT,
3219     .m_name = "_winapi",
3220     .m_size = sizeof(WinApiState),
3221     .m_methods = winapi_functions,
3222     .m_slots = winapi_slots,
3223     .m_traverse = winapi_traverse,
3224     .m_clear = winapi_clear,
3225     .m_free = winapi_free,
3226 };
3227 
3228 PyMODINIT_FUNC
PyInit__winapi(void)3229 PyInit__winapi(void)
3230 {
3231     return PyModuleDef_Init(&winapi_module);
3232 }
3233