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