1 /* POSIX module implementation */
2
3 /* This file is also used for Windows NT/MS-Win. In that case the
4 module actually calls itself 'nt', not 'posix', and a few
5 functions are either unimplemented or implemented differently. The source
6 assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent
7 of the compiler used. Different compilers define their own feature
8 test macro, e.g. '_MSC_VER'. */
9
10 #include "Python.h"
11
12 #ifdef __VXWORKS__
13 # include "pycore_bitutils.h" // _Py_popcount32()
14 #endif
15 #include "pycore_abstract.h" // _PyNumber_Index()
16 #include "pycore_call.h" // _PyObject_CallNoArgs()
17 #include "pycore_ceval.h" // _PyEval_ReInitThreads()
18 #include "pycore_fileutils.h" // _Py_closerange()
19 #include "pycore_initconfig.h" // _PyStatus_EXCEPTION()
20 #include "pycore_long.h" // _PyLong_IsNegative()
21 #include "pycore_moduleobject.h" // _PyModule_GetState()
22 #include "pycore_object.h" // _PyObject_LookupSpecial()
23 #include "pycore_pylifecycle.h" // _PyOS_URandom()
24 #include "pycore_pystate.h" // _PyInterpreterState_GET()
25 #include "pycore_signal.h" // Py_NSIG
26 #include "pycore_time.h" // _PyLong_FromTime_t()
27 #include "pycore_typeobject.h" // _PyType_AddMethod()
28
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h> // symlink()
31 #endif
32
33 #ifdef MS_WINDOWS
34 # include <windows.h>
35 # if !defined(MS_WINDOWS_GAMES) || defined(MS_WINDOWS_DESKTOP)
36 # include <pathcch.h>
37 # endif
38 # include <winioctl.h>
39 # include <lmcons.h> // UNLEN
40 # include "osdefs.h" // SEP
41 # include <aclapi.h> // SetEntriesInAcl
42 # include <sddl.h> // SDDL_REVISION_1
43 # if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
44 # define HAVE_SYMLINK
45 # endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */
46 #endif
47
48 #ifndef MS_WINDOWS
49 # include "posixmodule.h"
50 #else
51 # include "pycore_fileutils_windows.h"
52 # include "winreparse.h"
53 #endif
54
55 #if !defined(EX_OK) && defined(EXIT_SUCCESS)
56 # define EX_OK EXIT_SUCCESS
57 #endif
58
59 #ifdef __APPLE__
60 /* Needed for the implementation of os.statvfs */
61 # include <sys/param.h>
62 # include <sys/mount.h>
63 #endif
64
65 /* On android API level 21, 'AT_EACCESS' is not declared although
66 * HAVE_FACCESSAT is defined. */
67 #ifdef __ANDROID__
68 # undef HAVE_FACCESSAT
69 #endif
70
71 #include <stdio.h> // ctermid()
72 #include <stdlib.h> // system()
73 #ifdef HAVE_SYS_TIME_H
74 # include <sys/time.h> // futimes()
75 #endif
76
77
78 // SGI apparently needs this forward declaration
79 #ifdef HAVE__GETPTY
80 # include <sys/types.h> // mode_t
81 extern char * _getpty(int *, int, mode_t, int);
82 #endif
83
84
85 /*
86 * A number of APIs are available on macOS from a certain macOS version.
87 * To support building with a new SDK while deploying to older versions
88 * the availability test is split into two:
89 * - HAVE_<FUNCTION>: The configure check for compile time availability
90 * - HAVE_<FUNCTION>_RUNTIME: Runtime check for availability
91 *
92 * The latter is always true when not on macOS, or when using a compiler
93 * that does not support __has_builtin (older versions of Xcode).
94 *
95 * Due to compiler restrictions there is one valid use of HAVE_<FUNCTION>_RUNTIME:
96 * if (HAVE_<FUNCTION>_RUNTIME) { ... }
97 *
98 * In mixing the test with other tests or using negations will result in compile
99 * errors.
100 */
101 #if defined(__APPLE__)
102
103 #include <mach/mach.h>
104
105 #if defined(__has_builtin)
106 #if __has_builtin(__builtin_available)
107 #define HAVE_BUILTIN_AVAILABLE 1
108 #endif
109 #endif
110
111 #ifdef HAVE_BUILTIN_AVAILABLE
112 # define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
113 # define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
114 # define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
115 # define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
116 # define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
117 # define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
118 # define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
119 # define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
120 # define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
121 # define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
122 # define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
123 # define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
124 # define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
125 # define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
126 # define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)
127 # define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
128 # define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
129 # define HAVE_PTSNAME_R_RUNTIME __builtin_available(macOS 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.3, *)
130
131 # define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *)
132
133 #else /* Xcode 8 or earlier */
134
135 /* __builtin_available is not present in these compilers, but
136 * some of the symbols might be weak linked (10.10 SDK or later
137 * deploying on 10.9.
138 *
139 * Fall back to the older style of availability checking for
140 * symbols introduced in macOS 10.10.
141 */
142
143 # ifdef HAVE_FSTATAT
144 # define HAVE_FSTATAT_RUNTIME (fstatat != NULL)
145 # endif
146
147 # ifdef HAVE_FACCESSAT
148 # define HAVE_FACCESSAT_RUNTIME (faccessat != NULL)
149 # endif
150
151 # ifdef HAVE_FCHMODAT
152 # define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL)
153 # endif
154
155 # ifdef HAVE_FCHOWNAT
156 # define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL)
157 # endif
158
159 # ifdef HAVE_LINKAT
160 # define HAVE_LINKAT_RUNTIME (linkat != NULL)
161 # endif
162
163 # ifdef HAVE_FDOPENDIR
164 # define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL)
165 # endif
166
167 # ifdef HAVE_MKDIRAT
168 # define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL)
169 # endif
170
171 # ifdef HAVE_RENAMEAT
172 # define HAVE_RENAMEAT_RUNTIME (renameat != NULL)
173 # endif
174
175 # ifdef HAVE_UNLINKAT
176 # define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL)
177 # endif
178
179 # ifdef HAVE_OPENAT
180 # define HAVE_OPENAT_RUNTIME (openat != NULL)
181 # endif
182
183 # ifdef HAVE_READLINKAT
184 # define HAVE_READLINKAT_RUNTIME (readlinkat != NULL)
185 # endif
186
187 # ifdef HAVE_SYMLINKAT
188 # define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL)
189 # endif
190
191 # ifdef HAVE_UTIMENSAT
192 # define HAVE_UTIMENSAT_RUNTIME (utimensat != NULL)
193 # endif
194
195 # ifdef HAVE_FUTIMENS
196 # define HAVE_FUTIMENS_RUNTIME (futimens != NULL)
197 # endif
198
199 # ifdef HAVE_PWRITEV
200 # define HAVE_PWRITEV_RUNTIME (pwritev != NULL)
201 # endif
202
203 # ifdef HAVE_MKFIFOAT
204 # define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL)
205 # endif
206
207 # ifdef HAVE_MKNODAT
208 # define HAVE_MKNODAT_RUNTIME (mknodat != NULL)
209 # endif
210
211 # ifdef HAVE_PTSNAME_R
212 # define HAVE_PTSNAME_R_RUNTIME (ptsname_r != NULL)
213 # endif
214
215 #endif
216
217 #ifdef HAVE_FUTIMESAT
218 /* Some of the logic for weak linking depends on this assertion */
219 # error "HAVE_FUTIMESAT unexpectedly defined"
220 #endif
221
222 #else
223 # define HAVE_FSTATAT_RUNTIME 1
224 # define HAVE_FACCESSAT_RUNTIME 1
225 # define HAVE_FCHMODAT_RUNTIME 1
226 # define HAVE_FCHOWNAT_RUNTIME 1
227 # define HAVE_LINKAT_RUNTIME 1
228 # define HAVE_FDOPENDIR_RUNTIME 1
229 # define HAVE_MKDIRAT_RUNTIME 1
230 # define HAVE_RENAMEAT_RUNTIME 1
231 # define HAVE_UNLINKAT_RUNTIME 1
232 # define HAVE_OPENAT_RUNTIME 1
233 # define HAVE_READLINKAT_RUNTIME 1
234 # define HAVE_SYMLINKAT_RUNTIME 1
235 # define HAVE_FUTIMENS_RUNTIME 1
236 # define HAVE_UTIMENSAT_RUNTIME 1
237 # define HAVE_PWRITEV_RUNTIME 1
238 # define HAVE_MKFIFOAT_RUNTIME 1
239 # define HAVE_MKNODAT_RUNTIME 1
240 # define HAVE_PTSNAME_R_RUNTIME 1
241 #endif
242
243
244 PyDoc_STRVAR(posix__doc__,
245 "This module provides access to operating system functionality that is\n\
246 standardized by the C Standard and the POSIX standard (a thinly\n\
247 disguised Unix interface). Refer to the library manual and\n\
248 corresponding Unix manual entries for more information on calls.");
249
250
251 #ifdef HAVE_SYS_UIO_H
252 # include <sys/uio.h>
253 #endif
254
255 #ifdef HAVE_SYS_TYPES_H
256 /* Should be included before <sys/sysmacros.h> on HP-UX v3 */
257 # include <sys/types.h>
258 #endif /* HAVE_SYS_TYPES_H */
259
260 #ifdef HAVE_SYS_SYSMACROS_H
261 /* GNU C Library: major(), minor(), makedev() */
262 # include <sys/sysmacros.h>
263 #endif
264
265 #ifdef HAVE_SYS_STAT_H
266 # include <sys/stat.h>
267 #endif /* HAVE_SYS_STAT_H */
268
269 #ifdef HAVE_SYS_WAIT_H
270 # include <sys/wait.h> // WNOHANG
271 #endif
272 #ifdef HAVE_LINUX_WAIT_H
273 # include <linux/wait.h> // P_PIDFD
274 #endif
275
276 #ifdef HAVE_SIGNAL_H
277 # include <signal.h>
278 #endif
279
280 #ifdef HAVE_FCNTL_H
281 # include <fcntl.h>
282 #endif
283
284 #ifdef HAVE_GRP_H
285 # include <grp.h>
286 #endif
287
288 #ifdef HAVE_SYSEXITS_H
289 # include <sysexits.h>
290 #endif
291
292 #ifdef HAVE_SYS_LOADAVG_H
293 # include <sys/loadavg.h>
294 #endif
295
296 #ifdef HAVE_SYS_SENDFILE_H
297 # include <sys/sendfile.h>
298 #endif
299
300 #if defined(__APPLE__)
301 # include <copyfile.h>
302 #endif
303
304 #ifdef HAVE_SCHED_H
305 # include <sched.h>
306 #endif
307
308 #if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY)
309 # undef HAVE_SCHED_SETAFFINITY
310 #endif
311
312 #if defined(HAVE_SYS_XATTR_H)
313 # if defined(HAVE_LINUX_LIMITS_H) && !defined(__FreeBSD_kernel__) && !defined(__GNU__)
314 # define USE_XATTRS
315 # include <linux/limits.h> // Needed for XATTR_SIZE_MAX on musl libc.
316 # endif
317 # if defined(__CYGWIN__)
318 # define USE_XATTRS
319 # include <cygwin/limits.h> // Needed for XATTR_SIZE_MAX and XATTR_LIST_MAX.
320 # endif
321 #endif
322
323 #ifdef USE_XATTRS
324 # include <sys/xattr.h>
325 #endif
326
327 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
328 # ifdef HAVE_SYS_SOCKET_H
329 # include <sys/socket.h>
330 # endif
331 #endif
332
333 #ifdef HAVE_DLFCN_H
334 # include <dlfcn.h>
335 #endif
336
337 #ifdef __hpux
338 # include <sys/mpctl.h>
339 #endif
340
341 #if defined(__DragonFly__) || \
342 defined(__OpenBSD__) || \
343 defined(__FreeBSD__) || \
344 defined(__NetBSD__) || \
345 defined(__APPLE__)
346 # include <sys/sysctl.h>
347 #endif
348
349 #ifdef HAVE_LINUX_RANDOM_H
350 # include <linux/random.h>
351 #endif
352 #ifdef HAVE_GETRANDOM_SYSCALL
353 # include <sys/syscall.h>
354 #endif
355
356 #ifdef HAVE_WINDOWS_CONSOLE_IO
357 # define TERMSIZE_USE_CONIO
358 #elif defined(HAVE_SYS_IOCTL_H)
359 # include <sys/ioctl.h>
360 # if defined(HAVE_TERMIOS_H)
361 # include <termios.h>
362 # endif
363 # if defined(TIOCGWINSZ)
364 # define TERMSIZE_USE_IOCTL
365 # endif
366 #endif /* HAVE_WINDOWS_CONSOLE_IO */
367
368 /* Various compilers have only certain posix functions */
369 /* XXX Gosh I wish these were all moved into pyconfig.h */
370 #if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */
371 # define HAVE_OPENDIR 1
372 # define HAVE_SYSTEM 1
373 # include <process.h>
374 #elif defined( _MSC_VER)
375 /* Microsoft compiler */
376 # if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)
377 # define HAVE_GETPPID 1
378 # endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_APP | MS_WINDOWS_SYSTEM */
379 # if defined(MS_WINDOWS_DESKTOP)
380 # define HAVE_GETLOGIN 1
381 # endif /* MS_WINDOWS_DESKTOP */
382 # if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
383 # define HAVE_SPAWNV 1
384 # define HAVE_EXECV 1
385 # define HAVE_WSPAWNV 1
386 # define HAVE_WEXECV 1
387 # define HAVE_SYSTEM 1
388 # define HAVE_CWAIT 1
389 # endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */
390 # define HAVE_PIPE 1
391 # define HAVE_FSYNC 1
392 # define fsync _commit
393 #endif /* ! __WATCOMC__ || __QNX__ */
394
395 /*[clinic input]
396 # one of the few times we lie about this name!
397 module os
398 [clinic start generated code]*/
399 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/
400
401 #ifndef _MSC_VER
402
403 #if defined(__sgi)&&_COMPILER_VERSION>=700
404 /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode
405 (default) */
406 extern char *ctermid_r(char *);
407 #endif
408
409 #endif /* !_MSC_VER */
410
411 #if defined(__VXWORKS__)
412 # include <vxCpuLib.h>
413 # include <rtpLib.h>
414 # include <wait.h>
415 # include <taskLib.h>
416 # ifndef _P_WAIT
417 # define _P_WAIT 0
418 # define _P_NOWAIT 1
419 # define _P_NOWAITO 1
420 # endif
421 #endif /* __VXWORKS__ */
422
423 #ifdef HAVE_POSIX_SPAWN
424 # include <spawn.h>
425 #endif
426
427 #ifdef HAVE_UTIME_H
428 # include <utime.h>
429 #endif /* HAVE_UTIME_H */
430
431 #ifdef HAVE_SYS_UTIME_H
432 # include <sys/utime.h>
433 # define HAVE_UTIME_H /* pretend we do for the rest of this file */
434 #endif /* HAVE_SYS_UTIME_H */
435
436 #ifdef HAVE_SYS_TIMES_H
437 # include <sys/times.h>
438 #endif /* HAVE_SYS_TIMES_H */
439
440 #ifdef HAVE_SYS_PARAM_H
441 # include <sys/param.h>
442 #endif /* HAVE_SYS_PARAM_H */
443
444 #ifdef HAVE_SYS_UTSNAME_H
445 # include <sys/utsname.h>
446 #endif /* HAVE_SYS_UTSNAME_H */
447
448 #ifdef HAVE_DIRENT_H
449 # include <dirent.h>
450 # define NAMLEN(dirent) strlen((dirent)->d_name)
451 #else
452 # if defined(__WATCOMC__) && !defined(__QNX__)
453 # include <direct.h>
454 # define NAMLEN(dirent) strlen((dirent)->d_name)
455 # else
456 # define dirent direct
457 # define NAMLEN(dirent) (dirent)->d_namlen
458 # endif
459 # ifdef HAVE_SYS_NDIR_H
460 # include <sys/ndir.h>
461 # endif
462 # ifdef HAVE_SYS_DIR_H
463 # include <sys/dir.h>
464 # endif
465 # ifdef HAVE_NDIR_H
466 # include <ndir.h>
467 # endif
468 #endif
469
470 #ifdef _MSC_VER
471 # ifdef HAVE_DIRECT_H
472 # include <direct.h>
473 # endif
474 # ifdef HAVE_IO_H
475 # include <io.h>
476 # endif
477 # ifdef HAVE_PROCESS_H
478 # include <process.h>
479 # endif
480 # include <malloc.h>
481 #endif /* _MSC_VER */
482
483 #ifndef MAXPATHLEN
484 # if defined(PATH_MAX) && PATH_MAX > 1024
485 # define MAXPATHLEN PATH_MAX
486 # else
487 # define MAXPATHLEN 1024
488 # endif
489 #endif /* MAXPATHLEN */
490
491 #ifdef UNION_WAIT
492 /* Emulate some macros on systems that have a union instead of macros */
493 # ifndef WIFEXITED
494 # define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump)
495 # endif
496 # ifndef WEXITSTATUS
497 # define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1)
498 # endif
499 # ifndef WTERMSIG
500 # define WTERMSIG(u_wait) ((u_wait).w_termsig)
501 # endif
502 # define WAIT_TYPE union wait
503 # define WAIT_STATUS_INT(s) (s.w_status)
504 #else
505 /* !UNION_WAIT */
506 # define WAIT_TYPE int
507 # define WAIT_STATUS_INT(s) (s)
508 #endif /* UNION_WAIT */
509
510 /* Don't use the "_r" form if we don't need it (also, won't have a
511 prototype for it, at least on Solaris -- maybe others as well?). */
512 #if defined(HAVE_CTERMID_R)
513 # define USE_CTERMID_R
514 #endif
515
516 /* choose the appropriate stat and fstat functions and return structs */
517 #undef STAT
518 #undef FSTAT
519 #undef STRUCT_STAT
520 #ifdef MS_WINDOWS
521 # define STAT win32_stat
522 # define LSTAT win32_lstat
523 # define FSTAT _Py_fstat_noraise
524 # define STRUCT_STAT struct _Py_stat_struct
525 #else
526 # define STAT stat
527 # define LSTAT lstat
528 # define FSTAT fstat
529 # define STRUCT_STAT struct stat
530 #endif
531
532 #if defined(MAJOR_IN_MKDEV)
533 # include <sys/mkdev.h>
534 #else
535 # if defined(MAJOR_IN_SYSMACROS)
536 # include <sys/sysmacros.h>
537 # endif
538 # if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H)
539 # include <sys/mkdev.h>
540 # endif
541 #endif
542
543 #ifdef MS_WINDOWS
544 # define INITFUNC PyInit_nt
545 # define MODNAME "nt"
546 # define MODNAME_OBJ &_Py_ID(nt)
547 #else
548 # define INITFUNC PyInit_posix
549 # define MODNAME "posix"
550 # define MODNAME_OBJ &_Py_ID(posix)
551 #endif
552
553 #if defined(__sun)
554 /* Something to implement in autoconf, not present in autoconf 2.69 */
555 # define HAVE_STRUCT_STAT_ST_FSTYPE 1
556 #endif
557
558 /* memfd_create is either defined in sys/mman.h or sys/memfd.h
559 * linux/memfd.h defines additional flags
560 */
561 #ifdef HAVE_SYS_MMAN_H
562 # include <sys/mman.h>
563 #endif
564 #ifdef HAVE_SYS_MEMFD_H
565 # include <sys/memfd.h>
566 #endif
567 #ifdef HAVE_LINUX_MEMFD_H
568 # include <linux/memfd.h>
569 #endif
570
571 /* eventfd() */
572 #ifdef HAVE_SYS_EVENTFD_H
573 # include <sys/eventfd.h>
574 #endif
575
576 /* timerfd_create() */
577 #ifdef HAVE_SYS_TIMERFD_H
578 # include <sys/timerfd.h>
579 #endif
580
581 #ifdef _Py_MEMORY_SANITIZER
582 # include <sanitizer/msan_interface.h>
583 #endif
584
585 #ifdef HAVE_FORK
586 static void
run_at_forkers(PyObject * lst,int reverse)587 run_at_forkers(PyObject *lst, int reverse)
588 {
589 Py_ssize_t i;
590 PyObject *cpy;
591
592 if (lst != NULL) {
593 assert(PyList_CheckExact(lst));
594
595 /* Use a list copy in case register_at_fork() is called from
596 * one of the callbacks.
597 */
598 cpy = PyList_GetSlice(lst, 0, PyList_GET_SIZE(lst));
599 if (cpy == NULL)
600 PyErr_WriteUnraisable(lst);
601 else {
602 if (reverse)
603 PyList_Reverse(cpy);
604 for (i = 0; i < PyList_GET_SIZE(cpy); i++) {
605 PyObject *func, *res;
606 func = PyList_GET_ITEM(cpy, i);
607 res = _PyObject_CallNoArgs(func);
608 if (res == NULL)
609 PyErr_WriteUnraisable(func);
610 else
611 Py_DECREF(res);
612 }
613 Py_DECREF(cpy);
614 }
615 }
616 }
617
618 void
PyOS_BeforeFork(void)619 PyOS_BeforeFork(void)
620 {
621 PyInterpreterState *interp = _PyInterpreterState_GET();
622 run_at_forkers(interp->before_forkers, 1);
623
624 _PyImport_AcquireLock(interp);
625 _PyEval_StopTheWorldAll(&_PyRuntime);
626 HEAD_LOCK(&_PyRuntime);
627 }
628
629 void
PyOS_AfterFork_Parent(void)630 PyOS_AfterFork_Parent(void)
631 {
632 HEAD_UNLOCK(&_PyRuntime);
633 _PyEval_StartTheWorldAll(&_PyRuntime);
634
635 PyInterpreterState *interp = _PyInterpreterState_GET();
636 _PyImport_ReleaseLock(interp);
637 run_at_forkers(interp->after_forkers_parent, 0);
638 }
639
640 void
PyOS_AfterFork_Child(void)641 PyOS_AfterFork_Child(void)
642 {
643 PyStatus status;
644 _PyRuntimeState *runtime = &_PyRuntime;
645
646 // re-creates runtime->interpreters.mutex (HEAD_UNLOCK)
647 status = _PyRuntimeState_ReInitThreads(runtime);
648 if (_PyStatus_EXCEPTION(status)) {
649 goto fatal_error;
650 }
651
652 PyThreadState *tstate = _PyThreadState_GET();
653 _Py_EnsureTstateNotNULL(tstate);
654
655 assert(tstate->thread_id == PyThread_get_thread_ident());
656 #ifdef PY_HAVE_THREAD_NATIVE_ID
657 tstate->native_thread_id = PyThread_get_thread_native_id();
658 #endif
659
660 #ifdef Py_GIL_DISABLED
661 _Py_brc_after_fork(tstate->interp);
662 _Py_qsbr_after_fork((_PyThreadStateImpl *)tstate);
663 #endif
664
665 // Ideally we could guarantee tstate is running main.
666 _PyInterpreterState_ReinitRunningMain(tstate);
667
668 status = _PyEval_ReInitThreads(tstate);
669 if (_PyStatus_EXCEPTION(status)) {
670 goto fatal_error;
671 }
672
673 // Remove the dead thread states. We "start the world" once we are the only
674 // thread state left to undo the stop the world call in `PyOS_BeforeFork`.
675 // That needs to happen before `_PyThreadState_DeleteList`, because that
676 // may call destructors.
677 PyThreadState *list = _PyThreadState_RemoveExcept(tstate);
678 _PyEval_StartTheWorldAll(&_PyRuntime);
679 _PyThreadState_DeleteList(list);
680
681 _PyImport_ReInitLock(tstate->interp);
682 _PyImport_ReleaseLock(tstate->interp);
683
684 _PySignal_AfterFork();
685
686 status = _PyInterpreterState_DeleteExceptMain(runtime);
687 if (_PyStatus_EXCEPTION(status)) {
688 goto fatal_error;
689 }
690 assert(_PyThreadState_GET() == tstate);
691
692 status = _PyPerfTrampoline_AfterFork_Child();
693 if (_PyStatus_EXCEPTION(status)) {
694 goto fatal_error;
695 }
696
697 run_at_forkers(tstate->interp->after_forkers_child, 0);
698 return;
699
700 fatal_error:
701 Py_ExitStatusException(status);
702 }
703
704 static int
register_at_forker(PyObject ** lst,PyObject * func)705 register_at_forker(PyObject **lst, PyObject *func)
706 {
707 if (func == NULL) /* nothing to register? do nothing. */
708 return 0;
709 if (*lst == NULL) {
710 *lst = PyList_New(0);
711 if (*lst == NULL)
712 return -1;
713 }
714 return PyList_Append(*lst, func);
715 }
716 #endif /* HAVE_FORK */
717
718
719 /* Legacy wrapper */
720 void
PyOS_AfterFork(void)721 PyOS_AfterFork(void)
722 {
723 #ifdef HAVE_FORK
724 PyOS_AfterFork_Child();
725 #endif
726 }
727
728
729 #ifdef MS_WINDOWS
730 /* defined in fileutils.c */
731 void _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *);
732 void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, ULONG,
733 FILE_BASIC_INFO *, FILE_ID_INFO *,
734 struct _Py_stat_struct *);
735 void _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *,
736 struct _Py_stat_struct *);
737 #endif
738
739
740 #ifndef MS_WINDOWS
741 PyObject *
_PyLong_FromUid(uid_t uid)742 _PyLong_FromUid(uid_t uid)
743 {
744 if (uid == (uid_t)-1)
745 return PyLong_FromLong(-1);
746 return PyLong_FromUnsignedLong(uid);
747 }
748
749 PyObject *
_PyLong_FromGid(gid_t gid)750 _PyLong_FromGid(gid_t gid)
751 {
752 if (gid == (gid_t)-1)
753 return PyLong_FromLong(-1);
754 return PyLong_FromUnsignedLong(gid);
755 }
756
757 int
_Py_Uid_Converter(PyObject * obj,uid_t * p)758 _Py_Uid_Converter(PyObject *obj, uid_t *p)
759 {
760 uid_t uid;
761 PyObject *index;
762 int overflow;
763 long result;
764 unsigned long uresult;
765
766 index = _PyNumber_Index(obj);
767 if (index == NULL) {
768 PyErr_Format(PyExc_TypeError,
769 "uid should be integer, not %.200s",
770 _PyType_Name(Py_TYPE(obj)));
771 return 0;
772 }
773
774 /*
775 * Handling uid_t is complicated for two reasons:
776 * * Although uid_t is (always?) unsigned, it still
777 * accepts -1.
778 * * We don't know its size in advance--it may be
779 * bigger than an int, or it may be smaller than
780 * a long.
781 *
782 * So a bit of defensive programming is in order.
783 * Start with interpreting the value passed
784 * in as a signed long and see if it works.
785 */
786
787 result = PyLong_AsLongAndOverflow(index, &overflow);
788
789 if (!overflow) {
790 uid = (uid_t)result;
791
792 if (result == -1) {
793 if (PyErr_Occurred())
794 goto fail;
795 /* It's a legitimate -1, we're done. */
796 goto success;
797 }
798
799 /* Any other negative number is disallowed. */
800 if (result < 0)
801 goto underflow;
802
803 /* Ensure the value wasn't truncated. */
804 if (sizeof(uid_t) < sizeof(long) &&
805 (long)uid != result)
806 goto underflow;
807 goto success;
808 }
809
810 if (overflow < 0)
811 goto underflow;
812
813 /*
814 * Okay, the value overflowed a signed long. If it
815 * fits in an *unsigned* long, it may still be okay,
816 * as uid_t may be unsigned long on this platform.
817 */
818 uresult = PyLong_AsUnsignedLong(index);
819 if (PyErr_Occurred()) {
820 if (PyErr_ExceptionMatches(PyExc_OverflowError))
821 goto overflow;
822 goto fail;
823 }
824
825 uid = (uid_t)uresult;
826
827 /*
828 * If uid == (uid_t)-1, the user actually passed in ULONG_MAX,
829 * but this value would get interpreted as (uid_t)-1 by chown
830 * and its siblings. That's not what the user meant! So we
831 * throw an overflow exception instead. (We already
832 * handled a real -1 with PyLong_AsLongAndOverflow() above.)
833 */
834 if (uid == (uid_t)-1)
835 goto overflow;
836
837 /* Ensure the value wasn't truncated. */
838 if (sizeof(uid_t) < sizeof(long) &&
839 (unsigned long)uid != uresult)
840 goto overflow;
841 /* fallthrough */
842
843 success:
844 Py_DECREF(index);
845 *p = uid;
846 return 1;
847
848 underflow:
849 PyErr_SetString(PyExc_OverflowError,
850 "uid is less than minimum");
851 goto fail;
852
853 overflow:
854 PyErr_SetString(PyExc_OverflowError,
855 "uid is greater than maximum");
856 /* fallthrough */
857
858 fail:
859 Py_DECREF(index);
860 return 0;
861 }
862
863 int
_Py_Gid_Converter(PyObject * obj,gid_t * p)864 _Py_Gid_Converter(PyObject *obj, gid_t *p)
865 {
866 gid_t gid;
867 PyObject *index;
868 int overflow;
869 long result;
870 unsigned long uresult;
871
872 index = _PyNumber_Index(obj);
873 if (index == NULL) {
874 PyErr_Format(PyExc_TypeError,
875 "gid should be integer, not %.200s",
876 _PyType_Name(Py_TYPE(obj)));
877 return 0;
878 }
879
880 /*
881 * Handling gid_t is complicated for two reasons:
882 * * Although gid_t is (always?) unsigned, it still
883 * accepts -1.
884 * * We don't know its size in advance--it may be
885 * bigger than an int, or it may be smaller than
886 * a long.
887 *
888 * So a bit of defensive programming is in order.
889 * Start with interpreting the value passed
890 * in as a signed long and see if it works.
891 */
892
893 result = PyLong_AsLongAndOverflow(index, &overflow);
894
895 if (!overflow) {
896 gid = (gid_t)result;
897
898 if (result == -1) {
899 if (PyErr_Occurred())
900 goto fail;
901 /* It's a legitimate -1, we're done. */
902 goto success;
903 }
904
905 /* Any other negative number is disallowed. */
906 if (result < 0) {
907 goto underflow;
908 }
909
910 /* Ensure the value wasn't truncated. */
911 if (sizeof(gid_t) < sizeof(long) &&
912 (long)gid != result)
913 goto underflow;
914 goto success;
915 }
916
917 if (overflow < 0)
918 goto underflow;
919
920 /*
921 * Okay, the value overflowed a signed long. If it
922 * fits in an *unsigned* long, it may still be okay,
923 * as gid_t may be unsigned long on this platform.
924 */
925 uresult = PyLong_AsUnsignedLong(index);
926 if (PyErr_Occurred()) {
927 if (PyErr_ExceptionMatches(PyExc_OverflowError))
928 goto overflow;
929 goto fail;
930 }
931
932 gid = (gid_t)uresult;
933
934 /*
935 * If gid == (gid_t)-1, the user actually passed in ULONG_MAX,
936 * but this value would get interpreted as (gid_t)-1 by chown
937 * and its siblings. That's not what the user meant! So we
938 * throw an overflow exception instead. (We already
939 * handled a real -1 with PyLong_AsLongAndOverflow() above.)
940 */
941 if (gid == (gid_t)-1)
942 goto overflow;
943
944 /* Ensure the value wasn't truncated. */
945 if (sizeof(gid_t) < sizeof(long) &&
946 (unsigned long)gid != uresult)
947 goto overflow;
948 /* fallthrough */
949
950 success:
951 Py_DECREF(index);
952 *p = gid;
953 return 1;
954
955 underflow:
956 PyErr_SetString(PyExc_OverflowError,
957 "gid is less than minimum");
958 goto fail;
959
960 overflow:
961 PyErr_SetString(PyExc_OverflowError,
962 "gid is greater than maximum");
963 /* fallthrough */
964
965 fail:
966 Py_DECREF(index);
967 return 0;
968 }
969 #endif /* MS_WINDOWS */
970
971
972 static PyObject *
_PyLong_FromDev(dev_t dev)973 _PyLong_FromDev(dev_t dev)
974 {
975 #ifdef NODEV
976 if (dev == NODEV) {
977 return PyLong_FromLongLong((long long)dev);
978 }
979 #endif
980 return PyLong_FromUnsignedLongLong((unsigned long long)dev);
981 }
982
983
984 #if (defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)) || defined(HAVE_DEVICE_MACROS)
985 static int
_Py_Dev_Converter(PyObject * obj,void * p)986 _Py_Dev_Converter(PyObject *obj, void *p)
987 {
988 #ifdef NODEV
989 if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
990 int overflow;
991 long long result = PyLong_AsLongLongAndOverflow(obj, &overflow);
992 if (result == -1 && PyErr_Occurred()) {
993 return 0;
994 }
995 if (!overflow && result == (long long)NODEV) {
996 *((dev_t *)p) = NODEV;
997 return 1;
998 }
999 }
1000 #endif
1001
1002 unsigned long long result = PyLong_AsUnsignedLongLong(obj);
1003 if (result == (unsigned long long)-1 && PyErr_Occurred()) {
1004 return 0;
1005 }
1006 if ((unsigned long long)(dev_t)result != result) {
1007 PyErr_SetString(PyExc_OverflowError,
1008 "Python int too large to convert to C dev_t");
1009 return 0;
1010 }
1011 *((dev_t *)p) = (dev_t)result;
1012 return 1;
1013 }
1014 #endif /* (HAVE_MKNOD && HAVE_MAKEDEV) || HAVE_DEVICE_MACROS */
1015
1016
1017 #ifdef AT_FDCWD
1018 /*
1019 * Why the (int) cast? Solaris 10 defines AT_FDCWD as 0xffd19553 (-3041965);
1020 * without the int cast, the value gets interpreted as uint (4291925331),
1021 * which doesn't play nicely with all the initializer lines in this file that
1022 * look like this:
1023 * int dir_fd = DEFAULT_DIR_FD;
1024 */
1025 #define DEFAULT_DIR_FD (int)AT_FDCWD
1026 #else
1027 #define DEFAULT_DIR_FD (-100)
1028 #endif
1029
1030 static int
_fd_converter(PyObject * o,int * p)1031 _fd_converter(PyObject *o, int *p)
1032 {
1033 int overflow;
1034 long long_value;
1035
1036 if (PyBool_Check(o)) {
1037 if (PyErr_WarnEx(PyExc_RuntimeWarning,
1038 "bool is used as a file descriptor", 1))
1039 {
1040 return 0;
1041 }
1042 }
1043 PyObject *index = _PyNumber_Index(o);
1044 if (index == NULL) {
1045 return 0;
1046 }
1047
1048 assert(PyLong_Check(index));
1049 long_value = PyLong_AsLongAndOverflow(index, &overflow);
1050 Py_DECREF(index);
1051 assert(!PyErr_Occurred());
1052 if (overflow > 0 || long_value > INT_MAX) {
1053 PyErr_SetString(PyExc_OverflowError,
1054 "fd is greater than maximum");
1055 return 0;
1056 }
1057 if (overflow < 0 || long_value < INT_MIN) {
1058 PyErr_SetString(PyExc_OverflowError,
1059 "fd is less than minimum");
1060 return 0;
1061 }
1062
1063 *p = (int)long_value;
1064 return 1;
1065 }
1066
1067 static int
dir_fd_converter(PyObject * o,void * p)1068 dir_fd_converter(PyObject *o, void *p)
1069 {
1070 if (o == Py_None) {
1071 *(int *)p = DEFAULT_DIR_FD;
1072 return 1;
1073 }
1074 else if (PyIndex_Check(o)) {
1075 return _fd_converter(o, (int *)p);
1076 }
1077 else {
1078 PyErr_Format(PyExc_TypeError,
1079 "argument should be integer or None, not %.200s",
1080 _PyType_Name(Py_TYPE(o)));
1081 return 0;
1082 }
1083 }
1084
1085 typedef struct {
1086 PyObject *billion;
1087 PyObject *DirEntryType;
1088 PyObject *ScandirIteratorType;
1089 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
1090 PyObject *SchedParamType;
1091 #endif
1092 newfunc statresult_new_orig;
1093 PyObject *StatResultType;
1094 PyObject *StatVFSResultType;
1095 PyObject *TerminalSizeType;
1096 PyObject *TimesResultType;
1097 PyObject *UnameResultType;
1098 #if defined(HAVE_WAITID)
1099 PyObject *WaitidResultType;
1100 #endif
1101 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
1102 PyObject *struct_rusage;
1103 #endif
1104 PyObject *st_mode;
1105 #ifndef MS_WINDOWS
1106 // times() clock frequency in hertz; used by os.times()
1107 long ticks_per_second;
1108 #endif
1109 } _posixstate;
1110
1111
1112 static inline _posixstate*
get_posix_state(PyObject * module)1113 get_posix_state(PyObject *module)
1114 {
1115 void *state = _PyModule_GetState(module);
1116 assert(state != NULL);
1117 return (_posixstate *)state;
1118 }
1119
1120 /*
1121 * A PyArg_ParseTuple "converter" function
1122 * that handles filesystem paths in the manner
1123 * preferred by the os module.
1124 *
1125 * path_converter accepts (Unicode) strings and their
1126 * subclasses, and bytes and their subclasses. What
1127 * it does with the argument depends on path.make_wide:
1128 *
1129 * * If path.make_wide is nonzero, if we get a (Unicode)
1130 * string we extract the wchar_t * and return it; if we
1131 * get bytes we decode to wchar_t * and return that.
1132 *
1133 * * If path.make_wide is zero, if we get bytes we extract
1134 * the char_t * and return it; if we get a (Unicode)
1135 * string we encode to char_t * and return that.
1136 *
1137 * path_converter also optionally accepts signed
1138 * integers (representing open file descriptors) instead
1139 * of path strings.
1140 *
1141 * Input fields:
1142 * path.nullable
1143 * If nonzero, the path is permitted to be None.
1144 * path.nonstrict
1145 * If nonzero, the path is permitted to contain
1146 * embedded null characters and have any length.
1147 * path.make_wide
1148 * If nonzero, the converter always uses wide, decoding if necessary, else
1149 * it always uses narrow, encoding if necessary. The default value is
1150 * nonzero on Windows, else zero.
1151 * path.suppress_value_error
1152 * If nonzero, raising ValueError is suppressed.
1153 * path.allow_fd
1154 * If nonzero, the path is permitted to be a file handle
1155 * (a signed int) instead of a string.
1156 * path.function_name
1157 * If non-NULL, path_converter will use that as the name
1158 * of the function in error messages.
1159 * (If path.function_name is NULL it omits the function name.)
1160 * path.argument_name
1161 * If non-NULL, path_converter will use that as the name
1162 * of the parameter in error messages.
1163 * (If path.argument_name is NULL it uses "path".)
1164 *
1165 * Output fields:
1166 * path.wide
1167 * Points to the path if it was expressed as Unicode
1168 * or if it was bytes and decoded to Unicode.
1169 * path.narrow
1170 * Points to the path if it was expressed as bytes,
1171 * or if it was Unicode and encoded to bytes.
1172 * path.fd
1173 * Contains a file descriptor if path.accept_fd was true
1174 * and the caller provided a signed integer instead of any
1175 * sort of string.
1176 *
1177 * WARNING: if your "path" parameter is optional, and is
1178 * unspecified, path_converter will never get called.
1179 * So if you set allow_fd, you *MUST* initialize path.fd = -1
1180 * yourself!
1181 * path.value_error
1182 * If nonzero, then suppress_value_error was specified and a ValueError
1183 * occurred.
1184 * path.length
1185 * The length of the path in characters, if specified as
1186 * a string.
1187 * path.object
1188 * The original object passed in (if get a PathLike object,
1189 * the result of PyOS_FSPath() is treated as the original object).
1190 * Own a reference to the object.
1191 * path.cleanup
1192 * For internal use only. May point to a temporary object.
1193 * (Pay no attention to the man behind the curtain.)
1194 *
1195 * At most one of path.wide or path.narrow will be non-NULL.
1196 * If path was None and path.nullable was set,
1197 * or if path was an integer and path.allow_fd was set,
1198 * both path.wide and path.narrow will be NULL
1199 * and path.length will be 0.
1200 *
1201 * path_converter takes care to not write to the path_t
1202 * unless it's successful. However it must reset the
1203 * "cleanup" field each time it's called.
1204 *
1205 * Use as follows:
1206 * path_t path;
1207 * memset(&path, 0, sizeof(path));
1208 * PyArg_ParseTuple(args, "O&", path_converter, &path);
1209 * // ... use values from path ...
1210 * path_cleanup(&path);
1211 *
1212 * (Note that if PyArg_Parse fails you don't need to call
1213 * path_cleanup(). However it is safe to do so.)
1214 */
1215 typedef struct {
1216 // Input fields
1217 const char *function_name;
1218 const char *argument_name;
1219 int nullable;
1220 int nonstrict;
1221 int make_wide;
1222 int suppress_value_error;
1223 int allow_fd;
1224 // Output fields
1225 const wchar_t *wide;
1226 const char *narrow;
1227 int fd;
1228 int value_error;
1229 Py_ssize_t length;
1230 PyObject *object;
1231 PyObject *cleanup;
1232 } path_t;
1233
1234 #define PATH_T_INITIALIZE(function_name, argument_name, nullable, nonstrict, \
1235 make_wide, suppress_value_error, allow_fd) \
1236 {function_name, argument_name, nullable, nonstrict, make_wide, \
1237 suppress_value_error, allow_fd, NULL, NULL, -1, 0, 0, NULL, NULL}
1238 #ifdef MS_WINDOWS
1239 #define PATH_T_INITIALIZE_P(function_name, argument_name, nullable, \
1240 nonstrict, suppress_value_error, allow_fd) \
1241 PATH_T_INITIALIZE(function_name, argument_name, nullable, nonstrict, 1, \
1242 suppress_value_error, allow_fd)
1243 #else
1244 #define PATH_T_INITIALIZE_P(function_name, argument_name, nullable, \
1245 nonstrict, suppress_value_error, allow_fd) \
1246 PATH_T_INITIALIZE(function_name, argument_name, nullable, nonstrict, 0, \
1247 suppress_value_error, allow_fd)
1248 #endif
1249
1250 static void
path_cleanup(path_t * path)1251 path_cleanup(path_t *path)
1252 {
1253 wchar_t *wide = (wchar_t *)path->wide;
1254 path->wide = NULL;
1255 PyMem_Free(wide);
1256 Py_CLEAR(path->object);
1257 Py_CLEAR(path->cleanup);
1258 }
1259
1260 static int
path_converter(PyObject * o,void * p)1261 path_converter(PyObject *o, void *p)
1262 {
1263 path_t *path = (path_t *)p;
1264 PyObject *bytes = NULL;
1265 Py_ssize_t length = 0;
1266 int is_index, is_bytes, is_unicode;
1267 const char *narrow;
1268 PyObject *wo = NULL;
1269 wchar_t *wide = NULL;
1270
1271 #define FORMAT_EXCEPTION(exc, fmt) \
1272 PyErr_Format(exc, "%s%s" fmt, \
1273 path->function_name ? path->function_name : "", \
1274 path->function_name ? ": " : "", \
1275 path->argument_name ? path->argument_name : "path")
1276
1277 /* Py_CLEANUP_SUPPORTED support */
1278 if (o == NULL) {
1279 path_cleanup(path);
1280 return 1;
1281 }
1282
1283 /* Ensure it's always safe to call path_cleanup(). */
1284 path->object = path->cleanup = NULL;
1285 /* path->object owns a reference to the original object */
1286 Py_INCREF(o);
1287
1288 if ((o == Py_None) && path->nullable) {
1289 path->wide = NULL;
1290 path->narrow = NULL;
1291 path->fd = -1;
1292 goto success_exit;
1293 }
1294
1295 /* Only call this here so that we don't treat the return value of
1296 os.fspath() as an fd or buffer. */
1297 is_index = path->allow_fd && PyIndex_Check(o);
1298 is_bytes = PyBytes_Check(o);
1299 is_unicode = PyUnicode_Check(o);
1300
1301 if (!is_index && !is_unicode && !is_bytes) {
1302 /* Inline PyOS_FSPath() for better error messages. */
1303 PyObject *func, *res;
1304
1305 func = _PyObject_LookupSpecial(o, &_Py_ID(__fspath__));
1306 if ((NULL == func) || (func == Py_None)) {
1307 goto error_format;
1308 }
1309 res = _PyObject_CallNoArgs(func);
1310 Py_DECREF(func);
1311 if (NULL == res) {
1312 goto error_exit;
1313 }
1314 else if (PyUnicode_Check(res)) {
1315 is_unicode = 1;
1316 }
1317 else if (PyBytes_Check(res)) {
1318 is_bytes = 1;
1319 }
1320 else {
1321 PyErr_Format(PyExc_TypeError,
1322 "expected %.200s.__fspath__() to return str or bytes, "
1323 "not %.200s", _PyType_Name(Py_TYPE(o)),
1324 _PyType_Name(Py_TYPE(res)));
1325 Py_DECREF(res);
1326 goto error_exit;
1327 }
1328
1329 /* still owns a reference to the original object */
1330 Py_SETREF(o, res);
1331 }
1332
1333 if (is_unicode) {
1334 if (path->make_wide) {
1335 wide = PyUnicode_AsWideCharString(o, &length);
1336 if (!wide) {
1337 goto error_exit;
1338 }
1339 #ifdef MS_WINDOWS
1340 if (!path->nonstrict && length > 32767) {
1341 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
1342 goto error_exit;
1343 }
1344 #endif
1345 if (!path->nonstrict && wcslen(wide) != (size_t)length) {
1346 FORMAT_EXCEPTION(PyExc_ValueError,
1347 "embedded null character in %s");
1348 goto error_exit;
1349 }
1350
1351 path->wide = wide;
1352 path->narrow = NULL;
1353 path->fd = -1;
1354 wide = NULL;
1355 goto success_exit;
1356 }
1357 bytes = PyUnicode_EncodeFSDefault(o);
1358 if (!bytes) {
1359 goto error_exit;
1360 }
1361 }
1362 else if (is_bytes) {
1363 bytes = Py_NewRef(o);
1364 }
1365 else if (is_index) {
1366 if (!_fd_converter(o, &path->fd)) {
1367 goto error_exit;
1368 }
1369 path->wide = NULL;
1370 path->narrow = NULL;
1371 goto success_exit;
1372 }
1373 else {
1374 error_format:
1375 PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s",
1376 path->function_name ? path->function_name : "",
1377 path->function_name ? ": " : "",
1378 path->argument_name ? path->argument_name : "path",
1379 path->allow_fd && path->nullable ? "string, bytes, os.PathLike, "
1380 "integer or None" :
1381 path->allow_fd ? "string, bytes, os.PathLike or integer" :
1382 path->nullable ? "string, bytes, os.PathLike or None" :
1383 "string, bytes or os.PathLike",
1384 _PyType_Name(Py_TYPE(o)));
1385 goto error_exit;
1386 }
1387
1388 length = PyBytes_GET_SIZE(bytes);
1389 narrow = PyBytes_AS_STRING(bytes);
1390 if (!path->nonstrict && strlen(narrow) != (size_t)length) {
1391 FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
1392 goto error_exit;
1393 }
1394
1395 if (path->make_wide) {
1396 wo = PyUnicode_DecodeFSDefaultAndSize(narrow, length);
1397 if (!wo) {
1398 goto error_exit;
1399 }
1400
1401 wide = PyUnicode_AsWideCharString(wo, &length);
1402 Py_DECREF(wo);
1403 if (!wide) {
1404 goto error_exit;
1405 }
1406 #ifdef MS_WINDOWS
1407 if (!path->nonstrict && length > 32767) {
1408 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
1409 goto error_exit;
1410 }
1411 #endif
1412 if (!path->nonstrict && wcslen(wide) != (size_t)length) {
1413 FORMAT_EXCEPTION(PyExc_ValueError,
1414 "embedded null character in %s");
1415 goto error_exit;
1416 }
1417 path->wide = wide;
1418 path->narrow = NULL;
1419 Py_DECREF(bytes);
1420 wide = NULL;
1421 }
1422 else {
1423 path->wide = NULL;
1424 path->narrow = narrow;
1425 if (bytes == o) {
1426 /* Still a reference owned by path->object, don't have to
1427 worry about path->narrow is used after free. */
1428 Py_DECREF(bytes);
1429 }
1430 else {
1431 path->cleanup = bytes;
1432 }
1433 }
1434 path->fd = -1;
1435
1436 success_exit:
1437 path->value_error = 0;
1438 path->length = length;
1439 path->object = o;
1440 return Py_CLEANUP_SUPPORTED;
1441
1442 error_exit:
1443 Py_XDECREF(o);
1444 Py_XDECREF(bytes);
1445 PyMem_Free(wide);
1446 if (!path->suppress_value_error ||
1447 !PyErr_ExceptionMatches(PyExc_ValueError))
1448 {
1449 return 0;
1450 }
1451 PyErr_Clear();
1452 path->wide = NULL;
1453 path->narrow = NULL;
1454 path->fd = -1;
1455 path->value_error = 1;
1456 path->length = 0;
1457 path->object = NULL;
1458 return Py_CLEANUP_SUPPORTED;
1459 }
1460
1461 static void
argument_unavailable_error(const char * function_name,const char * argument_name)1462 argument_unavailable_error(const char *function_name, const char *argument_name)
1463 {
1464 PyErr_Format(PyExc_NotImplementedError,
1465 "%s%s%s unavailable on this platform",
1466 (function_name != NULL) ? function_name : "",
1467 (function_name != NULL) ? ": ": "",
1468 argument_name);
1469 }
1470
1471 static int
dir_fd_unavailable(PyObject * o,void * p)1472 dir_fd_unavailable(PyObject *o, void *p)
1473 {
1474 int dir_fd;
1475 if (!dir_fd_converter(o, &dir_fd))
1476 return 0;
1477 if (dir_fd != DEFAULT_DIR_FD) {
1478 argument_unavailable_error(NULL, "dir_fd");
1479 return 0;
1480 }
1481 *(int *)p = dir_fd;
1482 return 1;
1483 }
1484
1485 static int
fd_specified(const char * function_name,int fd)1486 fd_specified(const char *function_name, int fd)
1487 {
1488 if (fd == -1)
1489 return 0;
1490
1491 argument_unavailable_error(function_name, "fd");
1492 return 1;
1493 }
1494
1495 static int
follow_symlinks_specified(const char * function_name,int follow_symlinks)1496 follow_symlinks_specified(const char *function_name, int follow_symlinks)
1497 {
1498 if (follow_symlinks)
1499 return 0;
1500
1501 argument_unavailable_error(function_name, "follow_symlinks");
1502 return 1;
1503 }
1504
1505 static int
path_and_dir_fd_invalid(const char * function_name,path_t * path,int dir_fd)1506 path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd)
1507 {
1508 if (!path->wide && (dir_fd != DEFAULT_DIR_FD) && !path->narrow) {
1509 PyErr_Format(PyExc_ValueError,
1510 "%s: can't specify dir_fd without matching path",
1511 function_name);
1512 return 1;
1513 }
1514 return 0;
1515 }
1516
1517 static int
dir_fd_and_fd_invalid(const char * function_name,int dir_fd,int fd)1518 dir_fd_and_fd_invalid(const char *function_name, int dir_fd, int fd)
1519 {
1520 if ((dir_fd != DEFAULT_DIR_FD) && (fd != -1)) {
1521 PyErr_Format(PyExc_ValueError,
1522 "%s: can't specify both dir_fd and fd",
1523 function_name);
1524 return 1;
1525 }
1526 return 0;
1527 }
1528
1529 static int
fd_and_follow_symlinks_invalid(const char * function_name,int fd,int follow_symlinks)1530 fd_and_follow_symlinks_invalid(const char *function_name, int fd,
1531 int follow_symlinks)
1532 {
1533 if ((fd > 0) && (!follow_symlinks)) {
1534 PyErr_Format(PyExc_ValueError,
1535 "%s: cannot use fd and follow_symlinks together",
1536 function_name);
1537 return 1;
1538 }
1539 return 0;
1540 }
1541
1542 static int
dir_fd_and_follow_symlinks_invalid(const char * function_name,int dir_fd,int follow_symlinks)1543 dir_fd_and_follow_symlinks_invalid(const char *function_name, int dir_fd,
1544 int follow_symlinks)
1545 {
1546 if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
1547 PyErr_Format(PyExc_ValueError,
1548 "%s: cannot use dir_fd and follow_symlinks together",
1549 function_name);
1550 return 1;
1551 }
1552 return 0;
1553 }
1554
1555 #ifdef MS_WINDOWS
1556 typedef long long Py_off_t;
1557 #else
1558 typedef off_t Py_off_t;
1559 #endif
1560
1561 static int
Py_off_t_converter(PyObject * arg,void * addr)1562 Py_off_t_converter(PyObject *arg, void *addr)
1563 {
1564 #ifdef HAVE_LARGEFILE_SUPPORT
1565 *((Py_off_t *)addr) = PyLong_AsLongLong(arg);
1566 #else
1567 *((Py_off_t *)addr) = PyLong_AsLong(arg);
1568 #endif
1569 if (PyErr_Occurred())
1570 return 0;
1571 return 1;
1572 }
1573
1574 static PyObject *
PyLong_FromPy_off_t(Py_off_t offset)1575 PyLong_FromPy_off_t(Py_off_t offset)
1576 {
1577 #ifdef HAVE_LARGEFILE_SUPPORT
1578 return PyLong_FromLongLong(offset);
1579 #else
1580 return PyLong_FromLong(offset);
1581 #endif
1582 }
1583
1584 #ifdef HAVE_SIGSET_T
1585 /* Convert an iterable of integers to a sigset.
1586 Return 1 on success, return 0 and raise an exception on error. */
1587 int
_Py_Sigset_Converter(PyObject * obj,void * addr)1588 _Py_Sigset_Converter(PyObject *obj, void *addr)
1589 {
1590 sigset_t *mask = (sigset_t *)addr;
1591 PyObject *iterator, *item;
1592 long signum;
1593 int overflow;
1594
1595 // The extra parens suppress the unreachable-code warning with clang on MacOS
1596 if (sigemptyset(mask) < (0)) {
1597 /* Probably only if mask == NULL. */
1598 PyErr_SetFromErrno(PyExc_OSError);
1599 return 0;
1600 }
1601
1602 iterator = PyObject_GetIter(obj);
1603 if (iterator == NULL) {
1604 return 0;
1605 }
1606
1607 while ((item = PyIter_Next(iterator)) != NULL) {
1608 signum = PyLong_AsLongAndOverflow(item, &overflow);
1609 Py_DECREF(item);
1610 if (signum <= 0 || signum >= Py_NSIG) {
1611 if (overflow || signum != -1 || !PyErr_Occurred()) {
1612 PyErr_Format(PyExc_ValueError,
1613 "signal number %ld out of range [1; %i]",
1614 signum, Py_NSIG - 1);
1615 }
1616 goto error;
1617 }
1618 if (sigaddset(mask, (int)signum)) {
1619 if (errno != EINVAL) {
1620 /* Probably impossible */
1621 PyErr_SetFromErrno(PyExc_OSError);
1622 goto error;
1623 }
1624 /* For backwards compatibility, allow idioms such as
1625 * `range(1, NSIG)` but warn about invalid signal numbers
1626 */
1627 const char msg[] =
1628 "invalid signal number %ld, please use valid_signals()";
1629 if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1, msg, signum)) {
1630 goto error;
1631 }
1632 }
1633 }
1634 if (!PyErr_Occurred()) {
1635 Py_DECREF(iterator);
1636 return 1;
1637 }
1638
1639 error:
1640 Py_DECREF(iterator);
1641 return 0;
1642 }
1643 #endif /* HAVE_SIGSET_T */
1644
1645 /* Return a dictionary corresponding to the POSIX environment table */
1646 #if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
1647 /* On Darwin/MacOSX a shared library or framework has no access to
1648 ** environ directly, we must obtain it with _NSGetEnviron(). See also
1649 ** man environ(7).
1650 */
1651 #include <crt_externs.h>
1652 #define USE_DARWIN_NS_GET_ENVIRON 1
1653 #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__))
1654 extern char **environ;
1655 #endif /* !_MSC_VER */
1656
1657 static PyObject *
convertenviron(void)1658 convertenviron(void)
1659 {
1660 PyObject *d;
1661 #ifdef MS_WINDOWS
1662 wchar_t **e;
1663 #else
1664 char **e;
1665 #endif
1666
1667 d = PyDict_New();
1668 if (d == NULL)
1669 return NULL;
1670 #ifdef MS_WINDOWS
1671 /* _wenviron must be initialized in this way if the program is started
1672 through main() instead of wmain(). */
1673 (void)_wgetenv(L"");
1674 e = _wenviron;
1675 #elif defined(USE_DARWIN_NS_GET_ENVIRON)
1676 /* environ is not accessible as an extern in a shared object on OSX; use
1677 _NSGetEnviron to resolve it. The value changes if you add environment
1678 variables between calls to Py_Initialize, so don't cache the value. */
1679 e = *_NSGetEnviron();
1680 #else
1681 e = environ;
1682 #endif
1683 if (e == NULL)
1684 return d;
1685 for (; *e != NULL; e++) {
1686 PyObject *k;
1687 PyObject *v;
1688 #ifdef MS_WINDOWS
1689 const wchar_t *p = wcschr(*e, L'=');
1690 #else
1691 const char *p = strchr(*e, '=');
1692 #endif
1693 if (p == NULL)
1694 continue;
1695 #ifdef MS_WINDOWS
1696 k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e));
1697 #else
1698 k = PyBytes_FromStringAndSize(*e, (int)(p-*e));
1699 #endif
1700 if (k == NULL) {
1701 Py_DECREF(d);
1702 return NULL;
1703 }
1704 #ifdef MS_WINDOWS
1705 v = PyUnicode_FromWideChar(p+1, wcslen(p+1));
1706 #else
1707 v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
1708 #endif
1709 if (v == NULL) {
1710 Py_DECREF(k);
1711 Py_DECREF(d);
1712 return NULL;
1713 }
1714 if (PyDict_SetDefaultRef(d, k, v, NULL) < 0) {
1715 Py_DECREF(v);
1716 Py_DECREF(k);
1717 Py_DECREF(d);
1718 return NULL;
1719 }
1720 Py_DECREF(k);
1721 Py_DECREF(v);
1722 }
1723 return d;
1724 }
1725
1726 /* Set a POSIX-specific error from errno, and return NULL */
1727
1728 static PyObject *
posix_error(void)1729 posix_error(void)
1730 {
1731 return PyErr_SetFromErrno(PyExc_OSError);
1732 }
1733
1734 #ifdef MS_WINDOWS
1735 static PyObject *
win32_error(const char * function,const char * filename)1736 win32_error(const char* function, const char* filename)
1737 {
1738 /* XXX We should pass the function name along in the future.
1739 (winreg.c also wants to pass the function name.)
1740 This would however require an additional param to the
1741 Windows error object, which is non-trivial.
1742 */
1743 errno = GetLastError();
1744 if (filename)
1745 return PyErr_SetFromWindowsErrWithFilename(errno, filename);
1746 else
1747 return PyErr_SetFromWindowsErr(errno);
1748 }
1749
1750 static PyObject *
win32_error_object_err(const char * function,PyObject * filename,DWORD err)1751 win32_error_object_err(const char* function, PyObject* filename, DWORD err)
1752 {
1753 /* XXX - see win32_error for comments on 'function' */
1754 if (filename)
1755 return PyErr_SetExcFromWindowsErrWithFilenameObject(
1756 PyExc_OSError,
1757 err,
1758 filename);
1759 else
1760 return PyErr_SetFromWindowsErr(err);
1761 }
1762
1763 static PyObject *
win32_error_object(const char * function,PyObject * filename)1764 win32_error_object(const char* function, PyObject* filename)
1765 {
1766 errno = GetLastError();
1767 return win32_error_object_err(function, filename, errno);
1768 }
1769
1770 #endif /* MS_WINDOWS */
1771
1772 static PyObject *
posix_path_object_error(PyObject * path)1773 posix_path_object_error(PyObject *path)
1774 {
1775 return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
1776 }
1777
1778 static PyObject *
path_object_error(PyObject * path)1779 path_object_error(PyObject *path)
1780 {
1781 #ifdef MS_WINDOWS
1782 return PyErr_SetExcFromWindowsErrWithFilenameObject(
1783 PyExc_OSError, 0, path);
1784 #else
1785 return posix_path_object_error(path);
1786 #endif
1787 }
1788
1789 static PyObject *
path_object_error2(PyObject * path,PyObject * path2)1790 path_object_error2(PyObject *path, PyObject *path2)
1791 {
1792 #ifdef MS_WINDOWS
1793 return PyErr_SetExcFromWindowsErrWithFilenameObjects(
1794 PyExc_OSError, 0, path, path2);
1795 #else
1796 return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path, path2);
1797 #endif
1798 }
1799
1800 static PyObject *
path_error(path_t * path)1801 path_error(path_t *path)
1802 {
1803 return path_object_error(path->object);
1804 }
1805
1806 static PyObject *
posix_path_error(path_t * path)1807 posix_path_error(path_t *path)
1808 {
1809 return posix_path_object_error(path->object);
1810 }
1811
1812 static PyObject *
path_error2(path_t * path,path_t * path2)1813 path_error2(path_t *path, path_t *path2)
1814 {
1815 return path_object_error2(path->object, path2->object);
1816 }
1817
1818
1819 /* POSIX generic methods */
1820
1821 static PyObject *
posix_fildes_fd(int fd,int (* func)(int))1822 posix_fildes_fd(int fd, int (*func)(int))
1823 {
1824 int res;
1825 int async_err = 0;
1826
1827 do {
1828 Py_BEGIN_ALLOW_THREADS
1829 _Py_BEGIN_SUPPRESS_IPH
1830 res = (*func)(fd);
1831 _Py_END_SUPPRESS_IPH
1832 Py_END_ALLOW_THREADS
1833 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
1834 if (res != 0)
1835 return (!async_err) ? posix_error() : NULL;
1836 Py_RETURN_NONE;
1837 }
1838
1839
1840 #ifdef MS_WINDOWS
1841 /* This is a reimplementation of the C library's chdir function,
1842 but one that produces Win32 errors instead of DOS error codes.
1843 chdir is essentially a wrapper around SetCurrentDirectory; however,
1844 it also needs to set "magic" environment variables indicating
1845 the per-drive current directory, which are of the form =<drive>: */
1846 static BOOL __stdcall
win32_wchdir(LPCWSTR path)1847 win32_wchdir(LPCWSTR path)
1848 {
1849 wchar_t path_buf[MAX_PATH], *new_path = path_buf;
1850 int result;
1851 wchar_t env[4] = L"=x:";
1852
1853 if(!SetCurrentDirectoryW(path))
1854 return FALSE;
1855 result = GetCurrentDirectoryW(Py_ARRAY_LENGTH(path_buf), new_path);
1856 if (!result)
1857 return FALSE;
1858 if (result > Py_ARRAY_LENGTH(path_buf)) {
1859 new_path = PyMem_RawMalloc(result * sizeof(wchar_t));
1860 if (!new_path) {
1861 SetLastError(ERROR_OUTOFMEMORY);
1862 return FALSE;
1863 }
1864 result = GetCurrentDirectoryW(result, new_path);
1865 if (!result) {
1866 PyMem_RawFree(new_path);
1867 return FALSE;
1868 }
1869 }
1870 int is_unc_like_path = (wcsncmp(new_path, L"\\\\", 2) == 0 ||
1871 wcsncmp(new_path, L"//", 2) == 0);
1872 if (!is_unc_like_path) {
1873 env[1] = new_path[0];
1874 result = SetEnvironmentVariableW(env, new_path);
1875 }
1876 if (new_path != path_buf)
1877 PyMem_RawFree(new_path);
1878 return result ? TRUE : FALSE;
1879 }
1880 #endif
1881
1882 #ifdef MS_WINDOWS
1883 /* The CRT of Windows has a number of flaws wrt. its stat() implementation:
1884 - time stamps are restricted to second resolution
1885 - file modification times suffer from forth-and-back conversions between
1886 UTC and local time
1887 Therefore, we implement our own stat, based on the Win32 API directly.
1888 */
1889 #define HAVE_STAT_NSEC 1
1890 #define HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES 1
1891 #define HAVE_STRUCT_STAT_ST_REPARSE_TAG 1
1892
1893 static void
find_data_to_file_info(WIN32_FIND_DATAW * pFileData,BY_HANDLE_FILE_INFORMATION * info,ULONG * reparse_tag)1894 find_data_to_file_info(WIN32_FIND_DATAW *pFileData,
1895 BY_HANDLE_FILE_INFORMATION *info,
1896 ULONG *reparse_tag)
1897 {
1898 memset(info, 0, sizeof(*info));
1899 info->dwFileAttributes = pFileData->dwFileAttributes;
1900 info->ftCreationTime = pFileData->ftCreationTime;
1901 info->ftLastAccessTime = pFileData->ftLastAccessTime;
1902 info->ftLastWriteTime = pFileData->ftLastWriteTime;
1903 info->nFileSizeHigh = pFileData->nFileSizeHigh;
1904 info->nFileSizeLow = pFileData->nFileSizeLow;
1905 /* info->nNumberOfLinks = 1; */
1906 if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1907 *reparse_tag = pFileData->dwReserved0;
1908 else
1909 *reparse_tag = 0;
1910 }
1911
1912 static BOOL
attributes_from_dir(LPCWSTR pszFile,BY_HANDLE_FILE_INFORMATION * info,ULONG * reparse_tag)1913 attributes_from_dir(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag)
1914 {
1915 HANDLE hFindFile;
1916 WIN32_FIND_DATAW FileData;
1917 LPCWSTR filename = pszFile;
1918 size_t n = wcslen(pszFile);
1919 if (n && (pszFile[n - 1] == L'\\' || pszFile[n - 1] == L'/')) {
1920 // cannot use PyMem_Malloc here because we do not hold the GIL
1921 filename = (LPCWSTR)malloc((n + 1) * sizeof(filename[0]));
1922 if(!filename) {
1923 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1924 return FALSE;
1925 }
1926 wcsncpy_s((LPWSTR)filename, n + 1, pszFile, n);
1927 while (--n > 0 && (filename[n] == L'\\' || filename[n] == L'/')) {
1928 ((LPWSTR)filename)[n] = L'\0';
1929 }
1930 if (!n || (n == 1 && filename[1] == L':')) {
1931 // Nothing left to query
1932 free((void *)filename);
1933 return FALSE;
1934 }
1935 }
1936 hFindFile = FindFirstFileW(filename, &FileData);
1937 if (pszFile != filename) {
1938 free((void *)filename);
1939 }
1940 if (hFindFile == INVALID_HANDLE_VALUE) {
1941 return FALSE;
1942 }
1943 FindClose(hFindFile);
1944 find_data_to_file_info(&FileData, info, reparse_tag);
1945 return TRUE;
1946 }
1947
1948
1949 static void
update_st_mode_from_path(const wchar_t * path,DWORD attr,struct _Py_stat_struct * result)1950 update_st_mode_from_path(const wchar_t *path, DWORD attr,
1951 struct _Py_stat_struct *result)
1952 {
1953 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
1954 /* Fix the file execute permissions. This hack sets S_IEXEC if
1955 the filename has an extension that is commonly used by files
1956 that CreateProcessW can execute. A real implementation calls
1957 GetSecurityInfo, OpenThreadToken/OpenProcessToken, and
1958 AccessCheck to check for generic read, write, and execute
1959 access. */
1960 const wchar_t *fileExtension = wcsrchr(path, '.');
1961 if (fileExtension) {
1962 if (_wcsicmp(fileExtension, L".exe") == 0 ||
1963 _wcsicmp(fileExtension, L".bat") == 0 ||
1964 _wcsicmp(fileExtension, L".cmd") == 0 ||
1965 _wcsicmp(fileExtension, L".com") == 0) {
1966 result->st_mode |= 0111;
1967 }
1968 }
1969 }
1970 }
1971
1972
1973 static int
win32_xstat_slow_impl(const wchar_t * path,struct _Py_stat_struct * result,BOOL traverse)1974 win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result,
1975 BOOL traverse)
1976 {
1977 HANDLE hFile;
1978 BY_HANDLE_FILE_INFORMATION fileInfo;
1979 FILE_BASIC_INFO basicInfo;
1980 FILE_BASIC_INFO *pBasicInfo = NULL;
1981 FILE_ID_INFO idInfo;
1982 FILE_ID_INFO *pIdInfo = NULL;
1983 FILE_ATTRIBUTE_TAG_INFO tagInfo = { 0 };
1984 DWORD fileType, error;
1985 BOOL isUnhandledTag = FALSE;
1986 int retval = 0;
1987
1988 DWORD access = FILE_READ_ATTRIBUTES;
1989 DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; /* Allow opening directories. */
1990 if (!traverse) {
1991 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
1992 }
1993
1994 hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING, flags, NULL);
1995 if (hFile == INVALID_HANDLE_VALUE) {
1996 /* Either the path doesn't exist, or the caller lacks access. */
1997 error = GetLastError();
1998 switch (error) {
1999 case ERROR_ACCESS_DENIED: /* Cannot sync or read attributes. */
2000 case ERROR_SHARING_VIOLATION: /* It's a paging file. */
2001 /* Try reading the parent directory. */
2002 if (!attributes_from_dir(path, &fileInfo, &tagInfo.ReparseTag)) {
2003 /* Cannot read the parent directory. */
2004 switch (GetLastError()) {
2005 case ERROR_FILE_NOT_FOUND: /* File cannot be found */
2006 case ERROR_PATH_NOT_FOUND: /* File parent directory cannot be found */
2007 case ERROR_NOT_READY: /* Drive exists but unavailable */
2008 case ERROR_BAD_NET_NAME: /* Remote drive unavailable */
2009 break;
2010 /* Restore the error from CreateFileW(). */
2011 default:
2012 SetLastError(error);
2013 }
2014
2015 return -1;
2016 }
2017 if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
2018 if (traverse ||
2019 !IsReparseTagNameSurrogate(tagInfo.ReparseTag)) {
2020 /* The stat call has to traverse but cannot, so fail. */
2021 SetLastError(error);
2022 return -1;
2023 }
2024 }
2025 break;
2026
2027 case ERROR_INVALID_PARAMETER:
2028 /* \\.\con requires read or write access. */
2029 hFile = CreateFileW(path, access | GENERIC_READ,
2030 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2031 OPEN_EXISTING, flags, NULL);
2032 if (hFile == INVALID_HANDLE_VALUE) {
2033 SetLastError(error);
2034 return -1;
2035 }
2036 break;
2037
2038 case ERROR_CANT_ACCESS_FILE:
2039 /* bpo37834: open unhandled reparse points if traverse fails. */
2040 if (traverse) {
2041 traverse = FALSE;
2042 isUnhandledTag = TRUE;
2043 hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING,
2044 flags | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
2045 }
2046 if (hFile == INVALID_HANDLE_VALUE) {
2047 SetLastError(error);
2048 return -1;
2049 }
2050 break;
2051
2052 default:
2053 return -1;
2054 }
2055 }
2056
2057 if (hFile != INVALID_HANDLE_VALUE) {
2058 /* Handle types other than files on disk. */
2059 fileType = GetFileType(hFile);
2060 if (fileType != FILE_TYPE_DISK) {
2061 if (fileType == FILE_TYPE_UNKNOWN && GetLastError() != 0) {
2062 retval = -1;
2063 goto cleanup;
2064 }
2065 DWORD fileAttributes = GetFileAttributesW(path);
2066 memset(result, 0, sizeof(*result));
2067 if (fileAttributes != INVALID_FILE_ATTRIBUTES &&
2068 fileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2069 /* \\.\pipe\ or \\.\mailslot\ */
2070 result->st_mode = _S_IFDIR;
2071 } else if (fileType == FILE_TYPE_CHAR) {
2072 /* \\.\nul */
2073 result->st_mode = _S_IFCHR;
2074 } else if (fileType == FILE_TYPE_PIPE) {
2075 /* \\.\pipe\spam */
2076 result->st_mode = _S_IFIFO;
2077 }
2078 /* FILE_TYPE_UNKNOWN, e.g. \\.\mailslot\waitfor.exe\spam */
2079 goto cleanup;
2080 }
2081
2082 /* Query the reparse tag, and traverse a non-link. */
2083 if (!traverse) {
2084 if (!GetFileInformationByHandleEx(hFile, FileAttributeTagInfo,
2085 &tagInfo, sizeof(tagInfo))) {
2086 /* Allow devices that do not support FileAttributeTagInfo. */
2087 switch (GetLastError()) {
2088 case ERROR_INVALID_PARAMETER:
2089 case ERROR_INVALID_FUNCTION:
2090 case ERROR_NOT_SUPPORTED:
2091 tagInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2092 tagInfo.ReparseTag = 0;
2093 break;
2094 default:
2095 retval = -1;
2096 goto cleanup;
2097 }
2098 } else if (tagInfo.FileAttributes &
2099 FILE_ATTRIBUTE_REPARSE_POINT) {
2100 if (IsReparseTagNameSurrogate(tagInfo.ReparseTag)) {
2101 if (isUnhandledTag) {
2102 /* Traversing previously failed for either this link
2103 or its target. */
2104 SetLastError(ERROR_CANT_ACCESS_FILE);
2105 retval = -1;
2106 goto cleanup;
2107 }
2108 /* Traverse a non-link, but not if traversing already failed
2109 for an unhandled tag. */
2110 } else if (!isUnhandledTag) {
2111 CloseHandle(hFile);
2112 return win32_xstat_slow_impl(path, result, TRUE);
2113 }
2114 }
2115 }
2116
2117 if (!GetFileInformationByHandle(hFile, &fileInfo) ||
2118 !GetFileInformationByHandleEx(hFile, FileBasicInfo,
2119 &basicInfo, sizeof(basicInfo))) {
2120 switch (GetLastError()) {
2121 case ERROR_INVALID_PARAMETER:
2122 case ERROR_INVALID_FUNCTION:
2123 case ERROR_NOT_SUPPORTED:
2124 /* Volumes and physical disks are block devices, e.g.
2125 \\.\C: and \\.\PhysicalDrive0. */
2126 memset(result, 0, sizeof(*result));
2127 result->st_mode = 0x6000; /* S_IFBLK */
2128 goto cleanup;
2129 }
2130 retval = -1;
2131 goto cleanup;
2132 }
2133
2134 /* Successfully got FileBasicInfo, so we'll pass it along */
2135 pBasicInfo = &basicInfo;
2136
2137 if (GetFileInformationByHandleEx(hFile, FileIdInfo, &idInfo, sizeof(idInfo))) {
2138 /* Successfully got FileIdInfo, so pass it along */
2139 pIdInfo = &idInfo;
2140 }
2141 }
2142
2143 _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, pBasicInfo, pIdInfo, result);
2144 update_st_mode_from_path(path, fileInfo.dwFileAttributes, result);
2145
2146 cleanup:
2147 if (hFile != INVALID_HANDLE_VALUE) {
2148 /* Preserve last error if we are failing */
2149 error = retval ? GetLastError() : 0;
2150 if (!CloseHandle(hFile)) {
2151 retval = -1;
2152 } else if (retval) {
2153 /* Restore last error */
2154 SetLastError(error);
2155 }
2156 }
2157
2158 return retval;
2159 }
2160
2161 static int
win32_xstat_impl(const wchar_t * path,struct _Py_stat_struct * result,BOOL traverse)2162 win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result,
2163 BOOL traverse)
2164 {
2165 FILE_STAT_BASIC_INFORMATION statInfo;
2166 if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo,
2167 &statInfo, sizeof(statInfo))) {
2168 if (// Cannot use fast path for reparse points ...
2169 !(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
2170 // ... unless it's a name surrogate (symlink) and we're not following
2171 || (!traverse && IsReparseTagNameSurrogate(statInfo.ReparseTag))
2172 ) {
2173 _Py_stat_basic_info_to_stat(&statInfo, result);
2174 update_st_mode_from_path(path, statInfo.FileAttributes, result);
2175 return 0;
2176 }
2177 } else {
2178 switch(GetLastError()) {
2179 case ERROR_FILE_NOT_FOUND:
2180 case ERROR_PATH_NOT_FOUND:
2181 case ERROR_NOT_READY:
2182 case ERROR_BAD_NET_NAME:
2183 /* These errors aren't worth retrying with the slow path */
2184 return -1;
2185 case ERROR_NOT_SUPPORTED:
2186 /* indicates the API couldn't be loaded */
2187 break;
2188 }
2189 }
2190
2191 return win32_xstat_slow_impl(path, result, traverse);
2192 }
2193
2194 static int
win32_xstat(const wchar_t * path,struct _Py_stat_struct * result,BOOL traverse)2195 win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse)
2196 {
2197 /* Protocol violation: we explicitly clear errno, instead of
2198 setting it to a POSIX error. Callers should use GetLastError. */
2199 int code = win32_xstat_impl(path, result, traverse);
2200 errno = 0;
2201
2202 /* ctime is only deprecated from 3.12, so we copy birthtime across */
2203 result->st_ctime = result->st_birthtime;
2204 result->st_ctime_nsec = result->st_birthtime_nsec;
2205 return code;
2206 }
2207 /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w
2208
2209 In Posix, stat automatically traverses symlinks and returns the stat
2210 structure for the target. In Windows, the equivalent GetFileAttributes by
2211 default does not traverse symlinks and instead returns attributes for
2212 the symlink.
2213
2214 Instead, we will open the file (which *does* traverse symlinks by default)
2215 and GetFileInformationByHandle(). */
2216
2217 static int
win32_lstat(const wchar_t * path,struct _Py_stat_struct * result)2218 win32_lstat(const wchar_t* path, struct _Py_stat_struct *result)
2219 {
2220 return win32_xstat(path, result, FALSE);
2221 }
2222
2223 static int
win32_stat(const wchar_t * path,struct _Py_stat_struct * result)2224 win32_stat(const wchar_t* path, struct _Py_stat_struct *result)
2225 {
2226 return win32_xstat(path, result, TRUE);
2227 }
2228
2229 #endif /* MS_WINDOWS */
2230
2231 PyDoc_STRVAR(stat_result__doc__,
2232 "stat_result: Result from stat, fstat, or lstat.\n\n\
2233 This object may be accessed either as a tuple of\n\
2234 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
2235 or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\
2236 \n\
2237 Posix/windows: If your platform supports st_blksize, st_blocks, st_rdev,\n\
2238 or st_flags, they are available as attributes only.\n\
2239 \n\
2240 See os.stat for more information.");
2241
2242 static PyStructSequence_Field stat_result_fields[] = {
2243 {"st_mode", "protection bits"},
2244 {"st_ino", "inode"},
2245 {"st_dev", "device"},
2246 {"st_nlink", "number of hard links"},
2247 {"st_uid", "user ID of owner"},
2248 {"st_gid", "group ID of owner"},
2249 {"st_size", "total size, in bytes"},
2250 /* The NULL is replaced with PyStructSequence_UnnamedField later. */
2251 {NULL, "integer time of last access"},
2252 {NULL, "integer time of last modification"},
2253 {NULL, "integer time of last change"},
2254 {"st_atime", "time of last access"},
2255 {"st_mtime", "time of last modification"},
2256 {"st_ctime", "time of last change"},
2257 {"st_atime_ns", "time of last access in nanoseconds"},
2258 {"st_mtime_ns", "time of last modification in nanoseconds"},
2259 {"st_ctime_ns", "time of last change in nanoseconds"},
2260 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2261 {"st_blksize", "blocksize for filesystem I/O"},
2262 #endif
2263 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2264 {"st_blocks", "number of blocks allocated"},
2265 #endif
2266 #ifdef HAVE_STRUCT_STAT_ST_RDEV
2267 {"st_rdev", "device type (if inode device)"},
2268 #endif
2269 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2270 {"st_flags", "user defined flags for file"},
2271 #endif
2272 #ifdef HAVE_STRUCT_STAT_ST_GEN
2273 {"st_gen", "generation number"},
2274 #endif
2275 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS)
2276 {"st_birthtime", "time of creation"},
2277 #endif
2278 #ifdef MS_WINDOWS
2279 {"st_birthtime_ns", "time of creation in nanoseconds"},
2280 #endif
2281 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2282 {"st_file_attributes", "Windows file attribute bits"},
2283 #endif
2284 #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2285 {"st_fstype", "Type of filesystem"},
2286 #endif
2287 #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2288 {"st_reparse_tag", "Windows reparse tag"},
2289 #endif
2290 {0}
2291 };
2292
2293 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2294 #define ST_BLKSIZE_IDX 16
2295 #else
2296 #define ST_BLKSIZE_IDX 15
2297 #endif
2298
2299 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2300 #define ST_BLOCKS_IDX (ST_BLKSIZE_IDX+1)
2301 #else
2302 #define ST_BLOCKS_IDX ST_BLKSIZE_IDX
2303 #endif
2304
2305 #ifdef HAVE_STRUCT_STAT_ST_RDEV
2306 #define ST_RDEV_IDX (ST_BLOCKS_IDX+1)
2307 #else
2308 #define ST_RDEV_IDX ST_BLOCKS_IDX
2309 #endif
2310
2311 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2312 #define ST_FLAGS_IDX (ST_RDEV_IDX+1)
2313 #else
2314 #define ST_FLAGS_IDX ST_RDEV_IDX
2315 #endif
2316
2317 #ifdef HAVE_STRUCT_STAT_ST_GEN
2318 #define ST_GEN_IDX (ST_FLAGS_IDX+1)
2319 #else
2320 #define ST_GEN_IDX ST_FLAGS_IDX
2321 #endif
2322
2323 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS)
2324 #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
2325 #else
2326 #define ST_BIRTHTIME_IDX ST_GEN_IDX
2327 #endif
2328
2329 #ifdef MS_WINDOWS
2330 #define ST_BIRTHTIME_NS_IDX (ST_BIRTHTIME_IDX+1)
2331 #else
2332 #define ST_BIRTHTIME_NS_IDX ST_BIRTHTIME_IDX
2333 #endif
2334
2335 #if defined(HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES) || defined(MS_WINDOWS)
2336 #define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_NS_IDX+1)
2337 #else
2338 #define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_NS_IDX
2339 #endif
2340
2341 #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2342 #define ST_FSTYPE_IDX (ST_FILE_ATTRIBUTES_IDX+1)
2343 #else
2344 #define ST_FSTYPE_IDX ST_FILE_ATTRIBUTES_IDX
2345 #endif
2346
2347 #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2348 #define ST_REPARSE_TAG_IDX (ST_FSTYPE_IDX+1)
2349 #else
2350 #define ST_REPARSE_TAG_IDX ST_FSTYPE_IDX
2351 #endif
2352
2353 static PyStructSequence_Desc stat_result_desc = {
2354 "stat_result", /* name */
2355 stat_result__doc__, /* doc */
2356 stat_result_fields,
2357 10
2358 };
2359
2360 PyDoc_STRVAR(statvfs_result__doc__,
2361 "statvfs_result: Result from statvfs or fstatvfs.\n\n\
2362 This object may be accessed either as a tuple of\n\
2363 (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax),\n\
2364 or via the attributes f_bsize, f_frsize, f_blocks, f_bfree, and so on.\n\
2365 \n\
2366 See os.statvfs for more information.");
2367
2368 static PyStructSequence_Field statvfs_result_fields[] = {
2369 {"f_bsize", },
2370 {"f_frsize", },
2371 {"f_blocks", },
2372 {"f_bfree", },
2373 {"f_bavail", },
2374 {"f_files", },
2375 {"f_ffree", },
2376 {"f_favail", },
2377 {"f_flag", },
2378 {"f_namemax",},
2379 {"f_fsid", },
2380 {0}
2381 };
2382
2383 static PyStructSequence_Desc statvfs_result_desc = {
2384 "statvfs_result", /* name */
2385 statvfs_result__doc__, /* doc */
2386 statvfs_result_fields,
2387 10
2388 };
2389
2390 #if defined(HAVE_WAITID)
2391 PyDoc_STRVAR(waitid_result__doc__,
2392 "waitid_result: Result from waitid.\n\n\
2393 This object may be accessed either as a tuple of\n\
2394 (si_pid, si_uid, si_signo, si_status, si_code),\n\
2395 or via the attributes si_pid, si_uid, and so on.\n\
2396 \n\
2397 See os.waitid for more information.");
2398
2399 static PyStructSequence_Field waitid_result_fields[] = {
2400 {"si_pid", },
2401 {"si_uid", },
2402 {"si_signo", },
2403 {"si_status", },
2404 {"si_code", },
2405 {0}
2406 };
2407
2408 static PyStructSequence_Desc waitid_result_desc = {
2409 "waitid_result", /* name */
2410 waitid_result__doc__, /* doc */
2411 waitid_result_fields,
2412 5
2413 };
2414 #endif
2415
2416 static PyObject *
statresult_new(PyTypeObject * type,PyObject * args,PyObject * kwds)2417 statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2418 {
2419 PyStructSequence *result;
2420 int i;
2421
2422 // ht_module doesn't get set in PyStructSequence_NewType(),
2423 // so we can't use PyType_GetModule().
2424 PyObject *mod = PyImport_GetModule(MODNAME_OBJ);
2425 if (mod == NULL) {
2426 return NULL;
2427 }
2428 _posixstate *state = get_posix_state(mod);
2429 Py_DECREF(mod);
2430 if (state == NULL) {
2431 return NULL;
2432 }
2433 #define structseq_new state->statresult_new_orig
2434
2435 result = (PyStructSequence*)structseq_new(type, args, kwds);
2436 if (!result)
2437 return NULL;
2438 /* If we have been initialized from a tuple,
2439 st_?time might be set to None. Initialize it
2440 from the int slots. */
2441 for (i = 7; i <= 9; i++) {
2442 if (result->ob_item[i+3] == Py_None) {
2443 Py_DECREF(Py_None);
2444 result->ob_item[i+3] = Py_NewRef(result->ob_item[i]);
2445 }
2446 }
2447 return (PyObject*)result;
2448 }
2449
2450 static int
_posix_clear(PyObject * module)2451 _posix_clear(PyObject *module)
2452 {
2453 _posixstate *state = get_posix_state(module);
2454 Py_CLEAR(state->billion);
2455 Py_CLEAR(state->DirEntryType);
2456 Py_CLEAR(state->ScandirIteratorType);
2457 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
2458 Py_CLEAR(state->SchedParamType);
2459 #endif
2460 Py_CLEAR(state->StatResultType);
2461 Py_CLEAR(state->StatVFSResultType);
2462 Py_CLEAR(state->TerminalSizeType);
2463 Py_CLEAR(state->TimesResultType);
2464 Py_CLEAR(state->UnameResultType);
2465 #if defined(HAVE_WAITID)
2466 Py_CLEAR(state->WaitidResultType);
2467 #endif
2468 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
2469 Py_CLEAR(state->struct_rusage);
2470 #endif
2471 Py_CLEAR(state->st_mode);
2472 return 0;
2473 }
2474
2475 static int
_posix_traverse(PyObject * module,visitproc visit,void * arg)2476 _posix_traverse(PyObject *module, visitproc visit, void *arg)
2477 {
2478 _posixstate *state = get_posix_state(module);
2479 Py_VISIT(state->billion);
2480 Py_VISIT(state->DirEntryType);
2481 Py_VISIT(state->ScandirIteratorType);
2482 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
2483 Py_VISIT(state->SchedParamType);
2484 #endif
2485 Py_VISIT(state->StatResultType);
2486 Py_VISIT(state->StatVFSResultType);
2487 Py_VISIT(state->TerminalSizeType);
2488 Py_VISIT(state->TimesResultType);
2489 Py_VISIT(state->UnameResultType);
2490 #if defined(HAVE_WAITID)
2491 Py_VISIT(state->WaitidResultType);
2492 #endif
2493 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
2494 Py_VISIT(state->struct_rusage);
2495 #endif
2496 Py_VISIT(state->st_mode);
2497 return 0;
2498 }
2499
2500 static void
_posix_free(void * module)2501 _posix_free(void *module)
2502 {
2503 _posix_clear((PyObject *)module);
2504 }
2505
2506 static int
fill_time(PyObject * module,PyObject * v,int s_index,int f_index,int ns_index,time_t sec,unsigned long nsec)2507 fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec)
2508 {
2509 assert(!PyErr_Occurred());
2510
2511 int res = -1;
2512 PyObject *s_in_ns = NULL;
2513 PyObject *ns_total = NULL;
2514 PyObject *float_s = NULL;
2515
2516 PyObject *s = _PyLong_FromTime_t(sec);
2517 PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2518 if (!(s && ns_fractional)) {
2519 goto exit;
2520 }
2521
2522 s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
2523 if (!s_in_ns) {
2524 goto exit;
2525 }
2526
2527 ns_total = PyNumber_Add(s_in_ns, ns_fractional);
2528 if (!ns_total)
2529 goto exit;
2530
2531 float_s = PyFloat_FromDouble(sec + 1e-9*nsec);
2532 if (!float_s) {
2533 goto exit;
2534 }
2535
2536 if (s_index >= 0) {
2537 PyStructSequence_SET_ITEM(v, s_index, s);
2538 s = NULL;
2539 }
2540 if (f_index >= 0) {
2541 PyStructSequence_SET_ITEM(v, f_index, float_s);
2542 float_s = NULL;
2543 }
2544 if (ns_index >= 0) {
2545 PyStructSequence_SET_ITEM(v, ns_index, ns_total);
2546 ns_total = NULL;
2547 }
2548
2549 assert(!PyErr_Occurred());
2550 res = 0;
2551
2552 exit:
2553 Py_XDECREF(s);
2554 Py_XDECREF(ns_fractional);
2555 Py_XDECREF(s_in_ns);
2556 Py_XDECREF(ns_total);
2557 Py_XDECREF(float_s);
2558 return res;
2559 }
2560
2561 #ifdef MS_WINDOWS
2562 static PyObject*
_pystat_l128_from_l64_l64(uint64_t low,uint64_t high)2563 _pystat_l128_from_l64_l64(uint64_t low, uint64_t high)
2564 {
2565 PyObject *o_low = PyLong_FromUnsignedLongLong(low);
2566 if (!o_low || !high) {
2567 return o_low;
2568 }
2569 PyObject *o_high = PyLong_FromUnsignedLongLong(high);
2570 PyObject *l64 = o_high ? PyLong_FromLong(64) : NULL;
2571 if (!l64) {
2572 Py_XDECREF(o_high);
2573 Py_DECREF(o_low);
2574 return NULL;
2575 }
2576 Py_SETREF(o_high, PyNumber_Lshift(o_high, l64));
2577 Py_DECREF(l64);
2578 if (!o_high) {
2579 Py_DECREF(o_low);
2580 return NULL;
2581 }
2582 Py_SETREF(o_low, PyNumber_Add(o_low, o_high));
2583 Py_DECREF(o_high);
2584 return o_low;
2585 }
2586 #endif
2587
2588 /* pack a system stat C structure into the Python stat tuple
2589 (used by posix_stat() and posix_fstat()) */
2590 static PyObject*
_pystat_fromstructstat(PyObject * module,STRUCT_STAT * st)2591 _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
2592 {
2593 assert(!PyErr_Occurred());
2594
2595 PyObject *StatResultType = get_posix_state(module)->StatResultType;
2596 PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType);
2597 if (v == NULL) {
2598 return NULL;
2599 }
2600
2601 #define SET_ITEM(pos, expr) \
2602 do { \
2603 PyObject *obj = (expr); \
2604 if (obj == NULL) { \
2605 goto error; \
2606 } \
2607 PyStructSequence_SET_ITEM(v, (pos), obj); \
2608 } while (0)
2609
2610 SET_ITEM(0, PyLong_FromLong((long)st->st_mode));
2611 #ifdef MS_WINDOWS
2612 SET_ITEM(1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high));
2613 SET_ITEM(2, PyLong_FromUnsignedLongLong(st->st_dev));
2614 #else
2615 static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
2616 "stat.st_ino is larger than unsigned long long");
2617 SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino));
2618 SET_ITEM(2, _PyLong_FromDev(st->st_dev));
2619 #endif
2620 SET_ITEM(3, PyLong_FromLong((long)st->st_nlink));
2621 #if defined(MS_WINDOWS)
2622 SET_ITEM(4, PyLong_FromLong(0));
2623 SET_ITEM(5, PyLong_FromLong(0));
2624 #else
2625 SET_ITEM(4, _PyLong_FromUid(st->st_uid));
2626 SET_ITEM(5, _PyLong_FromGid(st->st_gid));
2627 #endif
2628 static_assert(sizeof(long long) >= sizeof(st->st_size),
2629 "stat.st_size is larger than long long");
2630 SET_ITEM(6, PyLong_FromLongLong(st->st_size));
2631
2632 // Set st_atime, st_mtime and st_ctime
2633 unsigned long ansec, mnsec, cnsec;
2634 #if defined(HAVE_STAT_TV_NSEC)
2635 ansec = st->st_atim.tv_nsec;
2636 mnsec = st->st_mtim.tv_nsec;
2637 cnsec = st->st_ctim.tv_nsec;
2638 #elif defined(HAVE_STAT_TV_NSEC2)
2639 ansec = st->st_atimespec.tv_nsec;
2640 mnsec = st->st_mtimespec.tv_nsec;
2641 cnsec = st->st_ctimespec.tv_nsec;
2642 #elif defined(HAVE_STAT_NSEC)
2643 ansec = st->st_atime_nsec;
2644 mnsec = st->st_mtime_nsec;
2645 cnsec = st->st_ctime_nsec;
2646 #else
2647 ansec = mnsec = cnsec = 0;
2648 #endif
2649 if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) {
2650 goto error;
2651 }
2652 if (fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec) < 0) {
2653 goto error;
2654 }
2655 if (fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec) < 0) {
2656 goto error;
2657 }
2658
2659 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2660 SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize));
2661 #endif
2662 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2663 SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks));
2664 #endif
2665 #ifdef HAVE_STRUCT_STAT_ST_RDEV
2666 SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev));
2667 #endif
2668 #ifdef HAVE_STRUCT_STAT_ST_GEN
2669 SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen));
2670 #endif
2671 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
2672 {
2673 unsigned long bsec, bnsec;
2674 bsec = (long)st->st_birthtime;
2675 #ifdef HAVE_STAT_TV_NSEC2
2676 bnsec = st->st_birthtimespec.tv_nsec;
2677 #else
2678 bnsec = 0;
2679 #endif
2680 SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9));
2681 }
2682 #elif defined(MS_WINDOWS)
2683 if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX,
2684 st->st_birthtime, st->st_birthtime_nsec) < 0) {
2685 goto error;
2686 }
2687 #endif
2688 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2689 SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags));
2690 #endif
2691 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2692 SET_ITEM(ST_FILE_ATTRIBUTES_IDX,
2693 PyLong_FromUnsignedLong(st->st_file_attributes));
2694 #endif
2695 #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2696 SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype));
2697 #endif
2698 #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2699 SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag));
2700 #endif
2701
2702 assert(!PyErr_Occurred());
2703 return v;
2704
2705 error:
2706 Py_DECREF(v);
2707 return NULL;
2708
2709 #undef SET_ITEM
2710 }
2711
2712 /* POSIX methods */
2713
2714
2715 static PyObject *
posix_do_stat(PyObject * module,const char * function_name,path_t * path,int dir_fd,int follow_symlinks)2716 posix_do_stat(PyObject *module, const char *function_name, path_t *path,
2717 int dir_fd, int follow_symlinks)
2718 {
2719 STRUCT_STAT st;
2720 int result;
2721
2722 #ifdef HAVE_FSTATAT
2723 int fstatat_unavailable = 0;
2724 #endif
2725
2726 #if !defined(MS_WINDOWS) && !defined(HAVE_FSTATAT) && !defined(HAVE_LSTAT)
2727 if (follow_symlinks_specified(function_name, follow_symlinks))
2728 return NULL;
2729 #endif
2730
2731 if (path_and_dir_fd_invalid("stat", path, dir_fd) ||
2732 dir_fd_and_fd_invalid("stat", dir_fd, path->fd) ||
2733 fd_and_follow_symlinks_invalid("stat", path->fd, follow_symlinks))
2734 return NULL;
2735
2736 Py_BEGIN_ALLOW_THREADS
2737 if (path->fd != -1)
2738 result = FSTAT(path->fd, &st);
2739 #ifdef MS_WINDOWS
2740 else if (follow_symlinks)
2741 result = win32_stat(path->wide, &st);
2742 else
2743 result = win32_lstat(path->wide, &st);
2744 #else
2745 else
2746 #if defined(HAVE_LSTAT)
2747 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
2748 result = LSTAT(path->narrow, &st);
2749 else
2750 #endif /* HAVE_LSTAT */
2751 #ifdef HAVE_FSTATAT
2752 if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) {
2753 if (HAVE_FSTATAT_RUNTIME) {
2754 result = fstatat(dir_fd, path->narrow, &st,
2755 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
2756
2757 } else {
2758 fstatat_unavailable = 1;
2759 }
2760 } else
2761 #endif /* HAVE_FSTATAT */
2762 result = STAT(path->narrow, &st);
2763 #endif /* MS_WINDOWS */
2764 Py_END_ALLOW_THREADS
2765
2766 #ifdef HAVE_FSTATAT
2767 if (fstatat_unavailable) {
2768 argument_unavailable_error("stat", "dir_fd");
2769 return NULL;
2770 }
2771 #endif
2772
2773 if (result != 0) {
2774 return path_error(path);
2775 }
2776
2777 return _pystat_fromstructstat(module, &st);
2778 }
2779
2780 /*[python input]
2781
2782 for s in """
2783
2784 FACCESSAT
2785 FCHMODAT
2786 FCHOWNAT
2787 FSTATAT
2788 LINKAT
2789 MKDIRAT
2790 MKFIFOAT
2791 MKNODAT
2792 OPENAT
2793 READLINKAT
2794 SYMLINKAT
2795 UNLINKAT
2796
2797 """.strip().split():
2798 s = s.strip()
2799 print("""
2800 #ifdef HAVE_{s}
2801 #define {s}_DIR_FD_CONVERTER dir_fd_converter
2802 #else
2803 #define {s}_DIR_FD_CONVERTER dir_fd_unavailable
2804 #endif
2805 """.rstrip().format(s=s))
2806
2807 for s in """
2808
2809 FCHDIR
2810 FCHMOD
2811 FCHOWN
2812 FDOPENDIR
2813 FEXECVE
2814 FPATHCONF
2815 FSTATVFS
2816 FTRUNCATE
2817
2818 """.strip().split():
2819 s = s.strip()
2820 print("""
2821 #ifdef HAVE_{s}
2822 #define PATH_HAVE_{s} 1
2823 #else
2824 #define PATH_HAVE_{s} 0
2825 #endif
2826
2827 """.rstrip().format(s=s))
2828 [python start generated code]*/
2829
2830 #ifdef HAVE_FACCESSAT
2831 #define FACCESSAT_DIR_FD_CONVERTER dir_fd_converter
2832 #else
2833 #define FACCESSAT_DIR_FD_CONVERTER dir_fd_unavailable
2834 #endif
2835
2836 #ifdef HAVE_FCHMODAT
2837 #define FCHMODAT_DIR_FD_CONVERTER dir_fd_converter
2838 #else
2839 #define FCHMODAT_DIR_FD_CONVERTER dir_fd_unavailable
2840 #endif
2841
2842 #ifdef HAVE_FCHOWNAT
2843 #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_converter
2844 #else
2845 #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_unavailable
2846 #endif
2847
2848 #ifdef HAVE_FSTATAT
2849 #define FSTATAT_DIR_FD_CONVERTER dir_fd_converter
2850 #else
2851 #define FSTATAT_DIR_FD_CONVERTER dir_fd_unavailable
2852 #endif
2853
2854 #ifdef HAVE_LINKAT
2855 #define LINKAT_DIR_FD_CONVERTER dir_fd_converter
2856 #else
2857 #define LINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2858 #endif
2859
2860 #ifdef HAVE_MKDIRAT
2861 #define MKDIRAT_DIR_FD_CONVERTER dir_fd_converter
2862 #else
2863 #define MKDIRAT_DIR_FD_CONVERTER dir_fd_unavailable
2864 #endif
2865
2866 #ifdef HAVE_MKFIFOAT
2867 #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_converter
2868 #else
2869 #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_unavailable
2870 #endif
2871
2872 #ifdef HAVE_MKNODAT
2873 #define MKNODAT_DIR_FD_CONVERTER dir_fd_converter
2874 #else
2875 #define MKNODAT_DIR_FD_CONVERTER dir_fd_unavailable
2876 #endif
2877
2878 #ifdef HAVE_OPENAT
2879 #define OPENAT_DIR_FD_CONVERTER dir_fd_converter
2880 #else
2881 #define OPENAT_DIR_FD_CONVERTER dir_fd_unavailable
2882 #endif
2883
2884 #ifdef HAVE_READLINKAT
2885 #define READLINKAT_DIR_FD_CONVERTER dir_fd_converter
2886 #else
2887 #define READLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2888 #endif
2889
2890 #ifdef HAVE_SYMLINKAT
2891 #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_converter
2892 #else
2893 #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2894 #endif
2895
2896 #ifdef HAVE_UNLINKAT
2897 #define UNLINKAT_DIR_FD_CONVERTER dir_fd_converter
2898 #else
2899 #define UNLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2900 #endif
2901
2902 #ifdef HAVE_FCHDIR
2903 #define PATH_HAVE_FCHDIR 1
2904 #else
2905 #define PATH_HAVE_FCHDIR 0
2906 #endif
2907
2908 #ifdef HAVE_FCHMOD
2909 #define PATH_HAVE_FCHMOD 1
2910 #else
2911 #define PATH_HAVE_FCHMOD 0
2912 #endif
2913
2914 #ifdef HAVE_FCHOWN
2915 #define PATH_HAVE_FCHOWN 1
2916 #else
2917 #define PATH_HAVE_FCHOWN 0
2918 #endif
2919
2920 #ifdef HAVE_FDOPENDIR
2921 #define PATH_HAVE_FDOPENDIR 1
2922 #else
2923 #define PATH_HAVE_FDOPENDIR 0
2924 #endif
2925
2926 #ifdef HAVE_FEXECVE
2927 #define PATH_HAVE_FEXECVE 1
2928 #else
2929 #define PATH_HAVE_FEXECVE 0
2930 #endif
2931
2932 #ifdef HAVE_FPATHCONF
2933 #define PATH_HAVE_FPATHCONF 1
2934 #else
2935 #define PATH_HAVE_FPATHCONF 0
2936 #endif
2937
2938 #ifdef HAVE_FSTATVFS
2939 #define PATH_HAVE_FSTATVFS 1
2940 #else
2941 #define PATH_HAVE_FSTATVFS 0
2942 #endif
2943
2944 #ifdef HAVE_FTRUNCATE
2945 #define PATH_HAVE_FTRUNCATE 1
2946 #else
2947 #define PATH_HAVE_FTRUNCATE 0
2948 #endif
2949 /*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/
2950
2951 #ifdef MS_WINDOWS
2952 #undef PATH_HAVE_FTRUNCATE
2953 #define PATH_HAVE_FTRUNCATE 1
2954 #undef PATH_HAVE_FCHMOD
2955 #define PATH_HAVE_FCHMOD 1
2956 #endif
2957
2958 /*[python input]
2959
2960 class path_t_converter(CConverter):
2961
2962 type = "path_t"
2963 impl_by_reference = True
2964 parse_by_reference = True
2965
2966 converter = 'path_converter'
2967
2968 def converter_init(self, *, allow_fd=False, make_wide=None,
2969 nonstrict=False, nullable=False,
2970 suppress_value_error=False):
2971 # right now path_t doesn't support default values.
2972 # to support a default value, you'll need to override initialize().
2973 if self.default not in (unspecified, None):
2974 fail("Can't specify a default to the path_t converter!")
2975
2976 if self.c_default not in (None, 'Py_None'):
2977 raise RuntimeError("Can't specify a c_default to the path_t converter!")
2978
2979 self.nullable = nullable
2980 self.nonstrict = nonstrict
2981 self.make_wide = make_wide
2982 self.suppress_value_error = suppress_value_error
2983 self.allow_fd = allow_fd
2984
2985 def pre_render(self):
2986 def strify(value):
2987 if isinstance(value, str):
2988 return value
2989 return str(int(bool(value)))
2990
2991 # add self.py_name here when merging with posixmodule conversion
2992 if self.make_wide is None:
2993 self.c_default = 'PATH_T_INITIALIZE_P("{}", "{}", {}, {}, {}, {})'.format(
2994 self.function.name,
2995 self.name,
2996 strify(self.nullable),
2997 strify(self.nonstrict),
2998 strify(self.suppress_value_error),
2999 strify(self.allow_fd),
3000 )
3001 else:
3002 self.c_default = 'PATH_T_INITIALIZE("{}", "{}", {}, {}, {}, {}, {})'.format(
3003 self.function.name,
3004 self.name,
3005 strify(self.nullable),
3006 strify(self.nonstrict),
3007 strify(self.make_wide),
3008 strify(self.suppress_value_error),
3009 strify(self.allow_fd),
3010 )
3011
3012 def cleanup(self):
3013 return "path_cleanup(&" + self.name + ");\n"
3014
3015
3016 class dir_fd_converter(CConverter):
3017 type = 'int'
3018
3019 def converter_init(self, requires=None):
3020 if self.default in (unspecified, None):
3021 self.c_default = 'DEFAULT_DIR_FD'
3022 if isinstance(requires, str):
3023 self.converter = requires.upper() + '_DIR_FD_CONVERTER'
3024 else:
3025 self.converter = 'dir_fd_converter'
3026
3027 class uid_t_converter(CConverter):
3028 type = "uid_t"
3029 converter = '_Py_Uid_Converter'
3030
3031 class gid_t_converter(CConverter):
3032 type = "gid_t"
3033 converter = '_Py_Gid_Converter'
3034
3035 class dev_t_converter(CConverter):
3036 type = 'dev_t'
3037 converter = '_Py_Dev_Converter'
3038
3039 class dev_t_return_converter(unsigned_long_return_converter):
3040 type = 'dev_t'
3041 conversion_fn = '_PyLong_FromDev'
3042 unsigned_cast = '(dev_t)'
3043
3044 class FSConverter_converter(CConverter):
3045 type = 'PyObject *'
3046 converter = 'PyUnicode_FSConverter'
3047 def converter_init(self):
3048 if self.default is not unspecified:
3049 fail("FSConverter_converter does not support default values")
3050 self.c_default = 'NULL'
3051
3052 def cleanup(self):
3053 return "Py_XDECREF(" + self.name + ");\n"
3054
3055 class pid_t_converter(CConverter):
3056 type = 'pid_t'
3057 format_unit = '" _Py_PARSE_PID "'
3058
3059 class idtype_t_converter(int_converter):
3060 type = 'idtype_t'
3061
3062 class id_t_converter(CConverter):
3063 type = 'id_t'
3064 format_unit = '" _Py_PARSE_PID "'
3065
3066 class intptr_t_converter(CConverter):
3067 type = 'intptr_t'
3068 format_unit = '" _Py_PARSE_INTPTR "'
3069
3070 class Py_off_t_converter(CConverter):
3071 type = 'Py_off_t'
3072 converter = 'Py_off_t_converter'
3073
3074 class Py_off_t_return_converter(long_return_converter):
3075 type = 'Py_off_t'
3076 conversion_fn = 'PyLong_FromPy_off_t'
3077
3078 class path_confname_converter(CConverter):
3079 type="int"
3080 converter="conv_path_confname"
3081
3082 class confstr_confname_converter(path_confname_converter):
3083 converter='conv_confstr_confname'
3084
3085 class sysconf_confname_converter(path_confname_converter):
3086 converter="conv_sysconf_confname"
3087
3088 [python start generated code]*/
3089 /*[python end generated code: output=da39a3ee5e6b4b0d input=577cb476e5d64960]*/
3090
3091 /*[clinic input]
3092
3093 os.stat
3094
3095 path : path_t(allow_fd=True)
3096 Path to be examined; can be string, bytes, a path-like object or
3097 open-file-descriptor int.
3098
3099 *
3100
3101 dir_fd : dir_fd(requires='fstatat') = None
3102 If not None, it should be a file descriptor open to a directory,
3103 and path should be a relative string; path will then be relative to
3104 that directory.
3105
3106 follow_symlinks: bool = True
3107 If False, and the last element of the path is a symbolic link,
3108 stat will examine the symbolic link itself instead of the file
3109 the link points to.
3110
3111 Perform a stat system call on the given path.
3112
3113 dir_fd and follow_symlinks may not be implemented
3114 on your platform. If they are unavailable, using them will raise a
3115 NotImplementedError.
3116
3117 It's an error to use dir_fd or follow_symlinks when specifying path as
3118 an open file descriptor.
3119
3120 [clinic start generated code]*/
3121
3122 static PyObject *
os_stat_impl(PyObject * module,path_t * path,int dir_fd,int follow_symlinks)3123 os_stat_impl(PyObject *module, path_t *path, int dir_fd, int follow_symlinks)
3124 /*[clinic end generated code: output=7d4976e6f18a59c5 input=01d362ebcc06996b]*/
3125 {
3126 return posix_do_stat(module, "stat", path, dir_fd, follow_symlinks);
3127 }
3128
3129
3130 /*[clinic input]
3131 os.lstat
3132
3133 path : path_t
3134
3135 *
3136
3137 dir_fd : dir_fd(requires='fstatat') = None
3138
3139 Perform a stat system call on the given path, without following symbolic links.
3140
3141 Like stat(), but do not follow symbolic links.
3142 Equivalent to stat(path, follow_symlinks=False).
3143 [clinic start generated code]*/
3144
3145 static PyObject *
os_lstat_impl(PyObject * module,path_t * path,int dir_fd)3146 os_lstat_impl(PyObject *module, path_t *path, int dir_fd)
3147 /*[clinic end generated code: output=ef82a5d35ce8ab37 input=0b7474765927b925]*/
3148 {
3149 int follow_symlinks = 0;
3150 return posix_do_stat(module, "lstat", path, dir_fd, follow_symlinks);
3151 }
3152
3153
3154 /*[clinic input]
3155 os.access -> bool
3156
3157 path: path_t
3158 Path to be tested; can be string, bytes, or a path-like object.
3159
3160 mode: int
3161 Operating-system mode bitfield. Can be F_OK to test existence,
3162 or the inclusive-OR of R_OK, W_OK, and X_OK.
3163
3164 *
3165
3166 dir_fd : dir_fd(requires='faccessat') = None
3167 If not None, it should be a file descriptor open to a directory,
3168 and path should be relative; path will then be relative to that
3169 directory.
3170
3171 effective_ids: bool = False
3172 If True, access will use the effective uid/gid instead of
3173 the real uid/gid.
3174
3175 follow_symlinks: bool = True
3176 If False, and the last element of the path is a symbolic link,
3177 access will examine the symbolic link itself instead of the file
3178 the link points to.
3179
3180 Use the real uid/gid to test for access to a path.
3181
3182 {parameters}
3183 dir_fd, effective_ids, and follow_symlinks may not be implemented
3184 on your platform. If they are unavailable, using them will raise a
3185 NotImplementedError.
3186
3187 Note that most operations will use the effective uid/gid, therefore this
3188 routine can be used in a suid/sgid environment to test if the invoking user
3189 has the specified access to the path.
3190
3191 [clinic start generated code]*/
3192
3193 static int
os_access_impl(PyObject * module,path_t * path,int mode,int dir_fd,int effective_ids,int follow_symlinks)3194 os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd,
3195 int effective_ids, int follow_symlinks)
3196 /*[clinic end generated code: output=cf84158bc90b1a77 input=3ffe4e650ee3bf20]*/
3197 {
3198 int return_value;
3199
3200 #ifdef MS_WINDOWS
3201 DWORD attr;
3202 #else
3203 int result;
3204 #endif
3205
3206 #ifdef HAVE_FACCESSAT
3207 int faccessat_unavailable = 0;
3208 #endif
3209
3210 #ifndef HAVE_FACCESSAT
3211 if (follow_symlinks_specified("access", follow_symlinks))
3212 return -1;
3213
3214 if (effective_ids) {
3215 argument_unavailable_error("access", "effective_ids");
3216 return -1;
3217 }
3218 #endif
3219
3220 #ifdef MS_WINDOWS
3221 Py_BEGIN_ALLOW_THREADS
3222 attr = GetFileAttributesW(path->wide);
3223 Py_END_ALLOW_THREADS
3224
3225 /*
3226 * Access is possible if
3227 * * we didn't get a -1, and
3228 * * write access wasn't requested,
3229 * * or the file isn't read-only,
3230 * * or it's a directory.
3231 * (Directories cannot be read-only on Windows.)
3232 */
3233 return_value = (attr != INVALID_FILE_ATTRIBUTES) &&
3234 (!(mode & 2) ||
3235 !(attr & FILE_ATTRIBUTE_READONLY) ||
3236 (attr & FILE_ATTRIBUTE_DIRECTORY));
3237 #else
3238
3239 Py_BEGIN_ALLOW_THREADS
3240 #ifdef HAVE_FACCESSAT
3241 if ((dir_fd != DEFAULT_DIR_FD) ||
3242 effective_ids ||
3243 !follow_symlinks) {
3244
3245 if (HAVE_FACCESSAT_RUNTIME) {
3246 int flags = 0;
3247 if (!follow_symlinks)
3248 flags |= AT_SYMLINK_NOFOLLOW;
3249 if (effective_ids)
3250 flags |= AT_EACCESS;
3251 result = faccessat(dir_fd, path->narrow, mode, flags);
3252 } else {
3253 faccessat_unavailable = 1;
3254 }
3255 }
3256 else
3257 #endif
3258 result = access(path->narrow, mode);
3259 Py_END_ALLOW_THREADS
3260
3261 #ifdef HAVE_FACCESSAT
3262 if (faccessat_unavailable) {
3263 if (dir_fd != DEFAULT_DIR_FD) {
3264 argument_unavailable_error("access", "dir_fd");
3265 return -1;
3266 }
3267 if (follow_symlinks_specified("access", follow_symlinks))
3268 return -1;
3269
3270 if (effective_ids) {
3271 argument_unavailable_error("access", "effective_ids");
3272 return -1;
3273 }
3274 /* should be unreachable */
3275 return -1;
3276 }
3277 #endif
3278 return_value = !result;
3279 #endif
3280
3281 return return_value;
3282 }
3283
3284 #ifndef F_OK
3285 #define F_OK 0
3286 #endif
3287 #ifndef R_OK
3288 #define R_OK 4
3289 #endif
3290 #ifndef W_OK
3291 #define W_OK 2
3292 #endif
3293 #ifndef X_OK
3294 #define X_OK 1
3295 #endif
3296
3297
3298 #ifdef HAVE_TTYNAME
3299 /*[clinic input]
3300 os.ttyname
3301
3302 fd: int
3303 Integer file descriptor handle.
3304
3305 /
3306
3307 Return the name of the terminal device connected to 'fd'.
3308 [clinic start generated code]*/
3309
3310 static PyObject *
os_ttyname_impl(PyObject * module,int fd)3311 os_ttyname_impl(PyObject *module, int fd)
3312 /*[clinic end generated code: output=c424d2e9d1cd636a input=9ff5a58b08115c55]*/
3313 {
3314
3315 long size = sysconf(_SC_TTY_NAME_MAX);
3316 if (size == -1) {
3317 return posix_error();
3318 }
3319 char *buffer = (char *)PyMem_RawMalloc(size);
3320 if (buffer == NULL) {
3321 return PyErr_NoMemory();
3322 }
3323 int ret = ttyname_r(fd, buffer, size);
3324 if (ret != 0) {
3325 PyMem_RawFree(buffer);
3326 errno = ret;
3327 return posix_error();
3328 }
3329 PyObject *res = PyUnicode_DecodeFSDefault(buffer);
3330 PyMem_RawFree(buffer);
3331 return res;
3332 }
3333 #endif
3334
3335 #ifdef HAVE_CTERMID
3336 /*[clinic input]
3337 os.ctermid
3338
3339 Return the name of the controlling terminal for this process.
3340 [clinic start generated code]*/
3341
3342 static PyObject *
os_ctermid_impl(PyObject * module)3343 os_ctermid_impl(PyObject *module)
3344 /*[clinic end generated code: output=02f017e6c9e620db input=3b87fdd52556382d]*/
3345 {
3346 char *ret;
3347 char buffer[L_ctermid];
3348
3349 #ifdef USE_CTERMID_R
3350 ret = ctermid_r(buffer);
3351 #else
3352 ret = ctermid(buffer);
3353 #endif
3354 if (ret == NULL)
3355 return posix_error();
3356 return PyUnicode_DecodeFSDefault(buffer);
3357 }
3358 #endif /* HAVE_CTERMID */
3359
3360
3361 /*[clinic input]
3362 os.chdir
3363
3364 path: path_t(allow_fd='PATH_HAVE_FCHDIR')
3365
3366 Change the current working directory to the specified path.
3367
3368 path may always be specified as a string.
3369 On some platforms, path may also be specified as an open file descriptor.
3370 If this functionality is unavailable, using it raises an exception.
3371 [clinic start generated code]*/
3372
3373 static PyObject *
os_chdir_impl(PyObject * module,path_t * path)3374 os_chdir_impl(PyObject *module, path_t *path)
3375 /*[clinic end generated code: output=3be6400eee26eaae input=1a4a15b4d12cb15d]*/
3376 {
3377 int result;
3378
3379 if (PySys_Audit("os.chdir", "(O)", path->object) < 0) {
3380 return NULL;
3381 }
3382
3383 Py_BEGIN_ALLOW_THREADS
3384 #ifdef MS_WINDOWS
3385 /* on unix, success = 0, on windows, success = !0 */
3386 result = !win32_wchdir(path->wide);
3387 #else
3388 #ifdef HAVE_FCHDIR
3389 if (path->fd != -1)
3390 result = fchdir(path->fd);
3391 else
3392 #endif
3393 result = chdir(path->narrow);
3394 #endif
3395 Py_END_ALLOW_THREADS
3396
3397 if (result) {
3398 return path_error(path);
3399 }
3400
3401 Py_RETURN_NONE;
3402 }
3403
3404
3405 #ifdef HAVE_FCHDIR
3406 /*[clinic input]
3407 os.fchdir
3408
3409 fd: fildes
3410
3411 Change to the directory of the given file descriptor.
3412
3413 fd must be opened on a directory, not a file.
3414 Equivalent to os.chdir(fd).
3415
3416 [clinic start generated code]*/
3417
3418 static PyObject *
os_fchdir_impl(PyObject * module,int fd)3419 os_fchdir_impl(PyObject *module, int fd)
3420 /*[clinic end generated code: output=42e064ec4dc00ab0 input=18e816479a2fa985]*/
3421 {
3422 if (PySys_Audit("os.chdir", "(i)", fd) < 0) {
3423 return NULL;
3424 }
3425 return posix_fildes_fd(fd, fchdir);
3426 }
3427 #endif /* HAVE_FCHDIR */
3428
3429 #ifdef MS_WINDOWS
3430 # define CHMOD_DEFAULT_FOLLOW_SYMLINKS 0
3431 #else
3432 # define CHMOD_DEFAULT_FOLLOW_SYMLINKS 1
3433 #endif
3434
3435 #ifdef MS_WINDOWS
3436 static int
win32_lchmod(LPCWSTR path,int mode)3437 win32_lchmod(LPCWSTR path, int mode)
3438 {
3439 DWORD attr = GetFileAttributesW(path);
3440 if (attr == INVALID_FILE_ATTRIBUTES) {
3441 return 0;
3442 }
3443 if (mode & _S_IWRITE) {
3444 attr &= ~FILE_ATTRIBUTE_READONLY;
3445 }
3446 else {
3447 attr |= FILE_ATTRIBUTE_READONLY;
3448 }
3449 return SetFileAttributesW(path, attr);
3450 }
3451
3452 static int
win32_hchmod(HANDLE hfile,int mode)3453 win32_hchmod(HANDLE hfile, int mode)
3454 {
3455 FILE_BASIC_INFO info;
3456 if (!GetFileInformationByHandleEx(hfile, FileBasicInfo,
3457 &info, sizeof(info)))
3458 {
3459 return 0;
3460 }
3461 if (mode & _S_IWRITE) {
3462 info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
3463 }
3464 else {
3465 info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
3466 }
3467 return SetFileInformationByHandle(hfile, FileBasicInfo,
3468 &info, sizeof(info));
3469 }
3470
3471 static int
win32_fchmod(int fd,int mode)3472 win32_fchmod(int fd, int mode)
3473 {
3474 HANDLE hfile = _Py_get_osfhandle_noraise(fd);
3475 if (hfile == INVALID_HANDLE_VALUE) {
3476 SetLastError(ERROR_INVALID_HANDLE);
3477 return 0;
3478 }
3479 return win32_hchmod(hfile, mode);
3480 }
3481
3482 #endif /* MS_WINDOWS */
3483
3484 /*[clinic input]
3485 os.chmod
3486
3487 path: path_t(allow_fd='PATH_HAVE_FCHMOD')
3488 Path to be modified. May always be specified as a str, bytes, or a path-like object.
3489 On some platforms, path may also be specified as an open file descriptor.
3490 If this functionality is unavailable, using it raises an exception.
3491
3492 mode: int
3493 Operating-system mode bitfield.
3494 Be careful when using number literals for *mode*. The conventional UNIX notation for
3495 numeric modes uses an octal base, which needs to be indicated with a ``0o`` prefix in
3496 Python.
3497
3498 *
3499
3500 dir_fd : dir_fd(requires='fchmodat') = None
3501 If not None, it should be a file descriptor open to a directory,
3502 and path should be relative; path will then be relative to that
3503 directory.
3504
3505 follow_symlinks: bool(c_default="CHMOD_DEFAULT_FOLLOW_SYMLINKS", \
3506 py_default="(os.name != 'nt')") = CHMOD_DEFAULT_FOLLOW_SYMLINKS
3507 If False, and the last element of the path is a symbolic link,
3508 chmod will modify the symbolic link itself instead of the file
3509 the link points to.
3510
3511 Change the access permissions of a file.
3512
3513 It is an error to use dir_fd or follow_symlinks when specifying path as
3514 an open file descriptor.
3515 dir_fd and follow_symlinks may not be implemented on your platform.
3516 If they are unavailable, using them will raise a NotImplementedError.
3517
3518 [clinic start generated code]*/
3519
3520 static PyObject *
os_chmod_impl(PyObject * module,path_t * path,int mode,int dir_fd,int follow_symlinks)3521 os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
3522 int follow_symlinks)
3523 /*[clinic end generated code: output=5cf6a94915cc7bff input=fcf115d174b9f3d8]*/
3524 {
3525 int result;
3526
3527 #ifdef HAVE_FCHMODAT
3528 int fchmodat_nofollow_unsupported = 0;
3529 int fchmodat_unsupported = 0;
3530 #endif
3531
3532 #if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD) || defined(MS_WINDOWS))
3533 if (follow_symlinks_specified("chmod", follow_symlinks))
3534 return NULL;
3535 #endif
3536
3537 if (PySys_Audit("os.chmod", "Oii", path->object, mode,
3538 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
3539 return NULL;
3540 }
3541
3542 #ifdef MS_WINDOWS
3543 result = 0;
3544 Py_BEGIN_ALLOW_THREADS
3545 if (path->fd != -1) {
3546 result = win32_fchmod(path->fd, mode);
3547 }
3548 else if (follow_symlinks) {
3549 HANDLE hfile = CreateFileW(path->wide,
3550 FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
3551 0, NULL,
3552 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
3553 if (hfile != INVALID_HANDLE_VALUE) {
3554 result = win32_hchmod(hfile, mode);
3555 (void)CloseHandle(hfile);
3556 }
3557 }
3558 else {
3559 result = win32_lchmod(path->wide, mode);
3560 }
3561 Py_END_ALLOW_THREADS
3562 if (!result) {
3563 return path_error(path);
3564 }
3565 #else /* MS_WINDOWS */
3566 Py_BEGIN_ALLOW_THREADS
3567 #ifdef HAVE_FCHMOD
3568 if (path->fd != -1)
3569 result = fchmod(path->fd, mode);
3570 else
3571 #endif /* HAVE_CHMOD */
3572 #ifdef HAVE_LCHMOD
3573 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3574 result = lchmod(path->narrow, mode);
3575 else
3576 #endif /* HAVE_LCHMOD */
3577 #ifdef HAVE_FCHMODAT
3578 if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) {
3579 if (HAVE_FCHMODAT_RUNTIME) {
3580 /*
3581 * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW!
3582 * The documentation specifically shows how to use it,
3583 * and then says it isn't implemented yet.
3584 * (true on linux with glibc 2.15, and openindiana 3.x)
3585 *
3586 * Once it is supported, os.chmod will automatically
3587 * support dir_fd and follow_symlinks=False. (Hopefully.)
3588 * Until then, we need to be careful what exception we raise.
3589 */
3590 result = fchmodat(dir_fd, path->narrow, mode,
3591 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3592 /*
3593 * But wait! We can't throw the exception without allowing threads,
3594 * and we can't do that in this nested scope. (Macro trickery, sigh.)
3595 */
3596 fchmodat_nofollow_unsupported =
3597 result &&
3598 ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) &&
3599 !follow_symlinks;
3600 } else {
3601 fchmodat_unsupported = 1;
3602 fchmodat_nofollow_unsupported = 1;
3603
3604 result = -1;
3605 }
3606 }
3607 else
3608 #endif /* HAVE_FHCMODAT */
3609 {
3610 #ifdef HAVE_CHMOD
3611 result = chmod(path->narrow, mode);
3612 #elif defined(__wasi__)
3613 // WASI SDK 15.0 does not support chmod.
3614 // Ignore missing syscall for now.
3615 result = 0;
3616 #else
3617 result = -1;
3618 errno = ENOSYS;
3619 #endif
3620 }
3621 Py_END_ALLOW_THREADS
3622
3623 if (result) {
3624 #ifdef HAVE_FCHMODAT
3625 if (fchmodat_unsupported) {
3626 if (dir_fd != DEFAULT_DIR_FD) {
3627 argument_unavailable_error("chmod", "dir_fd");
3628 return NULL;
3629 }
3630 }
3631
3632 if (fchmodat_nofollow_unsupported) {
3633 if (dir_fd != DEFAULT_DIR_FD)
3634 dir_fd_and_follow_symlinks_invalid("chmod",
3635 dir_fd, follow_symlinks);
3636 else
3637 follow_symlinks_specified("chmod", follow_symlinks);
3638 return NULL;
3639 }
3640 else
3641 #endif /* HAVE_FCHMODAT */
3642 return path_error(path);
3643 }
3644 #endif /* MS_WINDOWS */
3645
3646 Py_RETURN_NONE;
3647 }
3648
3649
3650 #if defined(HAVE_FCHMOD) || defined(MS_WINDOWS)
3651 /*[clinic input]
3652 os.fchmod
3653
3654 fd: int
3655 The file descriptor of the file to be modified.
3656 mode: int
3657 Operating-system mode bitfield.
3658 Be careful when using number literals for *mode*. The conventional UNIX notation for
3659 numeric modes uses an octal base, which needs to be indicated with a ``0o`` prefix in
3660 Python.
3661
3662 Change the access permissions of the file given by file descriptor fd.
3663
3664 Equivalent to os.chmod(fd, mode).
3665 [clinic start generated code]*/
3666
3667 static PyObject *
os_fchmod_impl(PyObject * module,int fd,int mode)3668 os_fchmod_impl(PyObject *module, int fd, int mode)
3669 /*[clinic end generated code: output=afd9bc05b4e426b3 input=b5594618bbbc22df]*/
3670 {
3671 int res;
3672
3673 if (PySys_Audit("os.chmod", "iii", fd, mode, -1) < 0) {
3674 return NULL;
3675 }
3676
3677 #ifdef MS_WINDOWS
3678 res = 0;
3679 Py_BEGIN_ALLOW_THREADS
3680 res = win32_fchmod(fd, mode);
3681 Py_END_ALLOW_THREADS
3682 if (!res) {
3683 return PyErr_SetFromWindowsErr(0);
3684 }
3685 #else /* MS_WINDOWS */
3686 int async_err = 0;
3687 do {
3688 Py_BEGIN_ALLOW_THREADS
3689 res = fchmod(fd, mode);
3690 Py_END_ALLOW_THREADS
3691 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
3692 if (res != 0)
3693 return (!async_err) ? posix_error() : NULL;
3694 #endif /* MS_WINDOWS */
3695
3696 Py_RETURN_NONE;
3697 }
3698 #endif /* HAVE_FCHMOD || MS_WINDOWS */
3699
3700
3701 #if defined(HAVE_LCHMOD) || defined(MS_WINDOWS)
3702 /*[clinic input]
3703 os.lchmod
3704
3705 path: path_t
3706 mode: int
3707
3708 Change the access permissions of a file, without following symbolic links.
3709
3710 If path is a symlink, this affects the link itself rather than the target.
3711 Equivalent to chmod(path, mode, follow_symlinks=False)."
3712 [clinic start generated code]*/
3713
3714 static PyObject *
os_lchmod_impl(PyObject * module,path_t * path,int mode)3715 os_lchmod_impl(PyObject *module, path_t *path, int mode)
3716 /*[clinic end generated code: output=082344022b51a1d5 input=90c5663c7465d24f]*/
3717 {
3718 int res;
3719 if (PySys_Audit("os.chmod", "Oii", path->object, mode, -1) < 0) {
3720 return NULL;
3721 }
3722 #ifdef MS_WINDOWS
3723 Py_BEGIN_ALLOW_THREADS
3724 res = win32_lchmod(path->wide, mode);
3725 Py_END_ALLOW_THREADS
3726 if (!res) {
3727 path_error(path);
3728 return NULL;
3729 }
3730 #else /* MS_WINDOWS */
3731 Py_BEGIN_ALLOW_THREADS
3732 res = lchmod(path->narrow, mode);
3733 Py_END_ALLOW_THREADS
3734 if (res < 0) {
3735 path_error(path);
3736 return NULL;
3737 }
3738 #endif /* MS_WINDOWS */
3739 Py_RETURN_NONE;
3740 }
3741 #endif /* HAVE_LCHMOD || MS_WINDOWS */
3742
3743
3744 #ifdef HAVE_CHFLAGS
3745 /*[clinic input]
3746 os.chflags
3747
3748 path: path_t
3749 flags: unsigned_long(bitwise=True)
3750 follow_symlinks: bool=True
3751
3752 Set file flags.
3753
3754 If follow_symlinks is False, and the last element of the path is a symbolic
3755 link, chflags will change flags on the symbolic link itself instead of the
3756 file the link points to.
3757 follow_symlinks may not be implemented on your platform. If it is
3758 unavailable, using it will raise a NotImplementedError.
3759
3760 [clinic start generated code]*/
3761
3762 static PyObject *
os_chflags_impl(PyObject * module,path_t * path,unsigned long flags,int follow_symlinks)3763 os_chflags_impl(PyObject *module, path_t *path, unsigned long flags,
3764 int follow_symlinks)
3765 /*[clinic end generated code: output=85571c6737661ce9 input=0327e29feb876236]*/
3766 {
3767 int result;
3768
3769 #ifndef HAVE_LCHFLAGS
3770 if (follow_symlinks_specified("chflags", follow_symlinks))
3771 return NULL;
3772 #endif
3773
3774 if (PySys_Audit("os.chflags", "Ok", path->object, flags) < 0) {
3775 return NULL;
3776 }
3777
3778 Py_BEGIN_ALLOW_THREADS
3779 #ifdef HAVE_LCHFLAGS
3780 if (!follow_symlinks)
3781 result = lchflags(path->narrow, flags);
3782 else
3783 #endif
3784 result = chflags(path->narrow, flags);
3785 Py_END_ALLOW_THREADS
3786
3787 if (result)
3788 return path_error(path);
3789
3790 Py_RETURN_NONE;
3791 }
3792 #endif /* HAVE_CHFLAGS */
3793
3794
3795 #ifdef HAVE_LCHFLAGS
3796 /*[clinic input]
3797 os.lchflags
3798
3799 path: path_t
3800 flags: unsigned_long(bitwise=True)
3801
3802 Set file flags.
3803
3804 This function will not follow symbolic links.
3805 Equivalent to chflags(path, flags, follow_symlinks=False).
3806 [clinic start generated code]*/
3807
3808 static PyObject *
os_lchflags_impl(PyObject * module,path_t * path,unsigned long flags)3809 os_lchflags_impl(PyObject *module, path_t *path, unsigned long flags)
3810 /*[clinic end generated code: output=30ae958695c07316 input=f9f82ea8b585ca9d]*/
3811 {
3812 int res;
3813 if (PySys_Audit("os.chflags", "Ok", path->object, flags) < 0) {
3814 return NULL;
3815 }
3816 Py_BEGIN_ALLOW_THREADS
3817 res = lchflags(path->narrow, flags);
3818 Py_END_ALLOW_THREADS
3819 if (res < 0) {
3820 return path_error(path);
3821 }
3822 Py_RETURN_NONE;
3823 }
3824 #endif /* HAVE_LCHFLAGS */
3825
3826
3827 #ifdef HAVE_CHROOT
3828 /*[clinic input]
3829 os.chroot
3830 path: path_t
3831
3832 Change root directory to path.
3833
3834 [clinic start generated code]*/
3835
3836 static PyObject *
os_chroot_impl(PyObject * module,path_t * path)3837 os_chroot_impl(PyObject *module, path_t *path)
3838 /*[clinic end generated code: output=de80befc763a4475 input=14822965652c3dc3]*/
3839 {
3840 int res;
3841 Py_BEGIN_ALLOW_THREADS
3842 res = chroot(path->narrow);
3843 Py_END_ALLOW_THREADS
3844 if (res < 0)
3845 return path_error(path);
3846 Py_RETURN_NONE;
3847 }
3848 #endif /* HAVE_CHROOT */
3849
3850
3851 #ifdef HAVE_FSYNC
3852 /*[clinic input]
3853 os.fsync
3854
3855 fd: fildes
3856
3857 Force write of fd to disk.
3858 [clinic start generated code]*/
3859
3860 static PyObject *
os_fsync_impl(PyObject * module,int fd)3861 os_fsync_impl(PyObject *module, int fd)
3862 /*[clinic end generated code: output=4a10d773f52b3584 input=21c3645c056967f2]*/
3863 {
3864 return posix_fildes_fd(fd, fsync);
3865 }
3866 #endif /* HAVE_FSYNC */
3867
3868
3869 #ifdef HAVE_SYNC
3870 /*[clinic input]
3871 os.sync
3872
3873 Force write of everything to disk.
3874 [clinic start generated code]*/
3875
3876 static PyObject *
os_sync_impl(PyObject * module)3877 os_sync_impl(PyObject *module)
3878 /*[clinic end generated code: output=2796b1f0818cd71c input=84749fe5e9b404ff]*/
3879 {
3880 Py_BEGIN_ALLOW_THREADS
3881 sync();
3882 Py_END_ALLOW_THREADS
3883 Py_RETURN_NONE;
3884 }
3885 #endif /* HAVE_SYNC */
3886
3887
3888 #ifdef HAVE_FDATASYNC
3889 #ifdef __hpux
3890 extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */
3891 #endif
3892
3893 /*[clinic input]
3894 os.fdatasync
3895
3896 fd: fildes
3897
3898 Force write of fd to disk without forcing update of metadata.
3899 [clinic start generated code]*/
3900
3901 static PyObject *
os_fdatasync_impl(PyObject * module,int fd)3902 os_fdatasync_impl(PyObject *module, int fd)
3903 /*[clinic end generated code: output=b4b9698b5d7e26dd input=bc74791ee54dd291]*/
3904 {
3905 return posix_fildes_fd(fd, fdatasync);
3906 }
3907 #endif /* HAVE_FDATASYNC */
3908
3909
3910 #ifdef HAVE_CHOWN
3911 /*[clinic input]
3912 os.chown
3913
3914 path : path_t(allow_fd='PATH_HAVE_FCHOWN')
3915 Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.
3916
3917 uid: uid_t
3918
3919 gid: gid_t
3920
3921 *
3922
3923 dir_fd : dir_fd(requires='fchownat') = None
3924 If not None, it should be a file descriptor open to a directory,
3925 and path should be relative; path will then be relative to that
3926 directory.
3927
3928 follow_symlinks: bool = True
3929 If False, and the last element of the path is a symbolic link,
3930 stat will examine the symbolic link itself instead of the file
3931 the link points to.
3932
3933 Change the owner and group id of path to the numeric uid and gid.\
3934
3935 path may always be specified as a string.
3936 On some platforms, path may also be specified as an open file descriptor.
3937 If this functionality is unavailable, using it raises an exception.
3938 If dir_fd is not None, it should be a file descriptor open to a directory,
3939 and path should be relative; path will then be relative to that directory.
3940 If follow_symlinks is False, and the last element of the path is a symbolic
3941 link, chown will modify the symbolic link itself instead of the file the
3942 link points to.
3943 It is an error to use dir_fd or follow_symlinks when specifying path as
3944 an open file descriptor.
3945 dir_fd and follow_symlinks may not be implemented on your platform.
3946 If they are unavailable, using them will raise a NotImplementedError.
3947
3948 [clinic start generated code]*/
3949
3950 static PyObject *
os_chown_impl(PyObject * module,path_t * path,uid_t uid,gid_t gid,int dir_fd,int follow_symlinks)3951 os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid,
3952 int dir_fd, int follow_symlinks)
3953 /*[clinic end generated code: output=4beadab0db5f70cd input=b08c5ec67996a97d]*/
3954 {
3955 int result;
3956
3957 #if defined(HAVE_FCHOWNAT)
3958 int fchownat_unsupported = 0;
3959 #endif
3960
3961 #if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT))
3962 if (follow_symlinks_specified("chown", follow_symlinks))
3963 return NULL;
3964 #endif
3965 if (dir_fd_and_fd_invalid("chown", dir_fd, path->fd) ||
3966 fd_and_follow_symlinks_invalid("chown", path->fd, follow_symlinks))
3967 return NULL;
3968
3969 if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid,
3970 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
3971 return NULL;
3972 }
3973
3974 Py_BEGIN_ALLOW_THREADS
3975 #ifdef HAVE_FCHOWN
3976 if (path->fd != -1)
3977 result = fchown(path->fd, uid, gid);
3978 else
3979 #endif
3980 #ifdef HAVE_LCHOWN
3981 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3982 result = lchown(path->narrow, uid, gid);
3983 else
3984 #endif
3985 #ifdef HAVE_FCHOWNAT
3986 if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) {
3987 if (HAVE_FCHOWNAT_RUNTIME) {
3988 result = fchownat(dir_fd, path->narrow, uid, gid,
3989 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3990 } else {
3991 fchownat_unsupported = 1;
3992 }
3993 } else
3994 #endif
3995 result = chown(path->narrow, uid, gid);
3996 Py_END_ALLOW_THREADS
3997
3998 #ifdef HAVE_FCHOWNAT
3999 if (fchownat_unsupported) {
4000 /* This would be incorrect if the current platform
4001 * doesn't support lchown.
4002 */
4003 argument_unavailable_error(NULL, "dir_fd");
4004 return NULL;
4005 }
4006 #endif
4007
4008 if (result)
4009 return path_error(path);
4010
4011 Py_RETURN_NONE;
4012 }
4013 #endif /* HAVE_CHOWN */
4014
4015
4016 #ifdef HAVE_FCHOWN
4017 /*[clinic input]
4018 os.fchown
4019
4020 fd: int
4021 uid: uid_t
4022 gid: gid_t
4023
4024 Change the owner and group id of the file specified by file descriptor.
4025
4026 Equivalent to os.chown(fd, uid, gid).
4027
4028 [clinic start generated code]*/
4029
4030 static PyObject *
os_fchown_impl(PyObject * module,int fd,uid_t uid,gid_t gid)4031 os_fchown_impl(PyObject *module, int fd, uid_t uid, gid_t gid)
4032 /*[clinic end generated code: output=97d21cbd5a4350a6 input=3af544ba1b13a0d7]*/
4033 {
4034 int res;
4035 int async_err = 0;
4036
4037 if (PySys_Audit("os.chown", "iIIi", fd, uid, gid, -1) < 0) {
4038 return NULL;
4039 }
4040
4041 do {
4042 Py_BEGIN_ALLOW_THREADS
4043 res = fchown(fd, uid, gid);
4044 Py_END_ALLOW_THREADS
4045 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
4046 if (res != 0)
4047 return (!async_err) ? posix_error() : NULL;
4048
4049 Py_RETURN_NONE;
4050 }
4051 #endif /* HAVE_FCHOWN */
4052
4053
4054 #ifdef HAVE_LCHOWN
4055 /*[clinic input]
4056 os.lchown
4057
4058 path : path_t
4059 uid: uid_t
4060 gid: gid_t
4061
4062 Change the owner and group id of path to the numeric uid and gid.
4063
4064 This function will not follow symbolic links.
4065 Equivalent to os.chown(path, uid, gid, follow_symlinks=False).
4066 [clinic start generated code]*/
4067
4068 static PyObject *
os_lchown_impl(PyObject * module,path_t * path,uid_t uid,gid_t gid)4069 os_lchown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid)
4070 /*[clinic end generated code: output=25eaf6af412fdf2f input=b1c6014d563a7161]*/
4071 {
4072 int res;
4073 if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid, -1) < 0) {
4074 return NULL;
4075 }
4076 Py_BEGIN_ALLOW_THREADS
4077 res = lchown(path->narrow, uid, gid);
4078 Py_END_ALLOW_THREADS
4079 if (res < 0) {
4080 return path_error(path);
4081 }
4082 Py_RETURN_NONE;
4083 }
4084 #endif /* HAVE_LCHOWN */
4085
4086
4087 static PyObject *
posix_getcwd(int use_bytes)4088 posix_getcwd(int use_bytes)
4089 {
4090 #ifdef MS_WINDOWS
4091 wchar_t wbuf[MAXPATHLEN];
4092 wchar_t *wbuf2 = wbuf;
4093 DWORD len;
4094
4095 Py_BEGIN_ALLOW_THREADS
4096 len = GetCurrentDirectoryW(Py_ARRAY_LENGTH(wbuf), wbuf);
4097 /* If the buffer is large enough, len does not include the
4098 terminating \0. If the buffer is too small, len includes
4099 the space needed for the terminator. */
4100 if (len >= Py_ARRAY_LENGTH(wbuf)) {
4101 if (len <= PY_SSIZE_T_MAX / sizeof(wchar_t)) {
4102 wbuf2 = PyMem_RawMalloc(len * sizeof(wchar_t));
4103 }
4104 else {
4105 wbuf2 = NULL;
4106 }
4107 if (wbuf2) {
4108 len = GetCurrentDirectoryW(len, wbuf2);
4109 }
4110 }
4111 Py_END_ALLOW_THREADS
4112
4113 if (!wbuf2) {
4114 PyErr_NoMemory();
4115 return NULL;
4116 }
4117 if (!len) {
4118 PyErr_SetFromWindowsErr(0);
4119 if (wbuf2 != wbuf)
4120 PyMem_RawFree(wbuf2);
4121 return NULL;
4122 }
4123
4124 PyObject *resobj = PyUnicode_FromWideChar(wbuf2, len);
4125 if (wbuf2 != wbuf) {
4126 PyMem_RawFree(wbuf2);
4127 }
4128
4129 if (use_bytes) {
4130 if (resobj == NULL) {
4131 return NULL;
4132 }
4133 Py_SETREF(resobj, PyUnicode_EncodeFSDefault(resobj));
4134 }
4135
4136 return resobj;
4137 #else
4138 const size_t chunk = 1024;
4139
4140 char *buf = NULL;
4141 char *cwd = NULL;
4142 size_t buflen = 0;
4143
4144 Py_BEGIN_ALLOW_THREADS
4145 do {
4146 char *newbuf;
4147 if (buflen <= PY_SSIZE_T_MAX - chunk) {
4148 buflen += chunk;
4149 newbuf = PyMem_RawRealloc(buf, buflen);
4150 }
4151 else {
4152 newbuf = NULL;
4153 }
4154 if (newbuf == NULL) {
4155 PyMem_RawFree(buf);
4156 buf = NULL;
4157 break;
4158 }
4159 buf = newbuf;
4160
4161 cwd = getcwd(buf, buflen);
4162 } while (cwd == NULL && errno == ERANGE);
4163 Py_END_ALLOW_THREADS
4164
4165 if (buf == NULL) {
4166 return PyErr_NoMemory();
4167 }
4168 if (cwd == NULL) {
4169 posix_error();
4170 PyMem_RawFree(buf);
4171 return NULL;
4172 }
4173
4174 PyObject *obj;
4175 if (use_bytes) {
4176 obj = PyBytes_FromStringAndSize(buf, strlen(buf));
4177 }
4178 else {
4179 obj = PyUnicode_DecodeFSDefault(buf);
4180 }
4181 #ifdef __linux__
4182 if (buf[0] != '/') {
4183 /*
4184 * On Linux >= 2.6.36 with glibc < 2.27, getcwd() can return a
4185 * relative pathname starting with '(unreachable)'. We detect this
4186 * and fail with ENOENT, matching newer glibc behaviour.
4187 */
4188 errno = ENOENT;
4189 path_object_error(obj);
4190 PyMem_RawFree(buf);
4191 return NULL;
4192 }
4193 #endif
4194 assert(buf[0] == '/');
4195 PyMem_RawFree(buf);
4196
4197 return obj;
4198 #endif /* !MS_WINDOWS */
4199 }
4200
4201
4202 /*[clinic input]
4203 os.getcwd
4204
4205 Return a unicode string representing the current working directory.
4206 [clinic start generated code]*/
4207
4208 static PyObject *
os_getcwd_impl(PyObject * module)4209 os_getcwd_impl(PyObject *module)
4210 /*[clinic end generated code: output=21badfae2ea99ddc input=f069211bb70e3d39]*/
4211 {
4212 return posix_getcwd(0);
4213 }
4214
4215
4216 /*[clinic input]
4217 os.getcwdb
4218
4219 Return a bytes string representing the current working directory.
4220 [clinic start generated code]*/
4221
4222 static PyObject *
os_getcwdb_impl(PyObject * module)4223 os_getcwdb_impl(PyObject *module)
4224 /*[clinic end generated code: output=3dd47909480e4824 input=f6f6a378dad3d9cb]*/
4225 {
4226 return posix_getcwd(1);
4227 }
4228
4229
4230 #if ((!defined(HAVE_LINK)) && defined(MS_WINDOWS))
4231 #define HAVE_LINK 1
4232 #endif
4233
4234 #ifdef HAVE_LINK
4235 /*[clinic input]
4236
4237 os.link
4238
4239 src : path_t
4240 dst : path_t
4241 *
4242 src_dir_fd : dir_fd = None
4243 dst_dir_fd : dir_fd = None
4244 follow_symlinks: bool = True
4245
4246 Create a hard link to a file.
4247
4248 If either src_dir_fd or dst_dir_fd is not None, it should be a file
4249 descriptor open to a directory, and the respective path string (src or dst)
4250 should be relative; the path will then be relative to that directory.
4251 If follow_symlinks is False, and the last element of src is a symbolic
4252 link, link will create a link to the symbolic link itself instead of the
4253 file the link points to.
4254 src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your
4255 platform. If they are unavailable, using them will raise a
4256 NotImplementedError.
4257 [clinic start generated code]*/
4258
4259 static PyObject *
os_link_impl(PyObject * module,path_t * src,path_t * dst,int src_dir_fd,int dst_dir_fd,int follow_symlinks)4260 os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
4261 int dst_dir_fd, int follow_symlinks)
4262 /*[clinic end generated code: output=7f00f6007fd5269a input=b0095ebbcbaa7e04]*/
4263 {
4264 #ifdef MS_WINDOWS
4265 BOOL result = FALSE;
4266 #else
4267 int result;
4268 #endif
4269 #if defined(HAVE_LINKAT)
4270 int linkat_unavailable = 0;
4271 #endif
4272
4273 #ifndef HAVE_LINKAT
4274 if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) {
4275 argument_unavailable_error("link", "src_dir_fd and dst_dir_fd");
4276 return NULL;
4277 }
4278 #endif
4279
4280 #ifndef MS_WINDOWS
4281 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
4282 PyErr_SetString(PyExc_NotImplementedError,
4283 "link: src and dst must be the same type");
4284 return NULL;
4285 }
4286 #endif
4287
4288 if (PySys_Audit("os.link", "OOii", src->object, dst->object,
4289 src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
4290 dst_dir_fd == DEFAULT_DIR_FD ? -1 : dst_dir_fd) < 0) {
4291 return NULL;
4292 }
4293
4294 #ifdef MS_WINDOWS
4295 Py_BEGIN_ALLOW_THREADS
4296 result = CreateHardLinkW(dst->wide, src->wide, NULL);
4297 Py_END_ALLOW_THREADS
4298
4299 if (!result)
4300 return path_error2(src, dst);
4301 #else
4302 Py_BEGIN_ALLOW_THREADS
4303 #ifdef HAVE_LINKAT
4304 if ((src_dir_fd != DEFAULT_DIR_FD) ||
4305 (dst_dir_fd != DEFAULT_DIR_FD) ||
4306 (!follow_symlinks)) {
4307
4308 if (HAVE_LINKAT_RUNTIME) {
4309
4310 result = linkat(src_dir_fd, src->narrow,
4311 dst_dir_fd, dst->narrow,
4312 follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
4313
4314 }
4315 #ifdef __APPLE__
4316 else {
4317 if (src_dir_fd == DEFAULT_DIR_FD && dst_dir_fd == DEFAULT_DIR_FD) {
4318 /* See issue 41355: This matches the behaviour of !HAVE_LINKAT */
4319 result = link(src->narrow, dst->narrow);
4320 } else {
4321 linkat_unavailable = 1;
4322 }
4323 }
4324 #endif
4325 }
4326 else
4327 #endif /* HAVE_LINKAT */
4328 result = link(src->narrow, dst->narrow);
4329 Py_END_ALLOW_THREADS
4330
4331 #ifdef HAVE_LINKAT
4332 if (linkat_unavailable) {
4333 /* Either or both dir_fd arguments were specified */
4334 if (src_dir_fd != DEFAULT_DIR_FD) {
4335 argument_unavailable_error("link", "src_dir_fd");
4336 } else {
4337 argument_unavailable_error("link", "dst_dir_fd");
4338 }
4339 return NULL;
4340 }
4341 #endif
4342
4343 if (result)
4344 return path_error2(src, dst);
4345 #endif /* MS_WINDOWS */
4346
4347 Py_RETURN_NONE;
4348 }
4349 #endif
4350
4351
4352 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
4353 static PyObject *
_listdir_windows_no_opendir(path_t * path,PyObject * list)4354 _listdir_windows_no_opendir(path_t *path, PyObject *list)
4355 {
4356 PyObject *v;
4357 HANDLE hFindFile = INVALID_HANDLE_VALUE;
4358 BOOL result, return_bytes;
4359 wchar_t namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */
4360 /* only claim to have space for MAX_PATH */
4361 Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4;
4362 wchar_t *wnamebuf = NULL;
4363
4364 WIN32_FIND_DATAW wFileData;
4365 const wchar_t *po_wchars;
4366
4367 if (!path->wide) { /* Default arg: "." */
4368 po_wchars = L".";
4369 len = 1;
4370 return_bytes = 0;
4371 } else {
4372 po_wchars = path->wide;
4373 len = wcslen(path->wide);
4374 return_bytes = PyBytes_Check(path->object);
4375 }
4376 /* The +5 is so we can append "\\*.*\0" */
4377 wnamebuf = PyMem_New(wchar_t, len + 5);
4378 if (!wnamebuf) {
4379 PyErr_NoMemory();
4380 goto exit;
4381 }
4382 wcscpy(wnamebuf, po_wchars);
4383 if (len > 0) {
4384 wchar_t wch = wnamebuf[len-1];
4385 if (wch != SEP && wch != ALTSEP && wch != L':')
4386 wnamebuf[len++] = SEP;
4387 wcscpy(wnamebuf + len, L"*.*");
4388 }
4389 if ((list = PyList_New(0)) == NULL) {
4390 goto exit;
4391 }
4392 Py_BEGIN_ALLOW_THREADS
4393 hFindFile = FindFirstFileW(wnamebuf, &wFileData);
4394 Py_END_ALLOW_THREADS
4395 if (hFindFile == INVALID_HANDLE_VALUE) {
4396 int error = GetLastError();
4397 if (error == ERROR_FILE_NOT_FOUND)
4398 goto exit;
4399 path_error(path);
4400 Py_CLEAR(list);
4401 goto exit;
4402 }
4403 do {
4404 /* Skip over . and .. */
4405 if (wcscmp(wFileData.cFileName, L".") != 0 &&
4406 wcscmp(wFileData.cFileName, L"..") != 0) {
4407 v = PyUnicode_FromWideChar(wFileData.cFileName,
4408 wcslen(wFileData.cFileName));
4409 if (return_bytes && v) {
4410 Py_SETREF(v, PyUnicode_EncodeFSDefault(v));
4411 }
4412 if (v == NULL) {
4413 Py_CLEAR(list);
4414 break;
4415 }
4416 if (PyList_Append(list, v) != 0) {
4417 Py_DECREF(v);
4418 Py_CLEAR(list);
4419 break;
4420 }
4421 Py_DECREF(v);
4422 }
4423 Py_BEGIN_ALLOW_THREADS
4424 result = FindNextFileW(hFindFile, &wFileData);
4425 Py_END_ALLOW_THREADS
4426 /* FindNextFile sets error to ERROR_NO_MORE_FILES if
4427 it got to the end of the directory. */
4428 if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
4429 path_error(path);
4430 Py_CLEAR(list);
4431 goto exit;
4432 }
4433 } while (result == TRUE);
4434
4435 exit:
4436 if (hFindFile != INVALID_HANDLE_VALUE) {
4437 if (FindClose(hFindFile) == FALSE) {
4438 if (list != NULL) {
4439 path_error(path);
4440 Py_CLEAR(list);
4441 }
4442 }
4443 }
4444 PyMem_Free(wnamebuf);
4445
4446 return list;
4447 } /* end of _listdir_windows_no_opendir */
4448
4449 #else /* thus POSIX, ie: not (MS_WINDOWS and not HAVE_OPENDIR) */
4450
4451 static PyObject *
_posix_listdir(path_t * path,PyObject * list)4452 _posix_listdir(path_t *path, PyObject *list)
4453 {
4454 PyObject *v;
4455 DIR *dirp = NULL;
4456 struct dirent *ep;
4457 int return_str; /* if false, return bytes */
4458 #ifdef HAVE_FDOPENDIR
4459 int fd = -1;
4460 #endif
4461
4462 errno = 0;
4463 #ifdef HAVE_FDOPENDIR
4464 if (path->fd != -1) {
4465 if (HAVE_FDOPENDIR_RUNTIME) {
4466 /* closedir() closes the FD, so we duplicate it */
4467 fd = _Py_dup(path->fd);
4468 if (fd == -1)
4469 return NULL;
4470
4471 return_str = 1;
4472
4473 Py_BEGIN_ALLOW_THREADS
4474 dirp = fdopendir(fd);
4475 Py_END_ALLOW_THREADS
4476 } else {
4477 PyErr_SetString(PyExc_TypeError,
4478 "listdir: path should be string, bytes, os.PathLike or None, not int");
4479 return NULL;
4480 }
4481 }
4482 else
4483 #endif
4484 {
4485 const char *name;
4486 if (path->narrow) {
4487 name = path->narrow;
4488 /* only return bytes if they specified a bytes object */
4489 return_str = !PyBytes_Check(path->object);
4490 }
4491 else {
4492 name = ".";
4493 return_str = 1;
4494 }
4495
4496 Py_BEGIN_ALLOW_THREADS
4497 dirp = opendir(name);
4498 Py_END_ALLOW_THREADS
4499 }
4500
4501 if (dirp == NULL) {
4502 path_error(path);
4503 list = NULL;
4504 #ifdef HAVE_FDOPENDIR
4505 if (fd != -1) {
4506 Py_BEGIN_ALLOW_THREADS
4507 close(fd);
4508 Py_END_ALLOW_THREADS
4509 }
4510 #endif
4511 goto exit;
4512 }
4513 if ((list = PyList_New(0)) == NULL) {
4514 goto exit;
4515 }
4516 for (;;) {
4517 errno = 0;
4518 Py_BEGIN_ALLOW_THREADS
4519 ep = readdir(dirp);
4520 Py_END_ALLOW_THREADS
4521 if (ep == NULL) {
4522 if (errno == 0) {
4523 break;
4524 } else {
4525 path_error(path);
4526 Py_CLEAR(list);
4527 goto exit;
4528 }
4529 }
4530 if (ep->d_name[0] == '.' &&
4531 (NAMLEN(ep) == 1 ||
4532 (ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
4533 continue;
4534 if (return_str)
4535 v = PyUnicode_DecodeFSDefaultAndSize(ep->d_name, NAMLEN(ep));
4536 else
4537 v = PyBytes_FromStringAndSize(ep->d_name, NAMLEN(ep));
4538 if (v == NULL) {
4539 Py_CLEAR(list);
4540 break;
4541 }
4542 if (PyList_Append(list, v) != 0) {
4543 Py_DECREF(v);
4544 Py_CLEAR(list);
4545 break;
4546 }
4547 Py_DECREF(v);
4548 }
4549
4550 exit:
4551 if (dirp != NULL) {
4552 Py_BEGIN_ALLOW_THREADS
4553 #ifdef HAVE_FDOPENDIR
4554 if (fd > -1)
4555 rewinddir(dirp);
4556 #endif
4557 closedir(dirp);
4558 Py_END_ALLOW_THREADS
4559 }
4560
4561 return list;
4562 } /* end of _posix_listdir */
4563 #endif /* which OS */
4564
4565
4566 /*[clinic input]
4567 os.listdir
4568
4569 path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None
4570
4571 Return a list containing the names of the files in the directory.
4572
4573 path can be specified as either str, bytes, or a path-like object. If path is bytes,
4574 the filenames returned will also be bytes; in all other circumstances
4575 the filenames returned will be str.
4576 If path is None, uses the path='.'.
4577 On some platforms, path may also be specified as an open file descriptor;\
4578 the file descriptor must refer to a directory.
4579 If this functionality is unavailable, using it raises NotImplementedError.
4580
4581 The list is in arbitrary order. It does not include the special
4582 entries '.' and '..' even if they are present in the directory.
4583
4584
4585 [clinic start generated code]*/
4586
4587 static PyObject *
os_listdir_impl(PyObject * module,path_t * path)4588 os_listdir_impl(PyObject *module, path_t *path)
4589 /*[clinic end generated code: output=293045673fcd1a75 input=e3f58030f538295d]*/
4590 {
4591 if (PySys_Audit("os.listdir", "O",
4592 path->object ? path->object : Py_None) < 0) {
4593 return NULL;
4594 }
4595 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
4596 return _listdir_windows_no_opendir(path, NULL);
4597 #else
4598 return _posix_listdir(path, NULL);
4599 #endif
4600 }
4601
4602
4603 #ifdef MS_WINDOWS
4604
4605 /*[clinic input]
4606 os.listdrives
4607
4608 Return a list containing the names of drives in the system.
4609
4610 A drive name typically looks like 'C:\\'.
4611
4612 [clinic start generated code]*/
4613
4614 static PyObject *
os_listdrives_impl(PyObject * module)4615 os_listdrives_impl(PyObject *module)
4616 /*[clinic end generated code: output=aaece9dacdf682b5 input=1af9ccc9e583798e]*/
4617 {
4618 /* Number of possible drives is limited, so 256 should always be enough.
4619 On the day when it is not, listmounts() will have to be used. */
4620 wchar_t buffer[256];
4621 DWORD buflen = Py_ARRAY_LENGTH(buffer);
4622 PyObject *result = NULL;
4623 if (PySys_Audit("os.listdrives", NULL) < 0) {
4624 return NULL;
4625 }
4626
4627 Py_BEGIN_ALLOW_THREADS;
4628 buflen = GetLogicalDriveStringsW(buflen, buffer);
4629 Py_END_ALLOW_THREADS;
4630
4631 if (!buflen) {
4632 PyErr_SetFromWindowsErr(0);
4633 return NULL;
4634 } else if (buflen >= Py_ARRAY_LENGTH(buffer)) {
4635 PyErr_SetFromWindowsErr(ERROR_MORE_DATA);
4636 return NULL;
4637 }
4638
4639 /* buflen includes a null terminator, so remove it */
4640 PyObject *str = PyUnicode_FromWideChar(buffer, buflen - 1);
4641 if (str) {
4642 PyObject *nullchar = PyUnicode_FromStringAndSize("\0", 1);
4643 if (nullchar) {
4644 result = PyUnicode_Split(str, nullchar, -1);
4645 Py_DECREF(nullchar);
4646 }
4647 Py_DECREF(str);
4648 }
4649 return result;
4650 }
4651
4652 /*[clinic input]
4653 os.listvolumes
4654
4655 Return a list containing the volumes in the system.
4656
4657 Volumes are typically represented as a GUID path.
4658
4659 [clinic start generated code]*/
4660
4661 static PyObject *
os_listvolumes_impl(PyObject * module)4662 os_listvolumes_impl(PyObject *module)
4663 /*[clinic end generated code: output=534e10ea2bf9d386 input=f6e4e70371f11e99]*/
4664 {
4665 PyObject *result = PyList_New(0);
4666 HANDLE find = INVALID_HANDLE_VALUE;
4667 wchar_t buffer[MAX_PATH + 1];
4668 if (!result) {
4669 return NULL;
4670 }
4671 if (PySys_Audit("os.listvolumes", NULL) < 0) {
4672 Py_DECREF(result);
4673 return NULL;
4674 }
4675
4676 int err = 0;
4677 Py_BEGIN_ALLOW_THREADS;
4678 find = FindFirstVolumeW(buffer, Py_ARRAY_LENGTH(buffer));
4679 if (find == INVALID_HANDLE_VALUE) {
4680 err = GetLastError();
4681 }
4682 Py_END_ALLOW_THREADS;
4683
4684 while (!err) {
4685 PyObject *s = PyUnicode_FromWideChar(buffer, -1);
4686 if (!s || PyList_Append(result, s) < 0) {
4687 Py_XDECREF(s);
4688 Py_CLEAR(result);
4689 break;
4690 }
4691 Py_DECREF(s);
4692
4693 Py_BEGIN_ALLOW_THREADS;
4694 if (!FindNextVolumeW(find, buffer, Py_ARRAY_LENGTH(buffer))) {
4695 err = GetLastError();
4696 }
4697 Py_END_ALLOW_THREADS;
4698 }
4699
4700 if (find != INVALID_HANDLE_VALUE) {
4701 Py_BEGIN_ALLOW_THREADS;
4702 FindVolumeClose(find);
4703 Py_END_ALLOW_THREADS;
4704 }
4705 if (err && err != ERROR_NO_MORE_FILES) {
4706 PyErr_SetFromWindowsErr(err);
4707 Py_XDECREF(result);
4708 result = NULL;
4709 }
4710 return result;
4711 }
4712
4713
4714 /*[clinic input]
4715 os.listmounts
4716
4717 volume: path_t
4718
4719 Return a list containing mount points for a particular volume.
4720
4721 'volume' should be a GUID path as returned from os.listvolumes.
4722
4723 [clinic start generated code]*/
4724
4725 static PyObject *
os_listmounts_impl(PyObject * module,path_t * volume)4726 os_listmounts_impl(PyObject *module, path_t *volume)
4727 /*[clinic end generated code: output=06da49679de4512e input=a8a27178e3f67845]*/
4728 {
4729 wchar_t default_buffer[MAX_PATH + 1];
4730 DWORD buflen = Py_ARRAY_LENGTH(default_buffer);
4731 LPWSTR buffer = default_buffer;
4732 DWORD attributes;
4733 PyObject *str = NULL;
4734 PyObject *nullchar = NULL;
4735 PyObject *result = NULL;
4736
4737 /* Ensure we have a valid volume path before continuing */
4738 Py_BEGIN_ALLOW_THREADS
4739 attributes = GetFileAttributesW(volume->wide);
4740 Py_END_ALLOW_THREADS
4741 if (attributes == INVALID_FILE_ATTRIBUTES &&
4742 GetLastError() == ERROR_UNRECOGNIZED_VOLUME)
4743 {
4744 return PyErr_SetFromWindowsErr(ERROR_UNRECOGNIZED_VOLUME);
4745 }
4746
4747 if (PySys_Audit("os.listmounts", "O", volume->object) < 0) {
4748 return NULL;
4749 }
4750
4751 while (1) {
4752 BOOL success;
4753 Py_BEGIN_ALLOW_THREADS
4754 success = GetVolumePathNamesForVolumeNameW(volume->wide, buffer,
4755 buflen, &buflen);
4756 Py_END_ALLOW_THREADS
4757 if (success) {
4758 break;
4759 }
4760 if (GetLastError() != ERROR_MORE_DATA) {
4761 PyErr_SetFromWindowsErr(0);
4762 goto exit;
4763 }
4764 if (buffer != default_buffer) {
4765 PyMem_Free((void *)buffer);
4766 }
4767 buffer = (wchar_t*)PyMem_Malloc(sizeof(wchar_t) * buflen);
4768 if (!buffer) {
4769 PyErr_NoMemory();
4770 goto exit;
4771 }
4772 }
4773 if (buflen < 2) {
4774 result = PyList_New(0);
4775 goto exit;
4776 }
4777 // buflen includes two null terminators, one for the last string
4778 // and one for the array of strings.
4779 str = PyUnicode_FromWideChar(buffer, buflen - 2);
4780 nullchar = PyUnicode_FromStringAndSize("\0", 1);
4781 if (str && nullchar) {
4782 result = PyUnicode_Split(str, nullchar, -1);
4783 }
4784 exit:
4785 if (buffer != default_buffer) {
4786 PyMem_Free(buffer);
4787 }
4788 Py_XDECREF(nullchar);
4789 Py_XDECREF(str);
4790 return result;
4791 }
4792
4793
4794 /*[clinic input]
4795 os._path_isdevdrive
4796
4797 path: path_t
4798
4799 Determines whether the specified path is on a Windows Dev Drive.
4800
4801 [clinic start generated code]*/
4802
4803 static PyObject *
os__path_isdevdrive_impl(PyObject * module,path_t * path)4804 os__path_isdevdrive_impl(PyObject *module, path_t *path)
4805 /*[clinic end generated code: output=1f437ea6677433a2 input=ee83e4996a48e23d]*/
4806 {
4807 #ifndef PERSISTENT_VOLUME_STATE_DEV_VOLUME
4808 /* This flag will be documented at
4809 https://learn.microsoft.com/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_persistent_volume_information
4810 after release, and will be available in the latest WinSDK.
4811 We include the flag to avoid a specific version dependency
4812 on the latest WinSDK. */
4813 const int PERSISTENT_VOLUME_STATE_DEV_VOLUME = 0x00002000;
4814 #endif
4815 int err = 0;
4816 PyObject *r = NULL;
4817 wchar_t volume[MAX_PATH];
4818
4819 Py_BEGIN_ALLOW_THREADS
4820 if (!GetVolumePathNameW(path->wide, volume, MAX_PATH)) {
4821 /* invalid path of some kind */
4822 /* Note that this also includes the case where a volume is mounted
4823 in a path longer than 260 characters. This is likely to be rare
4824 and problematic for other reasons, so a (soft) failure in this
4825 check seems okay. */
4826 err = GetLastError();
4827 } else if (GetDriveTypeW(volume) != DRIVE_FIXED) {
4828 /* only care about local dev drives */
4829 r = Py_False;
4830 } else {
4831 HANDLE hVolume = CreateFileW(
4832 volume,
4833 FILE_READ_ATTRIBUTES,
4834 FILE_SHARE_READ | FILE_SHARE_WRITE,
4835 NULL,
4836 OPEN_EXISTING,
4837 FILE_FLAG_BACKUP_SEMANTICS,
4838 NULL
4839 );
4840 if (hVolume == INVALID_HANDLE_VALUE) {
4841 err = GetLastError();
4842 } else {
4843 FILE_FS_PERSISTENT_VOLUME_INFORMATION volumeState = {0};
4844 volumeState.Version = 1;
4845 volumeState.FlagMask = PERSISTENT_VOLUME_STATE_DEV_VOLUME;
4846 if (!DeviceIoControl(
4847 hVolume,
4848 FSCTL_QUERY_PERSISTENT_VOLUME_STATE,
4849 &volumeState,
4850 sizeof(volumeState),
4851 &volumeState,
4852 sizeof(volumeState),
4853 NULL,
4854 NULL
4855 )) {
4856 err = GetLastError();
4857 }
4858 CloseHandle(hVolume);
4859 if (err == ERROR_INVALID_PARAMETER) {
4860 /* not supported on this platform */
4861 r = Py_False;
4862 } else if (!err) {
4863 r = (volumeState.VolumeFlags & PERSISTENT_VOLUME_STATE_DEV_VOLUME)
4864 ? Py_True : Py_False;
4865 }
4866 }
4867 }
4868 Py_END_ALLOW_THREADS
4869
4870 if (err) {
4871 PyErr_SetFromWindowsErr(err);
4872 return NULL;
4873 }
4874
4875 if (r) {
4876 return Py_NewRef(r);
4877 }
4878
4879 return NULL;
4880 }
4881
4882
4883 int
_PyOS_getfullpathname(const wchar_t * path,wchar_t ** abspath_p)4884 _PyOS_getfullpathname(const wchar_t *path, wchar_t **abspath_p)
4885 {
4886 wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf;
4887 DWORD result;
4888
4889 result = GetFullPathNameW(path,
4890 Py_ARRAY_LENGTH(woutbuf), woutbuf,
4891 NULL);
4892 if (!result) {
4893 return -1;
4894 }
4895
4896 if (result >= Py_ARRAY_LENGTH(woutbuf)) {
4897 if ((size_t)result <= (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) {
4898 woutbufp = PyMem_RawMalloc((size_t)result * sizeof(wchar_t));
4899 }
4900 else {
4901 woutbufp = NULL;
4902 }
4903 if (!woutbufp) {
4904 *abspath_p = NULL;
4905 return 0;
4906 }
4907
4908 result = GetFullPathNameW(path, result, woutbufp, NULL);
4909 if (!result) {
4910 PyMem_RawFree(woutbufp);
4911 return -1;
4912 }
4913 }
4914
4915 if (woutbufp != woutbuf) {
4916 *abspath_p = woutbufp;
4917 return 0;
4918 }
4919
4920 *abspath_p = _PyMem_RawWcsdup(woutbufp);
4921 return 0;
4922 }
4923
4924
4925 /* A helper function for abspath on win32 */
4926 /*[clinic input]
4927 os._getfullpathname
4928
4929 path: path_t
4930 /
4931
4932 [clinic start generated code]*/
4933
4934 static PyObject *
os__getfullpathname_impl(PyObject * module,path_t * path)4935 os__getfullpathname_impl(PyObject *module, path_t *path)
4936 /*[clinic end generated code: output=bb8679d56845bc9b input=332ed537c29d0a3e]*/
4937 {
4938 wchar_t *abspath;
4939
4940 if (_PyOS_getfullpathname(path->wide, &abspath) < 0) {
4941 return win32_error_object("GetFullPathNameW", path->object);
4942 }
4943 if (abspath == NULL) {
4944 return PyErr_NoMemory();
4945 }
4946
4947 PyObject *str = PyUnicode_FromWideChar(abspath, wcslen(abspath));
4948 PyMem_RawFree(abspath);
4949 if (str == NULL) {
4950 return NULL;
4951 }
4952 if (PyBytes_Check(path->object)) {
4953 Py_SETREF(str, PyUnicode_EncodeFSDefault(str));
4954 }
4955 return str;
4956 }
4957
4958
4959 /*[clinic input]
4960 os._getfinalpathname
4961
4962 path: path_t
4963 /
4964
4965 A helper function for samepath on windows.
4966 [clinic start generated code]*/
4967
4968 static PyObject *
os__getfinalpathname_impl(PyObject * module,path_t * path)4969 os__getfinalpathname_impl(PyObject *module, path_t *path)
4970 /*[clinic end generated code: output=621a3c79bc29ebfa input=2b6b6c7cbad5fb84]*/
4971 {
4972 HANDLE hFile;
4973 wchar_t buf[MAXPATHLEN], *target_path = buf;
4974 int buf_size = Py_ARRAY_LENGTH(buf);
4975 int result_length;
4976 PyObject *result;
4977
4978 Py_BEGIN_ALLOW_THREADS
4979 hFile = CreateFileW(
4980 path->wide,
4981 0, /* desired access */
4982 0, /* share mode */
4983 NULL, /* security attributes */
4984 OPEN_EXISTING,
4985 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
4986 FILE_FLAG_BACKUP_SEMANTICS,
4987 NULL);
4988 Py_END_ALLOW_THREADS
4989
4990 if (hFile == INVALID_HANDLE_VALUE) {
4991 return win32_error_object("CreateFileW", path->object);
4992 }
4993
4994 /* We have a good handle to the target, use it to determine the
4995 target path name. */
4996 while (1) {
4997 Py_BEGIN_ALLOW_THREADS
4998 result_length = GetFinalPathNameByHandleW(hFile, target_path,
4999 buf_size, VOLUME_NAME_DOS);
5000 Py_END_ALLOW_THREADS
5001
5002 if (!result_length) {
5003 result = win32_error_object("GetFinalPathNameByHandleW",
5004 path->object);
5005 goto cleanup;
5006 }
5007
5008 if (result_length < buf_size) {
5009 break;
5010 }
5011
5012 wchar_t *tmp;
5013 tmp = PyMem_Realloc(target_path != buf ? target_path : NULL,
5014 result_length * sizeof(*tmp));
5015 if (!tmp) {
5016 result = PyErr_NoMemory();
5017 goto cleanup;
5018 }
5019
5020 buf_size = result_length;
5021 target_path = tmp;
5022 }
5023
5024 result = PyUnicode_FromWideChar(target_path, result_length);
5025 if (result && PyBytes_Check(path->object)) {
5026 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
5027 }
5028
5029 cleanup:
5030 if (target_path != buf) {
5031 PyMem_Free(target_path);
5032 }
5033 CloseHandle(hFile);
5034 return result;
5035 }
5036
5037 /*[clinic input]
5038 os._findfirstfile
5039 path: path_t
5040 /
5041 A function to get the real file name without accessing the file in Windows.
5042 [clinic start generated code]*/
5043
5044 static PyObject *
os__findfirstfile_impl(PyObject * module,path_t * path)5045 os__findfirstfile_impl(PyObject *module, path_t *path)
5046 /*[clinic end generated code: output=106dd3f0779c83dd input=0734dff70f60e1a8]*/
5047 {
5048 PyObject *result;
5049 HANDLE hFindFile;
5050 WIN32_FIND_DATAW wFileData;
5051 WCHAR *wRealFileName;
5052
5053 Py_BEGIN_ALLOW_THREADS
5054 hFindFile = FindFirstFileW(path->wide, &wFileData);
5055 Py_END_ALLOW_THREADS
5056
5057 if (hFindFile == INVALID_HANDLE_VALUE) {
5058 path_error(path);
5059 return NULL;
5060 }
5061
5062 wRealFileName = wFileData.cFileName;
5063 result = PyUnicode_FromWideChar(wRealFileName, wcslen(wRealFileName));
5064 FindClose(hFindFile);
5065 return result;
5066 }
5067
5068
5069 /*[clinic input]
5070 os._getvolumepathname
5071
5072 path: path_t
5073
5074 A helper function for ismount on Win32.
5075 [clinic start generated code]*/
5076
5077 static PyObject *
os__getvolumepathname_impl(PyObject * module,path_t * path)5078 os__getvolumepathname_impl(PyObject *module, path_t *path)
5079 /*[clinic end generated code: output=804c63fd13a1330b input=722b40565fa21552]*/
5080 {
5081 PyObject *result;
5082 wchar_t *mountpath=NULL;
5083 size_t buflen;
5084 BOOL ret;
5085
5086 /* Volume path should be shorter than entire path */
5087 buflen = Py_MAX(path->length, MAX_PATH);
5088
5089 if (buflen > PY_DWORD_MAX) {
5090 PyErr_SetString(PyExc_OverflowError, "path too long");
5091 return NULL;
5092 }
5093
5094 mountpath = PyMem_New(wchar_t, buflen);
5095 if (mountpath == NULL)
5096 return PyErr_NoMemory();
5097
5098 Py_BEGIN_ALLOW_THREADS
5099 ret = GetVolumePathNameW(path->wide, mountpath,
5100 Py_SAFE_DOWNCAST(buflen, size_t, DWORD));
5101 Py_END_ALLOW_THREADS
5102
5103 if (!ret) {
5104 result = win32_error_object("_getvolumepathname", path->object);
5105 goto exit;
5106 }
5107 result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath));
5108 if (PyBytes_Check(path->object))
5109 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
5110
5111 exit:
5112 PyMem_Free(mountpath);
5113 return result;
5114 }
5115
5116
5117 /*[clinic input]
5118 os._path_splitroot
5119
5120 path: path_t
5121
5122 Removes everything after the root on Win32.
5123 [clinic start generated code]*/
5124
5125 static PyObject *
os__path_splitroot_impl(PyObject * module,path_t * path)5126 os__path_splitroot_impl(PyObject *module, path_t *path)
5127 /*[clinic end generated code: output=ab7f1a88b654581c input=dc93b1d3984cffb6]*/
5128 {
5129 wchar_t *buffer;
5130 wchar_t *end;
5131 PyObject *result = NULL;
5132 HRESULT ret;
5133
5134 buffer = (wchar_t*)PyMem_Malloc(sizeof(wchar_t) * (wcslen(path->wide) + 1));
5135 if (!buffer) {
5136 return NULL;
5137 }
5138 wcscpy(buffer, path->wide);
5139 for (wchar_t *p = wcschr(buffer, L'/'); p; p = wcschr(p, L'/')) {
5140 *p = L'\\';
5141 }
5142
5143 Py_BEGIN_ALLOW_THREADS
5144 ret = PathCchSkipRoot(buffer, &end);
5145 Py_END_ALLOW_THREADS
5146 if (FAILED(ret)) {
5147 result = Py_BuildValue("sO", "", path->object);
5148 } else if (end != buffer) {
5149 size_t rootLen = (size_t)(end - buffer);
5150 result = Py_BuildValue("NN",
5151 PyUnicode_FromWideChar(path->wide, rootLen),
5152 PyUnicode_FromWideChar(path->wide + rootLen, -1)
5153 );
5154 } else {
5155 result = Py_BuildValue("Os", path->object, "");
5156 }
5157 PyMem_Free(buffer);
5158
5159 return result;
5160 }
5161
5162
5163 #define PY_IFREG 1 // Regular file
5164 #define PY_IFDIR 2 // Directory
5165 #define PY_IFLNK 4 // Symlink
5166 #define PY_IFMNT 8 // Mount Point (junction)
5167 #define PY_IFLRP 16 // Link Reparse Point (name-surrogate, symlink, junction)
5168 #define PY_IFRRP 32 // Regular Reparse Point
5169
5170 static inline BOOL
_testInfo(DWORD attributes,DWORD reparseTag,BOOL diskDevice,int testedType)5171 _testInfo(DWORD attributes, DWORD reparseTag, BOOL diskDevice, int testedType)
5172 {
5173 switch (testedType) {
5174 case PY_IFREG:
5175 return diskDevice && attributes &&
5176 !(attributes & FILE_ATTRIBUTE_DIRECTORY);
5177 case PY_IFDIR:
5178 return attributes & FILE_ATTRIBUTE_DIRECTORY;
5179 case PY_IFLNK:
5180 return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
5181 reparseTag == IO_REPARSE_TAG_SYMLINK;
5182 case PY_IFMNT:
5183 return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
5184 reparseTag == IO_REPARSE_TAG_MOUNT_POINT;
5185 case PY_IFLRP:
5186 return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
5187 IsReparseTagNameSurrogate(reparseTag);
5188 case PY_IFRRP:
5189 return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
5190 reparseTag && !IsReparseTagNameSurrogate(reparseTag);
5191 }
5192
5193 return FALSE;
5194 }
5195
5196 static BOOL
_testFileTypeByHandle(HANDLE hfile,int testedType,BOOL diskOnly)5197 _testFileTypeByHandle(HANDLE hfile, int testedType, BOOL diskOnly)
5198 {
5199 assert(testedType == PY_IFREG || testedType == PY_IFDIR ||
5200 testedType == PY_IFLNK || testedType == PY_IFMNT ||
5201 testedType == PY_IFLRP || testedType == PY_IFRRP);
5202
5203 BOOL diskDevice = GetFileType(hfile) == FILE_TYPE_DISK;
5204 if (diskOnly && !diskDevice) {
5205 return FALSE;
5206 }
5207 if (testedType != PY_IFREG && testedType != PY_IFDIR) {
5208 FILE_ATTRIBUTE_TAG_INFO info;
5209 return GetFileInformationByHandleEx(hfile, FileAttributeTagInfo, &info,
5210 sizeof(info)) &&
5211 _testInfo(info.FileAttributes, info.ReparseTag, diskDevice,
5212 testedType);
5213 }
5214 FILE_BASIC_INFO info;
5215 return GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
5216 sizeof(info)) &&
5217 _testInfo(info.FileAttributes, 0, diskDevice, testedType);
5218 }
5219
5220 static BOOL
_testFileTypeByName(LPCWSTR path,int testedType)5221 _testFileTypeByName(LPCWSTR path, int testedType)
5222 {
5223 assert(testedType == PY_IFREG || testedType == PY_IFDIR ||
5224 testedType == PY_IFLNK || testedType == PY_IFMNT ||
5225 testedType == PY_IFLRP || testedType == PY_IFRRP);
5226
5227 FILE_STAT_BASIC_INFORMATION info;
5228 if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, &info,
5229 sizeof(info)))
5230 {
5231 BOOL diskDevice = info.DeviceType == FILE_DEVICE_DISK ||
5232 info.DeviceType == FILE_DEVICE_VIRTUAL_DISK ||
5233 info.DeviceType == FILE_DEVICE_CD_ROM;
5234 BOOL result = _testInfo(info.FileAttributes, info.ReparseTag,
5235 diskDevice, testedType);
5236 if (!result || (testedType != PY_IFREG && testedType != PY_IFDIR) ||
5237 !(info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
5238 {
5239 return result;
5240 }
5241 }
5242 else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(
5243 GetLastError()))
5244 {
5245 return FALSE;
5246 }
5247
5248 DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
5249 if (testedType != PY_IFREG && testedType != PY_IFDIR) {
5250 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5251 }
5252 HANDLE hfile = CreateFileW(path, FILE_READ_ATTRIBUTES, 0, NULL,
5253 OPEN_EXISTING, flags, NULL);
5254 if (hfile != INVALID_HANDLE_VALUE) {
5255 BOOL result = _testFileTypeByHandle(hfile, testedType, FALSE);
5256 CloseHandle(hfile);
5257 return result;
5258 }
5259
5260 switch (GetLastError()) {
5261 case ERROR_ACCESS_DENIED:
5262 case ERROR_SHARING_VIOLATION:
5263 case ERROR_CANT_ACCESS_FILE:
5264 case ERROR_INVALID_PARAMETER:
5265 int rc;
5266 STRUCT_STAT st;
5267 if (testedType == PY_IFREG || testedType == PY_IFDIR) {
5268 rc = STAT(path, &st);
5269 }
5270 else {
5271 // PY_IFRRP is not generally supported in this case, except for
5272 // unhandled reparse points such as IO_REPARSE_TAG_APPEXECLINK.
5273 rc = LSTAT(path, &st);
5274 }
5275 if (!rc) {
5276 return _testInfo(st.st_file_attributes, st.st_reparse_tag,
5277 st.st_mode & S_IFREG, testedType);
5278 }
5279 }
5280
5281 return FALSE;
5282 }
5283
5284
5285 static BOOL
_testFileExistsByName(LPCWSTR path,BOOL followLinks)5286 _testFileExistsByName(LPCWSTR path, BOOL followLinks)
5287 {
5288 FILE_STAT_BASIC_INFORMATION info;
5289 if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, &info,
5290 sizeof(info)))
5291 {
5292 if (!(info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ||
5293 !followLinks && IsReparseTagNameSurrogate(info.ReparseTag))
5294 {
5295 return TRUE;
5296 }
5297 }
5298 else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(
5299 GetLastError()))
5300 {
5301 return FALSE;
5302 }
5303
5304 DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
5305 if (!followLinks) {
5306 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5307 }
5308 HANDLE hfile = CreateFileW(path, FILE_READ_ATTRIBUTES, 0, NULL,
5309 OPEN_EXISTING, flags, NULL);
5310 if (hfile != INVALID_HANDLE_VALUE) {
5311 if (followLinks) {
5312 CloseHandle(hfile);
5313 return TRUE;
5314 }
5315 // Regular Reparse Points (PY_IFRRP) have to be traversed.
5316 BOOL result = _testFileTypeByHandle(hfile, PY_IFRRP, FALSE);
5317 CloseHandle(hfile);
5318 if (!result) {
5319 return TRUE;
5320 }
5321 hfile = CreateFileW(path, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
5322 FILE_FLAG_BACKUP_SEMANTICS, NULL);
5323 if (hfile != INVALID_HANDLE_VALUE) {
5324 CloseHandle(hfile);
5325 return TRUE;
5326 }
5327 }
5328
5329 switch (GetLastError()) {
5330 case ERROR_ACCESS_DENIED:
5331 case ERROR_SHARING_VIOLATION:
5332 case ERROR_CANT_ACCESS_FILE:
5333 case ERROR_INVALID_PARAMETER:
5334 STRUCT_STAT _st;
5335 return followLinks ? !STAT(path, &_st): !LSTAT(path, &_st);
5336 }
5337
5338 return FALSE;
5339 }
5340
5341
5342 static BOOL
_testFileExists(path_t * path,BOOL followLinks)5343 _testFileExists(path_t *path, BOOL followLinks)
5344 {
5345 BOOL result = FALSE;
5346 if (path->value_error) {
5347 return FALSE;
5348 }
5349
5350 Py_BEGIN_ALLOW_THREADS
5351 if (path->fd != -1) {
5352 HANDLE hfile = _Py_get_osfhandle_noraise(path->fd);
5353 if (hfile != INVALID_HANDLE_VALUE) {
5354 if (GetFileType(hfile) != FILE_TYPE_UNKNOWN || !GetLastError()) {
5355 result = TRUE;
5356 }
5357 }
5358 }
5359 else if (path->wide) {
5360 result = _testFileExistsByName(path->wide, followLinks);
5361 }
5362 Py_END_ALLOW_THREADS
5363
5364 return result;
5365 }
5366
5367
5368 static BOOL
_testFileType(path_t * path,int testedType)5369 _testFileType(path_t *path, int testedType)
5370 {
5371 BOOL result = FALSE;
5372 if (path->value_error) {
5373 return FALSE;
5374 }
5375
5376 Py_BEGIN_ALLOW_THREADS
5377 if (path->fd != -1) {
5378 HANDLE hfile = _Py_get_osfhandle_noraise(path->fd);
5379 if (hfile != INVALID_HANDLE_VALUE) {
5380 result = _testFileTypeByHandle(hfile, testedType, TRUE);
5381 }
5382 }
5383 else if (path->wide) {
5384 result = _testFileTypeByName(path->wide, testedType);
5385 }
5386 Py_END_ALLOW_THREADS
5387
5388 return result;
5389 }
5390
5391
5392 /*[clinic input]
5393 os._path_exists -> bool
5394
5395 path: path_t(allow_fd=True, suppress_value_error=True)
5396
5397 Test whether a path exists. Returns False for broken symbolic links.
5398
5399 [clinic start generated code]*/
5400
5401 static int
os__path_exists_impl(PyObject * module,path_t * path)5402 os__path_exists_impl(PyObject *module, path_t *path)
5403 /*[clinic end generated code: output=8da13acf666e16ba input=142beabfc66783eb]*/
5404 {
5405 return _testFileExists(path, TRUE);
5406 }
5407
5408
5409 /*[clinic input]
5410 os._path_lexists -> bool
5411
5412 path: path_t(allow_fd=True, suppress_value_error=True)
5413
5414 Test whether a path exists. Returns True for broken symbolic links.
5415
5416 [clinic start generated code]*/
5417
5418 static int
os__path_lexists_impl(PyObject * module,path_t * path)5419 os__path_lexists_impl(PyObject *module, path_t *path)
5420 /*[clinic end generated code: output=e7240ed5fc45bff3 input=208205112a3cc1ed]*/
5421 {
5422 return _testFileExists(path, FALSE);
5423 }
5424
5425
5426 /*[clinic input]
5427 os._path_isdir -> bool
5428
5429 s as path: path_t(allow_fd=True, suppress_value_error=True)
5430
5431 Return true if the pathname refers to an existing directory.
5432
5433 [clinic start generated code]*/
5434
5435 static int
os__path_isdir_impl(PyObject * module,path_t * path)5436 os__path_isdir_impl(PyObject *module, path_t *path)
5437 /*[clinic end generated code: output=d5786196f9e2fa7a input=132a3b5301aecf79]*/
5438 {
5439 return _testFileType(path, PY_IFDIR);
5440 }
5441
5442
5443 /*[clinic input]
5444 os._path_isfile -> bool
5445
5446 path: path_t(allow_fd=True, suppress_value_error=True)
5447
5448 Test whether a path is a regular file
5449
5450 [clinic start generated code]*/
5451
5452 static int
os__path_isfile_impl(PyObject * module,path_t * path)5453 os__path_isfile_impl(PyObject *module, path_t *path)
5454 /*[clinic end generated code: output=5c3073bc212b9863 input=4ac1fd350b30a39e]*/
5455 {
5456 return _testFileType(path, PY_IFREG);
5457 }
5458
5459
5460 /*[clinic input]
5461 os._path_islink -> bool
5462
5463 path: path_t(allow_fd=True, suppress_value_error=True)
5464
5465 Test whether a path is a symbolic link
5466
5467 [clinic start generated code]*/
5468
5469 static int
os__path_islink_impl(PyObject * module,path_t * path)5470 os__path_islink_impl(PyObject *module, path_t *path)
5471 /*[clinic end generated code: output=30da7bda8296adcc input=7510ce05b547debb]*/
5472 {
5473 return _testFileType(path, PY_IFLNK);
5474 }
5475
5476
5477 /*[clinic input]
5478 os._path_isjunction -> bool
5479
5480 path: path_t(allow_fd=True, suppress_value_error=True)
5481
5482 Test whether a path is a junction
5483
5484 [clinic start generated code]*/
5485
5486 static int
os__path_isjunction_impl(PyObject * module,path_t * path)5487 os__path_isjunction_impl(PyObject *module, path_t *path)
5488 /*[clinic end generated code: output=e1d17a9dd18a9945 input=7dcb8bc4e972fcaf]*/
5489 {
5490 return _testFileType(path, PY_IFMNT);
5491 }
5492
5493 #undef PY_IFREG
5494 #undef PY_IFDIR
5495 #undef PY_IFLNK
5496 #undef PY_IFMNT
5497 #undef PY_IFLRP
5498 #undef PY_IFRRP
5499
5500 #endif /* MS_WINDOWS */
5501
5502
5503 /*[clinic input]
5504 os._path_splitroot_ex
5505
5506 p as path: path_t(make_wide=True, nonstrict=True)
5507
5508 Split a pathname into drive, root and tail.
5509
5510 The tail contains anything after the root.
5511 [clinic start generated code]*/
5512
5513 static PyObject *
os__path_splitroot_ex_impl(PyObject * module,path_t * path)5514 os__path_splitroot_ex_impl(PyObject *module, path_t *path)
5515 /*[clinic end generated code: output=4b0072b6cdf4b611 input=4556b615c7cc13f2]*/
5516 {
5517 Py_ssize_t drvsize, rootsize;
5518 PyObject *drv = NULL, *root = NULL, *tail = NULL, *result = NULL;
5519
5520 const wchar_t *buffer = path->wide;
5521 _Py_skiproot(buffer, path->length, &drvsize, &rootsize);
5522 drv = PyUnicode_FromWideChar(buffer, drvsize);
5523 if (drv == NULL) {
5524 goto exit;
5525 }
5526 root = PyUnicode_FromWideChar(&buffer[drvsize], rootsize);
5527 if (root == NULL) {
5528 goto exit;
5529 }
5530 tail = PyUnicode_FromWideChar(&buffer[drvsize + rootsize],
5531 path->length - drvsize - rootsize);
5532 if (tail == NULL) {
5533 goto exit;
5534 }
5535 if (PyBytes_Check(path->object)) {
5536 Py_SETREF(drv, PyUnicode_EncodeFSDefault(drv));
5537 if (drv == NULL) {
5538 goto exit;
5539 }
5540 Py_SETREF(root, PyUnicode_EncodeFSDefault(root));
5541 if (root == NULL) {
5542 goto exit;
5543 }
5544 Py_SETREF(tail, PyUnicode_EncodeFSDefault(tail));
5545 if (tail == NULL) {
5546 goto exit;
5547 }
5548 }
5549 result = PyTuple_Pack(3, drv, root, tail);
5550 exit:
5551 Py_XDECREF(drv);
5552 Py_XDECREF(root);
5553 Py_XDECREF(tail);
5554 return result;
5555 }
5556
5557
5558 /*[clinic input]
5559 os._path_normpath
5560
5561 path: path_t(make_wide=True, nonstrict=True)
5562
5563 Normalize path, eliminating double slashes, etc.
5564 [clinic start generated code]*/
5565
5566 static PyObject *
os__path_normpath_impl(PyObject * module,path_t * path)5567 os__path_normpath_impl(PyObject *module, path_t *path)
5568 /*[clinic end generated code: output=d353e7ed9410c044 input=3d4ac23b06332dcb]*/
5569 {
5570 PyObject *result;
5571 Py_ssize_t norm_len;
5572 wchar_t *norm_path = _Py_normpath_and_size((wchar_t *)path->wide,
5573 path->length, &norm_len);
5574 if (!norm_len) {
5575 result = PyUnicode_FromOrdinal('.');
5576 }
5577 else {
5578 result = PyUnicode_FromWideChar(norm_path, norm_len);
5579 }
5580 if (PyBytes_Check(path->object)) {
5581 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
5582 }
5583 return result;
5584 }
5585
5586 /*[clinic input]
5587 os.mkdir
5588
5589 path : path_t
5590
5591 mode: int = 0o777
5592
5593 *
5594
5595 dir_fd : dir_fd(requires='mkdirat') = None
5596
5597 # "mkdir(path, mode=0o777, *, dir_fd=None)\n\n\
5598
5599 Create a directory.
5600
5601 If dir_fd is not None, it should be a file descriptor open to a directory,
5602 and path should be relative; path will then be relative to that directory.
5603 dir_fd may not be implemented on your platform.
5604 If it is unavailable, using it will raise a NotImplementedError.
5605
5606 The mode argument is ignored on Windows. Where it is used, the current umask
5607 value is first masked out.
5608 [clinic start generated code]*/
5609
5610 static PyObject *
os_mkdir_impl(PyObject * module,path_t * path,int mode,int dir_fd)5611 os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
5612 /*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/
5613 {
5614 int result;
5615 #ifdef MS_WINDOWS
5616 int error = 0;
5617 int pathError = 0;
5618 SECURITY_ATTRIBUTES secAttr = { sizeof(secAttr) };
5619 SECURITY_ATTRIBUTES *pSecAttr = NULL;
5620 #endif
5621 #ifdef HAVE_MKDIRAT
5622 int mkdirat_unavailable = 0;
5623 #endif
5624
5625 if (PySys_Audit("os.mkdir", "Oii", path->object, mode,
5626 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
5627 return NULL;
5628 }
5629
5630 #ifdef MS_WINDOWS
5631 Py_BEGIN_ALLOW_THREADS
5632 if (mode == 0700 /* 0o700 */) {
5633 ULONG sdSize;
5634 pSecAttr = &secAttr;
5635 // Set a discretionary ACL (D) that is protected (P) and includes
5636 // inheritable (OICI) entries that allow (A) full control (FA) to
5637 // SYSTEM (SY), Administrators (BA), and the owner (OW).
5638 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
5639 L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)",
5640 SDDL_REVISION_1,
5641 &secAttr.lpSecurityDescriptor,
5642 &sdSize
5643 )) {
5644 error = GetLastError();
5645 }
5646 }
5647 if (!error) {
5648 result = CreateDirectoryW(path->wide, pSecAttr);
5649 if (secAttr.lpSecurityDescriptor &&
5650 // uncommonly, LocalFree returns non-zero on error, but still uses
5651 // GetLastError() to see what the error code is
5652 LocalFree(secAttr.lpSecurityDescriptor)) {
5653 error = GetLastError();
5654 }
5655 }
5656 Py_END_ALLOW_THREADS
5657
5658 if (error) {
5659 return PyErr_SetFromWindowsErr(error);
5660 }
5661 if (!result) {
5662 return path_error(path);
5663 }
5664 #else
5665 Py_BEGIN_ALLOW_THREADS
5666 #if HAVE_MKDIRAT
5667 if (dir_fd != DEFAULT_DIR_FD) {
5668 if (HAVE_MKDIRAT_RUNTIME) {
5669 result = mkdirat(dir_fd, path->narrow, mode);
5670
5671 } else {
5672 mkdirat_unavailable = 1;
5673 }
5674 } else
5675 #endif
5676 #if defined(__WATCOMC__) && !defined(__QNX__)
5677 result = mkdir(path->narrow);
5678 #else
5679 result = mkdir(path->narrow, mode);
5680 #endif
5681 Py_END_ALLOW_THREADS
5682
5683 #if HAVE_MKDIRAT
5684 if (mkdirat_unavailable) {
5685 argument_unavailable_error(NULL, "dir_fd");
5686 return NULL;
5687 }
5688 #endif
5689
5690 if (result < 0)
5691 return path_error(path);
5692 #endif /* MS_WINDOWS */
5693 Py_RETURN_NONE;
5694 }
5695
5696
5697 /* sys/resource.h is needed for at least: wait3(), wait4(), broken nice. */
5698 #if defined(HAVE_SYS_RESOURCE_H)
5699 #include <sys/resource.h>
5700 #endif
5701
5702
5703 #ifdef HAVE_NICE
5704 /*[clinic input]
5705 os.nice
5706
5707 increment: int
5708 /
5709
5710 Add increment to the priority of process and return the new priority.
5711 [clinic start generated code]*/
5712
5713 static PyObject *
os_nice_impl(PyObject * module,int increment)5714 os_nice_impl(PyObject *module, int increment)
5715 /*[clinic end generated code: output=9dad8a9da8109943 input=864be2d402a21da2]*/
5716 {
5717 int value;
5718
5719 /* There are two flavours of 'nice': one that returns the new
5720 priority (as required by almost all standards out there) and the
5721 Linux/FreeBSD one, which returns '0' on success and advices
5722 the use of getpriority() to get the new priority.
5723
5724 If we are of the nice family that returns the new priority, we
5725 need to clear errno before the call, and check if errno is filled
5726 before calling posix_error() on a returnvalue of -1, because the
5727 -1 may be the actual new priority! */
5728
5729 errno = 0;
5730 value = nice(increment);
5731 #if defined(HAVE_BROKEN_NICE) && defined(HAVE_GETPRIORITY)
5732 if (value == 0)
5733 value = getpriority(PRIO_PROCESS, 0);
5734 #endif
5735 if (value == -1 && errno != 0)
5736 /* either nice() or getpriority() returned an error */
5737 return posix_error();
5738 return PyLong_FromLong((long) value);
5739 }
5740 #endif /* HAVE_NICE */
5741
5742
5743 #ifdef HAVE_GETPRIORITY
5744 /*[clinic input]
5745 os.getpriority
5746
5747 which: int
5748 who: int
5749
5750 Return program scheduling priority.
5751 [clinic start generated code]*/
5752
5753 static PyObject *
os_getpriority_impl(PyObject * module,int which,int who)5754 os_getpriority_impl(PyObject *module, int which, int who)
5755 /*[clinic end generated code: output=c41b7b63c7420228 input=9be615d40e2544ef]*/
5756 {
5757 int retval;
5758
5759 errno = 0;
5760 retval = getpriority(which, who);
5761 if (errno != 0)
5762 return posix_error();
5763 return PyLong_FromLong((long)retval);
5764 }
5765 #endif /* HAVE_GETPRIORITY */
5766
5767
5768 #ifdef HAVE_SETPRIORITY
5769 /*[clinic input]
5770 os.setpriority
5771
5772 which: int
5773 who: int
5774 priority: int
5775
5776 Set program scheduling priority.
5777 [clinic start generated code]*/
5778
5779 static PyObject *
os_setpriority_impl(PyObject * module,int which,int who,int priority)5780 os_setpriority_impl(PyObject *module, int which, int who, int priority)
5781 /*[clinic end generated code: output=3d910d95a7771eb2 input=710ccbf65b9dc513]*/
5782 {
5783 int retval;
5784
5785 retval = setpriority(which, who, priority);
5786 if (retval == -1)
5787 return posix_error();
5788 Py_RETURN_NONE;
5789 }
5790 #endif /* HAVE_SETPRIORITY */
5791
5792
5793 static PyObject *
internal_rename(path_t * src,path_t * dst,int src_dir_fd,int dst_dir_fd,int is_replace)5794 internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is_replace)
5795 {
5796 const char *function_name = is_replace ? "replace" : "rename";
5797 int dir_fd_specified;
5798
5799 #ifdef HAVE_RENAMEAT
5800 int renameat_unavailable = 0;
5801 #endif
5802
5803 #ifdef MS_WINDOWS
5804 BOOL result;
5805 int flags = is_replace ? MOVEFILE_REPLACE_EXISTING : 0;
5806 #else
5807 int result;
5808 #endif
5809
5810 dir_fd_specified = (src_dir_fd != DEFAULT_DIR_FD) ||
5811 (dst_dir_fd != DEFAULT_DIR_FD);
5812 #ifndef HAVE_RENAMEAT
5813 if (dir_fd_specified) {
5814 argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd");
5815 return NULL;
5816 }
5817 #endif
5818
5819 if (PySys_Audit("os.rename", "OOii", src->object, dst->object,
5820 src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
5821 dst_dir_fd == DEFAULT_DIR_FD ? -1 : dst_dir_fd) < 0) {
5822 return NULL;
5823 }
5824
5825 #ifdef MS_WINDOWS
5826 Py_BEGIN_ALLOW_THREADS
5827 result = MoveFileExW(src->wide, dst->wide, flags);
5828 Py_END_ALLOW_THREADS
5829
5830 if (!result)
5831 return path_error2(src, dst);
5832
5833 #else
5834 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
5835 PyErr_Format(PyExc_ValueError,
5836 "%s: src and dst must be the same type", function_name);
5837 return NULL;
5838 }
5839
5840 Py_BEGIN_ALLOW_THREADS
5841 #ifdef HAVE_RENAMEAT
5842 if (dir_fd_specified) {
5843 if (HAVE_RENAMEAT_RUNTIME) {
5844 result = renameat(src_dir_fd, src->narrow, dst_dir_fd, dst->narrow);
5845 } else {
5846 renameat_unavailable = 1;
5847 }
5848 } else
5849 #endif
5850 result = rename(src->narrow, dst->narrow);
5851 Py_END_ALLOW_THREADS
5852
5853
5854 #ifdef HAVE_RENAMEAT
5855 if (renameat_unavailable) {
5856 argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd");
5857 return NULL;
5858 }
5859 #endif
5860
5861 if (result)
5862 return path_error2(src, dst);
5863 #endif
5864 Py_RETURN_NONE;
5865 }
5866
5867
5868 /*[clinic input]
5869 os.rename
5870
5871 src : path_t
5872 dst : path_t
5873 *
5874 src_dir_fd : dir_fd = None
5875 dst_dir_fd : dir_fd = None
5876
5877 Rename a file or directory.
5878
5879 If either src_dir_fd or dst_dir_fd is not None, it should be a file
5880 descriptor open to a directory, and the respective path string (src or dst)
5881 should be relative; the path will then be relative to that directory.
5882 src_dir_fd and dst_dir_fd, may not be implemented on your platform.
5883 If they are unavailable, using them will raise a NotImplementedError.
5884 [clinic start generated code]*/
5885
5886 static PyObject *
os_rename_impl(PyObject * module,path_t * src,path_t * dst,int src_dir_fd,int dst_dir_fd)5887 os_rename_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
5888 int dst_dir_fd)
5889 /*[clinic end generated code: output=59e803072cf41230 input=faa61c847912c850]*/
5890 {
5891 return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 0);
5892 }
5893
5894
5895 /*[clinic input]
5896 os.replace = os.rename
5897
5898 Rename a file or directory, overwriting the destination.
5899
5900 If either src_dir_fd or dst_dir_fd is not None, it should be a file
5901 descriptor open to a directory, and the respective path string (src or dst)
5902 should be relative; the path will then be relative to that directory.
5903 src_dir_fd and dst_dir_fd, may not be implemented on your platform.
5904 If they are unavailable, using them will raise a NotImplementedError.
5905 [clinic start generated code]*/
5906
5907 static PyObject *
os_replace_impl(PyObject * module,path_t * src,path_t * dst,int src_dir_fd,int dst_dir_fd)5908 os_replace_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
5909 int dst_dir_fd)
5910 /*[clinic end generated code: output=1968c02e7857422b input=c003f0def43378ef]*/
5911 {
5912 return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 1);
5913 }
5914
5915
5916 /*[clinic input]
5917 os.rmdir
5918
5919 path: path_t
5920 *
5921 dir_fd: dir_fd(requires='unlinkat') = None
5922
5923 Remove a directory.
5924
5925 If dir_fd is not None, it should be a file descriptor open to a directory,
5926 and path should be relative; path will then be relative to that directory.
5927 dir_fd may not be implemented on your platform.
5928 If it is unavailable, using it will raise a NotImplementedError.
5929 [clinic start generated code]*/
5930
5931 static PyObject *
os_rmdir_impl(PyObject * module,path_t * path,int dir_fd)5932 os_rmdir_impl(PyObject *module, path_t *path, int dir_fd)
5933 /*[clinic end generated code: output=080eb54f506e8301 input=38c8b375ca34a7e2]*/
5934 {
5935 int result;
5936 #ifdef HAVE_UNLINKAT
5937 int unlinkat_unavailable = 0;
5938 #endif
5939
5940 if (PySys_Audit("os.rmdir", "Oi", path->object,
5941 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
5942 return NULL;
5943 }
5944
5945 Py_BEGIN_ALLOW_THREADS
5946 #ifdef MS_WINDOWS
5947 /* Windows, success=1, UNIX, success=0 */
5948 result = !RemoveDirectoryW(path->wide);
5949 #else
5950 #ifdef HAVE_UNLINKAT
5951 if (dir_fd != DEFAULT_DIR_FD) {
5952 if (HAVE_UNLINKAT_RUNTIME) {
5953 result = unlinkat(dir_fd, path->narrow, AT_REMOVEDIR);
5954 } else {
5955 unlinkat_unavailable = 1;
5956 result = -1;
5957 }
5958 } else
5959 #endif
5960 result = rmdir(path->narrow);
5961 #endif
5962 Py_END_ALLOW_THREADS
5963
5964 #ifdef HAVE_UNLINKAT
5965 if (unlinkat_unavailable) {
5966 argument_unavailable_error("rmdir", "dir_fd");
5967 return NULL;
5968 }
5969 #endif
5970
5971 if (result)
5972 return path_error(path);
5973
5974 Py_RETURN_NONE;
5975 }
5976
5977
5978 #ifdef HAVE_SYSTEM
5979 #ifdef MS_WINDOWS
5980 /*[clinic input]
5981 os.system -> long
5982
5983 command: Py_UNICODE
5984
5985 Execute the command in a subshell.
5986 [clinic start generated code]*/
5987
5988 static long
os_system_impl(PyObject * module,const wchar_t * command)5989 os_system_impl(PyObject *module, const wchar_t *command)
5990 /*[clinic end generated code: output=dd528cbd5943a679 input=303f5ce97df606b0]*/
5991 {
5992 long result;
5993
5994 if (PySys_Audit("os.system", "(u)", command) < 0) {
5995 return -1;
5996 }
5997
5998 Py_BEGIN_ALLOW_THREADS
5999 _Py_BEGIN_SUPPRESS_IPH
6000 result = _wsystem(command);
6001 _Py_END_SUPPRESS_IPH
6002 Py_END_ALLOW_THREADS
6003 return result;
6004 }
6005 #else /* MS_WINDOWS */
6006 /*[clinic input]
6007 os.system -> long
6008
6009 command: FSConverter
6010
6011 Execute the command in a subshell.
6012 [clinic start generated code]*/
6013
6014 static long
os_system_impl(PyObject * module,PyObject * command)6015 os_system_impl(PyObject *module, PyObject *command)
6016 /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
6017 {
6018 long result;
6019 const char *bytes = PyBytes_AsString(command);
6020
6021 if (PySys_Audit("os.system", "(O)", command) < 0) {
6022 return -1;
6023 }
6024
6025 Py_BEGIN_ALLOW_THREADS
6026 result = system(bytes);
6027 Py_END_ALLOW_THREADS
6028 return result;
6029 }
6030 #endif
6031 #endif /* HAVE_SYSTEM */
6032
6033
6034 #ifdef HAVE_UMASK
6035 /*[clinic input]
6036 os.umask
6037
6038 mask: int
6039 /
6040
6041 Set the current numeric umask and return the previous umask.
6042 [clinic start generated code]*/
6043
6044 static PyObject *
os_umask_impl(PyObject * module,int mask)6045 os_umask_impl(PyObject *module, int mask)
6046 /*[clinic end generated code: output=a2e33ce3bc1a6e33 input=ab6bfd9b24d8a7e8]*/
6047 {
6048 int i = (int)umask(mask);
6049 if (i < 0)
6050 return posix_error();
6051 return PyLong_FromLong((long)i);
6052 }
6053 #endif
6054
6055 #ifdef MS_WINDOWS
6056
6057 /* override the default DeleteFileW behavior so that directory
6058 symlinks can be removed with this function, the same as with
6059 Unix symlinks */
Py_DeleteFileW(LPCWSTR lpFileName)6060 BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName)
6061 {
6062 WIN32_FILE_ATTRIBUTE_DATA info;
6063 WIN32_FIND_DATAW find_data;
6064 HANDLE find_data_handle;
6065 int is_directory = 0;
6066 int is_link = 0;
6067
6068 if (GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &info)) {
6069 is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
6070
6071 /* Get WIN32_FIND_DATA structure for the path to determine if
6072 it is a symlink */
6073 if(is_directory &&
6074 info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
6075 find_data_handle = FindFirstFileW(lpFileName, &find_data);
6076
6077 if(find_data_handle != INVALID_HANDLE_VALUE) {
6078 /* IO_REPARSE_TAG_SYMLINK if it is a symlink and
6079 IO_REPARSE_TAG_MOUNT_POINT if it is a junction point. */
6080 is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK ||
6081 find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT;
6082 FindClose(find_data_handle);
6083 }
6084 }
6085 }
6086
6087 if (is_directory && is_link)
6088 return RemoveDirectoryW(lpFileName);
6089
6090 return DeleteFileW(lpFileName);
6091 }
6092 #endif /* MS_WINDOWS */
6093
6094
6095 /*[clinic input]
6096 os.unlink
6097
6098 path: path_t
6099 *
6100 dir_fd: dir_fd(requires='unlinkat')=None
6101
6102 Remove a file (same as remove()).
6103
6104 If dir_fd is not None, it should be a file descriptor open to a directory,
6105 and path should be relative; path will then be relative to that directory.
6106 dir_fd may not be implemented on your platform.
6107 If it is unavailable, using it will raise a NotImplementedError.
6108
6109 [clinic start generated code]*/
6110
6111 static PyObject *
os_unlink_impl(PyObject * module,path_t * path,int dir_fd)6112 os_unlink_impl(PyObject *module, path_t *path, int dir_fd)
6113 /*[clinic end generated code: output=621797807b9963b1 input=d7bcde2b1b2a2552]*/
6114 {
6115 int result;
6116 #ifdef HAVE_UNLINKAT
6117 int unlinkat_unavailable = 0;
6118 #endif
6119
6120 if (PySys_Audit("os.remove", "Oi", path->object,
6121 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
6122 return NULL;
6123 }
6124
6125 Py_BEGIN_ALLOW_THREADS
6126 _Py_BEGIN_SUPPRESS_IPH
6127 #ifdef MS_WINDOWS
6128 /* Windows, success=1, UNIX, success=0 */
6129 result = !Py_DeleteFileW(path->wide);
6130 #else
6131 #ifdef HAVE_UNLINKAT
6132 if (dir_fd != DEFAULT_DIR_FD) {
6133 if (HAVE_UNLINKAT_RUNTIME) {
6134
6135 result = unlinkat(dir_fd, path->narrow, 0);
6136 } else {
6137 unlinkat_unavailable = 1;
6138 }
6139 } else
6140 #endif /* HAVE_UNLINKAT */
6141 result = unlink(path->narrow);
6142 #endif
6143 _Py_END_SUPPRESS_IPH
6144 Py_END_ALLOW_THREADS
6145
6146 #ifdef HAVE_UNLINKAT
6147 if (unlinkat_unavailable) {
6148 argument_unavailable_error(NULL, "dir_fd");
6149 return NULL;
6150 }
6151 #endif
6152
6153 if (result)
6154 return path_error(path);
6155
6156 Py_RETURN_NONE;
6157 }
6158
6159
6160 /*[clinic input]
6161 os.remove = os.unlink
6162
6163 Remove a file (same as unlink()).
6164
6165 If dir_fd is not None, it should be a file descriptor open to a directory,
6166 and path should be relative; path will then be relative to that directory.
6167 dir_fd may not be implemented on your platform.
6168 If it is unavailable, using it will raise a NotImplementedError.
6169 [clinic start generated code]*/
6170
6171 static PyObject *
os_remove_impl(PyObject * module,path_t * path,int dir_fd)6172 os_remove_impl(PyObject *module, path_t *path, int dir_fd)
6173 /*[clinic end generated code: output=a8535b28f0068883 input=e05c5ab55cd30983]*/
6174 {
6175 return os_unlink_impl(module, path, dir_fd);
6176 }
6177
6178
6179 static PyStructSequence_Field uname_result_fields[] = {
6180 {"sysname", "operating system name"},
6181 {"nodename", "name of machine on network (implementation-defined)"},
6182 {"release", "operating system release"},
6183 {"version", "operating system version"},
6184 {"machine", "hardware identifier"},
6185 {NULL}
6186 };
6187
6188 PyDoc_STRVAR(uname_result__doc__,
6189 "uname_result: Result from os.uname().\n\n\
6190 This object may be accessed either as a tuple of\n\
6191 (sysname, nodename, release, version, machine),\n\
6192 or via the attributes sysname, nodename, release, version, and machine.\n\
6193 \n\
6194 See os.uname for more information.");
6195
6196 static PyStructSequence_Desc uname_result_desc = {
6197 MODNAME ".uname_result", /* name */
6198 uname_result__doc__, /* doc */
6199 uname_result_fields,
6200 5
6201 };
6202
6203 #ifdef HAVE_UNAME
6204 /*[clinic input]
6205 os.uname
6206
6207 Return an object identifying the current operating system.
6208
6209 The object behaves like a named tuple with the following fields:
6210 (sysname, nodename, release, version, machine)
6211
6212 [clinic start generated code]*/
6213
6214 static PyObject *
os_uname_impl(PyObject * module)6215 os_uname_impl(PyObject *module)
6216 /*[clinic end generated code: output=e6a49cf1a1508a19 input=e68bd246db3043ed]*/
6217 {
6218 struct utsname u;
6219 int res;
6220 PyObject *value;
6221
6222 Py_BEGIN_ALLOW_THREADS
6223 res = uname(&u);
6224 Py_END_ALLOW_THREADS
6225 if (res < 0)
6226 return posix_error();
6227
6228 PyObject *UnameResultType = get_posix_state(module)->UnameResultType;
6229 value = PyStructSequence_New((PyTypeObject *)UnameResultType);
6230 if (value == NULL)
6231 return NULL;
6232
6233 #define SET(i, field) \
6234 { \
6235 PyObject *o = PyUnicode_DecodeFSDefault(field); \
6236 if (!o) { \
6237 Py_DECREF(value); \
6238 return NULL; \
6239 } \
6240 PyStructSequence_SET_ITEM(value, i, o); \
6241 } \
6242
6243 SET(0, u.sysname);
6244 SET(1, u.nodename);
6245 SET(2, u.release);
6246 SET(3, u.version);
6247 SET(4, u.machine);
6248
6249 #undef SET
6250
6251 return value;
6252 }
6253 #endif /* HAVE_UNAME */
6254
6255
6256
6257 typedef struct {
6258 int now;
6259 time_t atime_s;
6260 long atime_ns;
6261 time_t mtime_s;
6262 long mtime_ns;
6263 } utime_t;
6264
6265 /*
6266 * these macros assume that "ut" is a pointer to a utime_t
6267 * they also intentionally leak the declaration of a pointer named "time"
6268 */
6269 #define UTIME_TO_TIMESPEC \
6270 struct timespec ts[2]; \
6271 struct timespec *time; \
6272 if (ut->now) \
6273 time = NULL; \
6274 else { \
6275 ts[0].tv_sec = ut->atime_s; \
6276 ts[0].tv_nsec = ut->atime_ns; \
6277 ts[1].tv_sec = ut->mtime_s; \
6278 ts[1].tv_nsec = ut->mtime_ns; \
6279 time = ts; \
6280 } \
6281
6282 #define UTIME_TO_TIMEVAL \
6283 struct timeval tv[2]; \
6284 struct timeval *time; \
6285 if (ut->now) \
6286 time = NULL; \
6287 else { \
6288 tv[0].tv_sec = ut->atime_s; \
6289 tv[0].tv_usec = ut->atime_ns / 1000; \
6290 tv[1].tv_sec = ut->mtime_s; \
6291 tv[1].tv_usec = ut->mtime_ns / 1000; \
6292 time = tv; \
6293 } \
6294
6295 #define UTIME_TO_UTIMBUF \
6296 struct utimbuf u; \
6297 struct utimbuf *time; \
6298 if (ut->now) \
6299 time = NULL; \
6300 else { \
6301 u.actime = ut->atime_s; \
6302 u.modtime = ut->mtime_s; \
6303 time = &u; \
6304 }
6305
6306 #define UTIME_TO_TIME_T \
6307 time_t timet[2]; \
6308 time_t *time; \
6309 if (ut->now) \
6310 time = NULL; \
6311 else { \
6312 timet[0] = ut->atime_s; \
6313 timet[1] = ut->mtime_s; \
6314 time = timet; \
6315 } \
6316
6317
6318 #if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
6319
6320 static int
utime_dir_fd(utime_t * ut,int dir_fd,const char * path,int follow_symlinks)6321 utime_dir_fd(utime_t *ut, int dir_fd, const char *path, int follow_symlinks)
6322 {
6323 #if defined(__APPLE__) && defined(HAVE_UTIMENSAT)
6324 if (HAVE_UTIMENSAT_RUNTIME) {
6325 int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
6326 UTIME_TO_TIMESPEC;
6327 return utimensat(dir_fd, path, time, flags);
6328 } else {
6329 errno = ENOSYS;
6330 return -1;
6331 }
6332 #elif defined(HAVE_UTIMENSAT)
6333 int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
6334 UTIME_TO_TIMESPEC;
6335 return utimensat(dir_fd, path, time, flags);
6336 #elif defined(HAVE_FUTIMESAT)
6337 UTIME_TO_TIMEVAL;
6338 /*
6339 * follow_symlinks will never be false here;
6340 * we only allow !follow_symlinks and dir_fd together
6341 * if we have utimensat()
6342 */
6343 assert(follow_symlinks);
6344 return futimesat(dir_fd, path, time);
6345 #endif
6346 }
6347
6348 #define FUTIMENSAT_DIR_FD_CONVERTER dir_fd_converter
6349 #else
6350 #define FUTIMENSAT_DIR_FD_CONVERTER dir_fd_unavailable
6351 #endif
6352
6353 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
6354
6355 static int
utime_fd(utime_t * ut,int fd)6356 utime_fd(utime_t *ut, int fd)
6357 {
6358 #ifdef HAVE_FUTIMENS
6359
6360 if (HAVE_FUTIMENS_RUNTIME) {
6361
6362 UTIME_TO_TIMESPEC;
6363 return futimens(fd, time);
6364
6365 } else
6366 #ifndef HAVE_FUTIMES
6367 {
6368 /* Not sure if this can happen */
6369 PyErr_SetString(
6370 PyExc_RuntimeError,
6371 "neither futimens nor futimes are supported"
6372 " on this system");
6373 return -1;
6374 }
6375 #endif
6376
6377 #endif
6378 #ifdef HAVE_FUTIMES
6379 {
6380 UTIME_TO_TIMEVAL;
6381 return futimes(fd, time);
6382 }
6383 #endif
6384 }
6385
6386 #define PATH_UTIME_HAVE_FD 1
6387 #else
6388 #define PATH_UTIME_HAVE_FD 0
6389 #endif
6390
6391 #if defined(HAVE_UTIMENSAT) || defined(HAVE_LUTIMES)
6392 # define UTIME_HAVE_NOFOLLOW_SYMLINKS
6393 #endif
6394
6395 #ifdef UTIME_HAVE_NOFOLLOW_SYMLINKS
6396
6397 static int
utime_nofollow_symlinks(utime_t * ut,const char * path)6398 utime_nofollow_symlinks(utime_t *ut, const char *path)
6399 {
6400 #ifdef HAVE_UTIMENSAT
6401 if (HAVE_UTIMENSAT_RUNTIME) {
6402 UTIME_TO_TIMESPEC;
6403 return utimensat(DEFAULT_DIR_FD, path, time, AT_SYMLINK_NOFOLLOW);
6404 } else
6405 #ifndef HAVE_LUTIMES
6406 {
6407 /* Not sure if this can happen */
6408 PyErr_SetString(
6409 PyExc_RuntimeError,
6410 "neither utimensat nor lutimes are supported"
6411 " on this system");
6412 return -1;
6413 }
6414 #endif
6415 #endif
6416
6417 #ifdef HAVE_LUTIMES
6418 {
6419 UTIME_TO_TIMEVAL;
6420 return lutimes(path, time);
6421 }
6422 #endif
6423 }
6424
6425 #endif
6426
6427 #ifndef MS_WINDOWS
6428
6429 static int
utime_default(utime_t * ut,const char * path)6430 utime_default(utime_t *ut, const char *path)
6431 {
6432 #if defined(__APPLE__) && defined(HAVE_UTIMENSAT)
6433 if (HAVE_UTIMENSAT_RUNTIME) {
6434 UTIME_TO_TIMESPEC;
6435 return utimensat(DEFAULT_DIR_FD, path, time, 0);
6436 } else {
6437 UTIME_TO_TIMEVAL;
6438 return utimes(path, time);
6439 }
6440 #elif defined(HAVE_UTIMENSAT)
6441 UTIME_TO_TIMESPEC;
6442 return utimensat(DEFAULT_DIR_FD, path, time, 0);
6443 #elif defined(HAVE_UTIMES)
6444 UTIME_TO_TIMEVAL;
6445 return utimes(path, time);
6446 #elif defined(HAVE_UTIME_H)
6447 UTIME_TO_UTIMBUF;
6448 return utime(path, time);
6449 #else
6450 UTIME_TO_TIME_T;
6451 return utime(path, time);
6452 #endif
6453 }
6454
6455 #endif
6456
6457 static int
split_py_long_to_s_and_ns(PyObject * module,PyObject * py_long,time_t * s,long * ns)6458 split_py_long_to_s_and_ns(PyObject *module, PyObject *py_long, time_t *s, long *ns)
6459 {
6460 int result = 0;
6461 PyObject *divmod;
6462 divmod = PyNumber_Divmod(py_long, get_posix_state(module)->billion);
6463 if (!divmod)
6464 goto exit;
6465 if (!PyTuple_Check(divmod) || PyTuple_GET_SIZE(divmod) != 2) {
6466 PyErr_Format(PyExc_TypeError,
6467 "%.200s.__divmod__() must return a 2-tuple, not %.200s",
6468 _PyType_Name(Py_TYPE(py_long)), _PyType_Name(Py_TYPE(divmod)));
6469 goto exit;
6470 }
6471 *s = _PyLong_AsTime_t(PyTuple_GET_ITEM(divmod, 0));
6472 if ((*s == -1) && PyErr_Occurred())
6473 goto exit;
6474 *ns = PyLong_AsLong(PyTuple_GET_ITEM(divmod, 1));
6475 if ((*ns == -1) && PyErr_Occurred())
6476 goto exit;
6477
6478 result = 1;
6479 exit:
6480 Py_XDECREF(divmod);
6481 return result;
6482 }
6483
6484
6485 /*[clinic input]
6486 os.utime
6487
6488 path: path_t(allow_fd='PATH_UTIME_HAVE_FD')
6489 times: object = None
6490 *
6491 ns: object = NULL
6492 dir_fd: dir_fd(requires='futimensat') = None
6493 follow_symlinks: bool=True
6494
6495 # "utime(path, times=None, *[, ns], dir_fd=None, follow_symlinks=True)\n\
6496
6497 Set the access and modified time of path.
6498
6499 path may always be specified as a string.
6500 On some platforms, path may also be specified as an open file descriptor.
6501 If this functionality is unavailable, using it raises an exception.
6502
6503 If times is not None, it must be a tuple (atime, mtime);
6504 atime and mtime should be expressed as float seconds since the epoch.
6505 If ns is specified, it must be a tuple (atime_ns, mtime_ns);
6506 atime_ns and mtime_ns should be expressed as integer nanoseconds
6507 since the epoch.
6508 If times is None and ns is unspecified, utime uses the current time.
6509 Specifying tuples for both times and ns is an error.
6510
6511 If dir_fd is not None, it should be a file descriptor open to a directory,
6512 and path should be relative; path will then be relative to that directory.
6513 If follow_symlinks is False, and the last element of the path is a symbolic
6514 link, utime will modify the symbolic link itself instead of the file the
6515 link points to.
6516 It is an error to use dir_fd or follow_symlinks when specifying path
6517 as an open file descriptor.
6518 dir_fd and follow_symlinks may not be available on your platform.
6519 If they are unavailable, using them will raise a NotImplementedError.
6520
6521 [clinic start generated code]*/
6522
6523 static PyObject *
os_utime_impl(PyObject * module,path_t * path,PyObject * times,PyObject * ns,int dir_fd,int follow_symlinks)6524 os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
6525 int dir_fd, int follow_symlinks)
6526 /*[clinic end generated code: output=cfcac69d027b82cf input=2fbd62a2f228f8f4]*/
6527 {
6528 #ifdef MS_WINDOWS
6529 HANDLE hFile;
6530 FILETIME atime, mtime;
6531 #else
6532 int result;
6533 #endif
6534
6535 utime_t utime;
6536
6537 memset(&utime, 0, sizeof(utime_t));
6538
6539 if (times != Py_None && ns) {
6540 PyErr_SetString(PyExc_ValueError,
6541 "utime: you may specify either 'times'"
6542 " or 'ns' but not both");
6543 return NULL;
6544 }
6545
6546 if (times != Py_None) {
6547 time_t a_sec, m_sec;
6548 long a_nsec, m_nsec;
6549 if (!PyTuple_CheckExact(times) || (PyTuple_Size(times) != 2)) {
6550 PyErr_SetString(PyExc_TypeError,
6551 "utime: 'times' must be either"
6552 " a tuple of two ints or None");
6553 return NULL;
6554 }
6555 utime.now = 0;
6556 if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0),
6557 &a_sec, &a_nsec, _PyTime_ROUND_FLOOR) == -1 ||
6558 _PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1),
6559 &m_sec, &m_nsec, _PyTime_ROUND_FLOOR) == -1) {
6560 return NULL;
6561 }
6562 utime.atime_s = a_sec;
6563 utime.atime_ns = a_nsec;
6564 utime.mtime_s = m_sec;
6565 utime.mtime_ns = m_nsec;
6566 }
6567 else if (ns) {
6568 if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) {
6569 PyErr_SetString(PyExc_TypeError,
6570 "utime: 'ns' must be a tuple of two ints");
6571 return NULL;
6572 }
6573 utime.now = 0;
6574 if (!split_py_long_to_s_and_ns(module, PyTuple_GET_ITEM(ns, 0),
6575 &utime.atime_s, &utime.atime_ns) ||
6576 !split_py_long_to_s_and_ns(module, PyTuple_GET_ITEM(ns, 1),
6577 &utime.mtime_s, &utime.mtime_ns)) {
6578 return NULL;
6579 }
6580 }
6581 else {
6582 /* times and ns are both None/unspecified. use "now". */
6583 utime.now = 1;
6584 }
6585
6586 #if !defined(UTIME_HAVE_NOFOLLOW_SYMLINKS)
6587 if (follow_symlinks_specified("utime", follow_symlinks))
6588 return NULL;
6589 #endif
6590
6591 if (path_and_dir_fd_invalid("utime", path, dir_fd) ||
6592 dir_fd_and_fd_invalid("utime", dir_fd, path->fd) ||
6593 fd_and_follow_symlinks_invalid("utime", path->fd, follow_symlinks))
6594 return NULL;
6595
6596 #if !defined(HAVE_UTIMENSAT)
6597 if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
6598 PyErr_SetString(PyExc_ValueError,
6599 "utime: cannot use dir_fd and follow_symlinks "
6600 "together on this platform");
6601 return NULL;
6602 }
6603 #endif
6604
6605 if (PySys_Audit("os.utime", "OOOi", path->object, times, ns ? ns : Py_None,
6606 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
6607 return NULL;
6608 }
6609
6610 #ifdef MS_WINDOWS
6611 Py_BEGIN_ALLOW_THREADS
6612 hFile = CreateFileW(path->wide, FILE_WRITE_ATTRIBUTES, 0,
6613 NULL, OPEN_EXISTING,
6614 FILE_FLAG_BACKUP_SEMANTICS, NULL);
6615 Py_END_ALLOW_THREADS
6616 if (hFile == INVALID_HANDLE_VALUE) {
6617 path_error(path);
6618 return NULL;
6619 }
6620
6621 if (utime.now) {
6622 GetSystemTimeAsFileTime(&mtime);
6623 atime = mtime;
6624 }
6625 else {
6626 _Py_time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime);
6627 _Py_time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime);
6628 }
6629 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
6630 path_error(path);
6631 CloseHandle(hFile);
6632 return NULL;
6633 }
6634 CloseHandle(hFile);
6635 #else /* MS_WINDOWS */
6636 Py_BEGIN_ALLOW_THREADS
6637
6638 #ifdef UTIME_HAVE_NOFOLLOW_SYMLINKS
6639 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
6640 result = utime_nofollow_symlinks(&utime, path->narrow);
6641 else
6642 #endif
6643
6644 #if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
6645 if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) {
6646 result = utime_dir_fd(&utime, dir_fd, path->narrow, follow_symlinks);
6647
6648 } else
6649 #endif
6650
6651 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
6652 if (path->fd != -1)
6653 result = utime_fd(&utime, path->fd);
6654 else
6655 #endif
6656
6657 result = utime_default(&utime, path->narrow);
6658
6659 Py_END_ALLOW_THREADS
6660
6661 #if defined(__APPLE__) && defined(HAVE_UTIMENSAT)
6662 /* See utime_dir_fd implementation */
6663 if (result == -1 && errno == ENOSYS) {
6664 argument_unavailable_error(NULL, "dir_fd");
6665 return NULL;
6666 }
6667 #endif
6668
6669 if (result < 0) {
6670 path_error(path);
6671 return NULL;
6672 }
6673
6674 #endif /* MS_WINDOWS */
6675
6676 Py_RETURN_NONE;
6677 }
6678
6679 /* Process operations */
6680
6681
6682 /*[clinic input]
6683 os._exit
6684
6685 status: int
6686
6687 Exit to the system with specified status, without normal exit processing.
6688 [clinic start generated code]*/
6689
6690 static PyObject *
os__exit_impl(PyObject * module,int status)6691 os__exit_impl(PyObject *module, int status)
6692 /*[clinic end generated code: output=116e52d9c2260d54 input=5e6d57556b0c4a62]*/
6693 {
6694 _exit(status);
6695 return NULL; /* Make gcc -Wall happy */
6696 }
6697
6698 #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
6699 #define EXECV_CHAR wchar_t
6700 #else
6701 #define EXECV_CHAR char
6702 #endif
6703
6704 #if defined(HAVE_EXECV) || defined(HAVE_SPAWNV) || defined(HAVE_RTPSPAWN)
6705 static void
free_string_array(EXECV_CHAR ** array,Py_ssize_t count)6706 free_string_array(EXECV_CHAR **array, Py_ssize_t count)
6707 {
6708 Py_ssize_t i;
6709 for (i = 0; i < count; i++)
6710 PyMem_Free(array[i]);
6711 PyMem_Free(array);
6712 }
6713
6714 static int
fsconvert_strdup(PyObject * o,EXECV_CHAR ** out)6715 fsconvert_strdup(PyObject *o, EXECV_CHAR **out)
6716 {
6717 Py_ssize_t size;
6718 PyObject *ub;
6719 int result = 0;
6720 #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
6721 if (!PyUnicode_FSDecoder(o, &ub))
6722 return 0;
6723 *out = PyUnicode_AsWideCharString(ub, &size);
6724 if (*out)
6725 result = 1;
6726 #else
6727 if (!PyUnicode_FSConverter(o, &ub))
6728 return 0;
6729 size = PyBytes_GET_SIZE(ub);
6730 *out = PyMem_Malloc(size + 1);
6731 if (*out) {
6732 memcpy(*out, PyBytes_AS_STRING(ub), size + 1);
6733 result = 1;
6734 } else
6735 PyErr_NoMemory();
6736 #endif
6737 Py_DECREF(ub);
6738 return result;
6739 }
6740 #endif
6741
6742 #if defined(HAVE_EXECV) || defined (HAVE_FEXECVE) || defined(HAVE_RTPSPAWN)
6743 static EXECV_CHAR**
parse_envlist(PyObject * env,Py_ssize_t * envc_ptr)6744 parse_envlist(PyObject* env, Py_ssize_t *envc_ptr)
6745 {
6746 Py_ssize_t i, pos, envc;
6747 PyObject *keys=NULL, *vals=NULL;
6748 PyObject *key2, *val2, *keyval;
6749 EXECV_CHAR **envlist;
6750
6751 i = PyMapping_Size(env);
6752 if (i < 0)
6753 return NULL;
6754 envlist = PyMem_NEW(EXECV_CHAR *, i + 1);
6755 if (envlist == NULL) {
6756 PyErr_NoMemory();
6757 return NULL;
6758 }
6759 envc = 0;
6760 keys = PyMapping_Keys(env);
6761 if (!keys)
6762 goto error;
6763 vals = PyMapping_Values(env);
6764 if (!vals)
6765 goto error;
6766 if (!PyList_Check(keys) || !PyList_Check(vals)) {
6767 PyErr_Format(PyExc_TypeError,
6768 "env.keys() or env.values() is not a list");
6769 goto error;
6770 }
6771
6772 for (pos = 0; pos < i; pos++) {
6773 PyObject *key = PyList_GetItem(keys, pos); // Borrowed ref.
6774 if (key == NULL) {
6775 goto error;
6776 }
6777 PyObject *val = PyList_GetItem(vals, pos); // Borrowed ref.
6778 if (val == NULL) {
6779 goto error;
6780 }
6781
6782 #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
6783 if (!PyUnicode_FSDecoder(key, &key2))
6784 goto error;
6785 if (!PyUnicode_FSDecoder(val, &val2)) {
6786 Py_DECREF(key2);
6787 goto error;
6788 }
6789 /* Search from index 1 because on Windows starting '=' is allowed for
6790 defining hidden environment variables. */
6791 if (PyUnicode_GET_LENGTH(key2) == 0 ||
6792 PyUnicode_FindChar(key2, '=', 1, PyUnicode_GET_LENGTH(key2), 1) != -1)
6793 {
6794 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
6795 Py_DECREF(key2);
6796 Py_DECREF(val2);
6797 goto error;
6798 }
6799 keyval = PyUnicode_FromFormat("%U=%U", key2, val2);
6800 #else
6801 if (!PyUnicode_FSConverter(key, &key2))
6802 goto error;
6803 if (!PyUnicode_FSConverter(val, &val2)) {
6804 Py_DECREF(key2);
6805 goto error;
6806 }
6807 if (PyBytes_GET_SIZE(key2) == 0 ||
6808 strchr(PyBytes_AS_STRING(key2) + 1, '=') != NULL)
6809 {
6810 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
6811 Py_DECREF(key2);
6812 Py_DECREF(val2);
6813 goto error;
6814 }
6815 keyval = PyBytes_FromFormat("%s=%s", PyBytes_AS_STRING(key2),
6816 PyBytes_AS_STRING(val2));
6817 #endif
6818 Py_DECREF(key2);
6819 Py_DECREF(val2);
6820 if (!keyval)
6821 goto error;
6822
6823 if (!fsconvert_strdup(keyval, &envlist[envc++])) {
6824 Py_DECREF(keyval);
6825 goto error;
6826 }
6827
6828 Py_DECREF(keyval);
6829 }
6830 Py_DECREF(vals);
6831 Py_DECREF(keys);
6832
6833 envlist[envc] = 0;
6834 *envc_ptr = envc;
6835 return envlist;
6836
6837 error:
6838 Py_XDECREF(keys);
6839 Py_XDECREF(vals);
6840 free_string_array(envlist, envc);
6841 return NULL;
6842 }
6843
6844 static EXECV_CHAR**
parse_arglist(PyObject * argv,Py_ssize_t * argc)6845 parse_arglist(PyObject* argv, Py_ssize_t *argc)
6846 {
6847 int i;
6848 EXECV_CHAR **argvlist = PyMem_NEW(EXECV_CHAR *, *argc+1);
6849 if (argvlist == NULL) {
6850 PyErr_NoMemory();
6851 return NULL;
6852 }
6853 for (i = 0; i < *argc; i++) {
6854 PyObject* item = PySequence_ITEM(argv, i);
6855 if (item == NULL)
6856 goto fail;
6857 if (!fsconvert_strdup(item, &argvlist[i])) {
6858 Py_DECREF(item);
6859 goto fail;
6860 }
6861 Py_DECREF(item);
6862 }
6863 argvlist[*argc] = NULL;
6864 return argvlist;
6865 fail:
6866 *argc = i;
6867 free_string_array(argvlist, *argc);
6868 return NULL;
6869 }
6870
6871 #endif
6872
6873
6874 #ifdef HAVE_EXECV
6875 /*[clinic input]
6876 os.execv
6877
6878 path: path_t
6879 Path of executable file.
6880 argv: object
6881 Tuple or list of strings.
6882 /
6883
6884 Execute an executable path with arguments, replacing current process.
6885 [clinic start generated code]*/
6886
6887 static PyObject *
os_execv_impl(PyObject * module,path_t * path,PyObject * argv)6888 os_execv_impl(PyObject *module, path_t *path, PyObject *argv)
6889 /*[clinic end generated code: output=3b52fec34cd0dafd input=9bac31efae07dac7]*/
6890 {
6891 EXECV_CHAR **argvlist;
6892 Py_ssize_t argc;
6893
6894 PyInterpreterState *interp = _PyInterpreterState_GET();
6895 if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_EXEC)) {
6896 PyErr_SetString(PyExc_RuntimeError,
6897 "exec not supported for isolated subinterpreters");
6898 return NULL;
6899 }
6900
6901 /* execv has two arguments: (path, argv), where
6902 argv is a list or tuple of strings. */
6903
6904 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
6905 PyErr_SetString(PyExc_TypeError,
6906 "execv() arg 2 must be a tuple or list");
6907 return NULL;
6908 }
6909 argc = PySequence_Size(argv);
6910 if (argc < 1) {
6911 PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
6912 return NULL;
6913 }
6914
6915 argvlist = parse_arglist(argv, &argc);
6916 if (argvlist == NULL) {
6917 return NULL;
6918 }
6919 if (!argvlist[0][0]) {
6920 PyErr_SetString(PyExc_ValueError,
6921 "execv() arg 2 first element cannot be empty");
6922 free_string_array(argvlist, argc);
6923 return NULL;
6924 }
6925
6926 if (PySys_Audit("os.exec", "OOO", path->object, argv, Py_None) < 0) {
6927 free_string_array(argvlist, argc);
6928 return NULL;
6929 }
6930
6931 _Py_BEGIN_SUPPRESS_IPH
6932 #ifdef HAVE_WEXECV
6933 _wexecv(path->wide, argvlist);
6934 #else
6935 execv(path->narrow, argvlist);
6936 #endif
6937 _Py_END_SUPPRESS_IPH
6938
6939 /* If we get here it's definitely an error */
6940
6941 posix_error();
6942 free_string_array(argvlist, argc);
6943 return NULL;
6944 }
6945
6946
6947 /*[clinic input]
6948 os.execve
6949
6950 path: path_t(allow_fd='PATH_HAVE_FEXECVE')
6951 Path of executable file.
6952 argv: object
6953 Tuple or list of strings.
6954 env: object
6955 Dictionary of strings mapping to strings.
6956
6957 Execute an executable path with arguments, replacing current process.
6958 [clinic start generated code]*/
6959
6960 static PyObject *
os_execve_impl(PyObject * module,path_t * path,PyObject * argv,PyObject * env)6961 os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
6962 /*[clinic end generated code: output=ff9fa8e4da8bde58 input=626804fa092606d9]*/
6963 {
6964 EXECV_CHAR **argvlist = NULL;
6965 EXECV_CHAR **envlist;
6966 Py_ssize_t argc, envc;
6967
6968 PyInterpreterState *interp = _PyInterpreterState_GET();
6969 if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_EXEC)) {
6970 PyErr_SetString(PyExc_RuntimeError,
6971 "exec not supported for isolated subinterpreters");
6972 return NULL;
6973 }
6974
6975 /* execve has three arguments: (path, argv, env), where
6976 argv is a list or tuple of strings and env is a dictionary
6977 like posix.environ. */
6978
6979 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
6980 PyErr_SetString(PyExc_TypeError,
6981 "execve: argv must be a tuple or list");
6982 goto fail_0;
6983 }
6984 argc = PySequence_Size(argv);
6985 if (argc < 1) {
6986 PyErr_SetString(PyExc_ValueError, "execve: argv must not be empty");
6987 return NULL;
6988 }
6989
6990 if (!PyMapping_Check(env)) {
6991 PyErr_SetString(PyExc_TypeError,
6992 "execve: environment must be a mapping object");
6993 goto fail_0;
6994 }
6995
6996 argvlist = parse_arglist(argv, &argc);
6997 if (argvlist == NULL) {
6998 goto fail_0;
6999 }
7000 if (!argvlist[0][0]) {
7001 PyErr_SetString(PyExc_ValueError,
7002 "execve: argv first element cannot be empty");
7003 goto fail_0;
7004 }
7005
7006 envlist = parse_envlist(env, &envc);
7007 if (envlist == NULL)
7008 goto fail_0;
7009
7010 if (PySys_Audit("os.exec", "OOO", path->object, argv, env) < 0) {
7011 goto fail_1;
7012 }
7013
7014 _Py_BEGIN_SUPPRESS_IPH
7015 #ifdef HAVE_FEXECVE
7016 if (path->fd > -1)
7017 fexecve(path->fd, argvlist, envlist);
7018 else
7019 #endif
7020 #ifdef HAVE_WEXECV
7021 _wexecve(path->wide, argvlist, envlist);
7022 #else
7023 execve(path->narrow, argvlist, envlist);
7024 #endif
7025 _Py_END_SUPPRESS_IPH
7026
7027 /* If we get here it's definitely an error */
7028
7029 posix_path_error(path);
7030 fail_1:
7031 free_string_array(envlist, envc);
7032 fail_0:
7033 if (argvlist)
7034 free_string_array(argvlist, argc);
7035 return NULL;
7036 }
7037
7038 #endif /* HAVE_EXECV */
7039
7040 #ifdef HAVE_POSIX_SPAWN
7041
7042 enum posix_spawn_file_actions_identifier {
7043 POSIX_SPAWN_OPEN,
7044 POSIX_SPAWN_CLOSE,
7045 POSIX_SPAWN_DUP2
7046 #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP
7047 ,POSIX_SPAWN_CLOSEFROM
7048 #endif
7049 };
7050
7051 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
7052 static int
7053 convert_sched_param(PyObject *module, PyObject *param, struct sched_param *res);
7054 #endif
7055
7056 static int
parse_posix_spawn_flags(PyObject * module,const char * func_name,PyObject * setpgroup,int resetids,int setsid,PyObject * setsigmask,PyObject * setsigdef,PyObject * scheduler,posix_spawnattr_t * attrp)7057 parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpgroup,
7058 int resetids, int setsid, PyObject *setsigmask,
7059 PyObject *setsigdef, PyObject *scheduler,
7060 posix_spawnattr_t *attrp)
7061 {
7062 long all_flags = 0;
7063
7064 errno = posix_spawnattr_init(attrp);
7065 if (errno) {
7066 posix_error();
7067 return -1;
7068 }
7069
7070 if (setpgroup) {
7071 pid_t pgid = PyLong_AsPid(setpgroup);
7072 if (pgid == (pid_t)-1 && PyErr_Occurred()) {
7073 goto fail;
7074 }
7075 errno = posix_spawnattr_setpgroup(attrp, pgid);
7076 if (errno) {
7077 posix_error();
7078 goto fail;
7079 }
7080 all_flags |= POSIX_SPAWN_SETPGROUP;
7081 }
7082
7083 if (resetids) {
7084 all_flags |= POSIX_SPAWN_RESETIDS;
7085 }
7086
7087 if (setsid) {
7088 #ifdef HAVE_POSIX_SPAWN_SETSID_RUNTIME
7089 if (HAVE_POSIX_SPAWN_SETSID_RUNTIME) {
7090 #endif
7091 #ifdef POSIX_SPAWN_SETSID
7092 all_flags |= POSIX_SPAWN_SETSID;
7093 #elif defined(POSIX_SPAWN_SETSID_NP)
7094 all_flags |= POSIX_SPAWN_SETSID_NP;
7095 #else
7096 argument_unavailable_error(func_name, "setsid");
7097 return -1;
7098 #endif
7099
7100 #ifdef HAVE_POSIX_SPAWN_SETSID_RUNTIME
7101 } else {
7102 argument_unavailable_error(func_name, "setsid");
7103 return -1;
7104 }
7105 #endif /* HAVE_POSIX_SPAWN_SETSID_RUNTIME */
7106
7107 }
7108
7109 #ifdef HAVE_SIGSET_T
7110 if (setsigmask) {
7111 sigset_t set;
7112 if (!_Py_Sigset_Converter(setsigmask, &set)) {
7113 goto fail;
7114 }
7115 errno = posix_spawnattr_setsigmask(attrp, &set);
7116 if (errno) {
7117 posix_error();
7118 goto fail;
7119 }
7120 all_flags |= POSIX_SPAWN_SETSIGMASK;
7121 }
7122
7123 if (setsigdef) {
7124 sigset_t set;
7125 if (!_Py_Sigset_Converter(setsigdef, &set)) {
7126 goto fail;
7127 }
7128 errno = posix_spawnattr_setsigdefault(attrp, &set);
7129 if (errno) {
7130 posix_error();
7131 goto fail;
7132 }
7133 all_flags |= POSIX_SPAWN_SETSIGDEF;
7134 }
7135 #else
7136 if (setsigmask || setsigdef) {
7137 PyErr_SetString(PyExc_NotImplementedError,
7138 "sigset is not supported on this platform");
7139 goto fail;
7140 }
7141 #endif
7142
7143 if (scheduler) {
7144 #ifdef POSIX_SPAWN_SETSCHEDULER
7145 PyObject *py_schedpolicy;
7146 PyObject *schedparam_obj;
7147 struct sched_param schedparam;
7148
7149 if (!PyArg_ParseTuple(scheduler, "OO"
7150 ";A scheduler tuple must have two elements",
7151 &py_schedpolicy, &schedparam_obj)) {
7152 goto fail;
7153 }
7154 if (!convert_sched_param(module, schedparam_obj, &schedparam)) {
7155 goto fail;
7156 }
7157 if (py_schedpolicy != Py_None) {
7158 int schedpolicy = PyLong_AsInt(py_schedpolicy);
7159
7160 if (schedpolicy == -1 && PyErr_Occurred()) {
7161 goto fail;
7162 }
7163 errno = posix_spawnattr_setschedpolicy(attrp, schedpolicy);
7164 if (errno) {
7165 posix_error();
7166 goto fail;
7167 }
7168 all_flags |= POSIX_SPAWN_SETSCHEDULER;
7169 }
7170 errno = posix_spawnattr_setschedparam(attrp, &schedparam);
7171 if (errno) {
7172 posix_error();
7173 goto fail;
7174 }
7175 all_flags |= POSIX_SPAWN_SETSCHEDPARAM;
7176 #else
7177 PyErr_SetString(PyExc_NotImplementedError,
7178 "The scheduler option is not supported in this system.");
7179 goto fail;
7180 #endif
7181 }
7182
7183 errno = posix_spawnattr_setflags(attrp, all_flags);
7184 if (errno) {
7185 posix_error();
7186 goto fail;
7187 }
7188
7189 return 0;
7190
7191 fail:
7192 (void)posix_spawnattr_destroy(attrp);
7193 return -1;
7194 }
7195
7196 static int
parse_file_actions(PyObject * file_actions,posix_spawn_file_actions_t * file_actionsp,PyObject * temp_buffer)7197 parse_file_actions(PyObject *file_actions,
7198 posix_spawn_file_actions_t *file_actionsp,
7199 PyObject *temp_buffer)
7200 {
7201 PyObject *seq;
7202 PyObject *file_action = NULL;
7203 PyObject *tag_obj;
7204
7205 seq = PySequence_Fast(file_actions,
7206 "file_actions must be a sequence or None");
7207 if (seq == NULL) {
7208 return -1;
7209 }
7210
7211 errno = posix_spawn_file_actions_init(file_actionsp);
7212 if (errno) {
7213 posix_error();
7214 Py_DECREF(seq);
7215 return -1;
7216 }
7217
7218 for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(seq); ++i) {
7219 file_action = PySequence_Fast_GET_ITEM(seq, i);
7220 Py_INCREF(file_action);
7221 if (!PyTuple_Check(file_action) || !PyTuple_GET_SIZE(file_action)) {
7222 PyErr_SetString(PyExc_TypeError,
7223 "Each file_actions element must be a non-empty tuple");
7224 goto fail;
7225 }
7226 long tag = PyLong_AsLong(PyTuple_GET_ITEM(file_action, 0));
7227 if (tag == -1 && PyErr_Occurred()) {
7228 goto fail;
7229 }
7230
7231 /* Populate the file_actions object */
7232 switch (tag) {
7233 case POSIX_SPAWN_OPEN: {
7234 int fd, oflag;
7235 PyObject *path;
7236 unsigned long mode;
7237 if (!PyArg_ParseTuple(file_action, "OiO&ik"
7238 ";A open file_action tuple must have 5 elements",
7239 &tag_obj, &fd, PyUnicode_FSConverter, &path,
7240 &oflag, &mode))
7241 {
7242 goto fail;
7243 }
7244 if (PyList_Append(temp_buffer, path)) {
7245 Py_DECREF(path);
7246 goto fail;
7247 }
7248 errno = posix_spawn_file_actions_addopen(file_actionsp,
7249 fd, PyBytes_AS_STRING(path), oflag, (mode_t)mode);
7250 if (errno) {
7251 posix_error();
7252 Py_DECREF(path);
7253 goto fail;
7254 }
7255 Py_DECREF(path);
7256 break;
7257 }
7258 case POSIX_SPAWN_CLOSE: {
7259 int fd;
7260 if (!PyArg_ParseTuple(file_action, "Oi"
7261 ";A close file_action tuple must have 2 elements",
7262 &tag_obj, &fd))
7263 {
7264 goto fail;
7265 }
7266 errno = posix_spawn_file_actions_addclose(file_actionsp, fd);
7267 if (errno) {
7268 posix_error();
7269 goto fail;
7270 }
7271 break;
7272 }
7273 case POSIX_SPAWN_DUP2: {
7274 int fd1, fd2;
7275 if (!PyArg_ParseTuple(file_action, "Oii"
7276 ";A dup2 file_action tuple must have 3 elements",
7277 &tag_obj, &fd1, &fd2))
7278 {
7279 goto fail;
7280 }
7281 errno = posix_spawn_file_actions_adddup2(file_actionsp,
7282 fd1, fd2);
7283 if (errno) {
7284 posix_error();
7285 goto fail;
7286 }
7287 break;
7288 }
7289 #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP
7290 case POSIX_SPAWN_CLOSEFROM: {
7291 int fd;
7292 if (!PyArg_ParseTuple(file_action, "Oi"
7293 ";A closefrom file_action tuple must have 2 elements",
7294 &tag_obj, &fd))
7295 {
7296 goto fail;
7297 }
7298 errno = posix_spawn_file_actions_addclosefrom_np(file_actionsp,
7299 fd);
7300 if (errno) {
7301 posix_error();
7302 goto fail;
7303 }
7304 break;
7305 }
7306 #endif
7307 default: {
7308 PyErr_SetString(PyExc_TypeError,
7309 "Unknown file_actions identifier");
7310 goto fail;
7311 }
7312 }
7313 Py_DECREF(file_action);
7314 }
7315
7316 Py_DECREF(seq);
7317 return 0;
7318
7319 fail:
7320 Py_DECREF(seq);
7321 Py_DECREF(file_action);
7322 (void)posix_spawn_file_actions_destroy(file_actionsp);
7323 return -1;
7324 }
7325
7326
7327 static PyObject *
py_posix_spawn(int use_posix_spawnp,PyObject * module,path_t * path,PyObject * argv,PyObject * env,PyObject * file_actions,PyObject * setpgroup,int resetids,int setsid,PyObject * setsigmask,PyObject * setsigdef,PyObject * scheduler)7328 py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *argv,
7329 PyObject *env, PyObject *file_actions,
7330 PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask,
7331 PyObject *setsigdef, PyObject *scheduler)
7332 {
7333 const char *func_name = use_posix_spawnp ? "posix_spawnp" : "posix_spawn";
7334 EXECV_CHAR **argvlist = NULL;
7335 EXECV_CHAR **envlist = NULL;
7336 posix_spawn_file_actions_t file_actions_buf;
7337 posix_spawn_file_actions_t *file_actionsp = NULL;
7338 posix_spawnattr_t attr;
7339 posix_spawnattr_t *attrp = NULL;
7340 Py_ssize_t argc, envc;
7341 PyObject *result = NULL;
7342 PyObject *temp_buffer = NULL;
7343 pid_t pid;
7344 int err_code;
7345
7346 /* posix_spawn and posix_spawnp have three arguments: (path, argv, env), where
7347 argv is a list or tuple of strings and env is a dictionary
7348 like posix.environ. */
7349
7350 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
7351 PyErr_Format(PyExc_TypeError,
7352 "%s: argv must be a tuple or list", func_name);
7353 goto exit;
7354 }
7355 argc = PySequence_Size(argv);
7356 if (argc < 1) {
7357 PyErr_Format(PyExc_ValueError,
7358 "%s: argv must not be empty", func_name);
7359 return NULL;
7360 }
7361
7362 if (!PyMapping_Check(env) && env != Py_None) {
7363 PyErr_Format(PyExc_TypeError,
7364 "%s: environment must be a mapping object or None", func_name);
7365 goto exit;
7366 }
7367
7368 argvlist = parse_arglist(argv, &argc);
7369 if (argvlist == NULL) {
7370 goto exit;
7371 }
7372 if (!argvlist[0][0]) {
7373 PyErr_Format(PyExc_ValueError,
7374 "%s: argv first element cannot be empty", func_name);
7375 goto exit;
7376 }
7377
7378 #ifdef USE_DARWIN_NS_GET_ENVIRON
7379 // There is no environ global in this situation.
7380 char **environ = NULL;
7381 #endif
7382
7383 if (env == Py_None) {
7384 #ifdef USE_DARWIN_NS_GET_ENVIRON
7385 environ = *_NSGetEnviron();
7386 #endif
7387 envlist = environ;
7388 } else {
7389 envlist = parse_envlist(env, &envc);
7390 if (envlist == NULL) {
7391 goto exit;
7392 }
7393 }
7394
7395 if (file_actions != NULL && file_actions != Py_None) {
7396 /* There is a bug in old versions of glibc that makes some of the
7397 * helper functions for manipulating file actions not copy the provided
7398 * buffers. The problem is that posix_spawn_file_actions_addopen does not
7399 * copy the value of path for some old versions of glibc (<2.20).
7400 * The use of temp_buffer here is a workaround that keeps the
7401 * python objects that own the buffers alive until posix_spawn gets called.
7402 * Check https://bugs.python.org/issue33630 and
7403 * https://sourceware.org/bugzilla/show_bug.cgi?id=17048 for more info.*/
7404 temp_buffer = PyList_New(0);
7405 if (!temp_buffer) {
7406 goto exit;
7407 }
7408 if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer)) {
7409 goto exit;
7410 }
7411 file_actionsp = &file_actions_buf;
7412 }
7413
7414 if (parse_posix_spawn_flags(module, func_name, setpgroup, resetids, setsid,
7415 setsigmask, setsigdef, scheduler, &attr)) {
7416 goto exit;
7417 }
7418 attrp = &attr;
7419
7420 if (PySys_Audit("os.posix_spawn", "OOO", path->object, argv, env) < 0) {
7421 goto exit;
7422 }
7423
7424 _Py_BEGIN_SUPPRESS_IPH
7425 #ifdef HAVE_POSIX_SPAWNP
7426 if (use_posix_spawnp) {
7427 err_code = posix_spawnp(&pid, path->narrow,
7428 file_actionsp, attrp, argvlist, envlist);
7429 }
7430 else
7431 #endif /* HAVE_POSIX_SPAWNP */
7432 {
7433 err_code = posix_spawn(&pid, path->narrow,
7434 file_actionsp, attrp, argvlist, envlist);
7435 }
7436 _Py_END_SUPPRESS_IPH
7437
7438 if (err_code) {
7439 errno = err_code;
7440 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
7441 goto exit;
7442 }
7443 #ifdef _Py_MEMORY_SANITIZER
7444 __msan_unpoison(&pid, sizeof(pid));
7445 #endif
7446 result = PyLong_FromPid(pid);
7447
7448 exit:
7449 if (file_actionsp) {
7450 (void)posix_spawn_file_actions_destroy(file_actionsp);
7451 }
7452 if (attrp) {
7453 (void)posix_spawnattr_destroy(attrp);
7454 }
7455 if (envlist && envlist != environ) {
7456 free_string_array(envlist, envc);
7457 }
7458 if (argvlist) {
7459 free_string_array(argvlist, argc);
7460 }
7461 Py_XDECREF(temp_buffer);
7462 return result;
7463 }
7464
7465
7466 /*[clinic input]
7467
7468 os.posix_spawn
7469 path: path_t
7470 Path of executable file.
7471 argv: object
7472 Tuple or list of strings.
7473 env: object
7474 Dictionary of strings mapping to strings.
7475 /
7476 *
7477 file_actions: object(c_default='NULL') = ()
7478 A sequence of file action tuples.
7479 setpgroup: object = NULL
7480 The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
7481 resetids: bool = False
7482 If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.
7483 setsid: bool = False
7484 If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
7485 setsigmask: object(c_default='NULL') = ()
7486 The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
7487 setsigdef: object(c_default='NULL') = ()
7488 The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
7489 scheduler: object = NULL
7490 A tuple with the scheduler policy (optional) and parameters.
7491
7492 Execute the program specified by path in a new process.
7493 [clinic start generated code]*/
7494
7495 static PyObject *
os_posix_spawn_impl(PyObject * module,path_t * path,PyObject * argv,PyObject * env,PyObject * file_actions,PyObject * setpgroup,int resetids,int setsid,PyObject * setsigmask,PyObject * setsigdef,PyObject * scheduler)7496 os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
7497 PyObject *env, PyObject *file_actions,
7498 PyObject *setpgroup, int resetids, int setsid,
7499 PyObject *setsigmask, PyObject *setsigdef,
7500 PyObject *scheduler)
7501 /*[clinic end generated code: output=14a1098c566bc675 input=808aed1090d84e33]*/
7502 {
7503 return py_posix_spawn(0, module, path, argv, env, file_actions,
7504 setpgroup, resetids, setsid, setsigmask, setsigdef,
7505 scheduler);
7506 }
7507 #endif /* HAVE_POSIX_SPAWN */
7508
7509
7510
7511 #ifdef HAVE_POSIX_SPAWNP
7512 /*[clinic input]
7513
7514 os.posix_spawnp
7515 path: path_t
7516 Path of executable file.
7517 argv: object
7518 Tuple or list of strings.
7519 env: object
7520 Dictionary of strings mapping to strings.
7521 /
7522 *
7523 file_actions: object(c_default='NULL') = ()
7524 A sequence of file action tuples.
7525 setpgroup: object = NULL
7526 The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
7527 resetids: bool = False
7528 If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
7529 setsid: bool = False
7530 If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
7531 setsigmask: object(c_default='NULL') = ()
7532 The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
7533 setsigdef: object(c_default='NULL') = ()
7534 The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
7535 scheduler: object = NULL
7536 A tuple with the scheduler policy (optional) and parameters.
7537
7538 Execute the program specified by path in a new process.
7539 [clinic start generated code]*/
7540
7541 static PyObject *
os_posix_spawnp_impl(PyObject * module,path_t * path,PyObject * argv,PyObject * env,PyObject * file_actions,PyObject * setpgroup,int resetids,int setsid,PyObject * setsigmask,PyObject * setsigdef,PyObject * scheduler)7542 os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv,
7543 PyObject *env, PyObject *file_actions,
7544 PyObject *setpgroup, int resetids, int setsid,
7545 PyObject *setsigmask, PyObject *setsigdef,
7546 PyObject *scheduler)
7547 /*[clinic end generated code: output=7b9aaefe3031238d input=9e89e616116752a1]*/
7548 {
7549 return py_posix_spawn(1, module, path, argv, env, file_actions,
7550 setpgroup, resetids, setsid, setsigmask, setsigdef,
7551 scheduler);
7552 }
7553 #endif /* HAVE_POSIX_SPAWNP */
7554
7555 #ifdef HAVE_RTPSPAWN
7556 static intptr_t
_rtp_spawn(int mode,const char * rtpFileName,const char * argv[],const char * envp[])7557 _rtp_spawn(int mode, const char *rtpFileName, const char *argv[],
7558 const char *envp[])
7559 {
7560 RTP_ID rtpid;
7561 int status;
7562 pid_t res;
7563 int async_err = 0;
7564
7565 /* Set priority=100 and uStackSize=16 MiB (0x1000000) for new processes.
7566 uStackSize=0 cannot be used, the default stack size is too small for
7567 Python. */
7568 if (envp) {
7569 rtpid = rtpSpawn(rtpFileName, argv, envp,
7570 100, 0x1000000, 0, VX_FP_TASK);
7571 }
7572 else {
7573 rtpid = rtpSpawn(rtpFileName, argv, (const char **)environ,
7574 100, 0x1000000, 0, VX_FP_TASK);
7575 }
7576 if ((rtpid != RTP_ID_ERROR) && (mode == _P_WAIT)) {
7577 do {
7578 res = waitpid((pid_t)rtpid, &status, 0);
7579 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
7580
7581 if (res < 0)
7582 return RTP_ID_ERROR;
7583 return ((intptr_t)status);
7584 }
7585 return ((intptr_t)rtpid);
7586 }
7587 #endif
7588
7589 #if defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV) || defined(HAVE_RTPSPAWN)
7590 /*[clinic input]
7591 os.spawnv
7592
7593 mode: int
7594 Mode of process creation.
7595 path: path_t
7596 Path of executable file.
7597 argv: object
7598 Tuple or list of strings.
7599 /
7600
7601 Execute the program specified by path in a new process.
7602 [clinic start generated code]*/
7603
7604 static PyObject *
os_spawnv_impl(PyObject * module,int mode,path_t * path,PyObject * argv)7605 os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv)
7606 /*[clinic end generated code: output=71cd037a9d96b816 input=43224242303291be]*/
7607 {
7608 EXECV_CHAR **argvlist;
7609 int i;
7610 Py_ssize_t argc;
7611 intptr_t spawnval;
7612 PyObject *(*getitem)(PyObject *, Py_ssize_t);
7613
7614 /* spawnv has three arguments: (mode, path, argv), where
7615 argv is a list or tuple of strings. */
7616
7617 if (PyList_Check(argv)) {
7618 argc = PyList_Size(argv);
7619 getitem = PyList_GetItem;
7620 }
7621 else if (PyTuple_Check(argv)) {
7622 argc = PyTuple_Size(argv);
7623 getitem = PyTuple_GetItem;
7624 }
7625 else {
7626 PyErr_SetString(PyExc_TypeError,
7627 "spawnv() arg 2 must be a tuple or list");
7628 return NULL;
7629 }
7630 if (argc == 0) {
7631 PyErr_SetString(PyExc_ValueError,
7632 "spawnv() arg 2 cannot be empty");
7633 return NULL;
7634 }
7635
7636 argvlist = PyMem_NEW(EXECV_CHAR *, argc+1);
7637 if (argvlist == NULL) {
7638 return PyErr_NoMemory();
7639 }
7640 for (i = 0; i < argc; i++) {
7641 if (!fsconvert_strdup((*getitem)(argv, i),
7642 &argvlist[i])) {
7643 free_string_array(argvlist, i);
7644 PyErr_SetString(
7645 PyExc_TypeError,
7646 "spawnv() arg 2 must contain only strings");
7647 return NULL;
7648 }
7649 if (i == 0 && !argvlist[0][0]) {
7650 free_string_array(argvlist, i + 1);
7651 PyErr_SetString(
7652 PyExc_ValueError,
7653 "spawnv() arg 2 first element cannot be empty");
7654 return NULL;
7655 }
7656 }
7657 argvlist[argc] = NULL;
7658
7659 #if !defined(HAVE_RTPSPAWN)
7660 if (mode == _OLD_P_OVERLAY)
7661 mode = _P_OVERLAY;
7662 #endif
7663
7664 if (PySys_Audit("os.spawn", "iOOO", mode, path->object, argv,
7665 Py_None) < 0) {
7666 free_string_array(argvlist, argc);
7667 return NULL;
7668 }
7669
7670 Py_BEGIN_ALLOW_THREADS
7671 _Py_BEGIN_SUPPRESS_IPH
7672 #ifdef HAVE_WSPAWNV
7673 spawnval = _wspawnv(mode, path->wide, argvlist);
7674 #elif defined(HAVE_RTPSPAWN)
7675 spawnval = _rtp_spawn(mode, path->narrow, (const char **)argvlist, NULL);
7676 #else
7677 spawnval = _spawnv(mode, path->narrow, argvlist);
7678 #endif
7679 _Py_END_SUPPRESS_IPH
7680 Py_END_ALLOW_THREADS
7681
7682 int saved_errno = errno;
7683 free_string_array(argvlist, argc);
7684
7685 if (spawnval == -1) {
7686 errno = saved_errno;
7687 posix_error();
7688 return NULL;
7689 }
7690 return Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
7691 }
7692
7693 /*[clinic input]
7694 os.spawnve
7695
7696 mode: int
7697 Mode of process creation.
7698 path: path_t
7699 Path of executable file.
7700 argv: object
7701 Tuple or list of strings.
7702 env: object
7703 Dictionary of strings mapping to strings.
7704 /
7705
7706 Execute the program specified by path in a new process.
7707 [clinic start generated code]*/
7708
7709 static PyObject *
os_spawnve_impl(PyObject * module,int mode,path_t * path,PyObject * argv,PyObject * env)7710 os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
7711 PyObject *env)
7712 /*[clinic end generated code: output=30fe85be56fe37ad input=3e40803ee7c4c586]*/
7713 {
7714 EXECV_CHAR **argvlist;
7715 EXECV_CHAR **envlist;
7716 PyObject *res = NULL;
7717 Py_ssize_t argc, i, envc;
7718 intptr_t spawnval;
7719 PyObject *(*getitem)(PyObject *, Py_ssize_t);
7720 Py_ssize_t lastarg = 0;
7721
7722 /* spawnve has four arguments: (mode, path, argv, env), where
7723 argv is a list or tuple of strings and env is a dictionary
7724 like posix.environ. */
7725
7726 if (PyList_Check(argv)) {
7727 argc = PyList_Size(argv);
7728 getitem = PyList_GetItem;
7729 }
7730 else if (PyTuple_Check(argv)) {
7731 argc = PyTuple_Size(argv);
7732 getitem = PyTuple_GetItem;
7733 }
7734 else {
7735 PyErr_SetString(PyExc_TypeError,
7736 "spawnve() arg 2 must be a tuple or list");
7737 goto fail_0;
7738 }
7739 if (argc == 0) {
7740 PyErr_SetString(PyExc_ValueError,
7741 "spawnve() arg 2 cannot be empty");
7742 goto fail_0;
7743 }
7744 if (!PyMapping_Check(env)) {
7745 PyErr_SetString(PyExc_TypeError,
7746 "spawnve() arg 3 must be a mapping object");
7747 goto fail_0;
7748 }
7749
7750 argvlist = PyMem_NEW(EXECV_CHAR *, argc+1);
7751 if (argvlist == NULL) {
7752 PyErr_NoMemory();
7753 goto fail_0;
7754 }
7755 for (i = 0; i < argc; i++) {
7756 if (!fsconvert_strdup((*getitem)(argv, i),
7757 &argvlist[i]))
7758 {
7759 lastarg = i;
7760 goto fail_1;
7761 }
7762 if (i == 0 && !argvlist[0][0]) {
7763 lastarg = i + 1;
7764 PyErr_SetString(
7765 PyExc_ValueError,
7766 "spawnv() arg 2 first element cannot be empty");
7767 goto fail_1;
7768 }
7769 }
7770 lastarg = argc;
7771 argvlist[argc] = NULL;
7772
7773 envlist = parse_envlist(env, &envc);
7774 if (envlist == NULL)
7775 goto fail_1;
7776
7777 #if !defined(HAVE_RTPSPAWN)
7778 if (mode == _OLD_P_OVERLAY)
7779 mode = _P_OVERLAY;
7780 #endif
7781
7782 if (PySys_Audit("os.spawn", "iOOO", mode, path->object, argv, env) < 0) {
7783 goto fail_2;
7784 }
7785
7786 Py_BEGIN_ALLOW_THREADS
7787 _Py_BEGIN_SUPPRESS_IPH
7788 #ifdef HAVE_WSPAWNV
7789 spawnval = _wspawnve(mode, path->wide, argvlist, envlist);
7790 #elif defined(HAVE_RTPSPAWN)
7791 spawnval = _rtp_spawn(mode, path->narrow, (const char **)argvlist,
7792 (const char **)envlist);
7793 #else
7794 spawnval = _spawnve(mode, path->narrow, argvlist, envlist);
7795 #endif
7796 _Py_END_SUPPRESS_IPH
7797 Py_END_ALLOW_THREADS
7798
7799 if (spawnval == -1)
7800 (void) posix_error();
7801 else
7802 res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
7803
7804 fail_2:
7805 while (--envc >= 0) {
7806 PyMem_Free(envlist[envc]);
7807 }
7808 PyMem_Free(envlist);
7809 fail_1:
7810 free_string_array(argvlist, lastarg);
7811 fail_0:
7812 return res;
7813 }
7814
7815 #endif /* HAVE_SPAWNV */
7816
7817 #ifdef HAVE_FORK
7818
7819 /* Helper function to validate arguments.
7820 Returns 0 on success. non-zero on failure with a TypeError raised.
7821 If obj is non-NULL it must be callable. */
7822 static int
check_null_or_callable(PyObject * obj,const char * obj_name)7823 check_null_or_callable(PyObject *obj, const char* obj_name)
7824 {
7825 if (obj && !PyCallable_Check(obj)) {
7826 PyErr_Format(PyExc_TypeError, "'%s' must be callable, not %s",
7827 obj_name, _PyType_Name(Py_TYPE(obj)));
7828 return -1;
7829 }
7830 return 0;
7831 }
7832
7833 /*[clinic input]
7834 os.register_at_fork
7835
7836 *
7837 before: object=NULL
7838 A callable to be called in the parent before the fork() syscall.
7839 after_in_child: object=NULL
7840 A callable to be called in the child after fork().
7841 after_in_parent: object=NULL
7842 A callable to be called in the parent after fork().
7843
7844 Register callables to be called when forking a new process.
7845
7846 'before' callbacks are called in reverse order.
7847 'after_in_child' and 'after_in_parent' callbacks are called in order.
7848
7849 [clinic start generated code]*/
7850
7851 static PyObject *
os_register_at_fork_impl(PyObject * module,PyObject * before,PyObject * after_in_child,PyObject * after_in_parent)7852 os_register_at_fork_impl(PyObject *module, PyObject *before,
7853 PyObject *after_in_child, PyObject *after_in_parent)
7854 /*[clinic end generated code: output=5398ac75e8e97625 input=cd1187aa85d2312e]*/
7855 {
7856 PyInterpreterState *interp;
7857
7858 if (!before && !after_in_child && !after_in_parent) {
7859 PyErr_SetString(PyExc_TypeError, "At least one argument is required.");
7860 return NULL;
7861 }
7862 if (check_null_or_callable(before, "before") ||
7863 check_null_or_callable(after_in_child, "after_in_child") ||
7864 check_null_or_callable(after_in_parent, "after_in_parent")) {
7865 return NULL;
7866 }
7867 interp = _PyInterpreterState_GET();
7868
7869 if (register_at_forker(&interp->before_forkers, before)) {
7870 return NULL;
7871 }
7872 if (register_at_forker(&interp->after_forkers_child, after_in_child)) {
7873 return NULL;
7874 }
7875 if (register_at_forker(&interp->after_forkers_parent, after_in_parent)) {
7876 return NULL;
7877 }
7878 Py_RETURN_NONE;
7879 }
7880 #endif /* HAVE_FORK */
7881
7882 #if defined(HAVE_FORK1) || defined(HAVE_FORKPTY) || defined(HAVE_FORK)
7883 // Common code to raise a warning if we detect there is more than one thread
7884 // running in the process. Best effort, silent if unable to count threads.
7885 // Constraint: Quick. Never overcounts. Never leaves an error set.
7886 //
7887 // This should only be called from the parent process after
7888 // PyOS_AfterFork_Parent().
7889 static void
warn_about_fork_with_threads(const char * name)7890 warn_about_fork_with_threads(const char* name)
7891 {
7892 // It's not safe to issue the warning while the world is stopped, because
7893 // other threads might be holding locks that we need, which would deadlock.
7894 assert(!_PyRuntime.stoptheworld.world_stopped);
7895
7896 // TODO: Consider making an `os` module API to return the current number
7897 // of threads in the process. That'd presumably use this platform code but
7898 // raise an error rather than using the inaccurate fallback.
7899 Py_ssize_t num_python_threads = 0;
7900 #if defined(__APPLE__) && defined(HAVE_GETPID)
7901 mach_port_t macos_self = mach_task_self();
7902 mach_port_t macos_task;
7903 if (task_for_pid(macos_self, getpid(), &macos_task) == KERN_SUCCESS) {
7904 thread_array_t macos_threads;
7905 mach_msg_type_number_t macos_n_threads;
7906 if (task_threads(macos_task, &macos_threads,
7907 &macos_n_threads) == KERN_SUCCESS) {
7908 num_python_threads = macos_n_threads;
7909 }
7910 }
7911 #elif defined(__linux__)
7912 // Linux /proc/self/stat 20th field is the number of threads.
7913 FILE* proc_stat = fopen("/proc/self/stat", "r");
7914 if (proc_stat) {
7915 size_t n;
7916 // Size chosen arbitrarily. ~60% more bytes than a 20th column index
7917 // observed on the author's workstation.
7918 char stat_line[160];
7919 n = fread(&stat_line, 1, 159, proc_stat);
7920 stat_line[n] = '\0';
7921 fclose(proc_stat);
7922
7923 char *saveptr = NULL;
7924 char *field = strtok_r(stat_line, " ", &saveptr);
7925 unsigned int idx;
7926 for (idx = 19; idx && field; --idx) {
7927 field = strtok_r(NULL, " ", &saveptr);
7928 }
7929 if (idx == 0 && field) { // found the 20th field
7930 num_python_threads = atoi(field); // 0 on error
7931 }
7932 }
7933 #endif
7934 if (num_python_threads <= 0) {
7935 // Fall back to just the number our threading module knows about.
7936 // An incomplete view of the world, but better than nothing.
7937 PyObject *threading = PyImport_GetModule(&_Py_ID(threading));
7938 if (!threading) {
7939 PyErr_Clear();
7940 return;
7941 }
7942 PyObject *threading_active =
7943 PyObject_GetAttr(threading, &_Py_ID(_active));
7944 if (!threading_active) {
7945 PyErr_Clear();
7946 Py_DECREF(threading);
7947 return;
7948 }
7949 PyObject *threading_limbo =
7950 PyObject_GetAttr(threading, &_Py_ID(_limbo));
7951 if (!threading_limbo) {
7952 PyErr_Clear();
7953 Py_DECREF(threading);
7954 Py_DECREF(threading_active);
7955 return;
7956 }
7957 Py_DECREF(threading);
7958 // Duplicating what threading.active_count() does but without holding
7959 // threading._active_limbo_lock so our count could be inaccurate if
7960 // these dicts are mid-update from another thread. Not a big deal.
7961 // Worst case if someone replaced threading._active or threading._limbo
7962 // with non-dicts, we get -1 from *Length() below and undercount.
7963 // Nobody should, but we're best effort so we clear errors and move on.
7964 num_python_threads = (PyMapping_Length(threading_active)
7965 + PyMapping_Length(threading_limbo));
7966 PyErr_Clear();
7967 Py_DECREF(threading_active);
7968 Py_DECREF(threading_limbo);
7969 }
7970 if (num_python_threads > 1) {
7971 PyErr_WarnFormat(
7972 PyExc_DeprecationWarning, 1,
7973 #ifdef HAVE_GETPID
7974 "This process (pid=%d) is multi-threaded, "
7975 #else
7976 "This process is multi-threaded, "
7977 #endif
7978 "use of %s() may lead to deadlocks in the child.",
7979 #ifdef HAVE_GETPID
7980 getpid(),
7981 #endif
7982 name);
7983 PyErr_Clear();
7984 }
7985 }
7986 #endif // HAVE_FORK1 || HAVE_FORKPTY || HAVE_FORK
7987
7988 #ifdef HAVE_FORK1
7989 /*[clinic input]
7990 os.fork1
7991
7992 Fork a child process with a single multiplexed (i.e., not bound) thread.
7993
7994 Return 0 to child process and PID of child to parent process.
7995 [clinic start generated code]*/
7996
7997 static PyObject *
os_fork1_impl(PyObject * module)7998 os_fork1_impl(PyObject *module)
7999 /*[clinic end generated code: output=0de8e67ce2a310bc input=12db02167893926e]*/
8000 {
8001 pid_t pid;
8002
8003 PyInterpreterState *interp = _PyInterpreterState_GET();
8004 if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
8005 PyErr_SetString(PyExc_PythonFinalizationError,
8006 "can't fork at interpreter shutdown");
8007 return NULL;
8008 }
8009 if (!_Py_IsMainInterpreter(interp)) {
8010 PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters");
8011 return NULL;
8012 }
8013 PyOS_BeforeFork();
8014 pid = fork1();
8015 int saved_errno = errno;
8016 if (pid == 0) {
8017 /* child: this clobbers and resets the import lock. */
8018 PyOS_AfterFork_Child();
8019 } else {
8020 /* parent: release the import lock. */
8021 PyOS_AfterFork_Parent();
8022 // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
8023 warn_about_fork_with_threads("fork1");
8024 }
8025 if (pid == -1) {
8026 errno = saved_errno;
8027 return posix_error();
8028 }
8029 return PyLong_FromPid(pid);
8030 }
8031 #endif /* HAVE_FORK1 */
8032
8033
8034 #ifdef HAVE_FORK
8035 /*[clinic input]
8036 os.fork
8037
8038 Fork a child process.
8039
8040 Return 0 to child process and PID of child to parent process.
8041 [clinic start generated code]*/
8042
8043 static PyObject *
os_fork_impl(PyObject * module)8044 os_fork_impl(PyObject *module)
8045 /*[clinic end generated code: output=3626c81f98985d49 input=13c956413110eeaa]*/
8046 {
8047 pid_t pid;
8048 PyInterpreterState *interp = _PyInterpreterState_GET();
8049 if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
8050 PyErr_SetString(PyExc_PythonFinalizationError,
8051 "can't fork at interpreter shutdown");
8052 return NULL;
8053 }
8054 if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_FORK)) {
8055 PyErr_SetString(PyExc_RuntimeError,
8056 "fork not supported for isolated subinterpreters");
8057 return NULL;
8058 }
8059 if (PySys_Audit("os.fork", NULL) < 0) {
8060 return NULL;
8061 }
8062 PyOS_BeforeFork();
8063 pid = fork();
8064 int saved_errno = errno;
8065 if (pid == 0) {
8066 /* child: this clobbers and resets the import lock. */
8067 PyOS_AfterFork_Child();
8068 } else {
8069 /* parent: release the import lock. */
8070 PyOS_AfterFork_Parent();
8071 // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
8072 warn_about_fork_with_threads("fork");
8073 }
8074 if (pid == -1) {
8075 errno = saved_errno;
8076 return posix_error();
8077 }
8078 return PyLong_FromPid(pid);
8079 }
8080 #endif /* HAVE_FORK */
8081
8082
8083 #ifdef HAVE_SCHED_H
8084 #ifdef HAVE_SCHED_GET_PRIORITY_MAX
8085 /*[clinic input]
8086 os.sched_get_priority_max
8087
8088 policy: int
8089
8090 Get the maximum scheduling priority for policy.
8091 [clinic start generated code]*/
8092
8093 static PyObject *
os_sched_get_priority_max_impl(PyObject * module,int policy)8094 os_sched_get_priority_max_impl(PyObject *module, int policy)
8095 /*[clinic end generated code: output=9e465c6e43130521 input=2097b7998eca6874]*/
8096 {
8097 int max;
8098
8099 max = sched_get_priority_max(policy);
8100 if (max < 0)
8101 return posix_error();
8102 return PyLong_FromLong(max);
8103 }
8104
8105
8106 /*[clinic input]
8107 os.sched_get_priority_min
8108
8109 policy: int
8110
8111 Get the minimum scheduling priority for policy.
8112 [clinic start generated code]*/
8113
8114 static PyObject *
os_sched_get_priority_min_impl(PyObject * module,int policy)8115 os_sched_get_priority_min_impl(PyObject *module, int policy)
8116 /*[clinic end generated code: output=7595c1138cc47a6d input=21bc8fa0d70983bf]*/
8117 {
8118 int min = sched_get_priority_min(policy);
8119 if (min < 0)
8120 return posix_error();
8121 return PyLong_FromLong(min);
8122 }
8123 #endif /* HAVE_SCHED_GET_PRIORITY_MAX */
8124
8125
8126 #ifdef HAVE_SCHED_SETSCHEDULER
8127 /*[clinic input]
8128 os.sched_getscheduler
8129 pid: pid_t
8130 /
8131
8132 Get the scheduling policy for the process identified by pid.
8133
8134 Passing 0 for pid returns the scheduling policy for the calling process.
8135 [clinic start generated code]*/
8136
8137 static PyObject *
os_sched_getscheduler_impl(PyObject * module,pid_t pid)8138 os_sched_getscheduler_impl(PyObject *module, pid_t pid)
8139 /*[clinic end generated code: output=dce4c0bd3f1b34c8 input=8d99dac505485ac8]*/
8140 {
8141 int policy;
8142
8143 policy = sched_getscheduler(pid);
8144 if (policy < 0)
8145 return posix_error();
8146 return PyLong_FromLong(policy);
8147 }
8148 #endif /* HAVE_SCHED_SETSCHEDULER */
8149
8150
8151 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
8152 /*[clinic input]
8153 class os.sched_param "PyObject *" "SchedParamType"
8154
8155 @classmethod
8156 os.sched_param.__new__
8157
8158 sched_priority: object
8159 A scheduling parameter.
8160
8161 Currently has only one field: sched_priority
8162 [clinic start generated code]*/
8163
8164 static PyObject *
os_sched_param_impl(PyTypeObject * type,PyObject * sched_priority)8165 os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority)
8166 /*[clinic end generated code: output=48f4067d60f48c13 input=eb42909a2c0e3e6c]*/
8167 {
8168 PyObject *res;
8169
8170 res = PyStructSequence_New(type);
8171 if (!res)
8172 return NULL;
8173 PyStructSequence_SET_ITEM(res, 0, Py_NewRef(sched_priority));
8174 return res;
8175 }
8176
8177 static PyObject *
os_sched_param_reduce(PyObject * self,PyObject * Py_UNUSED (ignored))8178 os_sched_param_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
8179 {
8180 return Py_BuildValue("(O(N))", Py_TYPE(self), PyStructSequence_GetItem(self, 0));
8181 }
8182
8183 static PyMethodDef os_sched_param_reduce_method = {
8184 "__reduce__", (PyCFunction)os_sched_param_reduce, METH_NOARGS|METH_COEXIST, NULL,
8185 };
8186
8187 PyDoc_VAR(os_sched_param__doc__);
8188
8189 static PyStructSequence_Field sched_param_fields[] = {
8190 {"sched_priority", "the scheduling priority"},
8191 {0}
8192 };
8193
8194 static PyStructSequence_Desc sched_param_desc = {
8195 "sched_param", /* name */
8196 os_sched_param__doc__, /* doc */
8197 sched_param_fields,
8198 1
8199 };
8200
8201 static int
convert_sched_param(PyObject * module,PyObject * param,struct sched_param * res)8202 convert_sched_param(PyObject *module, PyObject *param, struct sched_param *res)
8203 {
8204 long priority;
8205
8206 if (!Py_IS_TYPE(param, (PyTypeObject *)get_posix_state(module)->SchedParamType)) {
8207 PyErr_SetString(PyExc_TypeError, "must have a sched_param object");
8208 return 0;
8209 }
8210 priority = PyLong_AsLong(PyStructSequence_GET_ITEM(param, 0));
8211 if (priority == -1 && PyErr_Occurred())
8212 return 0;
8213 if (priority > INT_MAX || priority < INT_MIN) {
8214 PyErr_SetString(PyExc_OverflowError, "sched_priority out of range");
8215 return 0;
8216 }
8217 res->sched_priority = Py_SAFE_DOWNCAST(priority, long, int);
8218 return 1;
8219 }
8220 #endif /* defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) */
8221
8222
8223 #ifdef HAVE_SCHED_SETSCHEDULER
8224 /*[clinic input]
8225 os.sched_setscheduler
8226
8227 pid: pid_t
8228 policy: int
8229 param as param_obj: object
8230 /
8231
8232 Set the scheduling policy for the process identified by pid.
8233
8234 If pid is 0, the calling process is changed.
8235 param is an instance of sched_param.
8236 [clinic start generated code]*/
8237
8238 static PyObject *
os_sched_setscheduler_impl(PyObject * module,pid_t pid,int policy,PyObject * param_obj)8239 os_sched_setscheduler_impl(PyObject *module, pid_t pid, int policy,
8240 PyObject *param_obj)
8241 /*[clinic end generated code: output=cde27faa55dc993e input=73013d731bd8fbe9]*/
8242 {
8243 struct sched_param param;
8244 if (!convert_sched_param(module, param_obj, ¶m)) {
8245 return NULL;
8246 }
8247
8248 /*
8249 ** sched_setscheduler() returns 0 in Linux, but the previous
8250 ** scheduling policy under Solaris/Illumos, and others.
8251 ** On error, -1 is returned in all Operating Systems.
8252 */
8253 if (sched_setscheduler(pid, policy, ¶m) == -1)
8254 return posix_error();
8255 Py_RETURN_NONE;
8256 }
8257 #endif /* HAVE_SCHED_SETSCHEDULER*/
8258
8259
8260 #ifdef HAVE_SCHED_SETPARAM
8261 /*[clinic input]
8262 os.sched_getparam
8263 pid: pid_t
8264 /
8265
8266 Returns scheduling parameters for the process identified by pid.
8267
8268 If pid is 0, returns parameters for the calling process.
8269 Return value is an instance of sched_param.
8270 [clinic start generated code]*/
8271
8272 static PyObject *
os_sched_getparam_impl(PyObject * module,pid_t pid)8273 os_sched_getparam_impl(PyObject *module, pid_t pid)
8274 /*[clinic end generated code: output=b194e8708dcf2db8 input=18a1ef9c2efae296]*/
8275 {
8276 struct sched_param param;
8277 PyObject *result;
8278 PyObject *priority;
8279
8280 if (sched_getparam(pid, ¶m))
8281 return posix_error();
8282 PyObject *SchedParamType = get_posix_state(module)->SchedParamType;
8283 result = PyStructSequence_New((PyTypeObject *)SchedParamType);
8284 if (!result)
8285 return NULL;
8286 priority = PyLong_FromLong(param.sched_priority);
8287 if (!priority) {
8288 Py_DECREF(result);
8289 return NULL;
8290 }
8291 PyStructSequence_SET_ITEM(result, 0, priority);
8292 return result;
8293 }
8294
8295
8296 /*[clinic input]
8297 os.sched_setparam
8298 pid: pid_t
8299 param as param_obj: object
8300 /
8301
8302 Set scheduling parameters for the process identified by pid.
8303
8304 If pid is 0, sets parameters for the calling process.
8305 param should be an instance of sched_param.
8306 [clinic start generated code]*/
8307
8308 static PyObject *
os_sched_setparam_impl(PyObject * module,pid_t pid,PyObject * param_obj)8309 os_sched_setparam_impl(PyObject *module, pid_t pid, PyObject *param_obj)
8310 /*[clinic end generated code: output=f19fe020a53741c1 input=27b98337c8b2dcc7]*/
8311 {
8312 struct sched_param param;
8313 if (!convert_sched_param(module, param_obj, ¶m)) {
8314 return NULL;
8315 }
8316
8317 if (sched_setparam(pid, ¶m))
8318 return posix_error();
8319 Py_RETURN_NONE;
8320 }
8321 #endif /* HAVE_SCHED_SETPARAM */
8322
8323
8324 #ifdef HAVE_SCHED_RR_GET_INTERVAL
8325 /*[clinic input]
8326 os.sched_rr_get_interval -> double
8327 pid: pid_t
8328 /
8329
8330 Return the round-robin quantum for the process identified by pid, in seconds.
8331
8332 Value returned is a float.
8333 [clinic start generated code]*/
8334
8335 static double
os_sched_rr_get_interval_impl(PyObject * module,pid_t pid)8336 os_sched_rr_get_interval_impl(PyObject *module, pid_t pid)
8337 /*[clinic end generated code: output=7e2d935833ab47dc input=2a973da15cca6fae]*/
8338 {
8339 struct timespec interval;
8340 if (sched_rr_get_interval(pid, &interval)) {
8341 posix_error();
8342 return -1.0;
8343 }
8344 #ifdef _Py_MEMORY_SANITIZER
8345 __msan_unpoison(&interval, sizeof(interval));
8346 #endif
8347 return (double)interval.tv_sec + 1e-9*interval.tv_nsec;
8348 }
8349 #endif /* HAVE_SCHED_RR_GET_INTERVAL */
8350
8351
8352 /*[clinic input]
8353 os.sched_yield
8354
8355 Voluntarily relinquish the CPU.
8356 [clinic start generated code]*/
8357
8358 static PyObject *
os_sched_yield_impl(PyObject * module)8359 os_sched_yield_impl(PyObject *module)
8360 /*[clinic end generated code: output=902323500f222cac input=e54d6f98189391d4]*/
8361 {
8362 int result;
8363 Py_BEGIN_ALLOW_THREADS
8364 result = sched_yield();
8365 Py_END_ALLOW_THREADS
8366 if (result < 0) {
8367 return posix_error();
8368 }
8369 Py_RETURN_NONE;
8370 }
8371
8372 #ifdef HAVE_SCHED_SETAFFINITY
8373 /* The minimum number of CPUs allocated in a cpu_set_t */
8374 static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
8375
8376 /*[clinic input]
8377 os.sched_setaffinity
8378 pid: pid_t
8379 mask : object
8380 /
8381
8382 Set the CPU affinity of the process identified by pid to mask.
8383
8384 mask should be an iterable of integers identifying CPUs.
8385 [clinic start generated code]*/
8386
8387 static PyObject *
os_sched_setaffinity_impl(PyObject * module,pid_t pid,PyObject * mask)8388 os_sched_setaffinity_impl(PyObject *module, pid_t pid, PyObject *mask)
8389 /*[clinic end generated code: output=882d7dd9a229335b input=a0791a597c7085ba]*/
8390 {
8391 int ncpus;
8392 size_t setsize;
8393 cpu_set_t *cpu_set = NULL;
8394 PyObject *iterator = NULL, *item;
8395
8396 iterator = PyObject_GetIter(mask);
8397 if (iterator == NULL)
8398 return NULL;
8399
8400 ncpus = NCPUS_START;
8401 setsize = CPU_ALLOC_SIZE(ncpus);
8402 cpu_set = CPU_ALLOC(ncpus);
8403 if (cpu_set == NULL) {
8404 PyErr_NoMemory();
8405 goto error;
8406 }
8407 CPU_ZERO_S(setsize, cpu_set);
8408
8409 while ((item = PyIter_Next(iterator))) {
8410 long cpu;
8411 if (!PyLong_Check(item)) {
8412 PyErr_Format(PyExc_TypeError,
8413 "expected an iterator of ints, "
8414 "but iterator yielded %R",
8415 Py_TYPE(item));
8416 Py_DECREF(item);
8417 goto error;
8418 }
8419 cpu = PyLong_AsLong(item);
8420 Py_DECREF(item);
8421 if (cpu < 0) {
8422 if (!PyErr_Occurred())
8423 PyErr_SetString(PyExc_ValueError, "negative CPU number");
8424 goto error;
8425 }
8426 if (cpu > INT_MAX - 1) {
8427 PyErr_SetString(PyExc_OverflowError, "CPU number too large");
8428 goto error;
8429 }
8430 if (cpu >= ncpus) {
8431 /* Grow CPU mask to fit the CPU number */
8432 int newncpus = ncpus;
8433 cpu_set_t *newmask;
8434 size_t newsetsize;
8435 while (newncpus <= cpu) {
8436 if (newncpus > INT_MAX / 2)
8437 newncpus = cpu + 1;
8438 else
8439 newncpus = newncpus * 2;
8440 }
8441 newmask = CPU_ALLOC(newncpus);
8442 if (newmask == NULL) {
8443 PyErr_NoMemory();
8444 goto error;
8445 }
8446 newsetsize = CPU_ALLOC_SIZE(newncpus);
8447 CPU_ZERO_S(newsetsize, newmask);
8448 memcpy(newmask, cpu_set, setsize);
8449 CPU_FREE(cpu_set);
8450 setsize = newsetsize;
8451 cpu_set = newmask;
8452 ncpus = newncpus;
8453 }
8454 CPU_SET_S(cpu, setsize, cpu_set);
8455 }
8456 if (PyErr_Occurred()) {
8457 goto error;
8458 }
8459 Py_CLEAR(iterator);
8460
8461 if (sched_setaffinity(pid, setsize, cpu_set)) {
8462 posix_error();
8463 goto error;
8464 }
8465 CPU_FREE(cpu_set);
8466 Py_RETURN_NONE;
8467
8468 error:
8469 if (cpu_set)
8470 CPU_FREE(cpu_set);
8471 Py_XDECREF(iterator);
8472 return NULL;
8473 }
8474
8475
8476 /*[clinic input]
8477 os.sched_getaffinity
8478 pid: pid_t
8479 /
8480
8481 Return the affinity of the process identified by pid (or the current process if zero).
8482
8483 The affinity is returned as a set of CPU identifiers.
8484 [clinic start generated code]*/
8485
8486 static PyObject *
os_sched_getaffinity_impl(PyObject * module,pid_t pid)8487 os_sched_getaffinity_impl(PyObject *module, pid_t pid)
8488 /*[clinic end generated code: output=f726f2c193c17a4f input=983ce7cb4a565980]*/
8489 {
8490 int ncpus = NCPUS_START;
8491 size_t setsize;
8492 cpu_set_t *mask;
8493
8494 while (1) {
8495 setsize = CPU_ALLOC_SIZE(ncpus);
8496 mask = CPU_ALLOC(ncpus);
8497 if (mask == NULL) {
8498 return PyErr_NoMemory();
8499 }
8500 if (sched_getaffinity(pid, setsize, mask) == 0) {
8501 break;
8502 }
8503 CPU_FREE(mask);
8504 if (errno != EINVAL) {
8505 return posix_error();
8506 }
8507 if (ncpus > INT_MAX / 2) {
8508 PyErr_SetString(PyExc_OverflowError,
8509 "could not allocate a large enough CPU set");
8510 return NULL;
8511 }
8512 ncpus *= 2;
8513 }
8514
8515 PyObject *res = PySet_New(NULL);
8516 if (res == NULL) {
8517 goto error;
8518 }
8519
8520 int cpu = 0;
8521 int count = CPU_COUNT_S(setsize, mask);
8522 for (; count; cpu++) {
8523 if (CPU_ISSET_S(cpu, setsize, mask)) {
8524 PyObject *cpu_num = PyLong_FromLong(cpu);
8525 --count;
8526 if (cpu_num == NULL) {
8527 goto error;
8528 }
8529 if (PySet_Add(res, cpu_num)) {
8530 Py_DECREF(cpu_num);
8531 goto error;
8532 }
8533 Py_DECREF(cpu_num);
8534 }
8535 }
8536 CPU_FREE(mask);
8537 return res;
8538
8539 error:
8540 if (mask) {
8541 CPU_FREE(mask);
8542 }
8543 Py_XDECREF(res);
8544 return NULL;
8545 }
8546 #endif /* HAVE_SCHED_SETAFFINITY */
8547
8548 #endif /* HAVE_SCHED_H */
8549
8550
8551 #ifdef HAVE_POSIX_OPENPT
8552 /*[clinic input]
8553 os.posix_openpt -> int
8554
8555 oflag: int
8556 /
8557
8558 Open and return a file descriptor for a master pseudo-terminal device.
8559
8560 Performs a posix_openpt() C function call. The oflag argument is used to
8561 set file status flags and file access modes as specified in the manual page
8562 of posix_openpt() of your system.
8563 [clinic start generated code]*/
8564
8565 static int
os_posix_openpt_impl(PyObject * module,int oflag)8566 os_posix_openpt_impl(PyObject *module, int oflag)
8567 /*[clinic end generated code: output=ee0bc2624305fc79 input=0de33d0e29693caa]*/
8568 {
8569 int fd;
8570
8571 #if defined(O_CLOEXEC)
8572 oflag |= O_CLOEXEC;
8573 #endif
8574
8575 fd = posix_openpt(oflag);
8576 if (fd == -1) {
8577 posix_error();
8578 return -1;
8579 }
8580
8581 // Just in case, likely a no-op given O_CLOEXEC above.
8582 if (_Py_set_inheritable(fd, 0, NULL) < 0) {
8583 close(fd);
8584 return -1;
8585 }
8586
8587 return fd;
8588 }
8589 #endif /* HAVE_POSIX_OPENPT */
8590
8591 #ifdef HAVE_GRANTPT
8592 /*[clinic input]
8593 os.grantpt
8594
8595 fd: fildes
8596 File descriptor of a master pseudo-terminal device.
8597 /
8598
8599 Grant access to the slave pseudo-terminal device.
8600
8601 Performs a grantpt() C function call.
8602 [clinic start generated code]*/
8603
8604 static PyObject *
os_grantpt_impl(PyObject * module,int fd)8605 os_grantpt_impl(PyObject *module, int fd)
8606 /*[clinic end generated code: output=dfd580015cf548ab input=0668e3b96760e849]*/
8607 {
8608 int ret;
8609 int saved_errno;
8610 PyOS_sighandler_t sig_saved;
8611
8612 sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
8613
8614 ret = grantpt(fd);
8615 if (ret == -1)
8616 saved_errno = errno;
8617
8618 PyOS_setsig(SIGCHLD, sig_saved);
8619
8620 if (ret == -1) {
8621 errno = saved_errno;
8622 return posix_error();
8623 }
8624
8625 Py_RETURN_NONE;
8626 }
8627 #endif /* HAVE_GRANTPT */
8628
8629 #ifdef HAVE_UNLOCKPT
8630 /*[clinic input]
8631 os.unlockpt
8632
8633 fd: fildes
8634 File descriptor of a master pseudo-terminal device.
8635 /
8636
8637 Unlock a pseudo-terminal master/slave pair.
8638
8639 Performs an unlockpt() C function call.
8640 [clinic start generated code]*/
8641
8642 static PyObject *
os_unlockpt_impl(PyObject * module,int fd)8643 os_unlockpt_impl(PyObject *module, int fd)
8644 /*[clinic end generated code: output=e08d354dec12d30c input=de7ab1f59f69a2b4]*/
8645 {
8646 if (unlockpt(fd) == -1)
8647 return posix_error();
8648
8649 Py_RETURN_NONE;
8650 }
8651 #endif /* HAVE_UNLOCKPT */
8652
8653 #if defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R)
8654 static PyObject *
py_ptsname(int fd)8655 py_ptsname(int fd)
8656 {
8657 // POSIX manpage: Upon failure, ptsname() shall return a null pointer
8658 // and may set errno. Always initialize errno to avoid undefined behavior.
8659 errno = 0;
8660 char *name = ptsname(fd);
8661 if (name == NULL) {
8662 return posix_error();
8663 }
8664 return PyUnicode_DecodeFSDefault(name);
8665 }
8666
8667 /*[clinic input]
8668 os.ptsname
8669
8670 fd: fildes
8671 File descriptor of a master pseudo-terminal device.
8672 /
8673
8674 Return the name of the slave pseudo-terminal device.
8675
8676 If the ptsname_r() C function is available, it is called;
8677 otherwise, performs a ptsname() C function call.
8678 [clinic start generated code]*/
8679
8680 static PyObject *
os_ptsname_impl(PyObject * module,int fd)8681 os_ptsname_impl(PyObject *module, int fd)
8682 /*[clinic end generated code: output=ef300fadc5675872 input=1369ccc0546f3130]*/
8683 {
8684 #ifdef HAVE_PTSNAME_R
8685 int ret;
8686 char name[MAXPATHLEN+1];
8687
8688 if (HAVE_PTSNAME_R_RUNTIME) {
8689 ret = ptsname_r(fd, name, sizeof(name));
8690 }
8691 else {
8692 // fallback to ptsname() if ptsname_r() is not available in runtime.
8693 return py_ptsname(fd);
8694 }
8695 if (ret != 0) {
8696 errno = ret;
8697 return posix_error();
8698 }
8699
8700 return PyUnicode_DecodeFSDefault(name);
8701 #else
8702 return py_ptsname(fd);
8703 #endif /* HAVE_PTSNAME_R */
8704 }
8705 #endif /* defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R) */
8706
8707 /* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */
8708 #if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX)
8709 # define DEV_PTY_FILE "/dev/ptc"
8710 # define HAVE_DEV_PTMX
8711 #else
8712 # define DEV_PTY_FILE "/dev/ptmx"
8713 #endif
8714
8715 #if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX)
8716 #ifdef HAVE_PTY_H
8717 #include <pty.h>
8718 #ifdef HAVE_UTMP_H
8719 #include <utmp.h>
8720 #endif /* HAVE_UTMP_H */
8721 #elif defined(HAVE_LIBUTIL_H)
8722 #include <libutil.h>
8723 #elif defined(HAVE_UTIL_H)
8724 #include <util.h>
8725 #endif /* HAVE_PTY_H */
8726 #ifdef HAVE_STROPTS_H
8727 #include <stropts.h>
8728 #endif
8729 #endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX) */
8730
8731
8732 #if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)
8733 /*[clinic input]
8734 os.openpty
8735
8736 Open a pseudo-terminal.
8737
8738 Return a tuple of (master_fd, slave_fd) containing open file descriptors
8739 for both the master and slave ends.
8740 [clinic start generated code]*/
8741
8742 static PyObject *
os_openpty_impl(PyObject * module)8743 os_openpty_impl(PyObject *module)
8744 /*[clinic end generated code: output=98841ce5ec9cef3c input=f3d99fd99e762907]*/
8745 {
8746 int master_fd = -1, slave_fd = -1;
8747 #ifndef HAVE_OPENPTY
8748 char * slave_name;
8749 #endif
8750 #if defined(HAVE_DEV_PTMX) && !defined(HAVE_OPENPTY) && !defined(HAVE__GETPTY)
8751 PyOS_sighandler_t sig_saved;
8752 #if defined(__sun) && defined(__SVR4)
8753 extern char *ptsname(int fildes);
8754 #endif
8755 #endif
8756
8757 #ifdef HAVE_OPENPTY
8758 if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)
8759 goto posix_error;
8760
8761 if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
8762 goto error;
8763 if (_Py_set_inheritable(slave_fd, 0, NULL) < 0)
8764 goto error;
8765
8766 #elif defined(HAVE__GETPTY)
8767 slave_name = _getpty(&master_fd, O_RDWR, 0666, 0);
8768 if (slave_name == NULL)
8769 goto posix_error;
8770 if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
8771 goto error;
8772
8773 slave_fd = _Py_open(slave_name, O_RDWR);
8774 if (slave_fd < 0)
8775 goto error;
8776
8777 #else
8778 master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
8779 if (master_fd < 0)
8780 goto posix_error;
8781
8782 sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
8783
8784 /* change permission of slave */
8785 if (grantpt(master_fd) < 0) {
8786 int saved_errno = errno;
8787 PyOS_setsig(SIGCHLD, sig_saved);
8788 errno = saved_errno;
8789 goto posix_error;
8790 }
8791
8792 /* unlock slave */
8793 if (unlockpt(master_fd) < 0) {
8794 int saved_errno = errno;
8795 PyOS_setsig(SIGCHLD, sig_saved);
8796 errno = saved_errno;
8797 goto posix_error;
8798 }
8799
8800 PyOS_setsig(SIGCHLD, sig_saved);
8801
8802 slave_name = ptsname(master_fd); /* get name of slave */
8803 if (slave_name == NULL)
8804 goto posix_error;
8805
8806 slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
8807 if (slave_fd == -1)
8808 goto error;
8809
8810 if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
8811 goto posix_error;
8812
8813 #if !defined(__CYGWIN__) && !defined(__ANDROID__) && !defined(HAVE_DEV_PTC)
8814 ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */
8815 ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */
8816 #ifndef __hpux
8817 ioctl(slave_fd, I_PUSH, "ttcompat"); /* push ttcompat */
8818 #endif /* __hpux */
8819 #endif /* HAVE_CYGWIN */
8820 #endif /* HAVE_OPENPTY */
8821
8822 return Py_BuildValue("(ii)", master_fd, slave_fd);
8823
8824 posix_error:
8825 posix_error();
8826 error:
8827 if (master_fd != -1)
8828 close(master_fd);
8829 if (slave_fd != -1)
8830 close(slave_fd);
8831 return NULL;
8832 }
8833 #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */
8834
8835
8836 #if defined(HAVE_SETSID) && defined(TIOCSCTTY)
8837 #define HAVE_FALLBACK_LOGIN_TTY 1
8838 #endif /* defined(HAVE_SETSID) && defined(TIOCSCTTY) */
8839
8840 #if defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY)
8841 /*[clinic input]
8842 os.login_tty
8843
8844 fd: fildes
8845 /
8846
8847 Prepare the tty of which fd is a file descriptor for a new login session.
8848
8849 Make the calling process a session leader; make the tty the
8850 controlling tty, the stdin, the stdout, and the stderr of the
8851 calling process; close fd.
8852 [clinic start generated code]*/
8853
8854 static PyObject *
os_login_tty_impl(PyObject * module,int fd)8855 os_login_tty_impl(PyObject *module, int fd)
8856 /*[clinic end generated code: output=495a79911b4cc1bc input=5f298565099903a2]*/
8857 {
8858 #ifdef HAVE_LOGIN_TTY
8859 if (login_tty(fd) == -1) {
8860 return posix_error();
8861 }
8862 #else /* defined(HAVE_FALLBACK_LOGIN_TTY) */
8863 /* Establish a new session. */
8864 if (setsid() == -1) {
8865 return posix_error();
8866 }
8867
8868 /* The tty becomes the controlling terminal. */
8869 if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) {
8870 return posix_error();
8871 }
8872
8873 /* The tty becomes stdin/stdout/stderr */
8874 if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1) {
8875 return posix_error();
8876 }
8877 if (fd > 2) {
8878 close(fd);
8879 }
8880 #endif /* HAVE_LOGIN_TTY */
8881 Py_RETURN_NONE;
8882 }
8883 #endif /* defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) */
8884
8885
8886 #ifdef HAVE_FORKPTY
8887 /*[clinic input]
8888 os.forkpty
8889
8890 Fork a new process with a new pseudo-terminal as controlling tty.
8891
8892 Returns a tuple of (pid, master_fd).
8893 Like fork(), return pid of 0 to the child process,
8894 and pid of child to the parent process.
8895 To both, return fd of newly opened pseudo-terminal.
8896 [clinic start generated code]*/
8897
8898 static PyObject *
os_forkpty_impl(PyObject * module)8899 os_forkpty_impl(PyObject *module)
8900 /*[clinic end generated code: output=60d0a5c7512e4087 input=f1f7f4bae3966010]*/
8901 {
8902 int master_fd = -1;
8903 pid_t pid;
8904
8905 PyInterpreterState *interp = _PyInterpreterState_GET();
8906 if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
8907 PyErr_SetString(PyExc_PythonFinalizationError,
8908 "can't fork at interpreter shutdown");
8909 return NULL;
8910 }
8911 if (!_Py_IsMainInterpreter(interp)) {
8912 PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters");
8913 return NULL;
8914 }
8915 if (PySys_Audit("os.forkpty", NULL) < 0) {
8916 return NULL;
8917 }
8918 PyOS_BeforeFork();
8919 pid = forkpty(&master_fd, NULL, NULL, NULL);
8920 if (pid == 0) {
8921 /* child: this clobbers and resets the import lock. */
8922 PyOS_AfterFork_Child();
8923 } else {
8924 /* parent: release the import lock. */
8925 PyOS_AfterFork_Parent();
8926 // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
8927 warn_about_fork_with_threads("forkpty");
8928 }
8929 if (pid == -1) {
8930 return posix_error();
8931 }
8932 return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd);
8933 }
8934 #endif /* HAVE_FORKPTY */
8935
8936
8937 #ifdef HAVE_GETEGID
8938 /*[clinic input]
8939 os.getegid
8940
8941 Return the current process's effective group id.
8942 [clinic start generated code]*/
8943
8944 static PyObject *
os_getegid_impl(PyObject * module)8945 os_getegid_impl(PyObject *module)
8946 /*[clinic end generated code: output=67d9be7ac68898a2 input=1596f79ad1107d5d]*/
8947 {
8948 return _PyLong_FromGid(getegid());
8949 }
8950 #endif /* HAVE_GETEGID */
8951
8952
8953 #ifdef HAVE_GETEUID
8954 /*[clinic input]
8955 os.geteuid
8956
8957 Return the current process's effective user id.
8958 [clinic start generated code]*/
8959
8960 static PyObject *
os_geteuid_impl(PyObject * module)8961 os_geteuid_impl(PyObject *module)
8962 /*[clinic end generated code: output=ea1b60f0d6abb66e input=4644c662d3bd9f19]*/
8963 {
8964 return _PyLong_FromUid(geteuid());
8965 }
8966 #endif /* HAVE_GETEUID */
8967
8968
8969 #ifdef HAVE_GETGID
8970 /*[clinic input]
8971 os.getgid
8972
8973 Return the current process's group id.
8974 [clinic start generated code]*/
8975
8976 static PyObject *
os_getgid_impl(PyObject * module)8977 os_getgid_impl(PyObject *module)
8978 /*[clinic end generated code: output=4f28ebc9d3e5dfcf input=58796344cd87c0f6]*/
8979 {
8980 return _PyLong_FromGid(getgid());
8981 }
8982 #endif /* HAVE_GETGID */
8983
8984
8985 #if defined(HAVE_GETPID)
8986 /*[clinic input]
8987 os.getpid
8988
8989 Return the current process id.
8990 [clinic start generated code]*/
8991
8992 static PyObject *
os_getpid_impl(PyObject * module)8993 os_getpid_impl(PyObject *module)
8994 /*[clinic end generated code: output=9ea6fdac01ed2b3c input=5a9a00f0ab68aa00]*/
8995 {
8996 #if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)
8997 return PyLong_FromPid(getpid());
8998 #else
8999 return PyLong_FromUnsignedLong(GetCurrentProcessId());
9000 #endif
9001 }
9002 #endif /* defined(HAVE_GETPID) */
9003
9004 #ifdef NGROUPS_MAX
9005 #define MAX_GROUPS NGROUPS_MAX
9006 #else
9007 /* defined to be 16 on Solaris7, so this should be a small number */
9008 #define MAX_GROUPS 64
9009 #endif
9010
9011 #ifdef HAVE_GETGROUPLIST
9012
9013 #ifdef __APPLE__
9014 /*[clinic input]
9015 os.getgrouplist
9016
9017 user: str
9018 username to lookup
9019 group as basegid: int
9020 base group id of the user
9021 /
9022
9023 Returns a list of groups to which a user belongs.
9024 [clinic start generated code]*/
9025
9026 static PyObject *
os_getgrouplist_impl(PyObject * module,const char * user,int basegid)9027 os_getgrouplist_impl(PyObject *module, const char *user, int basegid)
9028 /*[clinic end generated code: output=6e734697b8c26de0 input=f8d870374b09a490]*/
9029 #else
9030 /*[clinic input]
9031 os.getgrouplist
9032
9033 user: str
9034 username to lookup
9035 group as basegid: gid_t
9036 base group id of the user
9037 /
9038
9039 Returns a list of groups to which a user belongs.
9040 [clinic start generated code]*/
9041
9042 static PyObject *
9043 os_getgrouplist_impl(PyObject *module, const char *user, gid_t basegid)
9044 /*[clinic end generated code: output=0ebd7fb70115575b input=cc61d5c20b08958d]*/
9045 #endif
9046 {
9047 int i, ngroups;
9048 PyObject *list;
9049 #ifdef __APPLE__
9050 int *groups;
9051 #else
9052 gid_t *groups;
9053 #endif
9054
9055 /*
9056 * NGROUPS_MAX is defined by POSIX.1 as the maximum
9057 * number of supplimental groups a users can belong to.
9058 * We have to increment it by one because
9059 * getgrouplist() returns both the supplemental groups
9060 * and the primary group, i.e. all of the groups the
9061 * user belongs to.
9062 */
9063 ngroups = 1 + MAX_GROUPS;
9064
9065 while (1) {
9066 #ifdef __APPLE__
9067 groups = PyMem_New(int, ngroups);
9068 #else
9069 groups = PyMem_New(gid_t, ngroups);
9070 #endif
9071 if (groups == NULL) {
9072 return PyErr_NoMemory();
9073 }
9074
9075 int old_ngroups = ngroups;
9076 if (getgrouplist(user, basegid, groups, &ngroups) != -1) {
9077 /* Success */
9078 break;
9079 }
9080
9081 /* getgrouplist() fails if the group list is too small */
9082 PyMem_Free(groups);
9083
9084 if (ngroups > old_ngroups) {
9085 /* If the group list is too small, the glibc implementation of
9086 getgrouplist() sets ngroups to the total number of groups and
9087 returns -1. */
9088 }
9089 else {
9090 /* Double the group list size */
9091 if (ngroups > INT_MAX / 2) {
9092 return PyErr_NoMemory();
9093 }
9094 ngroups *= 2;
9095 }
9096
9097 /* Retry getgrouplist() with a larger group list */
9098 }
9099
9100 #ifdef _Py_MEMORY_SANITIZER
9101 /* Clang memory sanitizer libc intercepts don't know getgrouplist. */
9102 __msan_unpoison(&ngroups, sizeof(ngroups));
9103 __msan_unpoison(groups, ngroups*sizeof(*groups));
9104 #endif
9105
9106 list = PyList_New(ngroups);
9107 if (list == NULL) {
9108 PyMem_Free(groups);
9109 return NULL;
9110 }
9111
9112 for (i = 0; i < ngroups; i++) {
9113 #ifdef __APPLE__
9114 PyObject *o = PyLong_FromUnsignedLong((unsigned long)groups[i]);
9115 #else
9116 PyObject *o = _PyLong_FromGid(groups[i]);
9117 #endif
9118 if (o == NULL) {
9119 Py_DECREF(list);
9120 PyMem_Free(groups);
9121 return NULL;
9122 }
9123 PyList_SET_ITEM(list, i, o);
9124 }
9125
9126 PyMem_Free(groups);
9127
9128 return list;
9129 }
9130 #endif /* HAVE_GETGROUPLIST */
9131
9132
9133 #ifdef HAVE_GETGROUPS
9134 /*[clinic input]
9135 os.getgroups
9136
9137 Return list of supplemental group IDs for the process.
9138 [clinic start generated code]*/
9139
9140 static PyObject *
os_getgroups_impl(PyObject * module)9141 os_getgroups_impl(PyObject *module)
9142 /*[clinic end generated code: output=42b0c17758561b56 input=d3f109412e6a155c]*/
9143 {
9144 // Call getgroups with length 0 to get the actual number of groups
9145 int n = getgroups(0, NULL);
9146 if (n < 0) {
9147 return posix_error();
9148 }
9149
9150 if (n == 0) {
9151 return PyList_New(0);
9152 }
9153
9154 gid_t *grouplist = PyMem_New(gid_t, n);
9155 if (grouplist == NULL) {
9156 return PyErr_NoMemory();
9157 }
9158
9159 n = getgroups(n, grouplist);
9160 if (n == -1) {
9161 posix_error();
9162 PyMem_Free(grouplist);
9163 return NULL;
9164 }
9165
9166 PyObject *result = PyList_New(n);
9167 if (result == NULL) {
9168 goto error;
9169 }
9170
9171 for (int i = 0; i < n; ++i) {
9172 PyObject *group = _PyLong_FromGid(grouplist[i]);
9173 if (group == NULL) {
9174 goto error;
9175 }
9176 PyList_SET_ITEM(result, i, group);
9177 }
9178 PyMem_Free(grouplist);
9179
9180 return result;
9181
9182 error:
9183 PyMem_Free(grouplist);
9184 Py_XDECREF(result);
9185 return NULL;
9186 }
9187 #endif /* HAVE_GETGROUPS */
9188
9189 #ifdef HAVE_INITGROUPS
9190 #ifdef __APPLE__
9191 /*[clinic input]
9192 os.initgroups
9193
9194 username as oname: FSConverter
9195 gid: int
9196 /
9197
9198 Initialize the group access list.
9199
9200 Call the system initgroups() to initialize the group access list with all of
9201 the groups of which the specified username is a member, plus the specified
9202 group id.
9203 [clinic start generated code]*/
9204
9205 static PyObject *
os_initgroups_impl(PyObject * module,PyObject * oname,int gid)9206 os_initgroups_impl(PyObject *module, PyObject *oname, int gid)
9207 /*[clinic end generated code: output=7f074d30a425fd3a input=df3d54331b0af204]*/
9208 #else
9209 /*[clinic input]
9210 os.initgroups
9211
9212 username as oname: FSConverter
9213 gid: gid_t
9214 /
9215
9216 Initialize the group access list.
9217
9218 Call the system initgroups() to initialize the group access list with all of
9219 the groups of which the specified username is a member, plus the specified
9220 group id.
9221 [clinic start generated code]*/
9222
9223 static PyObject *
9224 os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid)
9225 /*[clinic end generated code: output=59341244521a9e3f input=0cb91bdc59a4c564]*/
9226 #endif
9227 {
9228 const char *username = PyBytes_AS_STRING(oname);
9229
9230 if (initgroups(username, gid) == -1)
9231 return PyErr_SetFromErrno(PyExc_OSError);
9232
9233 Py_RETURN_NONE;
9234 }
9235 #endif /* HAVE_INITGROUPS */
9236
9237
9238 #ifdef HAVE_GETPGID
9239 /*[clinic input]
9240 os.getpgid
9241
9242 pid: pid_t
9243
9244 Call the system call getpgid(), and return the result.
9245 [clinic start generated code]*/
9246
9247 static PyObject *
os_getpgid_impl(PyObject * module,pid_t pid)9248 os_getpgid_impl(PyObject *module, pid_t pid)
9249 /*[clinic end generated code: output=1db95a97be205d18 input=39d710ae3baaf1c7]*/
9250 {
9251 pid_t pgid = getpgid(pid);
9252 if (pgid < 0)
9253 return posix_error();
9254 return PyLong_FromPid(pgid);
9255 }
9256 #endif /* HAVE_GETPGID */
9257
9258
9259 #ifdef HAVE_GETPGRP
9260 /*[clinic input]
9261 os.getpgrp
9262
9263 Return the current process group id.
9264 [clinic start generated code]*/
9265
9266 static PyObject *
os_getpgrp_impl(PyObject * module)9267 os_getpgrp_impl(PyObject *module)
9268 /*[clinic end generated code: output=c4fc381e51103cf3 input=6846fb2bb9a3705e]*/
9269 {
9270 #ifdef GETPGRP_HAVE_ARG
9271 return PyLong_FromPid(getpgrp(0));
9272 #else /* GETPGRP_HAVE_ARG */
9273 return PyLong_FromPid(getpgrp());
9274 #endif /* GETPGRP_HAVE_ARG */
9275 }
9276 #endif /* HAVE_GETPGRP */
9277
9278
9279 #ifdef HAVE_SETPGRP
9280 /*[clinic input]
9281 os.setpgrp
9282
9283 Make the current process the leader of its process group.
9284 [clinic start generated code]*/
9285
9286 static PyObject *
os_setpgrp_impl(PyObject * module)9287 os_setpgrp_impl(PyObject *module)
9288 /*[clinic end generated code: output=2554735b0a60f0a0 input=1f0619fcb5731e7e]*/
9289 {
9290 #ifdef SETPGRP_HAVE_ARG
9291 if (setpgrp(0, 0) < 0)
9292 #else /* SETPGRP_HAVE_ARG */
9293 if (setpgrp() < 0)
9294 #endif /* SETPGRP_HAVE_ARG */
9295 return posix_error();
9296 Py_RETURN_NONE;
9297 }
9298 #endif /* HAVE_SETPGRP */
9299
9300 #ifdef HAVE_GETPPID
9301
9302 #ifdef MS_WINDOWS
9303 #include <winternl.h>
9304 #include <ProcessSnapshot.h>
9305
9306 // The structure definition in winternl.h may be incomplete.
9307 // This structure is the full version from the MSDN documentation.
9308 typedef struct _PROCESS_BASIC_INFORMATION_FULL {
9309 NTSTATUS ExitStatus;
9310 PVOID PebBaseAddress;
9311 ULONG_PTR AffinityMask;
9312 LONG BasePriority;
9313 ULONG_PTR UniqueProcessId;
9314 ULONG_PTR InheritedFromUniqueProcessId;
9315 } PROCESS_BASIC_INFORMATION_FULL;
9316
9317 typedef NTSTATUS (NTAPI *PNT_QUERY_INFORMATION_PROCESS) (
9318 IN HANDLE ProcessHandle,
9319 IN PROCESSINFOCLASS ProcessInformationClass,
9320 OUT PVOID ProcessInformation,
9321 IN ULONG ProcessInformationLength,
9322 OUT PULONG ReturnLength OPTIONAL);
9323
9324 // This function returns the process ID of the parent process.
9325 // Returns 0 on failure.
9326 static ULONG
win32_getppid_fast(void)9327 win32_getppid_fast(void)
9328 {
9329 NTSTATUS status;
9330 HMODULE ntdll;
9331 PNT_QUERY_INFORMATION_PROCESS pNtQueryInformationProcess;
9332 PROCESS_BASIC_INFORMATION_FULL basic_information;
9333 static ULONG cached_ppid = 0;
9334
9335 if (cached_ppid) {
9336 // No need to query the kernel again.
9337 return cached_ppid;
9338 }
9339
9340 ntdll = GetModuleHandleW(L"ntdll.dll");
9341 if (!ntdll) {
9342 return 0;
9343 }
9344
9345 pNtQueryInformationProcess = (PNT_QUERY_INFORMATION_PROCESS) GetProcAddress(ntdll, "NtQueryInformationProcess");
9346 if (!pNtQueryInformationProcess) {
9347 return 0;
9348 }
9349
9350 status = pNtQueryInformationProcess(GetCurrentProcess(),
9351 ProcessBasicInformation,
9352 &basic_information,
9353 sizeof(basic_information),
9354 NULL);
9355
9356 if (!NT_SUCCESS(status)) {
9357 return 0;
9358 }
9359
9360 // Perform sanity check on the parent process ID we received from NtQueryInformationProcess.
9361 // The check covers values which exceed the 32-bit range (if running on x64) as well as
9362 // zero and (ULONG) -1.
9363
9364 if (basic_information.InheritedFromUniqueProcessId == 0 ||
9365 basic_information.InheritedFromUniqueProcessId >= ULONG_MAX)
9366 {
9367 return 0;
9368 }
9369
9370 // Now that we have reached this point, the BasicInformation.InheritedFromUniqueProcessId
9371 // structure member contains a ULONG_PTR which represents the process ID of our parent
9372 // process. This process ID will be correctly returned even if the parent process has
9373 // exited or been terminated.
9374
9375 cached_ppid = (ULONG) basic_information.InheritedFromUniqueProcessId;
9376 return cached_ppid;
9377 }
9378
9379 static PyObject*
win32_getppid(void)9380 win32_getppid(void)
9381 {
9382 DWORD error;
9383 PyObject* result = NULL;
9384 HANDLE process = GetCurrentProcess();
9385 HPSS snapshot = NULL;
9386 ULONG pid;
9387
9388 pid = win32_getppid_fast();
9389 if (pid != 0) {
9390 return PyLong_FromUnsignedLong(pid);
9391 }
9392
9393 // If failure occurs in win32_getppid_fast(), fall back to using the PSS API.
9394
9395 error = PssCaptureSnapshot(process, PSS_CAPTURE_NONE, 0, &snapshot);
9396 if (error != ERROR_SUCCESS) {
9397 return PyErr_SetFromWindowsErr(error);
9398 }
9399
9400 PSS_PROCESS_INFORMATION info;
9401 error = PssQuerySnapshot(snapshot, PSS_QUERY_PROCESS_INFORMATION, &info,
9402 sizeof(info));
9403 if (error == ERROR_SUCCESS) {
9404 result = PyLong_FromUnsignedLong(info.ParentProcessId);
9405 }
9406 else {
9407 result = PyErr_SetFromWindowsErr(error);
9408 }
9409
9410 PssFreeSnapshot(process, snapshot);
9411 return result;
9412 }
9413 #endif /*MS_WINDOWS*/
9414
9415
9416 /*[clinic input]
9417 os.getppid
9418
9419 Return the parent's process id.
9420
9421 If the parent process has already exited, Windows machines will still
9422 return its id; others systems will return the id of the 'init' process (1).
9423 [clinic start generated code]*/
9424
9425 static PyObject *
os_getppid_impl(PyObject * module)9426 os_getppid_impl(PyObject *module)
9427 /*[clinic end generated code: output=43b2a946a8c603b4 input=e637cb87539c030e]*/
9428 {
9429 #ifdef MS_WINDOWS
9430 return win32_getppid();
9431 #else
9432 return PyLong_FromPid(getppid());
9433 #endif
9434 }
9435 #endif /* HAVE_GETPPID */
9436
9437
9438 #ifdef HAVE_GETLOGIN
9439 /*[clinic input]
9440 os.getlogin
9441
9442 Return the actual login name.
9443 [clinic start generated code]*/
9444
9445 static PyObject *
os_getlogin_impl(PyObject * module)9446 os_getlogin_impl(PyObject *module)
9447 /*[clinic end generated code: output=a32e66a7e5715dac input=2a21ab1e917163df]*/
9448 {
9449 PyObject *result = NULL;
9450 #ifdef MS_WINDOWS
9451 wchar_t user_name[UNLEN + 1];
9452 DWORD num_chars = Py_ARRAY_LENGTH(user_name);
9453
9454 if (GetUserNameW(user_name, &num_chars)) {
9455 /* num_chars is the number of unicode chars plus null terminator */
9456 result = PyUnicode_FromWideChar(user_name, num_chars - 1);
9457 }
9458 else
9459 result = PyErr_SetFromWindowsErr(GetLastError());
9460 #else
9461 char *name;
9462 int old_errno = errno;
9463
9464 errno = 0;
9465 name = getlogin();
9466 if (name == NULL) {
9467 if (errno)
9468 posix_error();
9469 else
9470 PyErr_SetString(PyExc_OSError, "unable to determine login name");
9471 }
9472 else
9473 result = PyUnicode_DecodeFSDefault(name);
9474 errno = old_errno;
9475 #endif
9476 return result;
9477 }
9478 #endif /* HAVE_GETLOGIN */
9479
9480
9481 #ifdef HAVE_GETUID
9482 /*[clinic input]
9483 os.getuid
9484
9485 Return the current process's user id.
9486 [clinic start generated code]*/
9487
9488 static PyObject *
os_getuid_impl(PyObject * module)9489 os_getuid_impl(PyObject *module)
9490 /*[clinic end generated code: output=415c0b401ebed11a input=b53c8b35f110a516]*/
9491 {
9492 return _PyLong_FromUid(getuid());
9493 }
9494 #endif /* HAVE_GETUID */
9495
9496
9497 #ifdef MS_WINDOWS
9498 #define HAVE_KILL
9499 #endif /* MS_WINDOWS */
9500
9501 #ifdef HAVE_KILL
9502 /*[clinic input]
9503 os.kill
9504
9505 pid: pid_t
9506 signal: Py_ssize_t
9507 /
9508
9509 Kill a process with a signal.
9510 [clinic start generated code]*/
9511
9512 static PyObject *
os_kill_impl(PyObject * module,pid_t pid,Py_ssize_t signal)9513 os_kill_impl(PyObject *module, pid_t pid, Py_ssize_t signal)
9514 /*[clinic end generated code: output=8e346a6701c88568 input=61a36b86ca275ab9]*/
9515 {
9516 if (PySys_Audit("os.kill", "in", pid, signal) < 0) {
9517 return NULL;
9518 }
9519 #ifndef MS_WINDOWS
9520 if (kill(pid, (int)signal) == -1) {
9521 return posix_error();
9522 }
9523
9524 // Check immediately if the signal was sent to the current process.
9525 // Don't micro-optimize pid == getpid(), since PyErr_SetString() check
9526 // is cheap.
9527 if (PyErr_CheckSignals()) {
9528 return NULL;
9529 }
9530
9531 Py_RETURN_NONE;
9532 #else /* !MS_WINDOWS */
9533 PyObject *result;
9534 DWORD sig = (DWORD)signal;
9535 DWORD err;
9536 HANDLE handle;
9537
9538 #ifdef HAVE_WINDOWS_CONSOLE_IO
9539 /* Console processes which share a common console can be sent CTRL+C or
9540 CTRL+BREAK events, provided they handle said events. */
9541 if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) {
9542 if (GenerateConsoleCtrlEvent(sig, (DWORD)pid) == 0) {
9543 err = GetLastError();
9544 PyErr_SetFromWindowsErr(err);
9545 }
9546 else {
9547 Py_RETURN_NONE;
9548 }
9549 }
9550 #endif /* HAVE_WINDOWS_CONSOLE_IO */
9551
9552 /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
9553 attempt to open and terminate the process. */
9554 handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
9555 if (handle == NULL) {
9556 err = GetLastError();
9557 return PyErr_SetFromWindowsErr(err);
9558 }
9559
9560 if (TerminateProcess(handle, sig) == 0) {
9561 err = GetLastError();
9562 result = PyErr_SetFromWindowsErr(err);
9563 } else {
9564 result = Py_NewRef(Py_None);
9565 }
9566
9567 CloseHandle(handle);
9568 return result;
9569 #endif /* !MS_WINDOWS */
9570 }
9571 #endif /* HAVE_KILL */
9572
9573
9574 #ifdef HAVE_KILLPG
9575 /*[clinic input]
9576 os.killpg
9577
9578 pgid: pid_t
9579 signal: int
9580 /
9581
9582 Kill a process group with a signal.
9583 [clinic start generated code]*/
9584
9585 static PyObject *
os_killpg_impl(PyObject * module,pid_t pgid,int signal)9586 os_killpg_impl(PyObject *module, pid_t pgid, int signal)
9587 /*[clinic end generated code: output=6dbcd2f1fdf5fdba input=38b5449eb8faec19]*/
9588 {
9589 if (PySys_Audit("os.killpg", "ii", pgid, signal) < 0) {
9590 return NULL;
9591 }
9592 /* XXX some man pages make the `pgid` parameter an int, others
9593 a pid_t. Since getpgrp() returns a pid_t, we assume killpg should
9594 take the same type. Moreover, pid_t is always at least as wide as
9595 int (else compilation of this module fails), which is safe. */
9596 if (killpg(pgid, signal) == -1)
9597 return posix_error();
9598 Py_RETURN_NONE;
9599 }
9600 #endif /* HAVE_KILLPG */
9601
9602
9603 #ifdef HAVE_PLOCK
9604 #ifdef HAVE_SYS_LOCK_H
9605 #include <sys/lock.h>
9606 #endif
9607
9608 /*[clinic input]
9609 os.plock
9610 op: int
9611 /
9612
9613 Lock program segments into memory.");
9614 [clinic start generated code]*/
9615
9616 static PyObject *
os_plock_impl(PyObject * module,int op)9617 os_plock_impl(PyObject *module, int op)
9618 /*[clinic end generated code: output=81424167033b168e input=e6e5e348e1525f60]*/
9619 {
9620 if (plock(op) == -1)
9621 return posix_error();
9622 Py_RETURN_NONE;
9623 }
9624 #endif /* HAVE_PLOCK */
9625
9626
9627 #ifdef HAVE_SETUID
9628 /*[clinic input]
9629 os.setuid
9630
9631 uid: uid_t
9632 /
9633
9634 Set the current process's user id.
9635 [clinic start generated code]*/
9636
9637 static PyObject *
os_setuid_impl(PyObject * module,uid_t uid)9638 os_setuid_impl(PyObject *module, uid_t uid)
9639 /*[clinic end generated code: output=a0a41fd0d1ec555f input=c921a3285aa22256]*/
9640 {
9641 if (setuid(uid) < 0)
9642 return posix_error();
9643 Py_RETURN_NONE;
9644 }
9645 #endif /* HAVE_SETUID */
9646
9647
9648 #ifdef HAVE_SETEUID
9649 /*[clinic input]
9650 os.seteuid
9651
9652 euid: uid_t
9653 /
9654
9655 Set the current process's effective user id.
9656 [clinic start generated code]*/
9657
9658 static PyObject *
os_seteuid_impl(PyObject * module,uid_t euid)9659 os_seteuid_impl(PyObject *module, uid_t euid)
9660 /*[clinic end generated code: output=102e3ad98361519a input=ba93d927e4781aa9]*/
9661 {
9662 if (seteuid(euid) < 0)
9663 return posix_error();
9664 Py_RETURN_NONE;
9665 }
9666 #endif /* HAVE_SETEUID */
9667
9668
9669 #ifdef HAVE_SETEGID
9670 /*[clinic input]
9671 os.setegid
9672
9673 egid: gid_t
9674 /
9675
9676 Set the current process's effective group id.
9677 [clinic start generated code]*/
9678
9679 static PyObject *
os_setegid_impl(PyObject * module,gid_t egid)9680 os_setegid_impl(PyObject *module, gid_t egid)
9681 /*[clinic end generated code: output=4e4b825a6a10258d input=4080526d0ccd6ce3]*/
9682 {
9683 if (setegid(egid) < 0)
9684 return posix_error();
9685 Py_RETURN_NONE;
9686 }
9687 #endif /* HAVE_SETEGID */
9688
9689
9690 #ifdef HAVE_SETREUID
9691 /*[clinic input]
9692 os.setreuid
9693
9694 ruid: uid_t
9695 euid: uid_t
9696 /
9697
9698 Set the current process's real and effective user ids.
9699 [clinic start generated code]*/
9700
9701 static PyObject *
os_setreuid_impl(PyObject * module,uid_t ruid,uid_t euid)9702 os_setreuid_impl(PyObject *module, uid_t ruid, uid_t euid)
9703 /*[clinic end generated code: output=62d991210006530a input=0ca8978de663880c]*/
9704 {
9705 if (setreuid(ruid, euid) < 0) {
9706 return posix_error();
9707 } else {
9708 Py_RETURN_NONE;
9709 }
9710 }
9711 #endif /* HAVE_SETREUID */
9712
9713
9714 #ifdef HAVE_SETREGID
9715 /*[clinic input]
9716 os.setregid
9717
9718 rgid: gid_t
9719 egid: gid_t
9720 /
9721
9722 Set the current process's real and effective group ids.
9723 [clinic start generated code]*/
9724
9725 static PyObject *
os_setregid_impl(PyObject * module,gid_t rgid,gid_t egid)9726 os_setregid_impl(PyObject *module, gid_t rgid, gid_t egid)
9727 /*[clinic end generated code: output=aa803835cf5342f3 input=c59499f72846db78]*/
9728 {
9729 if (setregid(rgid, egid) < 0)
9730 return posix_error();
9731 Py_RETURN_NONE;
9732 }
9733 #endif /* HAVE_SETREGID */
9734
9735
9736 #ifdef HAVE_SETGID
9737 /*[clinic input]
9738 os.setgid
9739 gid: gid_t
9740 /
9741
9742 Set the current process's group id.
9743 [clinic start generated code]*/
9744
9745 static PyObject *
os_setgid_impl(PyObject * module,gid_t gid)9746 os_setgid_impl(PyObject *module, gid_t gid)
9747 /*[clinic end generated code: output=bdccd7403f6ad8c3 input=27d30c4059045dc6]*/
9748 {
9749 if (setgid(gid) < 0)
9750 return posix_error();
9751 Py_RETURN_NONE;
9752 }
9753 #endif /* HAVE_SETGID */
9754
9755
9756 #ifdef HAVE_SETGROUPS
9757 /*[clinic input]
9758 os.setgroups
9759
9760 groups: object
9761 /
9762
9763 Set the groups of the current process to list.
9764 [clinic start generated code]*/
9765
9766 static PyObject *
os_setgroups(PyObject * module,PyObject * groups)9767 os_setgroups(PyObject *module, PyObject *groups)
9768 /*[clinic end generated code: output=3fcb32aad58c5ecd input=fa742ca3daf85a7e]*/
9769 {
9770 if (!PySequence_Check(groups)) {
9771 PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence");
9772 return NULL;
9773 }
9774 Py_ssize_t len = PySequence_Size(groups);
9775 if (len < 0) {
9776 return NULL;
9777 }
9778 if (len > MAX_GROUPS) {
9779 PyErr_SetString(PyExc_ValueError, "too many groups");
9780 return NULL;
9781 }
9782
9783 gid_t *grouplist = PyMem_New(gid_t, len);
9784 if (grouplist == NULL) {
9785 PyErr_NoMemory();
9786 return NULL;
9787 }
9788 for (Py_ssize_t i = 0; i < len; i++) {
9789 PyObject *elem;
9790 elem = PySequence_GetItem(groups, i);
9791 if (!elem) {
9792 PyMem_Free(grouplist);
9793 return NULL;
9794 }
9795 if (!PyLong_Check(elem)) {
9796 PyErr_SetString(PyExc_TypeError,
9797 "groups must be integers");
9798 Py_DECREF(elem);
9799 PyMem_Free(grouplist);
9800 return NULL;
9801 } else {
9802 if (!_Py_Gid_Converter(elem, &grouplist[i])) {
9803 Py_DECREF(elem);
9804 PyMem_Free(grouplist);
9805 return NULL;
9806 }
9807 }
9808 Py_DECREF(elem);
9809 }
9810
9811 if (setgroups(len, grouplist) < 0) {
9812 posix_error();
9813 PyMem_Free(grouplist);
9814 return NULL;
9815 }
9816 PyMem_Free(grouplist);
9817 Py_RETURN_NONE;
9818 }
9819 #endif /* HAVE_SETGROUPS */
9820
9821 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
9822 static PyObject *
wait_helper(PyObject * module,pid_t pid,int status,struct rusage * ru)9823 wait_helper(PyObject *module, pid_t pid, int status, struct rusage *ru)
9824 {
9825 PyObject *result;
9826 PyObject *struct_rusage;
9827
9828 if (pid == -1)
9829 return posix_error();
9830
9831 // If wait succeeded but no child was ready to report status, ru will not
9832 // have been populated.
9833 if (pid == 0) {
9834 memset(ru, 0, sizeof(*ru));
9835 }
9836
9837 struct_rusage = _PyImport_GetModuleAttrString("resource", "struct_rusage");
9838 if (struct_rusage == NULL)
9839 return NULL;
9840
9841 /* XXX(nnorwitz): Copied (w/mods) from resource.c, there should be only one. */
9842 result = PyStructSequence_New((PyTypeObject*) struct_rusage);
9843 Py_DECREF(struct_rusage);
9844 if (!result)
9845 return NULL;
9846
9847 int pos = 0;
9848
9849 #ifndef doubletime
9850 #define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
9851 #endif
9852
9853 #define SET_RESULT(CALL) \
9854 do { \
9855 PyObject *item = (CALL); \
9856 if (item == NULL) { \
9857 Py_DECREF(result); \
9858 return NULL; \
9859 } \
9860 PyStructSequence_SET_ITEM(result, pos++, item); \
9861 } while(0)
9862
9863 SET_RESULT(PyFloat_FromDouble(doubletime(ru->ru_utime)));
9864 SET_RESULT(PyFloat_FromDouble(doubletime(ru->ru_stime)));
9865 SET_RESULT(PyLong_FromLong(ru->ru_maxrss));
9866 SET_RESULT(PyLong_FromLong(ru->ru_ixrss));
9867 SET_RESULT(PyLong_FromLong(ru->ru_idrss));
9868 SET_RESULT(PyLong_FromLong(ru->ru_isrss));
9869 SET_RESULT(PyLong_FromLong(ru->ru_minflt));
9870 SET_RESULT(PyLong_FromLong(ru->ru_majflt));
9871 SET_RESULT(PyLong_FromLong(ru->ru_nswap));
9872 SET_RESULT(PyLong_FromLong(ru->ru_inblock));
9873 SET_RESULT(PyLong_FromLong(ru->ru_oublock));
9874 SET_RESULT(PyLong_FromLong(ru->ru_msgsnd));
9875 SET_RESULT(PyLong_FromLong(ru->ru_msgrcv));
9876 SET_RESULT(PyLong_FromLong(ru->ru_nsignals));
9877 SET_RESULT(PyLong_FromLong(ru->ru_nvcsw));
9878 SET_RESULT(PyLong_FromLong(ru->ru_nivcsw));
9879 #undef SET_RESULT
9880
9881 return Py_BuildValue("NiN", PyLong_FromPid(pid), status, result);
9882 }
9883 #endif /* HAVE_WAIT3 || HAVE_WAIT4 */
9884
9885
9886 #ifdef HAVE_WAIT3
9887 /*[clinic input]
9888 os.wait3
9889
9890 options: int
9891 Wait for completion of a child process.
9892
9893 Returns a tuple of information about the child process:
9894 (pid, status, rusage)
9895 [clinic start generated code]*/
9896
9897 static PyObject *
os_wait3_impl(PyObject * module,int options)9898 os_wait3_impl(PyObject *module, int options)
9899 /*[clinic end generated code: output=92c3224e6f28217a input=8ac4c56956b61710]*/
9900 {
9901 pid_t pid;
9902 struct rusage ru;
9903 int async_err = 0;
9904 WAIT_TYPE status;
9905 WAIT_STATUS_INT(status) = 0;
9906
9907 do {
9908 Py_BEGIN_ALLOW_THREADS
9909 pid = wait3(&status, options, &ru);
9910 Py_END_ALLOW_THREADS
9911 } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9912 if (pid < 0)
9913 return (!async_err) ? posix_error() : NULL;
9914
9915 return wait_helper(module, pid, WAIT_STATUS_INT(status), &ru);
9916 }
9917 #endif /* HAVE_WAIT3 */
9918
9919
9920 #ifdef HAVE_WAIT4
9921 /*[clinic input]
9922
9923 os.wait4
9924
9925 pid: pid_t
9926 options: int
9927
9928 Wait for completion of a specific child process.
9929
9930 Returns a tuple of information about the child process:
9931 (pid, status, rusage)
9932 [clinic start generated code]*/
9933
9934 static PyObject *
os_wait4_impl(PyObject * module,pid_t pid,int options)9935 os_wait4_impl(PyObject *module, pid_t pid, int options)
9936 /*[clinic end generated code: output=66195aa507b35f70 input=d11deed0750600ba]*/
9937 {
9938 pid_t res;
9939 struct rusage ru;
9940 int async_err = 0;
9941 WAIT_TYPE status;
9942 WAIT_STATUS_INT(status) = 0;
9943
9944 do {
9945 Py_BEGIN_ALLOW_THREADS
9946 res = wait4(pid, &status, options, &ru);
9947 Py_END_ALLOW_THREADS
9948 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9949 if (res < 0)
9950 return (!async_err) ? posix_error() : NULL;
9951
9952 return wait_helper(module, res, WAIT_STATUS_INT(status), &ru);
9953 }
9954 #endif /* HAVE_WAIT4 */
9955
9956
9957 #if defined(HAVE_WAITID)
9958 /*[clinic input]
9959 os.waitid
9960
9961 idtype: idtype_t
9962 Must be one of be P_PID, P_PGID or P_ALL.
9963 id: id_t
9964 The id to wait on.
9965 options: int
9966 Constructed from the ORing of one or more of WEXITED, WSTOPPED
9967 or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.
9968 /
9969
9970 Returns the result of waiting for a process or processes.
9971
9972 Returns either waitid_result or None if WNOHANG is specified and there are
9973 no children in a waitable state.
9974 [clinic start generated code]*/
9975
9976 static PyObject *
os_waitid_impl(PyObject * module,idtype_t idtype,id_t id,int options)9977 os_waitid_impl(PyObject *module, idtype_t idtype, id_t id, int options)
9978 /*[clinic end generated code: output=5d2e1c0bde61f4d8 input=d8e7f76e052b7920]*/
9979 {
9980 PyObject *result;
9981 int res;
9982 int async_err = 0;
9983 siginfo_t si;
9984 si.si_pid = 0;
9985
9986 do {
9987 Py_BEGIN_ALLOW_THREADS
9988 res = waitid(idtype, id, &si, options);
9989 Py_END_ALLOW_THREADS
9990 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9991 if (res < 0)
9992 return (!async_err) ? posix_error() : NULL;
9993
9994 if (si.si_pid == 0)
9995 Py_RETURN_NONE;
9996
9997 PyObject *WaitidResultType = get_posix_state(module)->WaitidResultType;
9998 result = PyStructSequence_New((PyTypeObject *)WaitidResultType);
9999 if (!result)
10000 return NULL;
10001
10002 int pos = 0;
10003
10004 #define SET_RESULT(CALL) \
10005 do { \
10006 PyObject *item = (CALL); \
10007 if (item == NULL) { \
10008 Py_DECREF(result); \
10009 return NULL; \
10010 } \
10011 PyStructSequence_SET_ITEM(result, pos++, item); \
10012 } while(0)
10013
10014 SET_RESULT(PyLong_FromPid(si.si_pid));
10015 SET_RESULT(_PyLong_FromUid(si.si_uid));
10016 SET_RESULT(PyLong_FromLong((long)(si.si_signo)));
10017 SET_RESULT(PyLong_FromLong((long)(si.si_status)));
10018 SET_RESULT(PyLong_FromLong((long)(si.si_code)));
10019
10020 #undef SET_RESULT
10021
10022 return result;
10023 }
10024 #endif /* defined(HAVE_WAITID) */
10025
10026
10027 #if defined(HAVE_WAITPID)
10028 /*[clinic input]
10029 os.waitpid
10030 pid: pid_t
10031 options: int
10032 /
10033
10034 Wait for completion of a given child process.
10035
10036 Returns a tuple of information regarding the child process:
10037 (pid, status)
10038
10039 The options argument is ignored on Windows.
10040 [clinic start generated code]*/
10041
10042 static PyObject *
os_waitpid_impl(PyObject * module,pid_t pid,int options)10043 os_waitpid_impl(PyObject *module, pid_t pid, int options)
10044 /*[clinic end generated code: output=5c37c06887a20270 input=0bf1666b8758fda3]*/
10045 {
10046 pid_t res;
10047 int async_err = 0;
10048 WAIT_TYPE status;
10049 WAIT_STATUS_INT(status) = 0;
10050
10051 do {
10052 Py_BEGIN_ALLOW_THREADS
10053 res = waitpid(pid, &status, options);
10054 Py_END_ALLOW_THREADS
10055 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10056 if (res < 0)
10057 return (!async_err) ? posix_error() : NULL;
10058
10059 return Py_BuildValue("Ni", PyLong_FromPid(res), WAIT_STATUS_INT(status));
10060 }
10061 #elif defined(HAVE_CWAIT)
10062 /* MS C has a variant of waitpid() that's usable for most purposes. */
10063 /*[clinic input]
10064 os.waitpid
10065 pid: intptr_t
10066 options: int
10067 /
10068
10069 Wait for completion of a given process.
10070
10071 Returns a tuple of information regarding the process:
10072 (pid, status << 8)
10073
10074 The options argument is ignored on Windows.
10075 [clinic start generated code]*/
10076
10077 static PyObject *
os_waitpid_impl(PyObject * module,intptr_t pid,int options)10078 os_waitpid_impl(PyObject *module, intptr_t pid, int options)
10079 /*[clinic end generated code: output=be836b221271d538 input=40f2440c515410f8]*/
10080 {
10081 int status;
10082 intptr_t res;
10083 int async_err = 0;
10084
10085 do {
10086 Py_BEGIN_ALLOW_THREADS
10087 _Py_BEGIN_SUPPRESS_IPH
10088 res = _cwait(&status, pid, options);
10089 _Py_END_SUPPRESS_IPH
10090 Py_END_ALLOW_THREADS
10091 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10092 if (res < 0)
10093 return (!async_err) ? posix_error() : NULL;
10094
10095 unsigned long long ustatus = (unsigned int)status;
10096
10097 /* shift the status left a byte so this is more like the POSIX waitpid */
10098 return Py_BuildValue(_Py_PARSE_INTPTR "K", res, ustatus << 8);
10099 }
10100 #endif
10101
10102
10103 #ifdef HAVE_WAIT
10104 /*[clinic input]
10105 os.wait
10106
10107 Wait for completion of a child process.
10108
10109 Returns a tuple of information about the child process:
10110 (pid, status)
10111 [clinic start generated code]*/
10112
10113 static PyObject *
os_wait_impl(PyObject * module)10114 os_wait_impl(PyObject *module)
10115 /*[clinic end generated code: output=6bc419ac32fb364b input=03b0182d4a4700ce]*/
10116 {
10117 pid_t pid;
10118 int async_err = 0;
10119 WAIT_TYPE status;
10120 WAIT_STATUS_INT(status) = 0;
10121
10122 do {
10123 Py_BEGIN_ALLOW_THREADS
10124 pid = wait(&status);
10125 Py_END_ALLOW_THREADS
10126 } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10127 if (pid < 0)
10128 return (!async_err) ? posix_error() : NULL;
10129
10130 return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
10131 }
10132 #endif /* HAVE_WAIT */
10133
10134
10135 // This system call always crashes on older Android versions.
10136 #if defined(__linux__) && defined(__NR_pidfd_open) && \
10137 !(defined(__ANDROID__) && __ANDROID_API__ < 31)
10138 /*[clinic input]
10139 os.pidfd_open
10140 pid: pid_t
10141 flags: unsigned_int = 0
10142
10143 Return a file descriptor referring to the process *pid*.
10144
10145 The descriptor can be used to perform process management without races and
10146 signals.
10147 [clinic start generated code]*/
10148
10149 static PyObject *
os_pidfd_open_impl(PyObject * module,pid_t pid,unsigned int flags)10150 os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
10151 /*[clinic end generated code: output=5c7252698947dc41 input=c3fd99ce947ccfef]*/
10152 {
10153 int fd = syscall(__NR_pidfd_open, pid, flags);
10154 if (fd < 0) {
10155 return posix_error();
10156 }
10157 return PyLong_FromLong(fd);
10158 }
10159 #endif
10160
10161
10162 #ifdef HAVE_SETNS
10163 /*[clinic input]
10164 os.setns
10165 fd: fildes
10166 A file descriptor to a namespace.
10167 nstype: int = 0
10168 Type of namespace.
10169
10170 Move the calling thread into different namespaces.
10171 [clinic start generated code]*/
10172
10173 static PyObject *
os_setns_impl(PyObject * module,int fd,int nstype)10174 os_setns_impl(PyObject *module, int fd, int nstype)
10175 /*[clinic end generated code: output=5dbd055bfb66ecd0 input=42787871226bf3ee]*/
10176 {
10177 int res;
10178
10179 Py_BEGIN_ALLOW_THREADS
10180 res = setns(fd, nstype);
10181 Py_END_ALLOW_THREADS
10182
10183 if (res != 0) {
10184 return posix_error();
10185 }
10186
10187 Py_RETURN_NONE;
10188 }
10189 #endif
10190
10191
10192 #ifdef HAVE_UNSHARE
10193 /*[clinic input]
10194 os.unshare
10195 flags: int
10196 Namespaces to be unshared.
10197
10198 Disassociate parts of a process (or thread) execution context.
10199 [clinic start generated code]*/
10200
10201 static PyObject *
os_unshare_impl(PyObject * module,int flags)10202 os_unshare_impl(PyObject *module, int flags)
10203 /*[clinic end generated code: output=1b3177906dd237ee input=9e065db3232b8b1b]*/
10204 {
10205 int res;
10206
10207 Py_BEGIN_ALLOW_THREADS
10208 res = unshare(flags);
10209 Py_END_ALLOW_THREADS
10210
10211 if (res != 0) {
10212 return posix_error();
10213 }
10214
10215 Py_RETURN_NONE;
10216 }
10217 #endif
10218
10219
10220 #if defined(HAVE_READLINK) || defined(MS_WINDOWS)
10221 /*[clinic input]
10222 os.readlink
10223
10224 path: path_t
10225 *
10226 dir_fd: dir_fd(requires='readlinkat') = None
10227
10228 Return a string representing the path to which the symbolic link points.
10229
10230 If dir_fd is not None, it should be a file descriptor open to a directory,
10231 and path should be relative; path will then be relative to that directory.
10232
10233 dir_fd may not be implemented on your platform. If it is unavailable,
10234 using it will raise a NotImplementedError.
10235 [clinic start generated code]*/
10236
10237 static PyObject *
os_readlink_impl(PyObject * module,path_t * path,int dir_fd)10238 os_readlink_impl(PyObject *module, path_t *path, int dir_fd)
10239 /*[clinic end generated code: output=d21b732a2e814030 input=113c87e0db1ecaf2]*/
10240 {
10241 #if defined(HAVE_READLINK)
10242 char buffer[MAXPATHLEN+1];
10243 ssize_t length;
10244 #ifdef HAVE_READLINKAT
10245 int readlinkat_unavailable = 0;
10246 #endif
10247
10248 Py_BEGIN_ALLOW_THREADS
10249 #ifdef HAVE_READLINKAT
10250 if (dir_fd != DEFAULT_DIR_FD) {
10251 if (HAVE_READLINKAT_RUNTIME) {
10252 length = readlinkat(dir_fd, path->narrow, buffer, MAXPATHLEN);
10253 } else {
10254 readlinkat_unavailable = 1;
10255 }
10256 } else
10257 #endif
10258 length = readlink(path->narrow, buffer, MAXPATHLEN);
10259 Py_END_ALLOW_THREADS
10260
10261 #ifdef HAVE_READLINKAT
10262 if (readlinkat_unavailable) {
10263 argument_unavailable_error(NULL, "dir_fd");
10264 return NULL;
10265 }
10266 #endif
10267
10268 if (length < 0) {
10269 return path_error(path);
10270 }
10271 buffer[length] = '\0';
10272
10273 if (PyUnicode_Check(path->object))
10274 return PyUnicode_DecodeFSDefaultAndSize(buffer, length);
10275 else
10276 return PyBytes_FromStringAndSize(buffer, length);
10277 #elif defined(MS_WINDOWS)
10278 DWORD n_bytes_returned;
10279 DWORD io_result = 0;
10280 HANDLE reparse_point_handle;
10281 char target_buffer[_Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
10282 _Py_REPARSE_DATA_BUFFER *rdb = (_Py_REPARSE_DATA_BUFFER *)target_buffer;
10283 PyObject *result = NULL;
10284
10285 /* First get a handle to the reparse point */
10286 Py_BEGIN_ALLOW_THREADS
10287 reparse_point_handle = CreateFileW(
10288 path->wide,
10289 0,
10290 0,
10291 0,
10292 OPEN_EXISTING,
10293 FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
10294 0);
10295 if (reparse_point_handle != INVALID_HANDLE_VALUE) {
10296 /* New call DeviceIoControl to read the reparse point */
10297 io_result = DeviceIoControl(
10298 reparse_point_handle,
10299 FSCTL_GET_REPARSE_POINT,
10300 0, 0, /* in buffer */
10301 target_buffer, sizeof(target_buffer),
10302 &n_bytes_returned,
10303 0 /* we're not using OVERLAPPED_IO */
10304 );
10305 CloseHandle(reparse_point_handle);
10306 }
10307 Py_END_ALLOW_THREADS
10308
10309 if (io_result == 0) {
10310 return path_error(path);
10311 }
10312
10313 wchar_t *name = NULL;
10314 Py_ssize_t nameLen = 0;
10315 if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK)
10316 {
10317 name = (wchar_t *)((char*)rdb->SymbolicLinkReparseBuffer.PathBuffer +
10318 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset);
10319 nameLen = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
10320 }
10321 else if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
10322 {
10323 name = (wchar_t *)((char*)rdb->MountPointReparseBuffer.PathBuffer +
10324 rdb->MountPointReparseBuffer.SubstituteNameOffset);
10325 nameLen = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
10326 }
10327 else
10328 {
10329 PyErr_SetString(PyExc_ValueError, "not a symbolic link");
10330 }
10331 if (name) {
10332 if (nameLen > 4 && wcsncmp(name, L"\\??\\", 4) == 0) {
10333 /* Our buffer is mutable, so this is okay */
10334 name[1] = L'\\';
10335 }
10336 result = PyUnicode_FromWideChar(name, nameLen);
10337 if (result && PyBytes_Check(path->object)) {
10338 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
10339 }
10340 }
10341 return result;
10342 #endif
10343 }
10344 #endif /* defined(HAVE_READLINK) || defined(MS_WINDOWS) */
10345
10346 #if defined(MS_WINDOWS)
10347
10348 /* Remove the last portion of the path - return 0 on success */
10349 static int
_dirnameW(WCHAR * path)10350 _dirnameW(WCHAR *path)
10351 {
10352 WCHAR *ptr;
10353 size_t length = wcsnlen_s(path, MAX_PATH);
10354 if (length == MAX_PATH) {
10355 return -1;
10356 }
10357
10358 /* walk the path from the end until a backslash is encountered */
10359 for(ptr = path + length; ptr != path; ptr--) {
10360 if (*ptr == L'\\' || *ptr == L'/') {
10361 break;
10362 }
10363 }
10364 *ptr = 0;
10365 return 0;
10366 }
10367
10368 #endif
10369
10370 #ifdef HAVE_SYMLINK
10371
10372 #if defined(MS_WINDOWS)
10373
10374 /* Is this path absolute? */
10375 static int
_is_absW(const WCHAR * path)10376 _is_absW(const WCHAR *path)
10377 {
10378 return path[0] == L'\\' || path[0] == L'/' ||
10379 (path[0] && path[1] == L':');
10380 }
10381
10382 /* join root and rest with a backslash - return 0 on success */
10383 static int
_joinW(WCHAR * dest_path,const WCHAR * root,const WCHAR * rest)10384 _joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest)
10385 {
10386 if (_is_absW(rest)) {
10387 return wcscpy_s(dest_path, MAX_PATH, rest);
10388 }
10389
10390 if (wcscpy_s(dest_path, MAX_PATH, root)) {
10391 return -1;
10392 }
10393
10394 if (dest_path[0] && wcscat_s(dest_path, MAX_PATH, L"\\")) {
10395 return -1;
10396 }
10397
10398 return wcscat_s(dest_path, MAX_PATH, rest);
10399 }
10400
10401 /* Return True if the path at src relative to dest is a directory */
10402 static int
_check_dirW(LPCWSTR src,LPCWSTR dest)10403 _check_dirW(LPCWSTR src, LPCWSTR dest)
10404 {
10405 WIN32_FILE_ATTRIBUTE_DATA src_info;
10406 WCHAR dest_parent[MAX_PATH];
10407 WCHAR src_resolved[MAX_PATH] = L"";
10408
10409 /* dest_parent = os.path.dirname(dest) */
10410 if (wcscpy_s(dest_parent, MAX_PATH, dest) ||
10411 _dirnameW(dest_parent)) {
10412 return 0;
10413 }
10414 /* src_resolved = os.path.join(dest_parent, src) */
10415 if (_joinW(src_resolved, dest_parent, src)) {
10416 return 0;
10417 }
10418 return (
10419 GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info)
10420 && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
10421 );
10422 }
10423 #endif
10424
10425
10426 /*[clinic input]
10427 os.symlink
10428 src: path_t
10429 dst: path_t
10430 target_is_directory: bool = False
10431 *
10432 dir_fd: dir_fd(requires='symlinkat')=None
10433
10434 # "symlink(src, dst, target_is_directory=False, *, dir_fd=None)\n\n\
10435
10436 Create a symbolic link pointing to src named dst.
10437
10438 target_is_directory is required on Windows if the target is to be
10439 interpreted as a directory. (On Windows, symlink requires
10440 Windows 6.0 or greater, and raises a NotImplementedError otherwise.)
10441 target_is_directory is ignored on non-Windows platforms.
10442
10443 If dir_fd is not None, it should be a file descriptor open to a directory,
10444 and path should be relative; path will then be relative to that directory.
10445 dir_fd may not be implemented on your platform.
10446 If it is unavailable, using it will raise a NotImplementedError.
10447
10448 [clinic start generated code]*/
10449
10450 static PyObject *
os_symlink_impl(PyObject * module,path_t * src,path_t * dst,int target_is_directory,int dir_fd)10451 os_symlink_impl(PyObject *module, path_t *src, path_t *dst,
10452 int target_is_directory, int dir_fd)
10453 /*[clinic end generated code: output=08ca9f3f3cf960f6 input=e820ec4472547bc3]*/
10454 {
10455 #ifdef MS_WINDOWS
10456 DWORD result;
10457 DWORD flags = 0;
10458
10459 /* Assumed true, set to false if detected to not be available. */
10460 static int windows_has_symlink_unprivileged_flag = TRUE;
10461 #else
10462 int result;
10463 #ifdef HAVE_SYMLINKAT
10464 int symlinkat_unavailable = 0;
10465 #endif
10466 #endif
10467
10468 if (PySys_Audit("os.symlink", "OOi", src->object, dst->object,
10469 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
10470 return NULL;
10471 }
10472
10473 #ifdef MS_WINDOWS
10474
10475 if (windows_has_symlink_unprivileged_flag) {
10476 /* Allow non-admin symlinks if system allows it. */
10477 flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
10478 }
10479
10480 Py_BEGIN_ALLOW_THREADS
10481 _Py_BEGIN_SUPPRESS_IPH
10482 /* if src is a directory, ensure flags==1 (target_is_directory bit) */
10483 if (target_is_directory || _check_dirW(src->wide, dst->wide)) {
10484 flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
10485 }
10486
10487 result = CreateSymbolicLinkW(dst->wide, src->wide, flags);
10488 _Py_END_SUPPRESS_IPH
10489 Py_END_ALLOW_THREADS
10490
10491 if (windows_has_symlink_unprivileged_flag && !result &&
10492 ERROR_INVALID_PARAMETER == GetLastError()) {
10493
10494 Py_BEGIN_ALLOW_THREADS
10495 _Py_BEGIN_SUPPRESS_IPH
10496 /* This error might be caused by
10497 SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE not being supported.
10498 Try again, and update windows_has_symlink_unprivileged_flag if we
10499 are successful this time.
10500
10501 NOTE: There is a risk of a race condition here if there are other
10502 conditions than the flag causing ERROR_INVALID_PARAMETER, and
10503 another process (or thread) changes that condition in between our
10504 calls to CreateSymbolicLink.
10505 */
10506 flags &= ~(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE);
10507 result = CreateSymbolicLinkW(dst->wide, src->wide, flags);
10508 _Py_END_SUPPRESS_IPH
10509 Py_END_ALLOW_THREADS
10510
10511 if (result || ERROR_INVALID_PARAMETER != GetLastError()) {
10512 windows_has_symlink_unprivileged_flag = FALSE;
10513 }
10514 }
10515
10516 if (!result)
10517 return path_error2(src, dst);
10518
10519 #else
10520
10521 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
10522 PyErr_SetString(PyExc_ValueError,
10523 "symlink: src and dst must be the same type");
10524 return NULL;
10525 }
10526
10527 Py_BEGIN_ALLOW_THREADS
10528 #ifdef HAVE_SYMLINKAT
10529 if (dir_fd != DEFAULT_DIR_FD) {
10530 if (HAVE_SYMLINKAT_RUNTIME) {
10531 result = symlinkat(src->narrow, dir_fd, dst->narrow);
10532 } else {
10533 symlinkat_unavailable = 1;
10534 }
10535 } else
10536 #endif
10537 result = symlink(src->narrow, dst->narrow);
10538 Py_END_ALLOW_THREADS
10539
10540 #ifdef HAVE_SYMLINKAT
10541 if (symlinkat_unavailable) {
10542 argument_unavailable_error(NULL, "dir_fd");
10543 return NULL;
10544 }
10545 #endif
10546
10547 if (result)
10548 return path_error2(src, dst);
10549 #endif
10550
10551 Py_RETURN_NONE;
10552 }
10553 #endif /* HAVE_SYMLINK */
10554
10555
10556 static PyStructSequence_Field times_result_fields[] = {
10557 {"user", "user time"},
10558 {"system", "system time"},
10559 {"children_user", "user time of children"},
10560 {"children_system", "system time of children"},
10561 {"elapsed", "elapsed time since an arbitrary point in the past"},
10562 {NULL}
10563 };
10564
10565 PyDoc_STRVAR(times_result__doc__,
10566 "times_result: Result from os.times().\n\n\
10567 This object may be accessed either as a tuple of\n\
10568 (user, system, children_user, children_system, elapsed),\n\
10569 or via the attributes user, system, children_user, children_system,\n\
10570 and elapsed.\n\
10571 \n\
10572 See os.times for more information.");
10573
10574 static PyStructSequence_Desc times_result_desc = {
10575 "times_result", /* name */
10576 times_result__doc__, /* doc */
10577 times_result_fields,
10578 5
10579 };
10580
10581 static PyObject *
build_times_result(PyObject * module,double user,double system,double children_user,double children_system,double elapsed)10582 build_times_result(PyObject *module, double user, double system,
10583 double children_user, double children_system,
10584 double elapsed)
10585 {
10586 PyObject *TimesResultType = get_posix_state(module)->TimesResultType;
10587 PyObject *value = PyStructSequence_New((PyTypeObject *)TimesResultType);
10588 if (value == NULL)
10589 return NULL;
10590
10591 #define SET(i, field) \
10592 { \
10593 PyObject *o = PyFloat_FromDouble(field); \
10594 if (!o) { \
10595 Py_DECREF(value); \
10596 return NULL; \
10597 } \
10598 PyStructSequence_SET_ITEM(value, i, o); \
10599 } \
10600
10601 SET(0, user);
10602 SET(1, system);
10603 SET(2, children_user);
10604 SET(3, children_system);
10605 SET(4, elapsed);
10606
10607 #undef SET
10608
10609 return value;
10610 }
10611
10612
10613 /*[clinic input]
10614 os.times
10615
10616 Return a collection containing process timing information.
10617
10618 The object returned behaves like a named tuple with these fields:
10619 (utime, stime, cutime, cstime, elapsed_time)
10620 All fields are floating-point numbers.
10621 [clinic start generated code]*/
10622
10623 static PyObject *
os_times_impl(PyObject * module)10624 os_times_impl(PyObject *module)
10625 /*[clinic end generated code: output=35f640503557d32a input=8dbfe33a2dcc3df3]*/
10626 {
10627 #ifdef MS_WINDOWS
10628 FILETIME create, exit, kernel, user;
10629 HANDLE hProc;
10630 hProc = GetCurrentProcess();
10631 GetProcessTimes(hProc, &create, &exit, &kernel, &user);
10632 /* The fields of a FILETIME structure are the hi and lo part
10633 of a 64-bit value expressed in 100 nanosecond units.
10634 1e7 is one second in such units; 1e-7 the inverse.
10635 429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
10636 */
10637 return build_times_result(module,
10638 (double)(user.dwHighDateTime*429.4967296 +
10639 user.dwLowDateTime*1e-7),
10640 (double)(kernel.dwHighDateTime*429.4967296 +
10641 kernel.dwLowDateTime*1e-7),
10642 (double)0,
10643 (double)0,
10644 (double)0);
10645 #else /* MS_WINDOWS */
10646 _posixstate *state = get_posix_state(module);
10647 long ticks_per_second = state->ticks_per_second;
10648
10649 struct tms process;
10650 clock_t elapsed;
10651 errno = 0;
10652 elapsed = times(&process);
10653 if (elapsed == (clock_t) -1) {
10654 return posix_error();
10655 }
10656
10657 return build_times_result(module,
10658 (double)process.tms_utime / ticks_per_second,
10659 (double)process.tms_stime / ticks_per_second,
10660 (double)process.tms_cutime / ticks_per_second,
10661 (double)process.tms_cstime / ticks_per_second,
10662 (double)elapsed / ticks_per_second);
10663 #endif /* MS_WINDOWS */
10664 }
10665
10666
10667 #if defined(HAVE_TIMERFD_CREATE)
10668 #define ONE_SECOND_IN_NS (1000 * 1000 * 1000)
10669 #define EXTRACT_NSEC(value) (long)( ( (double)(value) - (time_t)(value) ) * 1e9)
10670 #define CONVERT_SEC_AND_NSEC_TO_DOUBLE(sec, nsec) ( (double)(sec) + (double)(nsec) * 1e-9 )
10671
10672 static PyObject *
build_itimerspec(const struct itimerspec * curr_value)10673 build_itimerspec(const struct itimerspec* curr_value)
10674 {
10675 double _value = CONVERT_SEC_AND_NSEC_TO_DOUBLE(curr_value->it_value.tv_sec,
10676 curr_value->it_value.tv_nsec);
10677 PyObject *value = PyFloat_FromDouble(_value);
10678 if (value == NULL) {
10679 return NULL;
10680 }
10681 double _interval = CONVERT_SEC_AND_NSEC_TO_DOUBLE(curr_value->it_interval.tv_sec,
10682 curr_value->it_interval.tv_nsec);
10683 PyObject *interval = PyFloat_FromDouble(_interval);
10684 if (interval == NULL) {
10685 Py_DECREF(value);
10686 return NULL;
10687 }
10688 PyObject *tuple = PyTuple_Pack(2, value, interval);
10689 Py_DECREF(interval);
10690 Py_DECREF(value);
10691 return tuple;
10692 }
10693
10694 static PyObject *
build_itimerspec_ns(const struct itimerspec * curr_value)10695 build_itimerspec_ns(const struct itimerspec* curr_value)
10696 {
10697 PyTime_t value, interval;
10698 if (_PyTime_FromTimespec(&value, &curr_value->it_value) < 0) {
10699 return NULL;
10700 }
10701 if (_PyTime_FromTimespec(&interval, &curr_value->it_interval) < 0) {
10702 return NULL;
10703 }
10704 return Py_BuildValue("LL", value, interval);
10705 }
10706
10707 /*[clinic input]
10708 os.timerfd_create
10709
10710 clockid: int
10711 A valid clock ID constant as timer file descriptor.
10712
10713 time.CLOCK_REALTIME
10714 time.CLOCK_MONOTONIC
10715 time.CLOCK_BOOTTIME
10716 /
10717 *
10718 flags: int = 0
10719 0 or a bit mask of os.TFD_NONBLOCK or os.TFD_CLOEXEC.
10720
10721 os.TFD_NONBLOCK
10722 If *TFD_NONBLOCK* is set as a flag, read doesn't blocks.
10723 If *TFD_NONBLOCK* is not set as a flag, read block until the timer fires.
10724
10725 os.TFD_CLOEXEC
10726 If *TFD_CLOEXEC* is set as a flag, enable the close-on-exec flag
10727
10728 Create and return a timer file descriptor.
10729 [clinic start generated code]*/
10730
10731 static PyObject *
os_timerfd_create_impl(PyObject * module,int clockid,int flags)10732 os_timerfd_create_impl(PyObject *module, int clockid, int flags)
10733 /*[clinic end generated code: output=1caae80fb168004a input=64b7020c5ac0b8f4]*/
10734
10735 {
10736 int fd;
10737 Py_BEGIN_ALLOW_THREADS
10738 flags |= TFD_CLOEXEC; // PEP 446: always create non-inheritable FD
10739 fd = timerfd_create(clockid, flags);
10740 Py_END_ALLOW_THREADS
10741 if (fd == -1) {
10742 return PyErr_SetFromErrno(PyExc_OSError);
10743 }
10744 return PyLong_FromLong(fd);
10745 }
10746
10747 /*[clinic input]
10748 os.timerfd_settime
10749
10750 fd: fildes
10751 A timer file descriptor.
10752 /
10753 *
10754 flags: int = 0
10755 0 or a bit mask of TFD_TIMER_ABSTIME or TFD_TIMER_CANCEL_ON_SET.
10756 initial as initial_double: double = 0.0
10757 The initial expiration time, in seconds.
10758 interval as interval_double: double = 0.0
10759 The timer's interval, in seconds.
10760
10761 Alter a timer file descriptor's internal timer in seconds.
10762 [clinic start generated code]*/
10763
10764 static PyObject *
os_timerfd_settime_impl(PyObject * module,int fd,int flags,double initial_double,double interval_double)10765 os_timerfd_settime_impl(PyObject *module, int fd, int flags,
10766 double initial_double, double interval_double)
10767 /*[clinic end generated code: output=df4c1bce6859224e input=81d2c0d7e936e8a7]*/
10768 {
10769 PyTime_t initial, interval;
10770 if (_PyTime_FromSecondsDouble(initial_double, _PyTime_ROUND_FLOOR,
10771 &initial) < 0) {
10772 return NULL;
10773 }
10774 if (_PyTime_FromSecondsDouble(interval_double, _PyTime_ROUND_FLOOR,
10775 &interval) < 0) {
10776 return NULL;
10777 }
10778
10779 struct itimerspec new_value, old_value;
10780 if (_PyTime_AsTimespec(initial, &new_value.it_value) < 0) {
10781 PyErr_SetString(PyExc_ValueError, "invalid initial value");
10782 return NULL;
10783 }
10784 if (_PyTime_AsTimespec(interval, &new_value.it_interval) < 0) {
10785 PyErr_SetString(PyExc_ValueError, "invalid interval value");
10786 return NULL;
10787 }
10788
10789 int result;
10790 Py_BEGIN_ALLOW_THREADS
10791 result = timerfd_settime(fd, flags, &new_value, &old_value);
10792 Py_END_ALLOW_THREADS
10793 if (result == -1) {
10794 return PyErr_SetFromErrno(PyExc_OSError);
10795 }
10796 return build_itimerspec(&old_value);
10797 }
10798
10799
10800 /*[clinic input]
10801 os.timerfd_settime_ns
10802
10803 fd: fildes
10804 A timer file descriptor.
10805 /
10806 *
10807 flags: int = 0
10808 0 or a bit mask of TFD_TIMER_ABSTIME or TFD_TIMER_CANCEL_ON_SET.
10809 initial: long_long = 0
10810 initial expiration timing in seconds.
10811 interval: long_long = 0
10812 interval for the timer in seconds.
10813
10814 Alter a timer file descriptor's internal timer in nanoseconds.
10815 [clinic start generated code]*/
10816
10817 static PyObject *
os_timerfd_settime_ns_impl(PyObject * module,int fd,int flags,long long initial,long long interval)10818 os_timerfd_settime_ns_impl(PyObject *module, int fd, int flags,
10819 long long initial, long long interval)
10820 /*[clinic end generated code: output=6273ec7d7b4cc0b3 input=261e105d6e42f5bc]*/
10821 {
10822 struct itimerspec new_value;
10823 struct itimerspec old_value;
10824 int result;
10825 if (_PyTime_AsTimespec(initial, &new_value.it_value) < 0) {
10826 PyErr_SetString(PyExc_ValueError, "invalid initial value");
10827 return NULL;
10828 }
10829 if (_PyTime_AsTimespec(interval, &new_value.it_interval) < 0) {
10830 PyErr_SetString(PyExc_ValueError, "invalid interval value");
10831 return NULL;
10832 }
10833 Py_BEGIN_ALLOW_THREADS
10834 result = timerfd_settime(fd, flags, &new_value, &old_value);
10835 Py_END_ALLOW_THREADS
10836 if (result == -1) {
10837 return PyErr_SetFromErrno(PyExc_OSError);
10838 }
10839 return build_itimerspec_ns(&old_value);
10840 }
10841
10842 /*[clinic input]
10843 os.timerfd_gettime
10844
10845 fd: fildes
10846 A timer file descriptor.
10847 /
10848
10849 Return a tuple of a timer file descriptor's (interval, next expiration) in float seconds.
10850 [clinic start generated code]*/
10851
10852 static PyObject *
os_timerfd_gettime_impl(PyObject * module,int fd)10853 os_timerfd_gettime_impl(PyObject *module, int fd)
10854 /*[clinic end generated code: output=ec5a94a66cfe6ab4 input=8148e3430870da1c]*/
10855 {
10856 struct itimerspec curr_value;
10857 int result;
10858 Py_BEGIN_ALLOW_THREADS
10859 result = timerfd_gettime(fd, &curr_value);
10860 Py_END_ALLOW_THREADS
10861 if (result == -1) {
10862 return PyErr_SetFromErrno(PyExc_OSError);
10863 }
10864 return build_itimerspec(&curr_value);
10865 }
10866
10867
10868 /*[clinic input]
10869 os.timerfd_gettime_ns
10870
10871 fd: fildes
10872 A timer file descriptor.
10873 /
10874
10875 Return a tuple of a timer file descriptor's (interval, next expiration) in nanoseconds.
10876 [clinic start generated code]*/
10877
10878 static PyObject *
os_timerfd_gettime_ns_impl(PyObject * module,int fd)10879 os_timerfd_gettime_ns_impl(PyObject *module, int fd)
10880 /*[clinic end generated code: output=580633a4465f39fe input=a825443e4c6b40ac]*/
10881 {
10882 struct itimerspec curr_value;
10883 int result;
10884 Py_BEGIN_ALLOW_THREADS
10885 result = timerfd_gettime(fd, &curr_value);
10886 Py_END_ALLOW_THREADS
10887 if (result == -1) {
10888 return PyErr_SetFromErrno(PyExc_OSError);
10889 }
10890 return build_itimerspec_ns(&curr_value);
10891 }
10892
10893 #undef ONE_SECOND_IN_NS
10894 #undef EXTRACT_NSEC
10895
10896 #endif /* HAVE_TIMERFD_CREATE */
10897
10898 #ifdef HAVE_GETSID
10899 /*[clinic input]
10900 os.getsid
10901
10902 pid: pid_t
10903 /
10904
10905 Call the system call getsid(pid) and return the result.
10906 [clinic start generated code]*/
10907
10908 static PyObject *
os_getsid_impl(PyObject * module,pid_t pid)10909 os_getsid_impl(PyObject *module, pid_t pid)
10910 /*[clinic end generated code: output=112deae56b306460 input=eeb2b923a30ce04e]*/
10911 {
10912 int sid;
10913 sid = getsid(pid);
10914 if (sid < 0)
10915 return posix_error();
10916 return PyLong_FromLong((long)sid);
10917 }
10918 #endif /* HAVE_GETSID */
10919
10920
10921 #ifdef HAVE_SETSID
10922 /*[clinic input]
10923 os.setsid
10924
10925 Call the system call setsid().
10926 [clinic start generated code]*/
10927
10928 static PyObject *
os_setsid_impl(PyObject * module)10929 os_setsid_impl(PyObject *module)
10930 /*[clinic end generated code: output=e2ddedd517086d77 input=5fff45858e2f0776]*/
10931 {
10932 if (setsid() < 0)
10933 return posix_error();
10934 Py_RETURN_NONE;
10935 }
10936 #endif /* HAVE_SETSID */
10937
10938
10939 #ifdef HAVE_SETPGID
10940 /*[clinic input]
10941 os.setpgid
10942
10943 pid: pid_t
10944 pgrp: pid_t
10945 /
10946
10947 Call the system call setpgid(pid, pgrp).
10948 [clinic start generated code]*/
10949
10950 static PyObject *
os_setpgid_impl(PyObject * module,pid_t pid,pid_t pgrp)10951 os_setpgid_impl(PyObject *module, pid_t pid, pid_t pgrp)
10952 /*[clinic end generated code: output=6461160319a43d6a input=fceb395eca572e1a]*/
10953 {
10954 if (setpgid(pid, pgrp) < 0)
10955 return posix_error();
10956 Py_RETURN_NONE;
10957 }
10958 #endif /* HAVE_SETPGID */
10959
10960
10961 #ifdef HAVE_TCGETPGRP
10962 /*[clinic input]
10963 os.tcgetpgrp
10964
10965 fd: int
10966 /
10967
10968 Return the process group associated with the terminal specified by fd.
10969 [clinic start generated code]*/
10970
10971 static PyObject *
os_tcgetpgrp_impl(PyObject * module,int fd)10972 os_tcgetpgrp_impl(PyObject *module, int fd)
10973 /*[clinic end generated code: output=f865e88be86c272b input=7f6c18eac10ada86]*/
10974 {
10975 pid_t pgid = tcgetpgrp(fd);
10976 if (pgid < 0)
10977 return posix_error();
10978 return PyLong_FromPid(pgid);
10979 }
10980 #endif /* HAVE_TCGETPGRP */
10981
10982
10983 #ifdef HAVE_TCSETPGRP
10984 /*[clinic input]
10985 os.tcsetpgrp
10986
10987 fd: int
10988 pgid: pid_t
10989 /
10990
10991 Set the process group associated with the terminal specified by fd.
10992 [clinic start generated code]*/
10993
10994 static PyObject *
os_tcsetpgrp_impl(PyObject * module,int fd,pid_t pgid)10995 os_tcsetpgrp_impl(PyObject *module, int fd, pid_t pgid)
10996 /*[clinic end generated code: output=f1821a381b9daa39 input=5bdc997c6a619020]*/
10997 {
10998 if (tcsetpgrp(fd, pgid) < 0)
10999 return posix_error();
11000 Py_RETURN_NONE;
11001 }
11002 #endif /* HAVE_TCSETPGRP */
11003
11004 /* Functions acting on file descriptors */
11005
11006 #ifdef O_CLOEXEC
11007 extern int _Py_open_cloexec_works;
11008 #endif
11009
11010
11011 /*[clinic input]
11012 os.open -> int
11013 path: path_t
11014 flags: int
11015 mode: int = 0o777
11016 *
11017 dir_fd: dir_fd(requires='openat') = None
11018
11019 # "open(path, flags, mode=0o777, *, dir_fd=None)\n\n\
11020
11021 Open a file for low level IO. Returns a file descriptor (integer).
11022
11023 If dir_fd is not None, it should be a file descriptor open to a directory,
11024 and path should be relative; path will then be relative to that directory.
11025 dir_fd may not be implemented on your platform.
11026 If it is unavailable, using it will raise a NotImplementedError.
11027 [clinic start generated code]*/
11028
11029 static int
os_open_impl(PyObject * module,path_t * path,int flags,int mode,int dir_fd)11030 os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd)
11031 /*[clinic end generated code: output=abc7227888c8bc73 input=ad8623b29acd2934]*/
11032 {
11033 int fd;
11034 int async_err = 0;
11035 #ifdef HAVE_OPENAT
11036 int openat_unavailable = 0;
11037 #endif
11038
11039 #ifdef O_CLOEXEC
11040 int *atomic_flag_works = &_Py_open_cloexec_works;
11041 #elif !defined(MS_WINDOWS)
11042 int *atomic_flag_works = NULL;
11043 #endif
11044
11045 #ifdef MS_WINDOWS
11046 flags |= O_NOINHERIT;
11047 #elif defined(O_CLOEXEC)
11048 flags |= O_CLOEXEC;
11049 #endif
11050
11051 if (PySys_Audit("open", "OOi", path->object, Py_None, flags) < 0) {
11052 return -1;
11053 }
11054
11055 _Py_BEGIN_SUPPRESS_IPH
11056 do {
11057 Py_BEGIN_ALLOW_THREADS
11058 #ifdef MS_WINDOWS
11059 fd = _wopen(path->wide, flags, mode);
11060 #else
11061 #ifdef HAVE_OPENAT
11062 if (dir_fd != DEFAULT_DIR_FD) {
11063 if (HAVE_OPENAT_RUNTIME) {
11064 fd = openat(dir_fd, path->narrow, flags, mode);
11065
11066 } else {
11067 openat_unavailable = 1;
11068 fd = -1;
11069 }
11070 } else
11071 #endif /* HAVE_OPENAT */
11072 fd = open(path->narrow, flags, mode);
11073 #endif /* !MS_WINDOWS */
11074 Py_END_ALLOW_THREADS
11075 } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11076 _Py_END_SUPPRESS_IPH
11077
11078 #ifdef HAVE_OPENAT
11079 if (openat_unavailable) {
11080 argument_unavailable_error(NULL, "dir_fd");
11081 return -1;
11082 }
11083 #endif
11084
11085 if (fd < 0) {
11086 if (!async_err)
11087 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
11088 return -1;
11089 }
11090
11091 #ifndef MS_WINDOWS
11092 if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
11093 close(fd);
11094 return -1;
11095 }
11096 #endif
11097
11098 return fd;
11099 }
11100
11101
11102 /*[clinic input]
11103 os.close
11104
11105 fd: int
11106
11107 Close a file descriptor.
11108 [clinic start generated code]*/
11109
11110 static PyObject *
os_close_impl(PyObject * module,int fd)11111 os_close_impl(PyObject *module, int fd)
11112 /*[clinic end generated code: output=2fe4e93602822c14 input=2bc42451ca5c3223]*/
11113 {
11114 int res;
11115 /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
11116 * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
11117 * for more details.
11118 */
11119 Py_BEGIN_ALLOW_THREADS
11120 _Py_BEGIN_SUPPRESS_IPH
11121 res = close(fd);
11122 _Py_END_SUPPRESS_IPH
11123 Py_END_ALLOW_THREADS
11124 if (res < 0)
11125 return posix_error();
11126 Py_RETURN_NONE;
11127 }
11128
11129 /*[clinic input]
11130 os.closerange
11131
11132 fd_low: int
11133 fd_high: int
11134 /
11135
11136 Closes all file descriptors in [fd_low, fd_high), ignoring errors.
11137 [clinic start generated code]*/
11138
11139 static PyObject *
os_closerange_impl(PyObject * module,int fd_low,int fd_high)11140 os_closerange_impl(PyObject *module, int fd_low, int fd_high)
11141 /*[clinic end generated code: output=0ce5c20fcda681c2 input=5855a3d053ebd4ec]*/
11142 {
11143 Py_BEGIN_ALLOW_THREADS
11144 _Py_closerange(fd_low, fd_high - 1);
11145 Py_END_ALLOW_THREADS
11146 Py_RETURN_NONE;
11147 }
11148
11149
11150 /*[clinic input]
11151 os.dup -> int
11152
11153 fd: int
11154 /
11155
11156 Return a duplicate of a file descriptor.
11157 [clinic start generated code]*/
11158
11159 static int
os_dup_impl(PyObject * module,int fd)11160 os_dup_impl(PyObject *module, int fd)
11161 /*[clinic end generated code: output=486f4860636b2a9f input=6f10f7ea97f7852a]*/
11162 {
11163 return _Py_dup(fd);
11164 }
11165
11166 // dup2() is either provided by libc or dup2.c with AC_REPLACE_FUNCS().
11167 // dup2.c provides working dup2() if and only if F_DUPFD is available.
11168 #if (defined(HAVE_DUP3) || defined(F_DUPFD) || defined(MS_WINDOWS))
11169 /*[clinic input]
11170 os.dup2 -> int
11171 fd: int
11172 fd2: int
11173 inheritable: bool=True
11174
11175 Duplicate file descriptor.
11176 [clinic start generated code]*/
11177
11178 static int
os_dup2_impl(PyObject * module,int fd,int fd2,int inheritable)11179 os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
11180 /*[clinic end generated code: output=bc059d34a73404d1 input=c3cddda8922b038d]*/
11181 {
11182 int res = 0;
11183 #if defined(HAVE_DUP3) && \
11184 !(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC))
11185 /* dup3() is available on Linux 2.6.27+ and glibc 2.9 */
11186 static int dup3_works = -1;
11187 #endif
11188
11189 /* dup2() can fail with EINTR if the target FD is already open, because it
11190 * then has to be closed. See os_close_impl() for why we don't handle EINTR
11191 * upon close(), and therefore below.
11192 */
11193 #ifdef MS_WINDOWS
11194 Py_BEGIN_ALLOW_THREADS
11195 _Py_BEGIN_SUPPRESS_IPH
11196 res = dup2(fd, fd2);
11197 _Py_END_SUPPRESS_IPH
11198 Py_END_ALLOW_THREADS
11199 if (res < 0) {
11200 posix_error();
11201 return -1;
11202 }
11203 res = fd2; // msvcrt dup2 returns 0 on success.
11204
11205 /* Character files like console cannot be make non-inheritable */
11206 if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
11207 close(fd2);
11208 return -1;
11209 }
11210
11211 #elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
11212 Py_BEGIN_ALLOW_THREADS
11213 if (!inheritable)
11214 res = fcntl(fd, F_DUP2FD_CLOEXEC, fd2);
11215 else
11216 res = dup2(fd, fd2);
11217 Py_END_ALLOW_THREADS
11218 if (res < 0) {
11219 posix_error();
11220 return -1;
11221 }
11222
11223 #else
11224
11225 #ifdef HAVE_DUP3
11226 if (!inheritable && dup3_works != 0) {
11227 Py_BEGIN_ALLOW_THREADS
11228 res = dup3(fd, fd2, O_CLOEXEC);
11229 Py_END_ALLOW_THREADS
11230 if (res < 0) {
11231 if (dup3_works == -1)
11232 dup3_works = (errno != ENOSYS);
11233 if (dup3_works) {
11234 posix_error();
11235 return -1;
11236 }
11237 }
11238 }
11239
11240 if (inheritable || dup3_works == 0)
11241 {
11242 #endif
11243 Py_BEGIN_ALLOW_THREADS
11244 res = dup2(fd, fd2);
11245 Py_END_ALLOW_THREADS
11246 if (res < 0) {
11247 posix_error();
11248 return -1;
11249 }
11250
11251 if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
11252 close(fd2);
11253 return -1;
11254 }
11255 #ifdef HAVE_DUP3
11256 }
11257 #endif
11258
11259 #endif
11260
11261 return res;
11262 }
11263 #endif
11264
11265
11266 #ifdef HAVE_LOCKF
11267 /*[clinic input]
11268 os.lockf
11269
11270 fd: int
11271 An open file descriptor.
11272 command: int
11273 One of F_LOCK, F_TLOCK, F_ULOCK or F_TEST.
11274 length: Py_off_t
11275 The number of bytes to lock, starting at the current position.
11276 /
11277
11278 Apply, test or remove a POSIX lock on an open file descriptor.
11279
11280 [clinic start generated code]*/
11281
11282 static PyObject *
os_lockf_impl(PyObject * module,int fd,int command,Py_off_t length)11283 os_lockf_impl(PyObject *module, int fd, int command, Py_off_t length)
11284 /*[clinic end generated code: output=af7051f3e7c29651 input=65da41d2106e9b79]*/
11285 {
11286 int res;
11287
11288 if (PySys_Audit("os.lockf", "iiL", fd, command, length) < 0) {
11289 return NULL;
11290 }
11291
11292 Py_BEGIN_ALLOW_THREADS
11293 res = lockf(fd, command, length);
11294 Py_END_ALLOW_THREADS
11295
11296 if (res < 0)
11297 return posix_error();
11298
11299 Py_RETURN_NONE;
11300 }
11301 #endif /* HAVE_LOCKF */
11302
11303
11304 /*[clinic input]
11305 os.lseek -> Py_off_t
11306
11307 fd: int
11308 An open file descriptor, as returned by os.open().
11309 position: Py_off_t
11310 Position, interpreted relative to 'whence'.
11311 whence as how: int
11312 The relative position to seek from. Valid values are:
11313 - SEEK_SET: seek from the start of the file.
11314 - SEEK_CUR: seek from the current file position.
11315 - SEEK_END: seek from the end of the file.
11316 /
11317
11318 Set the position of a file descriptor. Return the new position.
11319
11320 The return value is the number of bytes relative to the beginning of the file.
11321 [clinic start generated code]*/
11322
11323 static Py_off_t
os_lseek_impl(PyObject * module,int fd,Py_off_t position,int how)11324 os_lseek_impl(PyObject *module, int fd, Py_off_t position, int how)
11325 /*[clinic end generated code: output=971e1efb6b30bd2f input=f096e754c5367504]*/
11326 {
11327 Py_off_t result;
11328
11329 #ifdef SEEK_SET
11330 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
11331 switch (how) {
11332 case 0: how = SEEK_SET; break;
11333 case 1: how = SEEK_CUR; break;
11334 case 2: how = SEEK_END; break;
11335 }
11336 #endif /* SEEK_END */
11337
11338 Py_BEGIN_ALLOW_THREADS
11339 _Py_BEGIN_SUPPRESS_IPH
11340 #ifdef MS_WINDOWS
11341 result = _lseeki64(fd, position, how);
11342 #else
11343 result = lseek(fd, position, how);
11344 #endif
11345 _Py_END_SUPPRESS_IPH
11346 Py_END_ALLOW_THREADS
11347 if (result < 0)
11348 posix_error();
11349
11350 return result;
11351 }
11352
11353
11354 /*[clinic input]
11355 os.read
11356 fd: int
11357 length: Py_ssize_t
11358 /
11359
11360 Read from a file descriptor. Returns a bytes object.
11361 [clinic start generated code]*/
11362
11363 static PyObject *
os_read_impl(PyObject * module,int fd,Py_ssize_t length)11364 os_read_impl(PyObject *module, int fd, Py_ssize_t length)
11365 /*[clinic end generated code: output=dafbe9a5cddb987b input=1df2eaa27c0bf1d3]*/
11366 {
11367 Py_ssize_t n;
11368 PyObject *buffer;
11369
11370 if (length < 0) {
11371 errno = EINVAL;
11372 return posix_error();
11373 }
11374
11375 length = Py_MIN(length, _PY_READ_MAX);
11376
11377 buffer = PyBytes_FromStringAndSize((char *)NULL, length);
11378 if (buffer == NULL)
11379 return NULL;
11380
11381 n = _Py_read(fd, PyBytes_AS_STRING(buffer), length);
11382 if (n == -1) {
11383 Py_DECREF(buffer);
11384 return NULL;
11385 }
11386
11387 if (n != length)
11388 _PyBytes_Resize(&buffer, n);
11389
11390 return buffer;
11391 }
11392
11393 #if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
11394 || defined(__APPLE__))) \
11395 || defined(HAVE_READV) || defined(HAVE_PREADV) || defined (HAVE_PREADV2) \
11396 || defined(HAVE_WRITEV) || defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)
11397 static int
iov_setup(struct iovec ** iov,Py_buffer ** buf,PyObject * seq,Py_ssize_t cnt,int type)11398 iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, Py_ssize_t cnt, int type)
11399 {
11400 Py_ssize_t i, j;
11401
11402 *iov = PyMem_New(struct iovec, cnt);
11403 if (*iov == NULL) {
11404 PyErr_NoMemory();
11405 return -1;
11406 }
11407
11408 *buf = PyMem_New(Py_buffer, cnt);
11409 if (*buf == NULL) {
11410 PyMem_Free(*iov);
11411 PyErr_NoMemory();
11412 return -1;
11413 }
11414
11415 for (i = 0; i < cnt; i++) {
11416 PyObject *item = PySequence_GetItem(seq, i);
11417 if (item == NULL)
11418 goto fail;
11419 if (PyObject_GetBuffer(item, &(*buf)[i], type) == -1) {
11420 Py_DECREF(item);
11421 goto fail;
11422 }
11423 Py_DECREF(item);
11424 (*iov)[i].iov_base = (*buf)[i].buf;
11425 (*iov)[i].iov_len = (*buf)[i].len;
11426 }
11427 return 0;
11428
11429 fail:
11430 PyMem_Free(*iov);
11431 for (j = 0; j < i; j++) {
11432 PyBuffer_Release(&(*buf)[j]);
11433 }
11434 PyMem_Free(*buf);
11435 return -1;
11436 }
11437
11438 static void
iov_cleanup(struct iovec * iov,Py_buffer * buf,int cnt)11439 iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt)
11440 {
11441 int i;
11442 PyMem_Free(iov);
11443 for (i = 0; i < cnt; i++) {
11444 PyBuffer_Release(&buf[i]);
11445 }
11446 PyMem_Free(buf);
11447 }
11448 #endif
11449
11450
11451 #ifdef HAVE_READV
11452 /*[clinic input]
11453 os.readv -> Py_ssize_t
11454
11455 fd: int
11456 buffers: object
11457 /
11458
11459 Read from a file descriptor fd into an iterable of buffers.
11460
11461 The buffers should be mutable buffers accepting bytes.
11462 readv will transfer data into each buffer until it is full
11463 and then move on to the next buffer in the sequence to hold
11464 the rest of the data.
11465
11466 readv returns the total number of bytes read,
11467 which may be less than the total capacity of all the buffers.
11468 [clinic start generated code]*/
11469
11470 static Py_ssize_t
os_readv_impl(PyObject * module,int fd,PyObject * buffers)11471 os_readv_impl(PyObject *module, int fd, PyObject *buffers)
11472 /*[clinic end generated code: output=792da062d3fcebdb input=e679eb5dbfa0357d]*/
11473 {
11474 Py_ssize_t cnt, n;
11475 int async_err = 0;
11476 struct iovec *iov;
11477 Py_buffer *buf;
11478
11479 if (!PySequence_Check(buffers)) {
11480 PyErr_SetString(PyExc_TypeError,
11481 "readv() arg 2 must be a sequence");
11482 return -1;
11483 }
11484
11485 cnt = PySequence_Size(buffers);
11486 if (cnt < 0)
11487 return -1;
11488
11489 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0)
11490 return -1;
11491
11492 do {
11493 Py_BEGIN_ALLOW_THREADS
11494 n = readv(fd, iov, cnt);
11495 Py_END_ALLOW_THREADS
11496 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11497
11498 int saved_errno = errno;
11499 iov_cleanup(iov, buf, cnt);
11500 if (n < 0) {
11501 if (!async_err) {
11502 errno = saved_errno;
11503 posix_error();
11504 }
11505 return -1;
11506 }
11507
11508 return n;
11509 }
11510 #endif /* HAVE_READV */
11511
11512
11513 #ifdef HAVE_PREAD
11514 /*[clinic input]
11515 os.pread
11516
11517 fd: int
11518 length: Py_ssize_t
11519 offset: Py_off_t
11520 /
11521
11522 Read a number of bytes from a file descriptor starting at a particular offset.
11523
11524 Read length bytes from file descriptor fd, starting at offset bytes from
11525 the beginning of the file. The file offset remains unchanged.
11526 [clinic start generated code]*/
11527
11528 static PyObject *
os_pread_impl(PyObject * module,int fd,Py_ssize_t length,Py_off_t offset)11529 os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset)
11530 /*[clinic end generated code: output=3f875c1eef82e32f input=85cb4a5589627144]*/
11531 {
11532 Py_ssize_t n;
11533 int async_err = 0;
11534 PyObject *buffer;
11535
11536 if (length < 0) {
11537 errno = EINVAL;
11538 return posix_error();
11539 }
11540 buffer = PyBytes_FromStringAndSize((char *)NULL, length);
11541 if (buffer == NULL)
11542 return NULL;
11543
11544 do {
11545 Py_BEGIN_ALLOW_THREADS
11546 _Py_BEGIN_SUPPRESS_IPH
11547 n = pread(fd, PyBytes_AS_STRING(buffer), length, offset);
11548 _Py_END_SUPPRESS_IPH
11549 Py_END_ALLOW_THREADS
11550 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11551
11552 if (n < 0) {
11553 if (!async_err) {
11554 posix_error();
11555 }
11556 Py_DECREF(buffer);
11557 return NULL;
11558 }
11559 if (n != length)
11560 _PyBytes_Resize(&buffer, n);
11561 return buffer;
11562 }
11563 #endif /* HAVE_PREAD */
11564
11565 #if defined(HAVE_PREADV) || defined (HAVE_PREADV2)
11566 /*[clinic input]
11567 os.preadv -> Py_ssize_t
11568
11569 fd: int
11570 buffers: object
11571 offset: Py_off_t
11572 flags: int = 0
11573 /
11574
11575 Reads from a file descriptor into a number of mutable bytes-like objects.
11576
11577 Combines the functionality of readv() and pread(). As readv(), it will
11578 transfer data into each buffer until it is full and then move on to the next
11579 buffer in the sequence to hold the rest of the data. Its fourth argument,
11580 specifies the file offset at which the input operation is to be performed. It
11581 will return the total number of bytes read (which can be less than the total
11582 capacity of all the objects).
11583
11584 The flags argument contains a bitwise OR of zero or more of the following flags:
11585
11586 - RWF_HIPRI
11587 - RWF_NOWAIT
11588
11589 Using non-zero flags requires Linux 4.6 or newer.
11590 [clinic start generated code]*/
11591
11592 static Py_ssize_t
os_preadv_impl(PyObject * module,int fd,PyObject * buffers,Py_off_t offset,int flags)11593 os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
11594 int flags)
11595 /*[clinic end generated code: output=26fc9c6e58e7ada5 input=4173919dc1f7ed99]*/
11596 {
11597 Py_ssize_t cnt, n;
11598 int async_err = 0;
11599 struct iovec *iov;
11600 Py_buffer *buf;
11601
11602 if (!PySequence_Check(buffers)) {
11603 PyErr_SetString(PyExc_TypeError,
11604 "preadv2() arg 2 must be a sequence");
11605 return -1;
11606 }
11607
11608 cnt = PySequence_Size(buffers);
11609 if (cnt < 0) {
11610 return -1;
11611 }
11612
11613 #ifndef HAVE_PREADV2
11614 if(flags != 0) {
11615 argument_unavailable_error("preadv2", "flags");
11616 return -1;
11617 }
11618 #endif
11619
11620 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0) {
11621 return -1;
11622 }
11623 #ifdef HAVE_PREADV2
11624 do {
11625 Py_BEGIN_ALLOW_THREADS
11626 _Py_BEGIN_SUPPRESS_IPH
11627 n = preadv2(fd, iov, cnt, offset, flags);
11628 _Py_END_SUPPRESS_IPH
11629 Py_END_ALLOW_THREADS
11630 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11631 #else
11632 do {
11633 #if defined(__APPLE__) && defined(__clang__)
11634 /* This entire function will be removed from the module dict when the API
11635 * is not available.
11636 */
11637 #pragma clang diagnostic push
11638 #pragma clang diagnostic ignored "-Wunguarded-availability"
11639 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
11640 #endif
11641 Py_BEGIN_ALLOW_THREADS
11642 _Py_BEGIN_SUPPRESS_IPH
11643 n = preadv(fd, iov, cnt, offset);
11644 _Py_END_SUPPRESS_IPH
11645 Py_END_ALLOW_THREADS
11646 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11647
11648 #if defined(__APPLE__) && defined(__clang__)
11649 #pragma clang diagnostic pop
11650 #endif
11651
11652 #endif
11653
11654 int saved_errno = errno;
11655 iov_cleanup(iov, buf, cnt);
11656 if (n < 0) {
11657 if (!async_err) {
11658 errno = saved_errno;
11659 posix_error();
11660 }
11661 return -1;
11662 }
11663
11664 return n;
11665 }
11666 #endif /* HAVE_PREADV */
11667
11668
11669 /*[clinic input]
11670 os.write -> Py_ssize_t
11671
11672 fd: int
11673 data: Py_buffer
11674 /
11675
11676 Write a bytes object to a file descriptor.
11677 [clinic start generated code]*/
11678
11679 static Py_ssize_t
os_write_impl(PyObject * module,int fd,Py_buffer * data)11680 os_write_impl(PyObject *module, int fd, Py_buffer *data)
11681 /*[clinic end generated code: output=e4ef5bc904b58ef9 input=3207e28963234f3c]*/
11682 {
11683 return _Py_write(fd, data->buf, data->len);
11684 }
11685
11686 #ifdef HAVE_SENDFILE
11687 #ifdef __APPLE__
11688 /*[clinic input]
11689 os.sendfile
11690
11691 out_fd: int
11692 in_fd: int
11693 offset: Py_off_t
11694 count as sbytes: Py_off_t
11695 headers: object(c_default="NULL") = ()
11696 trailers: object(c_default="NULL") = ()
11697 flags: int = 0
11698
11699 Copy count bytes from file descriptor in_fd to file descriptor out_fd.
11700 [clinic start generated code]*/
11701
11702 static PyObject *
os_sendfile_impl(PyObject * module,int out_fd,int in_fd,Py_off_t offset,Py_off_t sbytes,PyObject * headers,PyObject * trailers,int flags)11703 os_sendfile_impl(PyObject *module, int out_fd, int in_fd, Py_off_t offset,
11704 Py_off_t sbytes, PyObject *headers, PyObject *trailers,
11705 int flags)
11706 /*[clinic end generated code: output=81c4bcd143f5c82b input=b0d72579d4c69afa]*/
11707 #elif defined(__FreeBSD__) || defined(__DragonFly__)
11708 /*[clinic input]
11709 os.sendfile
11710
11711 out_fd: int
11712 in_fd: int
11713 offset: Py_off_t
11714 count: Py_ssize_t
11715 headers: object(c_default="NULL") = ()
11716 trailers: object(c_default="NULL") = ()
11717 flags: int = 0
11718
11719 Copy count bytes from file descriptor in_fd to file descriptor out_fd.
11720 [clinic start generated code]*/
11721
11722 static PyObject *
11723 os_sendfile_impl(PyObject *module, int out_fd, int in_fd, Py_off_t offset,
11724 Py_ssize_t count, PyObject *headers, PyObject *trailers,
11725 int flags)
11726 /*[clinic end generated code: output=329ea009bdd55afc input=338adb8ff84ae8cd]*/
11727 #else
11728 /*[clinic input]
11729 os.sendfile
11730
11731 out_fd: int
11732 in_fd: int
11733 offset as offobj: object
11734 count: Py_ssize_t
11735
11736 Copy count bytes from file descriptor in_fd to file descriptor out_fd.
11737 [clinic start generated code]*/
11738
11739 static PyObject *
11740 os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj,
11741 Py_ssize_t count)
11742 /*[clinic end generated code: output=ae81216e40f167d8 input=76d64058c74477ba]*/
11743 #endif
11744 {
11745 Py_ssize_t ret;
11746 int async_err = 0;
11747
11748 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
11749 #ifndef __APPLE__
11750 off_t sbytes;
11751 #endif
11752 Py_buffer *hbuf, *tbuf;
11753 struct sf_hdtr sf;
11754
11755 sf.headers = NULL;
11756 sf.trailers = NULL;
11757
11758 if (headers != NULL) {
11759 if (!PySequence_Check(headers)) {
11760 PyErr_SetString(PyExc_TypeError,
11761 "sendfile() headers must be a sequence");
11762 return NULL;
11763 } else {
11764 Py_ssize_t i = PySequence_Size(headers);
11765 if (i < 0)
11766 return NULL;
11767 if (i > INT_MAX) {
11768 PyErr_SetString(PyExc_OverflowError,
11769 "sendfile() header is too large");
11770 return NULL;
11771 }
11772 if (i > 0) {
11773 sf.hdr_cnt = (int)i;
11774 if (iov_setup(&(sf.headers), &hbuf,
11775 headers, sf.hdr_cnt, PyBUF_SIMPLE) < 0)
11776 return NULL;
11777 #ifdef __APPLE__
11778 for (i = 0; i < sf.hdr_cnt; i++) {
11779 Py_ssize_t blen = sf.headers[i].iov_len;
11780 # define OFF_T_MAX 0x7fffffffffffffff
11781 if (sbytes >= OFF_T_MAX - blen) {
11782 PyErr_SetString(PyExc_OverflowError,
11783 "sendfile() header is too large");
11784 return NULL;
11785 }
11786 sbytes += blen;
11787 }
11788 #endif
11789 }
11790 }
11791 }
11792 if (trailers != NULL) {
11793 if (!PySequence_Check(trailers)) {
11794 PyErr_SetString(PyExc_TypeError,
11795 "sendfile() trailers must be a sequence");
11796 return NULL;
11797 } else {
11798 Py_ssize_t i = PySequence_Size(trailers);
11799 if (i < 0)
11800 return NULL;
11801 if (i > INT_MAX) {
11802 PyErr_SetString(PyExc_OverflowError,
11803 "sendfile() trailer is too large");
11804 return NULL;
11805 }
11806 if (i > 0) {
11807 sf.trl_cnt = (int)i;
11808 if (iov_setup(&(sf.trailers), &tbuf,
11809 trailers, sf.trl_cnt, PyBUF_SIMPLE) < 0)
11810 return NULL;
11811 }
11812 }
11813 }
11814
11815 _Py_BEGIN_SUPPRESS_IPH
11816 do {
11817 Py_BEGIN_ALLOW_THREADS
11818 #ifdef __APPLE__
11819 ret = sendfile(in_fd, out_fd, offset, &sbytes, &sf, flags);
11820 #else
11821 ret = sendfile(in_fd, out_fd, offset, count, &sf, &sbytes, flags);
11822 #endif
11823 Py_END_ALLOW_THREADS
11824 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11825 _Py_END_SUPPRESS_IPH
11826
11827 int saved_errno = errno;
11828 if (sf.headers != NULL)
11829 iov_cleanup(sf.headers, hbuf, sf.hdr_cnt);
11830 if (sf.trailers != NULL)
11831 iov_cleanup(sf.trailers, tbuf, sf.trl_cnt);
11832
11833 if (ret < 0) {
11834 if ((saved_errno == EAGAIN) || (saved_errno == EBUSY)) {
11835 if (sbytes != 0) {
11836 // some data has been sent
11837 goto done;
11838 }
11839 // no data has been sent; upper application is supposed
11840 // to retry on EAGAIN or EBUSY
11841 }
11842 if (!async_err) {
11843 errno = saved_errno;
11844 posix_error();
11845 }
11846 return NULL;
11847 }
11848 goto done;
11849
11850 done:
11851 #if !defined(HAVE_LARGEFILE_SUPPORT)
11852 return PyLong_FromLong(sbytes);
11853 #else
11854 return PyLong_FromLongLong(sbytes);
11855 #endif
11856
11857 #else
11858 #ifdef __linux__
11859 if (offobj == Py_None) {
11860 do {
11861 Py_BEGIN_ALLOW_THREADS
11862 ret = sendfile(out_fd, in_fd, NULL, count);
11863 Py_END_ALLOW_THREADS
11864 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11865 if (ret < 0)
11866 return (!async_err) ? posix_error() : NULL;
11867 return PyLong_FromSsize_t(ret);
11868 }
11869 #endif
11870 off_t offset;
11871 if (!Py_off_t_converter(offobj, &offset))
11872 return NULL;
11873
11874 #if defined(__sun) && defined(__SVR4)
11875 // On Solaris, sendfile raises EINVAL rather than returning 0
11876 // when the offset is equal or bigger than the in_fd size.
11877 struct stat st;
11878
11879 do {
11880 Py_BEGIN_ALLOW_THREADS
11881 ret = fstat(in_fd, &st);
11882 Py_END_ALLOW_THREADS
11883 } while (ret != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11884 if (ret < 0)
11885 return (!async_err) ? posix_error() : NULL;
11886
11887 if (offset >= st.st_size) {
11888 return PyLong_FromLong(0);
11889 }
11890
11891 // On illumos specifically sendfile() may perform a partial write but
11892 // return -1/an error (in one confirmed case the destination socket
11893 // had a 5 second timeout set and errno was EAGAIN) and it's on the client
11894 // code to check if the offset parameter was modified by sendfile().
11895 //
11896 // We need this variable to track said change.
11897 off_t original_offset = offset;
11898 #endif
11899
11900 do {
11901 Py_BEGIN_ALLOW_THREADS
11902 ret = sendfile(out_fd, in_fd, &offset, count);
11903 #if defined(__sun) && defined(__SVR4)
11904 // This handles illumos-specific sendfile() partial write behavior,
11905 // see a comment above for more details.
11906 if (ret < 0 && offset != original_offset) {
11907 ret = offset - original_offset;
11908 }
11909 #endif
11910 Py_END_ALLOW_THREADS
11911 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11912 if (ret < 0)
11913 return (!async_err) ? posix_error() : NULL;
11914 return PyLong_FromSsize_t(ret);
11915 #endif
11916 }
11917 #endif /* HAVE_SENDFILE */
11918
11919
11920 #if defined(__APPLE__)
11921 /*[clinic input]
11922 os._fcopyfile
11923
11924 in_fd: int
11925 out_fd: int
11926 flags: int
11927 /
11928
11929 Efficiently copy content or metadata of 2 regular file descriptors (macOS).
11930 [clinic start generated code]*/
11931
11932 static PyObject *
os__fcopyfile_impl(PyObject * module,int in_fd,int out_fd,int flags)11933 os__fcopyfile_impl(PyObject *module, int in_fd, int out_fd, int flags)
11934 /*[clinic end generated code: output=c9d1a35a992e401b input=1e34638a86948795]*/
11935 {
11936 int ret;
11937
11938 Py_BEGIN_ALLOW_THREADS
11939 ret = fcopyfile(in_fd, out_fd, NULL, flags);
11940 Py_END_ALLOW_THREADS
11941 if (ret < 0)
11942 return posix_error();
11943 Py_RETURN_NONE;
11944 }
11945 #endif
11946
11947
11948 /*[clinic input]
11949 os.fstat
11950
11951 fd : int
11952
11953 Perform a stat system call on the given file descriptor.
11954
11955 Like stat(), but for an open file descriptor.
11956 Equivalent to os.stat(fd).
11957 [clinic start generated code]*/
11958
11959 static PyObject *
os_fstat_impl(PyObject * module,int fd)11960 os_fstat_impl(PyObject *module, int fd)
11961 /*[clinic end generated code: output=efc038cb5f654492 input=27e0e0ebbe5600c9]*/
11962 {
11963 STRUCT_STAT st;
11964 int res;
11965 int async_err = 0;
11966
11967 do {
11968 Py_BEGIN_ALLOW_THREADS
11969 res = FSTAT(fd, &st);
11970 Py_END_ALLOW_THREADS
11971 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11972 if (res != 0) {
11973 #ifdef MS_WINDOWS
11974 return PyErr_SetFromWindowsErr(0);
11975 #else
11976 return (!async_err) ? posix_error() : NULL;
11977 #endif
11978 }
11979
11980 return _pystat_fromstructstat(module, &st);
11981 }
11982
11983
11984 /*[clinic input]
11985 os.isatty -> bool
11986 fd: int
11987 /
11988
11989 Return True if the fd is connected to a terminal.
11990
11991 Return True if the file descriptor is an open file descriptor
11992 connected to the slave end of a terminal.
11993 [clinic start generated code]*/
11994
11995 static int
os_isatty_impl(PyObject * module,int fd)11996 os_isatty_impl(PyObject *module, int fd)
11997 /*[clinic end generated code: output=6a48c8b4e644ca00 input=08ce94aa1eaf7b5e]*/
11998 {
11999 int return_value;
12000 Py_BEGIN_ALLOW_THREADS
12001 _Py_BEGIN_SUPPRESS_IPH
12002 return_value = isatty(fd);
12003 _Py_END_SUPPRESS_IPH
12004 Py_END_ALLOW_THREADS
12005 return return_value;
12006 }
12007
12008
12009 #ifdef HAVE_PIPE
12010 /*[clinic input]
12011 os.pipe
12012
12013 Create a pipe.
12014
12015 Returns a tuple of two file descriptors:
12016 (read_fd, write_fd)
12017 [clinic start generated code]*/
12018
12019 static PyObject *
os_pipe_impl(PyObject * module)12020 os_pipe_impl(PyObject *module)
12021 /*[clinic end generated code: output=ff9b76255793b440 input=02535e8c8fa6c4d4]*/
12022 {
12023 int fds[2];
12024 #ifdef MS_WINDOWS
12025 HANDLE read, write;
12026 SECURITY_ATTRIBUTES attr;
12027 BOOL ok;
12028 #else
12029 int res;
12030 #endif
12031
12032 #ifdef MS_WINDOWS
12033 attr.nLength = sizeof(attr);
12034 attr.lpSecurityDescriptor = NULL;
12035 attr.bInheritHandle = FALSE;
12036
12037 Py_BEGIN_ALLOW_THREADS
12038 ok = CreatePipe(&read, &write, &attr, 0);
12039 if (ok) {
12040 fds[0] = _Py_open_osfhandle_noraise(read, _O_RDONLY | _O_NOINHERIT);
12041 fds[1] = _Py_open_osfhandle_noraise(write, _O_WRONLY | _O_NOINHERIT);
12042 if (fds[0] == -1 || fds[1] == -1) {
12043 CloseHandle(read);
12044 CloseHandle(write);
12045 ok = 0;
12046 }
12047 }
12048 Py_END_ALLOW_THREADS
12049
12050 if (!ok)
12051 return PyErr_SetFromWindowsErr(0);
12052 #else
12053
12054 #ifdef HAVE_PIPE2
12055 Py_BEGIN_ALLOW_THREADS
12056 res = pipe2(fds, O_CLOEXEC);
12057 Py_END_ALLOW_THREADS
12058
12059 if (res != 0 && errno == ENOSYS)
12060 {
12061 #endif
12062 Py_BEGIN_ALLOW_THREADS
12063 res = pipe(fds);
12064 Py_END_ALLOW_THREADS
12065
12066 if (res == 0) {
12067 if (_Py_set_inheritable(fds[0], 0, NULL) < 0) {
12068 close(fds[0]);
12069 close(fds[1]);
12070 return NULL;
12071 }
12072 if (_Py_set_inheritable(fds[1], 0, NULL) < 0) {
12073 close(fds[0]);
12074 close(fds[1]);
12075 return NULL;
12076 }
12077 }
12078 #ifdef HAVE_PIPE2
12079 }
12080 #endif
12081
12082 if (res != 0)
12083 return PyErr_SetFromErrno(PyExc_OSError);
12084 #endif /* !MS_WINDOWS */
12085 return Py_BuildValue("(ii)", fds[0], fds[1]);
12086 }
12087 #endif /* HAVE_PIPE */
12088
12089
12090 #ifdef HAVE_PIPE2
12091 /*[clinic input]
12092 os.pipe2
12093
12094 flags: int
12095 /
12096
12097 Create a pipe with flags set atomically.
12098
12099 Returns a tuple of two file descriptors:
12100 (read_fd, write_fd)
12101
12102 flags can be constructed by ORing together one or more of these values:
12103 O_NONBLOCK, O_CLOEXEC.
12104 [clinic start generated code]*/
12105
12106 static PyObject *
os_pipe2_impl(PyObject * module,int flags)12107 os_pipe2_impl(PyObject *module, int flags)
12108 /*[clinic end generated code: output=25751fb43a45540f input=f261b6e7e63c6817]*/
12109 {
12110 int fds[2];
12111 int res;
12112
12113 res = pipe2(fds, flags);
12114 if (res != 0)
12115 return posix_error();
12116 return Py_BuildValue("(ii)", fds[0], fds[1]);
12117 }
12118 #endif /* HAVE_PIPE2 */
12119
12120
12121 #ifdef HAVE_WRITEV
12122 /*[clinic input]
12123 os.writev -> Py_ssize_t
12124 fd: int
12125 buffers: object
12126 /
12127
12128 Iterate over buffers, and write the contents of each to a file descriptor.
12129
12130 Returns the total number of bytes written.
12131 buffers must be a sequence of bytes-like objects.
12132 [clinic start generated code]*/
12133
12134 static Py_ssize_t
os_writev_impl(PyObject * module,int fd,PyObject * buffers)12135 os_writev_impl(PyObject *module, int fd, PyObject *buffers)
12136 /*[clinic end generated code: output=56565cfac3aac15b input=5b8d17fe4189d2fe]*/
12137 {
12138 Py_ssize_t cnt;
12139 Py_ssize_t result;
12140 int async_err = 0;
12141 struct iovec *iov;
12142 Py_buffer *buf;
12143
12144 if (!PySequence_Check(buffers)) {
12145 PyErr_SetString(PyExc_TypeError,
12146 "writev() arg 2 must be a sequence");
12147 return -1;
12148 }
12149 cnt = PySequence_Size(buffers);
12150 if (cnt < 0)
12151 return -1;
12152
12153 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
12154 return -1;
12155 }
12156
12157 do {
12158 Py_BEGIN_ALLOW_THREADS
12159 result = writev(fd, iov, cnt);
12160 Py_END_ALLOW_THREADS
12161 } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
12162
12163 if (result < 0 && !async_err)
12164 posix_error();
12165
12166 iov_cleanup(iov, buf, cnt);
12167 return result;
12168 }
12169 #endif /* HAVE_WRITEV */
12170
12171
12172 #ifdef HAVE_PWRITE
12173 /*[clinic input]
12174 os.pwrite -> Py_ssize_t
12175
12176 fd: int
12177 buffer: Py_buffer
12178 offset: Py_off_t
12179 /
12180
12181 Write bytes to a file descriptor starting at a particular offset.
12182
12183 Write buffer to fd, starting at offset bytes from the beginning of
12184 the file. Returns the number of bytes written. Does not change the
12185 current file offset.
12186 [clinic start generated code]*/
12187
12188 static Py_ssize_t
os_pwrite_impl(PyObject * module,int fd,Py_buffer * buffer,Py_off_t offset)12189 os_pwrite_impl(PyObject *module, int fd, Py_buffer *buffer, Py_off_t offset)
12190 /*[clinic end generated code: output=c74da630758ee925 input=614acbc7e5a0339a]*/
12191 {
12192 Py_ssize_t size;
12193 int async_err = 0;
12194
12195 do {
12196 Py_BEGIN_ALLOW_THREADS
12197 _Py_BEGIN_SUPPRESS_IPH
12198 size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
12199 _Py_END_SUPPRESS_IPH
12200 Py_END_ALLOW_THREADS
12201 } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
12202
12203 if (size < 0 && !async_err)
12204 posix_error();
12205 return size;
12206 }
12207 #endif /* HAVE_PWRITE */
12208
12209 #if defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)
12210 /*[clinic input]
12211 os.pwritev -> Py_ssize_t
12212
12213 fd: int
12214 buffers: object
12215 offset: Py_off_t
12216 flags: int = 0
12217 /
12218
12219 Writes the contents of bytes-like objects to a file descriptor at a given offset.
12220
12221 Combines the functionality of writev() and pwrite(). All buffers must be a sequence
12222 of bytes-like objects. Buffers are processed in array order. Entire contents of first
12223 buffer is written before proceeding to second, and so on. The operating system may
12224 set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used.
12225 This function writes the contents of each object to the file descriptor and returns
12226 the total number of bytes written.
12227
12228 The flags argument contains a bitwise OR of zero or more of the following flags:
12229
12230 - RWF_DSYNC
12231 - RWF_SYNC
12232 - RWF_APPEND
12233
12234 Using non-zero flags requires Linux 4.7 or newer.
12235 [clinic start generated code]*/
12236
12237 static Py_ssize_t
os_pwritev_impl(PyObject * module,int fd,PyObject * buffers,Py_off_t offset,int flags)12238 os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
12239 int flags)
12240 /*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=35358c327e1a2a8e]*/
12241 {
12242 Py_ssize_t cnt;
12243 Py_ssize_t result;
12244 int async_err = 0;
12245 struct iovec *iov;
12246 Py_buffer *buf;
12247
12248 if (!PySequence_Check(buffers)) {
12249 PyErr_SetString(PyExc_TypeError,
12250 "pwritev() arg 2 must be a sequence");
12251 return -1;
12252 }
12253
12254 cnt = PySequence_Size(buffers);
12255 if (cnt < 0) {
12256 return -1;
12257 }
12258
12259 #ifndef HAVE_PWRITEV2
12260 if(flags != 0) {
12261 argument_unavailable_error("pwritev2", "flags");
12262 return -1;
12263 }
12264 #endif
12265
12266 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
12267 return -1;
12268 }
12269 #ifdef HAVE_PWRITEV2
12270 do {
12271 Py_BEGIN_ALLOW_THREADS
12272 _Py_BEGIN_SUPPRESS_IPH
12273 result = pwritev2(fd, iov, cnt, offset, flags);
12274 _Py_END_SUPPRESS_IPH
12275 Py_END_ALLOW_THREADS
12276 } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
12277 #else
12278
12279 #if defined(__APPLE__) && defined(__clang__)
12280 /* This entire function will be removed from the module dict when the API
12281 * is not available.
12282 */
12283 #pragma clang diagnostic push
12284 #pragma clang diagnostic ignored "-Wunguarded-availability"
12285 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
12286 #endif
12287 do {
12288 Py_BEGIN_ALLOW_THREADS
12289 _Py_BEGIN_SUPPRESS_IPH
12290 result = pwritev(fd, iov, cnt, offset);
12291 _Py_END_SUPPRESS_IPH
12292 Py_END_ALLOW_THREADS
12293 } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
12294
12295 #if defined(__APPLE__) && defined(__clang__)
12296 #pragma clang diagnostic pop
12297 #endif
12298
12299 #endif
12300
12301 if (result < 0) {
12302 if (!async_err) {
12303 posix_error();
12304 }
12305 result = -1;
12306 }
12307 iov_cleanup(iov, buf, cnt);
12308
12309 return result;
12310 }
12311 #endif /* HAVE_PWRITEV */
12312
12313 #ifdef HAVE_COPY_FILE_RANGE
12314 /*[clinic input]
12315
12316 os.copy_file_range
12317 src: int
12318 Source file descriptor.
12319 dst: int
12320 Destination file descriptor.
12321 count: Py_ssize_t
12322 Number of bytes to copy.
12323 offset_src: object = None
12324 Starting offset in src.
12325 offset_dst: object = None
12326 Starting offset in dst.
12327
12328 Copy count bytes from one file descriptor to another.
12329
12330 If offset_src is None, then src is read from the current position;
12331 respectively for offset_dst.
12332 [clinic start generated code]*/
12333
12334 static PyObject *
os_copy_file_range_impl(PyObject * module,int src,int dst,Py_ssize_t count,PyObject * offset_src,PyObject * offset_dst)12335 os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count,
12336 PyObject *offset_src, PyObject *offset_dst)
12337 /*[clinic end generated code: output=1a91713a1d99fc7a input=42fdce72681b25a9]*/
12338 {
12339 off_t offset_src_val, offset_dst_val;
12340 off_t *p_offset_src = NULL;
12341 off_t *p_offset_dst = NULL;
12342 Py_ssize_t ret;
12343 int async_err = 0;
12344 /* The flags argument is provided to allow
12345 * for future extensions and currently must be to 0. */
12346 int flags = 0;
12347
12348
12349 if (count < 0) {
12350 PyErr_SetString(PyExc_ValueError, "negative value for 'count' not allowed");
12351 return NULL;
12352 }
12353
12354 if (offset_src != Py_None) {
12355 if (!Py_off_t_converter(offset_src, &offset_src_val)) {
12356 return NULL;
12357 }
12358 p_offset_src = &offset_src_val;
12359 }
12360
12361 if (offset_dst != Py_None) {
12362 if (!Py_off_t_converter(offset_dst, &offset_dst_val)) {
12363 return NULL;
12364 }
12365 p_offset_dst = &offset_dst_val;
12366 }
12367
12368 do {
12369 Py_BEGIN_ALLOW_THREADS
12370 ret = copy_file_range(src, p_offset_src, dst, p_offset_dst, count, flags);
12371 Py_END_ALLOW_THREADS
12372 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
12373
12374 if (ret < 0) {
12375 return (!async_err) ? posix_error() : NULL;
12376 }
12377
12378 return PyLong_FromSsize_t(ret);
12379 }
12380 #endif /* HAVE_COPY_FILE_RANGE*/
12381
12382 #if (defined(HAVE_SPLICE) && !defined(_AIX))
12383 /*[clinic input]
12384
12385 os.splice
12386 src: int
12387 Source file descriptor.
12388 dst: int
12389 Destination file descriptor.
12390 count: Py_ssize_t
12391 Number of bytes to copy.
12392 offset_src: object = None
12393 Starting offset in src.
12394 offset_dst: object = None
12395 Starting offset in dst.
12396 flags: unsigned_int = 0
12397 Flags to modify the semantics of the call.
12398
12399 Transfer count bytes from one pipe to a descriptor or vice versa.
12400
12401 If offset_src is None, then src is read from the current position;
12402 respectively for offset_dst. The offset associated to the file
12403 descriptor that refers to a pipe must be None.
12404 [clinic start generated code]*/
12405
12406 static PyObject *
os_splice_impl(PyObject * module,int src,int dst,Py_ssize_t count,PyObject * offset_src,PyObject * offset_dst,unsigned int flags)12407 os_splice_impl(PyObject *module, int src, int dst, Py_ssize_t count,
12408 PyObject *offset_src, PyObject *offset_dst,
12409 unsigned int flags)
12410 /*[clinic end generated code: output=d0386f25a8519dc5 input=047527c66c6d2e0a]*/
12411 {
12412 off_t offset_src_val, offset_dst_val;
12413 off_t *p_offset_src = NULL;
12414 off_t *p_offset_dst = NULL;
12415 Py_ssize_t ret;
12416 int async_err = 0;
12417
12418 if (count < 0) {
12419 PyErr_SetString(PyExc_ValueError, "negative value for 'count' not allowed");
12420 return NULL;
12421 }
12422
12423 if (offset_src != Py_None) {
12424 if (!Py_off_t_converter(offset_src, &offset_src_val)) {
12425 return NULL;
12426 }
12427 p_offset_src = &offset_src_val;
12428 }
12429
12430 if (offset_dst != Py_None) {
12431 if (!Py_off_t_converter(offset_dst, &offset_dst_val)) {
12432 return NULL;
12433 }
12434 p_offset_dst = &offset_dst_val;
12435 }
12436
12437 do {
12438 Py_BEGIN_ALLOW_THREADS
12439 ret = splice(src, p_offset_src, dst, p_offset_dst, count, flags);
12440 Py_END_ALLOW_THREADS
12441 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
12442
12443 if (ret < 0) {
12444 return (!async_err) ? posix_error() : NULL;
12445 }
12446
12447 return PyLong_FromSsize_t(ret);
12448 }
12449 #endif /* HAVE_SPLICE*/
12450
12451 #ifdef HAVE_MKFIFO
12452 /*[clinic input]
12453 os.mkfifo
12454
12455 path: path_t
12456 mode: int=0o666
12457 *
12458 dir_fd: dir_fd(requires='mkfifoat')=None
12459
12460 Create a "fifo" (a POSIX named pipe).
12461
12462 If dir_fd is not None, it should be a file descriptor open to a directory,
12463 and path should be relative; path will then be relative to that directory.
12464 dir_fd may not be implemented on your platform.
12465 If it is unavailable, using it will raise a NotImplementedError.
12466 [clinic start generated code]*/
12467
12468 static PyObject *
os_mkfifo_impl(PyObject * module,path_t * path,int mode,int dir_fd)12469 os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd)
12470 /*[clinic end generated code: output=ce41cfad0e68c940 input=73032e98a36e0e19]*/
12471 {
12472 int result;
12473 int async_err = 0;
12474 #ifdef HAVE_MKFIFOAT
12475 int mkfifoat_unavailable = 0;
12476 #endif
12477
12478 do {
12479 Py_BEGIN_ALLOW_THREADS
12480 #ifdef HAVE_MKFIFOAT
12481 if (dir_fd != DEFAULT_DIR_FD) {
12482 if (HAVE_MKFIFOAT_RUNTIME) {
12483 result = mkfifoat(dir_fd, path->narrow, mode);
12484
12485 } else {
12486 mkfifoat_unavailable = 1;
12487 result = 0;
12488 }
12489 } else
12490 #endif
12491 result = mkfifo(path->narrow, mode);
12492 Py_END_ALLOW_THREADS
12493 } while (result != 0 && errno == EINTR &&
12494 !(async_err = PyErr_CheckSignals()));
12495
12496 #ifdef HAVE_MKFIFOAT
12497 if (mkfifoat_unavailable) {
12498 argument_unavailable_error(NULL, "dir_fd");
12499 return NULL;
12500 }
12501 #endif
12502
12503 if (result != 0)
12504 return (!async_err) ? posix_error() : NULL;
12505
12506 Py_RETURN_NONE;
12507 }
12508 #endif /* HAVE_MKFIFO */
12509
12510
12511 #if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
12512 /*[clinic input]
12513 os.mknod
12514
12515 path: path_t
12516 mode: int=0o600
12517 device: dev_t=0
12518 *
12519 dir_fd: dir_fd(requires='mknodat')=None
12520
12521 Create a node in the file system.
12522
12523 Create a node in the file system (file, device special file or named pipe)
12524 at path. mode specifies both the permissions to use and the
12525 type of node to be created, being combined (bitwise OR) with one of
12526 S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set on mode,
12527 device defines the newly created device special file (probably using
12528 os.makedev()). Otherwise device is ignored.
12529
12530 If dir_fd is not None, it should be a file descriptor open to a directory,
12531 and path should be relative; path will then be relative to that directory.
12532 dir_fd may not be implemented on your platform.
12533 If it is unavailable, using it will raise a NotImplementedError.
12534 [clinic start generated code]*/
12535
12536 static PyObject *
os_mknod_impl(PyObject * module,path_t * path,int mode,dev_t device,int dir_fd)12537 os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device,
12538 int dir_fd)
12539 /*[clinic end generated code: output=92e55d3ca8917461 input=ee44531551a4d83b]*/
12540 {
12541 int result;
12542 int async_err = 0;
12543 #ifdef HAVE_MKNODAT
12544 int mknodat_unavailable = 0;
12545 #endif
12546
12547 do {
12548 Py_BEGIN_ALLOW_THREADS
12549 #ifdef HAVE_MKNODAT
12550 if (dir_fd != DEFAULT_DIR_FD) {
12551 if (HAVE_MKNODAT_RUNTIME) {
12552 result = mknodat(dir_fd, path->narrow, mode, device);
12553
12554 } else {
12555 mknodat_unavailable = 1;
12556 result = 0;
12557 }
12558 } else
12559 #endif
12560 result = mknod(path->narrow, mode, device);
12561 Py_END_ALLOW_THREADS
12562 } while (result != 0 && errno == EINTR &&
12563 !(async_err = PyErr_CheckSignals()));
12564 #ifdef HAVE_MKNODAT
12565 if (mknodat_unavailable) {
12566 argument_unavailable_error(NULL, "dir_fd");
12567 return NULL;
12568 }
12569 #endif
12570 if (result != 0)
12571 return (!async_err) ? posix_error() : NULL;
12572
12573 Py_RETURN_NONE;
12574 }
12575 #endif /* defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) */
12576
12577
12578 #ifdef HAVE_DEVICE_MACROS
12579 static PyObject *
major_minor_conv(unsigned int value)12580 major_minor_conv(unsigned int value)
12581 {
12582 #ifdef NODEV
12583 if (value == (unsigned int)NODEV) {
12584 return PyLong_FromLong((int)NODEV);
12585 }
12586 #endif
12587 return PyLong_FromUnsignedLong(value);
12588 }
12589
12590 static int
major_minor_check(dev_t value)12591 major_minor_check(dev_t value)
12592 {
12593 #ifdef NODEV
12594 if (value == NODEV) {
12595 return 1;
12596 }
12597 #endif
12598 return (dev_t)(unsigned int)value == value;
12599 }
12600
12601 /*[clinic input]
12602 os.major
12603
12604 device: dev_t
12605 /
12606
12607 Extracts a device major number from a raw device number.
12608 [clinic start generated code]*/
12609
12610 static PyObject *
os_major_impl(PyObject * module,dev_t device)12611 os_major_impl(PyObject *module, dev_t device)
12612 /*[clinic end generated code: output=4071ffee17647891 input=b1a0a14ec9448229]*/
12613 {
12614 return major_minor_conv(major(device));
12615 }
12616
12617
12618 /*[clinic input]
12619 os.minor
12620
12621 device: dev_t
12622 /
12623
12624 Extracts a device minor number from a raw device number.
12625 [clinic start generated code]*/
12626
12627 static PyObject *
os_minor_impl(PyObject * module,dev_t device)12628 os_minor_impl(PyObject *module, dev_t device)
12629 /*[clinic end generated code: output=306cb78e3bc5004f input=2f686e463682a9da]*/
12630 {
12631 return major_minor_conv(minor(device));
12632 }
12633
12634
12635 /*[clinic input]
12636 os.makedev -> dev_t
12637
12638 major: dev_t
12639 minor: dev_t
12640 /
12641
12642 Composes a raw device number from the major and minor device numbers.
12643 [clinic start generated code]*/
12644
12645 static dev_t
os_makedev_impl(PyObject * module,dev_t major,dev_t minor)12646 os_makedev_impl(PyObject *module, dev_t major, dev_t minor)
12647 /*[clinic end generated code: output=cad6125c51f5af80 input=2146126ec02e55c1]*/
12648 {
12649 if (!major_minor_check(major) || !major_minor_check(minor)) {
12650 PyErr_SetString(PyExc_OverflowError,
12651 "Python int too large to convert to C unsigned int");
12652 return (dev_t)-1;
12653 }
12654 return makedev(major, minor);
12655 }
12656 #endif /* HAVE_DEVICE_MACROS */
12657
12658
12659 #if defined HAVE_FTRUNCATE || defined MS_WINDOWS
12660 /*[clinic input]
12661 os.ftruncate
12662
12663 fd: int
12664 length: Py_off_t
12665 /
12666
12667 Truncate a file, specified by file descriptor, to a specific length.
12668 [clinic start generated code]*/
12669
12670 static PyObject *
os_ftruncate_impl(PyObject * module,int fd,Py_off_t length)12671 os_ftruncate_impl(PyObject *module, int fd, Py_off_t length)
12672 /*[clinic end generated code: output=fba15523721be7e4 input=63b43641e52818f2]*/
12673 {
12674 int result;
12675 int async_err = 0;
12676
12677 if (PySys_Audit("os.truncate", "in", fd, length) < 0) {
12678 return NULL;
12679 }
12680
12681 do {
12682 Py_BEGIN_ALLOW_THREADS
12683 _Py_BEGIN_SUPPRESS_IPH
12684 #ifdef MS_WINDOWS
12685 result = _chsize_s(fd, length);
12686 #else
12687 result = ftruncate(fd, length);
12688 #endif
12689 _Py_END_SUPPRESS_IPH
12690 Py_END_ALLOW_THREADS
12691 } while (result != 0 && errno == EINTR &&
12692 !(async_err = PyErr_CheckSignals()));
12693 if (result != 0)
12694 return (!async_err) ? posix_error() : NULL;
12695 Py_RETURN_NONE;
12696 }
12697 #endif /* HAVE_FTRUNCATE || MS_WINDOWS */
12698
12699
12700 #if defined HAVE_TRUNCATE || defined MS_WINDOWS
12701 /*[clinic input]
12702 os.truncate
12703 path: path_t(allow_fd='PATH_HAVE_FTRUNCATE')
12704 length: Py_off_t
12705
12706 Truncate a file, specified by path, to a specific length.
12707
12708 On some platforms, path may also be specified as an open file descriptor.
12709 If this functionality is unavailable, using it raises an exception.
12710 [clinic start generated code]*/
12711
12712 static PyObject *
os_truncate_impl(PyObject * module,path_t * path,Py_off_t length)12713 os_truncate_impl(PyObject *module, path_t *path, Py_off_t length)
12714 /*[clinic end generated code: output=43009c8df5c0a12b input=77229cf0b50a9b77]*/
12715 {
12716 int result;
12717 #ifdef MS_WINDOWS
12718 int fd;
12719 #endif
12720
12721 if (path->fd != -1)
12722 return os_ftruncate_impl(module, path->fd, length);
12723
12724 if (PySys_Audit("os.truncate", "On", path->object, length) < 0) {
12725 return NULL;
12726 }
12727
12728 Py_BEGIN_ALLOW_THREADS
12729 _Py_BEGIN_SUPPRESS_IPH
12730 #ifdef MS_WINDOWS
12731 fd = _wopen(path->wide, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
12732 if (fd < 0)
12733 result = -1;
12734 else {
12735 result = _chsize_s(fd, length);
12736 close(fd);
12737 if (result < 0)
12738 errno = result;
12739 }
12740 #else
12741 result = truncate(path->narrow, length);
12742 #endif
12743 _Py_END_SUPPRESS_IPH
12744 Py_END_ALLOW_THREADS
12745 if (result < 0)
12746 return posix_path_error(path);
12747
12748 Py_RETURN_NONE;
12749 }
12750 #endif /* HAVE_TRUNCATE || MS_WINDOWS */
12751
12752
12753 /* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise()
12754 and os.posix_fallocate() in system headers are wrong if _LARGE_FILES is
12755 defined, which is the case in Python on AIX. AIX bug report:
12756 http://www-01.ibm.com/support/docview.wss?uid=isg1IV56170 */
12757 #if defined(_AIX) && defined(_LARGE_FILES) && !defined(__64BIT__)
12758 # define POSIX_FADVISE_AIX_BUG
12759 #endif
12760
12761
12762 /* GH-111804: Due to posix_fallocate() not having consistent semantics across
12763 OSs, support was dropped in WASI preview2. */
12764 #if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) && \
12765 !defined(__wasi__)
12766 /*[clinic input]
12767 os.posix_fallocate
12768
12769 fd: int
12770 offset: Py_off_t
12771 length: Py_off_t
12772 /
12773
12774 Ensure a file has allocated at least a particular number of bytes on disk.
12775
12776 Ensure that the file specified by fd encompasses a range of bytes
12777 starting at offset bytes from the beginning and continuing for length bytes.
12778 [clinic start generated code]*/
12779
12780 static PyObject *
os_posix_fallocate_impl(PyObject * module,int fd,Py_off_t offset,Py_off_t length)12781 os_posix_fallocate_impl(PyObject *module, int fd, Py_off_t offset,
12782 Py_off_t length)
12783 /*[clinic end generated code: output=73f107139564aa9d input=d7a2ef0ab2ca52fb]*/
12784 {
12785 int result;
12786 int async_err = 0;
12787
12788 do {
12789 Py_BEGIN_ALLOW_THREADS
12790 result = posix_fallocate(fd, offset, length);
12791 Py_END_ALLOW_THREADS
12792 } while (result == EINTR && !(async_err = PyErr_CheckSignals()));
12793
12794 if (result == 0)
12795 Py_RETURN_NONE;
12796
12797 if (async_err)
12798 return NULL;
12799
12800 errno = result;
12801 return posix_error();
12802 }
12803 #endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG && !defined(__wasi__) */
12804
12805
12806 #if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG)
12807 /*[clinic input]
12808 os.posix_fadvise
12809
12810 fd: int
12811 offset: Py_off_t
12812 length: Py_off_t
12813 advice: int
12814 /
12815
12816 Announce an intention to access data in a specific pattern.
12817
12818 Announce an intention to access data in a specific pattern, thus allowing
12819 the kernel to make optimizations.
12820 The advice applies to the region of the file specified by fd starting at
12821 offset and continuing for length bytes.
12822 advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,
12823 POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED, or
12824 POSIX_FADV_DONTNEED.
12825 [clinic start generated code]*/
12826
12827 static PyObject *
os_posix_fadvise_impl(PyObject * module,int fd,Py_off_t offset,Py_off_t length,int advice)12828 os_posix_fadvise_impl(PyObject *module, int fd, Py_off_t offset,
12829 Py_off_t length, int advice)
12830 /*[clinic end generated code: output=412ef4aa70c98642 input=0fbe554edc2f04b5]*/
12831 {
12832 int result;
12833 int async_err = 0;
12834
12835 do {
12836 Py_BEGIN_ALLOW_THREADS
12837 result = posix_fadvise(fd, offset, length, advice);
12838 Py_END_ALLOW_THREADS
12839 } while (result == EINTR && !(async_err = PyErr_CheckSignals()));
12840
12841 if (result == 0)
12842 Py_RETURN_NONE;
12843
12844 if (async_err)
12845 return NULL;
12846
12847 errno = result;
12848 return posix_error();
12849 }
12850 #endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */
12851
12852
12853 #ifdef MS_WINDOWS
12854 static PyObject*
win32_putenv(PyObject * name,PyObject * value)12855 win32_putenv(PyObject *name, PyObject *value)
12856 {
12857 /* Search from index 1 because on Windows starting '=' is allowed for
12858 defining hidden environment variables. */
12859 if (PyUnicode_GET_LENGTH(name) == 0 ||
12860 PyUnicode_FindChar(name, '=', 1, PyUnicode_GET_LENGTH(name), 1) != -1)
12861 {
12862 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
12863 return NULL;
12864 }
12865 PyObject *unicode;
12866 if (value != NULL) {
12867 unicode = PyUnicode_FromFormat("%U=%U", name, value);
12868 }
12869 else {
12870 unicode = PyUnicode_FromFormat("%U=", name);
12871 }
12872 if (unicode == NULL) {
12873 return NULL;
12874 }
12875
12876 Py_ssize_t size;
12877 wchar_t *env = PyUnicode_AsWideCharString(unicode, &size);
12878 Py_DECREF(unicode);
12879
12880 if (env == NULL) {
12881 return NULL;
12882 }
12883 if (size > _MAX_ENV) {
12884 PyErr_Format(PyExc_ValueError,
12885 "the environment variable is longer than %u characters",
12886 _MAX_ENV);
12887 PyMem_Free(env);
12888 return NULL;
12889 }
12890 if (wcslen(env) != (size_t)size) {
12891 PyErr_SetString(PyExc_ValueError,
12892 "embedded null character");
12893 PyMem_Free(env);
12894 return NULL;
12895 }
12896
12897 /* _wputenv() and SetEnvironmentVariableW() update the environment in the
12898 Process Environment Block (PEB). _wputenv() also updates CRT 'environ'
12899 and '_wenviron' variables, whereas SetEnvironmentVariableW() does not.
12900
12901 Prefer _wputenv() to be compatible with C libraries using CRT
12902 variables and CRT functions using these variables (ex: getenv()). */
12903 int err = _wputenv(env);
12904
12905 if (err) {
12906 posix_error();
12907 PyMem_Free(env);
12908 return NULL;
12909 }
12910 PyMem_Free(env);
12911
12912 Py_RETURN_NONE;
12913 }
12914 #endif
12915
12916
12917 #ifdef MS_WINDOWS
12918 /*[clinic input]
12919 os.putenv
12920
12921 name: unicode
12922 value: unicode
12923 /
12924
12925 Change or add an environment variable.
12926 [clinic start generated code]*/
12927
12928 static PyObject *
os_putenv_impl(PyObject * module,PyObject * name,PyObject * value)12929 os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
12930 /*[clinic end generated code: output=d29a567d6b2327d2 input=ba586581c2e6105f]*/
12931 {
12932 if (PySys_Audit("os.putenv", "OO", name, value) < 0) {
12933 return NULL;
12934 }
12935 return win32_putenv(name, value);
12936 }
12937 #else
12938 /*[clinic input]
12939 os.putenv
12940
12941 name: FSConverter
12942 value: FSConverter
12943 /
12944
12945 Change or add an environment variable.
12946 [clinic start generated code]*/
12947
12948 static PyObject *
os_putenv_impl(PyObject * module,PyObject * name,PyObject * value)12949 os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
12950 /*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/
12951 {
12952 const char *name_string = PyBytes_AS_STRING(name);
12953 const char *value_string = PyBytes_AS_STRING(value);
12954
12955 if (strchr(name_string, '=') != NULL) {
12956 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
12957 return NULL;
12958 }
12959
12960 if (PySys_Audit("os.putenv", "OO", name, value) < 0) {
12961 return NULL;
12962 }
12963
12964 if (setenv(name_string, value_string, 1)) {
12965 return posix_error();
12966 }
12967 Py_RETURN_NONE;
12968 }
12969 #endif /* !defined(MS_WINDOWS) */
12970
12971
12972 #ifdef MS_WINDOWS
12973 /*[clinic input]
12974 os.unsetenv
12975 name: unicode
12976 /
12977
12978 Delete an environment variable.
12979 [clinic start generated code]*/
12980
12981 static PyObject *
os_unsetenv_impl(PyObject * module,PyObject * name)12982 os_unsetenv_impl(PyObject *module, PyObject *name)
12983 /*[clinic end generated code: output=54c4137ab1834f02 input=4d6a1747cc526d2f]*/
12984 {
12985 if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
12986 return NULL;
12987 }
12988 return win32_putenv(name, NULL);
12989 }
12990 #else
12991 /*[clinic input]
12992 os.unsetenv
12993 name: FSConverter
12994 /
12995
12996 Delete an environment variable.
12997 [clinic start generated code]*/
12998
12999 static PyObject *
os_unsetenv_impl(PyObject * module,PyObject * name)13000 os_unsetenv_impl(PyObject *module, PyObject *name)
13001 /*[clinic end generated code: output=54c4137ab1834f02 input=2bb5288a599c7107]*/
13002 {
13003 if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
13004 return NULL;
13005 }
13006 #ifdef HAVE_BROKEN_UNSETENV
13007 unsetenv(PyBytes_AS_STRING(name));
13008 #else
13009 int err = unsetenv(PyBytes_AS_STRING(name));
13010 if (err) {
13011 return posix_error();
13012 }
13013 #endif
13014
13015 Py_RETURN_NONE;
13016 }
13017 #endif /* !MS_WINDOWS */
13018
13019
13020 /*[clinic input]
13021 os.strerror
13022
13023 code: int
13024 /
13025
13026 Translate an error code to a message string.
13027 [clinic start generated code]*/
13028
13029 static PyObject *
os_strerror_impl(PyObject * module,int code)13030 os_strerror_impl(PyObject *module, int code)
13031 /*[clinic end generated code: output=baebf09fa02a78f2 input=75a8673d97915a91]*/
13032 {
13033 char *message = strerror(code);
13034 if (message == NULL) {
13035 PyErr_SetString(PyExc_ValueError,
13036 "strerror() argument out of range");
13037 return NULL;
13038 }
13039 return PyUnicode_DecodeLocale(message, "surrogateescape");
13040 }
13041
13042
13043 #ifdef HAVE_SYS_WAIT_H
13044 #ifdef WCOREDUMP
13045 /*[clinic input]
13046 os.WCOREDUMP -> bool
13047
13048 status: int
13049 /
13050
13051 Return True if the process returning status was dumped to a core file.
13052 [clinic start generated code]*/
13053
13054 static int
os_WCOREDUMP_impl(PyObject * module,int status)13055 os_WCOREDUMP_impl(PyObject *module, int status)
13056 /*[clinic end generated code: output=1a584b147b16bd18 input=8b05e7ab38528d04]*/
13057 {
13058 WAIT_TYPE wait_status;
13059 WAIT_STATUS_INT(wait_status) = status;
13060 return WCOREDUMP(wait_status);
13061 }
13062 #endif /* WCOREDUMP */
13063
13064
13065 #ifdef WIFCONTINUED
13066 /*[clinic input]
13067 os.WIFCONTINUED -> bool
13068
13069 status: int
13070
13071 Return True if a particular process was continued from a job control stop.
13072
13073 Return True if the process returning status was continued from a
13074 job control stop.
13075 [clinic start generated code]*/
13076
13077 static int
os_WIFCONTINUED_impl(PyObject * module,int status)13078 os_WIFCONTINUED_impl(PyObject *module, int status)
13079 /*[clinic end generated code: output=1e35295d844364bd input=e777e7d38eb25bd9]*/
13080 {
13081 WAIT_TYPE wait_status;
13082 WAIT_STATUS_INT(wait_status) = status;
13083 return WIFCONTINUED(wait_status);
13084 }
13085 #endif /* WIFCONTINUED */
13086
13087
13088 #ifdef WIFSTOPPED
13089 /*[clinic input]
13090 os.WIFSTOPPED -> bool
13091
13092 status: int
13093
13094 Return True if the process returning status was stopped.
13095 [clinic start generated code]*/
13096
13097 static int
os_WIFSTOPPED_impl(PyObject * module,int status)13098 os_WIFSTOPPED_impl(PyObject *module, int status)
13099 /*[clinic end generated code: output=fdb57122a5c9b4cb input=043cb7f1289ef904]*/
13100 {
13101 WAIT_TYPE wait_status;
13102 WAIT_STATUS_INT(wait_status) = status;
13103 return WIFSTOPPED(wait_status);
13104 }
13105 #endif /* WIFSTOPPED */
13106
13107
13108 #ifdef WIFSIGNALED
13109 /*[clinic input]
13110 os.WIFSIGNALED -> bool
13111
13112 status: int
13113
13114 Return True if the process returning status was terminated by a signal.
13115 [clinic start generated code]*/
13116
13117 static int
os_WIFSIGNALED_impl(PyObject * module,int status)13118 os_WIFSIGNALED_impl(PyObject *module, int status)
13119 /*[clinic end generated code: output=d1dde4dcc819a5f5 input=d55ba7cc9ce5dc43]*/
13120 {
13121 WAIT_TYPE wait_status;
13122 WAIT_STATUS_INT(wait_status) = status;
13123 return WIFSIGNALED(wait_status);
13124 }
13125 #endif /* WIFSIGNALED */
13126
13127
13128 #ifdef WIFEXITED
13129 /*[clinic input]
13130 os.WIFEXITED -> bool
13131
13132 status: int
13133
13134 Return True if the process returning status exited via the exit() system call.
13135 [clinic start generated code]*/
13136
13137 static int
os_WIFEXITED_impl(PyObject * module,int status)13138 os_WIFEXITED_impl(PyObject *module, int status)
13139 /*[clinic end generated code: output=01c09d6ebfeea397 input=d63775a6791586c0]*/
13140 {
13141 WAIT_TYPE wait_status;
13142 WAIT_STATUS_INT(wait_status) = status;
13143 return WIFEXITED(wait_status);
13144 }
13145 #endif /* WIFEXITED */
13146
13147
13148 #ifdef WEXITSTATUS
13149 /*[clinic input]
13150 os.WEXITSTATUS -> int
13151
13152 status: int
13153
13154 Return the process return code from status.
13155 [clinic start generated code]*/
13156
13157 static int
os_WEXITSTATUS_impl(PyObject * module,int status)13158 os_WEXITSTATUS_impl(PyObject *module, int status)
13159 /*[clinic end generated code: output=6e3efbba11f6488d input=e1fb4944e377585b]*/
13160 {
13161 WAIT_TYPE wait_status;
13162 WAIT_STATUS_INT(wait_status) = status;
13163 return WEXITSTATUS(wait_status);
13164 }
13165 #endif /* WEXITSTATUS */
13166
13167
13168 #ifdef WTERMSIG
13169 /*[clinic input]
13170 os.WTERMSIG -> int
13171
13172 status: int
13173
13174 Return the signal that terminated the process that provided the status value.
13175 [clinic start generated code]*/
13176
13177 static int
os_WTERMSIG_impl(PyObject * module,int status)13178 os_WTERMSIG_impl(PyObject *module, int status)
13179 /*[clinic end generated code: output=172f7dfc8dcfc3ad input=727fd7f84ec3f243]*/
13180 {
13181 WAIT_TYPE wait_status;
13182 WAIT_STATUS_INT(wait_status) = status;
13183 return WTERMSIG(wait_status);
13184 }
13185 #endif /* WTERMSIG */
13186
13187
13188 #ifdef WSTOPSIG
13189 /*[clinic input]
13190 os.WSTOPSIG -> int
13191
13192 status: int
13193
13194 Return the signal that stopped the process that provided the status value.
13195 [clinic start generated code]*/
13196
13197 static int
os_WSTOPSIG_impl(PyObject * module,int status)13198 os_WSTOPSIG_impl(PyObject *module, int status)
13199 /*[clinic end generated code: output=0ab7586396f5d82b input=46ebf1d1b293c5c1]*/
13200 {
13201 WAIT_TYPE wait_status;
13202 WAIT_STATUS_INT(wait_status) = status;
13203 return WSTOPSIG(wait_status);
13204 }
13205 #endif /* WSTOPSIG */
13206 #endif /* HAVE_SYS_WAIT_H */
13207
13208
13209 #if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H)
13210 #ifdef _SCO_DS
13211 /* SCO OpenServer 5.0 and later requires _SVID3 before it reveals the
13212 needed definitions in sys/statvfs.h */
13213 #define _SVID3
13214 #endif
13215 #include <sys/statvfs.h>
13216
13217 #ifdef __APPLE__
13218 /* On macOS struct statvfs uses 32-bit integers for block counts,
13219 * resulting in overflow when filesystems are larger than 4TB. Therefore
13220 * os.statvfs is implemented in terms of statfs(2).
13221 */
13222
13223 static PyObject*
_pystatvfs_fromstructstatfs(PyObject * module,struct statfs st)13224 _pystatvfs_fromstructstatfs(PyObject *module, struct statfs st) {
13225 PyObject *StatVFSResultType = get_posix_state(module)->StatVFSResultType;
13226 PyObject *v = PyStructSequence_New((PyTypeObject *)StatVFSResultType);
13227 if (v == NULL) {
13228 return NULL;
13229 }
13230
13231 long flags = 0;
13232 if (st.f_flags & MNT_RDONLY) {
13233 flags |= ST_RDONLY;
13234 }
13235 if (st.f_flags & MNT_NOSUID) {
13236 flags |= ST_NOSUID;
13237 }
13238
13239 _Static_assert(sizeof(st.f_blocks) == sizeof(long long), "assuming large file");
13240
13241 #define SET_ITEM(SEQ, INDEX, EXPR) \
13242 do { \
13243 PyObject *obj = (EXPR); \
13244 if (obj == NULL) { \
13245 Py_DECREF((SEQ)); \
13246 return NULL; \
13247 } \
13248 PyStructSequence_SET_ITEM((SEQ), (INDEX), obj); \
13249 } while (0)
13250
13251 SET_ITEM(v, 0, PyLong_FromLong((long) st.f_iosize));
13252 SET_ITEM(v, 1, PyLong_FromLong((long) st.f_bsize));
13253 SET_ITEM(v, 2, PyLong_FromLongLong((long long) st.f_blocks));
13254 SET_ITEM(v, 3, PyLong_FromLongLong((long long) st.f_bfree));
13255 SET_ITEM(v, 4, PyLong_FromLongLong((long long) st.f_bavail));
13256 SET_ITEM(v, 5, PyLong_FromLongLong((long long) st.f_files));
13257 SET_ITEM(v, 6, PyLong_FromLongLong((long long) st.f_ffree));
13258 SET_ITEM(v, 7, PyLong_FromLongLong((long long) st.f_ffree));
13259 SET_ITEM(v, 8, PyLong_FromLong((long) flags));
13260
13261 SET_ITEM(v, 9, PyLong_FromLong((long) NAME_MAX));
13262 SET_ITEM(v, 10, PyLong_FromUnsignedLong(st.f_fsid.val[0]));
13263
13264 #undef SET_ITEM
13265
13266 return v;
13267 }
13268
13269 #else
13270
13271
13272
13273 static PyObject*
_pystatvfs_fromstructstatvfs(PyObject * module,struct statvfs st)13274 _pystatvfs_fromstructstatvfs(PyObject *module, struct statvfs st) {
13275 PyObject *StatVFSResultType = get_posix_state(module)->StatVFSResultType;
13276 PyObject *v = PyStructSequence_New((PyTypeObject *)StatVFSResultType);
13277 if (v == NULL)
13278 return NULL;
13279
13280 int pos = 0;
13281
13282 #define SET_RESULT(CALL) \
13283 do { \
13284 PyObject *item = (CALL); \
13285 if (item == NULL) { \
13286 Py_DECREF(v); \
13287 return NULL; \
13288 } \
13289 PyStructSequence_SET_ITEM(v, pos++, item); \
13290 } while(0)
13291
13292 #if !defined(HAVE_LARGEFILE_SUPPORT)
13293 SET_RESULT(PyLong_FromLong((long) st.f_bsize));
13294 SET_RESULT(PyLong_FromLong((long) st.f_frsize));
13295 SET_RESULT(PyLong_FromLong((long) st.f_blocks));
13296 SET_RESULT(PyLong_FromLong((long) st.f_bfree));
13297 SET_RESULT(PyLong_FromLong((long) st.f_bavail));
13298 SET_RESULT(PyLong_FromLong((long) st.f_files));
13299 SET_RESULT(PyLong_FromLong((long) st.f_ffree));
13300 SET_RESULT(PyLong_FromLong((long) st.f_favail));
13301 SET_RESULT(PyLong_FromLong((long) st.f_flag));
13302 SET_RESULT(PyLong_FromLong((long) st.f_namemax));
13303 #else
13304 SET_RESULT(PyLong_FromLong((long) st.f_bsize));
13305 SET_RESULT(PyLong_FromLong((long) st.f_frsize));
13306 SET_RESULT(PyLong_FromLongLong((long long) st.f_blocks));
13307 SET_RESULT(PyLong_FromLongLong((long long) st.f_bfree));
13308 SET_RESULT(PyLong_FromLongLong((long long) st.f_bavail));
13309 SET_RESULT(PyLong_FromLongLong((long long) st.f_files));
13310 SET_RESULT(PyLong_FromLongLong((long long) st.f_ffree));
13311 SET_RESULT(PyLong_FromLongLong((long long) st.f_favail));
13312 SET_RESULT(PyLong_FromLong((long) st.f_flag));
13313 SET_RESULT(PyLong_FromLong((long) st.f_namemax));
13314 #endif
13315 /* The _ALL_SOURCE feature test macro defines f_fsid as a structure
13316 * (issue #32390). */
13317 #if defined(_AIX) && defined(_ALL_SOURCE)
13318 SET_RESULT(PyLong_FromUnsignedLong(st.f_fsid.val[0]));
13319 #else
13320 SET_RESULT(PyLong_FromUnsignedLong(st.f_fsid));
13321 #endif
13322
13323 #undef SET_RESULT
13324
13325 return v;
13326 }
13327
13328 #endif
13329
13330
13331 /*[clinic input]
13332 os.fstatvfs
13333 fd: int
13334 /
13335
13336 Perform an fstatvfs system call on the given fd.
13337
13338 Equivalent to statvfs(fd).
13339 [clinic start generated code]*/
13340
13341 static PyObject *
os_fstatvfs_impl(PyObject * module,int fd)13342 os_fstatvfs_impl(PyObject *module, int fd)
13343 /*[clinic end generated code: output=53547cf0cc55e6c5 input=d8122243ac50975e]*/
13344 {
13345 int result;
13346 int async_err = 0;
13347 #ifdef __APPLE__
13348 struct statfs st;
13349 /* On macOS os.fstatvfs is implemented using fstatfs(2) because
13350 * the former uses 32-bit values for block counts.
13351 */
13352 do {
13353 Py_BEGIN_ALLOW_THREADS
13354 result = fstatfs(fd, &st);
13355 Py_END_ALLOW_THREADS
13356 } while (result != 0 && errno == EINTR &&
13357 !(async_err = PyErr_CheckSignals()));
13358 if (result != 0)
13359 return (!async_err) ? posix_error() : NULL;
13360
13361 return _pystatvfs_fromstructstatfs(module, st);
13362 #else
13363 struct statvfs st;
13364
13365 do {
13366 Py_BEGIN_ALLOW_THREADS
13367 result = fstatvfs(fd, &st);
13368 Py_END_ALLOW_THREADS
13369 } while (result != 0 && errno == EINTR &&
13370 !(async_err = PyErr_CheckSignals()));
13371 if (result != 0)
13372 return (!async_err) ? posix_error() : NULL;
13373
13374 return _pystatvfs_fromstructstatvfs(module, st);
13375 #endif
13376 }
13377 #endif /* defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) */
13378
13379
13380 #if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
13381 #include <sys/statvfs.h>
13382 /*[clinic input]
13383 os.statvfs
13384
13385 path: path_t(allow_fd='PATH_HAVE_FSTATVFS')
13386
13387 Perform a statvfs system call on the given path.
13388
13389 path may always be specified as a string.
13390 On some platforms, path may also be specified as an open file descriptor.
13391 If this functionality is unavailable, using it raises an exception.
13392 [clinic start generated code]*/
13393
13394 static PyObject *
os_statvfs_impl(PyObject * module,path_t * path)13395 os_statvfs_impl(PyObject *module, path_t *path)
13396 /*[clinic end generated code: output=87106dd1beb8556e input=3f5c35791c669bd9]*/
13397 {
13398 int result;
13399
13400 #ifdef __APPLE__
13401 /* On macOS os.statvfs is implemented using statfs(2)/fstatfs(2) because
13402 * the former uses 32-bit values for block counts.
13403 */
13404 struct statfs st;
13405
13406 Py_BEGIN_ALLOW_THREADS
13407 if (path->fd != -1) {
13408 result = fstatfs(path->fd, &st);
13409 }
13410 else
13411 result = statfs(path->narrow, &st);
13412 Py_END_ALLOW_THREADS
13413
13414 if (result) {
13415 return path_error(path);
13416 }
13417
13418 return _pystatvfs_fromstructstatfs(module, st);
13419
13420 #else
13421 struct statvfs st;
13422
13423 Py_BEGIN_ALLOW_THREADS
13424 #ifdef HAVE_FSTATVFS
13425 if (path->fd != -1) {
13426 result = fstatvfs(path->fd, &st);
13427 }
13428 else
13429 #endif
13430 result = statvfs(path->narrow, &st);
13431 Py_END_ALLOW_THREADS
13432
13433 if (result) {
13434 return path_error(path);
13435 }
13436
13437 return _pystatvfs_fromstructstatvfs(module, st);
13438 #endif
13439 }
13440 #endif /* defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) */
13441
13442
13443 #ifdef MS_WINDOWS
13444 /*[clinic input]
13445 os._getdiskusage
13446
13447 path: path_t
13448
13449 Return disk usage statistics about the given path as a (total, free) tuple.
13450 [clinic start generated code]*/
13451
13452 static PyObject *
os__getdiskusage_impl(PyObject * module,path_t * path)13453 os__getdiskusage_impl(PyObject *module, path_t *path)
13454 /*[clinic end generated code: output=3bd3991f5e5c5dfb input=6af8d1b7781cc042]*/
13455 {
13456 BOOL retval;
13457 ULARGE_INTEGER _, total, free;
13458 DWORD err = 0;
13459
13460 Py_BEGIN_ALLOW_THREADS
13461 retval = GetDiskFreeSpaceExW(path->wide, &_, &total, &free);
13462 Py_END_ALLOW_THREADS
13463 if (retval == 0) {
13464 if (GetLastError() == ERROR_DIRECTORY) {
13465 wchar_t *dir_path = NULL;
13466
13467 dir_path = PyMem_New(wchar_t, path->length + 1);
13468 if (dir_path == NULL) {
13469 return PyErr_NoMemory();
13470 }
13471
13472 wcscpy_s(dir_path, path->length + 1, path->wide);
13473
13474 if (_dirnameW(dir_path) != -1) {
13475 Py_BEGIN_ALLOW_THREADS
13476 retval = GetDiskFreeSpaceExW(dir_path, &_, &total, &free);
13477 Py_END_ALLOW_THREADS
13478 }
13479 /* Record the last error in case it's modified by PyMem_Free. */
13480 err = GetLastError();
13481 PyMem_Free(dir_path);
13482 if (retval) {
13483 goto success;
13484 }
13485 }
13486 return PyErr_SetFromWindowsErr(err);
13487 }
13488
13489 success:
13490 return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
13491 }
13492 #endif /* MS_WINDOWS */
13493
13494
13495 /* This is used for fpathconf(), pathconf(), confstr() and sysconf().
13496 * It maps strings representing configuration variable names to
13497 * integer values, allowing those functions to be called with the
13498 * magic names instead of polluting the module's namespace with tons of
13499 * rarely-used constants. There are three separate tables that use
13500 * these definitions.
13501 *
13502 * This code is always included, even if none of the interfaces that
13503 * need it are included. The #if hackery needed to avoid it would be
13504 * sufficiently pervasive that it's not worth the loss of readability.
13505 */
13506 struct constdef {
13507 const char *name;
13508 int value;
13509 };
13510
13511 static int
conv_confname(PyObject * arg,int * valuep,struct constdef * table,size_t tablesize)13512 conv_confname(PyObject *arg, int *valuep, struct constdef *table,
13513 size_t tablesize)
13514 {
13515 if (PyLong_Check(arg)) {
13516 int value = PyLong_AsInt(arg);
13517 if (value == -1 && PyErr_Occurred())
13518 return 0;
13519 *valuep = value;
13520 return 1;
13521 }
13522 else {
13523 /* look up the value in the table using a binary search */
13524 size_t lo = 0;
13525 size_t mid;
13526 size_t hi = tablesize;
13527 int cmp;
13528 const char *confname;
13529 if (!PyUnicode_Check(arg)) {
13530 PyErr_SetString(PyExc_TypeError,
13531 "configuration names must be strings or integers");
13532 return 0;
13533 }
13534 confname = PyUnicode_AsUTF8(arg);
13535 if (confname == NULL)
13536 return 0;
13537 while (lo < hi) {
13538 mid = (lo + hi) / 2;
13539 cmp = strcmp(confname, table[mid].name);
13540 if (cmp < 0)
13541 hi = mid;
13542 else if (cmp > 0)
13543 lo = mid + 1;
13544 else {
13545 *valuep = table[mid].value;
13546 return 1;
13547 }
13548 }
13549 PyErr_SetString(PyExc_ValueError, "unrecognized configuration name");
13550 return 0;
13551 }
13552 }
13553
13554
13555 #if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
13556 static struct constdef posix_constants_pathconf[] = {
13557 #ifdef _PC_ABI_AIO_XFER_MAX
13558 {"PC_ABI_AIO_XFER_MAX", _PC_ABI_AIO_XFER_MAX},
13559 #endif
13560 #ifdef _PC_ABI_ASYNC_IO
13561 {"PC_ABI_ASYNC_IO", _PC_ABI_ASYNC_IO},
13562 #endif
13563 #ifdef _PC_ASYNC_IO
13564 {"PC_ASYNC_IO", _PC_ASYNC_IO},
13565 #endif
13566 #ifdef _PC_CHOWN_RESTRICTED
13567 {"PC_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED},
13568 #endif
13569 #ifdef _PC_FILESIZEBITS
13570 {"PC_FILESIZEBITS", _PC_FILESIZEBITS},
13571 #endif
13572 #ifdef _PC_LAST
13573 {"PC_LAST", _PC_LAST},
13574 #endif
13575 #ifdef _PC_LINK_MAX
13576 {"PC_LINK_MAX", _PC_LINK_MAX},
13577 #endif
13578 #ifdef _PC_MAX_CANON
13579 {"PC_MAX_CANON", _PC_MAX_CANON},
13580 #endif
13581 #ifdef _PC_MAX_INPUT
13582 {"PC_MAX_INPUT", _PC_MAX_INPUT},
13583 #endif
13584 #ifdef _PC_NAME_MAX
13585 {"PC_NAME_MAX", _PC_NAME_MAX},
13586 #endif
13587 #ifdef _PC_NO_TRUNC
13588 {"PC_NO_TRUNC", _PC_NO_TRUNC},
13589 #endif
13590 #ifdef _PC_PATH_MAX
13591 {"PC_PATH_MAX", _PC_PATH_MAX},
13592 #endif
13593 #ifdef _PC_PIPE_BUF
13594 {"PC_PIPE_BUF", _PC_PIPE_BUF},
13595 #endif
13596 #ifdef _PC_PRIO_IO
13597 {"PC_PRIO_IO", _PC_PRIO_IO},
13598 #endif
13599 #ifdef _PC_SOCK_MAXBUF
13600 {"PC_SOCK_MAXBUF", _PC_SOCK_MAXBUF},
13601 #endif
13602 #ifdef _PC_SYNC_IO
13603 {"PC_SYNC_IO", _PC_SYNC_IO},
13604 #endif
13605 #ifdef _PC_VDISABLE
13606 {"PC_VDISABLE", _PC_VDISABLE},
13607 #endif
13608 #ifdef _PC_ACL_ENABLED
13609 {"PC_ACL_ENABLED", _PC_ACL_ENABLED},
13610 #endif
13611 #ifdef _PC_MIN_HOLE_SIZE
13612 {"PC_MIN_HOLE_SIZE", _PC_MIN_HOLE_SIZE},
13613 #endif
13614 #ifdef _PC_ALLOC_SIZE_MIN
13615 {"PC_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN},
13616 #endif
13617 #ifdef _PC_REC_INCR_XFER_SIZE
13618 {"PC_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE},
13619 #endif
13620 #ifdef _PC_REC_MAX_XFER_SIZE
13621 {"PC_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE},
13622 #endif
13623 #ifdef _PC_REC_MIN_XFER_SIZE
13624 {"PC_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE},
13625 #endif
13626 #ifdef _PC_REC_XFER_ALIGN
13627 {"PC_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN},
13628 #endif
13629 #ifdef _PC_SYMLINK_MAX
13630 {"PC_SYMLINK_MAX", _PC_SYMLINK_MAX},
13631 #endif
13632 #ifdef _PC_XATTR_ENABLED
13633 {"PC_XATTR_ENABLED", _PC_XATTR_ENABLED},
13634 #endif
13635 #ifdef _PC_XATTR_EXISTS
13636 {"PC_XATTR_EXISTS", _PC_XATTR_EXISTS},
13637 #endif
13638 #ifdef _PC_TIMESTAMP_RESOLUTION
13639 {"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
13640 #endif
13641 };
13642
13643 static int
conv_path_confname(PyObject * arg,int * valuep)13644 conv_path_confname(PyObject *arg, int *valuep)
13645 {
13646 return conv_confname(arg, valuep, posix_constants_pathconf,
13647 sizeof(posix_constants_pathconf)
13648 / sizeof(struct constdef));
13649 }
13650 #endif
13651
13652
13653 #ifdef HAVE_FPATHCONF
13654 /*[clinic input]
13655 os.fpathconf -> long
13656
13657 fd: fildes
13658 name: path_confname
13659 /
13660
13661 Return the configuration limit name for the file descriptor fd.
13662
13663 If there is no limit, return -1.
13664 [clinic start generated code]*/
13665
13666 static long
os_fpathconf_impl(PyObject * module,int fd,int name)13667 os_fpathconf_impl(PyObject *module, int fd, int name)
13668 /*[clinic end generated code: output=d5b7042425fc3e21 input=5b8d2471cfaae186]*/
13669 {
13670 long limit;
13671
13672 errno = 0;
13673 limit = fpathconf(fd, name);
13674 if (limit == -1 && errno != 0)
13675 posix_error();
13676
13677 return limit;
13678 }
13679 #endif /* HAVE_FPATHCONF */
13680
13681
13682 #ifdef HAVE_PATHCONF
13683 /*[clinic input]
13684 os.pathconf -> long
13685 path: path_t(allow_fd='PATH_HAVE_FPATHCONF')
13686 name: path_confname
13687
13688 Return the configuration limit name for the file or directory path.
13689
13690 If there is no limit, return -1.
13691 On some platforms, path may also be specified as an open file descriptor.
13692 If this functionality is unavailable, using it raises an exception.
13693 [clinic start generated code]*/
13694
13695 static long
os_pathconf_impl(PyObject * module,path_t * path,int name)13696 os_pathconf_impl(PyObject *module, path_t *path, int name)
13697 /*[clinic end generated code: output=5bedee35b293a089 input=bc3e2a985af27e5e]*/
13698 {
13699 long limit;
13700
13701 errno = 0;
13702 #ifdef HAVE_FPATHCONF
13703 if (path->fd != -1)
13704 limit = fpathconf(path->fd, name);
13705 else
13706 #endif
13707 limit = pathconf(path->narrow, name);
13708 if (limit == -1 && errno != 0) {
13709 if (errno == EINVAL)
13710 /* could be a path or name problem */
13711 posix_error();
13712 else
13713 path_error(path);
13714 }
13715
13716 return limit;
13717 }
13718 #endif /* HAVE_PATHCONF */
13719
13720 #ifdef HAVE_CONFSTR
13721 static struct constdef posix_constants_confstr[] = {
13722 #ifdef _CS_ARCHITECTURE
13723 {"CS_ARCHITECTURE", _CS_ARCHITECTURE},
13724 #endif
13725 #ifdef _CS_GNU_LIBC_VERSION
13726 {"CS_GNU_LIBC_VERSION", _CS_GNU_LIBC_VERSION},
13727 #endif
13728 #ifdef _CS_GNU_LIBPTHREAD_VERSION
13729 {"CS_GNU_LIBPTHREAD_VERSION", _CS_GNU_LIBPTHREAD_VERSION},
13730 #endif
13731 #ifdef _CS_HOSTNAME
13732 {"CS_HOSTNAME", _CS_HOSTNAME},
13733 #endif
13734 #ifdef _CS_HW_PROVIDER
13735 {"CS_HW_PROVIDER", _CS_HW_PROVIDER},
13736 #endif
13737 #ifdef _CS_HW_SERIAL
13738 {"CS_HW_SERIAL", _CS_HW_SERIAL},
13739 #endif
13740 #ifdef _CS_INITTAB_NAME
13741 {"CS_INITTAB_NAME", _CS_INITTAB_NAME},
13742 #endif
13743 #ifdef _CS_LFS64_CFLAGS
13744 {"CS_LFS64_CFLAGS", _CS_LFS64_CFLAGS},
13745 #endif
13746 #ifdef _CS_LFS64_LDFLAGS
13747 {"CS_LFS64_LDFLAGS", _CS_LFS64_LDFLAGS},
13748 #endif
13749 #ifdef _CS_LFS64_LIBS
13750 {"CS_LFS64_LIBS", _CS_LFS64_LIBS},
13751 #endif
13752 #ifdef _CS_LFS64_LINTFLAGS
13753 {"CS_LFS64_LINTFLAGS", _CS_LFS64_LINTFLAGS},
13754 #endif
13755 #ifdef _CS_LFS_CFLAGS
13756 {"CS_LFS_CFLAGS", _CS_LFS_CFLAGS},
13757 #endif
13758 #ifdef _CS_LFS_LDFLAGS
13759 {"CS_LFS_LDFLAGS", _CS_LFS_LDFLAGS},
13760 #endif
13761 #ifdef _CS_LFS_LIBS
13762 {"CS_LFS_LIBS", _CS_LFS_LIBS},
13763 #endif
13764 #ifdef _CS_LFS_LINTFLAGS
13765 {"CS_LFS_LINTFLAGS", _CS_LFS_LINTFLAGS},
13766 #endif
13767 #ifdef _CS_MACHINE
13768 {"CS_MACHINE", _CS_MACHINE},
13769 #endif
13770 #ifdef _CS_PATH
13771 {"CS_PATH", _CS_PATH},
13772 #endif
13773 #ifdef _CS_RELEASE
13774 {"CS_RELEASE", _CS_RELEASE},
13775 #endif
13776 #ifdef _CS_SRPC_DOMAIN
13777 {"CS_SRPC_DOMAIN", _CS_SRPC_DOMAIN},
13778 #endif
13779 #ifdef _CS_SYSNAME
13780 {"CS_SYSNAME", _CS_SYSNAME},
13781 #endif
13782 #ifdef _CS_VERSION
13783 {"CS_VERSION", _CS_VERSION},
13784 #endif
13785 #ifdef _CS_XBS5_ILP32_OFF32_CFLAGS
13786 {"CS_XBS5_ILP32_OFF32_CFLAGS", _CS_XBS5_ILP32_OFF32_CFLAGS},
13787 #endif
13788 #ifdef _CS_XBS5_ILP32_OFF32_LDFLAGS
13789 {"CS_XBS5_ILP32_OFF32_LDFLAGS", _CS_XBS5_ILP32_OFF32_LDFLAGS},
13790 #endif
13791 #ifdef _CS_XBS5_ILP32_OFF32_LIBS
13792 {"CS_XBS5_ILP32_OFF32_LIBS", _CS_XBS5_ILP32_OFF32_LIBS},
13793 #endif
13794 #ifdef _CS_XBS5_ILP32_OFF32_LINTFLAGS
13795 {"CS_XBS5_ILP32_OFF32_LINTFLAGS", _CS_XBS5_ILP32_OFF32_LINTFLAGS},
13796 #endif
13797 #ifdef _CS_XBS5_ILP32_OFFBIG_CFLAGS
13798 {"CS_XBS5_ILP32_OFFBIG_CFLAGS", _CS_XBS5_ILP32_OFFBIG_CFLAGS},
13799 #endif
13800 #ifdef _CS_XBS5_ILP32_OFFBIG_LDFLAGS
13801 {"CS_XBS5_ILP32_OFFBIG_LDFLAGS", _CS_XBS5_ILP32_OFFBIG_LDFLAGS},
13802 #endif
13803 #ifdef _CS_XBS5_ILP32_OFFBIG_LIBS
13804 {"CS_XBS5_ILP32_OFFBIG_LIBS", _CS_XBS5_ILP32_OFFBIG_LIBS},
13805 #endif
13806 #ifdef _CS_XBS5_ILP32_OFFBIG_LINTFLAGS
13807 {"CS_XBS5_ILP32_OFFBIG_LINTFLAGS", _CS_XBS5_ILP32_OFFBIG_LINTFLAGS},
13808 #endif
13809 #ifdef _CS_XBS5_LP64_OFF64_CFLAGS
13810 {"CS_XBS5_LP64_OFF64_CFLAGS", _CS_XBS5_LP64_OFF64_CFLAGS},
13811 #endif
13812 #ifdef _CS_XBS5_LP64_OFF64_LDFLAGS
13813 {"CS_XBS5_LP64_OFF64_LDFLAGS", _CS_XBS5_LP64_OFF64_LDFLAGS},
13814 #endif
13815 #ifdef _CS_XBS5_LP64_OFF64_LIBS
13816 {"CS_XBS5_LP64_OFF64_LIBS", _CS_XBS5_LP64_OFF64_LIBS},
13817 #endif
13818 #ifdef _CS_XBS5_LP64_OFF64_LINTFLAGS
13819 {"CS_XBS5_LP64_OFF64_LINTFLAGS", _CS_XBS5_LP64_OFF64_LINTFLAGS},
13820 #endif
13821 #ifdef _CS_XBS5_LPBIG_OFFBIG_CFLAGS
13822 {"CS_XBS5_LPBIG_OFFBIG_CFLAGS", _CS_XBS5_LPBIG_OFFBIG_CFLAGS},
13823 #endif
13824 #ifdef _CS_XBS5_LPBIG_OFFBIG_LDFLAGS
13825 {"CS_XBS5_LPBIG_OFFBIG_LDFLAGS", _CS_XBS5_LPBIG_OFFBIG_LDFLAGS},
13826 #endif
13827 #ifdef _CS_XBS5_LPBIG_OFFBIG_LIBS
13828 {"CS_XBS5_LPBIG_OFFBIG_LIBS", _CS_XBS5_LPBIG_OFFBIG_LIBS},
13829 #endif
13830 #ifdef _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS
13831 {"CS_XBS5_LPBIG_OFFBIG_LINTFLAGS", _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS},
13832 #endif
13833 #ifdef _MIPS_CS_AVAIL_PROCESSORS
13834 {"MIPS_CS_AVAIL_PROCESSORS", _MIPS_CS_AVAIL_PROCESSORS},
13835 #endif
13836 #ifdef _MIPS_CS_BASE
13837 {"MIPS_CS_BASE", _MIPS_CS_BASE},
13838 #endif
13839 #ifdef _MIPS_CS_HOSTID
13840 {"MIPS_CS_HOSTID", _MIPS_CS_HOSTID},
13841 #endif
13842 #ifdef _MIPS_CS_HW_NAME
13843 {"MIPS_CS_HW_NAME", _MIPS_CS_HW_NAME},
13844 #endif
13845 #ifdef _MIPS_CS_NUM_PROCESSORS
13846 {"MIPS_CS_NUM_PROCESSORS", _MIPS_CS_NUM_PROCESSORS},
13847 #endif
13848 #ifdef _MIPS_CS_OSREL_MAJ
13849 {"MIPS_CS_OSREL_MAJ", _MIPS_CS_OSREL_MAJ},
13850 #endif
13851 #ifdef _MIPS_CS_OSREL_MIN
13852 {"MIPS_CS_OSREL_MIN", _MIPS_CS_OSREL_MIN},
13853 #endif
13854 #ifdef _MIPS_CS_OSREL_PATCH
13855 {"MIPS_CS_OSREL_PATCH", _MIPS_CS_OSREL_PATCH},
13856 #endif
13857 #ifdef _MIPS_CS_OS_NAME
13858 {"MIPS_CS_OS_NAME", _MIPS_CS_OS_NAME},
13859 #endif
13860 #ifdef _MIPS_CS_OS_PROVIDER
13861 {"MIPS_CS_OS_PROVIDER", _MIPS_CS_OS_PROVIDER},
13862 #endif
13863 #ifdef _MIPS_CS_PROCESSORS
13864 {"MIPS_CS_PROCESSORS", _MIPS_CS_PROCESSORS},
13865 #endif
13866 #ifdef _MIPS_CS_SERIAL
13867 {"MIPS_CS_SERIAL", _MIPS_CS_SERIAL},
13868 #endif
13869 #ifdef _MIPS_CS_VENDOR
13870 {"MIPS_CS_VENDOR", _MIPS_CS_VENDOR},
13871 #endif
13872 };
13873
13874 static int
conv_confstr_confname(PyObject * arg,int * valuep)13875 conv_confstr_confname(PyObject *arg, int *valuep)
13876 {
13877 return conv_confname(arg, valuep, posix_constants_confstr,
13878 sizeof(posix_constants_confstr)
13879 / sizeof(struct constdef));
13880 }
13881
13882
13883 /*[clinic input]
13884 os.confstr
13885
13886 name: confstr_confname
13887 /
13888
13889 Return a string-valued system configuration variable.
13890 [clinic start generated code]*/
13891
13892 static PyObject *
os_confstr_impl(PyObject * module,int name)13893 os_confstr_impl(PyObject *module, int name)
13894 /*[clinic end generated code: output=bfb0b1b1e49b9383 input=18fb4d0567242e65]*/
13895 {
13896 PyObject *result = NULL;
13897 char buffer[255];
13898 size_t len;
13899
13900 errno = 0;
13901 len = confstr(name, buffer, sizeof(buffer));
13902 if (len == 0) {
13903 if (errno) {
13904 posix_error();
13905 return NULL;
13906 }
13907 else {
13908 Py_RETURN_NONE;
13909 }
13910 }
13911
13912 if (len >= sizeof(buffer)) {
13913 size_t len2;
13914 char *buf = PyMem_Malloc(len);
13915 if (buf == NULL)
13916 return PyErr_NoMemory();
13917 len2 = confstr(name, buf, len);
13918 assert(len == len2);
13919 result = PyUnicode_DecodeFSDefaultAndSize(buf, len2-1);
13920 PyMem_Free(buf);
13921 }
13922 else
13923 result = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
13924 return result;
13925 }
13926 #endif /* HAVE_CONFSTR */
13927
13928
13929 #ifdef HAVE_SYSCONF
13930 static struct constdef posix_constants_sysconf[] = {
13931 #ifdef _SC_2_CHAR_TERM
13932 {"SC_2_CHAR_TERM", _SC_2_CHAR_TERM},
13933 #endif
13934 #ifdef _SC_2_C_BIND
13935 {"SC_2_C_BIND", _SC_2_C_BIND},
13936 #endif
13937 #ifdef _SC_2_C_DEV
13938 {"SC_2_C_DEV", _SC_2_C_DEV},
13939 #endif
13940 #ifdef _SC_2_C_VERSION
13941 {"SC_2_C_VERSION", _SC_2_C_VERSION},
13942 #endif
13943 #ifdef _SC_2_FORT_DEV
13944 {"SC_2_FORT_DEV", _SC_2_FORT_DEV},
13945 #endif
13946 #ifdef _SC_2_FORT_RUN
13947 {"SC_2_FORT_RUN", _SC_2_FORT_RUN},
13948 #endif
13949 #ifdef _SC_2_LOCALEDEF
13950 {"SC_2_LOCALEDEF", _SC_2_LOCALEDEF},
13951 #endif
13952 #ifdef _SC_2_SW_DEV
13953 {"SC_2_SW_DEV", _SC_2_SW_DEV},
13954 #endif
13955 #ifdef _SC_2_UPE
13956 {"SC_2_UPE", _SC_2_UPE},
13957 #endif
13958 #ifdef _SC_2_VERSION
13959 {"SC_2_VERSION", _SC_2_VERSION},
13960 #endif
13961 #ifdef _SC_ABI_ASYNCHRONOUS_IO
13962 {"SC_ABI_ASYNCHRONOUS_IO", _SC_ABI_ASYNCHRONOUS_IO},
13963 #endif
13964 #ifdef _SC_ACL
13965 {"SC_ACL", _SC_ACL},
13966 #endif
13967 #ifdef _SC_AIO_LISTIO_MAX
13968 {"SC_AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX},
13969 #endif
13970 #ifdef _SC_AIO_MAX
13971 {"SC_AIO_MAX", _SC_AIO_MAX},
13972 #endif
13973 #ifdef _SC_AIO_PRIO_DELTA_MAX
13974 {"SC_AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX},
13975 #endif
13976 #ifdef _SC_ARG_MAX
13977 {"SC_ARG_MAX", _SC_ARG_MAX},
13978 #endif
13979 #ifdef _SC_ASYNCHRONOUS_IO
13980 {"SC_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO},
13981 #endif
13982 #ifdef _SC_ATEXIT_MAX
13983 {"SC_ATEXIT_MAX", _SC_ATEXIT_MAX},
13984 #endif
13985 #ifdef _SC_AUDIT
13986 {"SC_AUDIT", _SC_AUDIT},
13987 #endif
13988 #ifdef _SC_AVPHYS_PAGES
13989 {"SC_AVPHYS_PAGES", _SC_AVPHYS_PAGES},
13990 #endif
13991 #ifdef _SC_BC_BASE_MAX
13992 {"SC_BC_BASE_MAX", _SC_BC_BASE_MAX},
13993 #endif
13994 #ifdef _SC_BC_DIM_MAX
13995 {"SC_BC_DIM_MAX", _SC_BC_DIM_MAX},
13996 #endif
13997 #ifdef _SC_BC_SCALE_MAX
13998 {"SC_BC_SCALE_MAX", _SC_BC_SCALE_MAX},
13999 #endif
14000 #ifdef _SC_BC_STRING_MAX
14001 {"SC_BC_STRING_MAX", _SC_BC_STRING_MAX},
14002 #endif
14003 #ifdef _SC_CAP
14004 {"SC_CAP", _SC_CAP},
14005 #endif
14006 #ifdef _SC_CHARCLASS_NAME_MAX
14007 {"SC_CHARCLASS_NAME_MAX", _SC_CHARCLASS_NAME_MAX},
14008 #endif
14009 #ifdef _SC_CHAR_BIT
14010 {"SC_CHAR_BIT", _SC_CHAR_BIT},
14011 #endif
14012 #ifdef _SC_CHAR_MAX
14013 {"SC_CHAR_MAX", _SC_CHAR_MAX},
14014 #endif
14015 #ifdef _SC_CHAR_MIN
14016 {"SC_CHAR_MIN", _SC_CHAR_MIN},
14017 #endif
14018 #ifdef _SC_CHILD_MAX
14019 {"SC_CHILD_MAX", _SC_CHILD_MAX},
14020 #endif
14021 #ifdef _SC_CLK_TCK
14022 {"SC_CLK_TCK", _SC_CLK_TCK},
14023 #endif
14024 #ifdef _SC_COHER_BLKSZ
14025 {"SC_COHER_BLKSZ", _SC_COHER_BLKSZ},
14026 #endif
14027 #ifdef _SC_COLL_WEIGHTS_MAX
14028 {"SC_COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX},
14029 #endif
14030 #ifdef _SC_DCACHE_ASSOC
14031 {"SC_DCACHE_ASSOC", _SC_DCACHE_ASSOC},
14032 #endif
14033 #ifdef _SC_DCACHE_BLKSZ
14034 {"SC_DCACHE_BLKSZ", _SC_DCACHE_BLKSZ},
14035 #endif
14036 #ifdef _SC_DCACHE_LINESZ
14037 {"SC_DCACHE_LINESZ", _SC_DCACHE_LINESZ},
14038 #endif
14039 #ifdef _SC_DCACHE_SZ
14040 {"SC_DCACHE_SZ", _SC_DCACHE_SZ},
14041 #endif
14042 #ifdef _SC_DCACHE_TBLKSZ
14043 {"SC_DCACHE_TBLKSZ", _SC_DCACHE_TBLKSZ},
14044 #endif
14045 #ifdef _SC_DELAYTIMER_MAX
14046 {"SC_DELAYTIMER_MAX", _SC_DELAYTIMER_MAX},
14047 #endif
14048 #ifdef _SC_EQUIV_CLASS_MAX
14049 {"SC_EQUIV_CLASS_MAX", _SC_EQUIV_CLASS_MAX},
14050 #endif
14051 #ifdef _SC_EXPR_NEST_MAX
14052 {"SC_EXPR_NEST_MAX", _SC_EXPR_NEST_MAX},
14053 #endif
14054 #ifdef _SC_FSYNC
14055 {"SC_FSYNC", _SC_FSYNC},
14056 #endif
14057 #ifdef _SC_GETGR_R_SIZE_MAX
14058 {"SC_GETGR_R_SIZE_MAX", _SC_GETGR_R_SIZE_MAX},
14059 #endif
14060 #ifdef _SC_GETPW_R_SIZE_MAX
14061 {"SC_GETPW_R_SIZE_MAX", _SC_GETPW_R_SIZE_MAX},
14062 #endif
14063 #ifdef _SC_ICACHE_ASSOC
14064 {"SC_ICACHE_ASSOC", _SC_ICACHE_ASSOC},
14065 #endif
14066 #ifdef _SC_ICACHE_BLKSZ
14067 {"SC_ICACHE_BLKSZ", _SC_ICACHE_BLKSZ},
14068 #endif
14069 #ifdef _SC_ICACHE_LINESZ
14070 {"SC_ICACHE_LINESZ", _SC_ICACHE_LINESZ},
14071 #endif
14072 #ifdef _SC_ICACHE_SZ
14073 {"SC_ICACHE_SZ", _SC_ICACHE_SZ},
14074 #endif
14075 #ifdef _SC_INF
14076 {"SC_INF", _SC_INF},
14077 #endif
14078 #ifdef _SC_INT_MAX
14079 {"SC_INT_MAX", _SC_INT_MAX},
14080 #endif
14081 #ifdef _SC_INT_MIN
14082 {"SC_INT_MIN", _SC_INT_MIN},
14083 #endif
14084 #ifdef _SC_IOV_MAX
14085 {"SC_IOV_MAX", _SC_IOV_MAX},
14086 #endif
14087 #ifdef _SC_IP_SECOPTS
14088 {"SC_IP_SECOPTS", _SC_IP_SECOPTS},
14089 #endif
14090 #ifdef _SC_JOB_CONTROL
14091 {"SC_JOB_CONTROL", _SC_JOB_CONTROL},
14092 #endif
14093 #ifdef _SC_KERN_POINTERS
14094 {"SC_KERN_POINTERS", _SC_KERN_POINTERS},
14095 #endif
14096 #ifdef _SC_KERN_SIM
14097 {"SC_KERN_SIM", _SC_KERN_SIM},
14098 #endif
14099 #ifdef _SC_LINE_MAX
14100 {"SC_LINE_MAX", _SC_LINE_MAX},
14101 #endif
14102 #ifdef _SC_LOGIN_NAME_MAX
14103 {"SC_LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX},
14104 #endif
14105 #ifdef _SC_LOGNAME_MAX
14106 {"SC_LOGNAME_MAX", _SC_LOGNAME_MAX},
14107 #endif
14108 #ifdef _SC_LONG_BIT
14109 {"SC_LONG_BIT", _SC_LONG_BIT},
14110 #endif
14111 #ifdef _SC_MAC
14112 {"SC_MAC", _SC_MAC},
14113 #endif
14114 #ifdef _SC_MAPPED_FILES
14115 {"SC_MAPPED_FILES", _SC_MAPPED_FILES},
14116 #endif
14117 #ifdef _SC_MAXPID
14118 {"SC_MAXPID", _SC_MAXPID},
14119 #endif
14120 #ifdef _SC_MB_LEN_MAX
14121 {"SC_MB_LEN_MAX", _SC_MB_LEN_MAX},
14122 #endif
14123 #ifdef _SC_MEMLOCK
14124 {"SC_MEMLOCK", _SC_MEMLOCK},
14125 #endif
14126 #ifdef _SC_MEMLOCK_RANGE
14127 {"SC_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE},
14128 #endif
14129 #ifdef _SC_MEMORY_PROTECTION
14130 {"SC_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION},
14131 #endif
14132 #ifdef _SC_MESSAGE_PASSING
14133 {"SC_MESSAGE_PASSING", _SC_MESSAGE_PASSING},
14134 #endif
14135 #ifdef _SC_MMAP_FIXED_ALIGNMENT
14136 {"SC_MMAP_FIXED_ALIGNMENT", _SC_MMAP_FIXED_ALIGNMENT},
14137 #endif
14138 #ifdef _SC_MQ_OPEN_MAX
14139 {"SC_MQ_OPEN_MAX", _SC_MQ_OPEN_MAX},
14140 #endif
14141 #ifdef _SC_MQ_PRIO_MAX
14142 {"SC_MQ_PRIO_MAX", _SC_MQ_PRIO_MAX},
14143 #endif
14144 #ifdef _SC_NACLS_MAX
14145 {"SC_NACLS_MAX", _SC_NACLS_MAX},
14146 #endif
14147 #ifdef _SC_NGROUPS_MAX
14148 {"SC_NGROUPS_MAX", _SC_NGROUPS_MAX},
14149 #endif
14150 #ifdef _SC_NL_ARGMAX
14151 {"SC_NL_ARGMAX", _SC_NL_ARGMAX},
14152 #endif
14153 #ifdef _SC_NL_LANGMAX
14154 {"SC_NL_LANGMAX", _SC_NL_LANGMAX},
14155 #endif
14156 #ifdef _SC_NL_MSGMAX
14157 {"SC_NL_MSGMAX", _SC_NL_MSGMAX},
14158 #endif
14159 #ifdef _SC_NL_NMAX
14160 {"SC_NL_NMAX", _SC_NL_NMAX},
14161 #endif
14162 #ifdef _SC_NL_SETMAX
14163 {"SC_NL_SETMAX", _SC_NL_SETMAX},
14164 #endif
14165 #ifdef _SC_NL_TEXTMAX
14166 {"SC_NL_TEXTMAX", _SC_NL_TEXTMAX},
14167 #endif
14168 #ifdef _SC_NPROCESSORS_CONF
14169 {"SC_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF},
14170 #endif
14171 #ifdef _SC_NPROCESSORS_ONLN
14172 {"SC_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN},
14173 #endif
14174 #ifdef _SC_NPROC_CONF
14175 {"SC_NPROC_CONF", _SC_NPROC_CONF},
14176 #endif
14177 #ifdef _SC_NPROC_ONLN
14178 {"SC_NPROC_ONLN", _SC_NPROC_ONLN},
14179 #endif
14180 #ifdef _SC_NZERO
14181 {"SC_NZERO", _SC_NZERO},
14182 #endif
14183 #ifdef _SC_OPEN_MAX
14184 {"SC_OPEN_MAX", _SC_OPEN_MAX},
14185 #endif
14186 #ifdef _SC_PAGESIZE
14187 {"SC_PAGESIZE", _SC_PAGESIZE},
14188 #endif
14189 #ifdef _SC_PAGE_SIZE
14190 {"SC_PAGE_SIZE", _SC_PAGE_SIZE},
14191 #endif
14192 #ifdef _SC_AIX_REALMEM
14193 {"SC_AIX_REALMEM", _SC_AIX_REALMEM},
14194 #endif
14195 #ifdef _SC_PASS_MAX
14196 {"SC_PASS_MAX", _SC_PASS_MAX},
14197 #endif
14198 #ifdef _SC_PHYS_PAGES
14199 {"SC_PHYS_PAGES", _SC_PHYS_PAGES},
14200 #endif
14201 #ifdef _SC_PII
14202 {"SC_PII", _SC_PII},
14203 #endif
14204 #ifdef _SC_PII_INTERNET
14205 {"SC_PII_INTERNET", _SC_PII_INTERNET},
14206 #endif
14207 #ifdef _SC_PII_INTERNET_DGRAM
14208 {"SC_PII_INTERNET_DGRAM", _SC_PII_INTERNET_DGRAM},
14209 #endif
14210 #ifdef _SC_PII_INTERNET_STREAM
14211 {"SC_PII_INTERNET_STREAM", _SC_PII_INTERNET_STREAM},
14212 #endif
14213 #ifdef _SC_PII_OSI
14214 {"SC_PII_OSI", _SC_PII_OSI},
14215 #endif
14216 #ifdef _SC_PII_OSI_CLTS
14217 {"SC_PII_OSI_CLTS", _SC_PII_OSI_CLTS},
14218 #endif
14219 #ifdef _SC_PII_OSI_COTS
14220 {"SC_PII_OSI_COTS", _SC_PII_OSI_COTS},
14221 #endif
14222 #ifdef _SC_PII_OSI_M
14223 {"SC_PII_OSI_M", _SC_PII_OSI_M},
14224 #endif
14225 #ifdef _SC_PII_SOCKET
14226 {"SC_PII_SOCKET", _SC_PII_SOCKET},
14227 #endif
14228 #ifdef _SC_PII_XTI
14229 {"SC_PII_XTI", _SC_PII_XTI},
14230 #endif
14231 #ifdef _SC_POLL
14232 {"SC_POLL", _SC_POLL},
14233 #endif
14234 #ifdef _SC_PRIORITIZED_IO
14235 {"SC_PRIORITIZED_IO", _SC_PRIORITIZED_IO},
14236 #endif
14237 #ifdef _SC_PRIORITY_SCHEDULING
14238 {"SC_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING},
14239 #endif
14240 #ifdef _SC_REALTIME_SIGNALS
14241 {"SC_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS},
14242 #endif
14243 #ifdef _SC_RE_DUP_MAX
14244 {"SC_RE_DUP_MAX", _SC_RE_DUP_MAX},
14245 #endif
14246 #ifdef _SC_RTSIG_MAX
14247 {"SC_RTSIG_MAX", _SC_RTSIG_MAX},
14248 #endif
14249 #ifdef _SC_SAVED_IDS
14250 {"SC_SAVED_IDS", _SC_SAVED_IDS},
14251 #endif
14252 #ifdef _SC_SCHAR_MAX
14253 {"SC_SCHAR_MAX", _SC_SCHAR_MAX},
14254 #endif
14255 #ifdef _SC_SCHAR_MIN
14256 {"SC_SCHAR_MIN", _SC_SCHAR_MIN},
14257 #endif
14258 #ifdef _SC_SELECT
14259 {"SC_SELECT", _SC_SELECT},
14260 #endif
14261 #ifdef _SC_SEMAPHORES
14262 {"SC_SEMAPHORES", _SC_SEMAPHORES},
14263 #endif
14264 #ifdef _SC_SEM_NSEMS_MAX
14265 {"SC_SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX},
14266 #endif
14267 #ifdef _SC_SEM_VALUE_MAX
14268 {"SC_SEM_VALUE_MAX", _SC_SEM_VALUE_MAX},
14269 #endif
14270 #ifdef _SC_SHARED_MEMORY_OBJECTS
14271 {"SC_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS},
14272 #endif
14273 #ifdef _SC_SHRT_MAX
14274 {"SC_SHRT_MAX", _SC_SHRT_MAX},
14275 #endif
14276 #ifdef _SC_SHRT_MIN
14277 {"SC_SHRT_MIN", _SC_SHRT_MIN},
14278 #endif
14279 #ifdef _SC_SIGQUEUE_MAX
14280 {"SC_SIGQUEUE_MAX", _SC_SIGQUEUE_MAX},
14281 #endif
14282 #ifdef _SC_SIGRT_MAX
14283 {"SC_SIGRT_MAX", _SC_SIGRT_MAX},
14284 #endif
14285 #ifdef _SC_SIGRT_MIN
14286 {"SC_SIGRT_MIN", _SC_SIGRT_MIN},
14287 #endif
14288 #ifdef _SC_SOFTPOWER
14289 {"SC_SOFTPOWER", _SC_SOFTPOWER},
14290 #endif
14291 #ifdef _SC_SPLIT_CACHE
14292 {"SC_SPLIT_CACHE", _SC_SPLIT_CACHE},
14293 #endif
14294 #ifdef _SC_SSIZE_MAX
14295 {"SC_SSIZE_MAX", _SC_SSIZE_MAX},
14296 #endif
14297 #ifdef _SC_STACK_PROT
14298 {"SC_STACK_PROT", _SC_STACK_PROT},
14299 #endif
14300 #ifdef _SC_STREAM_MAX
14301 {"SC_STREAM_MAX", _SC_STREAM_MAX},
14302 #endif
14303 #ifdef _SC_SYNCHRONIZED_IO
14304 {"SC_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO},
14305 #endif
14306 #ifdef _SC_THREADS
14307 {"SC_THREADS", _SC_THREADS},
14308 #endif
14309 #ifdef _SC_THREAD_ATTR_STACKADDR
14310 {"SC_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR},
14311 #endif
14312 #ifdef _SC_THREAD_ATTR_STACKSIZE
14313 {"SC_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE},
14314 #endif
14315 #ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS
14316 {"SC_THREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS},
14317 #endif
14318 #ifdef _SC_THREAD_KEYS_MAX
14319 {"SC_THREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX},
14320 #endif
14321 #ifdef _SC_THREAD_PRIORITY_SCHEDULING
14322 {"SC_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING},
14323 #endif
14324 #ifdef _SC_THREAD_PRIO_INHERIT
14325 {"SC_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT},
14326 #endif
14327 #ifdef _SC_THREAD_PRIO_PROTECT
14328 {"SC_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT},
14329 #endif
14330 #ifdef _SC_THREAD_PROCESS_SHARED
14331 {"SC_THREAD_PROCESS_SHARED", _SC_THREAD_PROCESS_SHARED},
14332 #endif
14333 #ifdef _SC_THREAD_SAFE_FUNCTIONS
14334 {"SC_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS},
14335 #endif
14336 #ifdef _SC_THREAD_STACK_MIN
14337 {"SC_THREAD_STACK_MIN", _SC_THREAD_STACK_MIN},
14338 #endif
14339 #ifdef _SC_THREAD_THREADS_MAX
14340 {"SC_THREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX},
14341 #endif
14342 #ifdef _SC_TIMERS
14343 {"SC_TIMERS", _SC_TIMERS},
14344 #endif
14345 #ifdef _SC_TIMER_MAX
14346 {"SC_TIMER_MAX", _SC_TIMER_MAX},
14347 #endif
14348 #ifdef _SC_TTY_NAME_MAX
14349 {"SC_TTY_NAME_MAX", _SC_TTY_NAME_MAX},
14350 #endif
14351 #ifdef _SC_TZNAME_MAX
14352 {"SC_TZNAME_MAX", _SC_TZNAME_MAX},
14353 #endif
14354 #ifdef _SC_T_IOV_MAX
14355 {"SC_T_IOV_MAX", _SC_T_IOV_MAX},
14356 #endif
14357 #ifdef _SC_UCHAR_MAX
14358 {"SC_UCHAR_MAX", _SC_UCHAR_MAX},
14359 #endif
14360 #ifdef _SC_UINT_MAX
14361 {"SC_UINT_MAX", _SC_UINT_MAX},
14362 #endif
14363 #ifdef _SC_UIO_MAXIOV
14364 {"SC_UIO_MAXIOV", _SC_UIO_MAXIOV},
14365 #endif
14366 #ifdef _SC_ULONG_MAX
14367 {"SC_ULONG_MAX", _SC_ULONG_MAX},
14368 #endif
14369 #ifdef _SC_USHRT_MAX
14370 {"SC_USHRT_MAX", _SC_USHRT_MAX},
14371 #endif
14372 #ifdef _SC_VERSION
14373 {"SC_VERSION", _SC_VERSION},
14374 #endif
14375 #ifdef _SC_WORD_BIT
14376 {"SC_WORD_BIT", _SC_WORD_BIT},
14377 #endif
14378 #ifdef _SC_XBS5_ILP32_OFF32
14379 {"SC_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32},
14380 #endif
14381 #ifdef _SC_XBS5_ILP32_OFFBIG
14382 {"SC_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG},
14383 #endif
14384 #ifdef _SC_XBS5_LP64_OFF64
14385 {"SC_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64},
14386 #endif
14387 #ifdef _SC_XBS5_LPBIG_OFFBIG
14388 {"SC_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG},
14389 #endif
14390 #ifdef _SC_XOPEN_CRYPT
14391 {"SC_XOPEN_CRYPT", _SC_XOPEN_CRYPT},
14392 #endif
14393 #ifdef _SC_XOPEN_ENH_I18N
14394 {"SC_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N},
14395 #endif
14396 #ifdef _SC_XOPEN_LEGACY
14397 {"SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY},
14398 #endif
14399 #ifdef _SC_XOPEN_REALTIME
14400 {"SC_XOPEN_REALTIME", _SC_XOPEN_REALTIME},
14401 #endif
14402 #ifdef _SC_XOPEN_REALTIME_THREADS
14403 {"SC_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS},
14404 #endif
14405 #ifdef _SC_XOPEN_SHM
14406 {"SC_XOPEN_SHM", _SC_XOPEN_SHM},
14407 #endif
14408 #ifdef _SC_XOPEN_UNIX
14409 {"SC_XOPEN_UNIX", _SC_XOPEN_UNIX},
14410 #endif
14411 #ifdef _SC_XOPEN_VERSION
14412 {"SC_XOPEN_VERSION", _SC_XOPEN_VERSION},
14413 #endif
14414 #ifdef _SC_XOPEN_XCU_VERSION
14415 {"SC_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION},
14416 #endif
14417 #ifdef _SC_XOPEN_XPG2
14418 {"SC_XOPEN_XPG2", _SC_XOPEN_XPG2},
14419 #endif
14420 #ifdef _SC_XOPEN_XPG3
14421 {"SC_XOPEN_XPG3", _SC_XOPEN_XPG3},
14422 #endif
14423 #ifdef _SC_XOPEN_XPG4
14424 {"SC_XOPEN_XPG4", _SC_XOPEN_XPG4},
14425 #endif
14426 #ifdef _SC_MINSIGSTKSZ
14427 {"SC_MINSIGSTKSZ", _SC_MINSIGSTKSZ},
14428 #endif
14429 };
14430
14431 static int
conv_sysconf_confname(PyObject * arg,int * valuep)14432 conv_sysconf_confname(PyObject *arg, int *valuep)
14433 {
14434 return conv_confname(arg, valuep, posix_constants_sysconf,
14435 sizeof(posix_constants_sysconf)
14436 / sizeof(struct constdef));
14437 }
14438
14439
14440 /*[clinic input]
14441 os.sysconf -> long
14442 name: sysconf_confname
14443 /
14444
14445 Return an integer-valued system configuration variable.
14446 [clinic start generated code]*/
14447
14448 static long
os_sysconf_impl(PyObject * module,int name)14449 os_sysconf_impl(PyObject *module, int name)
14450 /*[clinic end generated code: output=3662f945fc0cc756 input=279e3430a33f29e4]*/
14451 {
14452 long value;
14453
14454 errno = 0;
14455 value = sysconf(name);
14456 if (value == -1 && errno != 0)
14457 posix_error();
14458 return value;
14459 }
14460 #endif /* HAVE_SYSCONF */
14461
14462
14463 /* This code is used to ensure that the tables of configuration value names
14464 * are in sorted order as required by conv_confname(), and also to build
14465 * the exported dictionaries that are used to publish information about the
14466 * names available on the host platform.
14467 *
14468 * Sorting the table at runtime ensures that the table is properly ordered
14469 * when used, even for platforms we're not able to test on. It also makes
14470 * it easier to add additional entries to the tables.
14471 */
14472
14473 static int
cmp_constdefs(const void * v1,const void * v2)14474 cmp_constdefs(const void *v1, const void *v2)
14475 {
14476 const struct constdef *c1 =
14477 (const struct constdef *) v1;
14478 const struct constdef *c2 =
14479 (const struct constdef *) v2;
14480
14481 return strcmp(c1->name, c2->name);
14482 }
14483
14484 static int
setup_confname_table(struct constdef * table,size_t tablesize,const char * tablename,PyObject * module)14485 setup_confname_table(struct constdef *table, size_t tablesize,
14486 const char *tablename, PyObject *module)
14487 {
14488 PyObject *d = NULL;
14489 size_t i;
14490
14491 qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs);
14492 d = PyDict_New();
14493 if (d == NULL)
14494 return -1;
14495
14496 for (i=0; i < tablesize; ++i) {
14497 PyObject *o = PyLong_FromLong(table[i].value);
14498 if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) {
14499 Py_XDECREF(o);
14500 Py_DECREF(d);
14501 return -1;
14502 }
14503 Py_DECREF(o);
14504 }
14505 return PyModule_Add(module, tablename, d);
14506 }
14507
14508 /* Return -1 on failure, 0 on success. */
14509 static int
setup_confname_tables(PyObject * module)14510 setup_confname_tables(PyObject *module)
14511 {
14512 #if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
14513 if (setup_confname_table(posix_constants_pathconf,
14514 sizeof(posix_constants_pathconf)
14515 / sizeof(struct constdef),
14516 "pathconf_names", module))
14517 return -1;
14518 #endif
14519 #ifdef HAVE_CONFSTR
14520 if (setup_confname_table(posix_constants_confstr,
14521 sizeof(posix_constants_confstr)
14522 / sizeof(struct constdef),
14523 "confstr_names", module))
14524 return -1;
14525 #endif
14526 #ifdef HAVE_SYSCONF
14527 if (setup_confname_table(posix_constants_sysconf,
14528 sizeof(posix_constants_sysconf)
14529 / sizeof(struct constdef),
14530 "sysconf_names", module))
14531 return -1;
14532 #endif
14533 return 0;
14534 }
14535
14536
14537 /*[clinic input]
14538 os.abort
14539
14540 Abort the interpreter immediately.
14541
14542 This function 'dumps core' or otherwise fails in the hardest way possible
14543 on the hosting operating system. This function never returns.
14544 [clinic start generated code]*/
14545
14546 static PyObject *
os_abort_impl(PyObject * module)14547 os_abort_impl(PyObject *module)
14548 /*[clinic end generated code: output=dcf52586dad2467c input=cf2c7d98bc504047]*/
14549 {
14550 abort();
14551 /*NOTREACHED*/
14552 #ifndef __clang__
14553 /* Issue #28152: abort() is declared with __attribute__((__noreturn__)).
14554 GCC emits a warning without "return NULL;" (compiler bug?), but Clang
14555 is smarter and emits a warning on the return. */
14556 Py_FatalError("abort() called from Python code didn't abort!");
14557 return NULL;
14558 #endif
14559 }
14560
14561 #ifdef MS_WINDOWS
14562 /* Grab ShellExecute dynamically from shell32 */
14563 static int has_ShellExecute = -1;
14564 static HINSTANCE (CALLBACK *Py_ShellExecuteW)(HWND, LPCWSTR, LPCWSTR, LPCWSTR,
14565 LPCWSTR, INT);
14566 static int
check_ShellExecute(void)14567 check_ShellExecute(void)
14568 {
14569 HINSTANCE hShell32;
14570
14571 /* only recheck */
14572 if (-1 == has_ShellExecute) {
14573 Py_BEGIN_ALLOW_THREADS
14574 /* Security note: this call is not vulnerable to "DLL hijacking".
14575 SHELL32 is part of "KnownDLLs" and so Windows always load
14576 the system SHELL32.DLL, even if there is another SHELL32.DLL
14577 in the DLL search path. */
14578 hShell32 = LoadLibraryW(L"SHELL32");
14579 if (hShell32) {
14580 *(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32,
14581 "ShellExecuteW");
14582 has_ShellExecute = Py_ShellExecuteW != NULL;
14583 } else {
14584 has_ShellExecute = 0;
14585 }
14586 Py_END_ALLOW_THREADS
14587 }
14588 return has_ShellExecute;
14589 }
14590
14591
14592 /*[clinic input]
14593 os.startfile
14594 filepath: path_t
14595 operation: Py_UNICODE = NULL
14596 arguments: Py_UNICODE = NULL
14597 cwd: path_t(nullable=True) = None
14598 show_cmd: int = 1
14599
14600 Start a file with its associated application.
14601
14602 When "operation" is not specified or "open", this acts like
14603 double-clicking the file in Explorer, or giving the file name as an
14604 argument to the DOS "start" command: the file is opened with whatever
14605 application (if any) its extension is associated.
14606 When another "operation" is given, it specifies what should be done with
14607 the file. A typical operation is "print".
14608
14609 "arguments" is passed to the application, but should be omitted if the
14610 file is a document.
14611
14612 "cwd" is the working directory for the operation. If "filepath" is
14613 relative, it will be resolved against this directory. This argument
14614 should usually be an absolute path.
14615
14616 "show_cmd" can be used to override the recommended visibility option.
14617 See the Windows ShellExecute documentation for values.
14618
14619 startfile returns as soon as the associated application is launched.
14620 There is no option to wait for the application to close, and no way
14621 to retrieve the application's exit status.
14622
14623 The filepath is relative to the current directory. If you want to use
14624 an absolute path, make sure the first character is not a slash ("/");
14625 the underlying Win32 ShellExecute function doesn't work if it is.
14626 [clinic start generated code]*/
14627
14628 static PyObject *
os_startfile_impl(PyObject * module,path_t * filepath,const wchar_t * operation,const wchar_t * arguments,path_t * cwd,int show_cmd)14629 os_startfile_impl(PyObject *module, path_t *filepath,
14630 const wchar_t *operation, const wchar_t *arguments,
14631 path_t *cwd, int show_cmd)
14632 /*[clinic end generated code: output=1c6f2f3340e31ffa input=8248997b80669622]*/
14633 {
14634 HINSTANCE rc;
14635
14636 if(!check_ShellExecute()) {
14637 /* If the OS doesn't have ShellExecute, return a
14638 NotImplementedError. */
14639 return PyErr_Format(PyExc_NotImplementedError,
14640 "startfile not available on this platform");
14641 }
14642
14643 if (PySys_Audit("os.startfile", "Ou", filepath->object, operation) < 0) {
14644 return NULL;
14645 }
14646 if (PySys_Audit("os.startfile/2", "OuuOi", filepath->object, operation,
14647 arguments, cwd->object ? cwd->object : Py_None,
14648 show_cmd) < 0) {
14649 return NULL;
14650 }
14651
14652 Py_BEGIN_ALLOW_THREADS
14653 rc = Py_ShellExecuteW((HWND)0, operation, filepath->wide,
14654 arguments, cwd->wide, show_cmd);
14655 Py_END_ALLOW_THREADS
14656
14657 if (rc <= (HINSTANCE)32) {
14658 win32_error_object("startfile", filepath->object);
14659 return NULL;
14660 }
14661 Py_RETURN_NONE;
14662 }
14663 #endif /* MS_WINDOWS */
14664
14665
14666 #ifdef HAVE_GETLOADAVG
14667 /*[clinic input]
14668 os.getloadavg
14669
14670 Return average recent system load information.
14671
14672 Return the number of processes in the system run queue averaged over
14673 the last 1, 5, and 15 minutes as a tuple of three floats.
14674 Raises OSError if the load average was unobtainable.
14675 [clinic start generated code]*/
14676
14677 static PyObject *
os_getloadavg_impl(PyObject * module)14678 os_getloadavg_impl(PyObject *module)
14679 /*[clinic end generated code: output=9ad3a11bfb4f4bd2 input=3d6d826b76d8a34e]*/
14680 {
14681 double loadavg[3];
14682 if (getloadavg(loadavg, 3)!=3) {
14683 PyErr_SetString(PyExc_OSError, "Load averages are unobtainable");
14684 return NULL;
14685 } else
14686 return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]);
14687 }
14688 #endif /* HAVE_GETLOADAVG */
14689
14690
14691 /*[clinic input]
14692 os.device_encoding
14693 fd: int
14694
14695 Return a string describing the encoding of a terminal's file descriptor.
14696
14697 The file descriptor must be attached to a terminal.
14698 If the device is not a terminal, return None.
14699 [clinic start generated code]*/
14700
14701 static PyObject *
os_device_encoding_impl(PyObject * module,int fd)14702 os_device_encoding_impl(PyObject *module, int fd)
14703 /*[clinic end generated code: output=e0d294bbab7e8c2b input=9e1d4a42b66df312]*/
14704 {
14705 return _Py_device_encoding(fd);
14706 }
14707
14708
14709 #ifdef HAVE_SETRESUID
14710 /*[clinic input]
14711 os.setresuid
14712
14713 ruid: uid_t
14714 euid: uid_t
14715 suid: uid_t
14716 /
14717
14718 Set the current process's real, effective, and saved user ids.
14719 [clinic start generated code]*/
14720
14721 static PyObject *
os_setresuid_impl(PyObject * module,uid_t ruid,uid_t euid,uid_t suid)14722 os_setresuid_impl(PyObject *module, uid_t ruid, uid_t euid, uid_t suid)
14723 /*[clinic end generated code: output=834a641e15373e97 input=9e33cb79a82792f3]*/
14724 {
14725 if (setresuid(ruid, euid, suid) < 0)
14726 return posix_error();
14727 Py_RETURN_NONE;
14728 }
14729 #endif /* HAVE_SETRESUID */
14730
14731
14732 #ifdef HAVE_SETRESGID
14733 /*[clinic input]
14734 os.setresgid
14735
14736 rgid: gid_t
14737 egid: gid_t
14738 sgid: gid_t
14739 /
14740
14741 Set the current process's real, effective, and saved group ids.
14742 [clinic start generated code]*/
14743
14744 static PyObject *
os_setresgid_impl(PyObject * module,gid_t rgid,gid_t egid,gid_t sgid)14745 os_setresgid_impl(PyObject *module, gid_t rgid, gid_t egid, gid_t sgid)
14746 /*[clinic end generated code: output=6aa402f3d2e514a9 input=33e9e0785ef426b1]*/
14747 {
14748 if (setresgid(rgid, egid, sgid) < 0)
14749 return posix_error();
14750 Py_RETURN_NONE;
14751 }
14752 #endif /* HAVE_SETRESGID */
14753
14754
14755 #ifdef HAVE_GETRESUID
14756 /*[clinic input]
14757 os.getresuid
14758
14759 Return a tuple of the current process's real, effective, and saved user ids.
14760 [clinic start generated code]*/
14761
14762 static PyObject *
os_getresuid_impl(PyObject * module)14763 os_getresuid_impl(PyObject *module)
14764 /*[clinic end generated code: output=8e0becff5dece5bf input=41ccfa8e1f6517ad]*/
14765 {
14766 uid_t ruid, euid, suid;
14767 if (getresuid(&ruid, &euid, &suid) < 0)
14768 return posix_error();
14769 return Py_BuildValue("(NNN)", _PyLong_FromUid(ruid),
14770 _PyLong_FromUid(euid),
14771 _PyLong_FromUid(suid));
14772 }
14773 #endif /* HAVE_GETRESUID */
14774
14775
14776 #ifdef HAVE_GETRESGID
14777 /*[clinic input]
14778 os.getresgid
14779
14780 Return a tuple of the current process's real, effective, and saved group ids.
14781 [clinic start generated code]*/
14782
14783 static PyObject *
os_getresgid_impl(PyObject * module)14784 os_getresgid_impl(PyObject *module)
14785 /*[clinic end generated code: output=2719c4bfcf27fb9f input=517e68db9ca32df6]*/
14786 {
14787 gid_t rgid, egid, sgid;
14788 if (getresgid(&rgid, &egid, &sgid) < 0)
14789 return posix_error();
14790 return Py_BuildValue("(NNN)", _PyLong_FromGid(rgid),
14791 _PyLong_FromGid(egid),
14792 _PyLong_FromGid(sgid));
14793 }
14794 #endif /* HAVE_GETRESGID */
14795
14796
14797 #ifdef USE_XATTRS
14798 /*[clinic input]
14799 os.getxattr
14800
14801 path: path_t(allow_fd=True)
14802 attribute: path_t
14803 *
14804 follow_symlinks: bool = True
14805
14806 Return the value of extended attribute attribute on path.
14807
14808 path may be either a string, a path-like object, or an open file descriptor.
14809 If follow_symlinks is False, and the last element of the path is a symbolic
14810 link, getxattr will examine the symbolic link itself instead of the file
14811 the link points to.
14812
14813 [clinic start generated code]*/
14814
14815 static PyObject *
os_getxattr_impl(PyObject * module,path_t * path,path_t * attribute,int follow_symlinks)14816 os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute,
14817 int follow_symlinks)
14818 /*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/
14819 {
14820 Py_ssize_t i;
14821 PyObject *buffer = NULL;
14822
14823 if (fd_and_follow_symlinks_invalid("getxattr", path->fd, follow_symlinks))
14824 return NULL;
14825
14826 if (PySys_Audit("os.getxattr", "OO", path->object, attribute->object) < 0) {
14827 return NULL;
14828 }
14829
14830 for (i = 0; ; i++) {
14831 void *ptr;
14832 ssize_t result;
14833 static const Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0};
14834 Py_ssize_t buffer_size = buffer_sizes[i];
14835 if (!buffer_size) {
14836 path_error(path);
14837 return NULL;
14838 }
14839 buffer = PyBytes_FromStringAndSize(NULL, buffer_size);
14840 if (!buffer)
14841 return NULL;
14842 ptr = PyBytes_AS_STRING(buffer);
14843
14844 Py_BEGIN_ALLOW_THREADS;
14845 if (path->fd >= 0)
14846 result = fgetxattr(path->fd, attribute->narrow, ptr, buffer_size);
14847 else if (follow_symlinks)
14848 result = getxattr(path->narrow, attribute->narrow, ptr, buffer_size);
14849 else
14850 result = lgetxattr(path->narrow, attribute->narrow, ptr, buffer_size);
14851 Py_END_ALLOW_THREADS;
14852
14853 if (result < 0) {
14854 if (errno == ERANGE) {
14855 Py_DECREF(buffer);
14856 continue;
14857 }
14858 path_error(path);
14859 Py_DECREF(buffer);
14860 return NULL;
14861 }
14862
14863 if (result != buffer_size) {
14864 /* Can only shrink. */
14865 _PyBytes_Resize(&buffer, result);
14866 }
14867 break;
14868 }
14869
14870 return buffer;
14871 }
14872
14873
14874 /*[clinic input]
14875 os.setxattr
14876
14877 path: path_t(allow_fd=True)
14878 attribute: path_t
14879 value: Py_buffer
14880 flags: int = 0
14881 *
14882 follow_symlinks: bool = True
14883
14884 Set extended attribute attribute on path to value.
14885
14886 path may be either a string, a path-like object, or an open file descriptor.
14887 If follow_symlinks is False, and the last element of the path is a symbolic
14888 link, setxattr will modify the symbolic link itself instead of the file
14889 the link points to.
14890
14891 [clinic start generated code]*/
14892
14893 static PyObject *
os_setxattr_impl(PyObject * module,path_t * path,path_t * attribute,Py_buffer * value,int flags,int follow_symlinks)14894 os_setxattr_impl(PyObject *module, path_t *path, path_t *attribute,
14895 Py_buffer *value, int flags, int follow_symlinks)
14896 /*[clinic end generated code: output=98b83f63fdde26bb input=c17c0103009042f0]*/
14897 {
14898 ssize_t result;
14899
14900 if (fd_and_follow_symlinks_invalid("setxattr", path->fd, follow_symlinks))
14901 return NULL;
14902
14903 if (PySys_Audit("os.setxattr", "OOy#i", path->object, attribute->object,
14904 value->buf, value->len, flags) < 0) {
14905 return NULL;
14906 }
14907
14908 Py_BEGIN_ALLOW_THREADS;
14909 if (path->fd > -1)
14910 result = fsetxattr(path->fd, attribute->narrow,
14911 value->buf, value->len, flags);
14912 else if (follow_symlinks)
14913 result = setxattr(path->narrow, attribute->narrow,
14914 value->buf, value->len, flags);
14915 else
14916 result = lsetxattr(path->narrow, attribute->narrow,
14917 value->buf, value->len, flags);
14918 Py_END_ALLOW_THREADS;
14919
14920 if (result) {
14921 path_error(path);
14922 return NULL;
14923 }
14924
14925 Py_RETURN_NONE;
14926 }
14927
14928
14929 /*[clinic input]
14930 os.removexattr
14931
14932 path: path_t(allow_fd=True)
14933 attribute: path_t
14934 *
14935 follow_symlinks: bool = True
14936
14937 Remove extended attribute attribute on path.
14938
14939 path may be either a string, a path-like object, or an open file descriptor.
14940 If follow_symlinks is False, and the last element of the path is a symbolic
14941 link, removexattr will modify the symbolic link itself instead of the file
14942 the link points to.
14943
14944 [clinic start generated code]*/
14945
14946 static PyObject *
os_removexattr_impl(PyObject * module,path_t * path,path_t * attribute,int follow_symlinks)14947 os_removexattr_impl(PyObject *module, path_t *path, path_t *attribute,
14948 int follow_symlinks)
14949 /*[clinic end generated code: output=521a51817980cda6 input=3d9a7d36fe2f7c4e]*/
14950 {
14951 ssize_t result;
14952
14953 if (fd_and_follow_symlinks_invalid("removexattr", path->fd, follow_symlinks))
14954 return NULL;
14955
14956 if (PySys_Audit("os.removexattr", "OO", path->object, attribute->object) < 0) {
14957 return NULL;
14958 }
14959
14960 Py_BEGIN_ALLOW_THREADS;
14961 if (path->fd > -1)
14962 result = fremovexattr(path->fd, attribute->narrow);
14963 else if (follow_symlinks)
14964 result = removexattr(path->narrow, attribute->narrow);
14965 else
14966 result = lremovexattr(path->narrow, attribute->narrow);
14967 Py_END_ALLOW_THREADS;
14968
14969 if (result) {
14970 return path_error(path);
14971 }
14972
14973 Py_RETURN_NONE;
14974 }
14975
14976
14977 /*[clinic input]
14978 os.listxattr
14979
14980 path: path_t(allow_fd=True, nullable=True) = None
14981 *
14982 follow_symlinks: bool = True
14983
14984 Return a list of extended attributes on path.
14985
14986 path may be either None, a string, a path-like object, or an open file descriptor.
14987 if path is None, listxattr will examine the current directory.
14988 If follow_symlinks is False, and the last element of the path is a symbolic
14989 link, listxattr will examine the symbolic link itself instead of the file
14990 the link points to.
14991 [clinic start generated code]*/
14992
14993 static PyObject *
os_listxattr_impl(PyObject * module,path_t * path,int follow_symlinks)14994 os_listxattr_impl(PyObject *module, path_t *path, int follow_symlinks)
14995 /*[clinic end generated code: output=bebdb4e2ad0ce435 input=9826edf9fdb90869]*/
14996 {
14997 Py_ssize_t i;
14998 PyObject *result = NULL;
14999 const char *name;
15000 char *buffer = NULL;
15001
15002 if (fd_and_follow_symlinks_invalid("listxattr", path->fd, follow_symlinks))
15003 goto exit;
15004
15005 if (PySys_Audit("os.listxattr", "(O)",
15006 path->object ? path->object : Py_None) < 0) {
15007 return NULL;
15008 }
15009
15010 name = path->narrow ? path->narrow : ".";
15011
15012 for (i = 0; ; i++) {
15013 const char *start, *trace, *end;
15014 ssize_t length;
15015 static const Py_ssize_t buffer_sizes[] = { 256, XATTR_LIST_MAX, 0 };
15016 Py_ssize_t buffer_size = buffer_sizes[i];
15017 if (!buffer_size) {
15018 /* ERANGE */
15019 path_error(path);
15020 break;
15021 }
15022 buffer = PyMem_Malloc(buffer_size);
15023 if (!buffer) {
15024 PyErr_NoMemory();
15025 break;
15026 }
15027
15028 Py_BEGIN_ALLOW_THREADS;
15029 if (path->fd > -1)
15030 length = flistxattr(path->fd, buffer, buffer_size);
15031 else if (follow_symlinks)
15032 length = listxattr(name, buffer, buffer_size);
15033 else
15034 length = llistxattr(name, buffer, buffer_size);
15035 Py_END_ALLOW_THREADS;
15036
15037 if (length < 0) {
15038 if (errno == ERANGE) {
15039 PyMem_Free(buffer);
15040 buffer = NULL;
15041 continue;
15042 }
15043 path_error(path);
15044 break;
15045 }
15046
15047 result = PyList_New(0);
15048 if (!result) {
15049 goto exit;
15050 }
15051
15052 end = buffer + length;
15053 for (trace = start = buffer; trace != end; trace++) {
15054 if (!*trace) {
15055 int error;
15056 PyObject *attribute = PyUnicode_DecodeFSDefaultAndSize(start,
15057 trace - start);
15058 if (!attribute) {
15059 Py_SETREF(result, NULL);
15060 goto exit;
15061 }
15062 error = PyList_Append(result, attribute);
15063 Py_DECREF(attribute);
15064 if (error) {
15065 Py_SETREF(result, NULL);
15066 goto exit;
15067 }
15068 start = trace + 1;
15069 }
15070 }
15071 break;
15072 }
15073 exit:
15074 if (buffer)
15075 PyMem_Free(buffer);
15076 return result;
15077 }
15078 #endif /* USE_XATTRS */
15079
15080
15081 /*[clinic input]
15082 os.urandom
15083
15084 size: Py_ssize_t
15085 /
15086
15087 Return a bytes object containing random bytes suitable for cryptographic use.
15088 [clinic start generated code]*/
15089
15090 static PyObject *
os_urandom_impl(PyObject * module,Py_ssize_t size)15091 os_urandom_impl(PyObject *module, Py_ssize_t size)
15092 /*[clinic end generated code: output=42c5cca9d18068e9 input=4067cdb1b6776c29]*/
15093 {
15094 PyObject *bytes;
15095 int result;
15096
15097 if (size < 0)
15098 return PyErr_Format(PyExc_ValueError,
15099 "negative argument not allowed");
15100 bytes = PyBytes_FromStringAndSize(NULL, size);
15101 if (bytes == NULL)
15102 return NULL;
15103
15104 result = _PyOS_URandom(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes));
15105 if (result == -1) {
15106 Py_DECREF(bytes);
15107 return NULL;
15108 }
15109 return bytes;
15110 }
15111
15112 #ifdef HAVE_MEMFD_CREATE
15113 /*[clinic input]
15114 os.memfd_create
15115
15116 name: FSConverter
15117 flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC
15118
15119 [clinic start generated code]*/
15120
15121 static PyObject *
os_memfd_create_impl(PyObject * module,PyObject * name,unsigned int flags)15122 os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
15123 /*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/
15124 {
15125 int fd;
15126 const char *bytes = PyBytes_AS_STRING(name);
15127 Py_BEGIN_ALLOW_THREADS
15128 fd = memfd_create(bytes, flags);
15129 Py_END_ALLOW_THREADS
15130 if (fd == -1) {
15131 return PyErr_SetFromErrno(PyExc_OSError);
15132 }
15133 return PyLong_FromLong(fd);
15134 }
15135 #endif
15136
15137 #if defined(HAVE_EVENTFD) && defined(EFD_CLOEXEC)
15138 /*[clinic input]
15139 os.eventfd
15140
15141 initval: unsigned_int
15142 flags: int(c_default="EFD_CLOEXEC") = EFD_CLOEXEC
15143
15144 Creates and returns an event notification file descriptor.
15145 [clinic start generated code]*/
15146
15147 static PyObject *
os_eventfd_impl(PyObject * module,unsigned int initval,int flags)15148 os_eventfd_impl(PyObject *module, unsigned int initval, int flags)
15149 /*[clinic end generated code: output=ce9c9bbd1446f2de input=66203e3c50c4028b]*/
15150
15151 {
15152 /* initval is limited to uint32_t, internal counter is uint64_t */
15153 int fd;
15154 Py_BEGIN_ALLOW_THREADS
15155 fd = eventfd(initval, flags);
15156 Py_END_ALLOW_THREADS
15157 if (fd == -1) {
15158 return PyErr_SetFromErrno(PyExc_OSError);
15159 }
15160 return PyLong_FromLong(fd);
15161 }
15162
15163 /*[clinic input]
15164 os.eventfd_read
15165
15166 fd: fildes
15167
15168 Read eventfd value
15169 [clinic start generated code]*/
15170
15171 static PyObject *
os_eventfd_read_impl(PyObject * module,int fd)15172 os_eventfd_read_impl(PyObject *module, int fd)
15173 /*[clinic end generated code: output=8f2c7b59a3521fd1 input=110f8b57fa596afe]*/
15174 {
15175 eventfd_t value;
15176 int result;
15177 Py_BEGIN_ALLOW_THREADS
15178 result = eventfd_read(fd, &value);
15179 Py_END_ALLOW_THREADS
15180 if (result == -1) {
15181 return PyErr_SetFromErrno(PyExc_OSError);
15182 }
15183 return PyLong_FromUnsignedLongLong(value);
15184 }
15185
15186 /*[clinic input]
15187 os.eventfd_write
15188
15189 fd: fildes
15190 value: unsigned_long_long
15191
15192 Write eventfd value.
15193 [clinic start generated code]*/
15194
15195 static PyObject *
os_eventfd_write_impl(PyObject * module,int fd,unsigned long long value)15196 os_eventfd_write_impl(PyObject *module, int fd, unsigned long long value)
15197 /*[clinic end generated code: output=bebd9040bbf987f5 input=156de8555be5a949]*/
15198 {
15199 int result;
15200 Py_BEGIN_ALLOW_THREADS
15201 result = eventfd_write(fd, value);
15202 Py_END_ALLOW_THREADS
15203 if (result == -1) {
15204 return PyErr_SetFromErrno(PyExc_OSError);
15205 }
15206 Py_RETURN_NONE;
15207 }
15208 #endif /* HAVE_EVENTFD && EFD_CLOEXEC */
15209
15210 /* Terminal size querying */
15211
15212 PyDoc_STRVAR(TerminalSize_docstring,
15213 "A tuple of (columns, lines) for holding terminal window size");
15214
15215 static PyStructSequence_Field TerminalSize_fields[] = {
15216 {"columns", "width of the terminal window in characters"},
15217 {"lines", "height of the terminal window in characters"},
15218 {NULL, NULL}
15219 };
15220
15221 static PyStructSequence_Desc TerminalSize_desc = {
15222 "os.terminal_size",
15223 TerminalSize_docstring,
15224 TerminalSize_fields,
15225 2,
15226 };
15227
15228 #if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL)
15229 /*[clinic input]
15230 os.get_terminal_size
15231
15232 fd: int(c_default="fileno(stdout)", py_default="<unrepresentable>") = -1
15233 /
15234
15235 Return the size of the terminal window as (columns, lines).
15236
15237 The optional argument fd (default standard output) specifies
15238 which file descriptor should be queried.
15239
15240 If the file descriptor is not connected to a terminal, an OSError
15241 is thrown.
15242
15243 This function will only be defined if an implementation is
15244 available for this system.
15245
15246 shutil.get_terminal_size is the high-level function which should
15247 normally be used, os.get_terminal_size is the low-level implementation.
15248 [clinic start generated code]*/
15249
15250 static PyObject *
os_get_terminal_size_impl(PyObject * module,int fd)15251 os_get_terminal_size_impl(PyObject *module, int fd)
15252 /*[clinic end generated code: output=fbab93acef980508 input=ead5679b82ddb920]*/
15253 {
15254 int columns, lines;
15255 PyObject *termsize;
15256
15257 /* Under some conditions stdout may not be connected and
15258 * fileno(stdout) may point to an invalid file descriptor. For example
15259 * GUI apps don't have valid standard streams by default.
15260 *
15261 * If this happens, and the optional fd argument is not present,
15262 * the ioctl below will fail returning EBADF. This is what we want.
15263 */
15264
15265 #ifdef TERMSIZE_USE_IOCTL
15266 {
15267 struct winsize w;
15268 if (ioctl(fd, TIOCGWINSZ, &w))
15269 return PyErr_SetFromErrno(PyExc_OSError);
15270 columns = w.ws_col;
15271 lines = w.ws_row;
15272 }
15273 #endif /* TERMSIZE_USE_IOCTL */
15274
15275 #ifdef TERMSIZE_USE_CONIO
15276 {
15277 HANDLE handle;
15278 CONSOLE_SCREEN_BUFFER_INFO csbi;
15279 handle = _Py_get_osfhandle(fd);
15280 if (handle == INVALID_HANDLE_VALUE)
15281 return NULL;
15282
15283 if (!GetConsoleScreenBufferInfo(handle, &csbi))
15284 return PyErr_SetFromWindowsErr(0);
15285
15286 columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
15287 lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
15288 }
15289 #endif /* TERMSIZE_USE_CONIO */
15290
15291 PyObject *TerminalSizeType = get_posix_state(module)->TerminalSizeType;
15292 termsize = PyStructSequence_New((PyTypeObject *)TerminalSizeType);
15293 if (termsize == NULL)
15294 return NULL;
15295
15296 int pos = 0;
15297
15298 #define SET_TERMSIZE(CALL) \
15299 do { \
15300 PyObject *item = (CALL); \
15301 if (item == NULL) { \
15302 Py_DECREF(termsize); \
15303 return NULL; \
15304 } \
15305 PyStructSequence_SET_ITEM(termsize, pos++, item); \
15306 } while(0)
15307
15308 SET_TERMSIZE(PyLong_FromLong(columns));
15309 SET_TERMSIZE(PyLong_FromLong(lines));
15310 #undef SET_TERMSIZE
15311
15312 return termsize;
15313 }
15314 #endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */
15315
15316 /*[clinic input]
15317 os.cpu_count
15318
15319 Return the number of logical CPUs in the system.
15320
15321 Return None if indeterminable.
15322 [clinic start generated code]*/
15323
15324 static PyObject *
os_cpu_count_impl(PyObject * module)15325 os_cpu_count_impl(PyObject *module)
15326 /*[clinic end generated code: output=5fc29463c3936a9c input=ba2f6f8980a0e2eb]*/
15327 {
15328 const PyConfig *config = _Py_GetConfig();
15329 if (config->cpu_count > 0) {
15330 return PyLong_FromLong(config->cpu_count);
15331 }
15332
15333 int ncpu = 0;
15334 #ifdef MS_WINDOWS
15335 # ifdef MS_WINDOWS_DESKTOP
15336 ncpu = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
15337 # else
15338 ncpu = 0;
15339 # endif
15340
15341 #elif defined(__hpux)
15342 ncpu = mpctl(MPC_GETNUMSPUS, NULL, NULL);
15343
15344 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
15345 ncpu = sysconf(_SC_NPROCESSORS_ONLN);
15346
15347 #elif defined(__VXWORKS__)
15348 ncpu = _Py_popcount32(vxCpuEnabledGet());
15349
15350 #elif defined(__DragonFly__) || \
15351 defined(__OpenBSD__) || \
15352 defined(__FreeBSD__) || \
15353 defined(__NetBSD__) || \
15354 defined(__APPLE__)
15355 ncpu = 0;
15356 size_t len = sizeof(ncpu);
15357 int mib[2] = {CTL_HW, HW_NCPU};
15358 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) != 0) {
15359 ncpu = 0;
15360 }
15361 #endif
15362
15363 if (ncpu < 1) {
15364 Py_RETURN_NONE;
15365 }
15366 return PyLong_FromLong(ncpu);
15367 }
15368
15369
15370 /*[clinic input]
15371 os.get_inheritable -> bool
15372
15373 fd: int
15374 /
15375
15376 Get the close-on-exe flag of the specified file descriptor.
15377 [clinic start generated code]*/
15378
15379 static int
os_get_inheritable_impl(PyObject * module,int fd)15380 os_get_inheritable_impl(PyObject *module, int fd)
15381 /*[clinic end generated code: output=0445e20e149aa5b8 input=89ac008dc9ab6b95]*/
15382 {
15383 int return_value;
15384 _Py_BEGIN_SUPPRESS_IPH
15385 return_value = _Py_get_inheritable(fd);
15386 _Py_END_SUPPRESS_IPH
15387 return return_value;
15388 }
15389
15390
15391 /*[clinic input]
15392 os.set_inheritable
15393 fd: int
15394 inheritable: int
15395 /
15396
15397 Set the inheritable flag of the specified file descriptor.
15398 [clinic start generated code]*/
15399
15400 static PyObject *
os_set_inheritable_impl(PyObject * module,int fd,int inheritable)15401 os_set_inheritable_impl(PyObject *module, int fd, int inheritable)
15402 /*[clinic end generated code: output=f1b1918a2f3c38c2 input=9ceaead87a1e2402]*/
15403 {
15404 int result;
15405
15406 _Py_BEGIN_SUPPRESS_IPH
15407 result = _Py_set_inheritable(fd, inheritable, NULL);
15408 _Py_END_SUPPRESS_IPH
15409 if (result < 0)
15410 return NULL;
15411 Py_RETURN_NONE;
15412 }
15413
15414
15415 #ifdef MS_WINDOWS
15416 #ifndef HANDLE_FLAG_INHERIT
15417 #define HANDLE_FLAG_INHERIT 0x00000001
15418 #endif
15419
15420 /*[clinic input]
15421 os.get_handle_inheritable -> bool
15422 handle: intptr_t
15423 /
15424
15425 Get the close-on-exe flag of the specified file descriptor.
15426 [clinic start generated code]*/
15427
15428 static int
os_get_handle_inheritable_impl(PyObject * module,intptr_t handle)15429 os_get_handle_inheritable_impl(PyObject *module, intptr_t handle)
15430 /*[clinic end generated code: output=36be5afca6ea84d8 input=cfe99f9c05c70ad1]*/
15431 {
15432 DWORD flags;
15433
15434 if (!GetHandleInformation((HANDLE)handle, &flags)) {
15435 PyErr_SetFromWindowsErr(0);
15436 return -1;
15437 }
15438
15439 return flags & HANDLE_FLAG_INHERIT;
15440 }
15441
15442
15443 /*[clinic input]
15444 os.set_handle_inheritable
15445 handle: intptr_t
15446 inheritable: bool
15447 /
15448
15449 Set the inheritable flag of the specified handle.
15450 [clinic start generated code]*/
15451
15452 static PyObject *
os_set_handle_inheritable_impl(PyObject * module,intptr_t handle,int inheritable)15453 os_set_handle_inheritable_impl(PyObject *module, intptr_t handle,
15454 int inheritable)
15455 /*[clinic end generated code: output=021d74fe6c96baa3 input=7a7641390d8364fc]*/
15456 {
15457 DWORD flags = inheritable ? HANDLE_FLAG_INHERIT : 0;
15458 if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) {
15459 PyErr_SetFromWindowsErr(0);
15460 return NULL;
15461 }
15462 Py_RETURN_NONE;
15463 }
15464 #endif /* MS_WINDOWS */
15465
15466 /*[clinic input]
15467 os.get_blocking -> bool
15468 fd: int
15469 /
15470
15471 Get the blocking mode of the file descriptor.
15472
15473 Return False if the O_NONBLOCK flag is set, True if the flag is cleared.
15474 [clinic start generated code]*/
15475
15476 static int
os_get_blocking_impl(PyObject * module,int fd)15477 os_get_blocking_impl(PyObject *module, int fd)
15478 /*[clinic end generated code: output=336a12ad76a61482 input=f4afb59d51560179]*/
15479 {
15480 int blocking;
15481
15482 _Py_BEGIN_SUPPRESS_IPH
15483 blocking = _Py_get_blocking(fd);
15484 _Py_END_SUPPRESS_IPH
15485 return blocking;
15486 }
15487
15488 /*[clinic input]
15489 os.set_blocking
15490 fd: int
15491 blocking: bool
15492 /
15493
15494 Set the blocking mode of the specified file descriptor.
15495
15496 Set the O_NONBLOCK flag if blocking is False,
15497 clear the O_NONBLOCK flag otherwise.
15498 [clinic start generated code]*/
15499
15500 static PyObject *
os_set_blocking_impl(PyObject * module,int fd,int blocking)15501 os_set_blocking_impl(PyObject *module, int fd, int blocking)
15502 /*[clinic end generated code: output=384eb43aa0762a9d input=7e9dfc9b14804dd4]*/
15503 {
15504 int result;
15505
15506 _Py_BEGIN_SUPPRESS_IPH
15507 result = _Py_set_blocking(fd, blocking);
15508 _Py_END_SUPPRESS_IPH
15509 if (result < 0)
15510 return NULL;
15511 Py_RETURN_NONE;
15512 }
15513
15514
15515 /*[clinic input]
15516 class os.DirEntry "DirEntry *" "DirEntryType"
15517 [clinic start generated code]*/
15518 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c18c7a448247980]*/
15519
15520 typedef struct {
15521 PyObject_HEAD
15522 PyObject *name;
15523 PyObject *path;
15524 PyObject *stat;
15525 PyObject *lstat;
15526 #ifdef MS_WINDOWS
15527 struct _Py_stat_struct win32_lstat;
15528 uint64_t win32_file_index;
15529 uint64_t win32_file_index_high;
15530 int got_file_index;
15531 #else /* POSIX */
15532 #ifdef HAVE_DIRENT_D_TYPE
15533 unsigned char d_type;
15534 #endif
15535 ino_t d_ino;
15536 int dir_fd;
15537 #endif
15538 } DirEntry;
15539
15540 static void
DirEntry_dealloc(DirEntry * entry)15541 DirEntry_dealloc(DirEntry *entry)
15542 {
15543 PyTypeObject *tp = Py_TYPE(entry);
15544 Py_XDECREF(entry->name);
15545 Py_XDECREF(entry->path);
15546 Py_XDECREF(entry->stat);
15547 Py_XDECREF(entry->lstat);
15548 freefunc free_func = PyType_GetSlot(tp, Py_tp_free);
15549 free_func(entry);
15550 Py_DECREF(tp);
15551 }
15552
15553 /* Forward reference */
15554 static int
15555 DirEntry_test_mode(PyTypeObject *defining_class, DirEntry *self,
15556 int follow_symlinks, unsigned short mode_bits);
15557
15558 /*[clinic input]
15559 os.DirEntry.is_symlink -> bool
15560 defining_class: defining_class
15561 /
15562
15563 Return True if the entry is a symbolic link; cached per entry.
15564 [clinic start generated code]*/
15565
15566 static int
os_DirEntry_is_symlink_impl(DirEntry * self,PyTypeObject * defining_class)15567 os_DirEntry_is_symlink_impl(DirEntry *self, PyTypeObject *defining_class)
15568 /*[clinic end generated code: output=293096d589b6d47c input=e9acc5ee4d511113]*/
15569 {
15570 #ifdef MS_WINDOWS
15571 return (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK;
15572 #elif defined(HAVE_DIRENT_D_TYPE)
15573 /* POSIX */
15574 if (self->d_type != DT_UNKNOWN)
15575 return self->d_type == DT_LNK;
15576 else
15577 return DirEntry_test_mode(defining_class, self, 0, S_IFLNK);
15578 #else
15579 /* POSIX without d_type */
15580 return DirEntry_test_mode(defining_class, self, 0, S_IFLNK);
15581 #endif
15582 }
15583
15584 /*[clinic input]
15585 os.DirEntry.is_junction -> bool
15586
15587 Return True if the entry is a junction; cached per entry.
15588 [clinic start generated code]*/
15589
15590 static int
os_DirEntry_is_junction_impl(DirEntry * self)15591 os_DirEntry_is_junction_impl(DirEntry *self)
15592 /*[clinic end generated code: output=97f64d5d99eeccb5 input=4fc8e701eea118a1]*/
15593 {
15594 #ifdef MS_WINDOWS
15595 return self->win32_lstat.st_reparse_tag == IO_REPARSE_TAG_MOUNT_POINT;
15596 #else
15597 return 0;
15598 #endif
15599 }
15600
15601 static PyObject *
DirEntry_fetch_stat(PyObject * module,DirEntry * self,int follow_symlinks)15602 DirEntry_fetch_stat(PyObject *module, DirEntry *self, int follow_symlinks)
15603 {
15604 int result;
15605 STRUCT_STAT st;
15606 PyObject *ub;
15607
15608 #ifdef MS_WINDOWS
15609 if (!PyUnicode_FSDecoder(self->path, &ub))
15610 return NULL;
15611 wchar_t *path = PyUnicode_AsWideCharString(ub, NULL);
15612 Py_DECREF(ub);
15613 #else /* POSIX */
15614 if (!PyUnicode_FSConverter(self->path, &ub))
15615 return NULL;
15616 const char *path = PyBytes_AS_STRING(ub);
15617 if (self->dir_fd != DEFAULT_DIR_FD) {
15618 #ifdef HAVE_FSTATAT
15619 if (HAVE_FSTATAT_RUNTIME) {
15620 Py_BEGIN_ALLOW_THREADS
15621 result = fstatat(self->dir_fd, path, &st,
15622 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
15623 Py_END_ALLOW_THREADS
15624 } else
15625
15626 #endif /* HAVE_FSTATAT */
15627 {
15628 Py_DECREF(ub);
15629 PyErr_SetString(PyExc_NotImplementedError, "can't fetch stat");
15630 return NULL;
15631 }
15632 }
15633 else
15634 #endif
15635 {
15636 Py_BEGIN_ALLOW_THREADS
15637 if (follow_symlinks) {
15638 result = STAT(path, &st);
15639 }
15640 else {
15641 result = LSTAT(path, &st);
15642 }
15643 Py_END_ALLOW_THREADS
15644 }
15645
15646 int saved_errno = errno;
15647 #if defined(MS_WINDOWS)
15648 PyMem_Free(path);
15649 #else
15650 Py_DECREF(ub);
15651 #endif
15652
15653 if (result != 0) {
15654 errno = saved_errno;
15655 path_object_error(self->path);
15656 return NULL;
15657 }
15658
15659 return _pystat_fromstructstat(module, &st);
15660 }
15661
15662 static PyObject *
DirEntry_get_lstat(PyTypeObject * defining_class,DirEntry * self)15663 DirEntry_get_lstat(PyTypeObject *defining_class, DirEntry *self)
15664 {
15665 if (!self->lstat) {
15666 PyObject *module = PyType_GetModule(defining_class);
15667 #ifdef MS_WINDOWS
15668 self->lstat = _pystat_fromstructstat(module, &self->win32_lstat);
15669 #else /* POSIX */
15670 self->lstat = DirEntry_fetch_stat(module, self, 0);
15671 #endif
15672 }
15673 return Py_XNewRef(self->lstat);
15674 }
15675
15676 /*[clinic input]
15677 os.DirEntry.stat
15678 defining_class: defining_class
15679 /
15680 *
15681 follow_symlinks: bool = True
15682
15683 Return stat_result object for the entry; cached per entry.
15684 [clinic start generated code]*/
15685
15686 static PyObject *
os_DirEntry_stat_impl(DirEntry * self,PyTypeObject * defining_class,int follow_symlinks)15687 os_DirEntry_stat_impl(DirEntry *self, PyTypeObject *defining_class,
15688 int follow_symlinks)
15689 /*[clinic end generated code: output=23f803e19c3e780e input=e816273c4e67ee98]*/
15690 {
15691 if (!follow_symlinks) {
15692 return DirEntry_get_lstat(defining_class, self);
15693 }
15694
15695 if (!self->stat) {
15696 int result = os_DirEntry_is_symlink_impl(self, defining_class);
15697 if (result == -1) {
15698 return NULL;
15699 }
15700 if (result) {
15701 PyObject *module = PyType_GetModule(defining_class);
15702 self->stat = DirEntry_fetch_stat(module, self, 1);
15703 }
15704 else {
15705 self->stat = DirEntry_get_lstat(defining_class, self);
15706 }
15707 }
15708
15709 return Py_XNewRef(self->stat);
15710 }
15711
15712 /* Set exception and return -1 on error, 0 for False, 1 for True */
15713 static int
DirEntry_test_mode(PyTypeObject * defining_class,DirEntry * self,int follow_symlinks,unsigned short mode_bits)15714 DirEntry_test_mode(PyTypeObject *defining_class, DirEntry *self,
15715 int follow_symlinks, unsigned short mode_bits)
15716 {
15717 PyObject *stat = NULL;
15718 PyObject *st_mode = NULL;
15719 long mode;
15720 int result;
15721 #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE)
15722 int is_symlink;
15723 int need_stat;
15724 #endif
15725 #ifdef MS_WINDOWS
15726 unsigned long dir_bits;
15727 #endif
15728
15729 #ifdef MS_WINDOWS
15730 is_symlink = (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK;
15731 need_stat = follow_symlinks && is_symlink;
15732 #elif defined(HAVE_DIRENT_D_TYPE)
15733 is_symlink = self->d_type == DT_LNK;
15734 need_stat = self->d_type == DT_UNKNOWN || (follow_symlinks && is_symlink);
15735 #endif
15736
15737 #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE)
15738 if (need_stat) {
15739 #endif
15740 stat = os_DirEntry_stat_impl(self, defining_class, follow_symlinks);
15741 if (!stat) {
15742 if (PyErr_ExceptionMatches(PyExc_FileNotFoundError)) {
15743 /* If file doesn't exist (anymore), then return False
15744 (i.e., say it's not a file/directory) */
15745 PyErr_Clear();
15746 return 0;
15747 }
15748 goto error;
15749 }
15750 _posixstate* state = get_posix_state(PyType_GetModule(defining_class));
15751 st_mode = PyObject_GetAttr(stat, state->st_mode);
15752 if (!st_mode)
15753 goto error;
15754
15755 mode = PyLong_AsLong(st_mode);
15756 if (mode == -1 && PyErr_Occurred())
15757 goto error;
15758 Py_CLEAR(st_mode);
15759 Py_CLEAR(stat);
15760 result = (mode & S_IFMT) == mode_bits;
15761 #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE)
15762 }
15763 else if (is_symlink) {
15764 assert(mode_bits != S_IFLNK);
15765 result = 0;
15766 }
15767 else {
15768 assert(mode_bits == S_IFDIR || mode_bits == S_IFREG);
15769 #ifdef MS_WINDOWS
15770 dir_bits = self->win32_lstat.st_file_attributes & FILE_ATTRIBUTE_DIRECTORY;
15771 if (mode_bits == S_IFDIR)
15772 result = dir_bits != 0;
15773 else
15774 result = dir_bits == 0;
15775 #else /* POSIX */
15776 if (mode_bits == S_IFDIR)
15777 result = self->d_type == DT_DIR;
15778 else
15779 result = self->d_type == DT_REG;
15780 #endif
15781 }
15782 #endif
15783
15784 return result;
15785
15786 error:
15787 Py_XDECREF(st_mode);
15788 Py_XDECREF(stat);
15789 return -1;
15790 }
15791
15792 /*[clinic input]
15793 os.DirEntry.is_dir -> bool
15794 defining_class: defining_class
15795 /
15796 *
15797 follow_symlinks: bool = True
15798
15799 Return True if the entry is a directory; cached per entry.
15800 [clinic start generated code]*/
15801
15802 static int
os_DirEntry_is_dir_impl(DirEntry * self,PyTypeObject * defining_class,int follow_symlinks)15803 os_DirEntry_is_dir_impl(DirEntry *self, PyTypeObject *defining_class,
15804 int follow_symlinks)
15805 /*[clinic end generated code: output=0cd453b9c0987fdf input=1a4ffd6dec9920cb]*/
15806 {
15807 return DirEntry_test_mode(defining_class, self, follow_symlinks, S_IFDIR);
15808 }
15809
15810 /*[clinic input]
15811 os.DirEntry.is_file -> bool
15812 defining_class: defining_class
15813 /
15814 *
15815 follow_symlinks: bool = True
15816
15817 Return True if the entry is a file; cached per entry.
15818 [clinic start generated code]*/
15819
15820 static int
os_DirEntry_is_file_impl(DirEntry * self,PyTypeObject * defining_class,int follow_symlinks)15821 os_DirEntry_is_file_impl(DirEntry *self, PyTypeObject *defining_class,
15822 int follow_symlinks)
15823 /*[clinic end generated code: output=f7c277ab5ba80908 input=0a64c5a12e802e3b]*/
15824 {
15825 return DirEntry_test_mode(defining_class, self, follow_symlinks, S_IFREG);
15826 }
15827
15828 /*[clinic input]
15829 os.DirEntry.inode
15830
15831 Return inode of the entry; cached per entry.
15832 [clinic start generated code]*/
15833
15834 static PyObject *
os_DirEntry_inode_impl(DirEntry * self)15835 os_DirEntry_inode_impl(DirEntry *self)
15836 /*[clinic end generated code: output=156bb3a72162440e input=3ee7b872ae8649f0]*/
15837 {
15838 #ifdef MS_WINDOWS
15839 if (!self->got_file_index) {
15840 PyObject *unicode;
15841 STRUCT_STAT stat;
15842 int result;
15843
15844 if (!PyUnicode_FSDecoder(self->path, &unicode))
15845 return NULL;
15846 wchar_t *path = PyUnicode_AsWideCharString(unicode, NULL);
15847 Py_DECREF(unicode);
15848 result = LSTAT(path, &stat);
15849
15850 int saved_errno = errno;
15851 PyMem_Free(path);
15852
15853 if (result != 0) {
15854 errno = saved_errno;
15855 return path_object_error(self->path);
15856 }
15857
15858 self->win32_file_index = stat.st_ino;
15859 self->win32_file_index_high = stat.st_ino_high;
15860 self->got_file_index = 1;
15861 }
15862 return _pystat_l128_from_l64_l64(self->win32_file_index, self->win32_file_index_high);
15863 #else /* POSIX */
15864 static_assert(sizeof(unsigned long long) >= sizeof(self->d_ino),
15865 "DirEntry.d_ino is larger than unsigned long long");
15866 return PyLong_FromUnsignedLongLong(self->d_ino);
15867 #endif
15868 }
15869
15870 static PyObject *
DirEntry_repr(DirEntry * self)15871 DirEntry_repr(DirEntry *self)
15872 {
15873 return PyUnicode_FromFormat("<DirEntry %R>", self->name);
15874 }
15875
15876 /*[clinic input]
15877 os.DirEntry.__fspath__
15878
15879 Returns the path for the entry.
15880 [clinic start generated code]*/
15881
15882 static PyObject *
os_DirEntry___fspath___impl(DirEntry * self)15883 os_DirEntry___fspath___impl(DirEntry *self)
15884 /*[clinic end generated code: output=6dd7f7ef752e6f4f input=3c49d0cf38df4fac]*/
15885 {
15886 return Py_NewRef(self->path);
15887 }
15888
15889 static PyMemberDef DirEntry_members[] = {
15890 {"name", Py_T_OBJECT_EX, offsetof(DirEntry, name), Py_READONLY,
15891 "the entry's base filename, relative to scandir() \"path\" argument"},
15892 {"path", Py_T_OBJECT_EX, offsetof(DirEntry, path), Py_READONLY,
15893 "the entry's full path name; equivalent to os.path.join(scandir_path, entry.name)"},
15894 {NULL}
15895 };
15896
15897 #include "clinic/posixmodule.c.h"
15898
15899 static PyMethodDef DirEntry_methods[] = {
15900 OS_DIRENTRY_IS_DIR_METHODDEF
15901 OS_DIRENTRY_IS_FILE_METHODDEF
15902 OS_DIRENTRY_IS_SYMLINK_METHODDEF
15903 OS_DIRENTRY_IS_JUNCTION_METHODDEF
15904 OS_DIRENTRY_STAT_METHODDEF
15905 OS_DIRENTRY_INODE_METHODDEF
15906 OS_DIRENTRY___FSPATH___METHODDEF
15907 {"__class_getitem__", Py_GenericAlias,
15908 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
15909 {NULL}
15910 };
15911
15912 static PyType_Slot DirEntryType_slots[] = {
15913 {Py_tp_dealloc, DirEntry_dealloc},
15914 {Py_tp_repr, DirEntry_repr},
15915 {Py_tp_methods, DirEntry_methods},
15916 {Py_tp_members, DirEntry_members},
15917 {0, 0},
15918 };
15919
15920 static PyType_Spec DirEntryType_spec = {
15921 MODNAME ".DirEntry",
15922 sizeof(DirEntry),
15923 0,
15924 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
15925 DirEntryType_slots
15926 };
15927
15928
15929 #ifdef MS_WINDOWS
15930
15931 static wchar_t *
join_path_filenameW(const wchar_t * path_wide,const wchar_t * filename)15932 join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename)
15933 {
15934 Py_ssize_t path_len;
15935 Py_ssize_t size;
15936 wchar_t *result;
15937 wchar_t ch;
15938
15939 if (!path_wide) { /* Default arg: "." */
15940 path_wide = L".";
15941 path_len = 1;
15942 }
15943 else {
15944 path_len = wcslen(path_wide);
15945 }
15946
15947 /* The +1's are for the path separator and the NUL */
15948 size = path_len + 1 + wcslen(filename) + 1;
15949 result = PyMem_New(wchar_t, size);
15950 if (!result) {
15951 PyErr_NoMemory();
15952 return NULL;
15953 }
15954 wcscpy(result, path_wide);
15955 if (path_len > 0) {
15956 ch = result[path_len - 1];
15957 if (ch != SEP && ch != ALTSEP && ch != L':')
15958 result[path_len++] = SEP;
15959 wcscpy(result + path_len, filename);
15960 }
15961 return result;
15962 }
15963
15964 static PyObject *
DirEntry_from_find_data(PyObject * module,path_t * path,WIN32_FIND_DATAW * dataW)15965 DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW)
15966 {
15967 DirEntry *entry;
15968 BY_HANDLE_FILE_INFORMATION file_info;
15969 ULONG reparse_tag;
15970 wchar_t *joined_path;
15971
15972 PyObject *DirEntryType = get_posix_state(module)->DirEntryType;
15973 entry = PyObject_New(DirEntry, (PyTypeObject *)DirEntryType);
15974 if (!entry)
15975 return NULL;
15976 entry->name = NULL;
15977 entry->path = NULL;
15978 entry->stat = NULL;
15979 entry->lstat = NULL;
15980 entry->got_file_index = 0;
15981
15982 entry->name = PyUnicode_FromWideChar(dataW->cFileName, -1);
15983 if (!entry->name)
15984 goto error;
15985 int return_bytes = path->wide && PyBytes_Check(path->object);
15986 if (return_bytes) {
15987 Py_SETREF(entry->name, PyUnicode_EncodeFSDefault(entry->name));
15988 if (!entry->name)
15989 goto error;
15990 }
15991
15992 joined_path = join_path_filenameW(path->wide, dataW->cFileName);
15993 if (!joined_path)
15994 goto error;
15995
15996 entry->path = PyUnicode_FromWideChar(joined_path, -1);
15997 PyMem_Free(joined_path);
15998 if (!entry->path)
15999 goto error;
16000 if (return_bytes) {
16001 Py_SETREF(entry->path, PyUnicode_EncodeFSDefault(entry->path));
16002 if (!entry->path)
16003 goto error;
16004 }
16005
16006 find_data_to_file_info(dataW, &file_info, &reparse_tag);
16007 _Py_attribute_data_to_stat(&file_info, reparse_tag, NULL, NULL, &entry->win32_lstat);
16008
16009 /* ctime is only deprecated from 3.12, so we copy birthtime across */
16010 entry->win32_lstat.st_ctime = entry->win32_lstat.st_birthtime;
16011 entry->win32_lstat.st_ctime_nsec = entry->win32_lstat.st_birthtime_nsec;
16012
16013 return (PyObject *)entry;
16014
16015 error:
16016 Py_DECREF(entry);
16017 return NULL;
16018 }
16019
16020 #else /* POSIX */
16021
16022 static char *
join_path_filename(const char * path_narrow,const char * filename,Py_ssize_t filename_len)16023 join_path_filename(const char *path_narrow, const char* filename, Py_ssize_t filename_len)
16024 {
16025 Py_ssize_t path_len;
16026 Py_ssize_t size;
16027 char *result;
16028
16029 if (!path_narrow) { /* Default arg: "." */
16030 path_narrow = ".";
16031 path_len = 1;
16032 }
16033 else {
16034 path_len = strlen(path_narrow);
16035 }
16036
16037 if (filename_len == -1)
16038 filename_len = strlen(filename);
16039
16040 /* The +1's are for the path separator and the NUL */
16041 size = path_len + 1 + filename_len + 1;
16042 result = PyMem_New(char, size);
16043 if (!result) {
16044 PyErr_NoMemory();
16045 return NULL;
16046 }
16047 strcpy(result, path_narrow);
16048 if (path_len > 0 && result[path_len - 1] != '/')
16049 result[path_len++] = '/';
16050 strcpy(result + path_len, filename);
16051 return result;
16052 }
16053
16054 static PyObject *
DirEntry_from_posix_info(PyObject * module,path_t * path,const char * name,Py_ssize_t name_len,ino_t d_ino,unsigned char d_type)16055 DirEntry_from_posix_info(PyObject *module, path_t *path, const char *name,
16056 Py_ssize_t name_len, ino_t d_ino
16057 #ifdef HAVE_DIRENT_D_TYPE
16058 , unsigned char d_type
16059 #endif
16060 )
16061 {
16062 DirEntry *entry;
16063 char *joined_path;
16064
16065 PyObject *DirEntryType = get_posix_state(module)->DirEntryType;
16066 entry = PyObject_New(DirEntry, (PyTypeObject *)DirEntryType);
16067 if (!entry)
16068 return NULL;
16069 entry->name = NULL;
16070 entry->path = NULL;
16071 entry->stat = NULL;
16072 entry->lstat = NULL;
16073
16074 if (path->fd != -1) {
16075 entry->dir_fd = path->fd;
16076 joined_path = NULL;
16077 }
16078 else {
16079 entry->dir_fd = DEFAULT_DIR_FD;
16080 joined_path = join_path_filename(path->narrow, name, name_len);
16081 if (!joined_path)
16082 goto error;
16083 }
16084
16085 if (!path->narrow || !PyBytes_Check(path->object)) {
16086 entry->name = PyUnicode_DecodeFSDefaultAndSize(name, name_len);
16087 if (joined_path)
16088 entry->path = PyUnicode_DecodeFSDefault(joined_path);
16089 }
16090 else {
16091 entry->name = PyBytes_FromStringAndSize(name, name_len);
16092 if (joined_path)
16093 entry->path = PyBytes_FromString(joined_path);
16094 }
16095 PyMem_Free(joined_path);
16096 if (!entry->name)
16097 goto error;
16098
16099 if (path->fd != -1) {
16100 entry->path = Py_NewRef(entry->name);
16101 }
16102 else if (!entry->path)
16103 goto error;
16104
16105 #ifdef HAVE_DIRENT_D_TYPE
16106 entry->d_type = d_type;
16107 #endif
16108 entry->d_ino = d_ino;
16109
16110 return (PyObject *)entry;
16111
16112 error:
16113 Py_XDECREF(entry);
16114 return NULL;
16115 }
16116
16117 #endif
16118
16119
16120 typedef struct {
16121 PyObject_HEAD
16122 path_t path;
16123 #ifdef MS_WINDOWS
16124 HANDLE handle;
16125 WIN32_FIND_DATAW file_data;
16126 int first_time;
16127 #else /* POSIX */
16128 DIR *dirp;
16129 #endif
16130 #ifdef HAVE_FDOPENDIR
16131 int fd;
16132 #endif
16133 } ScandirIterator;
16134
16135 #ifdef MS_WINDOWS
16136
16137 static int
ScandirIterator_is_closed(ScandirIterator * iterator)16138 ScandirIterator_is_closed(ScandirIterator *iterator)
16139 {
16140 return iterator->handle == INVALID_HANDLE_VALUE;
16141 }
16142
16143 static void
ScandirIterator_closedir(ScandirIterator * iterator)16144 ScandirIterator_closedir(ScandirIterator *iterator)
16145 {
16146 HANDLE handle = iterator->handle;
16147
16148 if (handle == INVALID_HANDLE_VALUE)
16149 return;
16150
16151 iterator->handle = INVALID_HANDLE_VALUE;
16152 Py_BEGIN_ALLOW_THREADS
16153 FindClose(handle);
16154 Py_END_ALLOW_THREADS
16155 }
16156
16157 static PyObject *
ScandirIterator_iternext(ScandirIterator * iterator)16158 ScandirIterator_iternext(ScandirIterator *iterator)
16159 {
16160 WIN32_FIND_DATAW *file_data = &iterator->file_data;
16161 BOOL success;
16162 PyObject *entry;
16163
16164 /* Happens if the iterator is iterated twice, or closed explicitly */
16165 if (iterator->handle == INVALID_HANDLE_VALUE)
16166 return NULL;
16167
16168 while (1) {
16169 if (!iterator->first_time) {
16170 Py_BEGIN_ALLOW_THREADS
16171 success = FindNextFileW(iterator->handle, file_data);
16172 Py_END_ALLOW_THREADS
16173 if (!success) {
16174 /* Error or no more files */
16175 if (GetLastError() != ERROR_NO_MORE_FILES)
16176 path_error(&iterator->path);
16177 break;
16178 }
16179 }
16180 iterator->first_time = 0;
16181
16182 /* Skip over . and .. */
16183 if (wcscmp(file_data->cFileName, L".") != 0 &&
16184 wcscmp(file_data->cFileName, L"..") != 0)
16185 {
16186 PyObject *module = PyType_GetModule(Py_TYPE(iterator));
16187 entry = DirEntry_from_find_data(module, &iterator->path, file_data);
16188 if (!entry)
16189 break;
16190 return entry;
16191 }
16192
16193 /* Loop till we get a non-dot directory or finish iterating */
16194 }
16195
16196 /* Error or no more files */
16197 ScandirIterator_closedir(iterator);
16198 return NULL;
16199 }
16200
16201 #else /* POSIX */
16202
16203 static int
ScandirIterator_is_closed(ScandirIterator * iterator)16204 ScandirIterator_is_closed(ScandirIterator *iterator)
16205 {
16206 return !iterator->dirp;
16207 }
16208
16209 static void
ScandirIterator_closedir(ScandirIterator * iterator)16210 ScandirIterator_closedir(ScandirIterator *iterator)
16211 {
16212 DIR *dirp = iterator->dirp;
16213
16214 if (!dirp)
16215 return;
16216
16217 iterator->dirp = NULL;
16218 Py_BEGIN_ALLOW_THREADS
16219 #ifdef HAVE_FDOPENDIR
16220 if (iterator->path.fd != -1)
16221 rewinddir(dirp);
16222 #endif
16223 closedir(dirp);
16224 Py_END_ALLOW_THREADS
16225 return;
16226 }
16227
16228 static PyObject *
ScandirIterator_iternext(ScandirIterator * iterator)16229 ScandirIterator_iternext(ScandirIterator *iterator)
16230 {
16231 struct dirent *direntp;
16232 Py_ssize_t name_len;
16233 int is_dot;
16234 PyObject *entry;
16235
16236 /* Happens if the iterator is iterated twice, or closed explicitly */
16237 if (!iterator->dirp)
16238 return NULL;
16239
16240 while (1) {
16241 errno = 0;
16242 Py_BEGIN_ALLOW_THREADS
16243 direntp = readdir(iterator->dirp);
16244 Py_END_ALLOW_THREADS
16245
16246 if (!direntp) {
16247 /* Error or no more files */
16248 if (errno != 0)
16249 path_error(&iterator->path);
16250 break;
16251 }
16252
16253 /* Skip over . and .. */
16254 name_len = NAMLEN(direntp);
16255 is_dot = direntp->d_name[0] == '.' &&
16256 (name_len == 1 || (direntp->d_name[1] == '.' && name_len == 2));
16257 if (!is_dot) {
16258 PyObject *module = PyType_GetModule(Py_TYPE(iterator));
16259 entry = DirEntry_from_posix_info(module,
16260 &iterator->path, direntp->d_name,
16261 name_len, direntp->d_ino
16262 #ifdef HAVE_DIRENT_D_TYPE
16263 , direntp->d_type
16264 #endif
16265 );
16266 if (!entry)
16267 break;
16268 return entry;
16269 }
16270
16271 /* Loop till we get a non-dot directory or finish iterating */
16272 }
16273
16274 /* Error or no more files */
16275 ScandirIterator_closedir(iterator);
16276 return NULL;
16277 }
16278
16279 #endif
16280
16281 static PyObject *
ScandirIterator_close(ScandirIterator * self,PyObject * args)16282 ScandirIterator_close(ScandirIterator *self, PyObject *args)
16283 {
16284 ScandirIterator_closedir(self);
16285 Py_RETURN_NONE;
16286 }
16287
16288 static PyObject *
ScandirIterator_enter(PyObject * self,PyObject * args)16289 ScandirIterator_enter(PyObject *self, PyObject *args)
16290 {
16291 return Py_NewRef(self);
16292 }
16293
16294 static PyObject *
ScandirIterator_exit(ScandirIterator * self,PyObject * args)16295 ScandirIterator_exit(ScandirIterator *self, PyObject *args)
16296 {
16297 ScandirIterator_closedir(self);
16298 Py_RETURN_NONE;
16299 }
16300
16301 static void
ScandirIterator_finalize(ScandirIterator * iterator)16302 ScandirIterator_finalize(ScandirIterator *iterator)
16303 {
16304
16305 /* Save the current exception, if any. */
16306 PyObject *exc = PyErr_GetRaisedException();
16307
16308 if (!ScandirIterator_is_closed(iterator)) {
16309 ScandirIterator_closedir(iterator);
16310
16311 if (PyErr_ResourceWarning((PyObject *)iterator, 1,
16312 "unclosed scandir iterator %R", iterator)) {
16313 /* Spurious errors can appear at shutdown */
16314 if (PyErr_ExceptionMatches(PyExc_Warning)) {
16315 PyErr_WriteUnraisable((PyObject *) iterator);
16316 }
16317 }
16318 }
16319
16320 path_cleanup(&iterator->path);
16321
16322 /* Restore the saved exception. */
16323 PyErr_SetRaisedException(exc);
16324 }
16325
16326 static void
ScandirIterator_dealloc(ScandirIterator * iterator)16327 ScandirIterator_dealloc(ScandirIterator *iterator)
16328 {
16329 PyTypeObject *tp = Py_TYPE(iterator);
16330 if (PyObject_CallFinalizerFromDealloc((PyObject *)iterator) < 0)
16331 return;
16332
16333 freefunc free_func = PyType_GetSlot(tp, Py_tp_free);
16334 free_func(iterator);
16335 Py_DECREF(tp);
16336 }
16337
16338 static PyMethodDef ScandirIterator_methods[] = {
16339 {"__enter__", (PyCFunction)ScandirIterator_enter, METH_NOARGS},
16340 {"__exit__", (PyCFunction)ScandirIterator_exit, METH_VARARGS},
16341 {"close", (PyCFunction)ScandirIterator_close, METH_NOARGS},
16342 {NULL}
16343 };
16344
16345 static PyType_Slot ScandirIteratorType_slots[] = {
16346 {Py_tp_dealloc, ScandirIterator_dealloc},
16347 {Py_tp_finalize, ScandirIterator_finalize},
16348 {Py_tp_iter, PyObject_SelfIter},
16349 {Py_tp_iternext, ScandirIterator_iternext},
16350 {Py_tp_methods, ScandirIterator_methods},
16351 {0, 0},
16352 };
16353
16354 static PyType_Spec ScandirIteratorType_spec = {
16355 MODNAME ".ScandirIterator",
16356 sizeof(ScandirIterator),
16357 0,
16358 // bpo-40549: Py_TPFLAGS_BASETYPE should not be used, since
16359 // PyType_GetModule(Py_TYPE(self)) doesn't work on a subclass instance.
16360 (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE
16361 | Py_TPFLAGS_DISALLOW_INSTANTIATION),
16362 ScandirIteratorType_slots
16363 };
16364
16365 /*[clinic input]
16366 os.scandir
16367
16368 path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None
16369
16370 Return an iterator of DirEntry objects for given path.
16371
16372 path can be specified as either str, bytes, or a path-like object. If path
16373 is bytes, the names of yielded DirEntry objects will also be bytes; in
16374 all other circumstances they will be str.
16375
16376 If path is None, uses the path='.'.
16377 [clinic start generated code]*/
16378
16379 static PyObject *
os_scandir_impl(PyObject * module,path_t * path)16380 os_scandir_impl(PyObject *module, path_t *path)
16381 /*[clinic end generated code: output=6eb2668b675ca89e input=6bdd312708fc3bb0]*/
16382 {
16383 ScandirIterator *iterator;
16384 #ifdef MS_WINDOWS
16385 wchar_t *path_strW;
16386 #else
16387 const char *path_str;
16388 #ifdef HAVE_FDOPENDIR
16389 int fd = -1;
16390 #endif
16391 #endif
16392
16393 if (PySys_Audit("os.scandir", "O",
16394 path->object ? path->object : Py_None) < 0) {
16395 return NULL;
16396 }
16397
16398 PyObject *ScandirIteratorType = get_posix_state(module)->ScandirIteratorType;
16399 iterator = PyObject_New(ScandirIterator, (PyTypeObject *)ScandirIteratorType);
16400 if (!iterator)
16401 return NULL;
16402
16403 #ifdef MS_WINDOWS
16404 iterator->handle = INVALID_HANDLE_VALUE;
16405 #else
16406 iterator->dirp = NULL;
16407 #endif
16408
16409 /* Move the ownership to iterator->path */
16410 memcpy(&iterator->path, path, sizeof(path_t));
16411 memset(path, 0, sizeof(path_t));
16412
16413 #ifdef MS_WINDOWS
16414 iterator->first_time = 1;
16415
16416 path_strW = join_path_filenameW(iterator->path.wide, L"*.*");
16417 if (!path_strW)
16418 goto error;
16419
16420 Py_BEGIN_ALLOW_THREADS
16421 iterator->handle = FindFirstFileW(path_strW, &iterator->file_data);
16422 Py_END_ALLOW_THREADS
16423
16424 if (iterator->handle == INVALID_HANDLE_VALUE) {
16425 path_error(&iterator->path);
16426 PyMem_Free(path_strW);
16427 goto error;
16428 }
16429 PyMem_Free(path_strW);
16430 #else /* POSIX */
16431 errno = 0;
16432 #ifdef HAVE_FDOPENDIR
16433 if (iterator->path.fd != -1) {
16434 if (HAVE_FDOPENDIR_RUNTIME) {
16435 /* closedir() closes the FD, so we duplicate it */
16436 fd = _Py_dup(iterator->path.fd);
16437 if (fd == -1)
16438 goto error;
16439
16440 Py_BEGIN_ALLOW_THREADS
16441 iterator->dirp = fdopendir(fd);
16442 Py_END_ALLOW_THREADS
16443 } else {
16444 PyErr_SetString(PyExc_TypeError,
16445 "scandir: path should be string, bytes, os.PathLike or None, not int");
16446 return NULL;
16447 }
16448 }
16449 else
16450 #endif
16451 {
16452 if (iterator->path.narrow)
16453 path_str = iterator->path.narrow;
16454 else
16455 path_str = ".";
16456
16457 Py_BEGIN_ALLOW_THREADS
16458 iterator->dirp = opendir(path_str);
16459 Py_END_ALLOW_THREADS
16460 }
16461
16462 if (!iterator->dirp) {
16463 path_error(&iterator->path);
16464 #ifdef HAVE_FDOPENDIR
16465 if (fd != -1) {
16466 Py_BEGIN_ALLOW_THREADS
16467 close(fd);
16468 Py_END_ALLOW_THREADS
16469 }
16470 #endif
16471 goto error;
16472 }
16473 #endif
16474
16475 return (PyObject *)iterator;
16476
16477 error:
16478 Py_DECREF(iterator);
16479 return NULL;
16480 }
16481
16482 /*
16483 Return the file system path representation of the object.
16484
16485 If the object is str or bytes, then allow it to pass through with
16486 an incremented refcount. If the object defines __fspath__(), then
16487 return the result of that method. All other types raise a TypeError.
16488 */
16489 PyObject *
PyOS_FSPath(PyObject * path)16490 PyOS_FSPath(PyObject *path)
16491 {
16492 /* For error message reasons, this function is manually inlined in
16493 path_converter(). */
16494 PyObject *func = NULL;
16495 PyObject *path_repr = NULL;
16496
16497 if (PyUnicode_Check(path) || PyBytes_Check(path)) {
16498 return Py_NewRef(path);
16499 }
16500
16501 func = _PyObject_LookupSpecial(path, &_Py_ID(__fspath__));
16502 if ((NULL == func) || (func == Py_None)) {
16503 return PyErr_Format(PyExc_TypeError,
16504 "expected str, bytes or os.PathLike object, "
16505 "not %.200s",
16506 _PyType_Name(Py_TYPE(path)));
16507 }
16508
16509 path_repr = _PyObject_CallNoArgs(func);
16510 Py_DECREF(func);
16511 if (NULL == path_repr) {
16512 return NULL;
16513 }
16514
16515 if (!(PyUnicode_Check(path_repr) || PyBytes_Check(path_repr))) {
16516 PyErr_Format(PyExc_TypeError,
16517 "expected %.200s.__fspath__() to return str or bytes, "
16518 "not %.200s", _PyType_Name(Py_TYPE(path)),
16519 _PyType_Name(Py_TYPE(path_repr)));
16520 Py_DECREF(path_repr);
16521 return NULL;
16522 }
16523
16524 return path_repr;
16525 }
16526
16527 /*[clinic input]
16528 os.fspath
16529
16530 path: object
16531
16532 Return the file system path representation of the object.
16533
16534 If the object is str or bytes, then allow it to pass through as-is. If the
16535 object defines __fspath__(), then return the result of that method. All other
16536 types raise a TypeError.
16537 [clinic start generated code]*/
16538
16539 static PyObject *
os_fspath_impl(PyObject * module,PyObject * path)16540 os_fspath_impl(PyObject *module, PyObject *path)
16541 /*[clinic end generated code: output=c3c3b78ecff2914f input=e357165f7b22490f]*/
16542 {
16543 return PyOS_FSPath(path);
16544 }
16545
16546 #ifdef HAVE_GETRANDOM_SYSCALL
16547 /*[clinic input]
16548 os.getrandom
16549
16550 size: Py_ssize_t
16551 flags: int=0
16552
16553 Obtain a series of random bytes.
16554 [clinic start generated code]*/
16555
16556 static PyObject *
os_getrandom_impl(PyObject * module,Py_ssize_t size,int flags)16557 os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags)
16558 /*[clinic end generated code: output=b3a618196a61409c input=59bafac39c594947]*/
16559 {
16560 PyObject *bytes;
16561 Py_ssize_t n;
16562
16563 if (size < 0) {
16564 errno = EINVAL;
16565 return posix_error();
16566 }
16567
16568 bytes = PyBytes_FromStringAndSize(NULL, size);
16569 if (bytes == NULL) {
16570 PyErr_NoMemory();
16571 return NULL;
16572 }
16573
16574 while (1) {
16575 n = syscall(SYS_getrandom,
16576 PyBytes_AS_STRING(bytes),
16577 PyBytes_GET_SIZE(bytes),
16578 flags);
16579 if (n < 0 && errno == EINTR) {
16580 if (PyErr_CheckSignals() < 0) {
16581 goto error;
16582 }
16583
16584 /* getrandom() was interrupted by a signal: retry */
16585 continue;
16586 }
16587 break;
16588 }
16589
16590 if (n < 0) {
16591 PyErr_SetFromErrno(PyExc_OSError);
16592 goto error;
16593 }
16594
16595 if (n != size) {
16596 _PyBytes_Resize(&bytes, n);
16597 }
16598
16599 return bytes;
16600
16601 error:
16602 Py_DECREF(bytes);
16603 return NULL;
16604 }
16605 #endif /* HAVE_GETRANDOM_SYSCALL */
16606
16607 #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)
16608
16609 /* bpo-36085: Helper functions for managing DLL search directories
16610 * on win32
16611 */
16612
16613 /*[clinic input]
16614 os._add_dll_directory
16615
16616 path: path_t
16617
16618 Add a path to the DLL search path.
16619
16620 This search path is used when resolving dependencies for imported
16621 extension modules (the module itself is resolved through sys.path),
16622 and also by ctypes.
16623
16624 Returns an opaque value that may be passed to os.remove_dll_directory
16625 to remove this directory from the search path.
16626 [clinic start generated code]*/
16627
16628 static PyObject *
os__add_dll_directory_impl(PyObject * module,path_t * path)16629 os__add_dll_directory_impl(PyObject *module, path_t *path)
16630 /*[clinic end generated code: output=80b025daebb5d683 input=1de3e6c13a5808c8]*/
16631 {
16632 DLL_DIRECTORY_COOKIE cookie = 0;
16633 DWORD err = 0;
16634
16635 if (PySys_Audit("os.add_dll_directory", "(O)", path->object) < 0) {
16636 return NULL;
16637 }
16638
16639 Py_BEGIN_ALLOW_THREADS
16640 if (!(cookie = AddDllDirectory(path->wide))) {
16641 err = GetLastError();
16642 }
16643 Py_END_ALLOW_THREADS
16644
16645 if (err) {
16646 return win32_error_object_err("add_dll_directory",
16647 path->object, err);
16648 }
16649
16650 return PyCapsule_New(cookie, "DLL directory cookie", NULL);
16651 }
16652
16653 /*[clinic input]
16654 os._remove_dll_directory
16655
16656 cookie: object
16657
16658 Removes a path from the DLL search path.
16659
16660 The parameter is an opaque value that was returned from
16661 os.add_dll_directory. You can only remove directories that you added
16662 yourself.
16663 [clinic start generated code]*/
16664
16665 static PyObject *
os__remove_dll_directory_impl(PyObject * module,PyObject * cookie)16666 os__remove_dll_directory_impl(PyObject *module, PyObject *cookie)
16667 /*[clinic end generated code: output=594350433ae535bc input=c1d16a7e7d9dc5dc]*/
16668 {
16669 DLL_DIRECTORY_COOKIE cookieValue;
16670 DWORD err = 0;
16671
16672 if (!PyCapsule_IsValid(cookie, "DLL directory cookie")) {
16673 PyErr_SetString(PyExc_TypeError,
16674 "Provided cookie was not returned from os.add_dll_directory");
16675 return NULL;
16676 }
16677
16678 cookieValue = (DLL_DIRECTORY_COOKIE)PyCapsule_GetPointer(
16679 cookie, "DLL directory cookie");
16680
16681 Py_BEGIN_ALLOW_THREADS
16682 if (!RemoveDllDirectory(cookieValue)) {
16683 err = GetLastError();
16684 }
16685 Py_END_ALLOW_THREADS
16686
16687 if (err) {
16688 return win32_error_object_err("remove_dll_directory",
16689 NULL, err);
16690 }
16691
16692 if (PyCapsule_SetName(cookie, NULL)) {
16693 return NULL;
16694 }
16695
16696 Py_RETURN_NONE;
16697 }
16698
16699 #endif /* MS_WINDOWS_APP || MS_WINDOWS_SYSTEM */
16700
16701
16702 /* Only check if WIFEXITED is available: expect that it comes
16703 with WEXITSTATUS, WIFSIGNALED, etc.
16704
16705 os.waitstatus_to_exitcode() is implemented in C and not in Python, so
16706 subprocess can safely call it during late Python finalization without
16707 risking that used os attributes were set to None by finalize_modules(). */
16708 #if defined(WIFEXITED) || defined(MS_WINDOWS)
16709 /*[clinic input]
16710 os.waitstatus_to_exitcode
16711
16712 status as status_obj: object
16713
16714 Convert a wait status to an exit code.
16715
16716 On Unix:
16717
16718 * If WIFEXITED(status) is true, return WEXITSTATUS(status).
16719 * If WIFSIGNALED(status) is true, return -WTERMSIG(status).
16720 * Otherwise, raise a ValueError.
16721
16722 On Windows, return status shifted right by 8 bits.
16723
16724 On Unix, if the process is being traced or if waitpid() was called with
16725 WUNTRACED option, the caller must first check if WIFSTOPPED(status) is true.
16726 This function must not be called if WIFSTOPPED(status) is true.
16727 [clinic start generated code]*/
16728
16729 static PyObject *
os_waitstatus_to_exitcode_impl(PyObject * module,PyObject * status_obj)16730 os_waitstatus_to_exitcode_impl(PyObject *module, PyObject *status_obj)
16731 /*[clinic end generated code: output=db50b1b0ba3c7153 input=7fe2d7fdaea3db42]*/
16732 {
16733 #ifndef MS_WINDOWS
16734 int status = PyLong_AsInt(status_obj);
16735 if (status == -1 && PyErr_Occurred()) {
16736 return NULL;
16737 }
16738
16739 WAIT_TYPE wait_status;
16740 WAIT_STATUS_INT(wait_status) = status;
16741 int exitcode;
16742 if (WIFEXITED(wait_status)) {
16743 exitcode = WEXITSTATUS(wait_status);
16744 /* Sanity check to provide warranty on the function behavior.
16745 It should not occur in practice */
16746 if (exitcode < 0) {
16747 PyErr_Format(PyExc_ValueError, "invalid WEXITSTATUS: %i", exitcode);
16748 return NULL;
16749 }
16750 }
16751 else if (WIFSIGNALED(wait_status)) {
16752 int signum = WTERMSIG(wait_status);
16753 /* Sanity check to provide warranty on the function behavior.
16754 It should not occurs in practice */
16755 if (signum <= 0) {
16756 PyErr_Format(PyExc_ValueError, "invalid WTERMSIG: %i", signum);
16757 return NULL;
16758 }
16759 exitcode = -signum;
16760 } else if (WIFSTOPPED(wait_status)) {
16761 /* Status only received if the process is being traced
16762 or if waitpid() was called with WUNTRACED option. */
16763 int signum = WSTOPSIG(wait_status);
16764 PyErr_Format(PyExc_ValueError,
16765 "process stopped by delivery of signal %i",
16766 signum);
16767 return NULL;
16768 }
16769 else {
16770 PyErr_Format(PyExc_ValueError, "invalid wait status: %i", status);
16771 return NULL;
16772 }
16773 return PyLong_FromLong(exitcode);
16774 #else
16775 /* Windows implementation: see os.waitpid() implementation
16776 which uses _cwait(). */
16777 unsigned long long status = PyLong_AsUnsignedLongLong(status_obj);
16778 if (status == (unsigned long long)-1 && PyErr_Occurred()) {
16779 return NULL;
16780 }
16781
16782 unsigned long long exitcode = (status >> 8);
16783 /* ExitProcess() accepts an UINT type:
16784 reject exit code which doesn't fit in an UINT */
16785 if (exitcode > UINT_MAX) {
16786 PyErr_Format(PyExc_ValueError, "invalid exit code: %llu", exitcode);
16787 return NULL;
16788 }
16789 return PyLong_FromUnsignedLong((unsigned long)exitcode);
16790 #endif
16791 }
16792 #endif
16793
16794 #if defined(MS_WINDOWS)
16795 /*[clinic input]
16796 os._supports_virtual_terminal
16797
16798 Checks if virtual terminal is supported in windows
16799 [clinic start generated code]*/
16800
16801 static PyObject *
os__supports_virtual_terminal_impl(PyObject * module)16802 os__supports_virtual_terminal_impl(PyObject *module)
16803 /*[clinic end generated code: output=bd0556a6d9d99fe6 input=0752c98e5d321542]*/
16804 {
16805 DWORD mode = 0;
16806 HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
16807 if (!GetConsoleMode(handle, &mode)) {
16808 Py_RETURN_FALSE;
16809 }
16810 return PyBool_FromLong(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING);
16811 }
16812 #endif
16813
16814 /*[clinic input]
16815 os._inputhook
16816
16817 Calls PyOS_CallInputHook droppong the GIL first
16818 [clinic start generated code]*/
16819
16820 static PyObject *
os__inputhook_impl(PyObject * module)16821 os__inputhook_impl(PyObject *module)
16822 /*[clinic end generated code: output=525aca4ef3c6149f input=fc531701930d064f]*/
16823 {
16824 int result = 0;
16825 if (PyOS_InputHook) {
16826 Py_BEGIN_ALLOW_THREADS;
16827 result = PyOS_InputHook();
16828 Py_END_ALLOW_THREADS;
16829 }
16830 return PyLong_FromLong(result);
16831 }
16832
16833 /*[clinic input]
16834 os._is_inputhook_installed
16835
16836 Checks if PyOS_CallInputHook is set
16837 [clinic start generated code]*/
16838
16839 static PyObject *
os__is_inputhook_installed_impl(PyObject * module)16840 os__is_inputhook_installed_impl(PyObject *module)
16841 /*[clinic end generated code: output=3b3eab4f672c689a input=ff177c9938dd76d8]*/
16842 {
16843 return PyBool_FromLong(PyOS_InputHook != NULL);
16844 }
16845
16846 static PyMethodDef posix_methods[] = {
16847
16848 OS_STAT_METHODDEF
16849 OS_ACCESS_METHODDEF
16850 OS_TTYNAME_METHODDEF
16851 OS_CHDIR_METHODDEF
16852 OS_CHFLAGS_METHODDEF
16853 OS_CHMOD_METHODDEF
16854 OS_FCHMOD_METHODDEF
16855 OS_LCHMOD_METHODDEF
16856 OS_CHOWN_METHODDEF
16857 OS_FCHOWN_METHODDEF
16858 OS_LCHOWN_METHODDEF
16859 OS_LCHFLAGS_METHODDEF
16860 OS_CHROOT_METHODDEF
16861 OS_CTERMID_METHODDEF
16862 OS_GETCWD_METHODDEF
16863 OS_GETCWDB_METHODDEF
16864 OS_LINK_METHODDEF
16865 OS_LISTDIR_METHODDEF
16866 OS_LISTDRIVES_METHODDEF
16867 OS_LISTMOUNTS_METHODDEF
16868 OS_LISTVOLUMES_METHODDEF
16869 OS_LSTAT_METHODDEF
16870 OS_MKDIR_METHODDEF
16871 OS_NICE_METHODDEF
16872 OS_GETPRIORITY_METHODDEF
16873 OS_SETPRIORITY_METHODDEF
16874 OS_POSIX_SPAWN_METHODDEF
16875 OS_POSIX_SPAWNP_METHODDEF
16876 OS_READLINK_METHODDEF
16877 OS_COPY_FILE_RANGE_METHODDEF
16878 OS_SPLICE_METHODDEF
16879 OS_RENAME_METHODDEF
16880 OS_REPLACE_METHODDEF
16881 OS_RMDIR_METHODDEF
16882 OS_SYMLINK_METHODDEF
16883 OS_SYSTEM_METHODDEF
16884 OS_UMASK_METHODDEF
16885 OS_UNAME_METHODDEF
16886 OS_UNLINK_METHODDEF
16887 OS_REMOVE_METHODDEF
16888 OS_UTIME_METHODDEF
16889 OS_TIMES_METHODDEF
16890 OS__EXIT_METHODDEF
16891 OS__FCOPYFILE_METHODDEF
16892 OS_EXECV_METHODDEF
16893 OS_EXECVE_METHODDEF
16894 OS_SPAWNV_METHODDEF
16895 OS_SPAWNVE_METHODDEF
16896 OS_FORK1_METHODDEF
16897 OS_FORK_METHODDEF
16898 OS_REGISTER_AT_FORK_METHODDEF
16899 OS_SCHED_GET_PRIORITY_MAX_METHODDEF
16900 OS_SCHED_GET_PRIORITY_MIN_METHODDEF
16901 OS_SCHED_GETPARAM_METHODDEF
16902 OS_SCHED_GETSCHEDULER_METHODDEF
16903 OS_SCHED_RR_GET_INTERVAL_METHODDEF
16904 OS_SCHED_SETPARAM_METHODDEF
16905 OS_SCHED_SETSCHEDULER_METHODDEF
16906 OS_SCHED_YIELD_METHODDEF
16907 OS_SCHED_SETAFFINITY_METHODDEF
16908 OS_SCHED_GETAFFINITY_METHODDEF
16909 OS_POSIX_OPENPT_METHODDEF
16910 OS_GRANTPT_METHODDEF
16911 OS_UNLOCKPT_METHODDEF
16912 OS_PTSNAME_METHODDEF
16913 OS_OPENPTY_METHODDEF
16914 OS_LOGIN_TTY_METHODDEF
16915 OS_FORKPTY_METHODDEF
16916 OS_GETEGID_METHODDEF
16917 OS_GETEUID_METHODDEF
16918 OS_GETGID_METHODDEF
16919 OS_GETGROUPLIST_METHODDEF
16920 OS_GETGROUPS_METHODDEF
16921 OS_GETPID_METHODDEF
16922 OS_GETPGRP_METHODDEF
16923 OS_GETPPID_METHODDEF
16924 OS_GETUID_METHODDEF
16925 OS_GETLOGIN_METHODDEF
16926 OS_KILL_METHODDEF
16927 OS_KILLPG_METHODDEF
16928 OS_PLOCK_METHODDEF
16929 OS_STARTFILE_METHODDEF
16930 OS_SETUID_METHODDEF
16931 OS_SETEUID_METHODDEF
16932 OS_SETREUID_METHODDEF
16933 OS_SETGID_METHODDEF
16934 OS_SETEGID_METHODDEF
16935 OS_SETREGID_METHODDEF
16936 OS_SETGROUPS_METHODDEF
16937 OS_INITGROUPS_METHODDEF
16938 OS_GETPGID_METHODDEF
16939 OS_SETPGRP_METHODDEF
16940 OS_WAIT_METHODDEF
16941 OS_WAIT3_METHODDEF
16942 OS_WAIT4_METHODDEF
16943 OS_WAITID_METHODDEF
16944 OS_WAITPID_METHODDEF
16945 OS_PIDFD_OPEN_METHODDEF
16946 OS_GETSID_METHODDEF
16947 OS_SETSID_METHODDEF
16948 OS_SETPGID_METHODDEF
16949 OS_TCGETPGRP_METHODDEF
16950 OS_TCSETPGRP_METHODDEF
16951 OS_OPEN_METHODDEF
16952 OS_CLOSE_METHODDEF
16953 OS_CLOSERANGE_METHODDEF
16954 OS_DEVICE_ENCODING_METHODDEF
16955 OS_DUP_METHODDEF
16956 OS_DUP2_METHODDEF
16957 OS_LOCKF_METHODDEF
16958 OS_LSEEK_METHODDEF
16959 OS_READ_METHODDEF
16960 OS_READV_METHODDEF
16961 OS_PREAD_METHODDEF
16962 OS_PREADV_METHODDEF
16963 OS_WRITE_METHODDEF
16964 OS_WRITEV_METHODDEF
16965 OS_PWRITE_METHODDEF
16966 OS_PWRITEV_METHODDEF
16967 OS_SENDFILE_METHODDEF
16968 OS_FSTAT_METHODDEF
16969 OS_ISATTY_METHODDEF
16970 OS_PIPE_METHODDEF
16971 OS_PIPE2_METHODDEF
16972 OS_MKFIFO_METHODDEF
16973 OS_MKNOD_METHODDEF
16974 OS_MAJOR_METHODDEF
16975 OS_MINOR_METHODDEF
16976 OS_MAKEDEV_METHODDEF
16977 OS_FTRUNCATE_METHODDEF
16978 OS_TRUNCATE_METHODDEF
16979 OS_POSIX_FALLOCATE_METHODDEF
16980 OS_POSIX_FADVISE_METHODDEF
16981 OS_PUTENV_METHODDEF
16982 OS_UNSETENV_METHODDEF
16983 OS_STRERROR_METHODDEF
16984 OS_FCHDIR_METHODDEF
16985 OS_FSYNC_METHODDEF
16986 OS_SYNC_METHODDEF
16987 OS_FDATASYNC_METHODDEF
16988 OS_WCOREDUMP_METHODDEF
16989 OS_WIFCONTINUED_METHODDEF
16990 OS_WIFSTOPPED_METHODDEF
16991 OS_WIFSIGNALED_METHODDEF
16992 OS_WIFEXITED_METHODDEF
16993 OS_WEXITSTATUS_METHODDEF
16994 OS_WTERMSIG_METHODDEF
16995 OS_WSTOPSIG_METHODDEF
16996 OS_FSTATVFS_METHODDEF
16997 OS_STATVFS_METHODDEF
16998 OS_CONFSTR_METHODDEF
16999 OS_SYSCONF_METHODDEF
17000 OS_FPATHCONF_METHODDEF
17001 OS_PATHCONF_METHODDEF
17002 OS_ABORT_METHODDEF
17003 OS__GETFULLPATHNAME_METHODDEF
17004 OS__GETDISKUSAGE_METHODDEF
17005 OS__GETFINALPATHNAME_METHODDEF
17006 OS__FINDFIRSTFILE_METHODDEF
17007 OS__GETVOLUMEPATHNAME_METHODDEF
17008 OS__PATH_SPLITROOT_METHODDEF
17009 OS__PATH_SPLITROOT_EX_METHODDEF
17010 OS__PATH_NORMPATH_METHODDEF
17011 OS_GETLOADAVG_METHODDEF
17012 OS_URANDOM_METHODDEF
17013 OS_SETRESUID_METHODDEF
17014 OS_SETRESGID_METHODDEF
17015 OS_GETRESUID_METHODDEF
17016 OS_GETRESGID_METHODDEF
17017
17018 OS_GETXATTR_METHODDEF
17019 OS_SETXATTR_METHODDEF
17020 OS_REMOVEXATTR_METHODDEF
17021 OS_LISTXATTR_METHODDEF
17022
17023 OS_GET_TERMINAL_SIZE_METHODDEF
17024 OS_CPU_COUNT_METHODDEF
17025 OS_GET_INHERITABLE_METHODDEF
17026 OS_SET_INHERITABLE_METHODDEF
17027 OS_GET_HANDLE_INHERITABLE_METHODDEF
17028 OS_SET_HANDLE_INHERITABLE_METHODDEF
17029 OS_GET_BLOCKING_METHODDEF
17030 OS_SET_BLOCKING_METHODDEF
17031 OS_SCANDIR_METHODDEF
17032 OS_FSPATH_METHODDEF
17033 OS_GETRANDOM_METHODDEF
17034 OS_MEMFD_CREATE_METHODDEF
17035 OS_EVENTFD_METHODDEF
17036 OS_EVENTFD_READ_METHODDEF
17037 OS_EVENTFD_WRITE_METHODDEF
17038 OS__ADD_DLL_DIRECTORY_METHODDEF
17039 OS__REMOVE_DLL_DIRECTORY_METHODDEF
17040 OS_WAITSTATUS_TO_EXITCODE_METHODDEF
17041 OS_SETNS_METHODDEF
17042 OS_UNSHARE_METHODDEF
17043 OS_TIMERFD_CREATE_METHODDEF
17044 OS_TIMERFD_SETTIME_METHODDEF
17045 OS_TIMERFD_SETTIME_NS_METHODDEF
17046 OS_TIMERFD_GETTIME_METHODDEF
17047 OS_TIMERFD_GETTIME_NS_METHODDEF
17048
17049 OS__PATH_ISDEVDRIVE_METHODDEF
17050 OS__PATH_ISDIR_METHODDEF
17051 OS__PATH_ISFILE_METHODDEF
17052 OS__PATH_ISLINK_METHODDEF
17053 OS__PATH_ISJUNCTION_METHODDEF
17054 OS__PATH_EXISTS_METHODDEF
17055 OS__PATH_LEXISTS_METHODDEF
17056
17057 OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
17058 OS__INPUTHOOK_METHODDEF
17059 OS__IS_INPUTHOOK_INSTALLED_METHODDEF
17060 {NULL, NULL} /* Sentinel */
17061 };
17062
17063 static int
all_ins(PyObject * m)17064 all_ins(PyObject *m)
17065 {
17066 #ifdef F_OK
17067 if (PyModule_AddIntMacro(m, F_OK)) return -1;
17068 #endif
17069 #ifdef R_OK
17070 if (PyModule_AddIntMacro(m, R_OK)) return -1;
17071 #endif
17072 #ifdef W_OK
17073 if (PyModule_AddIntMacro(m, W_OK)) return -1;
17074 #endif
17075 #ifdef X_OK
17076 if (PyModule_AddIntMacro(m, X_OK)) return -1;
17077 #endif
17078 #ifdef NGROUPS_MAX
17079 if (PyModule_AddIntMacro(m, NGROUPS_MAX)) return -1;
17080 #endif
17081 #ifdef TMP_MAX
17082 if (PyModule_AddIntMacro(m, TMP_MAX)) return -1;
17083 #endif
17084 #ifdef WCONTINUED
17085 if (PyModule_AddIntMacro(m, WCONTINUED)) return -1;
17086 #endif
17087 #ifdef WNOHANG
17088 if (PyModule_AddIntMacro(m, WNOHANG)) return -1;
17089 #endif
17090 #ifdef WUNTRACED
17091 if (PyModule_AddIntMacro(m, WUNTRACED)) return -1;
17092 #endif
17093 #ifdef O_RDONLY
17094 if (PyModule_AddIntMacro(m, O_RDONLY)) return -1;
17095 #endif
17096 #ifdef O_WRONLY
17097 if (PyModule_AddIntMacro(m, O_WRONLY)) return -1;
17098 #endif
17099 #ifdef O_RDWR
17100 if (PyModule_AddIntMacro(m, O_RDWR)) return -1;
17101 #endif
17102 #ifdef O_NDELAY
17103 if (PyModule_AddIntMacro(m, O_NDELAY)) return -1;
17104 #endif
17105 #ifdef O_NONBLOCK
17106 if (PyModule_AddIntMacro(m, O_NONBLOCK)) return -1;
17107 #endif
17108 #ifdef O_APPEND
17109 if (PyModule_AddIntMacro(m, O_APPEND)) return -1;
17110 #endif
17111 #ifdef O_DSYNC
17112 if (PyModule_AddIntMacro(m, O_DSYNC)) return -1;
17113 #endif
17114 #ifdef O_RSYNC
17115 if (PyModule_AddIntMacro(m, O_RSYNC)) return -1;
17116 #endif
17117 #ifdef O_SYNC
17118 if (PyModule_AddIntMacro(m, O_SYNC)) return -1;
17119 #endif
17120 #ifdef O_NOCTTY
17121 if (PyModule_AddIntMacro(m, O_NOCTTY)) return -1;
17122 #endif
17123 #ifdef O_CREAT
17124 if (PyModule_AddIntMacro(m, O_CREAT)) return -1;
17125 #endif
17126 #ifdef O_EXCL
17127 if (PyModule_AddIntMacro(m, O_EXCL)) return -1;
17128 #endif
17129 #ifdef O_TRUNC
17130 if (PyModule_AddIntMacro(m, O_TRUNC)) return -1;
17131 #endif
17132 #ifdef O_BINARY
17133 if (PyModule_AddIntMacro(m, O_BINARY)) return -1;
17134 #endif
17135 #ifdef O_TEXT
17136 if (PyModule_AddIntMacro(m, O_TEXT)) return -1;
17137 #endif
17138 #ifdef O_XATTR
17139 if (PyModule_AddIntMacro(m, O_XATTR)) return -1;
17140 #endif
17141 #ifdef O_LARGEFILE
17142 if (PyModule_AddIntMacro(m, O_LARGEFILE)) return -1;
17143 #endif
17144 #ifndef __GNU__
17145 #ifdef O_SHLOCK
17146 if (PyModule_AddIntMacro(m, O_SHLOCK)) return -1;
17147 #endif
17148 #ifdef O_EXLOCK
17149 if (PyModule_AddIntMacro(m, O_EXLOCK)) return -1;
17150 #endif
17151 #endif
17152 #ifdef O_EXEC
17153 if (PyModule_AddIntMacro(m, O_EXEC)) return -1;
17154 #endif
17155 #ifdef O_SEARCH
17156 if (PyModule_AddIntMacro(m, O_SEARCH)) return -1;
17157 #endif
17158 #ifdef O_PATH
17159 if (PyModule_AddIntMacro(m, O_PATH)) return -1;
17160 #endif
17161 #ifdef O_TTY_INIT
17162 if (PyModule_AddIntMacro(m, O_TTY_INIT)) return -1;
17163 #endif
17164 #ifdef O_TMPFILE
17165 if (PyModule_AddIntMacro(m, O_TMPFILE)) return -1;
17166 #endif
17167 #ifdef PRIO_PROCESS
17168 if (PyModule_AddIntMacro(m, PRIO_PROCESS)) return -1;
17169 #endif
17170 #ifdef PRIO_PGRP
17171 if (PyModule_AddIntMacro(m, PRIO_PGRP)) return -1;
17172 #endif
17173 #ifdef PRIO_USER
17174 if (PyModule_AddIntMacro(m, PRIO_USER)) return -1;
17175 #endif
17176 #ifdef PRIO_DARWIN_THREAD
17177 if (PyModule_AddIntMacro(m, PRIO_DARWIN_THREAD)) return -1;
17178 #endif
17179 #ifdef PRIO_DARWIN_PROCESS
17180 if (PyModule_AddIntMacro(m, PRIO_DARWIN_PROCESS)) return -1;
17181 #endif
17182 #ifdef PRIO_DARWIN_BG
17183 if (PyModule_AddIntMacro(m, PRIO_DARWIN_BG)) return -1;
17184 #endif
17185 #ifdef PRIO_DARWIN_NONUI
17186 if (PyModule_AddIntMacro(m, PRIO_DARWIN_NONUI)) return -1;
17187 #endif
17188 #ifdef O_CLOEXEC
17189 if (PyModule_AddIntMacro(m, O_CLOEXEC)) return -1;
17190 #endif
17191 #ifdef O_ACCMODE
17192 if (PyModule_AddIntMacro(m, O_ACCMODE)) return -1;
17193 #endif
17194 #ifdef O_EVTONLY
17195 if (PyModule_AddIntMacro(m, O_EVTONLY)) return -1;
17196 #endif
17197 #ifdef O_FSYNC
17198 if (PyModule_AddIntMacro(m, O_FSYNC)) return -1;
17199 #endif
17200 #ifdef O_SYMLINK
17201 if (PyModule_AddIntMacro(m, O_SYMLINK)) return -1;
17202 #endif
17203
17204 #ifdef SEEK_HOLE
17205 if (PyModule_AddIntMacro(m, SEEK_HOLE)) return -1;
17206 #endif
17207 #ifdef SEEK_DATA
17208 if (PyModule_AddIntMacro(m, SEEK_DATA)) return -1;
17209 #endif
17210
17211 /* MS Windows */
17212 #ifdef O_NOINHERIT
17213 /* Don't inherit in child processes. */
17214 if (PyModule_AddIntMacro(m, O_NOINHERIT)) return -1;
17215 #endif
17216 #ifdef _O_SHORT_LIVED
17217 /* Optimize for short life (keep in memory). */
17218 /* MS forgot to define this one with a non-underscore form too. */
17219 if (PyModule_AddIntConstant(m, "O_SHORT_LIVED", _O_SHORT_LIVED)) return -1;
17220 #endif
17221 #ifdef O_TEMPORARY
17222 /* Automatically delete when last handle is closed. */
17223 if (PyModule_AddIntMacro(m, O_TEMPORARY)) return -1;
17224 #endif
17225 #ifdef O_RANDOM
17226 /* Optimize for random access. */
17227 if (PyModule_AddIntMacro(m, O_RANDOM)) return -1;
17228 #endif
17229 #ifdef O_SEQUENTIAL
17230 /* Optimize for sequential access. */
17231 if (PyModule_AddIntMacro(m, O_SEQUENTIAL)) return -1;
17232 #endif
17233
17234 /* GNU extensions. */
17235 #ifdef O_ASYNC
17236 /* Send a SIGIO signal whenever input or output
17237 becomes available on file descriptor */
17238 if (PyModule_AddIntMacro(m, O_ASYNC)) return -1;
17239 #endif
17240 #ifdef O_DIRECT
17241 /* Direct disk access. */
17242 if (PyModule_AddIntMacro(m, O_DIRECT)) return -1;
17243 #endif
17244 #ifdef O_DIRECTORY
17245 /* Must be a directory. */
17246 if (PyModule_AddIntMacro(m, O_DIRECTORY)) return -1;
17247 #endif
17248 #ifdef O_NOFOLLOW
17249 /* Do not follow links. */
17250 if (PyModule_AddIntMacro(m, O_NOFOLLOW)) return -1;
17251 #endif
17252 #ifdef O_NOFOLLOW_ANY
17253 if (PyModule_AddIntMacro(m, O_NOFOLLOW_ANY)) return -1;
17254 #endif
17255 #ifdef O_NOLINKS
17256 /* Fails if link count of the named file is greater than 1 */
17257 if (PyModule_AddIntMacro(m, O_NOLINKS)) return -1;
17258 #endif
17259 #ifdef O_NOATIME
17260 /* Do not update the access time. */
17261 if (PyModule_AddIntMacro(m, O_NOATIME)) return -1;
17262 #endif
17263
17264 /* These come from sysexits.h */
17265 #ifdef EX_OK
17266 if (PyModule_AddIntMacro(m, EX_OK)) return -1;
17267 #endif /* EX_OK */
17268 #ifdef EX_USAGE
17269 if (PyModule_AddIntMacro(m, EX_USAGE)) return -1;
17270 #endif /* EX_USAGE */
17271 #ifdef EX_DATAERR
17272 if (PyModule_AddIntMacro(m, EX_DATAERR)) return -1;
17273 #endif /* EX_DATAERR */
17274 #ifdef EX_NOINPUT
17275 if (PyModule_AddIntMacro(m, EX_NOINPUT)) return -1;
17276 #endif /* EX_NOINPUT */
17277 #ifdef EX_NOUSER
17278 if (PyModule_AddIntMacro(m, EX_NOUSER)) return -1;
17279 #endif /* EX_NOUSER */
17280 #ifdef EX_NOHOST
17281 if (PyModule_AddIntMacro(m, EX_NOHOST)) return -1;
17282 #endif /* EX_NOHOST */
17283 #ifdef EX_UNAVAILABLE
17284 if (PyModule_AddIntMacro(m, EX_UNAVAILABLE)) return -1;
17285 #endif /* EX_UNAVAILABLE */
17286 #ifdef EX_SOFTWARE
17287 if (PyModule_AddIntMacro(m, EX_SOFTWARE)) return -1;
17288 #endif /* EX_SOFTWARE */
17289 #ifdef EX_OSERR
17290 if (PyModule_AddIntMacro(m, EX_OSERR)) return -1;
17291 #endif /* EX_OSERR */
17292 #ifdef EX_OSFILE
17293 if (PyModule_AddIntMacro(m, EX_OSFILE)) return -1;
17294 #endif /* EX_OSFILE */
17295 #ifdef EX_CANTCREAT
17296 if (PyModule_AddIntMacro(m, EX_CANTCREAT)) return -1;
17297 #endif /* EX_CANTCREAT */
17298 #ifdef EX_IOERR
17299 if (PyModule_AddIntMacro(m, EX_IOERR)) return -1;
17300 #endif /* EX_IOERR */
17301 #ifdef EX_TEMPFAIL
17302 if (PyModule_AddIntMacro(m, EX_TEMPFAIL)) return -1;
17303 #endif /* EX_TEMPFAIL */
17304 #ifdef EX_PROTOCOL
17305 if (PyModule_AddIntMacro(m, EX_PROTOCOL)) return -1;
17306 #endif /* EX_PROTOCOL */
17307 #ifdef EX_NOPERM
17308 if (PyModule_AddIntMacro(m, EX_NOPERM)) return -1;
17309 #endif /* EX_NOPERM */
17310 #ifdef EX_CONFIG
17311 if (PyModule_AddIntMacro(m, EX_CONFIG)) return -1;
17312 #endif /* EX_CONFIG */
17313 #ifdef EX_NOTFOUND
17314 if (PyModule_AddIntMacro(m, EX_NOTFOUND)) return -1;
17315 #endif /* EX_NOTFOUND */
17316
17317 /* statvfs */
17318 #ifdef ST_RDONLY
17319 if (PyModule_AddIntMacro(m, ST_RDONLY)) return -1;
17320 #endif /* ST_RDONLY */
17321 #ifdef ST_NOSUID
17322 if (PyModule_AddIntMacro(m, ST_NOSUID)) return -1;
17323 #endif /* ST_NOSUID */
17324
17325 /* GNU extensions */
17326 #ifdef ST_NODEV
17327 if (PyModule_AddIntMacro(m, ST_NODEV)) return -1;
17328 #endif /* ST_NODEV */
17329 #ifdef ST_NOEXEC
17330 if (PyModule_AddIntMacro(m, ST_NOEXEC)) return -1;
17331 #endif /* ST_NOEXEC */
17332 #ifdef ST_SYNCHRONOUS
17333 if (PyModule_AddIntMacro(m, ST_SYNCHRONOUS)) return -1;
17334 #endif /* ST_SYNCHRONOUS */
17335 #ifdef ST_MANDLOCK
17336 if (PyModule_AddIntMacro(m, ST_MANDLOCK)) return -1;
17337 #endif /* ST_MANDLOCK */
17338 #ifdef ST_WRITE
17339 if (PyModule_AddIntMacro(m, ST_WRITE)) return -1;
17340 #endif /* ST_WRITE */
17341 #ifdef ST_APPEND
17342 if (PyModule_AddIntMacro(m, ST_APPEND)) return -1;
17343 #endif /* ST_APPEND */
17344 #ifdef ST_NOATIME
17345 if (PyModule_AddIntMacro(m, ST_NOATIME)) return -1;
17346 #endif /* ST_NOATIME */
17347 #ifdef ST_NODIRATIME
17348 if (PyModule_AddIntMacro(m, ST_NODIRATIME)) return -1;
17349 #endif /* ST_NODIRATIME */
17350 #ifdef ST_RELATIME
17351 if (PyModule_AddIntMacro(m, ST_RELATIME)) return -1;
17352 #endif /* ST_RELATIME */
17353
17354 /* FreeBSD sendfile() constants */
17355 #ifdef SF_NODISKIO
17356 if (PyModule_AddIntMacro(m, SF_NODISKIO)) return -1;
17357 #endif
17358 /* is obsolete since the 11.x release */
17359 #ifdef SF_MNOWAIT
17360 if (PyModule_AddIntMacro(m, SF_MNOWAIT)) return -1;
17361 #endif
17362 #ifdef SF_SYNC
17363 if (PyModule_AddIntMacro(m, SF_SYNC)) return -1;
17364 #endif
17365 #ifdef SF_NOCACHE
17366 if (PyModule_AddIntMacro(m, SF_NOCACHE)) return -1;
17367 #endif
17368
17369 #ifdef TFD_NONBLOCK
17370 if (PyModule_AddIntMacro(m, TFD_NONBLOCK)) return -1;
17371 #endif
17372 #ifdef TFD_CLOEXEC
17373 if (PyModule_AddIntMacro(m, TFD_CLOEXEC)) return -1;
17374 #endif
17375 #ifdef TFD_TIMER_ABSTIME
17376 if (PyModule_AddIntMacro(m, TFD_TIMER_ABSTIME)) return -1;
17377 #endif
17378 #ifdef TFD_TIMER_CANCEL_ON_SET
17379 if (PyModule_AddIntMacro(m, TFD_TIMER_CANCEL_ON_SET)) return -1;
17380 #endif
17381
17382 /* constants for posix_fadvise */
17383 #ifdef POSIX_FADV_NORMAL
17384 if (PyModule_AddIntMacro(m, POSIX_FADV_NORMAL)) return -1;
17385 #endif
17386 #ifdef POSIX_FADV_SEQUENTIAL
17387 if (PyModule_AddIntMacro(m, POSIX_FADV_SEQUENTIAL)) return -1;
17388 #endif
17389 #ifdef POSIX_FADV_RANDOM
17390 if (PyModule_AddIntMacro(m, POSIX_FADV_RANDOM)) return -1;
17391 #endif
17392 #ifdef POSIX_FADV_NOREUSE
17393 if (PyModule_AddIntMacro(m, POSIX_FADV_NOREUSE)) return -1;
17394 #endif
17395 #ifdef POSIX_FADV_WILLNEED
17396 if (PyModule_AddIntMacro(m, POSIX_FADV_WILLNEED)) return -1;
17397 #endif
17398 #ifdef POSIX_FADV_DONTNEED
17399 if (PyModule_AddIntMacro(m, POSIX_FADV_DONTNEED)) return -1;
17400 #endif
17401
17402 /* constants for waitid */
17403 #if defined(HAVE_SYS_WAIT_H) && defined(HAVE_WAITID)
17404 if (PyModule_AddIntMacro(m, P_PID)) return -1;
17405 if (PyModule_AddIntMacro(m, P_PGID)) return -1;
17406 if (PyModule_AddIntMacro(m, P_ALL)) return -1;
17407 #ifdef P_PIDFD
17408 if (PyModule_AddIntMacro(m, P_PIDFD)) return -1;
17409 #endif
17410 #ifdef PIDFD_NONBLOCK
17411 if (PyModule_AddIntMacro(m, PIDFD_NONBLOCK)) return -1;
17412 #endif
17413 #endif
17414 #ifdef WEXITED
17415 if (PyModule_AddIntMacro(m, WEXITED)) return -1;
17416 #endif
17417 #ifdef WNOWAIT
17418 if (PyModule_AddIntMacro(m, WNOWAIT)) return -1;
17419 #endif
17420 #ifdef WSTOPPED
17421 if (PyModule_AddIntMacro(m, WSTOPPED)) return -1;
17422 #endif
17423 #ifdef CLD_EXITED
17424 if (PyModule_AddIntMacro(m, CLD_EXITED)) return -1;
17425 #endif
17426 #ifdef CLD_KILLED
17427 if (PyModule_AddIntMacro(m, CLD_KILLED)) return -1;
17428 #endif
17429 #ifdef CLD_DUMPED
17430 if (PyModule_AddIntMacro(m, CLD_DUMPED)) return -1;
17431 #endif
17432 #ifdef CLD_TRAPPED
17433 if (PyModule_AddIntMacro(m, CLD_TRAPPED)) return -1;
17434 #endif
17435 #ifdef CLD_STOPPED
17436 if (PyModule_AddIntMacro(m, CLD_STOPPED)) return -1;
17437 #endif
17438 #ifdef CLD_CONTINUED
17439 if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1;
17440 #endif
17441
17442 /* constants for lockf */
17443 #ifdef F_LOCK
17444 if (PyModule_AddIntMacro(m, F_LOCK)) return -1;
17445 #endif
17446 #ifdef F_TLOCK
17447 if (PyModule_AddIntMacro(m, F_TLOCK)) return -1;
17448 #endif
17449 #ifdef F_ULOCK
17450 if (PyModule_AddIntMacro(m, F_ULOCK)) return -1;
17451 #endif
17452 #ifdef F_TEST
17453 if (PyModule_AddIntMacro(m, F_TEST)) return -1;
17454 #endif
17455
17456 #ifdef RWF_DSYNC
17457 if (PyModule_AddIntConstant(m, "RWF_DSYNC", RWF_DSYNC)) return -1;
17458 #endif
17459 #ifdef RWF_HIPRI
17460 if (PyModule_AddIntConstant(m, "RWF_HIPRI", RWF_HIPRI)) return -1;
17461 #endif
17462 #ifdef RWF_SYNC
17463 if (PyModule_AddIntConstant(m, "RWF_SYNC", RWF_SYNC)) return -1;
17464 #endif
17465 #ifdef RWF_NOWAIT
17466 if (PyModule_AddIntConstant(m, "RWF_NOWAIT", RWF_NOWAIT)) return -1;
17467 #endif
17468 #ifdef RWF_APPEND
17469 if (PyModule_AddIntConstant(m, "RWF_APPEND", RWF_APPEND)) return -1;
17470 #endif
17471
17472 /* constants for splice */
17473 #if defined(HAVE_SPLICE) && defined(__linux__)
17474 if (PyModule_AddIntConstant(m, "SPLICE_F_MOVE", SPLICE_F_MOVE)) return -1;
17475 if (PyModule_AddIntConstant(m, "SPLICE_F_NONBLOCK", SPLICE_F_NONBLOCK)) return -1;
17476 if (PyModule_AddIntConstant(m, "SPLICE_F_MORE", SPLICE_F_MORE)) return -1;
17477 #endif
17478
17479 /* constants for posix_spawn */
17480 #ifdef HAVE_POSIX_SPAWN
17481 if (PyModule_AddIntConstant(m, "POSIX_SPAWN_OPEN", POSIX_SPAWN_OPEN)) return -1;
17482 if (PyModule_AddIntConstant(m, "POSIX_SPAWN_CLOSE", POSIX_SPAWN_CLOSE)) return -1;
17483 if (PyModule_AddIntConstant(m, "POSIX_SPAWN_DUP2", POSIX_SPAWN_DUP2)) return -1;
17484 #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP
17485 if (PyModule_AddIntMacro(m, POSIX_SPAWN_CLOSEFROM)) return -1;
17486 #endif
17487 #endif
17488
17489 #if defined(HAVE_SPAWNV) || defined (HAVE_RTPSPAWN)
17490 if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1;
17491 if (PyModule_AddIntConstant(m, "P_NOWAIT", _P_NOWAIT)) return -1;
17492 if (PyModule_AddIntConstant(m, "P_NOWAITO", _P_NOWAITO)) return -1;
17493 #endif
17494 #ifdef HAVE_SPAWNV
17495 if (PyModule_AddIntConstant(m, "P_OVERLAY", _OLD_P_OVERLAY)) return -1;
17496 if (PyModule_AddIntConstant(m, "P_DETACH", _P_DETACH)) return -1;
17497 #endif
17498
17499 #ifdef HAVE_SCHED_H
17500 #ifdef SCHED_OTHER
17501 if (PyModule_AddIntMacro(m, SCHED_OTHER)) return -1;
17502 #endif
17503 #ifdef SCHED_FIFO
17504 if (PyModule_AddIntMacro(m, SCHED_FIFO)) return -1;
17505 #endif
17506 #ifdef SCHED_RR
17507 if (PyModule_AddIntMacro(m, SCHED_RR)) return -1;
17508 #endif
17509 #ifdef SCHED_SPORADIC
17510 if (PyModule_AddIntMacro(m, SCHED_SPORADIC)) return -1;
17511 #endif
17512 #ifdef SCHED_BATCH
17513 if (PyModule_AddIntMacro(m, SCHED_BATCH)) return -1;
17514 #endif
17515 #ifdef SCHED_IDLE
17516 if (PyModule_AddIntMacro(m, SCHED_IDLE)) return -1;
17517 #endif
17518 #ifdef SCHED_RESET_ON_FORK
17519 if (PyModule_AddIntMacro(m, SCHED_RESET_ON_FORK)) return -1;
17520 #endif
17521 #ifdef SCHED_SYS
17522 if (PyModule_AddIntMacro(m, SCHED_SYS)) return -1;
17523 #endif
17524 #ifdef SCHED_IA
17525 if (PyModule_AddIntMacro(m, SCHED_IA)) return -1;
17526 #endif
17527 #ifdef SCHED_FSS
17528 if (PyModule_AddIntMacro(m, SCHED_FSS)) return -1;
17529 #endif
17530 #ifdef SCHED_FX
17531 if (PyModule_AddIntConstant(m, "SCHED_FX", SCHED_FSS)) return -1;
17532 #endif
17533
17534 /* constants for namespaces */
17535 #if defined(HAVE_SETNS) || defined(HAVE_UNSHARE)
17536 #ifdef CLONE_FS
17537 if (PyModule_AddIntMacro(m, CLONE_FS)) return -1;
17538 #endif
17539 #ifdef CLONE_FILES
17540 if (PyModule_AddIntMacro(m, CLONE_FILES)) return -1;
17541 #endif
17542 #ifdef CLONE_NEWNS
17543 if (PyModule_AddIntMacro(m, CLONE_NEWNS)) return -1;
17544 #endif
17545 #ifdef CLONE_NEWCGROUP
17546 if (PyModule_AddIntMacro(m, CLONE_NEWCGROUP)) return -1;
17547 #endif
17548 #ifdef CLONE_NEWUTS
17549 if (PyModule_AddIntMacro(m, CLONE_NEWUTS)) return -1;
17550 #endif
17551 #ifdef CLONE_NEWIPC
17552 if (PyModule_AddIntMacro(m, CLONE_NEWIPC)) return -1;
17553 #endif
17554 #ifdef CLONE_NEWUSER
17555 if (PyModule_AddIntMacro(m, CLONE_NEWUSER)) return -1;
17556 #endif
17557 #ifdef CLONE_NEWPID
17558 if (PyModule_AddIntMacro(m, CLONE_NEWPID)) return -1;
17559 #endif
17560 #ifdef CLONE_NEWNET
17561 if (PyModule_AddIntMacro(m, CLONE_NEWNET)) return -1;
17562 #endif
17563 #ifdef CLONE_NEWTIME
17564 if (PyModule_AddIntMacro(m, CLONE_NEWTIME)) return -1;
17565 #endif
17566 #ifdef CLONE_SYSVSEM
17567 if (PyModule_AddIntMacro(m, CLONE_SYSVSEM)) return -1;
17568 #endif
17569 #ifdef CLONE_THREAD
17570 if (PyModule_AddIntMacro(m, CLONE_THREAD)) return -1;
17571 #endif
17572 #ifdef CLONE_SIGHAND
17573 if (PyModule_AddIntMacro(m, CLONE_SIGHAND)) return -1;
17574 #endif
17575 #ifdef CLONE_VM
17576 if (PyModule_AddIntMacro(m, CLONE_VM)) return -1;
17577 #endif
17578 #endif
17579
17580 #endif
17581
17582 #ifdef USE_XATTRS
17583 if (PyModule_AddIntMacro(m, XATTR_CREATE)) return -1;
17584 if (PyModule_AddIntMacro(m, XATTR_REPLACE)) return -1;
17585 if (PyModule_AddIntMacro(m, XATTR_SIZE_MAX)) return -1;
17586 #endif
17587
17588 #if HAVE_DECL_RTLD_LAZY
17589 if (PyModule_AddIntMacro(m, RTLD_LAZY)) return -1;
17590 #endif
17591 #if HAVE_DECL_RTLD_NOW
17592 if (PyModule_AddIntMacro(m, RTLD_NOW)) return -1;
17593 #endif
17594 #if HAVE_DECL_RTLD_GLOBAL
17595 if (PyModule_AddIntMacro(m, RTLD_GLOBAL)) return -1;
17596 #endif
17597 #if HAVE_DECL_RTLD_LOCAL
17598 if (PyModule_AddIntMacro(m, RTLD_LOCAL)) return -1;
17599 #endif
17600 #if HAVE_DECL_RTLD_NODELETE
17601 if (PyModule_AddIntMacro(m, RTLD_NODELETE)) return -1;
17602 #endif
17603 #if HAVE_DECL_RTLD_NOLOAD
17604 if (PyModule_AddIntMacro(m, RTLD_NOLOAD)) return -1;
17605 #endif
17606 #if HAVE_DECL_RTLD_DEEPBIND
17607 if (PyModule_AddIntMacro(m, RTLD_DEEPBIND)) return -1;
17608 #endif
17609 #if HAVE_DECL_RTLD_MEMBER
17610 if (PyModule_AddIntMacro(m, RTLD_MEMBER)) return -1;
17611 #endif
17612
17613 #ifdef HAVE_GETRANDOM_SYSCALL
17614 if (PyModule_AddIntMacro(m, GRND_RANDOM)) return -1;
17615 if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1;
17616 #endif
17617 #ifdef HAVE_MEMFD_CREATE
17618 if (PyModule_AddIntMacro(m, MFD_CLOEXEC)) return -1;
17619 if (PyModule_AddIntMacro(m, MFD_ALLOW_SEALING)) return -1;
17620 #ifdef MFD_HUGETLB
17621 if (PyModule_AddIntMacro(m, MFD_HUGETLB)) return -1;
17622 #endif
17623 #ifdef MFD_HUGE_SHIFT
17624 if (PyModule_AddIntMacro(m, MFD_HUGE_SHIFT)) return -1;
17625 #endif
17626 #ifdef MFD_HUGE_MASK
17627 if (PyModule_AddIntMacro(m, MFD_HUGE_MASK)) return -1;
17628 #endif
17629 #ifdef MFD_HUGE_64KB
17630 if (PyModule_AddIntMacro(m, MFD_HUGE_64KB)) return -1;
17631 #endif
17632 #ifdef MFD_HUGE_512KB
17633 if (PyModule_AddIntMacro(m, MFD_HUGE_512KB)) return -1;
17634 #endif
17635 #ifdef MFD_HUGE_1MB
17636 if (PyModule_AddIntMacro(m, MFD_HUGE_1MB)) return -1;
17637 #endif
17638 #ifdef MFD_HUGE_2MB
17639 if (PyModule_AddIntMacro(m, MFD_HUGE_2MB)) return -1;
17640 #endif
17641 #ifdef MFD_HUGE_8MB
17642 if (PyModule_AddIntMacro(m, MFD_HUGE_8MB)) return -1;
17643 #endif
17644 #ifdef MFD_HUGE_16MB
17645 if (PyModule_AddIntMacro(m, MFD_HUGE_16MB)) return -1;
17646 #endif
17647 #ifdef MFD_HUGE_32MB
17648 if (PyModule_AddIntMacro(m, MFD_HUGE_32MB)) return -1;
17649 #endif
17650 #ifdef MFD_HUGE_256MB
17651 if (PyModule_AddIntMacro(m, MFD_HUGE_256MB)) return -1;
17652 #endif
17653 #ifdef MFD_HUGE_512MB
17654 if (PyModule_AddIntMacro(m, MFD_HUGE_512MB)) return -1;
17655 #endif
17656 #ifdef MFD_HUGE_1GB
17657 if (PyModule_AddIntMacro(m, MFD_HUGE_1GB)) return -1;
17658 #endif
17659 #ifdef MFD_HUGE_2GB
17660 if (PyModule_AddIntMacro(m, MFD_HUGE_2GB)) return -1;
17661 #endif
17662 #ifdef MFD_HUGE_16GB
17663 if (PyModule_AddIntMacro(m, MFD_HUGE_16GB)) return -1;
17664 #endif
17665 #endif /* HAVE_MEMFD_CREATE */
17666
17667 #if defined(HAVE_EVENTFD) && defined(EFD_CLOEXEC)
17668 if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1;
17669 #ifdef EFD_NONBLOCK
17670 if (PyModule_AddIntMacro(m, EFD_NONBLOCK)) return -1;
17671 #endif
17672 #ifdef EFD_SEMAPHORE
17673 if (PyModule_AddIntMacro(m, EFD_SEMAPHORE)) return -1;
17674 #endif
17675 #endif /* HAVE_EVENTFD && EFD_CLOEXEC */
17676
17677 #if defined(__APPLE__)
17678 if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1;
17679 if (PyModule_AddIntConstant(m, "_COPYFILE_STAT", COPYFILE_STAT)) return -1;
17680 if (PyModule_AddIntConstant(m, "_COPYFILE_ACL", COPYFILE_ACL)) return -1;
17681 if (PyModule_AddIntConstant(m, "_COPYFILE_XATTR", COPYFILE_XATTR)) return -1;
17682 #endif
17683
17684 #ifdef MS_WINDOWS
17685 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DEFAULT_DIRS", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) return -1;
17686 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_APPLICATION_DIR", LOAD_LIBRARY_SEARCH_APPLICATION_DIR)) return -1;
17687 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_SYSTEM32", LOAD_LIBRARY_SEARCH_SYSTEM32)) return -1;
17688 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_USER_DIRS", LOAD_LIBRARY_SEARCH_USER_DIRS)) return -1;
17689 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR", LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)) return -1;
17690 #endif
17691
17692 return 0;
17693 }
17694
17695
17696
17697 #define PROBE(name, test) \
17698 static int name(void) \
17699 { \
17700 if (test) { \
17701 return 1; \
17702 } else { \
17703 return 0; \
17704 } \
17705 }
17706
17707 #ifdef HAVE_FSTATAT
17708 PROBE(probe_fstatat, HAVE_FSTATAT_RUNTIME)
17709 #endif
17710
17711 #ifdef HAVE_FACCESSAT
17712 PROBE(probe_faccessat, HAVE_FACCESSAT_RUNTIME)
17713 #endif
17714
17715 #ifdef HAVE_FCHMODAT
17716 PROBE(probe_fchmodat, HAVE_FCHMODAT_RUNTIME)
17717 #endif
17718
17719 #ifdef HAVE_FCHOWNAT
17720 PROBE(probe_fchownat, HAVE_FCHOWNAT_RUNTIME)
17721 #endif
17722
17723 #ifdef HAVE_LINKAT
17724 PROBE(probe_linkat, HAVE_LINKAT_RUNTIME)
17725 #endif
17726
17727 #ifdef HAVE_FDOPENDIR
17728 PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME)
17729 #endif
17730
17731 #ifdef HAVE_MKDIRAT
17732 PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME)
17733 #endif
17734
17735 #ifdef HAVE_MKFIFOAT
17736 PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME)
17737 #endif
17738
17739 #ifdef HAVE_MKNODAT
17740 PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME)
17741 #endif
17742
17743 #ifdef HAVE_RENAMEAT
17744 PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME)
17745 #endif
17746
17747 #ifdef HAVE_UNLINKAT
17748 PROBE(probe_unlinkat, HAVE_UNLINKAT_RUNTIME)
17749 #endif
17750
17751 #ifdef HAVE_OPENAT
17752 PROBE(probe_openat, HAVE_OPENAT_RUNTIME)
17753 #endif
17754
17755 #ifdef HAVE_READLINKAT
17756 PROBE(probe_readlinkat, HAVE_READLINKAT_RUNTIME)
17757 #endif
17758
17759 #ifdef HAVE_SYMLINKAT
17760 PROBE(probe_symlinkat, HAVE_SYMLINKAT_RUNTIME)
17761 #endif
17762
17763 #ifdef HAVE_FUTIMENS
17764 PROBE(probe_futimens, HAVE_FUTIMENS_RUNTIME)
17765 #endif
17766
17767 #ifdef HAVE_UTIMENSAT
17768 PROBE(probe_utimensat, HAVE_UTIMENSAT_RUNTIME)
17769 #endif
17770
17771 #ifdef HAVE_PTSNAME_R
17772 PROBE(probe_ptsname_r, HAVE_PTSNAME_R_RUNTIME)
17773 #endif
17774
17775
17776
17777 static const struct have_function {
17778 const char * const label;
17779 int (*probe)(void);
17780 } have_functions[] = {
17781
17782 #ifdef HAVE_EVENTFD
17783 {"HAVE_EVENTFD", NULL},
17784 #endif
17785
17786 #ifdef HAVE_TIMERFD_CREATE
17787 {"HAVE_TIMERFD_CREATE", NULL},
17788 #endif
17789
17790 #ifdef HAVE_FACCESSAT
17791 { "HAVE_FACCESSAT", probe_faccessat },
17792 #endif
17793
17794 #ifdef HAVE_FCHDIR
17795 { "HAVE_FCHDIR", NULL },
17796 #endif
17797
17798 #ifdef HAVE_FCHMOD
17799 { "HAVE_FCHMOD", NULL },
17800 #endif
17801
17802 #ifdef HAVE_FCHMODAT
17803 { "HAVE_FCHMODAT", probe_fchmodat },
17804 #endif
17805
17806 #ifdef HAVE_FCHOWN
17807 { "HAVE_FCHOWN", NULL },
17808 #endif
17809
17810 #ifdef HAVE_FCHOWNAT
17811 { "HAVE_FCHOWNAT", probe_fchownat },
17812 #endif
17813
17814 #ifdef HAVE_FEXECVE
17815 { "HAVE_FEXECVE", NULL },
17816 #endif
17817
17818 #ifdef HAVE_FDOPENDIR
17819 { "HAVE_FDOPENDIR", probe_fdopendir },
17820 #endif
17821
17822 #ifdef HAVE_FPATHCONF
17823 { "HAVE_FPATHCONF", NULL },
17824 #endif
17825
17826 #ifdef HAVE_FSTATAT
17827 { "HAVE_FSTATAT", probe_fstatat },
17828 #endif
17829
17830 #ifdef HAVE_FSTATVFS
17831 { "HAVE_FSTATVFS", NULL },
17832 #endif
17833
17834 #if defined HAVE_FTRUNCATE || defined MS_WINDOWS
17835 { "HAVE_FTRUNCATE", NULL },
17836 #endif
17837
17838 #ifdef HAVE_FUTIMENS
17839 { "HAVE_FUTIMENS", probe_futimens },
17840 #endif
17841
17842 #ifdef HAVE_FUTIMES
17843 { "HAVE_FUTIMES", NULL },
17844 #endif
17845
17846 #ifdef HAVE_FUTIMESAT
17847 { "HAVE_FUTIMESAT", NULL },
17848 #endif
17849
17850 #ifdef HAVE_LINKAT
17851 { "HAVE_LINKAT", probe_linkat },
17852 #endif
17853
17854 #ifdef HAVE_LCHFLAGS
17855 { "HAVE_LCHFLAGS", NULL },
17856 #endif
17857
17858 #ifdef HAVE_LCHMOD
17859 { "HAVE_LCHMOD", NULL },
17860 #endif
17861
17862 #ifdef HAVE_LCHOWN
17863 { "HAVE_LCHOWN", NULL },
17864 #endif
17865
17866 #ifdef HAVE_LSTAT
17867 { "HAVE_LSTAT", NULL },
17868 #endif
17869
17870 #ifdef HAVE_LUTIMES
17871 { "HAVE_LUTIMES", NULL },
17872 #endif
17873
17874 #ifdef HAVE_MEMFD_CREATE
17875 { "HAVE_MEMFD_CREATE", NULL },
17876 #endif
17877
17878 #ifdef HAVE_MKDIRAT
17879 { "HAVE_MKDIRAT", probe_mkdirat },
17880 #endif
17881
17882 #ifdef HAVE_MKFIFOAT
17883 { "HAVE_MKFIFOAT", probe_mkfifoat },
17884 #endif
17885
17886 #ifdef HAVE_MKNODAT
17887 { "HAVE_MKNODAT", probe_mknodat },
17888 #endif
17889
17890 #ifdef HAVE_OPENAT
17891 { "HAVE_OPENAT", probe_openat },
17892 #endif
17893
17894 #ifdef HAVE_READLINKAT
17895 { "HAVE_READLINKAT", probe_readlinkat },
17896 #endif
17897
17898 #ifdef HAVE_RENAMEAT
17899 { "HAVE_RENAMEAT", probe_renameat },
17900 #endif
17901
17902 #ifdef HAVE_SYMLINKAT
17903 { "HAVE_SYMLINKAT", probe_symlinkat },
17904 #endif
17905
17906 #ifdef HAVE_UNLINKAT
17907 { "HAVE_UNLINKAT", probe_unlinkat },
17908 #endif
17909
17910 #ifdef HAVE_UTIMENSAT
17911 { "HAVE_UTIMENSAT", probe_utimensat },
17912 #endif
17913
17914 #ifdef HAVE_PTSNAME_R
17915 { "HAVE_PTSNAME_R", probe_ptsname_r },
17916 #endif
17917
17918 #ifdef MS_WINDOWS
17919 { "MS_WINDOWS", NULL },
17920 #endif
17921
17922 { NULL, NULL }
17923 };
17924
17925
17926 static int
posixmodule_exec(PyObject * m)17927 posixmodule_exec(PyObject *m)
17928 {
17929 _posixstate *state = get_posix_state(m);
17930
17931 #if defined(HAVE_PWRITEV)
17932 if (HAVE_PWRITEV_RUNTIME) {} else {
17933 PyObject* dct = PyModule_GetDict(m);
17934
17935 if (dct == NULL) {
17936 return -1;
17937 }
17938
17939 if (PyDict_PopString(dct, "pwritev", NULL) < 0) {
17940 return -1;
17941 }
17942 if (PyDict_PopString(dct, "preadv", NULL) < 0) {
17943 return -1;
17944 }
17945 }
17946 #endif
17947
17948 /* Initialize environ dictionary */
17949 if (PyModule_Add(m, "environ", convertenviron()) != 0) {
17950 return -1;
17951 }
17952
17953 if (all_ins(m))
17954 return -1;
17955
17956 if (setup_confname_tables(m))
17957 return -1;
17958
17959 if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) {
17960 return -1;
17961 }
17962
17963 #if defined(HAVE_WAITID)
17964 waitid_result_desc.name = MODNAME ".waitid_result";
17965 state->WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc);
17966 if (PyModule_AddObjectRef(m, "waitid_result", state->WaitidResultType) < 0) {
17967 return -1;
17968 }
17969 #endif
17970
17971 stat_result_desc.name = "os.stat_result"; /* see issue #19209 */
17972 stat_result_desc.fields[7].name = PyStructSequence_UnnamedField;
17973 stat_result_desc.fields[8].name = PyStructSequence_UnnamedField;
17974 stat_result_desc.fields[9].name = PyStructSequence_UnnamedField;
17975 state->StatResultType = (PyObject *)PyStructSequence_NewType(&stat_result_desc);
17976 if (PyModule_AddObjectRef(m, "stat_result", state->StatResultType) < 0) {
17977 return -1;
17978 }
17979 state->statresult_new_orig = ((PyTypeObject *)state->StatResultType)->tp_new;
17980 ((PyTypeObject *)state->StatResultType)->tp_new = statresult_new;
17981
17982 statvfs_result_desc.name = "os.statvfs_result"; /* see issue #19209 */
17983 state->StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc);
17984 if (PyModule_AddObjectRef(m, "statvfs_result", state->StatVFSResultType) < 0) {
17985 return -1;
17986 }
17987
17988 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
17989 sched_param_desc.name = MODNAME ".sched_param";
17990 state->SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc);
17991 if (PyModule_AddObjectRef(m, "sched_param", state->SchedParamType) < 0) {
17992 return -1;
17993 }
17994 ((PyTypeObject *)state->SchedParamType)->tp_new = os_sched_param;
17995 if (_PyType_AddMethod((PyTypeObject *)state->SchedParamType,
17996 &os_sched_param_reduce_method) < 0)
17997 {
17998 return -1;
17999 }
18000 PyType_Modified((PyTypeObject *)state->SchedParamType);
18001 #endif
18002
18003 /* initialize TerminalSize_info */
18004 state->TerminalSizeType = (PyObject *)PyStructSequence_NewType(&TerminalSize_desc);
18005 if (PyModule_AddObjectRef(m, "terminal_size", state->TerminalSizeType) < 0) {
18006 return -1;
18007 }
18008
18009 /* initialize scandir types */
18010 PyObject *ScandirIteratorType = PyType_FromModuleAndSpec(m, &ScandirIteratorType_spec, NULL);
18011 if (ScandirIteratorType == NULL) {
18012 return -1;
18013 }
18014 state->ScandirIteratorType = ScandirIteratorType;
18015
18016 state->DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL);
18017 if (PyModule_AddObjectRef(m, "DirEntry", state->DirEntryType) < 0) {
18018 return -1;
18019 }
18020
18021 times_result_desc.name = MODNAME ".times_result";
18022 state->TimesResultType = (PyObject *)PyStructSequence_NewType(×_result_desc);
18023 if (PyModule_AddObjectRef(m, "times_result", state->TimesResultType) < 0) {
18024 return -1;
18025 }
18026
18027 state->UnameResultType = (PyObject *)PyStructSequence_NewType(&uname_result_desc);
18028 if (PyModule_AddObjectRef(m, "uname_result", state->UnameResultType) < 0) {
18029 return -1;
18030 }
18031
18032 if ((state->billion = PyLong_FromLong(1000000000)) == NULL)
18033 return -1;
18034 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
18035 state->struct_rusage = PyUnicode_InternFromString("struct_rusage");
18036 if (state->struct_rusage == NULL)
18037 return -1;
18038 #endif
18039 state->st_mode = PyUnicode_InternFromString("st_mode");
18040 if (state->st_mode == NULL)
18041 return -1;
18042
18043 /* suppress "function not used" warnings */
18044 {
18045 int ignored;
18046 fd_specified("", -1);
18047 follow_symlinks_specified("", 1);
18048 dir_fd_and_follow_symlinks_invalid("chmod", DEFAULT_DIR_FD, 1);
18049 dir_fd_converter(Py_None, &ignored);
18050 dir_fd_unavailable(Py_None, &ignored);
18051 }
18052
18053 /*
18054 * provide list of locally available functions
18055 * so os.py can populate support_* lists
18056 */
18057 PyObject *list = PyList_New(0);
18058 if (!list) {
18059 return -1;
18060 }
18061 for (const struct have_function *trace = have_functions; trace->label; trace++) {
18062 PyObject *unicode;
18063 if (trace->probe && !trace->probe()) continue;
18064 unicode = PyUnicode_DecodeASCII(trace->label, strlen(trace->label), NULL);
18065 if (!unicode)
18066 return -1;
18067 if (PyList_Append(list, unicode))
18068 return -1;
18069 Py_DECREF(unicode);
18070 }
18071
18072 #ifndef MS_WINDOWS
18073 if (_Py_GetTicksPerSecond(&state->ticks_per_second) < 0) {
18074 PyErr_SetString(PyExc_RuntimeError,
18075 "cannot read ticks_per_second");
18076 return -1;
18077 }
18078 assert(state->ticks_per_second >= 1);
18079 #endif
18080
18081 return PyModule_Add(m, "_have_functions", list);
18082 }
18083
18084
18085 static PyModuleDef_Slot posixmodile_slots[] = {
18086 {Py_mod_exec, posixmodule_exec},
18087 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
18088 {Py_mod_gil, Py_MOD_GIL_NOT_USED},
18089 {0, NULL}
18090 };
18091
18092 static struct PyModuleDef posixmodule = {
18093 PyModuleDef_HEAD_INIT,
18094 .m_name = MODNAME,
18095 .m_doc = posix__doc__,
18096 .m_size = sizeof(_posixstate),
18097 .m_methods = posix_methods,
18098 .m_slots = posixmodile_slots,
18099 .m_traverse = _posix_traverse,
18100 .m_clear = _posix_clear,
18101 .m_free = _posix_free,
18102 };
18103
18104 PyMODINIT_FUNC
INITFUNC(void)18105 INITFUNC(void)
18106 {
18107 return PyModuleDef_Init(&posixmodule);
18108 }
18109