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 ®Type, (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