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