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