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
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*
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
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
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 *
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 *
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 *
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 *
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 *
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 *
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
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
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 *
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
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 *
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
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
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 *
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
809 if (envsize == 0) {
810 // A environment block must be terminated by two null characters --
811 // one for the last string and one for the block.
812 buffer = PyMem_Calloc(2, sizeof(wchar_t));
813 if (!buffer) {
814 PyErr_NoMemory();
815 }
816 goto cleanup;
817 }
818
819 if (PyList_GET_SIZE(values) != envsize) {
820 PyErr_SetString(PyExc_RuntimeError,
821 "environment changed size during iteration");
822 goto error;
823 }
824
825 totalsize = 1; /* trailing null character */
826 for (i = 0; i < envsize; i++) {
827 PyObject* key = PyList_GET_ITEM(keys, i);
828 PyObject* value = PyList_GET_ITEM(values, i);
829 Py_ssize_t size;
830
831 if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
832 PyErr_SetString(PyExc_TypeError,
833 "environment can only contain strings");
834 goto error;
835 }
836 if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
837 PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
838 {
839 PyErr_SetString(PyExc_ValueError, "embedded null character");
840 goto error;
841 }
842 /* Search from index 1 because on Windows starting '=' is allowed for
843 defining hidden environment variables. */
844 if (PyUnicode_GET_LENGTH(key) == 0 ||
845 PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
846 {
847 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
848 goto error;
849 }
850
851 size = PyUnicode_AsWideChar(key, NULL, 0);
852 assert(size > 1);
853 if (totalsize > PY_SSIZE_T_MAX - size) {
854 PyErr_SetString(PyExc_OverflowError, "environment too long");
855 goto error;
856 }
857 totalsize += size; /* including '=' */
858
859 size = PyUnicode_AsWideChar(value, NULL, 0);
860 assert(size > 0);
861 if (totalsize > PY_SSIZE_T_MAX - size) {
862 PyErr_SetString(PyExc_OverflowError, "environment too long");
863 goto error;
864 }
865 totalsize += size; /* including trailing '\0' */
866 }
867
868 buffer = PyMem_NEW(wchar_t, totalsize);
869 if (! buffer) {
870 PyErr_NoMemory();
871 goto error;
872 }
873 p = buffer;
874 end = buffer + totalsize;
875
876 for (i = 0; i < envsize; i++) {
877 PyObject* key = PyList_GET_ITEM(keys, i);
878 PyObject* value = PyList_GET_ITEM(values, i);
879 Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
880 assert(1 <= size && size < end - p);
881 p += size;
882 *p++ = L'=';
883 size = PyUnicode_AsWideChar(value, p, end - p);
884 assert(0 <= size && size < end - p);
885 p += size + 1;
886 }
887
888 /* add trailing null character */
889 *p++ = L'\0';
890 assert(p == end);
891
892 cleanup:
893 error:
894 Py_XDECREF(keys);
895 Py_XDECREF(values);
896 return buffer;
897 }
898
899 static LPHANDLE
900 gethandlelist(PyObject *mapping, const char *name, Py_ssize_t *size)
901 {
902 LPHANDLE ret = NULL;
903 PyObject *value_fast = NULL;
904 PyObject *value;
905 Py_ssize_t i;
906
907 value = PyMapping_GetItemString(mapping, name);
908 if (!value) {
909 PyErr_Clear();
910 return NULL;
911 }
912
913 if (value == Py_None) {
914 goto cleanup;
915 }
916
917 value_fast = PySequence_Fast(value, "handle_list must be a sequence or None");
918 if (value_fast == NULL)
919 goto cleanup;
920
921 *size = PySequence_Fast_GET_SIZE(value_fast) * sizeof(HANDLE);
922
923 /* Passing an empty array causes CreateProcess to fail so just don't set it */
924 if (*size == 0) {
925 goto cleanup;
926 }
927
928 ret = PyMem_Malloc(*size);
929 if (ret == NULL)
930 goto cleanup;
931
932 for (i = 0; i < PySequence_Fast_GET_SIZE(value_fast); i++) {
933 ret[i] = PYNUM_TO_HANDLE(PySequence_Fast_GET_ITEM(value_fast, i));
934 if (ret[i] == (HANDLE)-1 && PyErr_Occurred()) {
935 PyMem_Free(ret);
936 ret = NULL;
937 goto cleanup;
938 }
939 }
940
941 cleanup:
942 Py_DECREF(value);
943 Py_XDECREF(value_fast);
944 return ret;
945 }
946
947 typedef struct {
948 LPPROC_THREAD_ATTRIBUTE_LIST attribute_list;
949 LPHANDLE handle_list;
950 } AttributeList;
951
952 static void
953 freeattributelist(AttributeList *attribute_list)
954 {
955 if (attribute_list->attribute_list != NULL) {
956 DeleteProcThreadAttributeList(attribute_list->attribute_list);
957 PyMem_Free(attribute_list->attribute_list);
958 }
959
960 PyMem_Free(attribute_list->handle_list);
961
962 memset(attribute_list, 0, sizeof(*attribute_list));
963 }
964
965 static int
966 getattributelist(PyObject *obj, const char *name, AttributeList *attribute_list)
967 {
968 int ret = 0;
969 DWORD err;
970 BOOL result;
971 PyObject *value;
972 Py_ssize_t handle_list_size;
973 DWORD attribute_count = 0;
974 SIZE_T attribute_list_size = 0;
975
976 value = PyObject_GetAttrString(obj, name);
977 if (!value) {
978 PyErr_Clear(); /* FIXME: propagate error? */
979 return 0;
980 }
981
982 if (value == Py_None) {
983 ret = 0;
984 goto cleanup;
985 }
986
987 if (!PyMapping_Check(value)) {
988 ret = -1;
989 PyErr_Format(PyExc_TypeError, "%s must be a mapping or None", name);
990 goto cleanup;
991 }
992
993 attribute_list->handle_list = gethandlelist(value, "handle_list", &handle_list_size);
994 if (attribute_list->handle_list == NULL && PyErr_Occurred()) {
995 ret = -1;
996 goto cleanup;
997 }
998
999 if (attribute_list->handle_list != NULL)
1000 ++attribute_count;
1001
1002 /* Get how many bytes we need for the attribute list */
1003 result = InitializeProcThreadAttributeList(NULL, attribute_count, 0, &attribute_list_size);
1004 if (result || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1005 ret = -1;
1006 PyErr_SetFromWindowsErr(GetLastError());
1007 goto cleanup;
1008 }
1009
1010 attribute_list->attribute_list = PyMem_Malloc(attribute_list_size);
1011 if (attribute_list->attribute_list == NULL) {
1012 ret = -1;
1013 goto cleanup;
1014 }
1015
1016 result = InitializeProcThreadAttributeList(
1017 attribute_list->attribute_list,
1018 attribute_count,
1019 0,
1020 &attribute_list_size);
1021 if (!result) {
1022 err = GetLastError();
1023
1024 /* So that we won't call DeleteProcThreadAttributeList */
1025 PyMem_Free(attribute_list->attribute_list);
1026 attribute_list->attribute_list = NULL;
1027
1028 ret = -1;
1029 PyErr_SetFromWindowsErr(err);
1030 goto cleanup;
1031 }
1032
1033 if (attribute_list->handle_list != NULL) {
1034 result = UpdateProcThreadAttribute(
1035 attribute_list->attribute_list,
1036 0,
1037 PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1038 attribute_list->handle_list,
1039 handle_list_size,
1040 NULL,
1041 NULL);
1042 if (!result) {
1043 ret = -1;
1044 PyErr_SetFromWindowsErr(GetLastError());
1045 goto cleanup;
1046 }
1047 }
1048
1049 cleanup:
1050 Py_DECREF(value);
1051
1052 if (ret < 0)
1053 freeattributelist(attribute_list);
1054
1055 return ret;
1056 }
1057
1058 /*[clinic input]
1059 _winapi.CreateProcess
1060
1061 application_name: Py_UNICODE(accept={str, NoneType})
1062 command_line: object
1063 Can be str or None
1064 proc_attrs: object
1065 Ignored internally, can be None.
1066 thread_attrs: object
1067 Ignored internally, can be None.
1068 inherit_handles: BOOL
1069 creation_flags: DWORD
1070 env_mapping: object
1071 current_directory: Py_UNICODE(accept={str, NoneType})
1072 startup_info: object
1073 /
1074
1075 Create a new process and its primary thread.
1076
1077 The return value is a tuple of the process handle, thread handle,
1078 process ID, and thread ID.
1079 [clinic start generated code]*/
1080
1081 static PyObject *
1082 _winapi_CreateProcess_impl(PyObject *module,
1083 const Py_UNICODE *application_name,
1084 PyObject *command_line, PyObject *proc_attrs,
1085 PyObject *thread_attrs, BOOL inherit_handles,
1086 DWORD creation_flags, PyObject *env_mapping,
1087 const Py_UNICODE *current_directory,
1088 PyObject *startup_info)
1089 /*[clinic end generated code: output=9b2423a609230132 input=42ac293eaea03fc4]*/
1090 {
1091 PyObject *ret = NULL;
1092 BOOL result;
1093 PROCESS_INFORMATION pi;
1094 STARTUPINFOEXW si;
1095 wchar_t *wenvironment = NULL;
1096 wchar_t *command_line_copy = NULL;
1097 AttributeList attribute_list = {0};
1098
1099 if (PySys_Audit("_winapi.CreateProcess", "uuu", application_name,
1100 command_line, current_directory) < 0) {
1101 return NULL;
1102 }
1103
1104 PyInterpreterState *interp = PyInterpreterState_Get();
1105 const PyConfig *config = _PyInterpreterState_GetConfig(interp);
1106 if (config->_isolated_interpreter) {
1107 PyErr_SetString(PyExc_RuntimeError,
1108 "subprocess not supported for isolated subinterpreters");
1109 return NULL;
1110 }
1111
1112 ZeroMemory(&si, sizeof(si));
1113 si.StartupInfo.cb = sizeof(si);
1114
1115 /* note: we only support a small subset of all SI attributes */
1116 si.StartupInfo.dwFlags = getulong(startup_info, "dwFlags");
1117 si.StartupInfo.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
1118 si.StartupInfo.hStdInput = gethandle(startup_info, "hStdInput");
1119 si.StartupInfo.hStdOutput = gethandle(startup_info, "hStdOutput");
1120 si.StartupInfo.hStdError = gethandle(startup_info, "hStdError");
1121 if (PyErr_Occurred())
1122 goto cleanup;
1123
1124 if (env_mapping != Py_None) {
1125 wenvironment = getenvironment(env_mapping);
1126 if (wenvironment == NULL) {
1127 goto cleanup;
1128 }
1129 }
1130
1131 if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
1132 goto cleanup;
1133
1134 si.lpAttributeList = attribute_list.attribute_list;
1135 if (PyUnicode_Check(command_line)) {
1136 command_line_copy = PyUnicode_AsWideCharString(command_line, NULL);
1137 if (command_line_copy == NULL) {
1138 goto cleanup;
1139 }
1140 }
1141 else if (command_line != Py_None) {
1142 PyErr_Format(PyExc_TypeError,
1143 "CreateProcess() argument 2 must be str or None, not %s",
1144 Py_TYPE(command_line)->tp_name);
1145 goto cleanup;
1146 }
1147
1148
1149 Py_BEGIN_ALLOW_THREADS
1150 result = CreateProcessW(application_name,
1151 command_line_copy,
1152 NULL,
1153 NULL,
1154 inherit_handles,
1155 creation_flags | EXTENDED_STARTUPINFO_PRESENT |
1156 CREATE_UNICODE_ENVIRONMENT,
1157 wenvironment,
1158 current_directory,
1159 (LPSTARTUPINFOW)&si,
1160 &pi);
1161 Py_END_ALLOW_THREADS
1162
1163 if (!result) {
1164 PyErr_SetFromWindowsErr(GetLastError());
1165 goto cleanup;
1166 }
1167
1168 ret = Py_BuildValue("NNkk",
1169 HANDLE_TO_PYNUM(pi.hProcess),
1170 HANDLE_TO_PYNUM(pi.hThread),
1171 pi.dwProcessId,
1172 pi.dwThreadId);
1173
1174 cleanup:
1175 PyMem_Free(command_line_copy);
1176 PyMem_Free(wenvironment);
1177 freeattributelist(&attribute_list);
1178
1179 return ret;
1180 }
1181
1182 /*[clinic input]
1183 _winapi.DuplicateHandle -> HANDLE
1184
1185 source_process_handle: HANDLE
1186 source_handle: HANDLE
1187 target_process_handle: HANDLE
1188 desired_access: DWORD
1189 inherit_handle: BOOL
1190 options: DWORD = 0
1191 /
1192
1193 Return a duplicate handle object.
1194
1195 The duplicate handle refers to the same object as the original
1196 handle. Therefore, any changes to the object are reflected
1197 through both handles.
1198 [clinic start generated code]*/
1199
1200 static HANDLE
1201 _winapi_DuplicateHandle_impl(PyObject *module, HANDLE source_process_handle,
1202 HANDLE source_handle,
1203 HANDLE target_process_handle,
1204 DWORD desired_access, BOOL inherit_handle,
1205 DWORD options)
1206 /*[clinic end generated code: output=ad9711397b5dcd4e input=b933e3f2356a8c12]*/
1207 {
1208 HANDLE target_handle;
1209 BOOL result;
1210
1211 Py_BEGIN_ALLOW_THREADS
1212 result = DuplicateHandle(
1213 source_process_handle,
1214 source_handle,
1215 target_process_handle,
1216 &target_handle,
1217 desired_access,
1218 inherit_handle,
1219 options
1220 );
1221 Py_END_ALLOW_THREADS
1222
1223 if (! result) {
1224 PyErr_SetFromWindowsErr(GetLastError());
1225 return INVALID_HANDLE_VALUE;
1226 }
1227
1228 return target_handle;
1229 }
1230
1231 /*[clinic input]
1232 _winapi.ExitProcess
1233
1234 ExitCode: UINT
1235 /
1236
1237 [clinic start generated code]*/
1238
1239 static PyObject *
1240 _winapi_ExitProcess_impl(PyObject *module, UINT ExitCode)
1241 /*[clinic end generated code: output=a387deb651175301 input=4f05466a9406c558]*/
1242 {
1243 #if defined(Py_DEBUG)
1244 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
1245 SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
1246 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
1247 #endif
1248
1249 ExitProcess(ExitCode);
1250
1251 return NULL;
1252 }
1253
1254 /*[clinic input]
1255 _winapi.GetCurrentProcess -> HANDLE
1256
1257 Return a handle object for the current process.
1258 [clinic start generated code]*/
1259
1260 static HANDLE
1261 _winapi_GetCurrentProcess_impl(PyObject *module)
1262 /*[clinic end generated code: output=ddeb4dd2ffadf344 input=b213403fd4b96b41]*/
1263 {
1264 return GetCurrentProcess();
1265 }
1266
1267 /*[clinic input]
1268 _winapi.GetExitCodeProcess -> DWORD
1269
1270 process: HANDLE
1271 /
1272
1273 Return the termination status of the specified process.
1274 [clinic start generated code]*/
1275
1276 static DWORD
1277 _winapi_GetExitCodeProcess_impl(PyObject *module, HANDLE process)
1278 /*[clinic end generated code: output=b4620bdf2bccf36b input=61b6bfc7dc2ee374]*/
1279 {
1280 DWORD exit_code;
1281 BOOL result;
1282
1283 result = GetExitCodeProcess(process, &exit_code);
1284
1285 if (! result) {
1286 PyErr_SetFromWindowsErr(GetLastError());
1287 exit_code = PY_DWORD_MAX;
1288 }
1289
1290 return exit_code;
1291 }
1292
1293 /*[clinic input]
1294 _winapi.GetLastError -> DWORD
1295 [clinic start generated code]*/
1296
1297 static DWORD
1298 _winapi_GetLastError_impl(PyObject *module)
1299 /*[clinic end generated code: output=8585b827cb1a92c5 input=62d47fb9bce038ba]*/
1300 {
1301 return GetLastError();
1302 }
1303
1304 /*[clinic input]
1305 _winapi.GetModuleFileName
1306
1307 module_handle: HMODULE
1308 /
1309
1310 Return the fully-qualified path for the file that contains module.
1311
1312 The module must have been loaded by the current process.
1313
1314 The module parameter should be a handle to the loaded module
1315 whose path is being requested. If this parameter is 0,
1316 GetModuleFileName retrieves the path of the executable file
1317 of the current process.
1318 [clinic start generated code]*/
1319
1320 static PyObject *
1321 _winapi_GetModuleFileName_impl(PyObject *module, HMODULE module_handle)
1322 /*[clinic end generated code: output=85b4b728c5160306 input=6d66ff7deca5d11f]*/
1323 {
1324 BOOL result;
1325 WCHAR filename[MAX_PATH];
1326
1327 Py_BEGIN_ALLOW_THREADS
1328 result = GetModuleFileNameW(module_handle, filename, MAX_PATH);
1329 filename[MAX_PATH-1] = '\0';
1330 Py_END_ALLOW_THREADS
1331
1332 if (! result)
1333 return PyErr_SetFromWindowsErr(GetLastError());
1334
1335 return PyUnicode_FromWideChar(filename, wcslen(filename));
1336 }
1337
1338 /*[clinic input]
1339 _winapi.GetStdHandle -> HANDLE
1340
1341 std_handle: DWORD
1342 One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE.
1343 /
1344
1345 Return a handle to the specified standard device.
1346
1347 The integer associated with the handle object is returned.
1348 [clinic start generated code]*/
1349
1350 static HANDLE
1351 _winapi_GetStdHandle_impl(PyObject *module, DWORD std_handle)
1352 /*[clinic end generated code: output=0e613001e73ab614 input=07016b06a2fc8826]*/
1353 {
1354 HANDLE handle;
1355
1356 Py_BEGIN_ALLOW_THREADS
1357 handle = GetStdHandle(std_handle);
1358 Py_END_ALLOW_THREADS
1359
1360 if (handle == INVALID_HANDLE_VALUE)
1361 PyErr_SetFromWindowsErr(GetLastError());
1362
1363 return handle;
1364 }
1365
1366 /*[clinic input]
1367 _winapi.GetVersion -> long
1368
1369 Return the version number of the current operating system.
1370 [clinic start generated code]*/
1371
1372 static long
1373 _winapi_GetVersion_impl(PyObject *module)
1374 /*[clinic end generated code: output=e41f0db5a3b82682 input=e21dff8d0baeded2]*/
1375 /* Disable deprecation warnings about GetVersionEx as the result is
1376 being passed straight through to the caller, who is responsible for
1377 using it correctly. */
1378 #pragma warning(push)
1379 #pragma warning(disable:4996)
1380
1381 {
1382 return GetVersion();
1383 }
1384
1385 #pragma warning(pop)
1386
1387 /*[clinic input]
1388 _winapi.MapViewOfFile -> LPVOID
1389
1390 file_map: HANDLE
1391 desired_access: DWORD
1392 file_offset_high: DWORD
1393 file_offset_low: DWORD
1394 number_bytes: size_t
1395 /
1396 [clinic start generated code]*/
1397
1398 static LPVOID
1399 _winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map,
1400 DWORD desired_access, DWORD file_offset_high,
1401 DWORD file_offset_low, size_t number_bytes)
1402 /*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/
1403 {
1404 LPVOID address;
1405
1406 Py_BEGIN_ALLOW_THREADS
1407 address = MapViewOfFile(file_map, desired_access, file_offset_high,
1408 file_offset_low, number_bytes);
1409 Py_END_ALLOW_THREADS
1410
1411 if (address == NULL)
1412 PyErr_SetFromWindowsErr(0);
1413
1414 return address;
1415 }
1416
1417 /*[clinic input]
1418 _winapi.UnmapViewOfFile
1419
1420 address: LPCVOID
1421 /
1422 [clinic start generated code]*/
1423
1424 static PyObject *
1425 _winapi_UnmapViewOfFile_impl(PyObject *module, LPCVOID address)
1426 /*[clinic end generated code: output=4f7e18ac75d19744 input=8c4b6119ad9288a3]*/
1427 {
1428 BOOL success;
1429
1430 Py_BEGIN_ALLOW_THREADS
1431 success = UnmapViewOfFile(address);
1432 Py_END_ALLOW_THREADS
1433
1434 if (!success) {
1435 return PyErr_SetFromWindowsErr(0);
1436 }
1437
1438 Py_RETURN_NONE;
1439 }
1440
1441 /*[clinic input]
1442 _winapi.OpenFileMapping -> HANDLE
1443
1444 desired_access: DWORD
1445 inherit_handle: BOOL
1446 name: LPCWSTR
1447 /
1448 [clinic start generated code]*/
1449
1450 static HANDLE
1451 _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access,
1452 BOOL inherit_handle, LPCWSTR name)
1453 /*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/
1454 {
1455 HANDLE handle;
1456
1457 Py_BEGIN_ALLOW_THREADS
1458 handle = OpenFileMappingW(desired_access, inherit_handle, name);
1459 Py_END_ALLOW_THREADS
1460
1461 if (handle == NULL) {
1462 PyObject *temp = PyUnicode_FromWideChar(name, -1);
1463 PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
1464 Py_XDECREF(temp);
1465 handle = INVALID_HANDLE_VALUE;
1466 }
1467
1468 return handle;
1469 }
1470
1471 /*[clinic input]
1472 _winapi.OpenProcess -> HANDLE
1473
1474 desired_access: DWORD
1475 inherit_handle: BOOL
1476 process_id: DWORD
1477 /
1478 [clinic start generated code]*/
1479
1480 static HANDLE
1481 _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access,
1482 BOOL inherit_handle, DWORD process_id)
1483 /*[clinic end generated code: output=b42b6b81ea5a0fc3 input=ec98c4cf4ea2ec36]*/
1484 {
1485 HANDLE handle;
1486
1487 if (PySys_Audit("_winapi.OpenProcess", "II",
1488 process_id, desired_access) < 0) {
1489 return INVALID_HANDLE_VALUE;
1490 }
1491
1492 Py_BEGIN_ALLOW_THREADS
1493 handle = OpenProcess(desired_access, inherit_handle, process_id);
1494 Py_END_ALLOW_THREADS
1495 if (handle == NULL) {
1496 PyErr_SetFromWindowsErr(GetLastError());
1497 handle = INVALID_HANDLE_VALUE;
1498 }
1499
1500 return handle;
1501 }
1502
1503 /*[clinic input]
1504 _winapi.PeekNamedPipe
1505
1506 handle: HANDLE
1507 size: int = 0
1508 /
1509 [clinic start generated code]*/
1510
1511 static PyObject *
1512 _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
1513 /*[clinic end generated code: output=d0c3e29e49d323dd input=c7aa53bfbce69d70]*/
1514 {
1515 PyObject *buf = NULL;
1516 DWORD nread, navail, nleft;
1517 BOOL ret;
1518
1519 if (size < 0) {
1520 PyErr_SetString(PyExc_ValueError, "negative size");
1521 return NULL;
1522 }
1523
1524 if (size) {
1525 buf = PyBytes_FromStringAndSize(NULL, size);
1526 if (!buf)
1527 return NULL;
1528 Py_BEGIN_ALLOW_THREADS
1529 ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1530 &navail, &nleft);
1531 Py_END_ALLOW_THREADS
1532 if (!ret) {
1533 Py_DECREF(buf);
1534 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1535 }
1536 if (_PyBytes_Resize(&buf, nread))
1537 return NULL;
1538 return Py_BuildValue("NII", buf, navail, nleft);
1539 }
1540 else {
1541 Py_BEGIN_ALLOW_THREADS
1542 ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1543 Py_END_ALLOW_THREADS
1544 if (!ret) {
1545 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1546 }
1547 return Py_BuildValue("II", navail, nleft);
1548 }
1549 }
1550
1551 /*[clinic input]
1552 _winapi.LCMapStringEx
1553
1554 locale: unicode
1555 flags: DWORD
1556 src: unicode
1557
1558 [clinic start generated code]*/
1559
1560 static PyObject *
1561 _winapi_LCMapStringEx_impl(PyObject *module, PyObject *locale, DWORD flags,
1562 PyObject *src)
1563 /*[clinic end generated code: output=8ea4c9d85a4a1f23 input=2fa6ebc92591731b]*/
1564 {
1565 if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV |
1566 LCMAP_SORTKEY)) {
1567 return PyErr_Format(PyExc_ValueError, "unsupported flags");
1568 }
1569
1570 wchar_t *locale_ = PyUnicode_AsWideCharString(locale, NULL);
1571 if (!locale_) {
1572 return NULL;
1573 }
1574 Py_ssize_t src_size;
1575 wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size);
1576 if (!src_) {
1577 PyMem_Free(locale_);
1578 return NULL;
1579 }
1580 if (src_size > INT_MAX) {
1581 PyMem_Free(locale_);
1582 PyMem_Free(src_);
1583 PyErr_SetString(PyExc_OverflowError, "input string is too long");
1584 return NULL;
1585 }
1586
1587 int dest_size = LCMapStringEx(locale_, flags, src_, (int)src_size, NULL, 0,
1588 NULL, NULL, 0);
1589 if (dest_size <= 0) {
1590 DWORD error = GetLastError();
1591 PyMem_Free(locale_);
1592 PyMem_Free(src_);
1593 return PyErr_SetFromWindowsErr(error);
1594 }
1595
1596 wchar_t* dest = PyMem_NEW(wchar_t, dest_size);
1597 if (dest == NULL) {
1598 PyMem_Free(locale_);
1599 PyMem_Free(src_);
1600 return PyErr_NoMemory();
1601 }
1602
1603 int nmapped = LCMapStringEx(locale_, flags, src_, (int)src_size, dest, dest_size,
1604 NULL, NULL, 0);
1605 if (nmapped <= 0) {
1606 DWORD error = GetLastError();
1607 PyMem_Free(locale_);
1608 PyMem_Free(src_);
1609 PyMem_DEL(dest);
1610 return PyErr_SetFromWindowsErr(error);
1611 }
1612
1613 PyMem_Free(locale_);
1614 PyMem_Free(src_);
1615 PyObject *ret = PyUnicode_FromWideChar(dest, nmapped);
1616 PyMem_DEL(dest);
1617
1618 return ret;
1619 }
1620
1621 /*[clinic input]
1622 _winapi.ReadFile
1623
1624 handle: HANDLE
1625 size: DWORD
1626 overlapped as use_overlapped: bool(accept={int}) = False
1627 [clinic start generated code]*/
1628
1629 static PyObject *
1630 _winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
1631 int use_overlapped)
1632 /*[clinic end generated code: output=d3d5b44a8201b944 input=08c439d03a11aac5]*/
1633 {
1634 DWORD nread;
1635 PyObject *buf;
1636 BOOL ret;
1637 DWORD err;
1638 OverlappedObject *overlapped = NULL;
1639
1640 buf = PyBytes_FromStringAndSize(NULL, size);
1641 if (!buf)
1642 return NULL;
1643 if (use_overlapped) {
1644 overlapped = new_overlapped(module, handle);
1645 if (!overlapped) {
1646 Py_DECREF(buf);
1647 return NULL;
1648 }
1649 /* Steals reference to buf */
1650 overlapped->read_buffer = buf;
1651 }
1652
1653 Py_BEGIN_ALLOW_THREADS
1654 ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
1655 overlapped ? &overlapped->overlapped : NULL);
1656 Py_END_ALLOW_THREADS
1657
1658 err = ret ? 0 : GetLastError();
1659
1660 if (overlapped) {
1661 if (!ret) {
1662 if (err == ERROR_IO_PENDING)
1663 overlapped->pending = 1;
1664 else if (err != ERROR_MORE_DATA) {
1665 Py_DECREF(overlapped);
1666 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1667 }
1668 }
1669 return Py_BuildValue("NI", (PyObject *) overlapped, err);
1670 }
1671
1672 if (!ret && err != ERROR_MORE_DATA) {
1673 Py_DECREF(buf);
1674 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1675 }
1676 if (_PyBytes_Resize(&buf, nread))
1677 return NULL;
1678 return Py_BuildValue("NI", buf, err);
1679 }
1680
1681 /*[clinic input]
1682 _winapi.SetNamedPipeHandleState
1683
1684 named_pipe: HANDLE
1685 mode: object
1686 max_collection_count: object
1687 collect_data_timeout: object
1688 /
1689 [clinic start generated code]*/
1690
1691 static PyObject *
1692 _winapi_SetNamedPipeHandleState_impl(PyObject *module, HANDLE named_pipe,
1693 PyObject *mode,
1694 PyObject *max_collection_count,
1695 PyObject *collect_data_timeout)
1696 /*[clinic end generated code: output=f2129d222cbfa095 input=9142d72163d0faa6]*/
1697 {
1698 PyObject *oArgs[3] = {mode, max_collection_count, collect_data_timeout};
1699 DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
1700 int i;
1701 BOOL b;
1702
1703 for (i = 0 ; i < 3 ; i++) {
1704 if (oArgs[i] != Py_None) {
1705 dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
1706 if (PyErr_Occurred())
1707 return NULL;
1708 pArgs[i] = &dwArgs[i];
1709 }
1710 }
1711
1712 Py_BEGIN_ALLOW_THREADS
1713 b = SetNamedPipeHandleState(named_pipe, pArgs[0], pArgs[1], pArgs[2]);
1714 Py_END_ALLOW_THREADS
1715
1716 if (!b)
1717 return PyErr_SetFromWindowsErr(0);
1718
1719 Py_RETURN_NONE;
1720 }
1721
1722
1723 /*[clinic input]
1724 _winapi.TerminateProcess
1725
1726 handle: HANDLE
1727 exit_code: UINT
1728 /
1729
1730 Terminate the specified process and all of its threads.
1731 [clinic start generated code]*/
1732
1733 static PyObject *
1734 _winapi_TerminateProcess_impl(PyObject *module, HANDLE handle,
1735 UINT exit_code)
1736 /*[clinic end generated code: output=f4e99ac3f0b1f34a input=d6bc0aa1ee3bb4df]*/
1737 {
1738 BOOL result;
1739
1740 if (PySys_Audit("_winapi.TerminateProcess", "nI",
1741 (Py_ssize_t)handle, exit_code) < 0) {
1742 return NULL;
1743 }
1744
1745 result = TerminateProcess(handle, exit_code);
1746
1747 if (! result)
1748 return PyErr_SetFromWindowsErr(GetLastError());
1749
1750 Py_RETURN_NONE;
1751 }
1752
1753 /*[clinic input]
1754 _winapi.VirtualQuerySize -> size_t
1755
1756 address: LPCVOID
1757 /
1758 [clinic start generated code]*/
1759
1760 static size_t
1761 _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address)
1762 /*[clinic end generated code: output=40c8e0ff5ec964df input=6b784a69755d0bb6]*/
1763 {
1764 SIZE_T size_of_buf;
1765 MEMORY_BASIC_INFORMATION mem_basic_info;
1766 SIZE_T region_size;
1767
1768 Py_BEGIN_ALLOW_THREADS
1769 size_of_buf = VirtualQuery(address, &mem_basic_info, sizeof(mem_basic_info));
1770 Py_END_ALLOW_THREADS
1771
1772 if (size_of_buf == 0)
1773 PyErr_SetFromWindowsErr(0);
1774
1775 region_size = mem_basic_info.RegionSize;
1776 return region_size;
1777 }
1778
1779 /*[clinic input]
1780 _winapi.WaitNamedPipe
1781
1782 name: LPCTSTR
1783 timeout: DWORD
1784 /
1785 [clinic start generated code]*/
1786
1787 static PyObject *
1788 _winapi_WaitNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD timeout)
1789 /*[clinic end generated code: output=c2866f4439b1fe38 input=36fc781291b1862c]*/
1790 {
1791 BOOL success;
1792
1793 Py_BEGIN_ALLOW_THREADS
1794 success = WaitNamedPipe(name, timeout);
1795 Py_END_ALLOW_THREADS
1796
1797 if (!success)
1798 return PyErr_SetFromWindowsErr(0);
1799
1800 Py_RETURN_NONE;
1801 }
1802
1803 /*[clinic input]
1804 _winapi.WaitForMultipleObjects
1805
1806 handle_seq: object
1807 wait_flag: BOOL
1808 milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
1809 /
1810 [clinic start generated code]*/
1811
1812 static PyObject *
1813 _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq,
1814 BOOL wait_flag, DWORD milliseconds)
1815 /*[clinic end generated code: output=295e3f00b8e45899 input=36f76ca057cd28a0]*/
1816 {
1817 DWORD result;
1818 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1819 HANDLE sigint_event = NULL;
1820 Py_ssize_t nhandles, i;
1821
1822 if (!PySequence_Check(handle_seq)) {
1823 PyErr_Format(PyExc_TypeError,
1824 "sequence type expected, got '%s'",
1825 Py_TYPE(handle_seq)->tp_name);
1826 return NULL;
1827 }
1828 nhandles = PySequence_Length(handle_seq);
1829 if (nhandles == -1)
1830 return NULL;
1831 if (nhandles < 0 || nhandles > MAXIMUM_WAIT_OBJECTS - 1) {
1832 PyErr_Format(PyExc_ValueError,
1833 "need at most %zd handles, got a sequence of length %zd",
1834 MAXIMUM_WAIT_OBJECTS - 1, nhandles);
1835 return NULL;
1836 }
1837 for (i = 0; i < nhandles; i++) {
1838 HANDLE h;
1839 PyObject *v = PySequence_GetItem(handle_seq, i);
1840 if (v == NULL)
1841 return NULL;
1842 if (!PyArg_Parse(v, F_HANDLE, &h)) {
1843 Py_DECREF(v);
1844 return NULL;
1845 }
1846 handles[i] = h;
1847 Py_DECREF(v);
1848 }
1849 /* If this is the main thread then make the wait interruptible
1850 by Ctrl-C unless we are waiting for *all* handles */
1851 if (!wait_flag && _PyOS_IsMainThread()) {
1852 sigint_event = _PyOS_SigintEvent();
1853 assert(sigint_event != NULL);
1854 handles[nhandles++] = sigint_event;
1855 }
1856
1857 Py_BEGIN_ALLOW_THREADS
1858 if (sigint_event != NULL)
1859 ResetEvent(sigint_event);
1860 result = WaitForMultipleObjects((DWORD) nhandles, handles,
1861 wait_flag, milliseconds);
1862 Py_END_ALLOW_THREADS
1863
1864 if (result == WAIT_FAILED)
1865 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1866 else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
1867 errno = EINTR;
1868 return PyErr_SetFromErrno(PyExc_OSError);
1869 }
1870
1871 return PyLong_FromLong((int) result);
1872 }
1873
1874 /*[clinic input]
1875 _winapi.WaitForSingleObject -> long
1876
1877 handle: HANDLE
1878 milliseconds: DWORD
1879 /
1880
1881 Wait for a single object.
1882
1883 Wait until the specified object is in the signaled state or
1884 the time-out interval elapses. The timeout value is specified
1885 in milliseconds.
1886 [clinic start generated code]*/
1887
1888 static long
1889 _winapi_WaitForSingleObject_impl(PyObject *module, HANDLE handle,
1890 DWORD milliseconds)
1891 /*[clinic end generated code: output=3c4715d8f1b39859 input=443d1ab076edc7b1]*/
1892 {
1893 DWORD result;
1894
1895 Py_BEGIN_ALLOW_THREADS
1896 result = WaitForSingleObject(handle, milliseconds);
1897 Py_END_ALLOW_THREADS
1898
1899 if (result == WAIT_FAILED) {
1900 PyErr_SetFromWindowsErr(GetLastError());
1901 return -1;
1902 }
1903
1904 return result;
1905 }
1906
1907 /*[clinic input]
1908 _winapi.WriteFile
1909
1910 handle: HANDLE
1911 buffer: object
1912 overlapped as use_overlapped: bool(accept={int}) = False
1913 [clinic start generated code]*/
1914
1915 static PyObject *
1916 _winapi_WriteFile_impl(PyObject *module, HANDLE handle, PyObject *buffer,
1917 int use_overlapped)
1918 /*[clinic end generated code: output=2ca80f6bf3fa92e3 input=11eae2a03aa32731]*/
1919 {
1920 Py_buffer _buf, *buf;
1921 DWORD len, written;
1922 BOOL ret;
1923 DWORD err;
1924 OverlappedObject *overlapped = NULL;
1925
1926 if (use_overlapped) {
1927 overlapped = new_overlapped(module, handle);
1928 if (!overlapped)
1929 return NULL;
1930 buf = &overlapped->write_buffer;
1931 }
1932 else
1933 buf = &_buf;
1934
1935 if (!PyArg_Parse(buffer, "y*", buf)) {
1936 Py_XDECREF(overlapped);
1937 return NULL;
1938 }
1939
1940 Py_BEGIN_ALLOW_THREADS
1941 len = (DWORD)Py_MIN(buf->len, PY_DWORD_MAX);
1942 ret = WriteFile(handle, buf->buf, len, &written,
1943 overlapped ? &overlapped->overlapped : NULL);
1944 Py_END_ALLOW_THREADS
1945
1946 err = ret ? 0 : GetLastError();
1947
1948 if (overlapped) {
1949 if (!ret) {
1950 if (err == ERROR_IO_PENDING)
1951 overlapped->pending = 1;
1952 else {
1953 Py_DECREF(overlapped);
1954 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1955 }
1956 }
1957 return Py_BuildValue("NI", (PyObject *) overlapped, err);
1958 }
1959
1960 PyBuffer_Release(buf);
1961 if (!ret)
1962 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1963 return Py_BuildValue("II", written, err);
1964 }
1965
1966 /*[clinic input]
1967 _winapi.GetACP
1968
1969 Get the current Windows ANSI code page identifier.
1970 [clinic start generated code]*/
1971
1972 static PyObject *
1973 _winapi_GetACP_impl(PyObject *module)
1974 /*[clinic end generated code: output=f7ee24bf705dbb88 input=1433c96d03a05229]*/
1975 {
1976 return PyLong_FromUnsignedLong(GetACP());
1977 }
1978
1979 /*[clinic input]
1980 _winapi.GetFileType -> DWORD
1981
1982 handle: HANDLE
1983 [clinic start generated code]*/
1984
1985 static DWORD
1986 _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
1987 /*[clinic end generated code: output=92b8466ac76ecc17 input=0058366bc40bbfbf]*/
1988 {
1989 DWORD result;
1990
1991 Py_BEGIN_ALLOW_THREADS
1992 result = GetFileType(handle);
1993 Py_END_ALLOW_THREADS
1994
1995 if (result == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) {
1996 PyErr_SetFromWindowsErr(0);
1997 return -1;
1998 }
1999
2000 return result;
2001 }
2002
2003 /*[clinic input]
2004 _winapi._mimetypes_read_windows_registry
2005
2006 on_type_read: object
2007
2008 Optimized function for reading all known MIME types from the registry.
2009
2010 *on_type_read* is a callable taking *type* and *ext* arguments, as for
2011 MimeTypes.add_type.
2012 [clinic start generated code]*/
2013
2014 static PyObject *
2015 _winapi__mimetypes_read_windows_registry_impl(PyObject *module,
2016 PyObject *on_type_read)
2017 /*[clinic end generated code: output=20829f00bebce55b input=cd357896d6501f68]*/
2018 {
2019 #define CCH_EXT 128
2020 #define CB_TYPE 510
2021 struct {
2022 wchar_t ext[CCH_EXT];
2023 wchar_t type[CB_TYPE / sizeof(wchar_t) + 1];
2024 } entries[64];
2025 int entry = 0;
2026 HKEY hkcr = NULL;
2027 LRESULT err;
2028
2029 Py_BEGIN_ALLOW_THREADS
2030 err = RegOpenKeyExW(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hkcr);
2031 for (DWORD i = 0; err == ERROR_SUCCESS || err == ERROR_MORE_DATA; ++i) {
2032 LPWSTR ext = entries[entry].ext;
2033 LPWSTR type = entries[entry].type;
2034 DWORD cchExt = CCH_EXT;
2035 DWORD cbType = CB_TYPE;
2036 HKEY subkey;
2037 DWORD regType;
2038
2039 err = RegEnumKeyExW(hkcr, i, ext, &cchExt, NULL, NULL, NULL, NULL);
2040 if (err != ERROR_SUCCESS || (cchExt && ext[0] != L'.')) {
2041 continue;
2042 }
2043
2044 err = RegOpenKeyExW(hkcr, ext, 0, KEY_READ, &subkey);
2045 if (err == ERROR_FILE_NOT_FOUND) {
2046 err = ERROR_SUCCESS;
2047 continue;
2048 } else if (err != ERROR_SUCCESS) {
2049 continue;
2050 }
2051
2052 err = RegQueryValueExW(subkey, L"Content Type", NULL,
2053 ®Type, (LPBYTE)type, &cbType);
2054 RegCloseKey(subkey);
2055 if (err == ERROR_FILE_NOT_FOUND) {
2056 err = ERROR_SUCCESS;
2057 continue;
2058 } else if (err != ERROR_SUCCESS) {
2059 continue;
2060 } else if (regType != REG_SZ || !cbType) {
2061 continue;
2062 }
2063 type[cbType / sizeof(wchar_t)] = L'\0';
2064
2065 entry += 1;
2066
2067 /* Flush our cached entries if we are full */
2068 if (entry == sizeof(entries) / sizeof(entries[0])) {
2069 Py_BLOCK_THREADS
2070 for (int j = 0; j < entry; ++j) {
2071 PyObject *r = PyObject_CallFunction(
2072 on_type_read, "uu", entries[j].type, entries[j].ext
2073 );
2074 if (!r) {
2075 /* We blocked threads, so safe to return from here */
2076 RegCloseKey(hkcr);
2077 return NULL;
2078 }
2079 Py_DECREF(r);
2080 }
2081 Py_UNBLOCK_THREADS
2082 entry = 0;
2083 }
2084 }
2085 if (hkcr) {
2086 RegCloseKey(hkcr);
2087 }
2088 Py_END_ALLOW_THREADS
2089
2090 if (err != ERROR_SUCCESS && err != ERROR_NO_MORE_ITEMS) {
2091 PyErr_SetFromWindowsErr((int)err);
2092 return NULL;
2093 }
2094
2095 for (int j = 0; j < entry; ++j) {
2096 PyObject *r = PyObject_CallFunction(
2097 on_type_read, "uu", entries[j].type, entries[j].ext
2098 );
2099 if (!r) {
2100 return NULL;
2101 }
2102 Py_DECREF(r);
2103 }
2104
2105 Py_RETURN_NONE;
2106 #undef CCH_EXT
2107 #undef CB_TYPE
2108 }
2109
2110
2111 static PyMethodDef winapi_functions[] = {
2112 _WINAPI_CLOSEHANDLE_METHODDEF
2113 _WINAPI_CONNECTNAMEDPIPE_METHODDEF
2114 _WINAPI_CREATEFILE_METHODDEF
2115 _WINAPI_CREATEFILEMAPPING_METHODDEF
2116 _WINAPI_CREATENAMEDPIPE_METHODDEF
2117 _WINAPI_CREATEPIPE_METHODDEF
2118 _WINAPI_CREATEPROCESS_METHODDEF
2119 _WINAPI_CREATEJUNCTION_METHODDEF
2120 _WINAPI_DUPLICATEHANDLE_METHODDEF
2121 _WINAPI_EXITPROCESS_METHODDEF
2122 _WINAPI_GETCURRENTPROCESS_METHODDEF
2123 _WINAPI_GETEXITCODEPROCESS_METHODDEF
2124 _WINAPI_GETLASTERROR_METHODDEF
2125 _WINAPI_GETMODULEFILENAME_METHODDEF
2126 _WINAPI_GETSTDHANDLE_METHODDEF
2127 _WINAPI_GETVERSION_METHODDEF
2128 _WINAPI_MAPVIEWOFFILE_METHODDEF
2129 _WINAPI_OPENFILEMAPPING_METHODDEF
2130 _WINAPI_OPENPROCESS_METHODDEF
2131 _WINAPI_PEEKNAMEDPIPE_METHODDEF
2132 _WINAPI_LCMAPSTRINGEX_METHODDEF
2133 _WINAPI_READFILE_METHODDEF
2134 _WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF
2135 _WINAPI_TERMINATEPROCESS_METHODDEF
2136 _WINAPI_UNMAPVIEWOFFILE_METHODDEF
2137 _WINAPI_VIRTUALQUERYSIZE_METHODDEF
2138 _WINAPI_WAITNAMEDPIPE_METHODDEF
2139 _WINAPI_WAITFORMULTIPLEOBJECTS_METHODDEF
2140 _WINAPI_WAITFORSINGLEOBJECT_METHODDEF
2141 _WINAPI_WRITEFILE_METHODDEF
2142 _WINAPI_GETACP_METHODDEF
2143 _WINAPI_GETFILETYPE_METHODDEF
2144 _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
2145 {NULL, NULL}
2146 };
2147
2148 #define WINAPI_CONSTANT(fmt, con) \
2149 do { \
2150 PyObject *value = Py_BuildValue(fmt, con); \
2151 if (value == NULL) { \
2152 return -1; \
2153 } \
2154 if (PyDict_SetItemString(d, #con, value) < 0) { \
2155 Py_DECREF(value); \
2156 return -1; \
2157 } \
2158 Py_DECREF(value); \
2159 } while (0)
2160
2161 static int winapi_exec(PyObject *m)
2162 {
2163 WinApiState *st = winapi_get_state(m);
2164
2165 st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &winapi_overlapped_type_spec, NULL);
2166 if (st->overlapped_type == NULL) {
2167 return -1;
2168 }
2169
2170 if (PyModule_AddType(m, st->overlapped_type) < 0) {
2171 return -1;
2172 }
2173
2174 PyObject *d = PyModule_GetDict(m);
2175
2176 /* constants */
2177 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
2178 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
2179 WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
2180 WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
2181 WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
2182 WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
2183 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
2184 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
2185 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
2186 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
2187 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
2188 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
2189 WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
2190 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
2191 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
2192 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
2193 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
2194 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
2195 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
2196 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
2197 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
2198 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
2199 WINAPI_CONSTANT(F_DWORD, FILE_MAP_ALL_ACCESS);
2200 WINAPI_CONSTANT(F_DWORD, FILE_MAP_COPY);
2201 WINAPI_CONSTANT(F_DWORD, FILE_MAP_EXECUTE);
2202 WINAPI_CONSTANT(F_DWORD, FILE_MAP_READ);
2203 WINAPI_CONSTANT(F_DWORD, FILE_MAP_WRITE);
2204 WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
2205 WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
2206 WINAPI_CONSTANT(F_DWORD, INFINITE);
2207 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
2208 WINAPI_CONSTANT(F_DWORD, MEM_COMMIT);
2209 WINAPI_CONSTANT(F_DWORD, MEM_FREE);
2210 WINAPI_CONSTANT(F_DWORD, MEM_IMAGE);
2211 WINAPI_CONSTANT(F_DWORD, MEM_MAPPED);
2212 WINAPI_CONSTANT(F_DWORD, MEM_PRIVATE);
2213 WINAPI_CONSTANT(F_DWORD, MEM_RESERVE);
2214 WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
2215 WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
2216 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE);
2217 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READ);
2218 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READWRITE);
2219 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_WRITECOPY);
2220 WINAPI_CONSTANT(F_DWORD, PAGE_GUARD);
2221 WINAPI_CONSTANT(F_DWORD, PAGE_NOACCESS);
2222 WINAPI_CONSTANT(F_DWORD, PAGE_NOCACHE);
2223 WINAPI_CONSTANT(F_DWORD, PAGE_READONLY);
2224 WINAPI_CONSTANT(F_DWORD, PAGE_READWRITE);
2225 WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOMBINE);
2226 WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOPY);
2227 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
2228 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
2229 WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
2230 WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
2231 WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
2232 WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
2233 WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
2234 WINAPI_CONSTANT(F_DWORD, SYNCHRONIZE);
2235 WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
2236 WINAPI_CONSTANT(F_DWORD, SEC_COMMIT);
2237 WINAPI_CONSTANT(F_DWORD, SEC_IMAGE);
2238 WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES);
2239 WINAPI_CONSTANT(F_DWORD, SEC_NOCACHE);
2240 WINAPI_CONSTANT(F_DWORD, SEC_RESERVE);
2241 WINAPI_CONSTANT(F_DWORD, SEC_WRITECOMBINE);
2242 WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
2243 WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
2244 WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
2245 WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
2246 WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
2247 WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
2248 WINAPI_CONSTANT(F_DWORD, SW_HIDE);
2249 WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
2250 WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
2251 WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
2252
2253 WINAPI_CONSTANT(F_DWORD, ABOVE_NORMAL_PRIORITY_CLASS);
2254 WINAPI_CONSTANT(F_DWORD, BELOW_NORMAL_PRIORITY_CLASS);
2255 WINAPI_CONSTANT(F_DWORD, HIGH_PRIORITY_CLASS);
2256 WINAPI_CONSTANT(F_DWORD, IDLE_PRIORITY_CLASS);
2257 WINAPI_CONSTANT(F_DWORD, NORMAL_PRIORITY_CLASS);
2258 WINAPI_CONSTANT(F_DWORD, REALTIME_PRIORITY_CLASS);
2259
2260 WINAPI_CONSTANT(F_DWORD, CREATE_NO_WINDOW);
2261 WINAPI_CONSTANT(F_DWORD, DETACHED_PROCESS);
2262 WINAPI_CONSTANT(F_DWORD, CREATE_DEFAULT_ERROR_MODE);
2263 WINAPI_CONSTANT(F_DWORD, CREATE_BREAKAWAY_FROM_JOB);
2264
2265 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_UNKNOWN);
2266 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_DISK);
2267 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_CHAR);
2268 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_PIPE);
2269 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_REMOTE);
2270
2271 WINAPI_CONSTANT("u", LOCALE_NAME_INVARIANT);
2272 WINAPI_CONSTANT(F_DWORD, LOCALE_NAME_MAX_LENGTH);
2273 WINAPI_CONSTANT("u", LOCALE_NAME_SYSTEM_DEFAULT);
2274 WINAPI_CONSTANT("u", LOCALE_NAME_USER_DEFAULT);
2275
2276 WINAPI_CONSTANT(F_DWORD, LCMAP_FULLWIDTH);
2277 WINAPI_CONSTANT(F_DWORD, LCMAP_HALFWIDTH);
2278 WINAPI_CONSTANT(F_DWORD, LCMAP_HIRAGANA);
2279 WINAPI_CONSTANT(F_DWORD, LCMAP_KATAKANA);
2280 WINAPI_CONSTANT(F_DWORD, LCMAP_LINGUISTIC_CASING);
2281 WINAPI_CONSTANT(F_DWORD, LCMAP_LOWERCASE);
2282 WINAPI_CONSTANT(F_DWORD, LCMAP_SIMPLIFIED_CHINESE);
2283 WINAPI_CONSTANT(F_DWORD, LCMAP_TITLECASE);
2284 WINAPI_CONSTANT(F_DWORD, LCMAP_TRADITIONAL_CHINESE);
2285 WINAPI_CONSTANT(F_DWORD, LCMAP_UPPERCASE);
2286
2287 WINAPI_CONSTANT("i", NULL);
2288
2289 return 0;
2290 }
2291
2292 static PyModuleDef_Slot winapi_slots[] = {
2293 {Py_mod_exec, winapi_exec},
2294 {0, NULL}
2295 };
2296
2297 static int
2298 winapi_traverse(PyObject *module, visitproc visit, void *arg)
2299 {
2300 WinApiState *st = winapi_get_state(module);
2301 Py_VISIT(st->overlapped_type);
2302 return 0;
2303 }
2304
2305 static int
2306 winapi_clear(PyObject *module)
2307 {
2308 WinApiState *st = winapi_get_state(module);
2309 Py_CLEAR(st->overlapped_type);
2310 return 0;
2311 }
2312
2313 static void
2314 winapi_free(void *module)
2315 {
2316 winapi_clear((PyObject *)module);
2317 }
2318
2319 static struct PyModuleDef winapi_module = {
2320 PyModuleDef_HEAD_INIT,
2321 .m_name = "_winapi",
2322 .m_size = sizeof(WinApiState),
2323 .m_methods = winapi_functions,
2324 .m_slots = winapi_slots,
2325 .m_traverse = winapi_traverse,
2326 .m_clear = winapi_clear,
2327 .m_free = winapi_free,
2328 };
2329
2330 PyMODINIT_FUNC
2331 PyInit__winapi(void)
2332 {
2333 return PyModuleDef_Init(&winapi_module);
2334 }