posixmodule.c revision bf19d169504823c258a9aae4bf61c8df9ff5987f
1
2/* POSIX module implementation */
3
4/* This file is also used for Windows NT/MS-Win.  In that case the
5   module actually calls itself 'nt', not 'posix', and a few
6   functions are either unimplemented or implemented differently.  The source
7   assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent
8   of the compiler used.  Different compilers define their own feature
9   test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */
10
11
12
13#ifdef __APPLE__
14   /*
15    * Step 1 of support for weak-linking a number of symbols existing on
16    * OSX 10.4 and later, see the comment in the #ifdef __APPLE__ block
17    * at the end of this file for more information.
18    */
19#  pragma weak lchown
20#  pragma weak statvfs
21#  pragma weak fstatvfs
22
23#endif /* __APPLE__ */
24
25#define PY_SSIZE_T_CLEAN
26
27#include "Python.h"
28#ifndef MS_WINDOWS
29#include "posixmodule.h"
30#endif
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36PyDoc_STRVAR(posix__doc__,
37"This module provides access to operating system functionality that is\n\
38standardized by the C Standard and the POSIX standard (a thinly\n\
39disguised Unix interface).  Refer to the library manual and\n\
40corresponding Unix manual entries for more information on calls.");
41
42
43#ifdef HAVE_SYS_UIO_H
44#include <sys/uio.h>
45#endif
46
47#ifdef HAVE_SYS_TYPES_H
48#include <sys/types.h>
49#endif /* HAVE_SYS_TYPES_H */
50
51#ifdef HAVE_SYS_STAT_H
52#include <sys/stat.h>
53#endif /* HAVE_SYS_STAT_H */
54
55#ifdef HAVE_SYS_WAIT_H
56#include <sys/wait.h>           /* For WNOHANG */
57#endif
58
59#ifdef HAVE_SIGNAL_H
60#include <signal.h>
61#endif
62
63#ifdef HAVE_FCNTL_H
64#include <fcntl.h>
65#endif /* HAVE_FCNTL_H */
66
67#ifdef HAVE_GRP_H
68#include <grp.h>
69#endif
70
71#ifdef HAVE_SYSEXITS_H
72#include <sysexits.h>
73#endif /* HAVE_SYSEXITS_H */
74
75#ifdef HAVE_SYS_LOADAVG_H
76#include <sys/loadavg.h>
77#endif
78
79#ifdef HAVE_LANGINFO_H
80#include <langinfo.h>
81#endif
82
83#ifdef HAVE_SYS_SENDFILE_H
84#include <sys/sendfile.h>
85#endif
86
87#ifdef HAVE_SCHED_H
88#include <sched.h>
89#endif
90
91#if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY)
92#undef HAVE_SCHED_SETAFFINITY
93#endif
94
95#if defined(HAVE_SYS_XATTR_H) && defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__)
96#define USE_XATTRS
97#endif
98
99#ifdef USE_XATTRS
100#include <sys/xattr.h>
101#endif
102
103#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
104#ifdef HAVE_SYS_SOCKET_H
105#include <sys/socket.h>
106#endif
107#endif
108
109#ifdef HAVE_DLFCN_H
110#include <dlfcn.h>
111#endif
112
113#ifdef __hpux
114#include <sys/mpctl.h>
115#endif
116
117#if defined(__DragonFly__) || \
118    defined(__OpenBSD__)   || \
119    defined(__FreeBSD__)   || \
120    defined(__NetBSD__)    || \
121    defined(__APPLE__)
122#include <sys/sysctl.h>
123#endif
124
125#if defined(MS_WINDOWS)
126#  define TERMSIZE_USE_CONIO
127#elif defined(HAVE_SYS_IOCTL_H)
128#  include <sys/ioctl.h>
129#  if defined(HAVE_TERMIOS_H)
130#    include <termios.h>
131#  endif
132#  if defined(TIOCGWINSZ)
133#    define TERMSIZE_USE_IOCTL
134#  endif
135#endif /* MS_WINDOWS */
136
137/* Various compilers have only certain posix functions */
138/* XXX Gosh I wish these were all moved into pyconfig.h */
139#if defined(__WATCOMC__) && !defined(__QNX__)           /* Watcom compiler */
140#define HAVE_OPENDIR    1
141#define HAVE_SYSTEM     1
142#include <process.h>
143#else
144#ifdef __BORLANDC__             /* Borland compiler */
145#define HAVE_EXECV      1
146#define HAVE_OPENDIR    1
147#define HAVE_PIPE       1
148#define HAVE_SYSTEM     1
149#define HAVE_WAIT       1
150#else
151#ifdef _MSC_VER         /* Microsoft compiler */
152#define HAVE_GETPPID    1
153#define HAVE_GETLOGIN   1
154#define HAVE_SPAWNV     1
155#define HAVE_EXECV      1
156#define HAVE_PIPE       1
157#define HAVE_SYSTEM     1
158#define HAVE_CWAIT      1
159#define HAVE_FSYNC      1
160#define fsync _commit
161#else
162/* Unix functions that the configure script doesn't check for */
163#define HAVE_EXECV      1
164#define HAVE_FORK       1
165#if defined(__USLC__) && defined(__SCO_VERSION__)       /* SCO UDK Compiler */
166#define HAVE_FORK1      1
167#endif
168#define HAVE_GETEGID    1
169#define HAVE_GETEUID    1
170#define HAVE_GETGID     1
171#define HAVE_GETPPID    1
172#define HAVE_GETUID     1
173#define HAVE_KILL       1
174#define HAVE_OPENDIR    1
175#define HAVE_PIPE       1
176#define HAVE_SYSTEM     1
177#define HAVE_WAIT       1
178#define HAVE_TTYNAME    1
179#endif  /* _MSC_VER */
180#endif  /* __BORLANDC__ */
181#endif  /* ! __WATCOMC__ || __QNX__ */
182
183
184/*[clinic input]
185module os
186[clinic start generated code]*/
187/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8cff096d1133288f]*/
188
189#ifndef _MSC_VER
190
191#if defined(__sgi)&&_COMPILER_VERSION>=700
192/* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode
193   (default) */
194extern char        *ctermid_r(char *);
195#endif
196
197#ifndef HAVE_UNISTD_H
198#if defined(PYCC_VACPP)
199extern int mkdir(char *);
200#else
201#if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__)
202extern int mkdir(const char *);
203#else
204extern int mkdir(const char *, mode_t);
205#endif
206#endif
207#if defined(__IBMC__) || defined(__IBMCPP__)
208extern int chdir(char *);
209extern int rmdir(char *);
210#else
211extern int chdir(const char *);
212extern int rmdir(const char *);
213#endif
214#ifdef __BORLANDC__
215extern int chmod(const char *, int);
216#else
217extern int chmod(const char *, mode_t);
218#endif
219/*#ifdef HAVE_FCHMOD
220extern int fchmod(int, mode_t);
221#endif*/
222/*#ifdef HAVE_LCHMOD
223extern int lchmod(const char *, mode_t);
224#endif*/
225extern int chown(const char *, uid_t, gid_t);
226extern char *getcwd(char *, int);
227extern char *strerror(int);
228extern int link(const char *, const char *);
229extern int rename(const char *, const char *);
230extern int stat(const char *, struct stat *);
231extern int unlink(const char *);
232#ifdef HAVE_SYMLINK
233extern int symlink(const char *, const char *);
234#endif /* HAVE_SYMLINK */
235#ifdef HAVE_LSTAT
236extern int lstat(const char *, struct stat *);
237#endif /* HAVE_LSTAT */
238#endif /* !HAVE_UNISTD_H */
239
240#endif /* !_MSC_VER */
241
242#ifdef HAVE_UTIME_H
243#include <utime.h>
244#endif /* HAVE_UTIME_H */
245
246#ifdef HAVE_SYS_UTIME_H
247#include <sys/utime.h>
248#define HAVE_UTIME_H /* pretend we do for the rest of this file */
249#endif /* HAVE_SYS_UTIME_H */
250
251#ifdef HAVE_SYS_TIMES_H
252#include <sys/times.h>
253#endif /* HAVE_SYS_TIMES_H */
254
255#ifdef HAVE_SYS_PARAM_H
256#include <sys/param.h>
257#endif /* HAVE_SYS_PARAM_H */
258
259#ifdef HAVE_SYS_UTSNAME_H
260#include <sys/utsname.h>
261#endif /* HAVE_SYS_UTSNAME_H */
262
263#ifdef HAVE_DIRENT_H
264#include <dirent.h>
265#define NAMLEN(dirent) strlen((dirent)->d_name)
266#else
267#if defined(__WATCOMC__) && !defined(__QNX__)
268#include <direct.h>
269#define NAMLEN(dirent) strlen((dirent)->d_name)
270#else
271#define dirent direct
272#define NAMLEN(dirent) (dirent)->d_namlen
273#endif
274#ifdef HAVE_SYS_NDIR_H
275#include <sys/ndir.h>
276#endif
277#ifdef HAVE_SYS_DIR_H
278#include <sys/dir.h>
279#endif
280#ifdef HAVE_NDIR_H
281#include <ndir.h>
282#endif
283#endif
284
285#ifdef _MSC_VER
286#ifdef HAVE_DIRECT_H
287#include <direct.h>
288#endif
289#ifdef HAVE_IO_H
290#include <io.h>
291#endif
292#ifdef HAVE_PROCESS_H
293#include <process.h>
294#endif
295#ifndef VOLUME_NAME_DOS
296#define VOLUME_NAME_DOS 0x0
297#endif
298#ifndef VOLUME_NAME_NT
299#define VOLUME_NAME_NT  0x2
300#endif
301#ifndef IO_REPARSE_TAG_SYMLINK
302#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
303#endif
304#include "osdefs.h"
305#include <malloc.h>
306#include <windows.h>
307#include <shellapi.h>   /* for ShellExecute() */
308#include <lmcons.h>     /* for UNLEN */
309#ifdef SE_CREATE_SYMBOLIC_LINK_NAME /* Available starting with Vista */
310#define HAVE_SYMLINK
311static int win32_can_symlink = 0;
312#endif
313#endif /* _MSC_VER */
314
315#ifndef MAXPATHLEN
316#if defined(PATH_MAX) && PATH_MAX > 1024
317#define MAXPATHLEN PATH_MAX
318#else
319#define MAXPATHLEN 1024
320#endif
321#endif /* MAXPATHLEN */
322
323#ifdef UNION_WAIT
324/* Emulate some macros on systems that have a union instead of macros */
325
326#ifndef WIFEXITED
327#define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump)
328#endif
329
330#ifndef WEXITSTATUS
331#define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1)
332#endif
333
334#ifndef WTERMSIG
335#define WTERMSIG(u_wait) ((u_wait).w_termsig)
336#endif
337
338#define WAIT_TYPE union wait
339#define WAIT_STATUS_INT(s) (s.w_status)
340
341#else /* !UNION_WAIT */
342#define WAIT_TYPE int
343#define WAIT_STATUS_INT(s) (s)
344#endif /* UNION_WAIT */
345
346/* Don't use the "_r" form if we don't need it (also, won't have a
347   prototype for it, at least on Solaris -- maybe others as well?). */
348#if defined(HAVE_CTERMID_R) && defined(WITH_THREAD)
349#define USE_CTERMID_R
350#endif
351
352/* choose the appropriate stat and fstat functions and return structs */
353#undef STAT
354#undef FSTAT
355#undef STRUCT_STAT
356#ifdef MS_WINDOWS
357#       define STAT win32_stat
358#       define LSTAT win32_lstat
359#       define FSTAT win32_fstat
360#       define STRUCT_STAT struct win32_stat
361#else
362#       define STAT stat
363#       define LSTAT lstat
364#       define FSTAT fstat
365#       define STRUCT_STAT struct stat
366#endif
367
368#if defined(MAJOR_IN_MKDEV)
369#include <sys/mkdev.h>
370#else
371#if defined(MAJOR_IN_SYSMACROS)
372#include <sys/sysmacros.h>
373#endif
374#if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H)
375#include <sys/mkdev.h>
376#endif
377#endif
378
379#define DWORD_MAX 4294967295U
380
381
382#ifdef MS_WINDOWS
383static int
384win32_warn_bytes_api()
385{
386    return PyErr_WarnEx(PyExc_DeprecationWarning,
387        "The Windows bytes API has been deprecated, "
388        "use Unicode filenames instead",
389        1);
390}
391#endif
392
393
394#ifndef MS_WINDOWS
395PyObject *
396_PyLong_FromUid(uid_t uid)
397{
398    if (uid == (uid_t)-1)
399        return PyLong_FromLong(-1);
400    return PyLong_FromUnsignedLong(uid);
401}
402
403PyObject *
404_PyLong_FromGid(gid_t gid)
405{
406    if (gid == (gid_t)-1)
407        return PyLong_FromLong(-1);
408    return PyLong_FromUnsignedLong(gid);
409}
410
411int
412_Py_Uid_Converter(PyObject *obj, void *p)
413{
414    uid_t uid;
415    PyObject *index;
416    int overflow;
417    long result;
418    unsigned long uresult;
419
420    index = PyNumber_Index(obj);
421    if (index == NULL) {
422        PyErr_Format(PyExc_TypeError,
423                     "uid should be integer, not %.200s",
424                     Py_TYPE(obj)->tp_name);
425        return 0;
426    }
427
428    /*
429     * Handling uid_t is complicated for two reasons:
430     *  * Although uid_t is (always?) unsigned, it still
431     *    accepts -1.
432     *  * We don't know its size in advance--it may be
433     *    bigger than an int, or it may be smaller than
434     *    a long.
435     *
436     * So a bit of defensive programming is in order.
437     * Start with interpreting the value passed
438     * in as a signed long and see if it works.
439     */
440
441    result = PyLong_AsLongAndOverflow(index, &overflow);
442
443    if (!overflow) {
444        uid = (uid_t)result;
445
446        if (result == -1) {
447            if (PyErr_Occurred())
448                goto fail;
449            /* It's a legitimate -1, we're done. */
450            goto success;
451        }
452
453        /* Any other negative number is disallowed. */
454        if (result < 0)
455            goto underflow;
456
457        /* Ensure the value wasn't truncated. */
458        if (sizeof(uid_t) < sizeof(long) &&
459            (long)uid != result)
460            goto underflow;
461        goto success;
462    }
463
464    if (overflow < 0)
465        goto underflow;
466
467    /*
468     * Okay, the value overflowed a signed long.  If it
469     * fits in an *unsigned* long, it may still be okay,
470     * as uid_t may be unsigned long on this platform.
471     */
472    uresult = PyLong_AsUnsignedLong(index);
473    if (PyErr_Occurred()) {
474        if (PyErr_ExceptionMatches(PyExc_OverflowError))
475            goto overflow;
476        goto fail;
477    }
478
479    uid = (uid_t)uresult;
480
481    /*
482     * If uid == (uid_t)-1, the user actually passed in ULONG_MAX,
483     * but this value would get interpreted as (uid_t)-1  by chown
484     * and its siblings.   That's not what the user meant!  So we
485     * throw an overflow exception instead.   (We already
486     * handled a real -1 with PyLong_AsLongAndOverflow() above.)
487     */
488    if (uid == (uid_t)-1)
489        goto overflow;
490
491    /* Ensure the value wasn't truncated. */
492    if (sizeof(uid_t) < sizeof(long) &&
493        (unsigned long)uid != uresult)
494        goto overflow;
495    /* fallthrough */
496
497success:
498    Py_DECREF(index);
499    *(uid_t *)p = uid;
500    return 1;
501
502underflow:
503    PyErr_SetString(PyExc_OverflowError,
504                    "uid is less than minimum");
505    goto fail;
506
507overflow:
508    PyErr_SetString(PyExc_OverflowError,
509                    "uid is greater than maximum");
510    /* fallthrough */
511
512fail:
513    Py_DECREF(index);
514    return 0;
515}
516
517int
518_Py_Gid_Converter(PyObject *obj, void *p)
519{
520    gid_t gid;
521    PyObject *index;
522    int overflow;
523    long result;
524    unsigned long uresult;
525
526    index = PyNumber_Index(obj);
527    if (index == NULL) {
528        PyErr_Format(PyExc_TypeError,
529                     "gid should be integer, not %.200s",
530                     Py_TYPE(obj)->tp_name);
531        return 0;
532    }
533
534    /*
535     * Handling gid_t is complicated for two reasons:
536     *  * Although gid_t is (always?) unsigned, it still
537     *    accepts -1.
538     *  * We don't know its size in advance--it may be
539     *    bigger than an int, or it may be smaller than
540     *    a long.
541     *
542     * So a bit of defensive programming is in order.
543     * Start with interpreting the value passed
544     * in as a signed long and see if it works.
545     */
546
547    result = PyLong_AsLongAndOverflow(index, &overflow);
548
549    if (!overflow) {
550        gid = (gid_t)result;
551
552        if (result == -1) {
553            if (PyErr_Occurred())
554                goto fail;
555            /* It's a legitimate -1, we're done. */
556            goto success;
557        }
558
559        /* Any other negative number is disallowed. */
560        if (result < 0) {
561            goto underflow;
562        }
563
564        /* Ensure the value wasn't truncated. */
565        if (sizeof(gid_t) < sizeof(long) &&
566            (long)gid != result)
567            goto underflow;
568        goto success;
569    }
570
571    if (overflow < 0)
572        goto underflow;
573
574    /*
575     * Okay, the value overflowed a signed long.  If it
576     * fits in an *unsigned* long, it may still be okay,
577     * as gid_t may be unsigned long on this platform.
578     */
579    uresult = PyLong_AsUnsignedLong(index);
580    if (PyErr_Occurred()) {
581        if (PyErr_ExceptionMatches(PyExc_OverflowError))
582            goto overflow;
583        goto fail;
584    }
585
586    gid = (gid_t)uresult;
587
588    /*
589     * If gid == (gid_t)-1, the user actually passed in ULONG_MAX,
590     * but this value would get interpreted as (gid_t)-1  by chown
591     * and its siblings.   That's not what the user meant!  So we
592     * throw an overflow exception instead.   (We already
593     * handled a real -1 with PyLong_AsLongAndOverflow() above.)
594     */
595    if (gid == (gid_t)-1)
596        goto overflow;
597
598    /* Ensure the value wasn't truncated. */
599    if (sizeof(gid_t) < sizeof(long) &&
600        (unsigned long)gid != uresult)
601        goto overflow;
602    /* fallthrough */
603
604success:
605    Py_DECREF(index);
606    *(gid_t *)p = gid;
607    return 1;
608
609underflow:
610    PyErr_SetString(PyExc_OverflowError,
611                    "gid is less than minimum");
612    goto fail;
613
614overflow:
615    PyErr_SetString(PyExc_OverflowError,
616                    "gid is greater than maximum");
617    /* fallthrough */
618
619fail:
620    Py_DECREF(index);
621    return 0;
622}
623#endif /* MS_WINDOWS */
624
625
626#ifdef HAVE_LONG_LONG
627#  define _PyLong_FromDev PyLong_FromLongLong
628#else
629#  define _PyLong_FromDev PyLong_FromLong
630#endif
631
632
633#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
634static int
635_Py_Dev_Converter(PyObject *obj, void *p)
636{
637#ifdef HAVE_LONG_LONG
638    *((dev_t *)p) = PyLong_AsUnsignedLongLong(obj);
639#else
640    *((dev_t *)p) = PyLong_AsUnsignedLong(obj);
641#endif
642    if (PyErr_Occurred())
643        return 0;
644    return 1;
645}
646#endif /* HAVE_MKNOD && HAVE_MAKEDEV */
647
648
649#ifdef AT_FDCWD
650/*
651 * Why the (int) cast?  Solaris 10 defines AT_FDCWD as 0xffd19553 (-3041965);
652 * without the int cast, the value gets interpreted as uint (4291925331),
653 * which doesn't play nicely with all the initializer lines in this file that
654 * look like this:
655 *      int dir_fd = DEFAULT_DIR_FD;
656 */
657#define DEFAULT_DIR_FD (int)AT_FDCWD
658#else
659#define DEFAULT_DIR_FD (-100)
660#endif
661
662static int
663_fd_converter(PyObject *o, int *p, const char *allowed)
664{
665    int overflow;
666    long long_value;
667
668    PyObject *index = PyNumber_Index(o);
669    if (index == NULL) {
670        PyErr_Format(PyExc_TypeError,
671                     "argument should be %s, not %.200s",
672                     allowed, Py_TYPE(o)->tp_name);
673        return 0;
674    }
675
676    long_value = PyLong_AsLongAndOverflow(index, &overflow);
677    Py_DECREF(index);
678    if (overflow > 0 || long_value > INT_MAX) {
679        PyErr_SetString(PyExc_OverflowError,
680                        "fd is greater than maximum");
681        return 0;
682    }
683    if (overflow < 0 || long_value < INT_MIN) {
684        PyErr_SetString(PyExc_OverflowError,
685                        "fd is less than minimum");
686        return 0;
687    }
688
689    *p = (int)long_value;
690    return 1;
691}
692
693static int
694dir_fd_converter(PyObject *o, void *p)
695{
696    if (o == Py_None) {
697        *(int *)p = DEFAULT_DIR_FD;
698        return 1;
699    }
700    return _fd_converter(o, (int *)p, "integer");
701}
702
703
704
705/*
706 * A PyArg_ParseTuple "converter" function
707 * that handles filesystem paths in the manner
708 * preferred by the os module.
709 *
710 * path_converter accepts (Unicode) strings and their
711 * subclasses, and bytes and their subclasses.  What
712 * it does with the argument depends on the platform:
713 *
714 *   * On Windows, if we get a (Unicode) string we
715 *     extract the wchar_t * and return it; if we get
716 *     bytes we extract the char * and return that.
717 *
718 *   * On all other platforms, strings are encoded
719 *     to bytes using PyUnicode_FSConverter, then we
720 *     extract the char * from the bytes object and
721 *     return that.
722 *
723 * path_converter also optionally accepts signed
724 * integers (representing open file descriptors) instead
725 * of path strings.
726 *
727 * Input fields:
728 *   path.nullable
729 *     If nonzero, the path is permitted to be None.
730 *   path.allow_fd
731 *     If nonzero, the path is permitted to be a file handle
732 *     (a signed int) instead of a string.
733 *   path.function_name
734 *     If non-NULL, path_converter will use that as the name
735 *     of the function in error messages.
736 *     (If path.function_name is NULL it omits the function name.)
737 *   path.argument_name
738 *     If non-NULL, path_converter will use that as the name
739 *     of the parameter in error messages.
740 *     (If path.argument_name is NULL it uses "path".)
741 *
742 * Output fields:
743 *   path.wide
744 *     Points to the path if it was expressed as Unicode
745 *     and was not encoded.  (Only used on Windows.)
746 *   path.narrow
747 *     Points to the path if it was expressed as bytes,
748 *     or it was Unicode and was encoded to bytes.
749 *   path.fd
750 *     Contains a file descriptor if path.accept_fd was true
751 *     and the caller provided a signed integer instead of any
752 *     sort of string.
753 *
754 *     WARNING: if your "path" parameter is optional, and is
755 *     unspecified, path_converter will never get called.
756 *     So if you set allow_fd, you *MUST* initialize path.fd = -1
757 *     yourself!
758 *   path.length
759 *     The length of the path in characters, if specified as
760 *     a string.
761 *   path.object
762 *     The original object passed in.
763 *   path.cleanup
764 *     For internal use only.  May point to a temporary object.
765 *     (Pay no attention to the man behind the curtain.)
766 *
767 *   At most one of path.wide or path.narrow will be non-NULL.
768 *   If path was None and path.nullable was set,
769 *     or if path was an integer and path.allow_fd was set,
770 *     both path.wide and path.narrow will be NULL
771 *     and path.length will be 0.
772 *
773 *   path_converter takes care to not write to the path_t
774 *   unless it's successful.  However it must reset the
775 *   "cleanup" field each time it's called.
776 *
777 * Use as follows:
778 *      path_t path;
779 *      memset(&path, 0, sizeof(path));
780 *      PyArg_ParseTuple(args, "O&", path_converter, &path);
781 *      // ... use values from path ...
782 *      path_cleanup(&path);
783 *
784 * (Note that if PyArg_Parse fails you don't need to call
785 * path_cleanup().  However it is safe to do so.)
786 */
787typedef struct {
788    const char *function_name;
789    const char *argument_name;
790    int nullable;
791    int allow_fd;
792    wchar_t *wide;
793    char *narrow;
794    int fd;
795    Py_ssize_t length;
796    PyObject *object;
797    PyObject *cleanup;
798} path_t;
799
800#define PATH_T_INITIALIZE(function_name, nullable, allow_fd) \
801    {function_name, NULL, nullable, allow_fd, NULL, NULL, 0, 0, NULL, NULL}
802
803static void
804path_cleanup(path_t *path) {
805    if (path->cleanup) {
806        Py_CLEAR(path->cleanup);
807    }
808}
809
810static int
811path_converter(PyObject *o, void *p) {
812    path_t *path = (path_t *)p;
813    PyObject *unicode, *bytes;
814    Py_ssize_t length;
815    char *narrow;
816
817#define FORMAT_EXCEPTION(exc, fmt) \
818    PyErr_Format(exc, "%s%s" fmt, \
819        path->function_name ? path->function_name : "", \
820        path->function_name ? ": "                : "", \
821        path->argument_name ? path->argument_name : "path")
822
823    /* Py_CLEANUP_SUPPORTED support */
824    if (o == NULL) {
825        path_cleanup(path);
826        return 1;
827    }
828
829    /* ensure it's always safe to call path_cleanup() */
830    path->cleanup = NULL;
831
832    if (o == Py_None) {
833        if (!path->nullable) {
834            FORMAT_EXCEPTION(PyExc_TypeError,
835                             "can't specify None for %s argument");
836            return 0;
837        }
838        path->wide = NULL;
839        path->narrow = NULL;
840        path->length = 0;
841        path->object = o;
842        path->fd = -1;
843        return 1;
844    }
845
846    unicode = PyUnicode_FromObject(o);
847    if (unicode) {
848#ifdef MS_WINDOWS
849        wchar_t *wide;
850
851        wide = PyUnicode_AsUnicodeAndSize(unicode, &length);
852        if (!wide) {
853            Py_DECREF(unicode);
854            return 0;
855        }
856        if (length > 32767) {
857            FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
858            Py_DECREF(unicode);
859            return 0;
860        }
861        if (wcslen(wide) != length) {
862            FORMAT_EXCEPTION(PyExc_TypeError, "embedded null character");
863            Py_DECREF(unicode);
864            return 0;
865        }
866
867        path->wide = wide;
868        path->narrow = NULL;
869        path->length = length;
870        path->object = o;
871        path->fd = -1;
872        path->cleanup = unicode;
873        return Py_CLEANUP_SUPPORTED;
874#else
875        int converted = PyUnicode_FSConverter(unicode, &bytes);
876        Py_DECREF(unicode);
877        if (!converted)
878            bytes = NULL;
879#endif
880    }
881    else {
882        PyErr_Clear();
883        if (PyObject_CheckBuffer(o))
884            bytes = PyBytes_FromObject(o);
885        else
886            bytes = NULL;
887        if (!bytes) {
888            PyErr_Clear();
889            if (path->allow_fd) {
890                int fd;
891                int result = _fd_converter(o, &fd,
892                        "string, bytes or integer");
893                if (result) {
894                    path->wide = NULL;
895                    path->narrow = NULL;
896                    path->length = 0;
897                    path->object = o;
898                    path->fd = fd;
899                    return result;
900                }
901            }
902        }
903    }
904
905    if (!bytes) {
906        if (!PyErr_Occurred())
907            FORMAT_EXCEPTION(PyExc_TypeError, "illegal type for %s parameter");
908        return 0;
909    }
910
911#ifdef MS_WINDOWS
912    if (win32_warn_bytes_api()) {
913        Py_DECREF(bytes);
914        return 0;
915    }
916#endif
917
918    length = PyBytes_GET_SIZE(bytes);
919#ifdef MS_WINDOWS
920    if (length > MAX_PATH-1) {
921        FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
922        Py_DECREF(bytes);
923        return 0;
924    }
925#endif
926
927    narrow = PyBytes_AS_STRING(bytes);
928    if (length != strlen(narrow)) {
929        FORMAT_EXCEPTION(PyExc_ValueError, "embedded NUL character in %s");
930        Py_DECREF(bytes);
931        return 0;
932    }
933
934    path->wide = NULL;
935    path->narrow = narrow;
936    path->length = length;
937    path->object = o;
938    path->fd = -1;
939    path->cleanup = bytes;
940    return Py_CLEANUP_SUPPORTED;
941}
942
943static void
944argument_unavailable_error(char *function_name, char *argument_name) {
945    PyErr_Format(PyExc_NotImplementedError,
946        "%s%s%s unavailable on this platform",
947        (function_name != NULL) ? function_name : "",
948        (function_name != NULL) ? ": ": "",
949        argument_name);
950}
951
952static int
953dir_fd_unavailable(PyObject *o, void *p)
954{
955    int dir_fd;
956    if (!dir_fd_converter(o, &dir_fd))
957        return 0;
958    if (dir_fd != DEFAULT_DIR_FD) {
959        argument_unavailable_error(NULL, "dir_fd");
960        return 0;
961    }
962    *(int *)p = dir_fd;
963    return 1;
964}
965
966static int
967fd_specified(char *function_name, int fd) {
968    if (fd == -1)
969        return 0;
970
971    argument_unavailable_error(function_name, "fd");
972    return 1;
973}
974
975static int
976follow_symlinks_specified(char *function_name, int follow_symlinks) {
977    if (follow_symlinks)
978        return 0;
979
980    argument_unavailable_error(function_name, "follow_symlinks");
981    return 1;
982}
983
984static int
985path_and_dir_fd_invalid(char *function_name, path_t *path, int dir_fd) {
986    if (!path->narrow && !path->wide && (dir_fd != DEFAULT_DIR_FD)) {
987        PyErr_Format(PyExc_ValueError,
988                     "%s: can't specify dir_fd without matching path",
989                     function_name);
990        return 1;
991    }
992    return 0;
993}
994
995static int
996dir_fd_and_fd_invalid(char *function_name, int dir_fd, int fd) {
997    if ((dir_fd != DEFAULT_DIR_FD) && (fd != -1)) {
998        PyErr_Format(PyExc_ValueError,
999                     "%s: can't specify both dir_fd and fd",
1000                     function_name);
1001        return 1;
1002    }
1003    return 0;
1004}
1005
1006static int
1007fd_and_follow_symlinks_invalid(char *function_name, int fd,
1008                               int follow_symlinks) {
1009    if ((fd > 0) && (!follow_symlinks)) {
1010        PyErr_Format(PyExc_ValueError,
1011                     "%s: cannot use fd and follow_symlinks together",
1012                     function_name);
1013        return 1;
1014    }
1015    return 0;
1016}
1017
1018static int
1019dir_fd_and_follow_symlinks_invalid(char *function_name, int dir_fd,
1020                                   int follow_symlinks) {
1021    if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
1022        PyErr_Format(PyExc_ValueError,
1023                     "%s: cannot use dir_fd and follow_symlinks together",
1024                     function_name);
1025        return 1;
1026    }
1027    return 0;
1028}
1029
1030/* A helper used by a number of POSIX-only functions */
1031#ifndef MS_WINDOWS
1032static int
1033_parse_off_t(PyObject* arg, void* addr)
1034{
1035#if !defined(HAVE_LARGEFILE_SUPPORT)
1036    *((off_t*)addr) = PyLong_AsLong(arg);
1037#else
1038    *((off_t*)addr) = PyLong_AsLongLong(arg);
1039#endif
1040    if (PyErr_Occurred())
1041        return 0;
1042    return 1;
1043}
1044#endif
1045
1046#if defined _MSC_VER && _MSC_VER >= 1400
1047/* Microsoft CRT in VS2005 and higher will verify that a filehandle is
1048 * valid and raise an assertion if it isn't.
1049 * Normally, an invalid fd is likely to be a C program error and therefore
1050 * an assertion can be useful, but it does contradict the POSIX standard
1051 * which for write(2) states:
1052 *    "Otherwise, -1 shall be returned and errno set to indicate the error."
1053 *    "[EBADF] The fildes argument is not a valid file descriptor open for
1054 *     writing."
1055 * Furthermore, python allows the user to enter any old integer
1056 * as a fd and should merely raise a python exception on error.
1057 * The Microsoft CRT doesn't provide an official way to check for the
1058 * validity of a file descriptor, but we can emulate its internal behaviour
1059 * by using the exported __pinfo data member and knowledge of the
1060 * internal structures involved.
1061 * The structures below must be updated for each version of visual studio
1062 * according to the file internal.h in the CRT source, until MS comes
1063 * up with a less hacky way to do this.
1064 * (all of this is to avoid globally modifying the CRT behaviour using
1065 * _set_invalid_parameter_handler() and _CrtSetReportMode())
1066 */
1067/* The actual size of the structure is determined at runtime.
1068 * Only the first items must be present.
1069 */
1070typedef struct {
1071    intptr_t osfhnd;
1072    char osfile;
1073} my_ioinfo;
1074
1075extern __declspec(dllimport) char * __pioinfo[];
1076#define IOINFO_L2E 5
1077#define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
1078#define IOINFO_ARRAYS 64
1079#define _NHANDLE_           (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
1080#define FOPEN 0x01
1081#define _NO_CONSOLE_FILENO (intptr_t)-2
1082
1083/* This function emulates what the windows CRT does to validate file handles */
1084int
1085_PyVerify_fd(int fd)
1086{
1087    const int i1 = fd >> IOINFO_L2E;
1088    const int i2 = fd & ((1 << IOINFO_L2E) - 1);
1089
1090    static size_t sizeof_ioinfo = 0;
1091
1092    /* Determine the actual size of the ioinfo structure,
1093     * as used by the CRT loaded in memory
1094     */
1095    if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
1096        sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
1097    }
1098    if (sizeof_ioinfo == 0) {
1099        /* This should not happen... */
1100        goto fail;
1101    }
1102
1103    /* See that it isn't a special CLEAR fileno */
1104    if (fd != _NO_CONSOLE_FILENO) {
1105        /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that.  Instead
1106         * we check pointer validity and other info
1107         */
1108        if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) {
1109            /* finally, check that the file is open */
1110            my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo);
1111            if (info->osfile & FOPEN) {
1112                return 1;
1113            }
1114        }
1115    }
1116  fail:
1117    errno = EBADF;
1118    return 0;
1119}
1120
1121/* the special case of checking dup2.  The target fd must be in a sensible range */
1122static int
1123_PyVerify_fd_dup2(int fd1, int fd2)
1124{
1125    if (!_PyVerify_fd(fd1))
1126        return 0;
1127    if (fd2 == _NO_CONSOLE_FILENO)
1128        return 0;
1129    if ((unsigned)fd2 < _NHANDLE_)
1130        return 1;
1131    else
1132        return 0;
1133}
1134#else
1135/* dummy version. _PyVerify_fd() is already defined in fileobject.h */
1136#define _PyVerify_fd_dup2(A, B) (1)
1137#endif
1138
1139#ifdef MS_WINDOWS
1140/* The following structure was copied from
1141   http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required
1142   include doesn't seem to be present in the Windows SDK (at least as included
1143   with Visual Studio Express). */
1144typedef struct _REPARSE_DATA_BUFFER {
1145    ULONG ReparseTag;
1146    USHORT ReparseDataLength;
1147    USHORT Reserved;
1148    union {
1149        struct {
1150            USHORT SubstituteNameOffset;
1151            USHORT SubstituteNameLength;
1152            USHORT PrintNameOffset;
1153            USHORT PrintNameLength;
1154            ULONG Flags;
1155            WCHAR PathBuffer[1];
1156        } SymbolicLinkReparseBuffer;
1157
1158        struct {
1159            USHORT SubstituteNameOffset;
1160            USHORT  SubstituteNameLength;
1161            USHORT  PrintNameOffset;
1162            USHORT  PrintNameLength;
1163            WCHAR  PathBuffer[1];
1164        } MountPointReparseBuffer;
1165
1166        struct {
1167            UCHAR  DataBuffer[1];
1168        } GenericReparseBuffer;
1169    };
1170} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
1171
1172#define REPARSE_DATA_BUFFER_HEADER_SIZE  FIELD_OFFSET(REPARSE_DATA_BUFFER,\
1173                                                      GenericReparseBuffer)
1174#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE  ( 16 * 1024 )
1175
1176static int
1177win32_get_reparse_tag(HANDLE reparse_point_handle, ULONG *reparse_tag)
1178{
1179    char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1180    REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
1181    DWORD n_bytes_returned;
1182
1183    if (0 == DeviceIoControl(
1184        reparse_point_handle,
1185        FSCTL_GET_REPARSE_POINT,
1186        NULL, 0, /* in buffer */
1187        target_buffer, sizeof(target_buffer),
1188        &n_bytes_returned,
1189        NULL)) /* we're not using OVERLAPPED_IO */
1190        return FALSE;
1191
1192    if (reparse_tag)
1193        *reparse_tag = rdb->ReparseTag;
1194
1195    return TRUE;
1196}
1197
1198#endif /* MS_WINDOWS */
1199
1200/* Return a dictionary corresponding to the POSIX environment table */
1201#if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
1202/* On Darwin/MacOSX a shared library or framework has no access to
1203** environ directly, we must obtain it with _NSGetEnviron(). See also
1204** man environ(7).
1205*/
1206#include <crt_externs.h>
1207static char **environ;
1208#elif !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) )
1209extern char **environ;
1210#endif /* !_MSC_VER */
1211
1212static PyObject *
1213convertenviron(void)
1214{
1215    PyObject *d;
1216#ifdef MS_WINDOWS
1217    wchar_t **e;
1218#else
1219    char **e;
1220#endif
1221
1222    d = PyDict_New();
1223    if (d == NULL)
1224        return NULL;
1225#if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
1226    if (environ == NULL)
1227        environ = *_NSGetEnviron();
1228#endif
1229#ifdef MS_WINDOWS
1230    /* _wenviron must be initialized in this way if the program is started
1231       through main() instead of wmain(). */
1232    _wgetenv(L"");
1233    if (_wenviron == NULL)
1234        return d;
1235    /* This part ignores errors */
1236    for (e = _wenviron; *e != NULL; e++) {
1237        PyObject *k;
1238        PyObject *v;
1239        wchar_t *p = wcschr(*e, L'=');
1240        if (p == NULL)
1241            continue;
1242        k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e));
1243        if (k == NULL) {
1244            PyErr_Clear();
1245            continue;
1246        }
1247        v = PyUnicode_FromWideChar(p+1, wcslen(p+1));
1248        if (v == NULL) {
1249            PyErr_Clear();
1250            Py_DECREF(k);
1251            continue;
1252        }
1253        if (PyDict_GetItem(d, k) == NULL) {
1254            if (PyDict_SetItem(d, k, v) != 0)
1255                PyErr_Clear();
1256        }
1257        Py_DECREF(k);
1258        Py_DECREF(v);
1259    }
1260#else
1261    if (environ == NULL)
1262        return d;
1263    /* This part ignores errors */
1264    for (e = environ; *e != NULL; e++) {
1265        PyObject *k;
1266        PyObject *v;
1267        char *p = strchr(*e, '=');
1268        if (p == NULL)
1269            continue;
1270        k = PyBytes_FromStringAndSize(*e, (int)(p-*e));
1271        if (k == NULL) {
1272            PyErr_Clear();
1273            continue;
1274        }
1275        v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
1276        if (v == NULL) {
1277            PyErr_Clear();
1278            Py_DECREF(k);
1279            continue;
1280        }
1281        if (PyDict_GetItem(d, k) == NULL) {
1282            if (PyDict_SetItem(d, k, v) != 0)
1283                PyErr_Clear();
1284        }
1285        Py_DECREF(k);
1286        Py_DECREF(v);
1287    }
1288#endif
1289    return d;
1290}
1291
1292/* Set a POSIX-specific error from errno, and return NULL */
1293
1294static PyObject *
1295posix_error(void)
1296{
1297    return PyErr_SetFromErrno(PyExc_OSError);
1298}
1299
1300#ifdef MS_WINDOWS
1301static PyObject *
1302win32_error(char* function, const char* filename)
1303{
1304    /* XXX We should pass the function name along in the future.
1305       (winreg.c also wants to pass the function name.)
1306       This would however require an additional param to the
1307       Windows error object, which is non-trivial.
1308    */
1309    errno = GetLastError();
1310    if (filename)
1311        return PyErr_SetFromWindowsErrWithFilename(errno, filename);
1312    else
1313        return PyErr_SetFromWindowsErr(errno);
1314}
1315
1316static PyObject *
1317win32_error_object(char* function, PyObject* filename)
1318{
1319    /* XXX - see win32_error for comments on 'function' */
1320    errno = GetLastError();
1321    if (filename)
1322        return PyErr_SetExcFromWindowsErrWithFilenameObject(
1323                    PyExc_OSError,
1324                    errno,
1325                    filename);
1326    else
1327        return PyErr_SetFromWindowsErr(errno);
1328}
1329
1330#endif /* MS_WINDOWS */
1331
1332static PyObject *
1333path_error(path_t *path)
1334{
1335#ifdef MS_WINDOWS
1336    return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError,
1337                                                        0, path->object);
1338#else
1339    return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
1340#endif
1341}
1342
1343
1344static PyObject *
1345path_error2(path_t *path, path_t *path2)
1346{
1347#ifdef MS_WINDOWS
1348    return PyErr_SetExcFromWindowsErrWithFilenameObjects(PyExc_OSError,
1349            0, path->object, path2->object);
1350#else
1351    return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError,
1352        path->object, path2->object);
1353#endif
1354}
1355
1356
1357/* POSIX generic methods */
1358
1359static PyObject *
1360posix_fildes(PyObject *fdobj, int (*func)(int))
1361{
1362    int fd;
1363    int res;
1364    fd = PyObject_AsFileDescriptor(fdobj);
1365    if (fd < 0)
1366        return NULL;
1367    if (!_PyVerify_fd(fd))
1368        return posix_error();
1369    Py_BEGIN_ALLOW_THREADS
1370    res = (*func)(fd);
1371    Py_END_ALLOW_THREADS
1372    if (res < 0)
1373        return posix_error();
1374    Py_INCREF(Py_None);
1375    return Py_None;
1376}
1377
1378static PyObject *
1379posix_1str(const char *func_name, PyObject *args, char *format,
1380           int (*func)(const char*))
1381{
1382    path_t path;
1383    int res;
1384    memset(&path, 0, sizeof(path));
1385    path.function_name = func_name;
1386    if (!PyArg_ParseTuple(args, format,
1387                          path_converter, &path))
1388        return NULL;
1389    Py_BEGIN_ALLOW_THREADS
1390    res = (*func)(path.narrow);
1391    Py_END_ALLOW_THREADS
1392    if (res < 0) {
1393        path_error(&path);
1394        path_cleanup(&path);
1395        return NULL;
1396    }
1397    path_cleanup(&path);
1398    Py_INCREF(Py_None);
1399    return Py_None;
1400}
1401
1402
1403#ifdef MS_WINDOWS
1404/* This is a reimplementation of the C library's chdir function,
1405   but one that produces Win32 errors instead of DOS error codes.
1406   chdir is essentially a wrapper around SetCurrentDirectory; however,
1407   it also needs to set "magic" environment variables indicating
1408   the per-drive current directory, which are of the form =<drive>: */
1409static BOOL __stdcall
1410win32_chdir(LPCSTR path)
1411{
1412    char new_path[MAX_PATH];
1413    int result;
1414    char env[4] = "=x:";
1415
1416    if(!SetCurrentDirectoryA(path))
1417        return FALSE;
1418    result = GetCurrentDirectoryA(Py_ARRAY_LENGTH(new_path), new_path);
1419    if (!result)
1420        return FALSE;
1421    /* In the ANSI API, there should not be any paths longer
1422       than MAX_PATH-1 (not including the final null character). */
1423    assert(result < Py_ARRAY_LENGTH(new_path));
1424    if (strncmp(new_path, "\\\\", 2) == 0 ||
1425        strncmp(new_path, "//", 2) == 0)
1426        /* UNC path, nothing to do. */
1427        return TRUE;
1428    env[1] = new_path[0];
1429    return SetEnvironmentVariableA(env, new_path);
1430}
1431
1432/* The Unicode version differs from the ANSI version
1433   since the current directory might exceed MAX_PATH characters */
1434static BOOL __stdcall
1435win32_wchdir(LPCWSTR path)
1436{
1437    wchar_t _new_path[MAX_PATH], *new_path = _new_path;
1438    int result;
1439    wchar_t env[4] = L"=x:";
1440
1441    if(!SetCurrentDirectoryW(path))
1442        return FALSE;
1443    result = GetCurrentDirectoryW(Py_ARRAY_LENGTH(new_path), new_path);
1444    if (!result)
1445        return FALSE;
1446    if (result > Py_ARRAY_LENGTH(new_path)) {
1447        new_path = PyMem_RawMalloc(result * sizeof(wchar_t));
1448        if (!new_path) {
1449            SetLastError(ERROR_OUTOFMEMORY);
1450            return FALSE;
1451        }
1452        result = GetCurrentDirectoryW(result, new_path);
1453        if (!result) {
1454            PyMem_RawFree(new_path);
1455            return FALSE;
1456        }
1457    }
1458    if (wcsncmp(new_path, L"\\\\", 2) == 0 ||
1459        wcsncmp(new_path, L"//", 2) == 0)
1460        /* UNC path, nothing to do. */
1461        return TRUE;
1462    env[1] = new_path[0];
1463    result = SetEnvironmentVariableW(env, new_path);
1464    if (new_path != _new_path)
1465        PyMem_RawFree(new_path);
1466    return result;
1467}
1468#endif
1469
1470#ifdef MS_WINDOWS
1471/* The CRT of Windows has a number of flaws wrt. its stat() implementation:
1472   - time stamps are restricted to second resolution
1473   - file modification times suffer from forth-and-back conversions between
1474     UTC and local time
1475   Therefore, we implement our own stat, based on the Win32 API directly.
1476*/
1477#define HAVE_STAT_NSEC 1
1478
1479struct win32_stat{
1480    unsigned long st_dev;
1481    __int64 st_ino;
1482    unsigned short st_mode;
1483    int st_nlink;
1484    int st_uid;
1485    int st_gid;
1486    unsigned long st_rdev;
1487    __int64 st_size;
1488    time_t st_atime;
1489    int st_atime_nsec;
1490    time_t st_mtime;
1491    int st_mtime_nsec;
1492    time_t st_ctime;
1493    int st_ctime_nsec;
1494};
1495
1496static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */
1497
1498static void
1499FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out)
1500{
1501    /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */
1502    /* Cannot simply cast and dereference in_ptr,
1503       since it might not be aligned properly */
1504    __int64 in;
1505    memcpy(&in, in_ptr, sizeof(in));
1506    *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */
1507    *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t);
1508}
1509
1510static void
1511time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr)
1512{
1513    /* XXX endianness */
1514    __int64 out;
1515    out = time_in + secs_between_epochs;
1516    out = out * 10000000 + nsec_in / 100;
1517    memcpy(out_ptr, &out, sizeof(out));
1518}
1519
1520/* Below, we *know* that ugo+r is 0444 */
1521#if _S_IREAD != 0400
1522#error Unsupported C library
1523#endif
1524static int
1525attributes_to_mode(DWORD attr)
1526{
1527    int m = 0;
1528    if (attr & FILE_ATTRIBUTE_DIRECTORY)
1529        m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */
1530    else
1531        m |= _S_IFREG;
1532    if (attr & FILE_ATTRIBUTE_READONLY)
1533        m |= 0444;
1534    else
1535        m |= 0666;
1536    return m;
1537}
1538
1539static int
1540attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct win32_stat *result)
1541{
1542    memset(result, 0, sizeof(*result));
1543    result->st_mode = attributes_to_mode(info->dwFileAttributes);
1544    result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
1545    result->st_dev = info->dwVolumeSerialNumber;
1546    result->st_rdev = result->st_dev;
1547    FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec);
1548    FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec);
1549    FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec);
1550    result->st_nlink = info->nNumberOfLinks;
1551    result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow;
1552    if (reparse_tag == IO_REPARSE_TAG_SYMLINK) {
1553        /* first clear the S_IFMT bits */
1554        result->st_mode ^= (result->st_mode & S_IFMT);
1555        /* now set the bits that make this a symlink */
1556        result->st_mode |= S_IFLNK;
1557    }
1558
1559    return 0;
1560}
1561
1562static BOOL
1563attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag)
1564{
1565    HANDLE hFindFile;
1566    WIN32_FIND_DATAA FileData;
1567    hFindFile = FindFirstFileA(pszFile, &FileData);
1568    if (hFindFile == INVALID_HANDLE_VALUE)
1569        return FALSE;
1570    FindClose(hFindFile);
1571    memset(info, 0, sizeof(*info));
1572    *reparse_tag = 0;
1573    info->dwFileAttributes = FileData.dwFileAttributes;
1574    info->ftCreationTime   = FileData.ftCreationTime;
1575    info->ftLastAccessTime = FileData.ftLastAccessTime;
1576    info->ftLastWriteTime  = FileData.ftLastWriteTime;
1577    info->nFileSizeHigh    = FileData.nFileSizeHigh;
1578    info->nFileSizeLow     = FileData.nFileSizeLow;
1579/*  info->nNumberOfLinks   = 1; */
1580    if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1581        *reparse_tag = FileData.dwReserved0;
1582    return TRUE;
1583}
1584
1585static BOOL
1586attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag)
1587{
1588    HANDLE hFindFile;
1589    WIN32_FIND_DATAW FileData;
1590    hFindFile = FindFirstFileW(pszFile, &FileData);
1591    if (hFindFile == INVALID_HANDLE_VALUE)
1592        return FALSE;
1593    FindClose(hFindFile);
1594    memset(info, 0, sizeof(*info));
1595    *reparse_tag = 0;
1596    info->dwFileAttributes = FileData.dwFileAttributes;
1597    info->ftCreationTime   = FileData.ftCreationTime;
1598    info->ftLastAccessTime = FileData.ftLastAccessTime;
1599    info->ftLastWriteTime  = FileData.ftLastWriteTime;
1600    info->nFileSizeHigh    = FileData.nFileSizeHigh;
1601    info->nFileSizeLow     = FileData.nFileSizeLow;
1602/*  info->nNumberOfLinks   = 1; */
1603    if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1604        *reparse_tag = FileData.dwReserved0;
1605    return TRUE;
1606}
1607
1608/* Grab GetFinalPathNameByHandle dynamically from kernel32 */
1609static int has_GetFinalPathNameByHandle = -1;
1610static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD,
1611                                                      DWORD);
1612static int
1613check_GetFinalPathNameByHandle()
1614{
1615    HINSTANCE hKernel32;
1616    DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD,
1617                                                   DWORD);
1618
1619    /* only recheck */
1620    if (-1 == has_GetFinalPathNameByHandle)
1621    {
1622        hKernel32 = GetModuleHandleW(L"KERNEL32");
1623        *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32,
1624                                                "GetFinalPathNameByHandleA");
1625        *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32,
1626                                                "GetFinalPathNameByHandleW");
1627        has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA &&
1628                                       Py_GetFinalPathNameByHandleW;
1629    }
1630    return has_GetFinalPathNameByHandle;
1631}
1632
1633static BOOL
1634get_target_path(HANDLE hdl, wchar_t **target_path)
1635{
1636    int buf_size, result_length;
1637    wchar_t *buf;
1638
1639    /* We have a good handle to the target, use it to determine
1640       the target path name (then we'll call lstat on it). */
1641    buf_size = Py_GetFinalPathNameByHandleW(hdl, 0, 0,
1642                                            VOLUME_NAME_DOS);
1643    if(!buf_size)
1644        return FALSE;
1645
1646    buf = PyMem_New(wchar_t, buf_size+1);
1647    if (!buf) {
1648        SetLastError(ERROR_OUTOFMEMORY);
1649        return FALSE;
1650    }
1651
1652    result_length = Py_GetFinalPathNameByHandleW(hdl,
1653                       buf, buf_size, VOLUME_NAME_DOS);
1654
1655    if(!result_length) {
1656        PyMem_Free(buf);
1657        return FALSE;
1658    }
1659
1660    if(!CloseHandle(hdl)) {
1661        PyMem_Free(buf);
1662        return FALSE;
1663    }
1664
1665    buf[result_length] = 0;
1666
1667    *target_path = buf;
1668    return TRUE;
1669}
1670
1671static int
1672win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result,
1673                   BOOL traverse);
1674static int
1675win32_xstat_impl(const char *path, struct win32_stat *result,
1676                 BOOL traverse)
1677{
1678    int code;
1679    HANDLE hFile, hFile2;
1680    BY_HANDLE_FILE_INFORMATION info;
1681    ULONG reparse_tag = 0;
1682    wchar_t *target_path;
1683    const char *dot;
1684
1685    if(!check_GetFinalPathNameByHandle()) {
1686        /* If the OS doesn't have GetFinalPathNameByHandle, don't
1687           traverse reparse point. */
1688        traverse = FALSE;
1689    }
1690
1691    hFile = CreateFileA(
1692        path,
1693        FILE_READ_ATTRIBUTES, /* desired access */
1694        0, /* share mode */
1695        NULL, /* security attributes */
1696        OPEN_EXISTING,
1697        /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1698        /* FILE_FLAG_OPEN_REPARSE_POINT does not follow the symlink.
1699           Because of this, calls like GetFinalPathNameByHandle will return
1700           the symlink path again and not the actual final path. */
1701        FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|
1702            FILE_FLAG_OPEN_REPARSE_POINT,
1703        NULL);
1704
1705    if (hFile == INVALID_HANDLE_VALUE) {
1706        /* Either the target doesn't exist, or we don't have access to
1707           get a handle to it. If the former, we need to return an error.
1708           If the latter, we can use attributes_from_dir. */
1709        if (GetLastError() != ERROR_SHARING_VIOLATION)
1710            return -1;
1711        /* Could not get attributes on open file. Fall back to
1712           reading the directory. */
1713        if (!attributes_from_dir(path, &info, &reparse_tag))
1714            /* Very strange. This should not fail now */
1715            return -1;
1716        if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1717            if (traverse) {
1718                /* Should traverse, but could not open reparse point handle */
1719                SetLastError(ERROR_SHARING_VIOLATION);
1720                return -1;
1721            }
1722        }
1723    } else {
1724        if (!GetFileInformationByHandle(hFile, &info)) {
1725            CloseHandle(hFile);
1726            return -1;
1727        }
1728        if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1729            if (!win32_get_reparse_tag(hFile, &reparse_tag))
1730                return -1;
1731
1732            /* Close the outer open file handle now that we're about to
1733               reopen it with different flags. */
1734            if (!CloseHandle(hFile))
1735                return -1;
1736
1737            if (traverse) {
1738                /* In order to call GetFinalPathNameByHandle we need to open
1739                   the file without the reparse handling flag set. */
1740                hFile2 = CreateFileA(
1741                           path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
1742                           NULL, OPEN_EXISTING,
1743                           FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,
1744                           NULL);
1745                if (hFile2 == INVALID_HANDLE_VALUE)
1746                    return -1;
1747
1748                if (!get_target_path(hFile2, &target_path))
1749                    return -1;
1750
1751                code = win32_xstat_impl_w(target_path, result, FALSE);
1752                PyMem_Free(target_path);
1753                return code;
1754            }
1755        } else
1756            CloseHandle(hFile);
1757    }
1758    attribute_data_to_stat(&info, reparse_tag, result);
1759
1760    /* Set S_IEXEC if it is an .exe, .bat, ... */
1761    dot = strrchr(path, '.');
1762    if (dot) {
1763        if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 ||
1764            stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0)
1765            result->st_mode |= 0111;
1766    }
1767    return 0;
1768}
1769
1770static int
1771win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result,
1772                   BOOL traverse)
1773{
1774    int code;
1775    HANDLE hFile, hFile2;
1776    BY_HANDLE_FILE_INFORMATION info;
1777    ULONG reparse_tag = 0;
1778    wchar_t *target_path;
1779    const wchar_t *dot;
1780
1781    if(!check_GetFinalPathNameByHandle()) {
1782        /* If the OS doesn't have GetFinalPathNameByHandle, don't
1783           traverse reparse point. */
1784        traverse = FALSE;
1785    }
1786
1787    hFile = CreateFileW(
1788        path,
1789        FILE_READ_ATTRIBUTES, /* desired access */
1790        0, /* share mode */
1791        NULL, /* security attributes */
1792        OPEN_EXISTING,
1793        /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1794        /* FILE_FLAG_OPEN_REPARSE_POINT does not follow the symlink.
1795           Because of this, calls like GetFinalPathNameByHandle will return
1796           the symlink path again and not the actual final path. */
1797        FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|
1798            FILE_FLAG_OPEN_REPARSE_POINT,
1799        NULL);
1800
1801    if (hFile == INVALID_HANDLE_VALUE) {
1802        /* Either the target doesn't exist, or we don't have access to
1803           get a handle to it. If the former, we need to return an error.
1804           If the latter, we can use attributes_from_dir. */
1805        if (GetLastError() != ERROR_SHARING_VIOLATION)
1806            return -1;
1807        /* Could not get attributes on open file. Fall back to
1808           reading the directory. */
1809        if (!attributes_from_dir_w(path, &info, &reparse_tag))
1810            /* Very strange. This should not fail now */
1811            return -1;
1812        if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1813            if (traverse) {
1814                /* Should traverse, but could not open reparse point handle */
1815                SetLastError(ERROR_SHARING_VIOLATION);
1816                return -1;
1817            }
1818        }
1819    } else {
1820        if (!GetFileInformationByHandle(hFile, &info)) {
1821            CloseHandle(hFile);
1822            return -1;
1823        }
1824        if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1825            if (!win32_get_reparse_tag(hFile, &reparse_tag))
1826                return -1;
1827
1828            /* Close the outer open file handle now that we're about to
1829               reopen it with different flags. */
1830            if (!CloseHandle(hFile))
1831                return -1;
1832
1833            if (traverse) {
1834                /* In order to call GetFinalPathNameByHandle we need to open
1835                   the file without the reparse handling flag set. */
1836                hFile2 = CreateFileW(
1837                           path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
1838                           NULL, OPEN_EXISTING,
1839                           FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,
1840                           NULL);
1841                if (hFile2 == INVALID_HANDLE_VALUE)
1842                    return -1;
1843
1844                if (!get_target_path(hFile2, &target_path))
1845                    return -1;
1846
1847                code = win32_xstat_impl_w(target_path, result, FALSE);
1848                PyMem_Free(target_path);
1849                return code;
1850            }
1851        } else
1852            CloseHandle(hFile);
1853    }
1854    attribute_data_to_stat(&info, reparse_tag, result);
1855
1856    /* Set S_IEXEC if it is an .exe, .bat, ... */
1857    dot = wcsrchr(path, '.');
1858    if (dot) {
1859        if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 ||
1860            _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0)
1861            result->st_mode |= 0111;
1862    }
1863    return 0;
1864}
1865
1866static int
1867win32_xstat(const char *path, struct win32_stat *result, BOOL traverse)
1868{
1869    /* Protocol violation: we explicitly clear errno, instead of
1870       setting it to a POSIX error. Callers should use GetLastError. */
1871    int code = win32_xstat_impl(path, result, traverse);
1872    errno = 0;
1873    return code;
1874}
1875
1876static int
1877win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse)
1878{
1879    /* Protocol violation: we explicitly clear errno, instead of
1880       setting it to a POSIX error. Callers should use GetLastError. */
1881    int code = win32_xstat_impl_w(path, result, traverse);
1882    errno = 0;
1883    return code;
1884}
1885/* About the following functions: win32_lstat_w, win32_stat, win32_stat_w
1886
1887   In Posix, stat automatically traverses symlinks and returns the stat
1888   structure for the target.  In Windows, the equivalent GetFileAttributes by
1889   default does not traverse symlinks and instead returns attributes for
1890   the symlink.
1891
1892   Therefore, win32_lstat will get the attributes traditionally, and
1893   win32_stat will first explicitly resolve the symlink target and then will
1894   call win32_lstat on that result.
1895
1896   The _w represent Unicode equivalents of the aforementioned ANSI functions. */
1897
1898static int
1899win32_lstat(const char* path, struct win32_stat *result)
1900{
1901    return win32_xstat(path, result, FALSE);
1902}
1903
1904static int
1905win32_lstat_w(const wchar_t* path, struct win32_stat *result)
1906{
1907    return win32_xstat_w(path, result, FALSE);
1908}
1909
1910static int
1911win32_stat(const char* path, struct win32_stat *result)
1912{
1913    return win32_xstat(path, result, TRUE);
1914}
1915
1916static int
1917win32_stat_w(const wchar_t* path, struct win32_stat *result)
1918{
1919    return win32_xstat_w(path, result, TRUE);
1920}
1921
1922static int
1923win32_fstat(int file_number, struct win32_stat *result)
1924{
1925    BY_HANDLE_FILE_INFORMATION info;
1926    HANDLE h;
1927    int type;
1928
1929    if (!_PyVerify_fd(file_number))
1930        h = INVALID_HANDLE_VALUE;
1931    else
1932        h = (HANDLE)_get_osfhandle(file_number);
1933
1934    /* Protocol violation: we explicitly clear errno, instead of
1935       setting it to a POSIX error. Callers should use GetLastError. */
1936    errno = 0;
1937
1938    if (h == INVALID_HANDLE_VALUE) {
1939        /* This is really a C library error (invalid file handle).
1940           We set the Win32 error to the closes one matching. */
1941        SetLastError(ERROR_INVALID_HANDLE);
1942        return -1;
1943    }
1944    memset(result, 0, sizeof(*result));
1945
1946    type = GetFileType(h);
1947    if (type == FILE_TYPE_UNKNOWN) {
1948        DWORD error = GetLastError();
1949        if (error != 0) {
1950            return -1;
1951        }
1952        /* else: valid but unknown file */
1953    }
1954
1955    if (type != FILE_TYPE_DISK) {
1956        if (type == FILE_TYPE_CHAR)
1957            result->st_mode = _S_IFCHR;
1958        else if (type == FILE_TYPE_PIPE)
1959            result->st_mode = _S_IFIFO;
1960        return 0;
1961    }
1962
1963    if (!GetFileInformationByHandle(h, &info)) {
1964        return -1;
1965    }
1966
1967    attribute_data_to_stat(&info, 0, result);
1968    /* specific to fstat() */
1969    result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
1970    return 0;
1971}
1972
1973#endif /* MS_WINDOWS */
1974
1975PyDoc_STRVAR(stat_result__doc__,
1976"stat_result: Result from stat, fstat, or lstat.\n\n\
1977This object may be accessed either as a tuple of\n\
1978  (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
1979or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\
1980\n\
1981Posix/windows: If your platform supports st_blksize, st_blocks, st_rdev,\n\
1982or st_flags, they are available as attributes only.\n\
1983\n\
1984See os.stat for more information.");
1985
1986static PyStructSequence_Field stat_result_fields[] = {
1987    {"st_mode",    "protection bits"},
1988    {"st_ino",     "inode"},
1989    {"st_dev",     "device"},
1990    {"st_nlink",   "number of hard links"},
1991    {"st_uid",     "user ID of owner"},
1992    {"st_gid",     "group ID of owner"},
1993    {"st_size",    "total size, in bytes"},
1994    /* The NULL is replaced with PyStructSequence_UnnamedField later. */
1995    {NULL,   "integer time of last access"},
1996    {NULL,   "integer time of last modification"},
1997    {NULL,   "integer time of last change"},
1998    {"st_atime",   "time of last access"},
1999    {"st_mtime",   "time of last modification"},
2000    {"st_ctime",   "time of last change"},
2001    {"st_atime_ns",   "time of last access in nanoseconds"},
2002    {"st_mtime_ns",   "time of last modification in nanoseconds"},
2003    {"st_ctime_ns",   "time of last change in nanoseconds"},
2004#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2005    {"st_blksize", "blocksize for filesystem I/O"},
2006#endif
2007#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2008    {"st_blocks",  "number of blocks allocated"},
2009#endif
2010#ifdef HAVE_STRUCT_STAT_ST_RDEV
2011    {"st_rdev",    "device type (if inode device)"},
2012#endif
2013#ifdef HAVE_STRUCT_STAT_ST_FLAGS
2014    {"st_flags",   "user defined flags for file"},
2015#endif
2016#ifdef HAVE_STRUCT_STAT_ST_GEN
2017    {"st_gen",    "generation number"},
2018#endif
2019#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2020    {"st_birthtime",   "time of creation"},
2021#endif
2022    {0}
2023};
2024
2025#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2026#define ST_BLKSIZE_IDX 16
2027#else
2028#define ST_BLKSIZE_IDX 15
2029#endif
2030
2031#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2032#define ST_BLOCKS_IDX (ST_BLKSIZE_IDX+1)
2033#else
2034#define ST_BLOCKS_IDX ST_BLKSIZE_IDX
2035#endif
2036
2037#ifdef HAVE_STRUCT_STAT_ST_RDEV
2038#define ST_RDEV_IDX (ST_BLOCKS_IDX+1)
2039#else
2040#define ST_RDEV_IDX ST_BLOCKS_IDX
2041#endif
2042
2043#ifdef HAVE_STRUCT_STAT_ST_FLAGS
2044#define ST_FLAGS_IDX (ST_RDEV_IDX+1)
2045#else
2046#define ST_FLAGS_IDX ST_RDEV_IDX
2047#endif
2048
2049#ifdef HAVE_STRUCT_STAT_ST_GEN
2050#define ST_GEN_IDX (ST_FLAGS_IDX+1)
2051#else
2052#define ST_GEN_IDX ST_FLAGS_IDX
2053#endif
2054
2055#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2056#define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
2057#else
2058#define ST_BIRTHTIME_IDX ST_GEN_IDX
2059#endif
2060
2061static PyStructSequence_Desc stat_result_desc = {
2062    "stat_result", /* name */
2063    stat_result__doc__, /* doc */
2064    stat_result_fields,
2065    10
2066};
2067
2068PyDoc_STRVAR(statvfs_result__doc__,
2069"statvfs_result: Result from statvfs or fstatvfs.\n\n\
2070This object may be accessed either as a tuple of\n\
2071  (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax),\n\
2072or via the attributes f_bsize, f_frsize, f_blocks, f_bfree, and so on.\n\
2073\n\
2074See os.statvfs for more information.");
2075
2076static PyStructSequence_Field statvfs_result_fields[] = {
2077    {"f_bsize",  },
2078    {"f_frsize", },
2079    {"f_blocks", },
2080    {"f_bfree",  },
2081    {"f_bavail", },
2082    {"f_files",  },
2083    {"f_ffree",  },
2084    {"f_favail", },
2085    {"f_flag",   },
2086    {"f_namemax",},
2087    {0}
2088};
2089
2090static PyStructSequence_Desc statvfs_result_desc = {
2091    "statvfs_result", /* name */
2092    statvfs_result__doc__, /* doc */
2093    statvfs_result_fields,
2094    10
2095};
2096
2097#if defined(HAVE_WAITID) && !defined(__APPLE__)
2098PyDoc_STRVAR(waitid_result__doc__,
2099"waitid_result: Result from waitid.\n\n\
2100This object may be accessed either as a tuple of\n\
2101  (si_pid, si_uid, si_signo, si_status, si_code),\n\
2102or via the attributes si_pid, si_uid, and so on.\n\
2103\n\
2104See os.waitid for more information.");
2105
2106static PyStructSequence_Field waitid_result_fields[] = {
2107    {"si_pid",  },
2108    {"si_uid", },
2109    {"si_signo", },
2110    {"si_status",  },
2111    {"si_code", },
2112    {0}
2113};
2114
2115static PyStructSequence_Desc waitid_result_desc = {
2116    "waitid_result", /* name */
2117    waitid_result__doc__, /* doc */
2118    waitid_result_fields,
2119    5
2120};
2121static PyTypeObject WaitidResultType;
2122#endif
2123
2124static int initialized;
2125static PyTypeObject StatResultType;
2126static PyTypeObject StatVFSResultType;
2127#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER)
2128static PyTypeObject SchedParamType;
2129#endif
2130static newfunc structseq_new;
2131
2132static PyObject *
2133statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2134{
2135    PyStructSequence *result;
2136    int i;
2137
2138    result = (PyStructSequence*)structseq_new(type, args, kwds);
2139    if (!result)
2140        return NULL;
2141    /* If we have been initialized from a tuple,
2142       st_?time might be set to None. Initialize it
2143       from the int slots.  */
2144    for (i = 7; i <= 9; i++) {
2145        if (result->ob_item[i+3] == Py_None) {
2146            Py_DECREF(Py_None);
2147            Py_INCREF(result->ob_item[i]);
2148            result->ob_item[i+3] = result->ob_item[i];
2149        }
2150    }
2151    return (PyObject*)result;
2152}
2153
2154
2155
2156/* If true, st_?time is float. */
2157static int _stat_float_times = 1;
2158
2159PyDoc_STRVAR(stat_float_times__doc__,
2160"stat_float_times([newval]) -> oldval\n\n\
2161Determine whether os.[lf]stat represents time stamps as float objects.\n\
2162If newval is True, future calls to stat() return floats, if it is False,\n\
2163future calls return ints. \n\
2164If newval is omitted, return the current setting.\n");
2165
2166static PyObject*
2167stat_float_times(PyObject* self, PyObject *args)
2168{
2169    int newval = -1;
2170    if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval))
2171        return NULL;
2172    if (PyErr_WarnEx(PyExc_DeprecationWarning,
2173                     "stat_float_times() is deprecated",
2174                     1))
2175        return NULL;
2176    if (newval == -1)
2177        /* Return old value */
2178        return PyBool_FromLong(_stat_float_times);
2179    _stat_float_times = newval;
2180    Py_INCREF(Py_None);
2181    return Py_None;
2182}
2183
2184static PyObject *billion = NULL;
2185
2186static void
2187fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
2188{
2189    PyObject *s = _PyLong_FromTime_t(sec);
2190    PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2191    PyObject *s_in_ns = NULL;
2192    PyObject *ns_total = NULL;
2193    PyObject *float_s = NULL;
2194
2195    if (!(s && ns_fractional))
2196        goto exit;
2197
2198    s_in_ns = PyNumber_Multiply(s, billion);
2199    if (!s_in_ns)
2200        goto exit;
2201
2202    ns_total = PyNumber_Add(s_in_ns, ns_fractional);
2203    if (!ns_total)
2204        goto exit;
2205
2206    if (_stat_float_times) {
2207        float_s = PyFloat_FromDouble(sec + 1e-9*nsec);
2208        if (!float_s)
2209            goto exit;
2210    }
2211    else {
2212        float_s = s;
2213        Py_INCREF(float_s);
2214    }
2215
2216    PyStructSequence_SET_ITEM(v, index, s);
2217    PyStructSequence_SET_ITEM(v, index+3, float_s);
2218    PyStructSequence_SET_ITEM(v, index+6, ns_total);
2219    s = NULL;
2220    float_s = NULL;
2221    ns_total = NULL;
2222exit:
2223    Py_XDECREF(s);
2224    Py_XDECREF(ns_fractional);
2225    Py_XDECREF(s_in_ns);
2226    Py_XDECREF(ns_total);
2227    Py_XDECREF(float_s);
2228}
2229
2230/* pack a system stat C structure into the Python stat tuple
2231   (used by posix_stat() and posix_fstat()) */
2232static PyObject*
2233_pystat_fromstructstat(STRUCT_STAT *st)
2234{
2235    unsigned long ansec, mnsec, cnsec;
2236    PyObject *v = PyStructSequence_New(&StatResultType);
2237    if (v == NULL)
2238        return NULL;
2239
2240    PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
2241#ifdef HAVE_LARGEFILE_SUPPORT
2242    PyStructSequence_SET_ITEM(v, 1,
2243                              PyLong_FromLongLong((PY_LONG_LONG)st->st_ino));
2244#else
2245    PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long)st->st_ino));
2246#endif
2247#ifdef MS_WINDOWS
2248    PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
2249#else
2250    PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev));
2251#endif
2252    PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink));
2253#if defined(MS_WINDOWS)
2254    PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0));
2255    PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0));
2256#else
2257    PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
2258    PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
2259#endif
2260#ifdef HAVE_LARGEFILE_SUPPORT
2261    PyStructSequence_SET_ITEM(v, 6,
2262                              PyLong_FromLongLong((PY_LONG_LONG)st->st_size));
2263#else
2264    PyStructSequence_SET_ITEM(v, 6, PyLong_FromLong(st->st_size));
2265#endif
2266
2267#if defined(HAVE_STAT_TV_NSEC)
2268    ansec = st->st_atim.tv_nsec;
2269    mnsec = st->st_mtim.tv_nsec;
2270    cnsec = st->st_ctim.tv_nsec;
2271#elif defined(HAVE_STAT_TV_NSEC2)
2272    ansec = st->st_atimespec.tv_nsec;
2273    mnsec = st->st_mtimespec.tv_nsec;
2274    cnsec = st->st_ctimespec.tv_nsec;
2275#elif defined(HAVE_STAT_NSEC)
2276    ansec = st->st_atime_nsec;
2277    mnsec = st->st_mtime_nsec;
2278    cnsec = st->st_ctime_nsec;
2279#else
2280    ansec = mnsec = cnsec = 0;
2281#endif
2282    fill_time(v, 7, st->st_atime, ansec);
2283    fill_time(v, 8, st->st_mtime, mnsec);
2284    fill_time(v, 9, st->st_ctime, cnsec);
2285
2286#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2287    PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
2288                              PyLong_FromLong((long)st->st_blksize));
2289#endif
2290#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2291    PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
2292                              PyLong_FromLong((long)st->st_blocks));
2293#endif
2294#ifdef HAVE_STRUCT_STAT_ST_RDEV
2295    PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
2296                              PyLong_FromLong((long)st->st_rdev));
2297#endif
2298#ifdef HAVE_STRUCT_STAT_ST_GEN
2299    PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
2300                              PyLong_FromLong((long)st->st_gen));
2301#endif
2302#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2303    {
2304      PyObject *val;
2305      unsigned long bsec,bnsec;
2306      bsec = (long)st->st_birthtime;
2307#ifdef HAVE_STAT_TV_NSEC2
2308      bnsec = st->st_birthtimespec.tv_nsec;
2309#else
2310      bnsec = 0;
2311#endif
2312      if (_stat_float_times) {
2313        val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
2314      } else {
2315        val = PyLong_FromLong((long)bsec);
2316      }
2317      PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
2318                                val);
2319    }
2320#endif
2321#ifdef HAVE_STRUCT_STAT_ST_FLAGS
2322    PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
2323                              PyLong_FromLong((long)st->st_flags));
2324#endif
2325
2326    if (PyErr_Occurred()) {
2327        Py_DECREF(v);
2328        return NULL;
2329    }
2330
2331    return v;
2332}
2333
2334/* POSIX methods */
2335
2336
2337static PyObject *
2338posix_do_stat(char *function_name, path_t *path,
2339              int dir_fd, int follow_symlinks)
2340{
2341    STRUCT_STAT st;
2342    int result;
2343
2344#if !defined(MS_WINDOWS) && !defined(HAVE_FSTATAT) && !defined(HAVE_LSTAT)
2345    if (follow_symlinks_specified(function_name, follow_symlinks))
2346        return NULL;
2347#endif
2348
2349    if (path_and_dir_fd_invalid("stat", path, dir_fd) ||
2350        dir_fd_and_fd_invalid("stat", dir_fd, path->fd) ||
2351        fd_and_follow_symlinks_invalid("stat", path->fd, follow_symlinks))
2352        return NULL;
2353
2354    Py_BEGIN_ALLOW_THREADS
2355    if (path->fd != -1)
2356        result = FSTAT(path->fd, &st);
2357    else
2358#ifdef MS_WINDOWS
2359    if (path->wide) {
2360        if (follow_symlinks)
2361            result = win32_stat_w(path->wide, &st);
2362        else
2363            result = win32_lstat_w(path->wide, &st);
2364    }
2365    else
2366#endif
2367#if defined(HAVE_LSTAT) || defined(MS_WINDOWS)
2368    if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
2369        result = LSTAT(path->narrow, &st);
2370    else
2371#endif
2372#ifdef HAVE_FSTATAT
2373    if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks)
2374        result = fstatat(dir_fd, path->narrow, &st,
2375                         follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
2376    else
2377#endif
2378        result = STAT(path->narrow, &st);
2379    Py_END_ALLOW_THREADS
2380
2381    if (result != 0) {
2382        return path_error(path);
2383    }
2384
2385    return _pystat_fromstructstat(&st);
2386}
2387
2388#ifdef HAVE_FSTATAT
2389    #define OS_STAT_DIR_FD_CONVERTER dir_fd_converter
2390#else
2391    #define OS_STAT_DIR_FD_CONVERTER dir_fd_unavailable
2392#endif
2393
2394
2395/*[python input]
2396
2397class path_t_converter(CConverter):
2398
2399    type = "path_t"
2400    impl_by_reference = True
2401    parse_by_reference = True
2402
2403    converter = 'path_converter'
2404
2405    def converter_init(self, *, allow_fd=False, nullable=False):
2406        # right now path_t doesn't support default values.
2407        # to support a default value, you'll need to override initialize().
2408        if self.default is not unspecified:
2409            fail("Can't specify a default to the path_t converter!")
2410
2411        if self.c_default is not None:
2412            fail("Can't specify a c_default to the path_t converter!")
2413
2414        self.nullable = nullable
2415        self.allow_fd = allow_fd
2416
2417    def pre_render(self):
2418        def strify(value):
2419            return str(int(bool(value)))
2420
2421        # add self.py_name here when merging with posixmodule conversion
2422        self.c_default = 'PATH_T_INITIALIZE("{}", {}, {})'.format(
2423            self.function.name,
2424            strify(self.nullable),
2425            strify(self.allow_fd),
2426            )
2427
2428    def cleanup(self):
2429        return "path_cleanup(&" + self.name + ");\n"
2430
2431
2432class dir_fd_converter(CConverter):
2433    type = 'int'
2434    converter = 'OS_STAT_DIR_FD_CONVERTER'
2435
2436    def converter_init(self):
2437        if self.default in (unspecified, None):
2438            self.c_default = 'DEFAULT_DIR_FD'
2439
2440
2441[python start generated code]*/
2442/*[python end generated code: output=da39a3ee5e6b4b0d input=5c9f456f53244fc3]*/
2443
2444/*[clinic input]
2445
2446os.stat
2447
2448    path : path_t(allow_fd=True)
2449        Path to be examined; can be string, bytes, or open-file-descriptor int.
2450
2451    *
2452
2453    dir_fd : dir_fd = None
2454        If not None, it should be a file descriptor open to a directory,
2455        and path should be a relative string; path will then be relative to
2456        that directory.
2457
2458    follow_symlinks: bool = True
2459        If False, and the last element of the path is a symbolic link,
2460        stat will examine the symbolic link itself instead of the file
2461        the link points to.
2462
2463Perform a stat system call on the given path.
2464
2465dir_fd and follow_symlinks may not be implemented
2466  on your platform.  If they are unavailable, using them will raise a
2467  NotImplementedError.
2468
2469It's an error to use dir_fd or follow_symlinks when specifying path as
2470  an open file descriptor.
2471
2472[clinic start generated code]*/
2473
2474PyDoc_STRVAR(os_stat__doc__,
2475"stat($module, /, path, *, dir_fd=None, follow_symlinks=True)\n"
2476"--\n"
2477"\n"
2478"Perform a stat system call on the given path.\n"
2479"\n"
2480"  path\n"
2481"    Path to be examined; can be string, bytes, or open-file-descriptor int.\n"
2482"  dir_fd\n"
2483"    If not None, it should be a file descriptor open to a directory,\n"
2484"    and path should be a relative string; path will then be relative to\n"
2485"    that directory.\n"
2486"  follow_symlinks\n"
2487"    If False, and the last element of the path is a symbolic link,\n"
2488"    stat will examine the symbolic link itself instead of the file\n"
2489"    the link points to.\n"
2490"\n"
2491"dir_fd and follow_symlinks may not be implemented\n"
2492"  on your platform.  If they are unavailable, using them will raise a\n"
2493"  NotImplementedError.\n"
2494"\n"
2495"It\'s an error to use dir_fd or follow_symlinks when specifying path as\n"
2496"  an open file descriptor.");
2497
2498#define OS_STAT_METHODDEF    \
2499    {"stat", (PyCFunction)os_stat, METH_VARARGS|METH_KEYWORDS, os_stat__doc__},
2500
2501static PyObject *
2502os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks);
2503
2504static PyObject *
2505os_stat(PyModuleDef *module, PyObject *args, PyObject *kwargs)
2506{
2507    PyObject *return_value = NULL;
2508    static char *_keywords[] = {"path", "dir_fd", "follow_symlinks", NULL};
2509    path_t path = PATH_T_INITIALIZE("stat", 0, 1);
2510    int dir_fd = DEFAULT_DIR_FD;
2511    int follow_symlinks = 1;
2512
2513    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
2514        "O&|$O&p:stat", _keywords,
2515        path_converter, &path, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &follow_symlinks))
2516        goto exit;
2517    return_value = os_stat_impl(module, &path, dir_fd, follow_symlinks);
2518
2519exit:
2520    /* Cleanup for path */
2521    path_cleanup(&path);
2522
2523    return return_value;
2524}
2525
2526static PyObject *
2527os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks)
2528/*[clinic end generated code: output=f1dcaa5e24db9882 input=5ae155bd475fd20a]*/
2529{
2530    return posix_do_stat("stat", path, dir_fd, follow_symlinks);
2531}
2532
2533PyDoc_STRVAR(posix_lstat__doc__,
2534"lstat(path, *, dir_fd=None) -> stat result\n\n\
2535Like stat(), but do not follow symbolic links.\n\
2536Equivalent to stat(path, follow_symlinks=False).");
2537
2538static PyObject *
2539posix_lstat(PyObject *self, PyObject *args, PyObject *kwargs)
2540{
2541    static char *keywords[] = {"path", "dir_fd", NULL};
2542    path_t path;
2543    int dir_fd = DEFAULT_DIR_FD;
2544    int follow_symlinks = 0;
2545    PyObject *return_value;
2546
2547    memset(&path, 0, sizeof(path));
2548    path.function_name = "lstat";
2549    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:lstat", keywords,
2550        path_converter, &path,
2551#ifdef HAVE_FSTATAT
2552        dir_fd_converter, &dir_fd
2553#else
2554        dir_fd_unavailable, &dir_fd
2555#endif
2556        ))
2557        return NULL;
2558    return_value = posix_do_stat("lstat", &path, dir_fd, follow_symlinks);
2559    path_cleanup(&path);
2560    return return_value;
2561}
2562
2563
2564#ifdef HAVE_FACCESSAT
2565    #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_converter
2566#else
2567    #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable
2568#endif
2569/*[clinic input]
2570os.access
2571
2572    path: path_t(allow_fd=True)
2573        Path to be tested; can be string, bytes, or open-file-descriptor int.
2574
2575    mode: int
2576        Operating-system mode bitfield.  Can be F_OK to test existence,
2577        or the inclusive-OR of R_OK, W_OK, and X_OK.
2578
2579    *
2580
2581    dir_fd : dir_fd = None
2582        If not None, it should be a file descriptor open to a directory,
2583        and path should be relative; path will then be relative to that
2584        directory.
2585
2586    effective_ids: bool = False
2587        If True, access will use the effective uid/gid instead of
2588        the real uid/gid.
2589
2590    follow_symlinks: bool = True
2591        If False, and the last element of the path is a symbolic link,
2592        access will examine the symbolic link itself instead of the file
2593        the link points to.
2594
2595Use the real uid/gid to test for access to a path.
2596
2597{parameters}
2598dir_fd, effective_ids, and follow_symlinks may not be implemented
2599  on your platform.  If they are unavailable, using them will raise a
2600  NotImplementedError.
2601
2602Note that most operations will use the effective uid/gid, therefore this
2603  routine can be used in a suid/sgid environment to test if the invoking user
2604  has the specified access to the path.
2605
2606[clinic start generated code]*/
2607
2608PyDoc_STRVAR(os_access__doc__,
2609"access($module, /, path, mode, *, dir_fd=None, effective_ids=False,\n"
2610"       follow_symlinks=True)\n"
2611"--\n"
2612"\n"
2613"Use the real uid/gid to test for access to a path.\n"
2614"\n"
2615"  path\n"
2616"    Path to be tested; can be string, bytes, or open-file-descriptor int.\n"
2617"  mode\n"
2618"    Operating-system mode bitfield.  Can be F_OK to test existence,\n"
2619"    or the inclusive-OR of R_OK, W_OK, and X_OK.\n"
2620"  dir_fd\n"
2621"    If not None, it should be a file descriptor open to a directory,\n"
2622"    and path should be relative; path will then be relative to that\n"
2623"    directory.\n"
2624"  effective_ids\n"
2625"    If True, access will use the effective uid/gid instead of\n"
2626"    the real uid/gid.\n"
2627"  follow_symlinks\n"
2628"    If False, and the last element of the path is a symbolic link,\n"
2629"    access will examine the symbolic link itself instead of the file\n"
2630"    the link points to.\n"
2631"\n"
2632"dir_fd, effective_ids, and follow_symlinks may not be implemented\n"
2633"  on your platform.  If they are unavailable, using them will raise a\n"
2634"  NotImplementedError.\n"
2635"\n"
2636"Note that most operations will use the effective uid/gid, therefore this\n"
2637"  routine can be used in a suid/sgid environment to test if the invoking user\n"
2638"  has the specified access to the path.");
2639
2640#define OS_ACCESS_METHODDEF    \
2641    {"access", (PyCFunction)os_access, METH_VARARGS|METH_KEYWORDS, os_access__doc__},
2642
2643static PyObject *
2644os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks);
2645
2646static PyObject *
2647os_access(PyModuleDef *module, PyObject *args, PyObject *kwargs)
2648{
2649    PyObject *return_value = NULL;
2650    static char *_keywords[] = {"path", "mode", "dir_fd", "effective_ids", "follow_symlinks", NULL};
2651    path_t path = PATH_T_INITIALIZE("access", 0, 1);
2652    int mode;
2653    int dir_fd = DEFAULT_DIR_FD;
2654    int effective_ids = 0;
2655    int follow_symlinks = 1;
2656
2657    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
2658        "O&i|$O&pp:access", _keywords,
2659        path_converter, &path, &mode, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &effective_ids, &follow_symlinks))
2660        goto exit;
2661    return_value = os_access_impl(module, &path, mode, dir_fd, effective_ids, follow_symlinks);
2662
2663exit:
2664    /* Cleanup for path */
2665    path_cleanup(&path);
2666
2667    return return_value;
2668}
2669
2670static PyObject *
2671os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks)
2672/*[clinic end generated code: output=a6ed4f151be9df0f input=2e2e7594371f5b7e]*/
2673{
2674    PyObject *return_value = NULL;
2675
2676#ifdef MS_WINDOWS
2677    DWORD attr;
2678#else
2679    int result;
2680#endif
2681
2682#ifndef HAVE_FACCESSAT
2683    if (follow_symlinks_specified("access", follow_symlinks))
2684        goto exit;
2685
2686    if (effective_ids) {
2687        argument_unavailable_error("access", "effective_ids");
2688        goto exit;
2689    }
2690#endif
2691
2692#ifdef MS_WINDOWS
2693    Py_BEGIN_ALLOW_THREADS
2694    if (path->wide != NULL)
2695        attr = GetFileAttributesW(path->wide);
2696    else
2697        attr = GetFileAttributesA(path->narrow);
2698    Py_END_ALLOW_THREADS
2699
2700    /*
2701     * Access is possible if
2702     *   * we didn't get a -1, and
2703     *     * write access wasn't requested,
2704     *     * or the file isn't read-only,
2705     *     * or it's a directory.
2706     * (Directories cannot be read-only on Windows.)
2707    */
2708    return_value = PyBool_FromLong(
2709        (attr != INVALID_FILE_ATTRIBUTES) &&
2710            (!(mode & 2) ||
2711            !(attr & FILE_ATTRIBUTE_READONLY) ||
2712            (attr & FILE_ATTRIBUTE_DIRECTORY)));
2713#else
2714
2715    Py_BEGIN_ALLOW_THREADS
2716#ifdef HAVE_FACCESSAT
2717    if ((dir_fd != DEFAULT_DIR_FD) ||
2718        effective_ids ||
2719        !follow_symlinks) {
2720        int flags = 0;
2721        if (!follow_symlinks)
2722            flags |= AT_SYMLINK_NOFOLLOW;
2723        if (effective_ids)
2724            flags |= AT_EACCESS;
2725        result = faccessat(dir_fd, path->narrow, mode, flags);
2726    }
2727    else
2728#endif
2729        result = access(path->narrow, mode);
2730    Py_END_ALLOW_THREADS
2731    return_value = PyBool_FromLong(!result);
2732#endif
2733
2734#ifndef HAVE_FACCESSAT
2735exit:
2736#endif
2737    return return_value;
2738}
2739
2740#ifndef F_OK
2741#define F_OK 0
2742#endif
2743#ifndef R_OK
2744#define R_OK 4
2745#endif
2746#ifndef W_OK
2747#define W_OK 2
2748#endif
2749#ifndef X_OK
2750#define X_OK 1
2751#endif
2752
2753
2754#ifdef HAVE_TTYNAME
2755
2756/*[clinic input]
2757os.ttyname -> DecodeFSDefault
2758
2759    fd: int
2760        Integer file descriptor handle.
2761
2762    /
2763
2764Return the name of the terminal device connected to 'fd'.
2765[clinic start generated code]*/
2766
2767PyDoc_STRVAR(os_ttyname__doc__,
2768"ttyname($module, fd, /)\n"
2769"--\n"
2770"\n"
2771"Return the name of the terminal device connected to \'fd\'.\n"
2772"\n"
2773"  fd\n"
2774"    Integer file descriptor handle.");
2775
2776#define OS_TTYNAME_METHODDEF    \
2777    {"ttyname", (PyCFunction)os_ttyname, METH_VARARGS, os_ttyname__doc__},
2778
2779static char *
2780os_ttyname_impl(PyModuleDef *module, int fd);
2781
2782static PyObject *
2783os_ttyname(PyModuleDef *module, PyObject *args)
2784{
2785    PyObject *return_value = NULL;
2786    int fd;
2787    char *_return_value;
2788
2789    if (!PyArg_ParseTuple(args,
2790        "i:ttyname",
2791        &fd))
2792        goto exit;
2793    _return_value = os_ttyname_impl(module, fd);
2794    if (_return_value == NULL)
2795        goto exit;
2796    return_value = PyUnicode_DecodeFSDefault(_return_value);
2797
2798exit:
2799    return return_value;
2800}
2801
2802static char *
2803os_ttyname_impl(PyModuleDef *module, int fd)
2804/*[clinic end generated code: output=cee7bc4cffec01a2 input=5f72ca83e76b3b45]*/
2805{
2806    char *ret;
2807
2808    ret = ttyname(fd);
2809    if (ret == NULL)
2810        posix_error();
2811    return ret;
2812}
2813#else
2814#define OS_TTYNAME_METHODDEF
2815#endif
2816
2817#ifdef HAVE_CTERMID
2818PyDoc_STRVAR(posix_ctermid__doc__,
2819"ctermid() -> string\n\n\
2820Return the name of the controlling terminal for this process.");
2821
2822static PyObject *
2823posix_ctermid(PyObject *self, PyObject *noargs)
2824{
2825    char *ret;
2826    char buffer[L_ctermid];
2827
2828#ifdef USE_CTERMID_R
2829    ret = ctermid_r(buffer);
2830#else
2831    ret = ctermid(buffer);
2832#endif
2833    if (ret == NULL)
2834        return posix_error();
2835    return PyUnicode_DecodeFSDefault(buffer);
2836}
2837#endif
2838
2839PyDoc_STRVAR(posix_chdir__doc__,
2840"chdir(path)\n\n\
2841Change the current working directory to the specified path.\n\
2842\n\
2843path may always be specified as a string.\n\
2844On some platforms, path may also be specified as an open file descriptor.\n\
2845  If this functionality is unavailable, using it raises an exception.");
2846
2847static PyObject *
2848posix_chdir(PyObject *self, PyObject *args, PyObject *kwargs)
2849{
2850    path_t path;
2851    int result;
2852    PyObject *return_value = NULL;
2853    static char *keywords[] = {"path", NULL};
2854
2855    memset(&path, 0, sizeof(path));
2856    path.function_name = "chdir";
2857#ifdef HAVE_FCHDIR
2858    path.allow_fd = 1;
2859#endif
2860    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:chdir", keywords,
2861        path_converter, &path
2862        ))
2863        return NULL;
2864
2865    Py_BEGIN_ALLOW_THREADS
2866#ifdef MS_WINDOWS
2867    if (path.wide)
2868        result = win32_wchdir(path.wide);
2869    else
2870        result = win32_chdir(path.narrow);
2871    result = !result; /* on unix, success = 0, on windows, success = !0 */
2872#else
2873#ifdef HAVE_FCHDIR
2874    if (path.fd != -1)
2875        result = fchdir(path.fd);
2876    else
2877#endif
2878        result = chdir(path.narrow);
2879#endif
2880    Py_END_ALLOW_THREADS
2881
2882    if (result) {
2883        return_value = path_error(&path);
2884        goto exit;
2885    }
2886
2887    return_value = Py_None;
2888    Py_INCREF(Py_None);
2889
2890exit:
2891    path_cleanup(&path);
2892    return return_value;
2893}
2894
2895#ifdef HAVE_FCHDIR
2896PyDoc_STRVAR(posix_fchdir__doc__,
2897"fchdir(fd)\n\n\
2898Change to the directory of the given file descriptor.  fd must be\n\
2899opened on a directory, not a file.  Equivalent to os.chdir(fd).");
2900
2901static PyObject *
2902posix_fchdir(PyObject *self, PyObject *fdobj)
2903{
2904    return posix_fildes(fdobj, fchdir);
2905}
2906#endif /* HAVE_FCHDIR */
2907
2908
2909PyDoc_STRVAR(posix_chmod__doc__,
2910"chmod(path, mode, *, dir_fd=None, follow_symlinks=True)\n\n\
2911Change the access permissions of a file.\n\
2912\n\
2913path may always be specified as a string.\n\
2914On some platforms, path may also be specified as an open file descriptor.\n\
2915  If this functionality is unavailable, using it raises an exception.\n\
2916If dir_fd is not None, it should be a file descriptor open to a directory,\n\
2917  and path should be relative; path will then be relative to that directory.\n\
2918If follow_symlinks is False, and the last element of the path is a symbolic\n\
2919  link, chmod will modify the symbolic link itself instead of the file the\n\
2920  link points to.\n\
2921It is an error to use dir_fd or follow_symlinks when specifying path as\n\
2922  an open file descriptor.\n\
2923dir_fd and follow_symlinks may not be implemented on your platform.\n\
2924  If they are unavailable, using them will raise a NotImplementedError.");
2925
2926static PyObject *
2927posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs)
2928{
2929    path_t path;
2930    int mode;
2931    int dir_fd = DEFAULT_DIR_FD;
2932    int follow_symlinks = 1;
2933    int result;
2934    PyObject *return_value = NULL;
2935    static char *keywords[] = {"path", "mode", "dir_fd",
2936                               "follow_symlinks", NULL};
2937
2938#ifdef MS_WINDOWS
2939    DWORD attr;
2940#endif
2941
2942#ifdef HAVE_FCHMODAT
2943    int fchmodat_nofollow_unsupported = 0;
2944#endif
2945
2946    memset(&path, 0, sizeof(path));
2947    path.function_name = "chmod";
2948#ifdef HAVE_FCHMOD
2949    path.allow_fd = 1;
2950#endif
2951    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|$O&p:chmod", keywords,
2952        path_converter, &path,
2953        &mode,
2954#ifdef HAVE_FCHMODAT
2955        dir_fd_converter, &dir_fd,
2956#else
2957        dir_fd_unavailable, &dir_fd,
2958#endif
2959        &follow_symlinks))
2960        return NULL;
2961
2962#if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD))
2963    if (follow_symlinks_specified("chmod", follow_symlinks))
2964        goto exit;
2965#endif
2966
2967#ifdef MS_WINDOWS
2968    Py_BEGIN_ALLOW_THREADS
2969    if (path.wide)
2970        attr = GetFileAttributesW(path.wide);
2971    else
2972        attr = GetFileAttributesA(path.narrow);
2973    if (attr == INVALID_FILE_ATTRIBUTES)
2974        result = 0;
2975    else {
2976        if (mode & _S_IWRITE)
2977            attr &= ~FILE_ATTRIBUTE_READONLY;
2978        else
2979            attr |= FILE_ATTRIBUTE_READONLY;
2980        if (path.wide)
2981            result = SetFileAttributesW(path.wide, attr);
2982        else
2983            result = SetFileAttributesA(path.narrow, attr);
2984    }
2985    Py_END_ALLOW_THREADS
2986
2987    if (!result) {
2988        return_value = path_error(&path);
2989        goto exit;
2990    }
2991#else /* MS_WINDOWS */
2992    Py_BEGIN_ALLOW_THREADS
2993#ifdef HAVE_FCHMOD
2994    if (path.fd != -1)
2995        result = fchmod(path.fd, mode);
2996    else
2997#endif
2998#ifdef HAVE_LCHMOD
2999    if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3000        result = lchmod(path.narrow, mode);
3001    else
3002#endif
3003#ifdef HAVE_FCHMODAT
3004    if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) {
3005        /*
3006         * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW!
3007         * The documentation specifically shows how to use it,
3008         * and then says it isn't implemented yet.
3009         * (true on linux with glibc 2.15, and openindiana 3.x)
3010         *
3011         * Once it is supported, os.chmod will automatically
3012         * support dir_fd and follow_symlinks=False.  (Hopefully.)
3013         * Until then, we need to be careful what exception we raise.
3014         */
3015        result = fchmodat(dir_fd, path.narrow, mode,
3016                          follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3017        /*
3018         * But wait!  We can't throw the exception without allowing threads,
3019         * and we can't do that in this nested scope.  (Macro trickery, sigh.)
3020         */
3021        fchmodat_nofollow_unsupported =
3022                         result &&
3023                         ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) &&
3024                         !follow_symlinks;
3025    }
3026    else
3027#endif
3028        result = chmod(path.narrow, mode);
3029    Py_END_ALLOW_THREADS
3030
3031    if (result) {
3032#ifdef HAVE_FCHMODAT
3033        if (fchmodat_nofollow_unsupported) {
3034            if (dir_fd != DEFAULT_DIR_FD)
3035                dir_fd_and_follow_symlinks_invalid("chmod",
3036                                                   dir_fd, follow_symlinks);
3037            else
3038                follow_symlinks_specified("chmod", follow_symlinks);
3039        }
3040        else
3041#endif
3042            return_value = path_error(&path);
3043        goto exit;
3044    }
3045#endif
3046
3047    Py_INCREF(Py_None);
3048    return_value = Py_None;
3049exit:
3050    path_cleanup(&path);
3051    return return_value;
3052}
3053
3054
3055#ifdef HAVE_FCHMOD
3056PyDoc_STRVAR(posix_fchmod__doc__,
3057"fchmod(fd, mode)\n\n\
3058Change the access permissions of the file given by file\n\
3059descriptor fd.  Equivalent to os.chmod(fd, mode).");
3060
3061static PyObject *
3062posix_fchmod(PyObject *self, PyObject *args)
3063{
3064    int fd, mode, res;
3065    if (!PyArg_ParseTuple(args, "ii:fchmod", &fd, &mode))
3066        return NULL;
3067    Py_BEGIN_ALLOW_THREADS
3068    res = fchmod(fd, mode);
3069    Py_END_ALLOW_THREADS
3070    if (res < 0)
3071        return posix_error();
3072    Py_RETURN_NONE;
3073}
3074#endif /* HAVE_FCHMOD */
3075
3076#ifdef HAVE_LCHMOD
3077PyDoc_STRVAR(posix_lchmod__doc__,
3078"lchmod(path, mode)\n\n\
3079Change the access permissions of a file. If path is a symlink, this\n\
3080affects the link itself rather than the target.\n\
3081Equivalent to chmod(path, mode, follow_symlinks=False).");
3082
3083static PyObject *
3084posix_lchmod(PyObject *self, PyObject *args)
3085{
3086    path_t path;
3087    int i;
3088    int res;
3089    memset(&path, 0, sizeof(path));
3090    path.function_name = "lchmod";
3091    if (!PyArg_ParseTuple(args, "O&i:lchmod",
3092                          path_converter, &path, &i))
3093        return NULL;
3094    Py_BEGIN_ALLOW_THREADS
3095    res = lchmod(path.narrow, i);
3096    Py_END_ALLOW_THREADS
3097    if (res < 0) {
3098        path_error(&path);
3099        path_cleanup(&path);
3100        return NULL;
3101    }
3102    path_cleanup(&path);
3103    Py_RETURN_NONE;
3104}
3105#endif /* HAVE_LCHMOD */
3106
3107
3108#ifdef HAVE_CHFLAGS
3109PyDoc_STRVAR(posix_chflags__doc__,
3110"chflags(path, flags, *, follow_symlinks=True)\n\n\
3111Set file flags.\n\
3112\n\
3113If follow_symlinks is False, and the last element of the path is a symbolic\n\
3114  link, chflags will change flags on the symbolic link itself instead of the\n\
3115  file the link points to.\n\
3116follow_symlinks may not be implemented on your platform.  If it is\n\
3117unavailable, using it will raise a NotImplementedError.");
3118
3119static PyObject *
3120posix_chflags(PyObject *self, PyObject *args, PyObject *kwargs)
3121{
3122    path_t path;
3123    unsigned long flags;
3124    int follow_symlinks = 1;
3125    int result;
3126    PyObject *return_value = NULL;
3127    static char *keywords[] = {"path", "flags", "follow_symlinks", NULL};
3128
3129    memset(&path, 0, sizeof(path));
3130    path.function_name = "chflags";
3131    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&k|$i:chflags", keywords,
3132                          path_converter, &path,
3133                          &flags, &follow_symlinks))
3134        return NULL;
3135
3136#ifndef HAVE_LCHFLAGS
3137    if (follow_symlinks_specified("chflags", follow_symlinks))
3138        goto exit;
3139#endif
3140
3141    Py_BEGIN_ALLOW_THREADS
3142#ifdef HAVE_LCHFLAGS
3143    if (!follow_symlinks)
3144        result = lchflags(path.narrow, flags);
3145    else
3146#endif
3147        result = chflags(path.narrow, flags);
3148    Py_END_ALLOW_THREADS
3149
3150    if (result) {
3151        return_value = path_error(&path);
3152        goto exit;
3153    }
3154
3155    return_value = Py_None;
3156    Py_INCREF(Py_None);
3157
3158exit:
3159    path_cleanup(&path);
3160    return return_value;
3161}
3162#endif /* HAVE_CHFLAGS */
3163
3164#ifdef HAVE_LCHFLAGS
3165PyDoc_STRVAR(posix_lchflags__doc__,
3166"lchflags(path, flags)\n\n\
3167Set file flags.\n\
3168This function will not follow symbolic links.\n\
3169Equivalent to chflags(path, flags, follow_symlinks=False).");
3170
3171static PyObject *
3172posix_lchflags(PyObject *self, PyObject *args)
3173{
3174    path_t path;
3175    unsigned long flags;
3176    int res;
3177    memset(&path, 0, sizeof(path));
3178    path.function_name = "lchflags";
3179    if (!PyArg_ParseTuple(args, "O&k:lchflags",
3180                          path_converter, &path, &flags))
3181        return NULL;
3182    Py_BEGIN_ALLOW_THREADS
3183    res = lchflags(path.narrow, flags);
3184    Py_END_ALLOW_THREADS
3185    if (res < 0) {
3186        path_error(&path);
3187        path_cleanup(&path);
3188        return NULL;
3189    }
3190    path_cleanup(&path);
3191    Py_RETURN_NONE;
3192}
3193#endif /* HAVE_LCHFLAGS */
3194
3195#ifdef HAVE_CHROOT
3196PyDoc_STRVAR(posix_chroot__doc__,
3197"chroot(path)\n\n\
3198Change root directory to path.");
3199
3200static PyObject *
3201posix_chroot(PyObject *self, PyObject *args)
3202{
3203    return posix_1str("chroot", args, "O&:chroot", chroot);
3204}
3205#endif
3206
3207#ifdef HAVE_FSYNC
3208PyDoc_STRVAR(posix_fsync__doc__,
3209"fsync(fildes)\n\n\
3210force write of file with filedescriptor to disk.");
3211
3212static PyObject *
3213posix_fsync(PyObject *self, PyObject *fdobj)
3214{
3215    return posix_fildes(fdobj, fsync);
3216}
3217#endif /* HAVE_FSYNC */
3218
3219#ifdef HAVE_SYNC
3220PyDoc_STRVAR(posix_sync__doc__,
3221"sync()\n\n\
3222Force write of everything to disk.");
3223
3224static PyObject *
3225posix_sync(PyObject *self, PyObject *noargs)
3226{
3227    Py_BEGIN_ALLOW_THREADS
3228    sync();
3229    Py_END_ALLOW_THREADS
3230    Py_RETURN_NONE;
3231}
3232#endif
3233
3234#ifdef HAVE_FDATASYNC
3235
3236#ifdef __hpux
3237extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */
3238#endif
3239
3240PyDoc_STRVAR(posix_fdatasync__doc__,
3241"fdatasync(fildes)\n\n\
3242force write of file with filedescriptor to disk.\n\
3243 does not force update of metadata.");
3244
3245static PyObject *
3246posix_fdatasync(PyObject *self, PyObject *fdobj)
3247{
3248    return posix_fildes(fdobj, fdatasync);
3249}
3250#endif /* HAVE_FDATASYNC */
3251
3252
3253#ifdef HAVE_CHOWN
3254PyDoc_STRVAR(posix_chown__doc__,
3255"chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)\n\n\
3256Change the owner and group id of path to the numeric uid and gid.\n\
3257\n\
3258path may always be specified as a string.\n\
3259On some platforms, path may also be specified as an open file descriptor.\n\
3260  If this functionality is unavailable, using it raises an exception.\n\
3261If dir_fd is not None, it should be a file descriptor open to a directory,\n\
3262  and path should be relative; path will then be relative to that directory.\n\
3263If follow_symlinks is False, and the last element of the path is a symbolic\n\
3264  link, chown will modify the symbolic link itself instead of the file the\n\
3265  link points to.\n\
3266It is an error to use dir_fd or follow_symlinks when specifying path as\n\
3267  an open file descriptor.\n\
3268dir_fd and follow_symlinks may not be implemented on your platform.\n\
3269  If they are unavailable, using them will raise a NotImplementedError.");
3270
3271static PyObject *
3272posix_chown(PyObject *self, PyObject *args, PyObject *kwargs)
3273{
3274    path_t path;
3275    uid_t uid;
3276    gid_t gid;
3277    int dir_fd = DEFAULT_DIR_FD;
3278    int follow_symlinks = 1;
3279    int result;
3280    PyObject *return_value = NULL;
3281    static char *keywords[] = {"path", "uid", "gid", "dir_fd",
3282                               "follow_symlinks", NULL};
3283
3284    memset(&path, 0, sizeof(path));
3285    path.function_name = "chown";
3286#ifdef HAVE_FCHOWN
3287    path.allow_fd = 1;
3288#endif
3289    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&O&|$O&p:chown", keywords,
3290                                     path_converter, &path,
3291                                     _Py_Uid_Converter, &uid,
3292                                     _Py_Gid_Converter, &gid,
3293#ifdef HAVE_FCHOWNAT
3294                                     dir_fd_converter, &dir_fd,
3295#else
3296                                     dir_fd_unavailable, &dir_fd,
3297#endif
3298                                     &follow_symlinks))
3299        return NULL;
3300
3301#if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT))
3302    if (follow_symlinks_specified("chown", follow_symlinks))
3303        goto exit;
3304#endif
3305    if (dir_fd_and_fd_invalid("chown", dir_fd, path.fd) ||
3306        fd_and_follow_symlinks_invalid("chown", path.fd, follow_symlinks))
3307        goto exit;
3308
3309#ifdef __APPLE__
3310    /*
3311     * This is for Mac OS X 10.3, which doesn't have lchown.
3312     * (But we still have an lchown symbol because of weak-linking.)
3313     * It doesn't have fchownat either.  So there's no possibility
3314     * of a graceful failover.
3315     */
3316    if ((!follow_symlinks) && (lchown == NULL)) {
3317        follow_symlinks_specified("chown", follow_symlinks);
3318        goto exit;
3319    }
3320#endif
3321
3322    Py_BEGIN_ALLOW_THREADS
3323#ifdef HAVE_FCHOWN
3324    if (path.fd != -1)
3325        result = fchown(path.fd, uid, gid);
3326    else
3327#endif
3328#ifdef HAVE_LCHOWN
3329    if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3330        result = lchown(path.narrow, uid, gid);
3331    else
3332#endif
3333#ifdef HAVE_FCHOWNAT
3334    if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks))
3335        result = fchownat(dir_fd, path.narrow, uid, gid,
3336                          follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3337    else
3338#endif
3339        result = chown(path.narrow, uid, gid);
3340    Py_END_ALLOW_THREADS
3341
3342    if (result) {
3343        return_value = path_error(&path);
3344        goto exit;
3345    }
3346
3347    return_value = Py_None;
3348    Py_INCREF(Py_None);
3349
3350exit:
3351    path_cleanup(&path);
3352    return return_value;
3353}
3354#endif /* HAVE_CHOWN */
3355
3356#ifdef HAVE_FCHOWN
3357PyDoc_STRVAR(posix_fchown__doc__,
3358"fchown(fd, uid, gid)\n\n\
3359Change the owner and group id of the file given by file descriptor\n\
3360fd to the numeric uid and gid.  Equivalent to os.chown(fd, uid, gid).");
3361
3362static PyObject *
3363posix_fchown(PyObject *self, PyObject *args)
3364{
3365    int fd;
3366    uid_t uid;
3367    gid_t gid;
3368    int res;
3369    if (!PyArg_ParseTuple(args, "iO&O&:fchown", &fd,
3370                          _Py_Uid_Converter, &uid,
3371                          _Py_Gid_Converter, &gid))
3372        return NULL;
3373    Py_BEGIN_ALLOW_THREADS
3374    res = fchown(fd, uid, gid);
3375    Py_END_ALLOW_THREADS
3376    if (res < 0)
3377        return posix_error();
3378    Py_RETURN_NONE;
3379}
3380#endif /* HAVE_FCHOWN */
3381
3382#ifdef HAVE_LCHOWN
3383PyDoc_STRVAR(posix_lchown__doc__,
3384"lchown(path, uid, gid)\n\n\
3385Change the owner and group id of path to the numeric uid and gid.\n\
3386This function will not follow symbolic links.\n\
3387Equivalent to os.chown(path, uid, gid, follow_symlinks=False).");
3388
3389static PyObject *
3390posix_lchown(PyObject *self, PyObject *args)
3391{
3392    path_t path;
3393    uid_t uid;
3394    gid_t gid;
3395    int res;
3396    memset(&path, 0, sizeof(path));
3397    path.function_name = "lchown";
3398    if (!PyArg_ParseTuple(args, "O&O&O&:lchown",
3399                          path_converter, &path,
3400                          _Py_Uid_Converter, &uid,
3401                          _Py_Gid_Converter, &gid))
3402        return NULL;
3403    Py_BEGIN_ALLOW_THREADS
3404    res = lchown(path.narrow, uid, gid);
3405    Py_END_ALLOW_THREADS
3406    if (res < 0) {
3407        path_error(&path);
3408        path_cleanup(&path);
3409        return NULL;
3410    }
3411    path_cleanup(&path);
3412    Py_INCREF(Py_None);
3413    return Py_None;
3414}
3415#endif /* HAVE_LCHOWN */
3416
3417
3418static PyObject *
3419posix_getcwd(int use_bytes)
3420{
3421    char *buf, *tmpbuf;
3422    char *cwd;
3423    const size_t chunk = 1024;
3424    size_t buflen = 0;
3425    PyObject *obj;
3426
3427#ifdef MS_WINDOWS
3428    if (!use_bytes) {
3429        wchar_t wbuf[MAXPATHLEN];
3430        wchar_t *wbuf2 = wbuf;
3431        PyObject *resobj;
3432        DWORD len;
3433        Py_BEGIN_ALLOW_THREADS
3434        len = GetCurrentDirectoryW(Py_ARRAY_LENGTH(wbuf), wbuf);
3435        /* If the buffer is large enough, len does not include the
3436           terminating \0. If the buffer is too small, len includes
3437           the space needed for the terminator. */
3438        if (len >= Py_ARRAY_LENGTH(wbuf)) {
3439            wbuf2 = PyMem_RawMalloc(len * sizeof(wchar_t));
3440            if (wbuf2)
3441                len = GetCurrentDirectoryW(len, wbuf2);
3442        }
3443        Py_END_ALLOW_THREADS
3444        if (!wbuf2) {
3445            PyErr_NoMemory();
3446            return NULL;
3447        }
3448        if (!len) {
3449            if (wbuf2 != wbuf)
3450                PyMem_RawFree(wbuf2);
3451            return PyErr_SetFromWindowsErr(0);
3452        }
3453        resobj = PyUnicode_FromWideChar(wbuf2, len);
3454        if (wbuf2 != wbuf)
3455            PyMem_RawFree(wbuf2);
3456        return resobj;
3457    }
3458
3459    if (win32_warn_bytes_api())
3460        return NULL;
3461#endif
3462
3463    buf = cwd = NULL;
3464    Py_BEGIN_ALLOW_THREADS
3465    do {
3466        buflen += chunk;
3467        tmpbuf = PyMem_RawRealloc(buf, buflen);
3468        if (tmpbuf == NULL)
3469            break;
3470
3471        buf = tmpbuf;
3472        cwd = getcwd(buf, buflen);
3473    } while (cwd == NULL && errno == ERANGE);
3474    Py_END_ALLOW_THREADS
3475
3476    if (cwd == NULL) {
3477        PyMem_RawFree(buf);
3478        return posix_error();
3479    }
3480
3481    if (use_bytes)
3482        obj = PyBytes_FromStringAndSize(buf, strlen(buf));
3483    else
3484        obj = PyUnicode_DecodeFSDefault(buf);
3485    PyMem_RawFree(buf);
3486
3487    return obj;
3488}
3489
3490PyDoc_STRVAR(posix_getcwd__doc__,
3491"getcwd() -> path\n\n\
3492Return a unicode string representing the current working directory.");
3493
3494static PyObject *
3495posix_getcwd_unicode(PyObject *self)
3496{
3497    return posix_getcwd(0);
3498}
3499
3500PyDoc_STRVAR(posix_getcwdb__doc__,
3501"getcwdb() -> path\n\n\
3502Return a bytes string representing the current working directory.");
3503
3504static PyObject *
3505posix_getcwd_bytes(PyObject *self)
3506{
3507    return posix_getcwd(1);
3508}
3509
3510#if ((!defined(HAVE_LINK)) && defined(MS_WINDOWS))
3511#define HAVE_LINK 1
3512#endif
3513
3514#ifdef HAVE_LINK
3515PyDoc_STRVAR(posix_link__doc__,
3516"link(src, dst, *, src_dir_fd=None, dst_dir_fd=None, follow_symlinks=True)\n\n\
3517Create a hard link to a file.\n\
3518\n\
3519If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\
3520  descriptor open to a directory, and the respective path string (src or dst)\n\
3521  should be relative; the path will then be relative to that directory.\n\
3522If follow_symlinks is False, and the last element of src is a symbolic\n\
3523  link, link will create a link to the symbolic link itself instead of the\n\
3524  file the link points to.\n\
3525src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your\n\
3526  platform.  If they are unavailable, using them will raise a\n\
3527  NotImplementedError.");
3528
3529static PyObject *
3530posix_link(PyObject *self, PyObject *args, PyObject *kwargs)
3531{
3532    path_t src, dst;
3533    int src_dir_fd = DEFAULT_DIR_FD;
3534    int dst_dir_fd = DEFAULT_DIR_FD;
3535    int follow_symlinks = 1;
3536    PyObject *return_value = NULL;
3537    static char *keywords[] = {"src", "dst", "src_dir_fd", "dst_dir_fd",
3538                               "follow_symlinks", NULL};
3539#ifdef MS_WINDOWS
3540    BOOL result;
3541#else
3542    int result;
3543#endif
3544
3545    memset(&src, 0, sizeof(src));
3546    memset(&dst, 0, sizeof(dst));
3547    src.function_name = "link";
3548    dst.function_name = "link";
3549    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|O&O&p:link", keywords,
3550            path_converter, &src,
3551            path_converter, &dst,
3552            dir_fd_converter, &src_dir_fd,
3553            dir_fd_converter, &dst_dir_fd,
3554            &follow_symlinks))
3555        return NULL;
3556
3557#ifndef HAVE_LINKAT
3558    if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) {
3559        argument_unavailable_error("link", "src_dir_fd and dst_dir_fd");
3560        goto exit;
3561    }
3562#endif
3563
3564    if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) {
3565        PyErr_SetString(PyExc_NotImplementedError,
3566                        "link: src and dst must be the same type");
3567        goto exit;
3568    }
3569
3570#ifdef MS_WINDOWS
3571    Py_BEGIN_ALLOW_THREADS
3572    if (src.wide)
3573        result = CreateHardLinkW(dst.wide, src.wide, NULL);
3574    else
3575        result = CreateHardLinkA(dst.narrow, src.narrow, NULL);
3576    Py_END_ALLOW_THREADS
3577
3578    if (!result) {
3579        return_value = path_error2(&src, &dst);
3580        goto exit;
3581    }
3582#else
3583    Py_BEGIN_ALLOW_THREADS
3584#ifdef HAVE_LINKAT
3585    if ((src_dir_fd != DEFAULT_DIR_FD) ||
3586        (dst_dir_fd != DEFAULT_DIR_FD) ||
3587        (!follow_symlinks))
3588        result = linkat(src_dir_fd, src.narrow,
3589            dst_dir_fd, dst.narrow,
3590            follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
3591    else
3592#endif
3593        result = link(src.narrow, dst.narrow);
3594    Py_END_ALLOW_THREADS
3595
3596    if (result) {
3597        return_value = path_error2(&src, &dst);
3598        goto exit;
3599    }
3600#endif
3601
3602    return_value = Py_None;
3603    Py_INCREF(Py_None);
3604
3605exit:
3606    path_cleanup(&src);
3607    path_cleanup(&dst);
3608    return return_value;
3609}
3610#endif
3611
3612
3613
3614PyDoc_STRVAR(posix_listdir__doc__,
3615"listdir(path='.') -> list_of_filenames\n\n\
3616Return a list containing the names of the files in the directory.\n\
3617The list is in arbitrary order.  It does not include the special\n\
3618entries '.' and '..' even if they are present in the directory.\n\
3619\n\
3620path can be specified as either str or bytes.  If path is bytes,\n\
3621  the filenames returned will also be bytes; in all other circumstances\n\
3622  the filenames returned will be str.\n\
3623On some platforms, path may also be specified as an open file descriptor;\n\
3624  the file descriptor must refer to a directory.\n\
3625  If this functionality is unavailable, using it raises NotImplementedError.");
3626
3627#if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
3628static PyObject *
3629_listdir_windows_no_opendir(path_t *path, PyObject *list)
3630{
3631    static char *keywords[] = {"path", NULL};
3632    PyObject *v;
3633    HANDLE hFindFile = INVALID_HANDLE_VALUE;
3634    BOOL result;
3635    WIN32_FIND_DATA FileData;
3636    char namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */
3637    char *bufptr = namebuf;
3638    /* only claim to have space for MAX_PATH */
3639    Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4;
3640    PyObject *po = NULL;
3641    wchar_t *wnamebuf = NULL;
3642
3643    if (!path->narrow) {
3644        WIN32_FIND_DATAW wFileData;
3645        wchar_t *po_wchars;
3646
3647        if (!path->wide) { /* Default arg: "." */
3648            po_wchars = L".";
3649            len = 1;
3650        } else {
3651            po_wchars = path->wide;
3652            len = wcslen(path->wide);
3653        }
3654        /* The +5 is so we can append "\\*.*\0" */
3655        wnamebuf = PyMem_New(wchar_t, len + 5);
3656        if (!wnamebuf) {
3657            PyErr_NoMemory();
3658            goto exit;
3659        }
3660        wcscpy(wnamebuf, po_wchars);
3661        if (len > 0) {
3662            wchar_t wch = wnamebuf[len-1];
3663            if (wch != SEP && wch != ALTSEP && wch != L':')
3664                wnamebuf[len++] = SEP;
3665            wcscpy(wnamebuf + len, L"*.*");
3666        }
3667        if ((list = PyList_New(0)) == NULL) {
3668            goto exit;
3669        }
3670        Py_BEGIN_ALLOW_THREADS
3671        hFindFile = FindFirstFileW(wnamebuf, &wFileData);
3672        Py_END_ALLOW_THREADS
3673        if (hFindFile == INVALID_HANDLE_VALUE) {
3674            int error = GetLastError();
3675            if (error == ERROR_FILE_NOT_FOUND)
3676                goto exit;
3677            Py_DECREF(list);
3678            list = path_error(path);
3679            goto exit;
3680        }
3681        do {
3682            /* Skip over . and .. */
3683            if (wcscmp(wFileData.cFileName, L".") != 0 &&
3684                wcscmp(wFileData.cFileName, L"..") != 0) {
3685                v = PyUnicode_FromWideChar(wFileData.cFileName,
3686                                           wcslen(wFileData.cFileName));
3687                if (v == NULL) {
3688                    Py_DECREF(list);
3689                    list = NULL;
3690                    break;
3691                }
3692                if (PyList_Append(list, v) != 0) {
3693                    Py_DECREF(v);
3694                    Py_DECREF(list);
3695                    list = NULL;
3696                    break;
3697                }
3698                Py_DECREF(v);
3699            }
3700            Py_BEGIN_ALLOW_THREADS
3701            result = FindNextFileW(hFindFile, &wFileData);
3702            Py_END_ALLOW_THREADS
3703            /* FindNextFile sets error to ERROR_NO_MORE_FILES if
3704               it got to the end of the directory. */
3705            if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
3706                Py_DECREF(list);
3707                list = path_error(path);
3708                goto exit;
3709            }
3710        } while (result == TRUE);
3711
3712        goto exit;
3713    }
3714    strcpy(namebuf, path->narrow);
3715    len = path->length;
3716    if (len > 0) {
3717        char ch = namebuf[len-1];
3718        if (ch != '\\' && ch != '/' && ch != ':')
3719            namebuf[len++] = '\\';
3720        strcpy(namebuf + len, "*.*");
3721    }
3722
3723    if ((list = PyList_New(0)) == NULL)
3724        return NULL;
3725
3726    Py_BEGIN_ALLOW_THREADS
3727    hFindFile = FindFirstFile(namebuf, &FileData);
3728    Py_END_ALLOW_THREADS
3729    if (hFindFile == INVALID_HANDLE_VALUE) {
3730        int error = GetLastError();
3731        if (error == ERROR_FILE_NOT_FOUND)
3732            goto exit;
3733        Py_DECREF(list);
3734        list = path_error(path);
3735        goto exit;
3736    }
3737    do {
3738        /* Skip over . and .. */
3739        if (strcmp(FileData.cFileName, ".") != 0 &&
3740            strcmp(FileData.cFileName, "..") != 0) {
3741            v = PyBytes_FromString(FileData.cFileName);
3742            if (v == NULL) {
3743                Py_DECREF(list);
3744                list = NULL;
3745                break;
3746            }
3747            if (PyList_Append(list, v) != 0) {
3748                Py_DECREF(v);
3749                Py_DECREF(list);
3750                list = NULL;
3751                break;
3752            }
3753            Py_DECREF(v);
3754        }
3755        Py_BEGIN_ALLOW_THREADS
3756        result = FindNextFile(hFindFile, &FileData);
3757        Py_END_ALLOW_THREADS
3758        /* FindNextFile sets error to ERROR_NO_MORE_FILES if
3759           it got to the end of the directory. */
3760        if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
3761            Py_DECREF(list);
3762            list = path_error(path);
3763            goto exit;
3764        }
3765    } while (result == TRUE);
3766
3767exit:
3768    if (hFindFile != INVALID_HANDLE_VALUE) {
3769        if (FindClose(hFindFile) == FALSE) {
3770            if (list != NULL) {
3771                Py_DECREF(list);
3772                list = path_error(path);
3773            }
3774        }
3775    }
3776    PyMem_Free(wnamebuf);
3777
3778    return list;
3779}  /* end of _listdir_windows_no_opendir */
3780
3781#else  /* thus POSIX, ie: not (MS_WINDOWS and not HAVE_OPENDIR) */
3782
3783static PyObject *
3784_posix_listdir(path_t *path, PyObject *list)
3785{
3786    PyObject *v;
3787    DIR *dirp = NULL;
3788    struct dirent *ep;
3789    int return_str; /* if false, return bytes */
3790#ifdef HAVE_FDOPENDIR
3791    int fd = -1;
3792#endif
3793
3794    errno = 0;
3795#ifdef HAVE_FDOPENDIR
3796    if (path->fd != -1) {
3797        /* closedir() closes the FD, so we duplicate it */
3798        fd = _Py_dup(path->fd);
3799        if (fd == -1)
3800            return NULL;
3801
3802        return_str = 1;
3803
3804        Py_BEGIN_ALLOW_THREADS
3805        dirp = fdopendir(fd);
3806        Py_END_ALLOW_THREADS
3807    }
3808    else
3809#endif
3810    {
3811        char *name;
3812        if (path->narrow) {
3813            name = path->narrow;
3814            /* only return bytes if they specified a bytes object */
3815            return_str = !(PyBytes_Check(path->object));
3816        }
3817        else {
3818            name = ".";
3819            return_str = 1;
3820        }
3821
3822        Py_BEGIN_ALLOW_THREADS
3823        dirp = opendir(name);
3824        Py_END_ALLOW_THREADS
3825    }
3826
3827    if (dirp == NULL) {
3828        list = path_error(path);
3829#ifdef HAVE_FDOPENDIR
3830        if (fd != -1) {
3831            Py_BEGIN_ALLOW_THREADS
3832            close(fd);
3833            Py_END_ALLOW_THREADS
3834        }
3835#endif
3836        goto exit;
3837    }
3838    if ((list = PyList_New(0)) == NULL) {
3839        goto exit;
3840    }
3841    for (;;) {
3842        errno = 0;
3843        Py_BEGIN_ALLOW_THREADS
3844        ep = readdir(dirp);
3845        Py_END_ALLOW_THREADS
3846        if (ep == NULL) {
3847            if (errno == 0) {
3848                break;
3849            } else {
3850                Py_DECREF(list);
3851                list = path_error(path);
3852                goto exit;
3853            }
3854        }
3855        if (ep->d_name[0] == '.' &&
3856            (NAMLEN(ep) == 1 ||
3857             (ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
3858            continue;
3859        if (return_str)
3860            v = PyUnicode_DecodeFSDefaultAndSize(ep->d_name, NAMLEN(ep));
3861        else
3862            v = PyBytes_FromStringAndSize(ep->d_name, NAMLEN(ep));
3863        if (v == NULL) {
3864            Py_CLEAR(list);
3865            break;
3866        }
3867        if (PyList_Append(list, v) != 0) {
3868            Py_DECREF(v);
3869            Py_CLEAR(list);
3870            break;
3871        }
3872        Py_DECREF(v);
3873    }
3874
3875exit:
3876    if (dirp != NULL) {
3877        Py_BEGIN_ALLOW_THREADS
3878#ifdef HAVE_FDOPENDIR
3879        if (fd > -1)
3880            rewinddir(dirp);
3881#endif
3882        closedir(dirp);
3883        Py_END_ALLOW_THREADS
3884    }
3885
3886    return list;
3887}  /* end of _posix_listdir */
3888#endif  /* which OS */
3889
3890static PyObject *
3891posix_listdir(PyObject *self, PyObject *args, PyObject *kwargs)
3892{
3893    path_t path;
3894    PyObject *list = NULL;
3895    static char *keywords[] = {"path", NULL};
3896    PyObject *return_value;
3897
3898    memset(&path, 0, sizeof(path));
3899    path.function_name = "listdir";
3900    path.nullable = 1;
3901#ifdef HAVE_FDOPENDIR
3902    path.allow_fd = 1;
3903    path.fd = -1;
3904#endif
3905
3906    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:listdir", keywords,
3907                                     path_converter, &path)) {
3908        return NULL;
3909    }
3910
3911#if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
3912    return_value = _listdir_windows_no_opendir(&path, list);
3913#else
3914    return_value = _posix_listdir(&path, list);
3915#endif
3916    path_cleanup(&path);
3917    return return_value;
3918}
3919
3920#ifdef MS_WINDOWS
3921/* A helper function for abspath on win32 */
3922static PyObject *
3923posix__getfullpathname(PyObject *self, PyObject *args)
3924{
3925    const char *path;
3926    char outbuf[MAX_PATH];
3927    char *temp;
3928    PyObject *po;
3929
3930    if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po))
3931    {
3932        wchar_t *wpath;
3933        wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf;
3934        wchar_t *wtemp;
3935        DWORD result;
3936        PyObject *v;
3937
3938        wpath = PyUnicode_AsUnicode(po);
3939        if (wpath == NULL)
3940            return NULL;
3941        result = GetFullPathNameW(wpath,
3942                                  Py_ARRAY_LENGTH(woutbuf),
3943                                  woutbuf, &wtemp);
3944        if (result > Py_ARRAY_LENGTH(woutbuf)) {
3945            woutbufp = PyMem_New(wchar_t, result);
3946            if (!woutbufp)
3947                return PyErr_NoMemory();
3948            result = GetFullPathNameW(wpath, result, woutbufp, &wtemp);
3949        }
3950        if (result)
3951            v = PyUnicode_FromWideChar(woutbufp, wcslen(woutbufp));
3952        else
3953            v = win32_error_object("GetFullPathNameW", po);
3954        if (woutbufp != woutbuf)
3955            PyMem_Free(woutbufp);
3956        return v;
3957    }
3958    /* Drop the argument parsing error as narrow strings
3959       are also valid. */
3960    PyErr_Clear();
3961
3962    if (!PyArg_ParseTuple (args, "y:_getfullpathname",
3963                           &path))
3964        return NULL;
3965    if (win32_warn_bytes_api())
3966        return NULL;
3967    if (!GetFullPathName(path, Py_ARRAY_LENGTH(outbuf),
3968                         outbuf, &temp)) {
3969        win32_error("GetFullPathName", path);
3970        return NULL;
3971    }
3972    if (PyUnicode_Check(PyTuple_GetItem(args, 0))) {
3973        return PyUnicode_Decode(outbuf, strlen(outbuf),
3974                                Py_FileSystemDefaultEncoding, NULL);
3975    }
3976    return PyBytes_FromString(outbuf);
3977} /* end of posix__getfullpathname */
3978
3979
3980
3981/* A helper function for samepath on windows */
3982static PyObject *
3983posix__getfinalpathname(PyObject *self, PyObject *args)
3984{
3985    HANDLE hFile;
3986    int buf_size;
3987    wchar_t *target_path;
3988    int result_length;
3989    PyObject *po, *result;
3990    wchar_t *path;
3991
3992    if (!PyArg_ParseTuple(args, "U|:_getfinalpathname", &po))
3993        return NULL;
3994    path = PyUnicode_AsUnicode(po);
3995    if (path == NULL)
3996        return NULL;
3997
3998    if(!check_GetFinalPathNameByHandle()) {
3999        /* If the OS doesn't have GetFinalPathNameByHandle, return a
4000           NotImplementedError. */
4001        return PyErr_Format(PyExc_NotImplementedError,
4002            "GetFinalPathNameByHandle not available on this platform");
4003    }
4004
4005    hFile = CreateFileW(
4006        path,
4007        0, /* desired access */
4008        0, /* share mode */
4009        NULL, /* security attributes */
4010        OPEN_EXISTING,
4011        /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
4012        FILE_FLAG_BACKUP_SEMANTICS,
4013        NULL);
4014
4015    if(hFile == INVALID_HANDLE_VALUE)
4016        return win32_error_object("CreateFileW", po);
4017
4018    /* We have a good handle to the target, use it to determine the
4019       target path name. */
4020    buf_size = Py_GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_NT);
4021
4022    if(!buf_size)
4023        return win32_error_object("GetFinalPathNameByHandle", po);
4024
4025    target_path = PyMem_New(wchar_t, buf_size+1);
4026    if(!target_path)
4027        return PyErr_NoMemory();
4028
4029    result_length = Py_GetFinalPathNameByHandleW(hFile, target_path,
4030                                                 buf_size, VOLUME_NAME_DOS);
4031    if(!result_length)
4032        return win32_error_object("GetFinalPathNamyByHandle", po);
4033
4034    if(!CloseHandle(hFile))
4035        return win32_error_object("CloseHandle", po);
4036
4037    target_path[result_length] = 0;
4038    result = PyUnicode_FromWideChar(target_path, result_length);
4039    PyMem_Free(target_path);
4040    return result;
4041
4042} /* end of posix__getfinalpathname */
4043
4044PyDoc_STRVAR(posix__isdir__doc__,
4045"Return true if the pathname refers to an existing directory.");
4046
4047static PyObject *
4048posix__isdir(PyObject *self, PyObject *args)
4049{
4050    const char *path;
4051    PyObject *po;
4052    DWORD attributes;
4053
4054    if (PyArg_ParseTuple(args, "U|:_isdir", &po)) {
4055        wchar_t *wpath = PyUnicode_AsUnicode(po);
4056        if (wpath == NULL)
4057            return NULL;
4058
4059        attributes = GetFileAttributesW(wpath);
4060        if (attributes == INVALID_FILE_ATTRIBUTES)
4061            Py_RETURN_FALSE;
4062        goto check;
4063    }
4064    /* Drop the argument parsing error as narrow strings
4065       are also valid. */
4066    PyErr_Clear();
4067
4068    if (!PyArg_ParseTuple(args, "y:_isdir", &path))
4069        return NULL;
4070    if (win32_warn_bytes_api())
4071        return NULL;
4072    attributes = GetFileAttributesA(path);
4073    if (attributes == INVALID_FILE_ATTRIBUTES)
4074        Py_RETURN_FALSE;
4075
4076check:
4077    if (attributes & FILE_ATTRIBUTE_DIRECTORY)
4078        Py_RETURN_TRUE;
4079    else
4080        Py_RETURN_FALSE;
4081}
4082
4083PyDoc_STRVAR(posix__getvolumepathname__doc__,
4084"Return volume mount point of the specified path.");
4085
4086/* A helper function for ismount on windows */
4087static PyObject *
4088posix__getvolumepathname(PyObject *self, PyObject *args)
4089{
4090    PyObject *po, *result;
4091    wchar_t *path, *mountpath=NULL;
4092    size_t buflen;
4093    BOOL ret;
4094
4095    if (!PyArg_ParseTuple(args, "U|:_getvolumepathname", &po))
4096        return NULL;
4097    path = PyUnicode_AsUnicodeAndSize(po, &buflen);
4098    if (path == NULL)
4099        return NULL;
4100    buflen += 1;
4101
4102    /* Volume path should be shorter than entire path */
4103    buflen = Py_MAX(buflen, MAX_PATH);
4104
4105    if (buflen > DWORD_MAX) {
4106        PyErr_SetString(PyExc_OverflowError, "path too long");
4107        return NULL;
4108    }
4109
4110    mountpath = PyMem_New(wchar_t, buflen);
4111    if (mountpath == NULL)
4112        return PyErr_NoMemory();
4113
4114    Py_BEGIN_ALLOW_THREADS
4115    ret = GetVolumePathNameW(path, mountpath,
4116                             Py_SAFE_DOWNCAST(buflen, size_t, DWORD));
4117    Py_END_ALLOW_THREADS
4118
4119    if (!ret) {
4120        result = win32_error_object("_getvolumepathname", po);
4121        goto exit;
4122    }
4123    result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath));
4124
4125exit:
4126    PyMem_Free(mountpath);
4127    return result;
4128}
4129/* end of posix__getvolumepathname */
4130
4131#endif /* MS_WINDOWS */
4132
4133PyDoc_STRVAR(posix_mkdir__doc__,
4134"mkdir(path, mode=0o777, *, dir_fd=None)\n\n\
4135Create a directory.\n\
4136\n\
4137If dir_fd is not None, it should be a file descriptor open to a directory,\n\
4138  and path should be relative; path will then be relative to that directory.\n\
4139dir_fd may not be implemented on your platform.\n\
4140  If it is unavailable, using it will raise a NotImplementedError.\n\
4141\n\
4142The mode argument is ignored on Windows.");
4143
4144static PyObject *
4145posix_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
4146{
4147    path_t path;
4148    int mode = 0777;
4149    int dir_fd = DEFAULT_DIR_FD;
4150    static char *keywords[] = {"path", "mode", "dir_fd", NULL};
4151    PyObject *return_value = NULL;
4152    int result;
4153
4154    memset(&path, 0, sizeof(path));
4155    path.function_name = "mkdir";
4156    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i$O&:mkdir", keywords,
4157        path_converter, &path, &mode,
4158#ifdef HAVE_MKDIRAT
4159        dir_fd_converter, &dir_fd
4160#else
4161        dir_fd_unavailable, &dir_fd
4162#endif
4163        ))
4164        return NULL;
4165
4166#ifdef MS_WINDOWS
4167    Py_BEGIN_ALLOW_THREADS
4168    if (path.wide)
4169        result = CreateDirectoryW(path.wide, NULL);
4170    else
4171        result = CreateDirectoryA(path.narrow, NULL);
4172    Py_END_ALLOW_THREADS
4173
4174    if (!result) {
4175        return_value = path_error(&path);
4176        goto exit;
4177    }
4178#else
4179    Py_BEGIN_ALLOW_THREADS
4180#if HAVE_MKDIRAT
4181    if (dir_fd != DEFAULT_DIR_FD)
4182        result = mkdirat(dir_fd, path.narrow, mode);
4183    else
4184#endif
4185#if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__)
4186        result = mkdir(path.narrow);
4187#else
4188        result = mkdir(path.narrow, mode);
4189#endif
4190    Py_END_ALLOW_THREADS
4191    if (result < 0) {
4192        return_value = path_error(&path);
4193        goto exit;
4194    }
4195#endif
4196    return_value = Py_None;
4197    Py_INCREF(Py_None);
4198exit:
4199    path_cleanup(&path);
4200    return return_value;
4201}
4202
4203
4204/* sys/resource.h is needed for at least: wait3(), wait4(), broken nice. */
4205#if defined(HAVE_SYS_RESOURCE_H)
4206#include <sys/resource.h>
4207#endif
4208
4209
4210#ifdef HAVE_NICE
4211PyDoc_STRVAR(posix_nice__doc__,
4212"nice(inc) -> new_priority\n\n\
4213Decrease the priority of process by inc and return the new priority.");
4214
4215static PyObject *
4216posix_nice(PyObject *self, PyObject *args)
4217{
4218    int increment, value;
4219
4220    if (!PyArg_ParseTuple(args, "i:nice", &increment))
4221        return NULL;
4222
4223    /* There are two flavours of 'nice': one that returns the new
4224       priority (as required by almost all standards out there) and the
4225       Linux/FreeBSD/BSDI one, which returns '0' on success and advices
4226       the use of getpriority() to get the new priority.
4227
4228       If we are of the nice family that returns the new priority, we
4229       need to clear errno before the call, and check if errno is filled
4230       before calling posix_error() on a returnvalue of -1, because the
4231       -1 may be the actual new priority! */
4232
4233    errno = 0;
4234    value = nice(increment);
4235#if defined(HAVE_BROKEN_NICE) && defined(HAVE_GETPRIORITY)
4236    if (value == 0)
4237        value = getpriority(PRIO_PROCESS, 0);
4238#endif
4239    if (value == -1 && errno != 0)
4240        /* either nice() or getpriority() returned an error */
4241        return posix_error();
4242    return PyLong_FromLong((long) value);
4243}
4244#endif /* HAVE_NICE */
4245
4246
4247#ifdef HAVE_GETPRIORITY
4248PyDoc_STRVAR(posix_getpriority__doc__,
4249"getpriority(which, who) -> current_priority\n\n\
4250Get program scheduling priority.");
4251
4252static PyObject *
4253posix_getpriority(PyObject *self, PyObject *args)
4254{
4255    int which, who, retval;
4256
4257    if (!PyArg_ParseTuple(args, "ii", &which, &who))
4258        return NULL;
4259    errno = 0;
4260    retval = getpriority(which, who);
4261    if (errno != 0)
4262        return posix_error();
4263    return PyLong_FromLong((long)retval);
4264}
4265#endif /* HAVE_GETPRIORITY */
4266
4267
4268#ifdef HAVE_SETPRIORITY
4269PyDoc_STRVAR(posix_setpriority__doc__,
4270"setpriority(which, who, prio) -> None\n\n\
4271Set program scheduling priority.");
4272
4273static PyObject *
4274posix_setpriority(PyObject *self, PyObject *args)
4275{
4276    int which, who, prio, retval;
4277
4278    if (!PyArg_ParseTuple(args, "iii", &which, &who, &prio))
4279        return NULL;
4280    retval = setpriority(which, who, prio);
4281    if (retval == -1)
4282        return posix_error();
4283    Py_RETURN_NONE;
4284}
4285#endif /* HAVE_SETPRIORITY */
4286
4287
4288static PyObject *
4289internal_rename(PyObject *args, PyObject *kwargs, int is_replace)
4290{
4291    char *function_name = is_replace ? "replace" : "rename";
4292    path_t src;
4293    path_t dst;
4294    int src_dir_fd = DEFAULT_DIR_FD;
4295    int dst_dir_fd = DEFAULT_DIR_FD;
4296    int dir_fd_specified;
4297    PyObject *return_value = NULL;
4298    char format[24];
4299    static char *keywords[] = {"src", "dst", "src_dir_fd", "dst_dir_fd", NULL};
4300
4301#ifdef MS_WINDOWS
4302    BOOL result;
4303    int flags = is_replace ? MOVEFILE_REPLACE_EXISTING : 0;
4304#else
4305    int result;
4306#endif
4307
4308    memset(&src, 0, sizeof(src));
4309    memset(&dst, 0, sizeof(dst));
4310    src.function_name = function_name;
4311    dst.function_name = function_name;
4312    strcpy(format, "O&O&|$O&O&:");
4313    strcat(format, function_name);
4314    if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, keywords,
4315        path_converter, &src,
4316        path_converter, &dst,
4317        dir_fd_converter, &src_dir_fd,
4318        dir_fd_converter, &dst_dir_fd))
4319        return NULL;
4320
4321    dir_fd_specified = (src_dir_fd != DEFAULT_DIR_FD) ||
4322                       (dst_dir_fd != DEFAULT_DIR_FD);
4323#ifndef HAVE_RENAMEAT
4324    if (dir_fd_specified) {
4325        argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd");
4326        goto exit;
4327    }
4328#endif
4329
4330    if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) {
4331        PyErr_Format(PyExc_ValueError,
4332                     "%s: src and dst must be the same type", function_name);
4333        goto exit;
4334    }
4335
4336#ifdef MS_WINDOWS
4337    Py_BEGIN_ALLOW_THREADS
4338    if (src.wide)
4339        result = MoveFileExW(src.wide, dst.wide, flags);
4340    else
4341        result = MoveFileExA(src.narrow, dst.narrow, flags);
4342    Py_END_ALLOW_THREADS
4343
4344    if (!result) {
4345        return_value = path_error2(&src, &dst);
4346        goto exit;
4347    }
4348
4349#else
4350    Py_BEGIN_ALLOW_THREADS
4351#ifdef HAVE_RENAMEAT
4352    if (dir_fd_specified)
4353        result = renameat(src_dir_fd, src.narrow, dst_dir_fd, dst.narrow);
4354    else
4355#endif
4356        result = rename(src.narrow, dst.narrow);
4357    Py_END_ALLOW_THREADS
4358
4359    if (result) {
4360        return_value = path_error2(&src, &dst);
4361        goto exit;
4362    }
4363#endif
4364
4365    Py_INCREF(Py_None);
4366    return_value = Py_None;
4367exit:
4368    path_cleanup(&src);
4369    path_cleanup(&dst);
4370    return return_value;
4371}
4372
4373PyDoc_STRVAR(posix_rename__doc__,
4374"rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)\n\n\
4375Rename a file or directory.\n\
4376\n\
4377If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\
4378  descriptor open to a directory, and the respective path string (src or dst)\n\
4379  should be relative; the path will then be relative to that directory.\n\
4380src_dir_fd and dst_dir_fd, may not be implemented on your platform.\n\
4381  If they are unavailable, using them will raise a NotImplementedError.");
4382
4383static PyObject *
4384posix_rename(PyObject *self, PyObject *args, PyObject *kwargs)
4385{
4386    return internal_rename(args, kwargs, 0);
4387}
4388
4389PyDoc_STRVAR(posix_replace__doc__,
4390"replace(src, dst, *, src_dir_fd=None, dst_dir_fd=None)\n\n\
4391Rename a file or directory, overwriting the destination.\n\
4392\n\
4393If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\
4394  descriptor open to a directory, and the respective path string (src or dst)\n\
4395  should be relative; the path will then be relative to that directory.\n\
4396src_dir_fd and dst_dir_fd, may not be implemented on your platform.\n\
4397  If they are unavailable, using them will raise a NotImplementedError.");
4398
4399static PyObject *
4400posix_replace(PyObject *self, PyObject *args, PyObject *kwargs)
4401{
4402    return internal_rename(args, kwargs, 1);
4403}
4404
4405PyDoc_STRVAR(posix_rmdir__doc__,
4406"rmdir(path, *, dir_fd=None)\n\n\
4407Remove a directory.\n\
4408\n\
4409If dir_fd is not None, it should be a file descriptor open to a directory,\n\
4410  and path should be relative; path will then be relative to that directory.\n\
4411dir_fd may not be implemented on your platform.\n\
4412  If it is unavailable, using it will raise a NotImplementedError.");
4413
4414static PyObject *
4415posix_rmdir(PyObject *self, PyObject *args, PyObject *kwargs)
4416{
4417    path_t path;
4418    int dir_fd = DEFAULT_DIR_FD;
4419    static char *keywords[] = {"path", "dir_fd", NULL};
4420    int result;
4421    PyObject *return_value = NULL;
4422
4423    memset(&path, 0, sizeof(path));
4424    path.function_name = "rmdir";
4425    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:rmdir", keywords,
4426            path_converter, &path,
4427#ifdef HAVE_UNLINKAT
4428            dir_fd_converter, &dir_fd
4429#else
4430            dir_fd_unavailable, &dir_fd
4431#endif
4432            ))
4433        return NULL;
4434
4435    Py_BEGIN_ALLOW_THREADS
4436#ifdef MS_WINDOWS
4437    if (path.wide)
4438        result = RemoveDirectoryW(path.wide);
4439    else
4440        result = RemoveDirectoryA(path.narrow);
4441    result = !result; /* Windows, success=1, UNIX, success=0 */
4442#else
4443#ifdef HAVE_UNLINKAT
4444    if (dir_fd != DEFAULT_DIR_FD)
4445        result = unlinkat(dir_fd, path.narrow, AT_REMOVEDIR);
4446    else
4447#endif
4448        result = rmdir(path.narrow);
4449#endif
4450    Py_END_ALLOW_THREADS
4451
4452    if (result) {
4453        return_value = path_error(&path);
4454        goto exit;
4455    }
4456
4457    return_value = Py_None;
4458    Py_INCREF(Py_None);
4459
4460exit:
4461    path_cleanup(&path);
4462    return return_value;
4463}
4464
4465
4466#ifdef HAVE_SYSTEM
4467PyDoc_STRVAR(posix_system__doc__,
4468"system(command) -> exit_status\n\n\
4469Execute the command (a string) in a subshell.");
4470
4471static PyObject *
4472posix_system(PyObject *self, PyObject *args)
4473{
4474    long sts;
4475#ifdef MS_WINDOWS
4476    wchar_t *command;
4477    if (!PyArg_ParseTuple(args, "u:system", &command))
4478        return NULL;
4479
4480    Py_BEGIN_ALLOW_THREADS
4481    sts = _wsystem(command);
4482    Py_END_ALLOW_THREADS
4483#else
4484    PyObject *command_obj;
4485    char *command;
4486    if (!PyArg_ParseTuple(args, "O&:system",
4487                          PyUnicode_FSConverter, &command_obj))
4488        return NULL;
4489
4490    command = PyBytes_AsString(command_obj);
4491    Py_BEGIN_ALLOW_THREADS
4492    sts = system(command);
4493    Py_END_ALLOW_THREADS
4494    Py_DECREF(command_obj);
4495#endif
4496    return PyLong_FromLong(sts);
4497}
4498#endif
4499
4500
4501PyDoc_STRVAR(posix_umask__doc__,
4502"umask(new_mask) -> old_mask\n\n\
4503Set the current numeric umask and return the previous umask.");
4504
4505static PyObject *
4506posix_umask(PyObject *self, PyObject *args)
4507{
4508    int i;
4509    if (!PyArg_ParseTuple(args, "i:umask", &i))
4510        return NULL;
4511    i = (int)umask(i);
4512    if (i < 0)
4513        return posix_error();
4514    return PyLong_FromLong((long)i);
4515}
4516
4517#ifdef MS_WINDOWS
4518
4519/* override the default DeleteFileW behavior so that directory
4520symlinks can be removed with this function, the same as with
4521Unix symlinks */
4522BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName)
4523{
4524    WIN32_FILE_ATTRIBUTE_DATA info;
4525    WIN32_FIND_DATAW find_data;
4526    HANDLE find_data_handle;
4527    int is_directory = 0;
4528    int is_link = 0;
4529
4530    if (GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &info)) {
4531        is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
4532
4533        /* Get WIN32_FIND_DATA structure for the path to determine if
4534           it is a symlink */
4535        if(is_directory &&
4536           info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
4537            find_data_handle = FindFirstFileW(lpFileName, &find_data);
4538
4539            if(find_data_handle != INVALID_HANDLE_VALUE) {
4540                is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK;
4541                FindClose(find_data_handle);
4542            }
4543        }
4544    }
4545
4546    if (is_directory && is_link)
4547        return RemoveDirectoryW(lpFileName);
4548
4549    return DeleteFileW(lpFileName);
4550}
4551#endif /* MS_WINDOWS */
4552
4553PyDoc_STRVAR(posix_unlink__doc__,
4554"unlink(path, *, dir_fd=None)\n\n\
4555Remove a file (same as remove()).\n\
4556\n\
4557If dir_fd is not None, it should be a file descriptor open to a directory,\n\
4558  and path should be relative; path will then be relative to that directory.\n\
4559dir_fd may not be implemented on your platform.\n\
4560  If it is unavailable, using it will raise a NotImplementedError.");
4561
4562PyDoc_STRVAR(posix_remove__doc__,
4563"remove(path, *, dir_fd=None)\n\n\
4564Remove a file (same as unlink()).\n\
4565\n\
4566If dir_fd is not None, it should be a file descriptor open to a directory,\n\
4567  and path should be relative; path will then be relative to that directory.\n\
4568dir_fd may not be implemented on your platform.\n\
4569  If it is unavailable, using it will raise a NotImplementedError.");
4570
4571static PyObject *
4572posix_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
4573{
4574    path_t path;
4575    int dir_fd = DEFAULT_DIR_FD;
4576    static char *keywords[] = {"path", "dir_fd", NULL};
4577    int result;
4578    PyObject *return_value = NULL;
4579
4580    memset(&path, 0, sizeof(path));
4581    path.function_name = "unlink";
4582    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:unlink", keywords,
4583            path_converter, &path,
4584#ifdef HAVE_UNLINKAT
4585            dir_fd_converter, &dir_fd
4586#else
4587            dir_fd_unavailable, &dir_fd
4588#endif
4589            ))
4590        return NULL;
4591
4592    Py_BEGIN_ALLOW_THREADS
4593#ifdef MS_WINDOWS
4594    if (path.wide)
4595        result = Py_DeleteFileW(path.wide);
4596    else
4597        result = DeleteFileA(path.narrow);
4598    result = !result; /* Windows, success=1, UNIX, success=0 */
4599#else
4600#ifdef HAVE_UNLINKAT
4601    if (dir_fd != DEFAULT_DIR_FD)
4602        result = unlinkat(dir_fd, path.narrow, 0);
4603    else
4604#endif /* HAVE_UNLINKAT */
4605        result = unlink(path.narrow);
4606#endif
4607    Py_END_ALLOW_THREADS
4608
4609    if (result) {
4610        return_value = path_error(&path);
4611        goto exit;
4612    }
4613
4614    return_value = Py_None;
4615    Py_INCREF(Py_None);
4616
4617exit:
4618    path_cleanup(&path);
4619    return return_value;
4620}
4621
4622
4623PyDoc_STRVAR(posix_uname__doc__,
4624"uname() -> uname_result\n\n\
4625Return an object identifying the current operating system.\n\
4626The object behaves like a named tuple with the following fields:\n\
4627  (sysname, nodename, release, version, machine)");
4628
4629static PyStructSequence_Field uname_result_fields[] = {
4630    {"sysname",    "operating system name"},
4631    {"nodename",   "name of machine on network (implementation-defined)"},
4632    {"release",    "operating system release"},
4633    {"version",    "operating system version"},
4634    {"machine",    "hardware identifier"},
4635    {NULL}
4636};
4637
4638PyDoc_STRVAR(uname_result__doc__,
4639"uname_result: Result from os.uname().\n\n\
4640This object may be accessed either as a tuple of\n\
4641  (sysname, nodename, release, version, machine),\n\
4642or via the attributes sysname, nodename, release, version, and machine.\n\
4643\n\
4644See os.uname for more information.");
4645
4646static PyStructSequence_Desc uname_result_desc = {
4647    "uname_result", /* name */
4648    uname_result__doc__, /* doc */
4649    uname_result_fields,
4650    5
4651};
4652
4653static PyTypeObject UnameResultType;
4654
4655
4656#ifdef HAVE_UNAME
4657static PyObject *
4658posix_uname(PyObject *self, PyObject *noargs)
4659{
4660    struct utsname u;
4661    int res;
4662    PyObject *value;
4663
4664    Py_BEGIN_ALLOW_THREADS
4665    res = uname(&u);
4666    Py_END_ALLOW_THREADS
4667    if (res < 0)
4668        return posix_error();
4669
4670    value = PyStructSequence_New(&UnameResultType);
4671    if (value == NULL)
4672        return NULL;
4673
4674#define SET(i, field) \
4675    { \
4676    PyObject *o = PyUnicode_DecodeFSDefault(field); \
4677    if (!o) { \
4678        Py_DECREF(value); \
4679        return NULL; \
4680    } \
4681    PyStructSequence_SET_ITEM(value, i, o); \
4682    } \
4683
4684    SET(0, u.sysname);
4685    SET(1, u.nodename);
4686    SET(2, u.release);
4687    SET(3, u.version);
4688    SET(4, u.machine);
4689
4690#undef SET
4691
4692    return value;
4693}
4694#endif /* HAVE_UNAME */
4695
4696
4697PyDoc_STRVAR(posix_utime__doc__,
4698"utime(path, times=None, *[, ns], dir_fd=None, follow_symlinks=True)\n\
4699Set the access and modified time of path.\n\
4700\n\
4701path may always be specified as a string.\n\
4702On some platforms, path may also be specified as an open file descriptor.\n\
4703  If this functionality is unavailable, using it raises an exception.\n\
4704\n\
4705If times is not None, it must be a tuple (atime, mtime);\n\
4706    atime and mtime should be expressed as float seconds since the epoch.\n\
4707If ns is specified, it must be a tuple (atime_ns, mtime_ns);\n\
4708    atime_ns and mtime_ns should be expressed as integer nanoseconds\n\
4709    since the epoch.\n\
4710If times is None and ns is unspecified, utime uses the current time.\n\
4711Specifying tuples for both times and ns is an error.\n\
4712\n\
4713If dir_fd is not None, it should be a file descriptor open to a directory,\n\
4714  and path should be relative; path will then be relative to that directory.\n\
4715If follow_symlinks is False, and the last element of the path is a symbolic\n\
4716  link, utime will modify the symbolic link itself instead of the file the\n\
4717  link points to.\n\
4718It is an error to use dir_fd or follow_symlinks when specifying path\n\
4719  as an open file descriptor.\n\
4720dir_fd and follow_symlinks may not be available on your platform.\n\
4721  If they are unavailable, using them will raise a NotImplementedError.");
4722
4723typedef struct {
4724    int    now;
4725    time_t atime_s;
4726    long   atime_ns;
4727    time_t mtime_s;
4728    long   mtime_ns;
4729} utime_t;
4730
4731/*
4732 * these macros assume that "ut" is a pointer to a utime_t
4733 * they also intentionally leak the declaration of a pointer named "time"
4734 */
4735#define UTIME_TO_TIMESPEC \
4736    struct timespec ts[2]; \
4737    struct timespec *time; \
4738    if (ut->now) \
4739        time = NULL; \
4740    else { \
4741        ts[0].tv_sec = ut->atime_s; \
4742        ts[0].tv_nsec = ut->atime_ns; \
4743        ts[1].tv_sec = ut->mtime_s; \
4744        ts[1].tv_nsec = ut->mtime_ns; \
4745        time = ts; \
4746    } \
4747
4748#define UTIME_TO_TIMEVAL \
4749    struct timeval tv[2]; \
4750    struct timeval *time; \
4751    if (ut->now) \
4752        time = NULL; \
4753    else { \
4754        tv[0].tv_sec = ut->atime_s; \
4755        tv[0].tv_usec = ut->atime_ns / 1000; \
4756        tv[1].tv_sec = ut->mtime_s; \
4757        tv[1].tv_usec = ut->mtime_ns / 1000; \
4758        time = tv; \
4759    } \
4760
4761#define UTIME_TO_UTIMBUF \
4762    struct utimbuf u; \
4763    struct utimbuf *time; \
4764    if (ut->now) \
4765        time = NULL; \
4766    else { \
4767        u.actime = ut->atime_s; \
4768        u.modtime = ut->mtime_s; \
4769        time = &u; \
4770    }
4771
4772#define UTIME_TO_TIME_T \
4773    time_t timet[2]; \
4774    time_t *time; \
4775    if (ut->now) \
4776        time = NULL; \
4777    else { \
4778        timet[0] = ut->atime_s; \
4779        timet[1] = ut->mtime_s; \
4780        time = timet; \
4781    } \
4782
4783
4784#if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
4785
4786static int
4787utime_dir_fd(utime_t *ut, int dir_fd, char *path, int follow_symlinks)
4788{
4789#ifdef HAVE_UTIMENSAT
4790    int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
4791    UTIME_TO_TIMESPEC;
4792    return utimensat(dir_fd, path, time, flags);
4793#elif defined(HAVE_FUTIMESAT)
4794    UTIME_TO_TIMEVAL;
4795    /*
4796     * follow_symlinks will never be false here;
4797     * we only allow !follow_symlinks and dir_fd together
4798     * if we have utimensat()
4799     */
4800    assert(follow_symlinks);
4801    return futimesat(dir_fd, path, time);
4802#endif
4803}
4804
4805#endif
4806
4807#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
4808
4809static int
4810utime_fd(utime_t *ut, int fd)
4811{
4812#ifdef HAVE_FUTIMENS
4813    UTIME_TO_TIMESPEC;
4814    return futimens(fd, time);
4815#else
4816    UTIME_TO_TIMEVAL;
4817    return futimes(fd, time);
4818#endif
4819}
4820
4821#endif
4822
4823
4824#define UTIME_HAVE_NOFOLLOW_SYMLINKS \
4825        (defined(HAVE_UTIMENSAT) || defined(HAVE_LUTIMES))
4826
4827#if UTIME_HAVE_NOFOLLOW_SYMLINKS
4828
4829static int
4830utime_nofollow_symlinks(utime_t *ut, char *path)
4831{
4832#ifdef HAVE_UTIMENSAT
4833    UTIME_TO_TIMESPEC;
4834    return utimensat(DEFAULT_DIR_FD, path, time, AT_SYMLINK_NOFOLLOW);
4835#else
4836    UTIME_TO_TIMEVAL;
4837    return lutimes(path, time);
4838#endif
4839}
4840
4841#endif
4842
4843#ifndef MS_WINDOWS
4844
4845static int
4846utime_default(utime_t *ut, char *path)
4847{
4848#ifdef HAVE_UTIMENSAT
4849    UTIME_TO_TIMESPEC;
4850    return utimensat(DEFAULT_DIR_FD, path, time, 0);
4851#elif defined(HAVE_UTIMES)
4852    UTIME_TO_TIMEVAL;
4853    return utimes(path, time);
4854#elif defined(HAVE_UTIME_H)
4855    UTIME_TO_UTIMBUF;
4856    return utime(path, time);
4857#else
4858    UTIME_TO_TIME_T;
4859    return utime(path, time);
4860#endif
4861}
4862
4863#endif
4864
4865static int
4866split_py_long_to_s_and_ns(PyObject *py_long, time_t *s, long *ns)
4867{
4868    int result = 0;
4869    PyObject *divmod;
4870    divmod = PyNumber_Divmod(py_long, billion);
4871    if (!divmod)
4872        goto exit;
4873    *s = _PyLong_AsTime_t(PyTuple_GET_ITEM(divmod, 0));
4874    if ((*s == -1) && PyErr_Occurred())
4875        goto exit;
4876    *ns = PyLong_AsLong(PyTuple_GET_ITEM(divmod, 1));
4877    if ((*ns == -1) && PyErr_Occurred())
4878        goto exit;
4879
4880    result = 1;
4881exit:
4882    Py_XDECREF(divmod);
4883    return result;
4884}
4885
4886static PyObject *
4887posix_utime(PyObject *self, PyObject *args, PyObject *kwargs)
4888{
4889    path_t path;
4890    PyObject *times = NULL;
4891    PyObject *ns = NULL;
4892    int dir_fd = DEFAULT_DIR_FD;
4893    int follow_symlinks = 1;
4894    char *keywords[] = {"path", "times", "ns", "dir_fd",
4895                        "follow_symlinks", NULL};
4896
4897    utime_t utime;
4898
4899#ifdef MS_WINDOWS
4900    HANDLE hFile;
4901    FILETIME atime, mtime;
4902#else
4903    int result;
4904#endif
4905
4906    PyObject *return_value = NULL;
4907
4908    memset(&path, 0, sizeof(path));
4909    path.function_name = "utime";
4910    memset(&utime, 0, sizeof(utime_t));
4911#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
4912    path.allow_fd = 1;
4913#endif
4914    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
4915            "O&|O$OO&p:utime", keywords,
4916            path_converter, &path,
4917            &times, &ns,
4918#if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
4919            dir_fd_converter, &dir_fd,
4920#else
4921            dir_fd_unavailable, &dir_fd,
4922#endif
4923            &follow_symlinks
4924            ))
4925        return NULL;
4926
4927    if (times && (times != Py_None) && ns) {
4928        PyErr_SetString(PyExc_ValueError,
4929                     "utime: you may specify either 'times'"
4930                     " or 'ns' but not both");
4931        goto exit;
4932    }
4933
4934    if (times && (times != Py_None)) {
4935        time_t a_sec, m_sec;
4936        long a_nsec, m_nsec;
4937        if (!PyTuple_CheckExact(times) || (PyTuple_Size(times) != 2)) {
4938            PyErr_SetString(PyExc_TypeError,
4939                         "utime: 'times' must be either"
4940                         " a tuple of two ints or None");
4941            goto exit;
4942        }
4943        utime.now = 0;
4944        if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0),
4945                                     &a_sec, &a_nsec, _PyTime_ROUND_DOWN) == -1 ||
4946            _PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1),
4947                                     &m_sec, &m_nsec, _PyTime_ROUND_DOWN) == -1) {
4948            goto exit;
4949        }
4950        utime.atime_s = a_sec;
4951        utime.atime_ns = a_nsec;
4952        utime.mtime_s = m_sec;
4953        utime.mtime_ns = m_nsec;
4954    }
4955    else if (ns) {
4956        if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) {
4957            PyErr_SetString(PyExc_TypeError,
4958                         "utime: 'ns' must be a tuple of two ints");
4959            goto exit;
4960        }
4961        utime.now = 0;
4962        if (!split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 0),
4963                                      &utime.atime_s, &utime.atime_ns) ||
4964            !split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 1),
4965                                       &utime.mtime_s, &utime.mtime_ns)) {
4966            goto exit;
4967        }
4968    }
4969    else {
4970        /* times and ns are both None/unspecified. use "now". */
4971        utime.now = 1;
4972    }
4973
4974#if !UTIME_HAVE_NOFOLLOW_SYMLINKS
4975    if (follow_symlinks_specified("utime", follow_symlinks))
4976        goto exit;
4977#endif
4978
4979    if (path_and_dir_fd_invalid("utime", &path, dir_fd) ||
4980        dir_fd_and_fd_invalid("utime", dir_fd, path.fd) ||
4981        fd_and_follow_symlinks_invalid("utime", path.fd, follow_symlinks))
4982        goto exit;
4983
4984#if !defined(HAVE_UTIMENSAT)
4985    if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
4986        PyErr_SetString(PyExc_ValueError,
4987                     "utime: cannot use dir_fd and follow_symlinks "
4988                     "together on this platform");
4989        goto exit;
4990    }
4991#endif
4992
4993#ifdef MS_WINDOWS
4994    Py_BEGIN_ALLOW_THREADS
4995    if (path.wide)
4996        hFile = CreateFileW(path.wide, FILE_WRITE_ATTRIBUTES, 0,
4997                            NULL, OPEN_EXISTING,
4998                            FILE_FLAG_BACKUP_SEMANTICS, NULL);
4999    else
5000        hFile = CreateFileA(path.narrow, FILE_WRITE_ATTRIBUTES, 0,
5001                            NULL, OPEN_EXISTING,
5002                            FILE_FLAG_BACKUP_SEMANTICS, NULL);
5003    Py_END_ALLOW_THREADS
5004    if (hFile == INVALID_HANDLE_VALUE) {
5005        path_error(&path);
5006        goto exit;
5007    }
5008
5009    if (utime.now) {
5010        GetSystemTimeAsFileTime(&mtime);
5011        atime = mtime;
5012    }
5013    else {
5014        time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime);
5015        time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime);
5016    }
5017    if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
5018        /* Avoid putting the file name into the error here,
5019           as that may confuse the user into believing that
5020           something is wrong with the file, when it also
5021           could be the time stamp that gives a problem. */
5022        PyErr_SetFromWindowsErr(0);
5023        goto exit;
5024    }
5025#else /* MS_WINDOWS */
5026    Py_BEGIN_ALLOW_THREADS
5027
5028#if UTIME_HAVE_NOFOLLOW_SYMLINKS
5029    if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
5030        result = utime_nofollow_symlinks(&utime, path.narrow);
5031    else
5032#endif
5033
5034#if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
5035    if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks))
5036        result = utime_dir_fd(&utime, dir_fd, path.narrow, follow_symlinks);
5037    else
5038#endif
5039
5040#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
5041    if (path.fd != -1)
5042        result = utime_fd(&utime, path.fd);
5043    else
5044#endif
5045
5046    result = utime_default(&utime, path.narrow);
5047
5048    Py_END_ALLOW_THREADS
5049
5050    if (result < 0) {
5051        /* see previous comment about not putting filename in error here */
5052        return_value = posix_error();
5053        goto exit;
5054    }
5055
5056#endif /* MS_WINDOWS */
5057
5058    Py_INCREF(Py_None);
5059    return_value = Py_None;
5060
5061exit:
5062    path_cleanup(&path);
5063#ifdef MS_WINDOWS
5064    if (hFile != INVALID_HANDLE_VALUE)
5065        CloseHandle(hFile);
5066#endif
5067    return return_value;
5068}
5069
5070/* Process operations */
5071
5072PyDoc_STRVAR(posix__exit__doc__,
5073"_exit(status)\n\n\
5074Exit to the system with specified status, without normal exit processing.");
5075
5076static PyObject *
5077posix__exit(PyObject *self, PyObject *args)
5078{
5079    int sts;
5080    if (!PyArg_ParseTuple(args, "i:_exit", &sts))
5081        return NULL;
5082    _exit(sts);
5083    return NULL; /* Make gcc -Wall happy */
5084}
5085
5086#if defined(HAVE_EXECV) || defined(HAVE_SPAWNV)
5087static void
5088free_string_array(char **array, Py_ssize_t count)
5089{
5090    Py_ssize_t i;
5091    for (i = 0; i < count; i++)
5092        PyMem_Free(array[i]);
5093    PyMem_DEL(array);
5094}
5095
5096static
5097int fsconvert_strdup(PyObject *o, char**out)
5098{
5099    PyObject *bytes;
5100    Py_ssize_t size;
5101    if (!PyUnicode_FSConverter(o, &bytes))
5102        return 0;
5103    size = PyBytes_GET_SIZE(bytes);
5104    *out = PyMem_Malloc(size+1);
5105    if (!*out) {
5106        PyErr_NoMemory();
5107        return 0;
5108    }
5109    memcpy(*out, PyBytes_AsString(bytes), size+1);
5110    Py_DECREF(bytes);
5111    return 1;
5112}
5113#endif
5114
5115#if defined(HAVE_EXECV) || defined (HAVE_FEXECVE)
5116static char**
5117parse_envlist(PyObject* env, Py_ssize_t *envc_ptr)
5118{
5119    char **envlist;
5120    Py_ssize_t i, pos, envc;
5121    PyObject *keys=NULL, *vals=NULL;
5122    PyObject *key, *val, *key2, *val2;
5123    char *p, *k, *v;
5124    size_t len;
5125
5126    i = PyMapping_Size(env);
5127    if (i < 0)
5128        return NULL;
5129    envlist = PyMem_NEW(char *, i + 1);
5130    if (envlist == NULL) {
5131        PyErr_NoMemory();
5132        return NULL;
5133    }
5134    envc = 0;
5135    keys = PyMapping_Keys(env);
5136    if (!keys)
5137        goto error;
5138    vals = PyMapping_Values(env);
5139    if (!vals)
5140        goto error;
5141    if (!PyList_Check(keys) || !PyList_Check(vals)) {
5142        PyErr_Format(PyExc_TypeError,
5143                     "env.keys() or env.values() is not a list");
5144        goto error;
5145    }
5146
5147    for (pos = 0; pos < i; pos++) {
5148        key = PyList_GetItem(keys, pos);
5149        val = PyList_GetItem(vals, pos);
5150        if (!key || !val)
5151            goto error;
5152
5153        if (PyUnicode_FSConverter(key, &key2) == 0)
5154            goto error;
5155        if (PyUnicode_FSConverter(val, &val2) == 0) {
5156            Py_DECREF(key2);
5157            goto error;
5158        }
5159
5160        k = PyBytes_AsString(key2);
5161        v = PyBytes_AsString(val2);
5162        len = PyBytes_GET_SIZE(key2) + PyBytes_GET_SIZE(val2) + 2;
5163
5164        p = PyMem_NEW(char, len);
5165        if (p == NULL) {
5166            PyErr_NoMemory();
5167            Py_DECREF(key2);
5168            Py_DECREF(val2);
5169            goto error;
5170        }
5171        PyOS_snprintf(p, len, "%s=%s", k, v);
5172        envlist[envc++] = p;
5173        Py_DECREF(key2);
5174        Py_DECREF(val2);
5175    }
5176    Py_DECREF(vals);
5177    Py_DECREF(keys);
5178
5179    envlist[envc] = 0;
5180    *envc_ptr = envc;
5181    return envlist;
5182
5183error:
5184    Py_XDECREF(keys);
5185    Py_XDECREF(vals);
5186    while (--envc >= 0)
5187        PyMem_DEL(envlist[envc]);
5188    PyMem_DEL(envlist);
5189    return NULL;
5190}
5191
5192static char**
5193parse_arglist(PyObject* argv, Py_ssize_t *argc)
5194{
5195    int i;
5196    char **argvlist = PyMem_NEW(char *, *argc+1);
5197    if (argvlist == NULL) {
5198        PyErr_NoMemory();
5199        return NULL;
5200    }
5201    for (i = 0; i < *argc; i++) {
5202        PyObject* item = PySequence_ITEM(argv, i);
5203        if (item == NULL)
5204            goto fail;
5205        if (!fsconvert_strdup(item, &argvlist[i])) {
5206            Py_DECREF(item);
5207            goto fail;
5208        }
5209        Py_DECREF(item);
5210    }
5211    argvlist[*argc] = NULL;
5212    return argvlist;
5213fail:
5214    *argc = i;
5215    free_string_array(argvlist, *argc);
5216    return NULL;
5217}
5218#endif
5219
5220#ifdef HAVE_EXECV
5221PyDoc_STRVAR(posix_execv__doc__,
5222"execv(path, args)\n\n\
5223Execute an executable path with arguments, replacing current process.\n\
5224\n\
5225    path: path of executable file\n\
5226    args: tuple or list of strings");
5227
5228static PyObject *
5229posix_execv(PyObject *self, PyObject *args)
5230{
5231    PyObject *opath;
5232    char *path;
5233    PyObject *argv;
5234    char **argvlist;
5235    Py_ssize_t argc;
5236
5237    /* execv has two arguments: (path, argv), where
5238       argv is a list or tuple of strings. */
5239
5240    if (!PyArg_ParseTuple(args, "O&O:execv",
5241                          PyUnicode_FSConverter,
5242                          &opath, &argv))
5243        return NULL;
5244    path = PyBytes_AsString(opath);
5245    if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
5246        PyErr_SetString(PyExc_TypeError,
5247                        "execv() arg 2 must be a tuple or list");
5248        Py_DECREF(opath);
5249        return NULL;
5250    }
5251    argc = PySequence_Size(argv);
5252    if (argc < 1) {
5253        PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
5254        Py_DECREF(opath);
5255        return NULL;
5256    }
5257
5258    argvlist = parse_arglist(argv, &argc);
5259    if (argvlist == NULL) {
5260        Py_DECREF(opath);
5261        return NULL;
5262    }
5263
5264    execv(path, argvlist);
5265
5266    /* If we get here it's definitely an error */
5267
5268    free_string_array(argvlist, argc);
5269    Py_DECREF(opath);
5270    return posix_error();
5271}
5272
5273PyDoc_STRVAR(posix_execve__doc__,
5274"execve(path, args, env)\n\n\
5275Execute a path with arguments and environment, replacing current process.\n\
5276\n\
5277    path: path of executable file\n\
5278    args: tuple or list of arguments\n\
5279    env: dictionary of strings mapping to strings\n\
5280\n\
5281On some platforms, you may specify an open file descriptor for path;\n\
5282  execve will execute the program the file descriptor is open to.\n\
5283  If this functionality is unavailable, using it raises NotImplementedError.");
5284
5285static PyObject *
5286posix_execve(PyObject *self, PyObject *args, PyObject *kwargs)
5287{
5288    path_t path;
5289    PyObject *argv, *env;
5290    char **argvlist = NULL;
5291    char **envlist;
5292    Py_ssize_t argc, envc;
5293    static char *keywords[] = {"path", "argv", "environment", NULL};
5294
5295    /* execve has three arguments: (path, argv, env), where
5296       argv is a list or tuple of strings and env is a dictionary
5297       like posix.environ. */
5298
5299    memset(&path, 0, sizeof(path));
5300    path.function_name = "execve";
5301#ifdef HAVE_FEXECVE
5302    path.allow_fd = 1;
5303#endif
5304    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&OO:execve", keywords,
5305                          path_converter, &path,
5306                          &argv, &env
5307                          ))
5308        return NULL;
5309
5310    if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
5311        PyErr_SetString(PyExc_TypeError,
5312                        "execve: argv must be a tuple or list");
5313        goto fail;
5314    }
5315    argc = PySequence_Size(argv);
5316    if (!PyMapping_Check(env)) {
5317        PyErr_SetString(PyExc_TypeError,
5318                        "execve: environment must be a mapping object");
5319        goto fail;
5320    }
5321
5322    argvlist = parse_arglist(argv, &argc);
5323    if (argvlist == NULL) {
5324        goto fail;
5325    }
5326
5327    envlist = parse_envlist(env, &envc);
5328    if (envlist == NULL)
5329        goto fail;
5330
5331#ifdef HAVE_FEXECVE
5332    if (path.fd > -1)
5333        fexecve(path.fd, argvlist, envlist);
5334    else
5335#endif
5336        execve(path.narrow, argvlist, envlist);
5337
5338    /* If we get here it's definitely an error */
5339
5340    path_error(&path);
5341
5342    while (--envc >= 0)
5343        PyMem_DEL(envlist[envc]);
5344    PyMem_DEL(envlist);
5345  fail:
5346    if (argvlist)
5347        free_string_array(argvlist, argc);
5348    path_cleanup(&path);
5349    return NULL;
5350}
5351#endif /* HAVE_EXECV */
5352
5353
5354#ifdef HAVE_SPAWNV
5355PyDoc_STRVAR(posix_spawnv__doc__,
5356"spawnv(mode, path, args)\n\n\
5357Execute the program 'path' in a new process.\n\
5358\n\
5359    mode: mode of process creation\n\
5360    path: path of executable file\n\
5361    args: tuple or list of strings");
5362
5363static PyObject *
5364posix_spawnv(PyObject *self, PyObject *args)
5365{
5366    PyObject *opath;
5367    char *path;
5368    PyObject *argv;
5369    char **argvlist;
5370    int mode, i;
5371    Py_ssize_t argc;
5372    Py_intptr_t spawnval;
5373    PyObject *(*getitem)(PyObject *, Py_ssize_t);
5374
5375    /* spawnv has three arguments: (mode, path, argv), where
5376       argv is a list or tuple of strings. */
5377
5378    if (!PyArg_ParseTuple(args, "iO&O:spawnv", &mode,
5379                          PyUnicode_FSConverter,
5380                          &opath, &argv))
5381        return NULL;
5382    path = PyBytes_AsString(opath);
5383    if (PyList_Check(argv)) {
5384        argc = PyList_Size(argv);
5385        getitem = PyList_GetItem;
5386    }
5387    else if (PyTuple_Check(argv)) {
5388        argc = PyTuple_Size(argv);
5389        getitem = PyTuple_GetItem;
5390    }
5391    else {
5392        PyErr_SetString(PyExc_TypeError,
5393                        "spawnv() arg 2 must be a tuple or list");
5394        Py_DECREF(opath);
5395        return NULL;
5396    }
5397
5398    argvlist = PyMem_NEW(char *, argc+1);
5399    if (argvlist == NULL) {
5400        Py_DECREF(opath);
5401        return PyErr_NoMemory();
5402    }
5403    for (i = 0; i < argc; i++) {
5404        if (!fsconvert_strdup((*getitem)(argv, i),
5405                              &argvlist[i])) {
5406            free_string_array(argvlist, i);
5407            PyErr_SetString(
5408                PyExc_TypeError,
5409                "spawnv() arg 2 must contain only strings");
5410            Py_DECREF(opath);
5411            return NULL;
5412        }
5413    }
5414    argvlist[argc] = NULL;
5415
5416    if (mode == _OLD_P_OVERLAY)
5417        mode = _P_OVERLAY;
5418
5419    Py_BEGIN_ALLOW_THREADS
5420    spawnval = _spawnv(mode, path, argvlist);
5421    Py_END_ALLOW_THREADS
5422
5423    free_string_array(argvlist, argc);
5424    Py_DECREF(opath);
5425
5426    if (spawnval == -1)
5427        return posix_error();
5428    else
5429        return Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
5430}
5431
5432
5433PyDoc_STRVAR(posix_spawnve__doc__,
5434"spawnve(mode, path, args, env)\n\n\
5435Execute the program 'path' in a new process.\n\
5436\n\
5437    mode: mode of process creation\n\
5438    path: path of executable file\n\
5439    args: tuple or list of arguments\n\
5440    env: dictionary of strings mapping to strings");
5441
5442static PyObject *
5443posix_spawnve(PyObject *self, PyObject *args)
5444{
5445    PyObject *opath;
5446    char *path;
5447    PyObject *argv, *env;
5448    char **argvlist;
5449    char **envlist;
5450    PyObject *res = NULL;
5451    int mode;
5452    Py_ssize_t argc, i, envc;
5453    Py_intptr_t spawnval;
5454    PyObject *(*getitem)(PyObject *, Py_ssize_t);
5455    Py_ssize_t lastarg = 0;
5456
5457    /* spawnve has four arguments: (mode, path, argv, env), where
5458       argv is a list or tuple of strings and env is a dictionary
5459       like posix.environ. */
5460
5461    if (!PyArg_ParseTuple(args, "iO&OO:spawnve", &mode,
5462                          PyUnicode_FSConverter,
5463                          &opath, &argv, &env))
5464        return NULL;
5465    path = PyBytes_AsString(opath);
5466    if (PyList_Check(argv)) {
5467        argc = PyList_Size(argv);
5468        getitem = PyList_GetItem;
5469    }
5470    else if (PyTuple_Check(argv)) {
5471        argc = PyTuple_Size(argv);
5472        getitem = PyTuple_GetItem;
5473    }
5474    else {
5475        PyErr_SetString(PyExc_TypeError,
5476                        "spawnve() arg 2 must be a tuple or list");
5477        goto fail_0;
5478    }
5479    if (!PyMapping_Check(env)) {
5480        PyErr_SetString(PyExc_TypeError,
5481                        "spawnve() arg 3 must be a mapping object");
5482        goto fail_0;
5483    }
5484
5485    argvlist = PyMem_NEW(char *, argc+1);
5486    if (argvlist == NULL) {
5487        PyErr_NoMemory();
5488        goto fail_0;
5489    }
5490    for (i = 0; i < argc; i++) {
5491        if (!fsconvert_strdup((*getitem)(argv, i),
5492                              &argvlist[i]))
5493        {
5494            lastarg = i;
5495            goto fail_1;
5496        }
5497    }
5498    lastarg = argc;
5499    argvlist[argc] = NULL;
5500
5501    envlist = parse_envlist(env, &envc);
5502    if (envlist == NULL)
5503        goto fail_1;
5504
5505    if (mode == _OLD_P_OVERLAY)
5506        mode = _P_OVERLAY;
5507
5508    Py_BEGIN_ALLOW_THREADS
5509    spawnval = _spawnve(mode, path, argvlist, envlist);
5510    Py_END_ALLOW_THREADS
5511
5512    if (spawnval == -1)
5513        (void) posix_error();
5514    else
5515        res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
5516
5517    while (--envc >= 0)
5518        PyMem_DEL(envlist[envc]);
5519    PyMem_DEL(envlist);
5520  fail_1:
5521    free_string_array(argvlist, lastarg);
5522  fail_0:
5523    Py_DECREF(opath);
5524    return res;
5525}
5526
5527#endif /* HAVE_SPAWNV */
5528
5529
5530#ifdef HAVE_FORK1
5531PyDoc_STRVAR(posix_fork1__doc__,
5532"fork1() -> pid\n\n\
5533Fork a child process with a single multiplexed (i.e., not bound) thread.\n\
5534\n\
5535Return 0 to child process and PID of child to parent process.");
5536
5537static PyObject *
5538posix_fork1(PyObject *self, PyObject *noargs)
5539{
5540    pid_t pid;
5541    int result = 0;
5542    _PyImport_AcquireLock();
5543    pid = fork1();
5544    if (pid == 0) {
5545        /* child: this clobbers and resets the import lock. */
5546        PyOS_AfterFork();
5547    } else {
5548        /* parent: release the import lock. */
5549        result = _PyImport_ReleaseLock();
5550    }
5551    if (pid == -1)
5552        return posix_error();
5553    if (result < 0) {
5554        /* Don't clobber the OSError if the fork failed. */
5555        PyErr_SetString(PyExc_RuntimeError,
5556                        "not holding the import lock");
5557        return NULL;
5558    }
5559    return PyLong_FromPid(pid);
5560}
5561#endif
5562
5563
5564#ifdef HAVE_FORK
5565PyDoc_STRVAR(posix_fork__doc__,
5566"fork() -> pid\n\n\
5567Fork a child process.\n\
5568Return 0 to child process and PID of child to parent process.");
5569
5570static PyObject *
5571posix_fork(PyObject *self, PyObject *noargs)
5572{
5573    pid_t pid;
5574    int result = 0;
5575    _PyImport_AcquireLock();
5576    pid = fork();
5577    if (pid == 0) {
5578        /* child: this clobbers and resets the import lock. */
5579        PyOS_AfterFork();
5580    } else {
5581        /* parent: release the import lock. */
5582        result = _PyImport_ReleaseLock();
5583    }
5584    if (pid == -1)
5585        return posix_error();
5586    if (result < 0) {
5587        /* Don't clobber the OSError if the fork failed. */
5588        PyErr_SetString(PyExc_RuntimeError,
5589                        "not holding the import lock");
5590        return NULL;
5591    }
5592    return PyLong_FromPid(pid);
5593}
5594#endif
5595
5596#ifdef HAVE_SCHED_H
5597
5598#ifdef HAVE_SCHED_GET_PRIORITY_MAX
5599
5600PyDoc_STRVAR(posix_sched_get_priority_max__doc__,
5601"sched_get_priority_max(policy)\n\n\
5602Get the maximum scheduling priority for *policy*.");
5603
5604static PyObject *
5605posix_sched_get_priority_max(PyObject *self, PyObject *args)
5606{
5607    int policy, max;
5608
5609    if (!PyArg_ParseTuple(args, "i:sched_get_priority_max", &policy))
5610        return NULL;
5611    max = sched_get_priority_max(policy);
5612    if (max < 0)
5613        return posix_error();
5614    return PyLong_FromLong(max);
5615}
5616
5617PyDoc_STRVAR(posix_sched_get_priority_min__doc__,
5618"sched_get_priority_min(policy)\n\n\
5619Get the minimum scheduling priority for *policy*.");
5620
5621static PyObject *
5622posix_sched_get_priority_min(PyObject *self, PyObject *args)
5623{
5624    int policy, min;
5625
5626    if (!PyArg_ParseTuple(args, "i:sched_get_priority_min", &policy))
5627        return NULL;
5628    min = sched_get_priority_min(policy);
5629    if (min < 0)
5630        return posix_error();
5631    return PyLong_FromLong(min);
5632}
5633
5634#endif /* HAVE_SCHED_GET_PRIORITY_MAX */
5635
5636#ifdef HAVE_SCHED_SETSCHEDULER
5637
5638PyDoc_STRVAR(posix_sched_getscheduler__doc__,
5639"sched_getscheduler(pid)\n\n\
5640Get the scheduling policy for the process with a PID of *pid*.\n\
5641Passing a PID of 0 returns the scheduling policy for the calling process.");
5642
5643static PyObject *
5644posix_sched_getscheduler(PyObject *self, PyObject *args)
5645{
5646    pid_t pid;
5647    int policy;
5648
5649    if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getscheduler", &pid))
5650        return NULL;
5651    policy = sched_getscheduler(pid);
5652    if (policy < 0)
5653        return posix_error();
5654    return PyLong_FromLong(policy);
5655}
5656
5657#endif
5658
5659#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SCHED_SETPARAM)
5660
5661static PyObject *
5662sched_param_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
5663{
5664    PyObject *res, *priority;
5665    static char *kwlist[] = {"sched_priority", NULL};
5666
5667    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:sched_param", kwlist, &priority))
5668        return NULL;
5669    res = PyStructSequence_New(type);
5670    if (!res)
5671        return NULL;
5672    Py_INCREF(priority);
5673    PyStructSequence_SET_ITEM(res, 0, priority);
5674    return res;
5675}
5676
5677PyDoc_STRVAR(sched_param__doc__,
5678"sched_param(sched_priority): A scheduling parameter.\n\n\
5679Current has only one field: sched_priority");
5680
5681static PyStructSequence_Field sched_param_fields[] = {
5682    {"sched_priority", "the scheduling priority"},
5683    {0}
5684};
5685
5686static PyStructSequence_Desc sched_param_desc = {
5687    "sched_param", /* name */
5688    sched_param__doc__, /* doc */
5689    sched_param_fields,
5690    1
5691};
5692
5693static int
5694convert_sched_param(PyObject *param, struct sched_param *res)
5695{
5696    long priority;
5697
5698    if (Py_TYPE(param) != &SchedParamType) {
5699        PyErr_SetString(PyExc_TypeError, "must have a sched_param object");
5700        return 0;
5701    }
5702    priority = PyLong_AsLong(PyStructSequence_GET_ITEM(param, 0));
5703    if (priority == -1 && PyErr_Occurred())
5704        return 0;
5705    if (priority > INT_MAX || priority < INT_MIN) {
5706        PyErr_SetString(PyExc_OverflowError, "sched_priority out of range");
5707        return 0;
5708    }
5709    res->sched_priority = Py_SAFE_DOWNCAST(priority, long, int);
5710    return 1;
5711}
5712
5713#endif
5714
5715#ifdef HAVE_SCHED_SETSCHEDULER
5716
5717PyDoc_STRVAR(posix_sched_setscheduler__doc__,
5718"sched_setscheduler(pid, policy, param)\n\n\
5719Set the scheduling policy, *policy*, for *pid*.\n\
5720If *pid* is 0, the calling process is changed.\n\
5721*param* is an instance of sched_param.");
5722
5723static PyObject *
5724posix_sched_setscheduler(PyObject *self, PyObject *args)
5725{
5726    pid_t pid;
5727    int policy;
5728    struct sched_param param;
5729
5730    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "iO&:sched_setscheduler",
5731                          &pid, &policy, &convert_sched_param, &param))
5732        return NULL;
5733
5734    /*
5735    ** sched_setscheduler() returns 0 in Linux, but the previous
5736    ** scheduling policy under Solaris/Illumos, and others.
5737    ** On error, -1 is returned in all Operating Systems.
5738    */
5739    if (sched_setscheduler(pid, policy, &param) == -1)
5740        return posix_error();
5741    Py_RETURN_NONE;
5742}
5743
5744#endif
5745
5746#ifdef HAVE_SCHED_SETPARAM
5747
5748PyDoc_STRVAR(posix_sched_getparam__doc__,
5749"sched_getparam(pid) -> sched_param\n\n\
5750Returns scheduling parameters for the process with *pid* as an instance of the\n\
5751sched_param class. A PID of 0 means the calling process.");
5752
5753static PyObject *
5754posix_sched_getparam(PyObject *self, PyObject *args)
5755{
5756    pid_t pid;
5757    struct sched_param param;
5758    PyObject *res, *priority;
5759
5760    if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getparam", &pid))
5761        return NULL;
5762    if (sched_getparam(pid, &param))
5763        return posix_error();
5764    res = PyStructSequence_New(&SchedParamType);
5765    if (!res)
5766        return NULL;
5767    priority = PyLong_FromLong(param.sched_priority);
5768    if (!priority) {
5769        Py_DECREF(res);
5770        return NULL;
5771    }
5772    PyStructSequence_SET_ITEM(res, 0, priority);
5773    return res;
5774}
5775
5776PyDoc_STRVAR(posix_sched_setparam__doc__,
5777"sched_setparam(pid, param)\n\n\
5778Set scheduling parameters for a process with PID *pid*.\n\
5779A PID of 0 means the calling process.");
5780
5781static PyObject *
5782posix_sched_setparam(PyObject *self, PyObject *args)
5783{
5784    pid_t pid;
5785    struct sched_param param;
5786
5787    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O&:sched_setparam",
5788                          &pid, &convert_sched_param, &param))
5789        return NULL;
5790    if (sched_setparam(pid, &param))
5791        return posix_error();
5792    Py_RETURN_NONE;
5793}
5794
5795#endif
5796
5797#ifdef HAVE_SCHED_RR_GET_INTERVAL
5798
5799PyDoc_STRVAR(posix_sched_rr_get_interval__doc__,
5800"sched_rr_get_interval(pid) -> float\n\n\
5801Return the round-robin quantum for the process with PID *pid* in seconds.");
5802
5803static PyObject *
5804posix_sched_rr_get_interval(PyObject *self, PyObject *args)
5805{
5806    pid_t pid;
5807    struct timespec interval;
5808
5809    if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_rr_get_interval", &pid))
5810        return NULL;
5811    if (sched_rr_get_interval(pid, &interval))
5812        return posix_error();
5813    return PyFloat_FromDouble((double)interval.tv_sec + 1e-9*interval.tv_nsec);
5814}
5815
5816#endif
5817
5818PyDoc_STRVAR(posix_sched_yield__doc__,
5819"sched_yield()\n\n\
5820Voluntarily relinquish the CPU.");
5821
5822static PyObject *
5823posix_sched_yield(PyObject *self, PyObject *noargs)
5824{
5825    if (sched_yield())
5826        return posix_error();
5827    Py_RETURN_NONE;
5828}
5829
5830#ifdef HAVE_SCHED_SETAFFINITY
5831
5832/* The minimum number of CPUs allocated in a cpu_set_t */
5833static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
5834
5835PyDoc_STRVAR(posix_sched_setaffinity__doc__,
5836"sched_setaffinity(pid, cpu_set)\n\n\
5837Set the affinity of the process with PID *pid* to *cpu_set*.");
5838
5839static PyObject *
5840posix_sched_setaffinity(PyObject *self, PyObject *args)
5841{
5842    pid_t pid;
5843    int ncpus;
5844    size_t setsize;
5845    cpu_set_t *mask = NULL;
5846    PyObject *iterable, *iterator = NULL, *item;
5847
5848    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O:sched_setaffinity",
5849                          &pid, &iterable))
5850        return NULL;
5851
5852    iterator = PyObject_GetIter(iterable);
5853    if (iterator == NULL)
5854        return NULL;
5855
5856    ncpus = NCPUS_START;
5857    setsize = CPU_ALLOC_SIZE(ncpus);
5858    mask = CPU_ALLOC(ncpus);
5859    if (mask == NULL) {
5860        PyErr_NoMemory();
5861        goto error;
5862    }
5863    CPU_ZERO_S(setsize, mask);
5864
5865    while ((item = PyIter_Next(iterator))) {
5866        long cpu;
5867        if (!PyLong_Check(item)) {
5868            PyErr_Format(PyExc_TypeError,
5869                        "expected an iterator of ints, "
5870                        "but iterator yielded %R",
5871                        Py_TYPE(item));
5872            Py_DECREF(item);
5873            goto error;
5874        }
5875        cpu = PyLong_AsLong(item);
5876        Py_DECREF(item);
5877        if (cpu < 0) {
5878            if (!PyErr_Occurred())
5879                PyErr_SetString(PyExc_ValueError, "negative CPU number");
5880            goto error;
5881        }
5882        if (cpu > INT_MAX - 1) {
5883            PyErr_SetString(PyExc_OverflowError, "CPU number too large");
5884            goto error;
5885        }
5886        if (cpu >= ncpus) {
5887            /* Grow CPU mask to fit the CPU number */
5888            int newncpus = ncpus;
5889            cpu_set_t *newmask;
5890            size_t newsetsize;
5891            while (newncpus <= cpu) {
5892                if (newncpus > INT_MAX / 2)
5893                    newncpus = cpu + 1;
5894                else
5895                    newncpus = newncpus * 2;
5896            }
5897            newmask = CPU_ALLOC(newncpus);
5898            if (newmask == NULL) {
5899                PyErr_NoMemory();
5900                goto error;
5901            }
5902            newsetsize = CPU_ALLOC_SIZE(newncpus);
5903            CPU_ZERO_S(newsetsize, newmask);
5904            memcpy(newmask, mask, setsize);
5905            CPU_FREE(mask);
5906            setsize = newsetsize;
5907            mask = newmask;
5908            ncpus = newncpus;
5909        }
5910        CPU_SET_S(cpu, setsize, mask);
5911    }
5912    Py_CLEAR(iterator);
5913
5914    if (sched_setaffinity(pid, setsize, mask)) {
5915        posix_error();
5916        goto error;
5917    }
5918    CPU_FREE(mask);
5919    Py_RETURN_NONE;
5920
5921error:
5922    if (mask)
5923        CPU_FREE(mask);
5924    Py_XDECREF(iterator);
5925    return NULL;
5926}
5927
5928PyDoc_STRVAR(posix_sched_getaffinity__doc__,
5929"sched_getaffinity(pid, ncpus) -> cpu_set\n\n\
5930Return the affinity of the process with PID *pid*.\n\
5931The returned cpu_set will be of size *ncpus*.");
5932
5933static PyObject *
5934posix_sched_getaffinity(PyObject *self, PyObject *args)
5935{
5936    pid_t pid;
5937    int cpu, ncpus, count;
5938    size_t setsize;
5939    cpu_set_t *mask = NULL;
5940    PyObject *res = NULL;
5941
5942    if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getaffinity",
5943                          &pid))
5944        return NULL;
5945
5946    ncpus = NCPUS_START;
5947    while (1) {
5948        setsize = CPU_ALLOC_SIZE(ncpus);
5949        mask = CPU_ALLOC(ncpus);
5950        if (mask == NULL)
5951            return PyErr_NoMemory();
5952        if (sched_getaffinity(pid, setsize, mask) == 0)
5953            break;
5954        CPU_FREE(mask);
5955        if (errno != EINVAL)
5956            return posix_error();
5957        if (ncpus > INT_MAX / 2) {
5958            PyErr_SetString(PyExc_OverflowError, "could not allocate "
5959                            "a large enough CPU set");
5960            return NULL;
5961        }
5962        ncpus = ncpus * 2;
5963    }
5964
5965    res = PySet_New(NULL);
5966    if (res == NULL)
5967        goto error;
5968    for (cpu = 0, count = CPU_COUNT_S(setsize, mask); count; cpu++) {
5969        if (CPU_ISSET_S(cpu, setsize, mask)) {
5970            PyObject *cpu_num = PyLong_FromLong(cpu);
5971            --count;
5972            if (cpu_num == NULL)
5973                goto error;
5974            if (PySet_Add(res, cpu_num)) {
5975                Py_DECREF(cpu_num);
5976                goto error;
5977            }
5978            Py_DECREF(cpu_num);
5979        }
5980    }
5981    CPU_FREE(mask);
5982    return res;
5983
5984error:
5985    if (mask)
5986        CPU_FREE(mask);
5987    Py_XDECREF(res);
5988    return NULL;
5989}
5990
5991#endif /* HAVE_SCHED_SETAFFINITY */
5992
5993#endif /* HAVE_SCHED_H */
5994
5995/* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */
5996/* IRIX has both /dev/ptc and /dev/ptmx, use ptmx */
5997#if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX)
5998#define DEV_PTY_FILE "/dev/ptc"
5999#define HAVE_DEV_PTMX
6000#else
6001#define DEV_PTY_FILE "/dev/ptmx"
6002#endif
6003
6004#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX)
6005#ifdef HAVE_PTY_H
6006#include <pty.h>
6007#else
6008#ifdef HAVE_LIBUTIL_H
6009#include <libutil.h>
6010#else
6011#ifdef HAVE_UTIL_H
6012#include <util.h>
6013#endif /* HAVE_UTIL_H */
6014#endif /* HAVE_LIBUTIL_H */
6015#endif /* HAVE_PTY_H */
6016#ifdef HAVE_STROPTS_H
6017#include <stropts.h>
6018#endif
6019#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX */
6020
6021#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)
6022PyDoc_STRVAR(posix_openpty__doc__,
6023"openpty() -> (master_fd, slave_fd)\n\n\
6024Open a pseudo-terminal, returning open fd's for both master and slave end.\n");
6025
6026static PyObject *
6027posix_openpty(PyObject *self, PyObject *noargs)
6028{
6029    int master_fd = -1, slave_fd = -1;
6030#ifndef HAVE_OPENPTY
6031    char * slave_name;
6032#endif
6033#if defined(HAVE_DEV_PTMX) && !defined(HAVE_OPENPTY) && !defined(HAVE__GETPTY)
6034    PyOS_sighandler_t sig_saved;
6035#ifdef sun
6036    extern char *ptsname(int fildes);
6037#endif
6038#endif
6039
6040#ifdef HAVE_OPENPTY
6041    if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)
6042        goto posix_error;
6043
6044    if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
6045        goto error;
6046    if (_Py_set_inheritable(slave_fd, 0, NULL) < 0)
6047        goto error;
6048
6049#elif defined(HAVE__GETPTY)
6050    slave_name = _getpty(&master_fd, O_RDWR, 0666, 0);
6051    if (slave_name == NULL)
6052        goto posix_error;
6053    if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
6054        goto error;
6055
6056    slave_fd = _Py_open(slave_name, O_RDWR);
6057    if (slave_fd < 0)
6058        goto posix_error;
6059
6060#else
6061    master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
6062    if (master_fd < 0)
6063        goto posix_error;
6064
6065    sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
6066
6067    /* change permission of slave */
6068    if (grantpt(master_fd) < 0) {
6069        PyOS_setsig(SIGCHLD, sig_saved);
6070        goto posix_error;
6071    }
6072
6073    /* unlock slave */
6074    if (unlockpt(master_fd) < 0) {
6075        PyOS_setsig(SIGCHLD, sig_saved);
6076        goto posix_error;
6077    }
6078
6079    PyOS_setsig(SIGCHLD, sig_saved);
6080
6081    slave_name = ptsname(master_fd); /* get name of slave */
6082    if (slave_name == NULL)
6083        goto posix_error;
6084
6085    slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
6086    if (slave_fd < 0)
6087        goto posix_error;
6088
6089    if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
6090        goto posix_error;
6091
6092#if !defined(__CYGWIN__) && !defined(HAVE_DEV_PTC)
6093    ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */
6094    ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */
6095#ifndef __hpux
6096    ioctl(slave_fd, I_PUSH, "ttcompat"); /* push ttcompat */
6097#endif /* __hpux */
6098#endif /* HAVE_CYGWIN */
6099#endif /* HAVE_OPENPTY */
6100
6101    return Py_BuildValue("(ii)", master_fd, slave_fd);
6102
6103posix_error:
6104    posix_error();
6105#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY)
6106error:
6107#endif
6108    if (master_fd != -1)
6109        close(master_fd);
6110    if (slave_fd != -1)
6111        close(slave_fd);
6112    return NULL;
6113}
6114#endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */
6115
6116#ifdef HAVE_FORKPTY
6117PyDoc_STRVAR(posix_forkpty__doc__,
6118"forkpty() -> (pid, master_fd)\n\n\
6119Fork a new process with a new pseudo-terminal as controlling tty.\n\n\
6120Like fork(), return 0 as pid to child process, and PID of child to parent.\n\
6121To both, return fd of newly opened pseudo-terminal.\n");
6122
6123static PyObject *
6124posix_forkpty(PyObject *self, PyObject *noargs)
6125{
6126    int master_fd = -1, result = 0;
6127    pid_t pid;
6128
6129    _PyImport_AcquireLock();
6130    pid = forkpty(&master_fd, NULL, NULL, NULL);
6131    if (pid == 0) {
6132        /* child: this clobbers and resets the import lock. */
6133        PyOS_AfterFork();
6134    } else {
6135        /* parent: release the import lock. */
6136        result = _PyImport_ReleaseLock();
6137    }
6138    if (pid == -1)
6139        return posix_error();
6140    if (result < 0) {
6141        /* Don't clobber the OSError if the fork failed. */
6142        PyErr_SetString(PyExc_RuntimeError,
6143                        "not holding the import lock");
6144        return NULL;
6145    }
6146    return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd);
6147}
6148#endif
6149
6150
6151#ifdef HAVE_GETEGID
6152PyDoc_STRVAR(posix_getegid__doc__,
6153"getegid() -> egid\n\n\
6154Return the current process's effective group id.");
6155
6156static PyObject *
6157posix_getegid(PyObject *self, PyObject *noargs)
6158{
6159    return _PyLong_FromGid(getegid());
6160}
6161#endif
6162
6163
6164#ifdef HAVE_GETEUID
6165PyDoc_STRVAR(posix_geteuid__doc__,
6166"geteuid() -> euid\n\n\
6167Return the current process's effective user id.");
6168
6169static PyObject *
6170posix_geteuid(PyObject *self, PyObject *noargs)
6171{
6172    return _PyLong_FromUid(geteuid());
6173}
6174#endif
6175
6176
6177#ifdef HAVE_GETGID
6178PyDoc_STRVAR(posix_getgid__doc__,
6179"getgid() -> gid\n\n\
6180Return the current process's group id.");
6181
6182static PyObject *
6183posix_getgid(PyObject *self, PyObject *noargs)
6184{
6185    return _PyLong_FromGid(getgid());
6186}
6187#endif
6188
6189
6190PyDoc_STRVAR(posix_getpid__doc__,
6191"getpid() -> pid\n\n\
6192Return the current process id");
6193
6194static PyObject *
6195posix_getpid(PyObject *self, PyObject *noargs)
6196{
6197    return PyLong_FromPid(getpid());
6198}
6199
6200#ifdef HAVE_GETGROUPLIST
6201PyDoc_STRVAR(posix_getgrouplist__doc__,
6202"getgrouplist(user, group) -> list of groups to which a user belongs\n\n\
6203Returns a list of groups to which a user belongs.\n\n\
6204    user: username to lookup\n\
6205    group: base group id of the user");
6206
6207static PyObject *
6208posix_getgrouplist(PyObject *self, PyObject *args)
6209{
6210#ifdef NGROUPS_MAX
6211#define MAX_GROUPS NGROUPS_MAX
6212#else
6213    /* defined to be 16 on Solaris7, so this should be a small number */
6214#define MAX_GROUPS 64
6215#endif
6216
6217    const char *user;
6218    int i, ngroups;
6219    PyObject *list;
6220#ifdef __APPLE__
6221    int *groups, basegid;
6222#else
6223    gid_t *groups, basegid;
6224#endif
6225    ngroups = MAX_GROUPS;
6226
6227#ifdef __APPLE__
6228    if (!PyArg_ParseTuple(args, "si:getgrouplist", &user, &basegid))
6229        return NULL;
6230#else
6231    if (!PyArg_ParseTuple(args, "sO&:getgrouplist", &user,
6232                          _Py_Gid_Converter, &basegid))
6233        return NULL;
6234#endif
6235
6236#ifdef __APPLE__
6237    groups = PyMem_New(int, ngroups);
6238#else
6239    groups = PyMem_New(gid_t, ngroups);
6240#endif
6241    if (groups == NULL)
6242        return PyErr_NoMemory();
6243
6244    if (getgrouplist(user, basegid, groups, &ngroups) == -1) {
6245        PyMem_Del(groups);
6246        return posix_error();
6247    }
6248
6249    list = PyList_New(ngroups);
6250    if (list == NULL) {
6251        PyMem_Del(groups);
6252        return NULL;
6253    }
6254
6255    for (i = 0; i < ngroups; i++) {
6256#ifdef __APPLE__
6257        PyObject *o = PyLong_FromUnsignedLong((unsigned long)groups[i]);
6258#else
6259        PyObject *o = _PyLong_FromGid(groups[i]);
6260#endif
6261        if (o == NULL) {
6262            Py_DECREF(list);
6263            PyMem_Del(groups);
6264            return NULL;
6265        }
6266        PyList_SET_ITEM(list, i, o);
6267    }
6268
6269    PyMem_Del(groups);
6270
6271    return list;
6272}
6273#endif
6274
6275#ifdef HAVE_GETGROUPS
6276PyDoc_STRVAR(posix_getgroups__doc__,
6277"getgroups() -> list of group IDs\n\n\
6278Return list of supplemental group IDs for the process.");
6279
6280static PyObject *
6281posix_getgroups(PyObject *self, PyObject *noargs)
6282{
6283    PyObject *result = NULL;
6284
6285#ifdef NGROUPS_MAX
6286#define MAX_GROUPS NGROUPS_MAX
6287#else
6288    /* defined to be 16 on Solaris7, so this should be a small number */
6289#define MAX_GROUPS 64
6290#endif
6291    gid_t grouplist[MAX_GROUPS];
6292
6293    /* On MacOSX getgroups(2) can return more than MAX_GROUPS results
6294     * This is a helper variable to store the intermediate result when
6295     * that happens.
6296     *
6297     * To keep the code readable the OSX behaviour is unconditional,
6298     * according to the POSIX spec this should be safe on all unix-y
6299     * systems.
6300     */
6301    gid_t* alt_grouplist = grouplist;
6302    int n;
6303
6304#ifdef __APPLE__
6305    /* Issue #17557: As of OS X 10.8, getgroups(2) no longer raises EINVAL if
6306     * there are more groups than can fit in grouplist.  Therefore, on OS X
6307     * always first call getgroups with length 0 to get the actual number
6308     * of groups.
6309     */
6310    n = getgroups(0, NULL);
6311    if (n < 0) {
6312        return posix_error();
6313    } else if (n <= MAX_GROUPS) {
6314        /* groups will fit in existing array */
6315        alt_grouplist = grouplist;
6316    } else {
6317        alt_grouplist = PyMem_New(gid_t, n);
6318        if (alt_grouplist == NULL) {
6319            errno = EINVAL;
6320            return posix_error();
6321        }
6322    }
6323
6324    n = getgroups(n, alt_grouplist);
6325    if (n == -1) {
6326        if (alt_grouplist != grouplist) {
6327            PyMem_Free(alt_grouplist);
6328        }
6329        return posix_error();
6330    }
6331#else
6332    n = getgroups(MAX_GROUPS, grouplist);
6333    if (n < 0) {
6334        if (errno == EINVAL) {
6335            n = getgroups(0, NULL);
6336            if (n == -1) {
6337                return posix_error();
6338            }
6339            if (n == 0) {
6340                /* Avoid malloc(0) */
6341                alt_grouplist = grouplist;
6342            } else {
6343                alt_grouplist = PyMem_New(gid_t, n);
6344                if (alt_grouplist == NULL) {
6345                    errno = EINVAL;
6346                    return posix_error();
6347                }
6348                n = getgroups(n, alt_grouplist);
6349                if (n == -1) {
6350                    PyMem_Free(alt_grouplist);
6351                    return posix_error();
6352                }
6353            }
6354        } else {
6355            return posix_error();
6356        }
6357    }
6358#endif
6359
6360    result = PyList_New(n);
6361    if (result != NULL) {
6362        int i;
6363        for (i = 0; i < n; ++i) {
6364            PyObject *o = _PyLong_FromGid(alt_grouplist[i]);
6365            if (o == NULL) {
6366                Py_DECREF(result);
6367                result = NULL;
6368                break;
6369            }
6370            PyList_SET_ITEM(result, i, o);
6371        }
6372    }
6373
6374    if (alt_grouplist != grouplist) {
6375        PyMem_Free(alt_grouplist);
6376    }
6377
6378    return result;
6379}
6380#endif
6381
6382#ifdef HAVE_INITGROUPS
6383PyDoc_STRVAR(posix_initgroups__doc__,
6384"initgroups(username, gid) -> None\n\n\
6385Call the system initgroups() to initialize the group access list with all of\n\
6386the groups of which the specified username is a member, plus the specified\n\
6387group id.");
6388
6389static PyObject *
6390posix_initgroups(PyObject *self, PyObject *args)
6391{
6392    PyObject *oname;
6393    char *username;
6394    int res;
6395#ifdef __APPLE__
6396    int gid;
6397#else
6398    gid_t gid;
6399#endif
6400
6401#ifdef __APPLE__
6402    if (!PyArg_ParseTuple(args, "O&i:initgroups",
6403                          PyUnicode_FSConverter, &oname,
6404                          &gid))
6405#else
6406    if (!PyArg_ParseTuple(args, "O&O&:initgroups",
6407                          PyUnicode_FSConverter, &oname,
6408                          _Py_Gid_Converter, &gid))
6409#endif
6410        return NULL;
6411    username = PyBytes_AS_STRING(oname);
6412
6413    res = initgroups(username, gid);
6414    Py_DECREF(oname);
6415    if (res == -1)
6416        return PyErr_SetFromErrno(PyExc_OSError);
6417
6418    Py_INCREF(Py_None);
6419    return Py_None;
6420}
6421#endif
6422
6423#ifdef HAVE_GETPGID
6424PyDoc_STRVAR(posix_getpgid__doc__,
6425"getpgid(pid) -> pgid\n\n\
6426Call the system call getpgid().");
6427
6428static PyObject *
6429posix_getpgid(PyObject *self, PyObject *args)
6430{
6431    pid_t pid, pgid;
6432    if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getpgid", &pid))
6433        return NULL;
6434    pgid = getpgid(pid);
6435    if (pgid < 0)
6436        return posix_error();
6437    return PyLong_FromPid(pgid);
6438}
6439#endif /* HAVE_GETPGID */
6440
6441
6442#ifdef HAVE_GETPGRP
6443PyDoc_STRVAR(posix_getpgrp__doc__,
6444"getpgrp() -> pgrp\n\n\
6445Return the current process group id.");
6446
6447static PyObject *
6448posix_getpgrp(PyObject *self, PyObject *noargs)
6449{
6450#ifdef GETPGRP_HAVE_ARG
6451    return PyLong_FromPid(getpgrp(0));
6452#else /* GETPGRP_HAVE_ARG */
6453    return PyLong_FromPid(getpgrp());
6454#endif /* GETPGRP_HAVE_ARG */
6455}
6456#endif /* HAVE_GETPGRP */
6457
6458
6459#ifdef HAVE_SETPGRP
6460PyDoc_STRVAR(posix_setpgrp__doc__,
6461"setpgrp()\n\n\
6462Make this process the process group leader.");
6463
6464static PyObject *
6465posix_setpgrp(PyObject *self, PyObject *noargs)
6466{
6467#ifdef SETPGRP_HAVE_ARG
6468    if (setpgrp(0, 0) < 0)
6469#else /* SETPGRP_HAVE_ARG */
6470    if (setpgrp() < 0)
6471#endif /* SETPGRP_HAVE_ARG */
6472        return posix_error();
6473    Py_INCREF(Py_None);
6474    return Py_None;
6475}
6476
6477#endif /* HAVE_SETPGRP */
6478
6479#ifdef HAVE_GETPPID
6480
6481#ifdef MS_WINDOWS
6482#include <tlhelp32.h>
6483
6484static PyObject*
6485win32_getppid()
6486{
6487    HANDLE snapshot;
6488    pid_t mypid;
6489    PyObject* result = NULL;
6490    BOOL have_record;
6491    PROCESSENTRY32 pe;
6492
6493    mypid = getpid(); /* This function never fails */
6494
6495    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
6496    if (snapshot == INVALID_HANDLE_VALUE)
6497        return PyErr_SetFromWindowsErr(GetLastError());
6498
6499    pe.dwSize = sizeof(pe);
6500    have_record = Process32First(snapshot, &pe);
6501    while (have_record) {
6502        if (mypid == (pid_t)pe.th32ProcessID) {
6503            /* We could cache the ulong value in a static variable. */
6504            result = PyLong_FromPid((pid_t)pe.th32ParentProcessID);
6505            break;
6506        }
6507
6508        have_record = Process32Next(snapshot, &pe);
6509    }
6510
6511    /* If our loop exits and our pid was not found (result will be NULL)
6512     * then GetLastError will return ERROR_NO_MORE_FILES. This is an
6513     * error anyway, so let's raise it. */
6514    if (!result)
6515        result = PyErr_SetFromWindowsErr(GetLastError());
6516
6517    CloseHandle(snapshot);
6518
6519    return result;
6520}
6521#endif /*MS_WINDOWS*/
6522
6523PyDoc_STRVAR(posix_getppid__doc__,
6524"getppid() -> ppid\n\n\
6525Return the parent's process id.  If the parent process has already exited,\n\
6526Windows machines will still return its id; others systems will return the id\n\
6527of the 'init' process (1).");
6528
6529static PyObject *
6530posix_getppid(PyObject *self, PyObject *noargs)
6531{
6532#ifdef MS_WINDOWS
6533    return win32_getppid();
6534#else
6535    return PyLong_FromPid(getppid());
6536#endif
6537}
6538#endif /* HAVE_GETPPID */
6539
6540
6541#ifdef HAVE_GETLOGIN
6542PyDoc_STRVAR(posix_getlogin__doc__,
6543"getlogin() -> string\n\n\
6544Return the actual login name.");
6545
6546static PyObject *
6547posix_getlogin(PyObject *self, PyObject *noargs)
6548{
6549    PyObject *result = NULL;
6550#ifdef MS_WINDOWS
6551    wchar_t user_name[UNLEN + 1];
6552    DWORD num_chars = Py_ARRAY_LENGTH(user_name);
6553
6554    if (GetUserNameW(user_name, &num_chars)) {
6555        /* num_chars is the number of unicode chars plus null terminator */
6556        result = PyUnicode_FromWideChar(user_name, num_chars - 1);
6557    }
6558    else
6559        result = PyErr_SetFromWindowsErr(GetLastError());
6560#else
6561    char *name;
6562    int old_errno = errno;
6563
6564    errno = 0;
6565    name = getlogin();
6566    if (name == NULL) {
6567        if (errno)
6568            posix_error();
6569        else
6570            PyErr_SetString(PyExc_OSError, "unable to determine login name");
6571    }
6572    else
6573        result = PyUnicode_DecodeFSDefault(name);
6574    errno = old_errno;
6575#endif
6576    return result;
6577}
6578#endif /* HAVE_GETLOGIN */
6579
6580#ifdef HAVE_GETUID
6581PyDoc_STRVAR(posix_getuid__doc__,
6582"getuid() -> uid\n\n\
6583Return the current process's user id.");
6584
6585static PyObject *
6586posix_getuid(PyObject *self, PyObject *noargs)
6587{
6588    return _PyLong_FromUid(getuid());
6589}
6590#endif
6591
6592
6593#ifdef HAVE_KILL
6594PyDoc_STRVAR(posix_kill__doc__,
6595"kill(pid, sig)\n\n\
6596Kill a process with a signal.");
6597
6598static PyObject *
6599posix_kill(PyObject *self, PyObject *args)
6600{
6601    pid_t pid;
6602    int sig;
6603    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:kill", &pid, &sig))
6604        return NULL;
6605    if (kill(pid, sig) == -1)
6606        return posix_error();
6607    Py_INCREF(Py_None);
6608    return Py_None;
6609}
6610#endif
6611
6612#ifdef HAVE_KILLPG
6613PyDoc_STRVAR(posix_killpg__doc__,
6614"killpg(pgid, sig)\n\n\
6615Kill a process group with a signal.");
6616
6617static PyObject *
6618posix_killpg(PyObject *self, PyObject *args)
6619{
6620    int sig;
6621    pid_t pgid;
6622    /* XXX some man pages make the `pgid` parameter an int, others
6623       a pid_t. Since getpgrp() returns a pid_t, we assume killpg should
6624       take the same type. Moreover, pid_t is always at least as wide as
6625       int (else compilation of this module fails), which is safe. */
6626    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:killpg", &pgid, &sig))
6627        return NULL;
6628    if (killpg(pgid, sig) == -1)
6629        return posix_error();
6630    Py_INCREF(Py_None);
6631    return Py_None;
6632}
6633#endif
6634
6635#ifdef MS_WINDOWS
6636PyDoc_STRVAR(win32_kill__doc__,
6637"kill(pid, sig)\n\n\
6638Kill a process with a signal.");
6639
6640static PyObject *
6641win32_kill(PyObject *self, PyObject *args)
6642{
6643    PyObject *result;
6644    pid_t pid;
6645    DWORD sig, err;
6646    HANDLE handle;
6647
6648    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "k:kill", &pid, &sig))
6649        return NULL;
6650
6651    /* Console processes which share a common console can be sent CTRL+C or
6652       CTRL+BREAK events, provided they handle said events. */
6653    if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) {
6654        if (GenerateConsoleCtrlEvent(sig, (DWORD)pid) == 0) {
6655            err = GetLastError();
6656            PyErr_SetFromWindowsErr(err);
6657        }
6658        else
6659            Py_RETURN_NONE;
6660    }
6661
6662    /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
6663       attempt to open and terminate the process. */
6664    handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
6665    if (handle == NULL) {
6666        err = GetLastError();
6667        return PyErr_SetFromWindowsErr(err);
6668    }
6669
6670    if (TerminateProcess(handle, sig) == 0) {
6671        err = GetLastError();
6672        result = PyErr_SetFromWindowsErr(err);
6673    } else {
6674        Py_INCREF(Py_None);
6675        result = Py_None;
6676    }
6677
6678    CloseHandle(handle);
6679    return result;
6680}
6681#endif /* MS_WINDOWS */
6682
6683#ifdef HAVE_PLOCK
6684
6685#ifdef HAVE_SYS_LOCK_H
6686#include <sys/lock.h>
6687#endif
6688
6689PyDoc_STRVAR(posix_plock__doc__,
6690"plock(op)\n\n\
6691Lock program segments into memory.");
6692
6693static PyObject *
6694posix_plock(PyObject *self, PyObject *args)
6695{
6696    int op;
6697    if (!PyArg_ParseTuple(args, "i:plock", &op))
6698        return NULL;
6699    if (plock(op) == -1)
6700        return posix_error();
6701    Py_INCREF(Py_None);
6702    return Py_None;
6703}
6704#endif
6705
6706#ifdef HAVE_SETUID
6707PyDoc_STRVAR(posix_setuid__doc__,
6708"setuid(uid)\n\n\
6709Set the current process's user id.");
6710
6711static PyObject *
6712posix_setuid(PyObject *self, PyObject *args)
6713{
6714    uid_t uid;
6715    if (!PyArg_ParseTuple(args, "O&:setuid", _Py_Uid_Converter, &uid))
6716        return NULL;
6717    if (setuid(uid) < 0)
6718        return posix_error();
6719    Py_INCREF(Py_None);
6720    return Py_None;
6721}
6722#endif /* HAVE_SETUID */
6723
6724
6725#ifdef HAVE_SETEUID
6726PyDoc_STRVAR(posix_seteuid__doc__,
6727"seteuid(uid)\n\n\
6728Set the current process's effective user id.");
6729
6730static PyObject *
6731posix_seteuid (PyObject *self, PyObject *args)
6732{
6733    uid_t euid;
6734    if (!PyArg_ParseTuple(args, "O&:seteuid", _Py_Uid_Converter, &euid))
6735        return NULL;
6736    if (seteuid(euid) < 0) {
6737        return posix_error();
6738    } else {
6739        Py_INCREF(Py_None);
6740        return Py_None;
6741    }
6742}
6743#endif /* HAVE_SETEUID */
6744
6745#ifdef HAVE_SETEGID
6746PyDoc_STRVAR(posix_setegid__doc__,
6747"setegid(gid)\n\n\
6748Set the current process's effective group id.");
6749
6750static PyObject *
6751posix_setegid (PyObject *self, PyObject *args)
6752{
6753    gid_t egid;
6754    if (!PyArg_ParseTuple(args, "O&:setegid", _Py_Gid_Converter, &egid))
6755        return NULL;
6756    if (setegid(egid) < 0) {
6757        return posix_error();
6758    } else {
6759        Py_INCREF(Py_None);
6760        return Py_None;
6761    }
6762}
6763#endif /* HAVE_SETEGID */
6764
6765#ifdef HAVE_SETREUID
6766PyDoc_STRVAR(posix_setreuid__doc__,
6767"setreuid(ruid, euid)\n\n\
6768Set the current process's real and effective user ids.");
6769
6770static PyObject *
6771posix_setreuid (PyObject *self, PyObject *args)
6772{
6773    uid_t ruid, euid;
6774    if (!PyArg_ParseTuple(args, "O&O&:setreuid",
6775                          _Py_Uid_Converter, &ruid,
6776                          _Py_Uid_Converter, &euid))
6777        return NULL;
6778    if (setreuid(ruid, euid) < 0) {
6779        return posix_error();
6780    } else {
6781        Py_INCREF(Py_None);
6782        return Py_None;
6783    }
6784}
6785#endif /* HAVE_SETREUID */
6786
6787#ifdef HAVE_SETREGID
6788PyDoc_STRVAR(posix_setregid__doc__,
6789"setregid(rgid, egid)\n\n\
6790Set the current process's real and effective group ids.");
6791
6792static PyObject *
6793posix_setregid (PyObject *self, PyObject *args)
6794{
6795    gid_t rgid, egid;
6796    if (!PyArg_ParseTuple(args, "O&O&:setregid",
6797                          _Py_Gid_Converter, &rgid,
6798                          _Py_Gid_Converter, &egid))
6799        return NULL;
6800    if (setregid(rgid, egid) < 0) {
6801        return posix_error();
6802    } else {
6803        Py_INCREF(Py_None);
6804        return Py_None;
6805    }
6806}
6807#endif /* HAVE_SETREGID */
6808
6809#ifdef HAVE_SETGID
6810PyDoc_STRVAR(posix_setgid__doc__,
6811"setgid(gid)\n\n\
6812Set the current process's group id.");
6813
6814static PyObject *
6815posix_setgid(PyObject *self, PyObject *args)
6816{
6817    gid_t gid;
6818    if (!PyArg_ParseTuple(args, "O&:setgid", _Py_Gid_Converter, &gid))
6819        return NULL;
6820    if (setgid(gid) < 0)
6821        return posix_error();
6822    Py_INCREF(Py_None);
6823    return Py_None;
6824}
6825#endif /* HAVE_SETGID */
6826
6827#ifdef HAVE_SETGROUPS
6828PyDoc_STRVAR(posix_setgroups__doc__,
6829"setgroups(list)\n\n\
6830Set the groups of the current process to list.");
6831
6832static PyObject *
6833posix_setgroups(PyObject *self, PyObject *groups)
6834{
6835    int i, len;
6836    gid_t grouplist[MAX_GROUPS];
6837
6838    if (!PySequence_Check(groups)) {
6839        PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence");
6840        return NULL;
6841    }
6842    len = PySequence_Size(groups);
6843    if (len > MAX_GROUPS) {
6844        PyErr_SetString(PyExc_ValueError, "too many groups");
6845        return NULL;
6846    }
6847    for(i = 0; i < len; i++) {
6848        PyObject *elem;
6849        elem = PySequence_GetItem(groups, i);
6850        if (!elem)
6851            return NULL;
6852        if (!PyLong_Check(elem)) {
6853            PyErr_SetString(PyExc_TypeError,
6854                            "groups must be integers");
6855            Py_DECREF(elem);
6856            return NULL;
6857        } else {
6858            if (!_Py_Gid_Converter(elem, &grouplist[i])) {
6859                Py_DECREF(elem);
6860                return NULL;
6861            }
6862        }
6863        Py_DECREF(elem);
6864    }
6865
6866    if (setgroups(len, grouplist) < 0)
6867        return posix_error();
6868    Py_INCREF(Py_None);
6869    return Py_None;
6870}
6871#endif /* HAVE_SETGROUPS */
6872
6873#if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
6874static PyObject *
6875wait_helper(pid_t pid, int status, struct rusage *ru)
6876{
6877    PyObject *result;
6878    static PyObject *struct_rusage;
6879    _Py_IDENTIFIER(struct_rusage);
6880
6881    if (pid == -1)
6882        return posix_error();
6883
6884    if (struct_rusage == NULL) {
6885        PyObject *m = PyImport_ImportModuleNoBlock("resource");
6886        if (m == NULL)
6887            return NULL;
6888        struct_rusage = _PyObject_GetAttrId(m, &PyId_struct_rusage);
6889        Py_DECREF(m);
6890        if (struct_rusage == NULL)
6891            return NULL;
6892    }
6893
6894    /* XXX(nnorwitz): Copied (w/mods) from resource.c, there should be only one. */
6895    result = PyStructSequence_New((PyTypeObject*) struct_rusage);
6896    if (!result)
6897        return NULL;
6898
6899#ifndef doubletime
6900#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
6901#endif
6902
6903    PyStructSequence_SET_ITEM(result, 0,
6904                              PyFloat_FromDouble(doubletime(ru->ru_utime)));
6905    PyStructSequence_SET_ITEM(result, 1,
6906                              PyFloat_FromDouble(doubletime(ru->ru_stime)));
6907#define SET_INT(result, index, value)\
6908        PyStructSequence_SET_ITEM(result, index, PyLong_FromLong(value))
6909    SET_INT(result, 2, ru->ru_maxrss);
6910    SET_INT(result, 3, ru->ru_ixrss);
6911    SET_INT(result, 4, ru->ru_idrss);
6912    SET_INT(result, 5, ru->ru_isrss);
6913    SET_INT(result, 6, ru->ru_minflt);
6914    SET_INT(result, 7, ru->ru_majflt);
6915    SET_INT(result, 8, ru->ru_nswap);
6916    SET_INT(result, 9, ru->ru_inblock);
6917    SET_INT(result, 10, ru->ru_oublock);
6918    SET_INT(result, 11, ru->ru_msgsnd);
6919    SET_INT(result, 12, ru->ru_msgrcv);
6920    SET_INT(result, 13, ru->ru_nsignals);
6921    SET_INT(result, 14, ru->ru_nvcsw);
6922    SET_INT(result, 15, ru->ru_nivcsw);
6923#undef SET_INT
6924
6925    if (PyErr_Occurred()) {
6926        Py_DECREF(result);
6927        return NULL;
6928    }
6929
6930    return Py_BuildValue("NiN", PyLong_FromPid(pid), status, result);
6931}
6932#endif /* HAVE_WAIT3 || HAVE_WAIT4 */
6933
6934#ifdef HAVE_WAIT3
6935PyDoc_STRVAR(posix_wait3__doc__,
6936"wait3(options) -> (pid, status, rusage)\n\n\
6937Wait for completion of a child process.");
6938
6939static PyObject *
6940posix_wait3(PyObject *self, PyObject *args)
6941{
6942    pid_t pid;
6943    int options;
6944    struct rusage ru;
6945    WAIT_TYPE status;
6946    WAIT_STATUS_INT(status) = 0;
6947
6948    if (!PyArg_ParseTuple(args, "i:wait3", &options))
6949        return NULL;
6950
6951    Py_BEGIN_ALLOW_THREADS
6952    pid = wait3(&status, options, &ru);
6953    Py_END_ALLOW_THREADS
6954
6955    return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
6956}
6957#endif /* HAVE_WAIT3 */
6958
6959#ifdef HAVE_WAIT4
6960PyDoc_STRVAR(posix_wait4__doc__,
6961"wait4(pid, options) -> (pid, status, rusage)\n\n\
6962Wait for completion of a given child process.");
6963
6964static PyObject *
6965posix_wait4(PyObject *self, PyObject *args)
6966{
6967    pid_t pid;
6968    int options;
6969    struct rusage ru;
6970    WAIT_TYPE status;
6971    WAIT_STATUS_INT(status) = 0;
6972
6973    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:wait4", &pid, &options))
6974        return NULL;
6975
6976    Py_BEGIN_ALLOW_THREADS
6977    pid = wait4(pid, &status, options, &ru);
6978    Py_END_ALLOW_THREADS
6979
6980    return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
6981}
6982#endif /* HAVE_WAIT4 */
6983
6984#if defined(HAVE_WAITID) && !defined(__APPLE__)
6985PyDoc_STRVAR(posix_waitid__doc__,
6986"waitid(idtype, id, options) -> waitid_result\n\n\
6987Wait for the completion of one or more child processes.\n\n\
6988idtype can be P_PID, P_PGID or P_ALL.\n\
6989id specifies the pid to wait on.\n\
6990options is constructed from the ORing of one or more of WEXITED, WSTOPPED\n\
6991or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.\n\
6992Returns either waitid_result or None if WNOHANG is specified and there are\n\
6993no children in a waitable state.");
6994
6995static PyObject *
6996posix_waitid(PyObject *self, PyObject *args)
6997{
6998    PyObject *result;
6999    idtype_t idtype;
7000    id_t id;
7001    int options, res;
7002    siginfo_t si;
7003    si.si_pid = 0;
7004    if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID "i:waitid", &idtype, &id, &options))
7005        return NULL;
7006    Py_BEGIN_ALLOW_THREADS
7007    res = waitid(idtype, id, &si, options);
7008    Py_END_ALLOW_THREADS
7009    if (res == -1)
7010        return posix_error();
7011
7012    if (si.si_pid == 0)
7013        Py_RETURN_NONE;
7014
7015    result = PyStructSequence_New(&WaitidResultType);
7016    if (!result)
7017        return NULL;
7018
7019    PyStructSequence_SET_ITEM(result, 0, PyLong_FromPid(si.si_pid));
7020    PyStructSequence_SET_ITEM(result, 1, _PyLong_FromUid(si.si_uid));
7021    PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong((long)(si.si_signo)));
7022    PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong((long)(si.si_status)));
7023    PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong((long)(si.si_code)));
7024    if (PyErr_Occurred()) {
7025        Py_DECREF(result);
7026        return NULL;
7027    }
7028
7029    return result;
7030}
7031#endif
7032
7033#ifdef HAVE_WAITPID
7034PyDoc_STRVAR(posix_waitpid__doc__,
7035"waitpid(pid, options) -> (pid, status)\n\n\
7036Wait for completion of a given child process.");
7037
7038static PyObject *
7039posix_waitpid(PyObject *self, PyObject *args)
7040{
7041    pid_t pid;
7042    int options;
7043    WAIT_TYPE status;
7044    WAIT_STATUS_INT(status) = 0;
7045
7046    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:waitpid", &pid, &options))
7047        return NULL;
7048    Py_BEGIN_ALLOW_THREADS
7049    pid = waitpid(pid, &status, options);
7050    Py_END_ALLOW_THREADS
7051    if (pid == -1)
7052        return posix_error();
7053
7054    return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
7055}
7056
7057#elif defined(HAVE_CWAIT)
7058
7059/* MS C has a variant of waitpid() that's usable for most purposes. */
7060PyDoc_STRVAR(posix_waitpid__doc__,
7061"waitpid(pid, options) -> (pid, status << 8)\n\n"
7062"Wait for completion of a given process.  options is ignored on Windows.");
7063
7064static PyObject *
7065posix_waitpid(PyObject *self, PyObject *args)
7066{
7067    Py_intptr_t pid;
7068    int status, options;
7069
7070    if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:waitpid", &pid, &options))
7071        return NULL;
7072    Py_BEGIN_ALLOW_THREADS
7073    pid = _cwait(&status, pid, options);
7074    Py_END_ALLOW_THREADS
7075    if (pid == -1)
7076        return posix_error();
7077
7078    /* shift the status left a byte so this is more like the POSIX waitpid */
7079    return Py_BuildValue(_Py_PARSE_INTPTR "i", pid, status << 8);
7080}
7081#endif /* HAVE_WAITPID || HAVE_CWAIT */
7082
7083#ifdef HAVE_WAIT
7084PyDoc_STRVAR(posix_wait__doc__,
7085"wait() -> (pid, status)\n\n\
7086Wait for completion of a child process.");
7087
7088static PyObject *
7089posix_wait(PyObject *self, PyObject *noargs)
7090{
7091    pid_t pid;
7092    WAIT_TYPE status;
7093    WAIT_STATUS_INT(status) = 0;
7094
7095    Py_BEGIN_ALLOW_THREADS
7096    pid = wait(&status);
7097    Py_END_ALLOW_THREADS
7098    if (pid == -1)
7099        return posix_error();
7100
7101    return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
7102}
7103#endif
7104
7105
7106#if defined(HAVE_READLINK) || defined(MS_WINDOWS)
7107PyDoc_STRVAR(readlink__doc__,
7108"readlink(path, *, dir_fd=None) -> path\n\n\
7109Return a string representing the path to which the symbolic link points.\n\
7110\n\
7111If dir_fd is not None, it should be a file descriptor open to a directory,\n\
7112  and path should be relative; path will then be relative to that directory.\n\
7113dir_fd may not be implemented on your platform.\n\
7114  If it is unavailable, using it will raise a NotImplementedError.");
7115#endif
7116
7117#ifdef HAVE_READLINK
7118
7119static PyObject *
7120posix_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
7121{
7122    path_t path;
7123    int dir_fd = DEFAULT_DIR_FD;
7124    char buffer[MAXPATHLEN];
7125    ssize_t length;
7126    PyObject *return_value = NULL;
7127    static char *keywords[] = {"path", "dir_fd", NULL};
7128
7129    memset(&path, 0, sizeof(path));
7130    path.function_name = "readlink";
7131    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:readlink", keywords,
7132                          path_converter, &path,
7133#ifdef HAVE_READLINKAT
7134                          dir_fd_converter, &dir_fd
7135#else
7136                          dir_fd_unavailable, &dir_fd
7137#endif
7138                          ))
7139        return NULL;
7140
7141    Py_BEGIN_ALLOW_THREADS
7142#ifdef HAVE_READLINKAT
7143    if (dir_fd != DEFAULT_DIR_FD)
7144        length = readlinkat(dir_fd, path.narrow, buffer, sizeof(buffer));
7145    else
7146#endif
7147        length = readlink(path.narrow, buffer, sizeof(buffer));
7148    Py_END_ALLOW_THREADS
7149
7150    if (length < 0) {
7151        return_value = path_error(&path);
7152        goto exit;
7153    }
7154
7155    if (PyUnicode_Check(path.object))
7156        return_value = PyUnicode_DecodeFSDefaultAndSize(buffer, length);
7157    else
7158        return_value = PyBytes_FromStringAndSize(buffer, length);
7159exit:
7160    path_cleanup(&path);
7161    return return_value;
7162}
7163
7164
7165#endif /* HAVE_READLINK */
7166
7167
7168#ifdef HAVE_SYMLINK
7169PyDoc_STRVAR(posix_symlink__doc__,
7170"symlink(src, dst, target_is_directory=False, *, dir_fd=None)\n\n\
7171Create a symbolic link pointing to src named dst.\n\n\
7172target_is_directory is required on Windows if the target is to be\n\
7173  interpreted as a directory.  (On Windows, symlink requires\n\
7174  Windows 6.0 or greater, and raises a NotImplementedError otherwise.)\n\
7175  target_is_directory is ignored on non-Windows platforms.\n\
7176\n\
7177If dir_fd is not None, it should be a file descriptor open to a directory,\n\
7178  and path should be relative; path will then be relative to that directory.\n\
7179dir_fd may not be implemented on your platform.\n\
7180  If it is unavailable, using it will raise a NotImplementedError.");
7181
7182#if defined(MS_WINDOWS)
7183
7184/* Grab CreateSymbolicLinkW dynamically from kernel32 */
7185static DWORD (CALLBACK *Py_CreateSymbolicLinkW)(LPWSTR, LPWSTR, DWORD) = NULL;
7186static DWORD (CALLBACK *Py_CreateSymbolicLinkA)(LPSTR, LPSTR, DWORD) = NULL;
7187
7188static int
7189check_CreateSymbolicLink(void)
7190{
7191    HINSTANCE hKernel32;
7192    /* only recheck */
7193    if (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA)
7194        return 1;
7195    hKernel32 = GetModuleHandleW(L"KERNEL32");
7196    *(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32,
7197                                                        "CreateSymbolicLinkW");
7198    *(FARPROC*)&Py_CreateSymbolicLinkA = GetProcAddress(hKernel32,
7199                                                        "CreateSymbolicLinkA");
7200    return (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA);
7201}
7202
7203/* Remove the last portion of the path */
7204static void
7205_dirnameW(WCHAR *path)
7206{
7207    WCHAR *ptr;
7208
7209    /* walk the path from the end until a backslash is encountered */
7210    for(ptr = path + wcslen(path); ptr != path; ptr--) {
7211        if (*ptr == L'\\' || *ptr == L'/')
7212            break;
7213    }
7214    *ptr = 0;
7215}
7216
7217/* Remove the last portion of the path */
7218static void
7219_dirnameA(char *path)
7220{
7221    char *ptr;
7222
7223    /* walk the path from the end until a backslash is encountered */
7224    for(ptr = path + strlen(path); ptr != path; ptr--) {
7225        if (*ptr == '\\' || *ptr == '/')
7226            break;
7227    }
7228    *ptr = 0;
7229}
7230
7231/* Is this path absolute? */
7232static int
7233_is_absW(const WCHAR *path)
7234{
7235    return path[0] == L'\\' || path[0] == L'/' || path[1] == L':';
7236
7237}
7238
7239/* Is this path absolute? */
7240static int
7241_is_absA(const char *path)
7242{
7243    return path[0] == '\\' || path[0] == '/' || path[1] == ':';
7244
7245}
7246
7247/* join root and rest with a backslash */
7248static void
7249_joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest)
7250{
7251    size_t root_len;
7252
7253    if (_is_absW(rest)) {
7254        wcscpy(dest_path, rest);
7255        return;
7256    }
7257
7258    root_len = wcslen(root);
7259
7260    wcscpy(dest_path, root);
7261    if(root_len) {
7262        dest_path[root_len] = L'\\';
7263        root_len++;
7264    }
7265    wcscpy(dest_path+root_len, rest);
7266}
7267
7268/* join root and rest with a backslash */
7269static void
7270_joinA(char *dest_path, const char *root, const char *rest)
7271{
7272    size_t root_len;
7273
7274    if (_is_absA(rest)) {
7275        strcpy(dest_path, rest);
7276        return;
7277    }
7278
7279    root_len = strlen(root);
7280
7281    strcpy(dest_path, root);
7282    if(root_len) {
7283        dest_path[root_len] = '\\';
7284        root_len++;
7285    }
7286    strcpy(dest_path+root_len, rest);
7287}
7288
7289/* Return True if the path at src relative to dest is a directory */
7290static int
7291_check_dirW(WCHAR *src, WCHAR *dest)
7292{
7293    WIN32_FILE_ATTRIBUTE_DATA src_info;
7294    WCHAR dest_parent[MAX_PATH];
7295    WCHAR src_resolved[MAX_PATH] = L"";
7296
7297    /* dest_parent = os.path.dirname(dest) */
7298    wcscpy(dest_parent, dest);
7299    _dirnameW(dest_parent);
7300    /* src_resolved = os.path.join(dest_parent, src) */
7301    _joinW(src_resolved, dest_parent, src);
7302    return (
7303        GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info)
7304        && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
7305    );
7306}
7307
7308/* Return True if the path at src relative to dest is a directory */
7309static int
7310_check_dirA(char *src, char *dest)
7311{
7312    WIN32_FILE_ATTRIBUTE_DATA src_info;
7313    char dest_parent[MAX_PATH];
7314    char src_resolved[MAX_PATH] = "";
7315
7316    /* dest_parent = os.path.dirname(dest) */
7317    strcpy(dest_parent, dest);
7318    _dirnameA(dest_parent);
7319    /* src_resolved = os.path.join(dest_parent, src) */
7320    _joinA(src_resolved, dest_parent, src);
7321    return (
7322        GetFileAttributesExA(src_resolved, GetFileExInfoStandard, &src_info)
7323        && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
7324    );
7325}
7326
7327#endif
7328
7329static PyObject *
7330posix_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
7331{
7332    path_t src;
7333    path_t dst;
7334    int dir_fd = DEFAULT_DIR_FD;
7335    int target_is_directory = 0;
7336    static char *keywords[] = {"src", "dst", "target_is_directory",
7337                               "dir_fd", NULL};
7338    PyObject *return_value;
7339#ifdef MS_WINDOWS
7340    DWORD result;
7341#else
7342    int result;
7343#endif
7344
7345    memset(&src, 0, sizeof(src));
7346    src.function_name = "symlink";
7347    src.argument_name = "src";
7348    memset(&dst, 0, sizeof(dst));
7349    dst.function_name = "symlink";
7350    dst.argument_name = "dst";
7351
7352#ifdef MS_WINDOWS
7353    if (!check_CreateSymbolicLink()) {
7354        PyErr_SetString(PyExc_NotImplementedError,
7355            "CreateSymbolicLink functions not found");
7356                return NULL;
7357        }
7358    if (!win32_can_symlink) {
7359        PyErr_SetString(PyExc_OSError, "symbolic link privilege not held");
7360                return NULL;
7361        }
7362#endif
7363
7364    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|i$O&:symlink",
7365            keywords,
7366            path_converter, &src,
7367            path_converter, &dst,
7368            &target_is_directory,
7369#ifdef HAVE_SYMLINKAT
7370            dir_fd_converter, &dir_fd
7371#else
7372            dir_fd_unavailable, &dir_fd
7373#endif
7374            ))
7375        return NULL;
7376
7377    if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) {
7378        PyErr_SetString(PyExc_ValueError,
7379            "symlink: src and dst must be the same type");
7380        return_value = NULL;
7381        goto exit;
7382    }
7383
7384#ifdef MS_WINDOWS
7385
7386    Py_BEGIN_ALLOW_THREADS
7387    if (dst.wide) {
7388        /* if src is a directory, ensure target_is_directory==1 */
7389        target_is_directory |= _check_dirW(src.wide, dst.wide);
7390        result = Py_CreateSymbolicLinkW(dst.wide, src.wide,
7391                                        target_is_directory);
7392    }
7393    else {
7394        /* if src is a directory, ensure target_is_directory==1 */
7395        target_is_directory |= _check_dirA(src.narrow, dst.narrow);
7396        result = Py_CreateSymbolicLinkA(dst.narrow, src.narrow,
7397                                        target_is_directory);
7398    }
7399    Py_END_ALLOW_THREADS
7400
7401    if (!result) {
7402        return_value = path_error2(&src, &dst);
7403        goto exit;
7404    }
7405
7406#else
7407
7408    Py_BEGIN_ALLOW_THREADS
7409#if HAVE_SYMLINKAT
7410    if (dir_fd != DEFAULT_DIR_FD)
7411        result = symlinkat(src.narrow, dir_fd, dst.narrow);
7412    else
7413#endif
7414        result = symlink(src.narrow, dst.narrow);
7415    Py_END_ALLOW_THREADS
7416
7417    if (result) {
7418        return_value = path_error2(&src, &dst);
7419        goto exit;
7420    }
7421#endif
7422
7423    return_value = Py_None;
7424    Py_INCREF(Py_None);
7425    goto exit; /* silence "unused label" warning */
7426exit:
7427    path_cleanup(&src);
7428    path_cleanup(&dst);
7429    return return_value;
7430}
7431
7432#endif /* HAVE_SYMLINK */
7433
7434
7435#if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
7436
7437static PyObject *
7438win_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
7439{
7440    wchar_t *path;
7441    DWORD n_bytes_returned;
7442    DWORD io_result;
7443    PyObject *po, *result;
7444        int dir_fd;
7445    HANDLE reparse_point_handle;
7446
7447    char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
7448    REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
7449    wchar_t *print_name;
7450
7451    static char *keywords[] = {"path", "dir_fd", NULL};
7452
7453    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "U|$O&:readlink", keywords,
7454                          &po,
7455                          dir_fd_unavailable, &dir_fd
7456                          ))
7457        return NULL;
7458
7459    path = PyUnicode_AsUnicode(po);
7460    if (path == NULL)
7461        return NULL;
7462
7463    /* First get a handle to the reparse point */
7464    Py_BEGIN_ALLOW_THREADS
7465    reparse_point_handle = CreateFileW(
7466        path,
7467        0,
7468        0,
7469        0,
7470        OPEN_EXISTING,
7471        FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
7472        0);
7473    Py_END_ALLOW_THREADS
7474
7475    if (reparse_point_handle==INVALID_HANDLE_VALUE)
7476        return win32_error_object("readlink", po);
7477
7478    Py_BEGIN_ALLOW_THREADS
7479    /* New call DeviceIoControl to read the reparse point */
7480    io_result = DeviceIoControl(
7481        reparse_point_handle,
7482        FSCTL_GET_REPARSE_POINT,
7483        0, 0, /* in buffer */
7484        target_buffer, sizeof(target_buffer),
7485        &n_bytes_returned,
7486        0 /* we're not using OVERLAPPED_IO */
7487        );
7488    CloseHandle(reparse_point_handle);
7489    Py_END_ALLOW_THREADS
7490
7491    if (io_result==0)
7492        return win32_error_object("readlink", po);
7493
7494    if (rdb->ReparseTag != IO_REPARSE_TAG_SYMLINK)
7495    {
7496        PyErr_SetString(PyExc_ValueError,
7497                "not a symbolic link");
7498        return NULL;
7499    }
7500    print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer +
7501                 rdb->SymbolicLinkReparseBuffer.PrintNameOffset;
7502
7503    result = PyUnicode_FromWideChar(print_name,
7504                    rdb->SymbolicLinkReparseBuffer.PrintNameLength/2);
7505    return result;
7506}
7507
7508#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
7509
7510
7511static PyStructSequence_Field times_result_fields[] = {
7512    {"user",    "user time"},
7513    {"system",   "system time"},
7514    {"children_user",    "user time of children"},
7515    {"children_system",    "system time of children"},
7516    {"elapsed",    "elapsed time since an arbitrary point in the past"},
7517    {NULL}
7518};
7519
7520PyDoc_STRVAR(times_result__doc__,
7521"times_result: Result from os.times().\n\n\
7522This object may be accessed either as a tuple of\n\
7523  (user, system, children_user, children_system, elapsed),\n\
7524or via the attributes user, system, children_user, children_system,\n\
7525and elapsed.\n\
7526\n\
7527See os.times for more information.");
7528
7529static PyStructSequence_Desc times_result_desc = {
7530    "times_result", /* name */
7531    times_result__doc__, /* doc */
7532    times_result_fields,
7533    5
7534};
7535
7536static PyTypeObject TimesResultType;
7537
7538#ifdef MS_WINDOWS
7539#define HAVE_TIMES  /* mandatory, for the method table */
7540#endif
7541
7542#ifdef HAVE_TIMES
7543
7544static PyObject *
7545build_times_result(double user, double system,
7546    double children_user, double children_system,
7547    double elapsed)
7548{
7549    PyObject *value = PyStructSequence_New(&TimesResultType);
7550    if (value == NULL)
7551        return NULL;
7552
7553#define SET(i, field) \
7554    { \
7555    PyObject *o = PyFloat_FromDouble(field); \
7556    if (!o) { \
7557        Py_DECREF(value); \
7558        return NULL; \
7559    } \
7560    PyStructSequence_SET_ITEM(value, i, o); \
7561    } \
7562
7563    SET(0, user);
7564    SET(1, system);
7565    SET(2, children_user);
7566    SET(3, children_system);
7567    SET(4, elapsed);
7568
7569#undef SET
7570
7571    return value;
7572}
7573
7574PyDoc_STRVAR(posix_times__doc__,
7575"times() -> times_result\n\n\
7576Return an object containing floating point numbers indicating process\n\
7577times.  The object behaves like a named tuple with these fields:\n\
7578  (utime, stime, cutime, cstime, elapsed_time)");
7579
7580#if defined(MS_WINDOWS)
7581static PyObject *
7582posix_times(PyObject *self, PyObject *noargs)
7583{
7584    FILETIME create, exit, kernel, user;
7585    HANDLE hProc;
7586    hProc = GetCurrentProcess();
7587    GetProcessTimes(hProc, &create, &exit, &kernel, &user);
7588    /* The fields of a FILETIME structure are the hi and lo part
7589       of a 64-bit value expressed in 100 nanosecond units.
7590       1e7 is one second in such units; 1e-7 the inverse.
7591       429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
7592    */
7593    return build_times_result(
7594        (double)(user.dwHighDateTime*429.4967296 +
7595                 user.dwLowDateTime*1e-7),
7596        (double)(kernel.dwHighDateTime*429.4967296 +
7597                 kernel.dwLowDateTime*1e-7),
7598        (double)0,
7599        (double)0,
7600        (double)0);
7601}
7602#else /* Not Windows */
7603#define NEED_TICKS_PER_SECOND
7604static long ticks_per_second = -1;
7605static PyObject *
7606posix_times(PyObject *self, PyObject *noargs)
7607{
7608    struct tms t;
7609    clock_t c;
7610    errno = 0;
7611    c = times(&t);
7612    if (c == (clock_t) -1)
7613        return posix_error();
7614    return build_times_result(
7615                         (double)t.tms_utime / ticks_per_second,
7616                         (double)t.tms_stime / ticks_per_second,
7617                         (double)t.tms_cutime / ticks_per_second,
7618                         (double)t.tms_cstime / ticks_per_second,
7619                         (double)c / ticks_per_second);
7620}
7621#endif
7622
7623#endif /* HAVE_TIMES */
7624
7625
7626#ifdef HAVE_GETSID
7627PyDoc_STRVAR(posix_getsid__doc__,
7628"getsid(pid) -> sid\n\n\
7629Call the system call getsid().");
7630
7631static PyObject *
7632posix_getsid(PyObject *self, PyObject *args)
7633{
7634    pid_t pid;
7635    int sid;
7636    if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getsid", &pid))
7637        return NULL;
7638    sid = getsid(pid);
7639    if (sid < 0)
7640        return posix_error();
7641    return PyLong_FromLong((long)sid);
7642}
7643#endif /* HAVE_GETSID */
7644
7645
7646#ifdef HAVE_SETSID
7647PyDoc_STRVAR(posix_setsid__doc__,
7648"setsid()\n\n\
7649Call the system call setsid().");
7650
7651static PyObject *
7652posix_setsid(PyObject *self, PyObject *noargs)
7653{
7654    if (setsid() < 0)
7655        return posix_error();
7656    Py_INCREF(Py_None);
7657    return Py_None;
7658}
7659#endif /* HAVE_SETSID */
7660
7661#ifdef HAVE_SETPGID
7662PyDoc_STRVAR(posix_setpgid__doc__,
7663"setpgid(pid, pgrp)\n\n\
7664Call the system call setpgid().");
7665
7666static PyObject *
7667posix_setpgid(PyObject *self, PyObject *args)
7668{
7669    pid_t pid;
7670    int pgrp;
7671    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:setpgid", &pid, &pgrp))
7672        return NULL;
7673    if (setpgid(pid, pgrp) < 0)
7674        return posix_error();
7675    Py_INCREF(Py_None);
7676    return Py_None;
7677}
7678#endif /* HAVE_SETPGID */
7679
7680
7681#ifdef HAVE_TCGETPGRP
7682PyDoc_STRVAR(posix_tcgetpgrp__doc__,
7683"tcgetpgrp(fd) -> pgid\n\n\
7684Return the process group associated with the terminal given by a fd.");
7685
7686static PyObject *
7687posix_tcgetpgrp(PyObject *self, PyObject *args)
7688{
7689    int fd;
7690    pid_t pgid;
7691    if (!PyArg_ParseTuple(args, "i:tcgetpgrp", &fd))
7692        return NULL;
7693    pgid = tcgetpgrp(fd);
7694    if (pgid < 0)
7695        return posix_error();
7696    return PyLong_FromPid(pgid);
7697}
7698#endif /* HAVE_TCGETPGRP */
7699
7700
7701#ifdef HAVE_TCSETPGRP
7702PyDoc_STRVAR(posix_tcsetpgrp__doc__,
7703"tcsetpgrp(fd, pgid)\n\n\
7704Set the process group associated with the terminal given by a fd.");
7705
7706static PyObject *
7707posix_tcsetpgrp(PyObject *self, PyObject *args)
7708{
7709    int fd;
7710    pid_t pgid;
7711    if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID ":tcsetpgrp", &fd, &pgid))
7712        return NULL;
7713    if (tcsetpgrp(fd, pgid) < 0)
7714        return posix_error();
7715    Py_INCREF(Py_None);
7716    return Py_None;
7717}
7718#endif /* HAVE_TCSETPGRP */
7719
7720/* Functions acting on file descriptors */
7721
7722#ifdef O_CLOEXEC
7723extern int _Py_open_cloexec_works;
7724#endif
7725
7726PyDoc_STRVAR(posix_open__doc__,
7727"open(path, flags, mode=0o777, *, dir_fd=None)\n\n\
7728Open a file for low level IO.  Returns a file handle (integer).\n\
7729\n\
7730If dir_fd is not None, it should be a file descriptor open to a directory,\n\
7731  and path should be relative; path will then be relative to that directory.\n\
7732dir_fd may not be implemented on your platform.\n\
7733  If it is unavailable, using it will raise a NotImplementedError.");
7734
7735static PyObject *
7736posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
7737{
7738    path_t path;
7739    int flags;
7740    int mode = 0777;
7741    int dir_fd = DEFAULT_DIR_FD;
7742    int fd;
7743    PyObject *return_value = NULL;
7744    static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL};
7745#ifdef O_CLOEXEC
7746    int *atomic_flag_works = &_Py_open_cloexec_works;
7747#elif !defined(MS_WINDOWS)
7748    int *atomic_flag_works = NULL;
7749#endif
7750
7751    memset(&path, 0, sizeof(path));
7752    path.function_name = "open";
7753    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|i$O&:open", keywords,
7754        path_converter, &path,
7755        &flags, &mode,
7756#ifdef HAVE_OPENAT
7757        dir_fd_converter, &dir_fd
7758#else
7759        dir_fd_unavailable, &dir_fd
7760#endif
7761        ))
7762        return NULL;
7763
7764#ifdef MS_WINDOWS
7765    flags |= O_NOINHERIT;
7766#elif defined(O_CLOEXEC)
7767    flags |= O_CLOEXEC;
7768#endif
7769
7770    Py_BEGIN_ALLOW_THREADS
7771#ifdef MS_WINDOWS
7772    if (path.wide)
7773        fd = _wopen(path.wide, flags, mode);
7774    else
7775#endif
7776#ifdef HAVE_OPENAT
7777    if (dir_fd != DEFAULT_DIR_FD)
7778        fd = openat(dir_fd, path.narrow, flags, mode);
7779    else
7780#endif
7781        fd = open(path.narrow, flags, mode);
7782    Py_END_ALLOW_THREADS
7783
7784    if (fd == -1) {
7785        PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path.object);
7786        goto exit;
7787    }
7788
7789#ifndef MS_WINDOWS
7790    if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
7791        close(fd);
7792        goto exit;
7793    }
7794#endif
7795
7796    return_value = PyLong_FromLong((long)fd);
7797
7798exit:
7799    path_cleanup(&path);
7800    return return_value;
7801}
7802
7803PyDoc_STRVAR(posix_close__doc__,
7804"close(fd)\n\n\
7805Close a file descriptor (for low level IO).");
7806
7807/*
7808The underscore at end of function name avoids a name clash with the libc
7809function posix_close.
7810*/
7811static PyObject *
7812posix_close_(PyObject *self, PyObject *args)
7813{
7814    int fd, res;
7815    if (!PyArg_ParseTuple(args, "i:close", &fd))
7816        return NULL;
7817    if (!_PyVerify_fd(fd))
7818        return posix_error();
7819    Py_BEGIN_ALLOW_THREADS
7820    res = close(fd);
7821    Py_END_ALLOW_THREADS
7822    if (res < 0)
7823        return posix_error();
7824    Py_INCREF(Py_None);
7825    return Py_None;
7826}
7827
7828
7829PyDoc_STRVAR(posix_closerange__doc__,
7830"closerange(fd_low, fd_high)\n\n\
7831Closes all file descriptors in [fd_low, fd_high), ignoring errors.");
7832
7833static PyObject *
7834posix_closerange(PyObject *self, PyObject *args)
7835{
7836    int fd_from, fd_to, i;
7837    if (!PyArg_ParseTuple(args, "ii:closerange", &fd_from, &fd_to))
7838        return NULL;
7839    Py_BEGIN_ALLOW_THREADS
7840    for (i = fd_from; i < fd_to; i++)
7841        if (_PyVerify_fd(i))
7842            close(i);
7843    Py_END_ALLOW_THREADS
7844    Py_RETURN_NONE;
7845}
7846
7847
7848PyDoc_STRVAR(posix_dup__doc__,
7849"dup(fd) -> fd2\n\n\
7850Return a duplicate of a file descriptor.");
7851
7852static PyObject *
7853posix_dup(PyObject *self, PyObject *args)
7854{
7855    int fd;
7856
7857    if (!PyArg_ParseTuple(args, "i:dup", &fd))
7858        return NULL;
7859
7860    fd = _Py_dup(fd);
7861    if (fd == -1)
7862        return NULL;
7863
7864    return PyLong_FromLong((long)fd);
7865}
7866
7867
7868PyDoc_STRVAR(posix_dup2__doc__,
7869"dup2(old_fd, new_fd)\n\n\
7870Duplicate file descriptor.");
7871
7872static PyObject *
7873posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs)
7874{
7875    static char *keywords[] = {"fd", "fd2", "inheritable", NULL};
7876    int fd, fd2;
7877    int inheritable = 1;
7878    int res;
7879#if defined(HAVE_DUP3) && \
7880    !(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC))
7881    /* dup3() is available on Linux 2.6.27+ and glibc 2.9 */
7882    int dup3_works = -1;
7883#endif
7884
7885    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:dup2", keywords,
7886                                     &fd, &fd2, &inheritable))
7887        return NULL;
7888
7889    if (!_PyVerify_fd_dup2(fd, fd2))
7890        return posix_error();
7891
7892#ifdef MS_WINDOWS
7893    Py_BEGIN_ALLOW_THREADS
7894    res = dup2(fd, fd2);
7895    Py_END_ALLOW_THREADS
7896    if (res < 0)
7897        return posix_error();
7898
7899    /* Character files like console cannot be make non-inheritable */
7900    if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
7901        close(fd2);
7902        return NULL;
7903    }
7904
7905#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
7906    Py_BEGIN_ALLOW_THREADS
7907    if (!inheritable)
7908        res = fcntl(fd, F_DUP2FD_CLOEXEC, fd2);
7909    else
7910        res = dup2(fd, fd2);
7911    Py_END_ALLOW_THREADS
7912    if (res < 0)
7913        return posix_error();
7914
7915#else
7916
7917#ifdef HAVE_DUP3
7918    if (!inheritable && dup3_works != 0) {
7919        Py_BEGIN_ALLOW_THREADS
7920        res = dup3(fd, fd2, O_CLOEXEC);
7921        Py_END_ALLOW_THREADS
7922        if (res < 0) {
7923            if (dup3_works == -1)
7924                dup3_works = (errno != ENOSYS);
7925            if (dup3_works)
7926                return posix_error();
7927        }
7928    }
7929
7930    if (inheritable || dup3_works == 0)
7931    {
7932#endif
7933        Py_BEGIN_ALLOW_THREADS
7934        res = dup2(fd, fd2);
7935        Py_END_ALLOW_THREADS
7936        if (res < 0)
7937            return posix_error();
7938
7939        if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
7940            close(fd2);
7941            return NULL;
7942        }
7943#ifdef HAVE_DUP3
7944    }
7945#endif
7946
7947#endif
7948
7949    Py_INCREF(Py_None);
7950    return Py_None;
7951}
7952
7953#ifdef HAVE_LOCKF
7954PyDoc_STRVAR(posix_lockf__doc__,
7955"lockf(fd, cmd, len)\n\n\
7956Apply, test or remove a POSIX lock on an open file descriptor.\n\n\
7957fd is an open file descriptor.\n\
7958cmd specifies the command to use - one of F_LOCK, F_TLOCK, F_ULOCK or\n\
7959F_TEST.\n\
7960len specifies the section of the file to lock.");
7961
7962static PyObject *
7963posix_lockf(PyObject *self, PyObject *args)
7964{
7965    int fd, cmd, res;
7966    off_t len;
7967    if (!PyArg_ParseTuple(args, "iiO&:lockf",
7968            &fd, &cmd, _parse_off_t, &len))
7969        return NULL;
7970
7971    Py_BEGIN_ALLOW_THREADS
7972    res = lockf(fd, cmd, len);
7973    Py_END_ALLOW_THREADS
7974
7975    if (res < 0)
7976        return posix_error();
7977
7978    Py_RETURN_NONE;
7979}
7980#endif
7981
7982
7983PyDoc_STRVAR(posix_lseek__doc__,
7984"lseek(fd, pos, how) -> newpos\n\n\
7985Set the current position of a file descriptor.\n\
7986Return the new cursor position in bytes, starting from the beginning.");
7987
7988static PyObject *
7989posix_lseek(PyObject *self, PyObject *args)
7990{
7991    int fd, how;
7992#ifdef MS_WINDOWS
7993    PY_LONG_LONG pos, res;
7994#else
7995    off_t pos, res;
7996#endif
7997    PyObject *posobj;
7998    if (!PyArg_ParseTuple(args, "iOi:lseek", &fd, &posobj, &how))
7999        return NULL;
8000#ifdef SEEK_SET
8001    /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
8002    switch (how) {
8003    case 0: how = SEEK_SET; break;
8004    case 1: how = SEEK_CUR; break;
8005    case 2: how = SEEK_END; break;
8006    }
8007#endif /* SEEK_END */
8008
8009#if !defined(HAVE_LARGEFILE_SUPPORT)
8010    pos = PyLong_AsLong(posobj);
8011#else
8012    pos = PyLong_AsLongLong(posobj);
8013#endif
8014    if (PyErr_Occurred())
8015        return NULL;
8016
8017    if (!_PyVerify_fd(fd))
8018        return posix_error();
8019    Py_BEGIN_ALLOW_THREADS
8020#ifdef MS_WINDOWS
8021    res = _lseeki64(fd, pos, how);
8022#else
8023    res = lseek(fd, pos, how);
8024#endif
8025    Py_END_ALLOW_THREADS
8026    if (res < 0)
8027        return posix_error();
8028
8029#if !defined(HAVE_LARGEFILE_SUPPORT)
8030    return PyLong_FromLong(res);
8031#else
8032    return PyLong_FromLongLong(res);
8033#endif
8034}
8035
8036
8037PyDoc_STRVAR(posix_read__doc__,
8038"read(fd, buffersize) -> bytes\n\n\
8039Read a file descriptor.");
8040
8041static PyObject *
8042posix_read(PyObject *self, PyObject *args)
8043{
8044    int fd, size;
8045    Py_ssize_t n;
8046    PyObject *buffer;
8047    if (!PyArg_ParseTuple(args, "ii:read", &fd, &size))
8048        return NULL;
8049    if (size < 0) {
8050        errno = EINVAL;
8051        return posix_error();
8052    }
8053    buffer = PyBytes_FromStringAndSize((char *)NULL, size);
8054    if (buffer == NULL)
8055        return NULL;
8056    if (!_PyVerify_fd(fd)) {
8057        Py_DECREF(buffer);
8058        return posix_error();
8059    }
8060    Py_BEGIN_ALLOW_THREADS
8061    n = read(fd, PyBytes_AS_STRING(buffer), size);
8062    Py_END_ALLOW_THREADS
8063    if (n < 0) {
8064        Py_DECREF(buffer);
8065        return posix_error();
8066    }
8067    if (n != size)
8068        _PyBytes_Resize(&buffer, n);
8069    return buffer;
8070}
8071
8072#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
8073    || defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
8074static Py_ssize_t
8075iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type)
8076{
8077    int i, j;
8078    Py_ssize_t blen, total = 0;
8079
8080    *iov = PyMem_New(struct iovec, cnt);
8081    if (*iov == NULL) {
8082        PyErr_NoMemory();
8083        return -1;
8084    }
8085
8086    *buf = PyMem_New(Py_buffer, cnt);
8087    if (*buf == NULL) {
8088        PyMem_Del(*iov);
8089        PyErr_NoMemory();
8090        return -1;
8091    }
8092
8093    for (i = 0; i < cnt; i++) {
8094        PyObject *item = PySequence_GetItem(seq, i);
8095        if (item == NULL)
8096            goto fail;
8097        if (PyObject_GetBuffer(item, &(*buf)[i], type) == -1) {
8098            Py_DECREF(item);
8099            goto fail;
8100        }
8101        Py_DECREF(item);
8102        (*iov)[i].iov_base = (*buf)[i].buf;
8103        blen = (*buf)[i].len;
8104        (*iov)[i].iov_len = blen;
8105        total += blen;
8106    }
8107    return total;
8108
8109fail:
8110    PyMem_Del(*iov);
8111    for (j = 0; j < i; j++) {
8112        PyBuffer_Release(&(*buf)[j]);
8113    }
8114    PyMem_Del(*buf);
8115    return -1;
8116}
8117
8118static void
8119iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt)
8120{
8121    int i;
8122    PyMem_Del(iov);
8123    for (i = 0; i < cnt; i++) {
8124        PyBuffer_Release(&buf[i]);
8125    }
8126    PyMem_Del(buf);
8127}
8128#endif
8129
8130#ifdef HAVE_READV
8131PyDoc_STRVAR(posix_readv__doc__,
8132"readv(fd, buffers) -> bytesread\n\n\
8133Read from a file descriptor fd into a number of mutable, bytes-like\n\
8134objects (\"buffers\").  readv will transfer data into each buffer\n\
8135until it is full and then move on to the next buffer in the sequence\n\
8136to hold the rest of the data.\n\n\
8137readv returns the total number of bytes read (which may be less than\n\
8138the total capacity of all the buffers.");
8139
8140static PyObject *
8141posix_readv(PyObject *self, PyObject *args)
8142{
8143    int fd, cnt;
8144    Py_ssize_t n;
8145    PyObject *seq;
8146    struct iovec *iov;
8147    Py_buffer *buf;
8148
8149    if (!PyArg_ParseTuple(args, "iO:readv", &fd, &seq))
8150        return NULL;
8151    if (!PySequence_Check(seq)) {
8152        PyErr_SetString(PyExc_TypeError,
8153            "readv() arg 2 must be a sequence");
8154        return NULL;
8155    }
8156    cnt = PySequence_Size(seq);
8157
8158    if (iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE) < 0)
8159        return NULL;
8160
8161    Py_BEGIN_ALLOW_THREADS
8162    n = readv(fd, iov, cnt);
8163    Py_END_ALLOW_THREADS
8164
8165    iov_cleanup(iov, buf, cnt);
8166    if (n < 0)
8167        return posix_error();
8168
8169    return PyLong_FromSsize_t(n);
8170}
8171#endif
8172
8173#ifdef HAVE_PREAD
8174PyDoc_STRVAR(posix_pread__doc__,
8175"pread(fd, buffersize, offset) -> string\n\n\
8176Read from a file descriptor, fd, at a position of offset. It will read up\n\
8177to buffersize number of bytes. The file offset remains unchanged.");
8178
8179static PyObject *
8180posix_pread(PyObject *self, PyObject *args)
8181{
8182    int fd, size;
8183    off_t offset;
8184    Py_ssize_t n;
8185    PyObject *buffer;
8186    if (!PyArg_ParseTuple(args, "iiO&:pread", &fd, &size, _parse_off_t, &offset))
8187        return NULL;
8188
8189    if (size < 0) {
8190        errno = EINVAL;
8191        return posix_error();
8192    }
8193    buffer = PyBytes_FromStringAndSize((char *)NULL, size);
8194    if (buffer == NULL)
8195        return NULL;
8196    if (!_PyVerify_fd(fd)) {
8197        Py_DECREF(buffer);
8198        return posix_error();
8199    }
8200    Py_BEGIN_ALLOW_THREADS
8201    n = pread(fd, PyBytes_AS_STRING(buffer), size, offset);
8202    Py_END_ALLOW_THREADS
8203    if (n < 0) {
8204        Py_DECREF(buffer);
8205        return posix_error();
8206    }
8207    if (n != size)
8208        _PyBytes_Resize(&buffer, n);
8209    return buffer;
8210}
8211#endif
8212
8213PyDoc_STRVAR(posix_write__doc__,
8214"write(fd, data) -> byteswritten\n\n\
8215Write bytes to a file descriptor.");
8216
8217static PyObject *
8218posix_write(PyObject *self, PyObject *args)
8219{
8220    Py_buffer pbuf;
8221    int fd;
8222    Py_ssize_t size, len;
8223
8224    if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf))
8225        return NULL;
8226    if (!_PyVerify_fd(fd)) {
8227        PyBuffer_Release(&pbuf);
8228        return posix_error();
8229    }
8230    len = pbuf.len;
8231    Py_BEGIN_ALLOW_THREADS
8232#ifdef MS_WINDOWS
8233    if (len > INT_MAX)
8234        len = INT_MAX;
8235    size = write(fd, pbuf.buf, (int)len);
8236#else
8237    size = write(fd, pbuf.buf, len);
8238#endif
8239    Py_END_ALLOW_THREADS
8240    PyBuffer_Release(&pbuf);
8241    if (size < 0)
8242        return posix_error();
8243    return PyLong_FromSsize_t(size);
8244}
8245
8246#ifdef HAVE_SENDFILE
8247PyDoc_STRVAR(posix_sendfile__doc__,
8248"sendfile(out, in, offset, count) -> byteswritten\n\
8249sendfile(out, in, offset, count, headers=None, trailers=None, flags=0)\n\
8250            -> byteswritten\n\
8251Copy count bytes from file descriptor in to file descriptor out.");
8252
8253static PyObject *
8254posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
8255{
8256    int in, out;
8257    Py_ssize_t ret;
8258    off_t offset;
8259
8260#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
8261#ifndef __APPLE__
8262    Py_ssize_t len;
8263#endif
8264    PyObject *headers = NULL, *trailers = NULL;
8265    Py_buffer *hbuf, *tbuf;
8266    off_t sbytes;
8267    struct sf_hdtr sf;
8268    int flags = 0;
8269    /* Beware that "in" clashes with Python's own "in" operator keyword */
8270    static char *keywords[] = {"out", "in",
8271                                "offset", "count",
8272                                "headers", "trailers", "flags", NULL};
8273
8274    sf.headers = NULL;
8275    sf.trailers = NULL;
8276
8277#ifdef __APPLE__
8278    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&O&|OOi:sendfile",
8279        keywords, &out, &in, _parse_off_t, &offset, _parse_off_t, &sbytes,
8280#else
8281    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&n|OOi:sendfile",
8282        keywords, &out, &in, _parse_off_t, &offset, &len,
8283#endif
8284                &headers, &trailers, &flags))
8285            return NULL;
8286    if (headers != NULL) {
8287        if (!PySequence_Check(headers)) {
8288            PyErr_SetString(PyExc_TypeError,
8289                "sendfile() headers must be a sequence or None");
8290            return NULL;
8291        } else {
8292            Py_ssize_t i = 0; /* Avoid uninitialized warning */
8293            sf.hdr_cnt = PySequence_Size(headers);
8294            if (sf.hdr_cnt > 0 &&
8295                (i = iov_setup(&(sf.headers), &hbuf,
8296                                headers, sf.hdr_cnt, PyBUF_SIMPLE)) < 0)
8297                return NULL;
8298#ifdef __APPLE__
8299            sbytes += i;
8300#endif
8301        }
8302    }
8303    if (trailers != NULL) {
8304        if (!PySequence_Check(trailers)) {
8305            PyErr_SetString(PyExc_TypeError,
8306                "sendfile() trailers must be a sequence or None");
8307            return NULL;
8308        } else {
8309            Py_ssize_t i = 0; /* Avoid uninitialized warning */
8310            sf.trl_cnt = PySequence_Size(trailers);
8311            if (sf.trl_cnt > 0 &&
8312                (i = iov_setup(&(sf.trailers), &tbuf,
8313                                trailers, sf.trl_cnt, PyBUF_SIMPLE)) < 0)
8314                return NULL;
8315#ifdef __APPLE__
8316            sbytes += i;
8317#endif
8318        }
8319    }
8320
8321    Py_BEGIN_ALLOW_THREADS
8322#ifdef __APPLE__
8323    ret = sendfile(in, out, offset, &sbytes, &sf, flags);
8324#else
8325    ret = sendfile(in, out, offset, len, &sf, &sbytes, flags);
8326#endif
8327    Py_END_ALLOW_THREADS
8328
8329    if (sf.headers != NULL)
8330        iov_cleanup(sf.headers, hbuf, sf.hdr_cnt);
8331    if (sf.trailers != NULL)
8332        iov_cleanup(sf.trailers, tbuf, sf.trl_cnt);
8333
8334    if (ret < 0) {
8335        if ((errno == EAGAIN) || (errno == EBUSY)) {
8336            if (sbytes != 0) {
8337                // some data has been sent
8338                goto done;
8339            }
8340            else {
8341                // no data has been sent; upper application is supposed
8342                // to retry on EAGAIN or EBUSY
8343                return posix_error();
8344            }
8345        }
8346        return posix_error();
8347    }
8348    goto done;
8349
8350done:
8351    #if !defined(HAVE_LARGEFILE_SUPPORT)
8352        return Py_BuildValue("l", sbytes);
8353    #else
8354        return Py_BuildValue("L", sbytes);
8355    #endif
8356
8357#else
8358    Py_ssize_t count;
8359    PyObject *offobj;
8360    static char *keywords[] = {"out", "in",
8361                                "offset", "count", NULL};
8362    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiOn:sendfile",
8363            keywords, &out, &in, &offobj, &count))
8364        return NULL;
8365#ifdef linux
8366    if (offobj == Py_None) {
8367        Py_BEGIN_ALLOW_THREADS
8368        ret = sendfile(out, in, NULL, count);
8369        Py_END_ALLOW_THREADS
8370        if (ret < 0)
8371            return posix_error();
8372        return Py_BuildValue("n", ret);
8373    }
8374#endif
8375    if (!_parse_off_t(offobj, &offset))
8376        return NULL;
8377    Py_BEGIN_ALLOW_THREADS
8378    ret = sendfile(out, in, &offset, count);
8379    Py_END_ALLOW_THREADS
8380    if (ret < 0)
8381        return posix_error();
8382    return Py_BuildValue("n", ret);
8383#endif
8384}
8385#endif
8386
8387PyDoc_STRVAR(posix_fstat__doc__,
8388"fstat(fd) -> stat result\n\n\
8389Like stat(), but for an open file descriptor.\n\
8390Equivalent to stat(fd=fd).");
8391
8392static PyObject *
8393posix_fstat(PyObject *self, PyObject *args)
8394{
8395    int fd;
8396    STRUCT_STAT st;
8397    int res;
8398    if (!PyArg_ParseTuple(args, "i:fstat", &fd))
8399        return NULL;
8400    Py_BEGIN_ALLOW_THREADS
8401    res = FSTAT(fd, &st);
8402    Py_END_ALLOW_THREADS
8403    if (res != 0) {
8404#ifdef MS_WINDOWS
8405        return PyErr_SetFromWindowsErr(0);
8406#else
8407        return posix_error();
8408#endif
8409    }
8410
8411    return _pystat_fromstructstat(&st);
8412}
8413
8414PyDoc_STRVAR(posix_isatty__doc__,
8415"isatty(fd) -> bool\n\n\
8416Return True if the file descriptor 'fd' is an open file descriptor\n\
8417connected to the slave end of a terminal.");
8418
8419static PyObject *
8420posix_isatty(PyObject *self, PyObject *args)
8421{
8422    int fd;
8423    if (!PyArg_ParseTuple(args, "i:isatty", &fd))
8424        return NULL;
8425    if (!_PyVerify_fd(fd))
8426        return PyBool_FromLong(0);
8427    return PyBool_FromLong(isatty(fd));
8428}
8429
8430#ifdef HAVE_PIPE
8431PyDoc_STRVAR(posix_pipe__doc__,
8432"pipe() -> (read_end, write_end)\n\n\
8433Create a pipe.");
8434
8435static PyObject *
8436posix_pipe(PyObject *self, PyObject *noargs)
8437{
8438    int fds[2];
8439#ifdef MS_WINDOWS
8440    HANDLE read, write;
8441    SECURITY_ATTRIBUTES attr;
8442    BOOL ok;
8443#else
8444    int res;
8445#endif
8446
8447#ifdef MS_WINDOWS
8448    attr.nLength = sizeof(attr);
8449    attr.lpSecurityDescriptor = NULL;
8450    attr.bInheritHandle = FALSE;
8451
8452    Py_BEGIN_ALLOW_THREADS
8453    ok = CreatePipe(&read, &write, &attr, 0);
8454    if (ok) {
8455        fds[0] = _open_osfhandle((Py_intptr_t)read, _O_RDONLY);
8456        fds[1] = _open_osfhandle((Py_intptr_t)write, _O_WRONLY);
8457        if (fds[0] == -1 || fds[1] == -1) {
8458            CloseHandle(read);
8459            CloseHandle(write);
8460            ok = 0;
8461        }
8462    }
8463    Py_END_ALLOW_THREADS
8464
8465    if (!ok)
8466        return PyErr_SetFromWindowsErr(0);
8467#else
8468
8469#ifdef HAVE_PIPE2
8470    Py_BEGIN_ALLOW_THREADS
8471    res = pipe2(fds, O_CLOEXEC);
8472    Py_END_ALLOW_THREADS
8473
8474    if (res != 0 && errno == ENOSYS)
8475    {
8476#endif
8477        Py_BEGIN_ALLOW_THREADS
8478        res = pipe(fds);
8479        Py_END_ALLOW_THREADS
8480
8481        if (res == 0) {
8482            if (_Py_set_inheritable(fds[0], 0, NULL) < 0) {
8483                close(fds[0]);
8484                close(fds[1]);
8485                return NULL;
8486            }
8487            if (_Py_set_inheritable(fds[1], 0, NULL) < 0) {
8488                close(fds[0]);
8489                close(fds[1]);
8490                return NULL;
8491            }
8492        }
8493#ifdef HAVE_PIPE2
8494    }
8495#endif
8496
8497    if (res != 0)
8498        return PyErr_SetFromErrno(PyExc_OSError);
8499#endif /* !MS_WINDOWS */
8500    return Py_BuildValue("(ii)", fds[0], fds[1]);
8501}
8502#endif  /* HAVE_PIPE */
8503
8504#ifdef HAVE_PIPE2
8505PyDoc_STRVAR(posix_pipe2__doc__,
8506"pipe2(flags) -> (read_end, write_end)\n\n\
8507Create a pipe with flags set atomically.\n\
8508flags can be constructed by ORing together one or more of these values:\n\
8509O_NONBLOCK, O_CLOEXEC.\n\
8510");
8511
8512static PyObject *
8513posix_pipe2(PyObject *self, PyObject *arg)
8514{
8515    int flags;
8516    int fds[2];
8517    int res;
8518
8519    flags = _PyLong_AsInt(arg);
8520    if (flags == -1 && PyErr_Occurred())
8521        return NULL;
8522
8523    res = pipe2(fds, flags);
8524    if (res != 0)
8525        return posix_error();
8526    return Py_BuildValue("(ii)", fds[0], fds[1]);
8527}
8528#endif /* HAVE_PIPE2 */
8529
8530#ifdef HAVE_WRITEV
8531PyDoc_STRVAR(posix_writev__doc__,
8532"writev(fd, buffers) -> byteswritten\n\n\
8533Write the contents of *buffers* to file descriptor *fd*. *buffers*\n\
8534must be a sequence of bytes-like objects.\n\n\
8535writev writes the contents of each object to the file descriptor\n\
8536and returns the total number of bytes written.");
8537
8538static PyObject *
8539posix_writev(PyObject *self, PyObject *args)
8540{
8541    int fd, cnt;
8542    Py_ssize_t res;
8543    PyObject *seq;
8544    struct iovec *iov;
8545    Py_buffer *buf;
8546    if (!PyArg_ParseTuple(args, "iO:writev", &fd, &seq))
8547        return NULL;
8548    if (!PySequence_Check(seq)) {
8549        PyErr_SetString(PyExc_TypeError,
8550            "writev() arg 2 must be a sequence");
8551        return NULL;
8552    }
8553    cnt = PySequence_Size(seq);
8554
8555    if (iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE) < 0) {
8556        return NULL;
8557    }
8558
8559    Py_BEGIN_ALLOW_THREADS
8560    res = writev(fd, iov, cnt);
8561    Py_END_ALLOW_THREADS
8562
8563    iov_cleanup(iov, buf, cnt);
8564    if (res < 0)
8565        return posix_error();
8566
8567    return PyLong_FromSsize_t(res);
8568}
8569#endif
8570
8571#ifdef HAVE_PWRITE
8572PyDoc_STRVAR(posix_pwrite__doc__,
8573"pwrite(fd, string, offset) -> byteswritten\n\n\
8574Write string to a file descriptor, fd, from offset, leaving the file\n\
8575offset unchanged.");
8576
8577static PyObject *
8578posix_pwrite(PyObject *self, PyObject *args)
8579{
8580    Py_buffer pbuf;
8581    int fd;
8582    off_t offset;
8583    Py_ssize_t size;
8584
8585    if (!PyArg_ParseTuple(args, "iy*O&:pwrite", &fd, &pbuf, _parse_off_t, &offset))
8586        return NULL;
8587
8588    if (!_PyVerify_fd(fd)) {
8589        PyBuffer_Release(&pbuf);
8590        return posix_error();
8591    }
8592    Py_BEGIN_ALLOW_THREADS
8593    size = pwrite(fd, pbuf.buf, (size_t)pbuf.len, offset);
8594    Py_END_ALLOW_THREADS
8595    PyBuffer_Release(&pbuf);
8596    if (size < 0)
8597        return posix_error();
8598    return PyLong_FromSsize_t(size);
8599}
8600#endif
8601
8602#ifdef HAVE_MKFIFO
8603PyDoc_STRVAR(posix_mkfifo__doc__,
8604"mkfifo(path, mode=0o666, *, dir_fd=None)\n\n\
8605Create a FIFO (a POSIX named pipe).\n\
8606\n\
8607If dir_fd is not None, it should be a file descriptor open to a directory,\n\
8608  and path should be relative; path will then be relative to that directory.\n\
8609dir_fd may not be implemented on your platform.\n\
8610  If it is unavailable, using it will raise a NotImplementedError.");
8611
8612static PyObject *
8613posix_mkfifo(PyObject *self, PyObject *args, PyObject *kwargs)
8614{
8615    path_t path;
8616    int mode = 0666;
8617    int dir_fd = DEFAULT_DIR_FD;
8618    int result;
8619    PyObject *return_value = NULL;
8620    static char *keywords[] = {"path", "mode", "dir_fd", NULL};
8621
8622    memset(&path, 0, sizeof(path));
8623    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i$O&:mkfifo", keywords,
8624        path_converter, &path,
8625        &mode,
8626#ifdef HAVE_MKFIFOAT
8627        dir_fd_converter, &dir_fd
8628#else
8629        dir_fd_unavailable, &dir_fd
8630#endif
8631        ))
8632        return NULL;
8633
8634    Py_BEGIN_ALLOW_THREADS
8635#ifdef HAVE_MKFIFOAT
8636    if (dir_fd != DEFAULT_DIR_FD)
8637        result = mkfifoat(dir_fd, path.narrow, mode);
8638    else
8639#endif
8640        result = mkfifo(path.narrow, mode);
8641    Py_END_ALLOW_THREADS
8642
8643    if (result < 0) {
8644        return_value = posix_error();
8645        goto exit;
8646    }
8647
8648    return_value = Py_None;
8649    Py_INCREF(Py_None);
8650
8651exit:
8652    path_cleanup(&path);
8653    return return_value;
8654}
8655#endif
8656
8657#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
8658PyDoc_STRVAR(posix_mknod__doc__,
8659"mknod(path, mode=0o600, device=0, *, dir_fd=None)\n\n\
8660Create a filesystem node (file, device special file or named pipe)\n\
8661named path. mode specifies both the permissions to use and the\n\
8662type of node to be created, being combined (bitwise OR) with one of\n\
8663S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,\n\
8664device defines the newly created device special file (probably using\n\
8665os.makedev()), otherwise it is ignored.\n\
8666\n\
8667If dir_fd is not None, it should be a file descriptor open to a directory,\n\
8668  and path should be relative; path will then be relative to that directory.\n\
8669dir_fd may not be implemented on your platform.\n\
8670  If it is unavailable, using it will raise a NotImplementedError.");
8671
8672
8673static PyObject *
8674posix_mknod(PyObject *self, PyObject *args, PyObject *kwargs)
8675{
8676    path_t path;
8677    int mode = 0666;
8678    dev_t device = 0;
8679    int dir_fd = DEFAULT_DIR_FD;
8680    int result;
8681    PyObject *return_value = NULL;
8682    static char *keywords[] = {"path", "mode", "device", "dir_fd", NULL};
8683
8684    memset(&path, 0, sizeof(path));
8685    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|iO&$O&:mknod", keywords,
8686        path_converter, &path,
8687        &mode, _Py_Dev_Converter, &device,
8688#ifdef HAVE_MKNODAT
8689        dir_fd_converter, &dir_fd
8690#else
8691        dir_fd_unavailable, &dir_fd
8692#endif
8693        ))
8694        return NULL;
8695
8696    Py_BEGIN_ALLOW_THREADS
8697#ifdef HAVE_MKNODAT
8698    if (dir_fd != DEFAULT_DIR_FD)
8699        result = mknodat(dir_fd, path.narrow, mode, device);
8700    else
8701#endif
8702        result = mknod(path.narrow, mode, device);
8703    Py_END_ALLOW_THREADS
8704
8705    if (result < 0) {
8706        return_value = posix_error();
8707        goto exit;
8708    }
8709
8710    return_value = Py_None;
8711    Py_INCREF(Py_None);
8712
8713exit:
8714    path_cleanup(&path);
8715    return return_value;
8716}
8717#endif
8718
8719#ifdef HAVE_DEVICE_MACROS
8720PyDoc_STRVAR(posix_major__doc__,
8721"major(device) -> major number\n\
8722Extracts a device major number from a raw device number.");
8723
8724static PyObject *
8725posix_major(PyObject *self, PyObject *args)
8726{
8727    dev_t device;
8728    if (!PyArg_ParseTuple(args, "O&:major", _Py_Dev_Converter, &device))
8729        return NULL;
8730    return PyLong_FromLong((long)major(device));
8731}
8732
8733PyDoc_STRVAR(posix_minor__doc__,
8734"minor(device) -> minor number\n\
8735Extracts a device minor number from a raw device number.");
8736
8737static PyObject *
8738posix_minor(PyObject *self, PyObject *args)
8739{
8740    dev_t device;
8741    if (!PyArg_ParseTuple(args, "O&:minor", _Py_Dev_Converter, &device))
8742        return NULL;
8743    return PyLong_FromLong((long)minor(device));
8744}
8745
8746PyDoc_STRVAR(posix_makedev__doc__,
8747"makedev(major, minor) -> device number\n\
8748Composes a raw device number from the major and minor device numbers.");
8749
8750static PyObject *
8751posix_makedev(PyObject *self, PyObject *args)
8752{
8753    int major, minor;
8754    if (!PyArg_ParseTuple(args, "ii:makedev", &major, &minor))
8755        return NULL;
8756    return _PyLong_FromDev(makedev(major, minor));
8757}
8758#endif /* device macros */
8759
8760
8761#ifdef HAVE_FTRUNCATE
8762PyDoc_STRVAR(posix_ftruncate__doc__,
8763"ftruncate(fd, length)\n\n\
8764Truncate a file to a specified length.");
8765
8766static PyObject *
8767posix_ftruncate(PyObject *self, PyObject *args)
8768{
8769    int fd;
8770    off_t length;
8771    int res;
8772
8773    if (!PyArg_ParseTuple(args, "iO&:ftruncate", &fd, _parse_off_t, &length))
8774        return NULL;
8775
8776    Py_BEGIN_ALLOW_THREADS
8777    res = ftruncate(fd, length);
8778    Py_END_ALLOW_THREADS
8779    if (res < 0)
8780        return posix_error();
8781    Py_INCREF(Py_None);
8782    return Py_None;
8783}
8784#endif
8785
8786#ifdef HAVE_TRUNCATE
8787PyDoc_STRVAR(posix_truncate__doc__,
8788"truncate(path, length)\n\n\
8789Truncate the file given by path to length bytes.\n\
8790On some platforms, path may also be specified as an open file descriptor.\n\
8791  If this functionality is unavailable, using it raises an exception.");
8792
8793static PyObject *
8794posix_truncate(PyObject *self, PyObject *args, PyObject *kwargs)
8795{
8796    path_t path;
8797    off_t length;
8798    int res;
8799    PyObject *result = NULL;
8800    static char *keywords[] = {"path", "length", NULL};
8801
8802    memset(&path, 0, sizeof(path));
8803    path.function_name = "truncate";
8804#ifdef HAVE_FTRUNCATE
8805    path.allow_fd = 1;
8806#endif
8807    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:truncate", keywords,
8808                                     path_converter, &path,
8809                                     _parse_off_t, &length))
8810        return NULL;
8811
8812    Py_BEGIN_ALLOW_THREADS
8813#ifdef HAVE_FTRUNCATE
8814    if (path.fd != -1)
8815        res = ftruncate(path.fd, length);
8816    else
8817#endif
8818        res = truncate(path.narrow, length);
8819    Py_END_ALLOW_THREADS
8820    if (res < 0)
8821        result = path_error(&path);
8822    else {
8823        Py_INCREF(Py_None);
8824        result = Py_None;
8825    }
8826    path_cleanup(&path);
8827    return result;
8828}
8829#endif
8830
8831/* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise()
8832   and os.posix_fallocate() in system headers are wrong if _LARGE_FILES is
8833   defined, which is the case in Python on AIX. AIX bug report:
8834   http://www-01.ibm.com/support/docview.wss?uid=isg1IV56170 */
8835#if defined(_AIX) && defined(_LARGE_FILES) && !defined(__64BIT__)
8836#  define POSIX_FADVISE_AIX_BUG
8837#endif
8838
8839#if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG)
8840PyDoc_STRVAR(posix_posix_fallocate__doc__,
8841"posix_fallocate(fd, offset, len)\n\n\
8842Ensures that enough disk space is allocated for the file specified by fd\n\
8843starting from offset and continuing for len bytes.");
8844
8845static PyObject *
8846posix_posix_fallocate(PyObject *self, PyObject *args)
8847{
8848    off_t len, offset;
8849    int res, fd;
8850
8851    if (!PyArg_ParseTuple(args, "iO&O&:posix_fallocate",
8852            &fd, _parse_off_t, &offset, _parse_off_t, &len))
8853        return NULL;
8854
8855    Py_BEGIN_ALLOW_THREADS
8856    res = posix_fallocate(fd, offset, len);
8857    Py_END_ALLOW_THREADS
8858    if (res != 0) {
8859        errno = res;
8860        return posix_error();
8861    }
8862    Py_RETURN_NONE;
8863}
8864#endif
8865
8866#if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG)
8867PyDoc_STRVAR(posix_posix_fadvise__doc__,
8868"posix_fadvise(fd, offset, len, advice)\n\n\
8869Announces an intention to access data in a specific pattern thus allowing\n\
8870the kernel to make optimizations.\n\
8871The advice applies to the region of the file specified by fd starting at\n\
8872offset and continuing for len bytes.\n\
8873advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,\n\
8874POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED or\n\
8875POSIX_FADV_DONTNEED.");
8876
8877static PyObject *
8878posix_posix_fadvise(PyObject *self, PyObject *args)
8879{
8880    off_t len, offset;
8881    int res, fd, advice;
8882
8883    if (!PyArg_ParseTuple(args, "iO&O&i:posix_fadvise",
8884            &fd, _parse_off_t, &offset, _parse_off_t, &len, &advice))
8885        return NULL;
8886
8887    Py_BEGIN_ALLOW_THREADS
8888    res = posix_fadvise(fd, offset, len, advice);
8889    Py_END_ALLOW_THREADS
8890    if (res != 0) {
8891        errno = res;
8892        return posix_error();
8893    }
8894    Py_RETURN_NONE;
8895}
8896#endif
8897
8898#ifdef HAVE_PUTENV
8899PyDoc_STRVAR(posix_putenv__doc__,
8900"putenv(key, value)\n\n\
8901Change or add an environment variable.");
8902
8903/* Save putenv() parameters as values here, so we can collect them when they
8904 * get re-set with another call for the same key. */
8905static PyObject *posix_putenv_garbage;
8906
8907static PyObject *
8908posix_putenv(PyObject *self, PyObject *args)
8909{
8910    PyObject *newstr = NULL;
8911#ifdef MS_WINDOWS
8912    PyObject *os1, *os2;
8913    wchar_t *newenv;
8914
8915    if (!PyArg_ParseTuple(args,
8916                          "UU:putenv",
8917                          &os1, &os2))
8918        return NULL;
8919
8920    newstr = PyUnicode_FromFormat("%U=%U", os1, os2);
8921    if (newstr == NULL) {
8922        PyErr_NoMemory();
8923        goto error;
8924    }
8925    if (_MAX_ENV < PyUnicode_GET_LENGTH(newstr)) {
8926        PyErr_Format(PyExc_ValueError,
8927                     "the environment variable is longer than %u characters",
8928                     _MAX_ENV);
8929        goto error;
8930    }
8931
8932    newenv = PyUnicode_AsUnicode(newstr);
8933    if (newenv == NULL)
8934        goto error;
8935    if (_wputenv(newenv)) {
8936        posix_error();
8937        goto error;
8938    }
8939#else
8940    PyObject *os1, *os2;
8941    char *s1, *s2;
8942    char *newenv;
8943
8944    if (!PyArg_ParseTuple(args,
8945                          "O&O&:putenv",
8946                          PyUnicode_FSConverter, &os1,
8947                          PyUnicode_FSConverter, &os2))
8948        return NULL;
8949    s1 = PyBytes_AsString(os1);
8950    s2 = PyBytes_AsString(os2);
8951
8952    newstr = PyBytes_FromFormat("%s=%s", s1, s2);
8953    if (newstr == NULL) {
8954        PyErr_NoMemory();
8955        goto error;
8956    }
8957
8958    newenv = PyBytes_AS_STRING(newstr);
8959    if (putenv(newenv)) {
8960        posix_error();
8961        goto error;
8962    }
8963#endif
8964
8965    /* Install the first arg and newstr in posix_putenv_garbage;
8966     * this will cause previous value to be collected.  This has to
8967     * happen after the real putenv() call because the old value
8968     * was still accessible until then. */
8969    if (PyDict_SetItem(posix_putenv_garbage, os1, newstr)) {
8970        /* really not much we can do; just leak */
8971        PyErr_Clear();
8972    }
8973    else {
8974        Py_DECREF(newstr);
8975    }
8976
8977#ifndef MS_WINDOWS
8978    Py_DECREF(os1);
8979    Py_DECREF(os2);
8980#endif
8981    Py_RETURN_NONE;
8982
8983error:
8984#ifndef MS_WINDOWS
8985    Py_DECREF(os1);
8986    Py_DECREF(os2);
8987#endif
8988    Py_XDECREF(newstr);
8989    return NULL;
8990}
8991#endif /* putenv */
8992
8993#ifdef HAVE_UNSETENV
8994PyDoc_STRVAR(posix_unsetenv__doc__,
8995"unsetenv(key)\n\n\
8996Delete an environment variable.");
8997
8998static PyObject *
8999posix_unsetenv(PyObject *self, PyObject *args)
9000{
9001    PyObject *name;
9002#ifndef HAVE_BROKEN_UNSETENV
9003    int err;
9004#endif
9005
9006    if (!PyArg_ParseTuple(args, "O&:unsetenv",
9007
9008                          PyUnicode_FSConverter, &name))
9009        return NULL;
9010
9011#ifdef HAVE_BROKEN_UNSETENV
9012    unsetenv(PyBytes_AS_STRING(name));
9013#else
9014    err = unsetenv(PyBytes_AS_STRING(name));
9015    if (err) {
9016        Py_DECREF(name);
9017        return posix_error();
9018    }
9019#endif
9020
9021    /* Remove the key from posix_putenv_garbage;
9022     * this will cause it to be collected.  This has to
9023     * happen after the real unsetenv() call because the
9024     * old value was still accessible until then.
9025     */
9026    if (PyDict_DelItem(posix_putenv_garbage, name)) {
9027        /* really not much we can do; just leak */
9028        PyErr_Clear();
9029    }
9030    Py_DECREF(name);
9031    Py_RETURN_NONE;
9032}
9033#endif /* unsetenv */
9034
9035PyDoc_STRVAR(posix_strerror__doc__,
9036"strerror(code) -> string\n\n\
9037Translate an error code to a message string.");
9038
9039static PyObject *
9040posix_strerror(PyObject *self, PyObject *args)
9041{
9042    int code;
9043    char *message;
9044    if (!PyArg_ParseTuple(args, "i:strerror", &code))
9045        return NULL;
9046    message = strerror(code);
9047    if (message == NULL) {
9048        PyErr_SetString(PyExc_ValueError,
9049                        "strerror() argument out of range");
9050        return NULL;
9051    }
9052    return PyUnicode_DecodeLocale(message, "surrogateescape");
9053}
9054
9055
9056#ifdef HAVE_SYS_WAIT_H
9057
9058#ifdef WCOREDUMP
9059PyDoc_STRVAR(posix_WCOREDUMP__doc__,
9060"WCOREDUMP(status) -> bool\n\n\
9061Return True if the process returning 'status' was dumped to a core file.");
9062
9063static PyObject *
9064posix_WCOREDUMP(PyObject *self, PyObject *args)
9065{
9066    WAIT_TYPE status;
9067    WAIT_STATUS_INT(status) = 0;
9068
9069    if (!PyArg_ParseTuple(args, "i:WCOREDUMP", &WAIT_STATUS_INT(status)))
9070        return NULL;
9071
9072    return PyBool_FromLong(WCOREDUMP(status));
9073}
9074#endif /* WCOREDUMP */
9075
9076#ifdef WIFCONTINUED
9077PyDoc_STRVAR(posix_WIFCONTINUED__doc__,
9078"WIFCONTINUED(status) -> bool\n\n\
9079Return True if the process returning 'status' was continued from a\n\
9080job control stop.");
9081
9082static PyObject *
9083posix_WIFCONTINUED(PyObject *self, PyObject *args)
9084{
9085    WAIT_TYPE status;
9086    WAIT_STATUS_INT(status) = 0;
9087
9088    if (!PyArg_ParseTuple(args, "i:WCONTINUED", &WAIT_STATUS_INT(status)))
9089        return NULL;
9090
9091    return PyBool_FromLong(WIFCONTINUED(status));
9092}
9093#endif /* WIFCONTINUED */
9094
9095#ifdef WIFSTOPPED
9096PyDoc_STRVAR(posix_WIFSTOPPED__doc__,
9097"WIFSTOPPED(status) -> bool\n\n\
9098Return True if the process returning 'status' was stopped.");
9099
9100static PyObject *
9101posix_WIFSTOPPED(PyObject *self, PyObject *args)
9102{
9103    WAIT_TYPE status;
9104    WAIT_STATUS_INT(status) = 0;
9105
9106    if (!PyArg_ParseTuple(args, "i:WIFSTOPPED", &WAIT_STATUS_INT(status)))
9107        return NULL;
9108
9109    return PyBool_FromLong(WIFSTOPPED(status));
9110}
9111#endif /* WIFSTOPPED */
9112
9113#ifdef WIFSIGNALED
9114PyDoc_STRVAR(posix_WIFSIGNALED__doc__,
9115"WIFSIGNALED(status) -> bool\n\n\
9116Return True if the process returning 'status' was terminated by a signal.");
9117
9118static PyObject *
9119posix_WIFSIGNALED(PyObject *self, PyObject *args)
9120{
9121    WAIT_TYPE status;
9122    WAIT_STATUS_INT(status) = 0;
9123
9124    if (!PyArg_ParseTuple(args, "i:WIFSIGNALED", &WAIT_STATUS_INT(status)))
9125        return NULL;
9126
9127    return PyBool_FromLong(WIFSIGNALED(status));
9128}
9129#endif /* WIFSIGNALED */
9130
9131#ifdef WIFEXITED
9132PyDoc_STRVAR(posix_WIFEXITED__doc__,
9133"WIFEXITED(status) -> bool\n\n\
9134Return true if the process returning 'status' exited using the exit()\n\
9135system call.");
9136
9137static PyObject *
9138posix_WIFEXITED(PyObject *self, PyObject *args)
9139{
9140    WAIT_TYPE status;
9141    WAIT_STATUS_INT(status) = 0;
9142
9143    if (!PyArg_ParseTuple(args, "i:WIFEXITED", &WAIT_STATUS_INT(status)))
9144        return NULL;
9145
9146    return PyBool_FromLong(WIFEXITED(status));
9147}
9148#endif /* WIFEXITED */
9149
9150#ifdef WEXITSTATUS
9151PyDoc_STRVAR(posix_WEXITSTATUS__doc__,
9152"WEXITSTATUS(status) -> integer\n\n\
9153Return the process return code from 'status'.");
9154
9155static PyObject *
9156posix_WEXITSTATUS(PyObject *self, PyObject *args)
9157{
9158    WAIT_TYPE status;
9159    WAIT_STATUS_INT(status) = 0;
9160
9161    if (!PyArg_ParseTuple(args, "i:WEXITSTATUS", &WAIT_STATUS_INT(status)))
9162        return NULL;
9163
9164    return Py_BuildValue("i", WEXITSTATUS(status));
9165}
9166#endif /* WEXITSTATUS */
9167
9168#ifdef WTERMSIG
9169PyDoc_STRVAR(posix_WTERMSIG__doc__,
9170"WTERMSIG(status) -> integer\n\n\
9171Return the signal that terminated the process that provided the 'status'\n\
9172value.");
9173
9174static PyObject *
9175posix_WTERMSIG(PyObject *self, PyObject *args)
9176{
9177    WAIT_TYPE status;
9178    WAIT_STATUS_INT(status) = 0;
9179
9180    if (!PyArg_ParseTuple(args, "i:WTERMSIG", &WAIT_STATUS_INT(status)))
9181        return NULL;
9182
9183    return Py_BuildValue("i", WTERMSIG(status));
9184}
9185#endif /* WTERMSIG */
9186
9187#ifdef WSTOPSIG
9188PyDoc_STRVAR(posix_WSTOPSIG__doc__,
9189"WSTOPSIG(status) -> integer\n\n\
9190Return the signal that stopped the process that provided\n\
9191the 'status' value.");
9192
9193static PyObject *
9194posix_WSTOPSIG(PyObject *self, PyObject *args)
9195{
9196    WAIT_TYPE status;
9197    WAIT_STATUS_INT(status) = 0;
9198
9199    if (!PyArg_ParseTuple(args, "i:WSTOPSIG", &WAIT_STATUS_INT(status)))
9200        return NULL;
9201
9202    return Py_BuildValue("i", WSTOPSIG(status));
9203}
9204#endif /* WSTOPSIG */
9205
9206#endif /* HAVE_SYS_WAIT_H */
9207
9208
9209#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H)
9210#ifdef _SCO_DS
9211/* SCO OpenServer 5.0 and later requires _SVID3 before it reveals the
9212   needed definitions in sys/statvfs.h */
9213#define _SVID3
9214#endif
9215#include <sys/statvfs.h>
9216
9217static PyObject*
9218_pystatvfs_fromstructstatvfs(struct statvfs st) {
9219    PyObject *v = PyStructSequence_New(&StatVFSResultType);
9220    if (v == NULL)
9221        return NULL;
9222
9223#if !defined(HAVE_LARGEFILE_SUPPORT)
9224    PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
9225    PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
9226    PyStructSequence_SET_ITEM(v, 2, PyLong_FromLong((long) st.f_blocks));
9227    PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long) st.f_bfree));
9228    PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong((long) st.f_bavail));
9229    PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong((long) st.f_files));
9230    PyStructSequence_SET_ITEM(v, 6, PyLong_FromLong((long) st.f_ffree));
9231    PyStructSequence_SET_ITEM(v, 7, PyLong_FromLong((long) st.f_favail));
9232    PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
9233    PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
9234#else
9235    PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
9236    PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
9237    PyStructSequence_SET_ITEM(v, 2,
9238                              PyLong_FromLongLong((PY_LONG_LONG) st.f_blocks));
9239    PyStructSequence_SET_ITEM(v, 3,
9240                              PyLong_FromLongLong((PY_LONG_LONG) st.f_bfree));
9241    PyStructSequence_SET_ITEM(v, 4,
9242                              PyLong_FromLongLong((PY_LONG_LONG) st.f_bavail));
9243    PyStructSequence_SET_ITEM(v, 5,
9244                              PyLong_FromLongLong((PY_LONG_LONG) st.f_files));
9245    PyStructSequence_SET_ITEM(v, 6,
9246                              PyLong_FromLongLong((PY_LONG_LONG) st.f_ffree));
9247    PyStructSequence_SET_ITEM(v, 7,
9248                              PyLong_FromLongLong((PY_LONG_LONG) st.f_favail));
9249    PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
9250    PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
9251#endif
9252    if (PyErr_Occurred()) {
9253        Py_DECREF(v);
9254        return NULL;
9255    }
9256
9257    return v;
9258}
9259
9260PyDoc_STRVAR(posix_fstatvfs__doc__,
9261"fstatvfs(fd) -> statvfs result\n\n\
9262Perform an fstatvfs system call on the given fd.\n\
9263Equivalent to statvfs(fd).");
9264
9265static PyObject *
9266posix_fstatvfs(PyObject *self, PyObject *args)
9267{
9268    int fd, res;
9269    struct statvfs st;
9270
9271    if (!PyArg_ParseTuple(args, "i:fstatvfs", &fd))
9272        return NULL;
9273    Py_BEGIN_ALLOW_THREADS
9274    res = fstatvfs(fd, &st);
9275    Py_END_ALLOW_THREADS
9276    if (res != 0)
9277        return posix_error();
9278
9279    return _pystatvfs_fromstructstatvfs(st);
9280}
9281#endif /* HAVE_FSTATVFS && HAVE_SYS_STATVFS_H */
9282
9283
9284#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
9285#include <sys/statvfs.h>
9286
9287PyDoc_STRVAR(posix_statvfs__doc__,
9288"statvfs(path)\n\n\
9289Perform a statvfs system call on the given path.\n\
9290\n\
9291path may always be specified as a string.\n\
9292On some platforms, path may also be specified as an open file descriptor.\n\
9293  If this functionality is unavailable, using it raises an exception.");
9294
9295static PyObject *
9296posix_statvfs(PyObject *self, PyObject *args, PyObject *kwargs)
9297{
9298    static char *keywords[] = {"path", NULL};
9299    path_t path;
9300    int result;
9301    PyObject *return_value = NULL;
9302    struct statvfs st;
9303
9304    memset(&path, 0, sizeof(path));
9305    path.function_name = "statvfs";
9306#ifdef HAVE_FSTATVFS
9307    path.allow_fd = 1;
9308#endif
9309    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:statvfs", keywords,
9310        path_converter, &path
9311        ))
9312        return NULL;
9313
9314    Py_BEGIN_ALLOW_THREADS
9315#ifdef HAVE_FSTATVFS
9316    if (path.fd != -1) {
9317#ifdef __APPLE__
9318        /* handle weak-linking on Mac OS X 10.3 */
9319        if (fstatvfs == NULL) {
9320            fd_specified("statvfs", path.fd);
9321            goto exit;
9322        }
9323#endif
9324        result = fstatvfs(path.fd, &st);
9325    }
9326    else
9327#endif
9328        result = statvfs(path.narrow, &st);
9329    Py_END_ALLOW_THREADS
9330
9331    if (result) {
9332        return_value = path_error(&path);
9333        goto exit;
9334    }
9335
9336    return_value = _pystatvfs_fromstructstatvfs(st);
9337
9338exit:
9339    path_cleanup(&path);
9340    return return_value;
9341}
9342#endif /* HAVE_STATVFS */
9343
9344#ifdef MS_WINDOWS
9345PyDoc_STRVAR(win32__getdiskusage__doc__,
9346"_getdiskusage(path) -> (total, free)\n\n\
9347Return disk usage statistics about the given path as (total, free) tuple.");
9348
9349static PyObject *
9350win32__getdiskusage(PyObject *self, PyObject *args)
9351{
9352    BOOL retval;
9353    ULARGE_INTEGER _, total, free;
9354    const wchar_t *path;
9355
9356    if (! PyArg_ParseTuple(args, "u", &path))
9357        return NULL;
9358
9359    Py_BEGIN_ALLOW_THREADS
9360    retval = GetDiskFreeSpaceExW(path, &_, &total, &free);
9361    Py_END_ALLOW_THREADS
9362    if (retval == 0)
9363        return PyErr_SetFromWindowsErr(0);
9364
9365    return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
9366}
9367#endif
9368
9369
9370/* This is used for fpathconf(), pathconf(), confstr() and sysconf().
9371 * It maps strings representing configuration variable names to
9372 * integer values, allowing those functions to be called with the
9373 * magic names instead of polluting the module's namespace with tons of
9374 * rarely-used constants.  There are three separate tables that use
9375 * these definitions.
9376 *
9377 * This code is always included, even if none of the interfaces that
9378 * need it are included.  The #if hackery needed to avoid it would be
9379 * sufficiently pervasive that it's not worth the loss of readability.
9380 */
9381struct constdef {
9382    char *name;
9383    long value;
9384};
9385
9386static int
9387conv_confname(PyObject *arg, int *valuep, struct constdef *table,
9388              size_t tablesize)
9389{
9390    if (PyLong_Check(arg)) {
9391        *valuep = PyLong_AS_LONG(arg);
9392        return 1;
9393    }
9394    else {
9395        /* look up the value in the table using a binary search */
9396        size_t lo = 0;
9397        size_t mid;
9398        size_t hi = tablesize;
9399        int cmp;
9400        const char *confname;
9401        if (!PyUnicode_Check(arg)) {
9402            PyErr_SetString(PyExc_TypeError,
9403                "configuration names must be strings or integers");
9404            return 0;
9405        }
9406        confname = _PyUnicode_AsString(arg);
9407        if (confname == NULL)
9408            return 0;
9409        while (lo < hi) {
9410            mid = (lo + hi) / 2;
9411            cmp = strcmp(confname, table[mid].name);
9412            if (cmp < 0)
9413                hi = mid;
9414            else if (cmp > 0)
9415                lo = mid + 1;
9416            else {
9417                *valuep = table[mid].value;
9418                return 1;
9419            }
9420        }
9421        PyErr_SetString(PyExc_ValueError, "unrecognized configuration name");
9422        return 0;
9423    }
9424}
9425
9426
9427#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
9428static struct constdef  posix_constants_pathconf[] = {
9429#ifdef _PC_ABI_AIO_XFER_MAX
9430    {"PC_ABI_AIO_XFER_MAX",     _PC_ABI_AIO_XFER_MAX},
9431#endif
9432#ifdef _PC_ABI_ASYNC_IO
9433    {"PC_ABI_ASYNC_IO", _PC_ABI_ASYNC_IO},
9434#endif
9435#ifdef _PC_ASYNC_IO
9436    {"PC_ASYNC_IO",     _PC_ASYNC_IO},
9437#endif
9438#ifdef _PC_CHOWN_RESTRICTED
9439    {"PC_CHOWN_RESTRICTED",     _PC_CHOWN_RESTRICTED},
9440#endif
9441#ifdef _PC_FILESIZEBITS
9442    {"PC_FILESIZEBITS", _PC_FILESIZEBITS},
9443#endif
9444#ifdef _PC_LAST
9445    {"PC_LAST", _PC_LAST},
9446#endif
9447#ifdef _PC_LINK_MAX
9448    {"PC_LINK_MAX",     _PC_LINK_MAX},
9449#endif
9450#ifdef _PC_MAX_CANON
9451    {"PC_MAX_CANON",    _PC_MAX_CANON},
9452#endif
9453#ifdef _PC_MAX_INPUT
9454    {"PC_MAX_INPUT",    _PC_MAX_INPUT},
9455#endif
9456#ifdef _PC_NAME_MAX
9457    {"PC_NAME_MAX",     _PC_NAME_MAX},
9458#endif
9459#ifdef _PC_NO_TRUNC
9460    {"PC_NO_TRUNC",     _PC_NO_TRUNC},
9461#endif
9462#ifdef _PC_PATH_MAX
9463    {"PC_PATH_MAX",     _PC_PATH_MAX},
9464#endif
9465#ifdef _PC_PIPE_BUF
9466    {"PC_PIPE_BUF",     _PC_PIPE_BUF},
9467#endif
9468#ifdef _PC_PRIO_IO
9469    {"PC_PRIO_IO",      _PC_PRIO_IO},
9470#endif
9471#ifdef _PC_SOCK_MAXBUF
9472    {"PC_SOCK_MAXBUF",  _PC_SOCK_MAXBUF},
9473#endif
9474#ifdef _PC_SYNC_IO
9475    {"PC_SYNC_IO",      _PC_SYNC_IO},
9476#endif
9477#ifdef _PC_VDISABLE
9478    {"PC_VDISABLE",     _PC_VDISABLE},
9479#endif
9480#ifdef _PC_ACL_ENABLED
9481    {"PC_ACL_ENABLED",  _PC_ACL_ENABLED},
9482#endif
9483#ifdef _PC_MIN_HOLE_SIZE
9484    {"PC_MIN_HOLE_SIZE",    _PC_MIN_HOLE_SIZE},
9485#endif
9486#ifdef _PC_ALLOC_SIZE_MIN
9487    {"PC_ALLOC_SIZE_MIN",   _PC_ALLOC_SIZE_MIN},
9488#endif
9489#ifdef _PC_REC_INCR_XFER_SIZE
9490    {"PC_REC_INCR_XFER_SIZE",   _PC_REC_INCR_XFER_SIZE},
9491#endif
9492#ifdef _PC_REC_MAX_XFER_SIZE
9493    {"PC_REC_MAX_XFER_SIZE",    _PC_REC_MAX_XFER_SIZE},
9494#endif
9495#ifdef _PC_REC_MIN_XFER_SIZE
9496    {"PC_REC_MIN_XFER_SIZE",    _PC_REC_MIN_XFER_SIZE},
9497#endif
9498#ifdef _PC_REC_XFER_ALIGN
9499    {"PC_REC_XFER_ALIGN",   _PC_REC_XFER_ALIGN},
9500#endif
9501#ifdef _PC_SYMLINK_MAX
9502    {"PC_SYMLINK_MAX",  _PC_SYMLINK_MAX},
9503#endif
9504#ifdef _PC_XATTR_ENABLED
9505    {"PC_XATTR_ENABLED",    _PC_XATTR_ENABLED},
9506#endif
9507#ifdef _PC_XATTR_EXISTS
9508    {"PC_XATTR_EXISTS", _PC_XATTR_EXISTS},
9509#endif
9510#ifdef _PC_TIMESTAMP_RESOLUTION
9511    {"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
9512#endif
9513};
9514
9515static int
9516conv_path_confname(PyObject *arg, int *valuep)
9517{
9518    return conv_confname(arg, valuep, posix_constants_pathconf,
9519                         sizeof(posix_constants_pathconf)
9520                           / sizeof(struct constdef));
9521}
9522#endif
9523
9524#ifdef HAVE_FPATHCONF
9525PyDoc_STRVAR(posix_fpathconf__doc__,
9526"fpathconf(fd, name) -> integer\n\n\
9527Return the configuration limit name for the file descriptor fd.\n\
9528If there is no limit, return -1.");
9529
9530static PyObject *
9531posix_fpathconf(PyObject *self, PyObject *args)
9532{
9533    PyObject *result = NULL;
9534    int name, fd;
9535
9536    if (PyArg_ParseTuple(args, "iO&:fpathconf", &fd,
9537                         conv_path_confname, &name)) {
9538        long limit;
9539
9540        errno = 0;
9541        limit = fpathconf(fd, name);
9542        if (limit == -1 && errno != 0)
9543            posix_error();
9544        else
9545            result = PyLong_FromLong(limit);
9546    }
9547    return result;
9548}
9549#endif
9550
9551
9552#ifdef HAVE_PATHCONF
9553PyDoc_STRVAR(posix_pathconf__doc__,
9554"pathconf(path, name) -> integer\n\n\
9555Return the configuration limit name for the file or directory path.\n\
9556If there is no limit, return -1.\n\
9557On some platforms, path may also be specified as an open file descriptor.\n\
9558  If this functionality is unavailable, using it raises an exception.");
9559
9560static PyObject *
9561posix_pathconf(PyObject *self, PyObject *args, PyObject *kwargs)
9562{
9563    path_t path;
9564    PyObject *result = NULL;
9565    int name;
9566    static char *keywords[] = {"path", "name", NULL};
9567
9568    memset(&path, 0, sizeof(path));
9569    path.function_name = "pathconf";
9570#ifdef HAVE_FPATHCONF
9571    path.allow_fd = 1;
9572#endif
9573    if (PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:pathconf", keywords,
9574                                    path_converter, &path,
9575                                    conv_path_confname, &name)) {
9576    long limit;
9577
9578    errno = 0;
9579#ifdef HAVE_FPATHCONF
9580    if (path.fd != -1)
9581        limit = fpathconf(path.fd, name);
9582    else
9583#endif
9584        limit = pathconf(path.narrow, name);
9585    if (limit == -1 && errno != 0) {
9586        if (errno == EINVAL)
9587            /* could be a path or name problem */
9588            posix_error();
9589        else
9590            result = path_error(&path);
9591    }
9592    else
9593        result = PyLong_FromLong(limit);
9594    }
9595    path_cleanup(&path);
9596    return result;
9597}
9598#endif
9599
9600#ifdef HAVE_CONFSTR
9601static struct constdef posix_constants_confstr[] = {
9602#ifdef _CS_ARCHITECTURE
9603    {"CS_ARCHITECTURE", _CS_ARCHITECTURE},
9604#endif
9605#ifdef _CS_GNU_LIBC_VERSION
9606    {"CS_GNU_LIBC_VERSION",     _CS_GNU_LIBC_VERSION},
9607#endif
9608#ifdef _CS_GNU_LIBPTHREAD_VERSION
9609    {"CS_GNU_LIBPTHREAD_VERSION",       _CS_GNU_LIBPTHREAD_VERSION},
9610#endif
9611#ifdef _CS_HOSTNAME
9612    {"CS_HOSTNAME",     _CS_HOSTNAME},
9613#endif
9614#ifdef _CS_HW_PROVIDER
9615    {"CS_HW_PROVIDER",  _CS_HW_PROVIDER},
9616#endif
9617#ifdef _CS_HW_SERIAL
9618    {"CS_HW_SERIAL",    _CS_HW_SERIAL},
9619#endif
9620#ifdef _CS_INITTAB_NAME
9621    {"CS_INITTAB_NAME", _CS_INITTAB_NAME},
9622#endif
9623#ifdef _CS_LFS64_CFLAGS
9624    {"CS_LFS64_CFLAGS", _CS_LFS64_CFLAGS},
9625#endif
9626#ifdef _CS_LFS64_LDFLAGS
9627    {"CS_LFS64_LDFLAGS",        _CS_LFS64_LDFLAGS},
9628#endif
9629#ifdef _CS_LFS64_LIBS
9630    {"CS_LFS64_LIBS",   _CS_LFS64_LIBS},
9631#endif
9632#ifdef _CS_LFS64_LINTFLAGS
9633    {"CS_LFS64_LINTFLAGS",      _CS_LFS64_LINTFLAGS},
9634#endif
9635#ifdef _CS_LFS_CFLAGS
9636    {"CS_LFS_CFLAGS",   _CS_LFS_CFLAGS},
9637#endif
9638#ifdef _CS_LFS_LDFLAGS
9639    {"CS_LFS_LDFLAGS",  _CS_LFS_LDFLAGS},
9640#endif
9641#ifdef _CS_LFS_LIBS
9642    {"CS_LFS_LIBS",     _CS_LFS_LIBS},
9643#endif
9644#ifdef _CS_LFS_LINTFLAGS
9645    {"CS_LFS_LINTFLAGS",        _CS_LFS_LINTFLAGS},
9646#endif
9647#ifdef _CS_MACHINE
9648    {"CS_MACHINE",      _CS_MACHINE},
9649#endif
9650#ifdef _CS_PATH
9651    {"CS_PATH", _CS_PATH},
9652#endif
9653#ifdef _CS_RELEASE
9654    {"CS_RELEASE",      _CS_RELEASE},
9655#endif
9656#ifdef _CS_SRPC_DOMAIN
9657    {"CS_SRPC_DOMAIN",  _CS_SRPC_DOMAIN},
9658#endif
9659#ifdef _CS_SYSNAME
9660    {"CS_SYSNAME",      _CS_SYSNAME},
9661#endif
9662#ifdef _CS_VERSION
9663    {"CS_VERSION",      _CS_VERSION},
9664#endif
9665#ifdef _CS_XBS5_ILP32_OFF32_CFLAGS
9666    {"CS_XBS5_ILP32_OFF32_CFLAGS",      _CS_XBS5_ILP32_OFF32_CFLAGS},
9667#endif
9668#ifdef _CS_XBS5_ILP32_OFF32_LDFLAGS
9669    {"CS_XBS5_ILP32_OFF32_LDFLAGS",     _CS_XBS5_ILP32_OFF32_LDFLAGS},
9670#endif
9671#ifdef _CS_XBS5_ILP32_OFF32_LIBS
9672    {"CS_XBS5_ILP32_OFF32_LIBS",        _CS_XBS5_ILP32_OFF32_LIBS},
9673#endif
9674#ifdef _CS_XBS5_ILP32_OFF32_LINTFLAGS
9675    {"CS_XBS5_ILP32_OFF32_LINTFLAGS",   _CS_XBS5_ILP32_OFF32_LINTFLAGS},
9676#endif
9677#ifdef _CS_XBS5_ILP32_OFFBIG_CFLAGS
9678    {"CS_XBS5_ILP32_OFFBIG_CFLAGS",     _CS_XBS5_ILP32_OFFBIG_CFLAGS},
9679#endif
9680#ifdef _CS_XBS5_ILP32_OFFBIG_LDFLAGS
9681    {"CS_XBS5_ILP32_OFFBIG_LDFLAGS",    _CS_XBS5_ILP32_OFFBIG_LDFLAGS},
9682#endif
9683#ifdef _CS_XBS5_ILP32_OFFBIG_LIBS
9684    {"CS_XBS5_ILP32_OFFBIG_LIBS",       _CS_XBS5_ILP32_OFFBIG_LIBS},
9685#endif
9686#ifdef _CS_XBS5_ILP32_OFFBIG_LINTFLAGS
9687    {"CS_XBS5_ILP32_OFFBIG_LINTFLAGS",  _CS_XBS5_ILP32_OFFBIG_LINTFLAGS},
9688#endif
9689#ifdef _CS_XBS5_LP64_OFF64_CFLAGS
9690    {"CS_XBS5_LP64_OFF64_CFLAGS",       _CS_XBS5_LP64_OFF64_CFLAGS},
9691#endif
9692#ifdef _CS_XBS5_LP64_OFF64_LDFLAGS
9693    {"CS_XBS5_LP64_OFF64_LDFLAGS",      _CS_XBS5_LP64_OFF64_LDFLAGS},
9694#endif
9695#ifdef _CS_XBS5_LP64_OFF64_LIBS
9696    {"CS_XBS5_LP64_OFF64_LIBS", _CS_XBS5_LP64_OFF64_LIBS},
9697#endif
9698#ifdef _CS_XBS5_LP64_OFF64_LINTFLAGS
9699    {"CS_XBS5_LP64_OFF64_LINTFLAGS",    _CS_XBS5_LP64_OFF64_LINTFLAGS},
9700#endif
9701#ifdef _CS_XBS5_LPBIG_OFFBIG_CFLAGS
9702    {"CS_XBS5_LPBIG_OFFBIG_CFLAGS",     _CS_XBS5_LPBIG_OFFBIG_CFLAGS},
9703#endif
9704#ifdef _CS_XBS5_LPBIG_OFFBIG_LDFLAGS
9705    {"CS_XBS5_LPBIG_OFFBIG_LDFLAGS",    _CS_XBS5_LPBIG_OFFBIG_LDFLAGS},
9706#endif
9707#ifdef _CS_XBS5_LPBIG_OFFBIG_LIBS
9708    {"CS_XBS5_LPBIG_OFFBIG_LIBS",       _CS_XBS5_LPBIG_OFFBIG_LIBS},
9709#endif
9710#ifdef _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS
9711    {"CS_XBS5_LPBIG_OFFBIG_LINTFLAGS",  _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS},
9712#endif
9713#ifdef _MIPS_CS_AVAIL_PROCESSORS
9714    {"MIPS_CS_AVAIL_PROCESSORS",        _MIPS_CS_AVAIL_PROCESSORS},
9715#endif
9716#ifdef _MIPS_CS_BASE
9717    {"MIPS_CS_BASE",    _MIPS_CS_BASE},
9718#endif
9719#ifdef _MIPS_CS_HOSTID
9720    {"MIPS_CS_HOSTID",  _MIPS_CS_HOSTID},
9721#endif
9722#ifdef _MIPS_CS_HW_NAME
9723    {"MIPS_CS_HW_NAME", _MIPS_CS_HW_NAME},
9724#endif
9725#ifdef _MIPS_CS_NUM_PROCESSORS
9726    {"MIPS_CS_NUM_PROCESSORS",  _MIPS_CS_NUM_PROCESSORS},
9727#endif
9728#ifdef _MIPS_CS_OSREL_MAJ
9729    {"MIPS_CS_OSREL_MAJ",       _MIPS_CS_OSREL_MAJ},
9730#endif
9731#ifdef _MIPS_CS_OSREL_MIN
9732    {"MIPS_CS_OSREL_MIN",       _MIPS_CS_OSREL_MIN},
9733#endif
9734#ifdef _MIPS_CS_OSREL_PATCH
9735    {"MIPS_CS_OSREL_PATCH",     _MIPS_CS_OSREL_PATCH},
9736#endif
9737#ifdef _MIPS_CS_OS_NAME
9738    {"MIPS_CS_OS_NAME", _MIPS_CS_OS_NAME},
9739#endif
9740#ifdef _MIPS_CS_OS_PROVIDER
9741    {"MIPS_CS_OS_PROVIDER",     _MIPS_CS_OS_PROVIDER},
9742#endif
9743#ifdef _MIPS_CS_PROCESSORS
9744    {"MIPS_CS_PROCESSORS",      _MIPS_CS_PROCESSORS},
9745#endif
9746#ifdef _MIPS_CS_SERIAL
9747    {"MIPS_CS_SERIAL",  _MIPS_CS_SERIAL},
9748#endif
9749#ifdef _MIPS_CS_VENDOR
9750    {"MIPS_CS_VENDOR",  _MIPS_CS_VENDOR},
9751#endif
9752};
9753
9754static int
9755conv_confstr_confname(PyObject *arg, int *valuep)
9756{
9757    return conv_confname(arg, valuep, posix_constants_confstr,
9758                         sizeof(posix_constants_confstr)
9759                           / sizeof(struct constdef));
9760}
9761
9762PyDoc_STRVAR(posix_confstr__doc__,
9763"confstr(name) -> string\n\n\
9764Return a string-valued system configuration variable.");
9765
9766static PyObject *
9767posix_confstr(PyObject *self, PyObject *args)
9768{
9769    PyObject *result = NULL;
9770    int name;
9771    char buffer[255];
9772    size_t len;
9773
9774    if (!PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name))
9775        return NULL;
9776
9777    errno = 0;
9778    len = confstr(name, buffer, sizeof(buffer));
9779    if (len == 0) {
9780        if (errno) {
9781            posix_error();
9782            return NULL;
9783        }
9784        else {
9785            Py_RETURN_NONE;
9786        }
9787    }
9788
9789    if (len >= sizeof(buffer)) {
9790        char *buf = PyMem_Malloc(len);
9791        if (buf == NULL)
9792            return PyErr_NoMemory();
9793        confstr(name, buf, len);
9794        result = PyUnicode_DecodeFSDefaultAndSize(buf, len-1);
9795        PyMem_Free(buf);
9796    }
9797    else
9798        result = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
9799    return result;
9800}
9801#endif
9802
9803
9804#ifdef HAVE_SYSCONF
9805static struct constdef posix_constants_sysconf[] = {
9806#ifdef _SC_2_CHAR_TERM
9807    {"SC_2_CHAR_TERM",  _SC_2_CHAR_TERM},
9808#endif
9809#ifdef _SC_2_C_BIND
9810    {"SC_2_C_BIND",     _SC_2_C_BIND},
9811#endif
9812#ifdef _SC_2_C_DEV
9813    {"SC_2_C_DEV",      _SC_2_C_DEV},
9814#endif
9815#ifdef _SC_2_C_VERSION
9816    {"SC_2_C_VERSION",  _SC_2_C_VERSION},
9817#endif
9818#ifdef _SC_2_FORT_DEV
9819    {"SC_2_FORT_DEV",   _SC_2_FORT_DEV},
9820#endif
9821#ifdef _SC_2_FORT_RUN
9822    {"SC_2_FORT_RUN",   _SC_2_FORT_RUN},
9823#endif
9824#ifdef _SC_2_LOCALEDEF
9825    {"SC_2_LOCALEDEF",  _SC_2_LOCALEDEF},
9826#endif
9827#ifdef _SC_2_SW_DEV
9828    {"SC_2_SW_DEV",     _SC_2_SW_DEV},
9829#endif
9830#ifdef _SC_2_UPE
9831    {"SC_2_UPE",        _SC_2_UPE},
9832#endif
9833#ifdef _SC_2_VERSION
9834    {"SC_2_VERSION",    _SC_2_VERSION},
9835#endif
9836#ifdef _SC_ABI_ASYNCHRONOUS_IO
9837    {"SC_ABI_ASYNCHRONOUS_IO",  _SC_ABI_ASYNCHRONOUS_IO},
9838#endif
9839#ifdef _SC_ACL
9840    {"SC_ACL",  _SC_ACL},
9841#endif
9842#ifdef _SC_AIO_LISTIO_MAX
9843    {"SC_AIO_LISTIO_MAX",       _SC_AIO_LISTIO_MAX},
9844#endif
9845#ifdef _SC_AIO_MAX
9846    {"SC_AIO_MAX",      _SC_AIO_MAX},
9847#endif
9848#ifdef _SC_AIO_PRIO_DELTA_MAX
9849    {"SC_AIO_PRIO_DELTA_MAX",   _SC_AIO_PRIO_DELTA_MAX},
9850#endif
9851#ifdef _SC_ARG_MAX
9852    {"SC_ARG_MAX",      _SC_ARG_MAX},
9853#endif
9854#ifdef _SC_ASYNCHRONOUS_IO
9855    {"SC_ASYNCHRONOUS_IO",      _SC_ASYNCHRONOUS_IO},
9856#endif
9857#ifdef _SC_ATEXIT_MAX
9858    {"SC_ATEXIT_MAX",   _SC_ATEXIT_MAX},
9859#endif
9860#ifdef _SC_AUDIT
9861    {"SC_AUDIT",        _SC_AUDIT},
9862#endif
9863#ifdef _SC_AVPHYS_PAGES
9864    {"SC_AVPHYS_PAGES", _SC_AVPHYS_PAGES},
9865#endif
9866#ifdef _SC_BC_BASE_MAX
9867    {"SC_BC_BASE_MAX",  _SC_BC_BASE_MAX},
9868#endif
9869#ifdef _SC_BC_DIM_MAX
9870    {"SC_BC_DIM_MAX",   _SC_BC_DIM_MAX},
9871#endif
9872#ifdef _SC_BC_SCALE_MAX
9873    {"SC_BC_SCALE_MAX", _SC_BC_SCALE_MAX},
9874#endif
9875#ifdef _SC_BC_STRING_MAX
9876    {"SC_BC_STRING_MAX",        _SC_BC_STRING_MAX},
9877#endif
9878#ifdef _SC_CAP
9879    {"SC_CAP",  _SC_CAP},
9880#endif
9881#ifdef _SC_CHARCLASS_NAME_MAX
9882    {"SC_CHARCLASS_NAME_MAX",   _SC_CHARCLASS_NAME_MAX},
9883#endif
9884#ifdef _SC_CHAR_BIT
9885    {"SC_CHAR_BIT",     _SC_CHAR_BIT},
9886#endif
9887#ifdef _SC_CHAR_MAX
9888    {"SC_CHAR_MAX",     _SC_CHAR_MAX},
9889#endif
9890#ifdef _SC_CHAR_MIN
9891    {"SC_CHAR_MIN",     _SC_CHAR_MIN},
9892#endif
9893#ifdef _SC_CHILD_MAX
9894    {"SC_CHILD_MAX",    _SC_CHILD_MAX},
9895#endif
9896#ifdef _SC_CLK_TCK
9897    {"SC_CLK_TCK",      _SC_CLK_TCK},
9898#endif
9899#ifdef _SC_COHER_BLKSZ
9900    {"SC_COHER_BLKSZ",  _SC_COHER_BLKSZ},
9901#endif
9902#ifdef _SC_COLL_WEIGHTS_MAX
9903    {"SC_COLL_WEIGHTS_MAX",     _SC_COLL_WEIGHTS_MAX},
9904#endif
9905#ifdef _SC_DCACHE_ASSOC
9906    {"SC_DCACHE_ASSOC", _SC_DCACHE_ASSOC},
9907#endif
9908#ifdef _SC_DCACHE_BLKSZ
9909    {"SC_DCACHE_BLKSZ", _SC_DCACHE_BLKSZ},
9910#endif
9911#ifdef _SC_DCACHE_LINESZ
9912    {"SC_DCACHE_LINESZ",        _SC_DCACHE_LINESZ},
9913#endif
9914#ifdef _SC_DCACHE_SZ
9915    {"SC_DCACHE_SZ",    _SC_DCACHE_SZ},
9916#endif
9917#ifdef _SC_DCACHE_TBLKSZ
9918    {"SC_DCACHE_TBLKSZ",        _SC_DCACHE_TBLKSZ},
9919#endif
9920#ifdef _SC_DELAYTIMER_MAX
9921    {"SC_DELAYTIMER_MAX",       _SC_DELAYTIMER_MAX},
9922#endif
9923#ifdef _SC_EQUIV_CLASS_MAX
9924    {"SC_EQUIV_CLASS_MAX",      _SC_EQUIV_CLASS_MAX},
9925#endif
9926#ifdef _SC_EXPR_NEST_MAX
9927    {"SC_EXPR_NEST_MAX",        _SC_EXPR_NEST_MAX},
9928#endif
9929#ifdef _SC_FSYNC
9930    {"SC_FSYNC",        _SC_FSYNC},
9931#endif
9932#ifdef _SC_GETGR_R_SIZE_MAX
9933    {"SC_GETGR_R_SIZE_MAX",     _SC_GETGR_R_SIZE_MAX},
9934#endif
9935#ifdef _SC_GETPW_R_SIZE_MAX
9936    {"SC_GETPW_R_SIZE_MAX",     _SC_GETPW_R_SIZE_MAX},
9937#endif
9938#ifdef _SC_ICACHE_ASSOC
9939    {"SC_ICACHE_ASSOC", _SC_ICACHE_ASSOC},
9940#endif
9941#ifdef _SC_ICACHE_BLKSZ
9942    {"SC_ICACHE_BLKSZ", _SC_ICACHE_BLKSZ},
9943#endif
9944#ifdef _SC_ICACHE_LINESZ
9945    {"SC_ICACHE_LINESZ",        _SC_ICACHE_LINESZ},
9946#endif
9947#ifdef _SC_ICACHE_SZ
9948    {"SC_ICACHE_SZ",    _SC_ICACHE_SZ},
9949#endif
9950#ifdef _SC_INF
9951    {"SC_INF",  _SC_INF},
9952#endif
9953#ifdef _SC_INT_MAX
9954    {"SC_INT_MAX",      _SC_INT_MAX},
9955#endif
9956#ifdef _SC_INT_MIN
9957    {"SC_INT_MIN",      _SC_INT_MIN},
9958#endif
9959#ifdef _SC_IOV_MAX
9960    {"SC_IOV_MAX",      _SC_IOV_MAX},
9961#endif
9962#ifdef _SC_IP_SECOPTS
9963    {"SC_IP_SECOPTS",   _SC_IP_SECOPTS},
9964#endif
9965#ifdef _SC_JOB_CONTROL
9966    {"SC_JOB_CONTROL",  _SC_JOB_CONTROL},
9967#endif
9968#ifdef _SC_KERN_POINTERS
9969    {"SC_KERN_POINTERS",        _SC_KERN_POINTERS},
9970#endif
9971#ifdef _SC_KERN_SIM
9972    {"SC_KERN_SIM",     _SC_KERN_SIM},
9973#endif
9974#ifdef _SC_LINE_MAX
9975    {"SC_LINE_MAX",     _SC_LINE_MAX},
9976#endif
9977#ifdef _SC_LOGIN_NAME_MAX
9978    {"SC_LOGIN_NAME_MAX",       _SC_LOGIN_NAME_MAX},
9979#endif
9980#ifdef _SC_LOGNAME_MAX
9981    {"SC_LOGNAME_MAX",  _SC_LOGNAME_MAX},
9982#endif
9983#ifdef _SC_LONG_BIT
9984    {"SC_LONG_BIT",     _SC_LONG_BIT},
9985#endif
9986#ifdef _SC_MAC
9987    {"SC_MAC",  _SC_MAC},
9988#endif
9989#ifdef _SC_MAPPED_FILES
9990    {"SC_MAPPED_FILES", _SC_MAPPED_FILES},
9991#endif
9992#ifdef _SC_MAXPID
9993    {"SC_MAXPID",       _SC_MAXPID},
9994#endif
9995#ifdef _SC_MB_LEN_MAX
9996    {"SC_MB_LEN_MAX",   _SC_MB_LEN_MAX},
9997#endif
9998#ifdef _SC_MEMLOCK
9999    {"SC_MEMLOCK",      _SC_MEMLOCK},
10000#endif
10001#ifdef _SC_MEMLOCK_RANGE
10002    {"SC_MEMLOCK_RANGE",        _SC_MEMLOCK_RANGE},
10003#endif
10004#ifdef _SC_MEMORY_PROTECTION
10005    {"SC_MEMORY_PROTECTION",    _SC_MEMORY_PROTECTION},
10006#endif
10007#ifdef _SC_MESSAGE_PASSING
10008    {"SC_MESSAGE_PASSING",      _SC_MESSAGE_PASSING},
10009#endif
10010#ifdef _SC_MMAP_FIXED_ALIGNMENT
10011    {"SC_MMAP_FIXED_ALIGNMENT", _SC_MMAP_FIXED_ALIGNMENT},
10012#endif
10013#ifdef _SC_MQ_OPEN_MAX
10014    {"SC_MQ_OPEN_MAX",  _SC_MQ_OPEN_MAX},
10015#endif
10016#ifdef _SC_MQ_PRIO_MAX
10017    {"SC_MQ_PRIO_MAX",  _SC_MQ_PRIO_MAX},
10018#endif
10019#ifdef _SC_NACLS_MAX
10020    {"SC_NACLS_MAX",    _SC_NACLS_MAX},
10021#endif
10022#ifdef _SC_NGROUPS_MAX
10023    {"SC_NGROUPS_MAX",  _SC_NGROUPS_MAX},
10024#endif
10025#ifdef _SC_NL_ARGMAX
10026    {"SC_NL_ARGMAX",    _SC_NL_ARGMAX},
10027#endif
10028#ifdef _SC_NL_LANGMAX
10029    {"SC_NL_LANGMAX",   _SC_NL_LANGMAX},
10030#endif
10031#ifdef _SC_NL_MSGMAX
10032    {"SC_NL_MSGMAX",    _SC_NL_MSGMAX},
10033#endif
10034#ifdef _SC_NL_NMAX
10035    {"SC_NL_NMAX",      _SC_NL_NMAX},
10036#endif
10037#ifdef _SC_NL_SETMAX
10038    {"SC_NL_SETMAX",    _SC_NL_SETMAX},
10039#endif
10040#ifdef _SC_NL_TEXTMAX
10041    {"SC_NL_TEXTMAX",   _SC_NL_TEXTMAX},
10042#endif
10043#ifdef _SC_NPROCESSORS_CONF
10044    {"SC_NPROCESSORS_CONF",     _SC_NPROCESSORS_CONF},
10045#endif
10046#ifdef _SC_NPROCESSORS_ONLN
10047    {"SC_NPROCESSORS_ONLN",     _SC_NPROCESSORS_ONLN},
10048#endif
10049#ifdef _SC_NPROC_CONF
10050    {"SC_NPROC_CONF",   _SC_NPROC_CONF},
10051#endif
10052#ifdef _SC_NPROC_ONLN
10053    {"SC_NPROC_ONLN",   _SC_NPROC_ONLN},
10054#endif
10055#ifdef _SC_NZERO
10056    {"SC_NZERO",        _SC_NZERO},
10057#endif
10058#ifdef _SC_OPEN_MAX
10059    {"SC_OPEN_MAX",     _SC_OPEN_MAX},
10060#endif
10061#ifdef _SC_PAGESIZE
10062    {"SC_PAGESIZE",     _SC_PAGESIZE},
10063#endif
10064#ifdef _SC_PAGE_SIZE
10065    {"SC_PAGE_SIZE",    _SC_PAGE_SIZE},
10066#endif
10067#ifdef _SC_PASS_MAX
10068    {"SC_PASS_MAX",     _SC_PASS_MAX},
10069#endif
10070#ifdef _SC_PHYS_PAGES
10071    {"SC_PHYS_PAGES",   _SC_PHYS_PAGES},
10072#endif
10073#ifdef _SC_PII
10074    {"SC_PII",  _SC_PII},
10075#endif
10076#ifdef _SC_PII_INTERNET
10077    {"SC_PII_INTERNET", _SC_PII_INTERNET},
10078#endif
10079#ifdef _SC_PII_INTERNET_DGRAM
10080    {"SC_PII_INTERNET_DGRAM",   _SC_PII_INTERNET_DGRAM},
10081#endif
10082#ifdef _SC_PII_INTERNET_STREAM
10083    {"SC_PII_INTERNET_STREAM",  _SC_PII_INTERNET_STREAM},
10084#endif
10085#ifdef _SC_PII_OSI
10086    {"SC_PII_OSI",      _SC_PII_OSI},
10087#endif
10088#ifdef _SC_PII_OSI_CLTS
10089    {"SC_PII_OSI_CLTS", _SC_PII_OSI_CLTS},
10090#endif
10091#ifdef _SC_PII_OSI_COTS
10092    {"SC_PII_OSI_COTS", _SC_PII_OSI_COTS},
10093#endif
10094#ifdef _SC_PII_OSI_M
10095    {"SC_PII_OSI_M",    _SC_PII_OSI_M},
10096#endif
10097#ifdef _SC_PII_SOCKET
10098    {"SC_PII_SOCKET",   _SC_PII_SOCKET},
10099#endif
10100#ifdef _SC_PII_XTI
10101    {"SC_PII_XTI",      _SC_PII_XTI},
10102#endif
10103#ifdef _SC_POLL
10104    {"SC_POLL", _SC_POLL},
10105#endif
10106#ifdef _SC_PRIORITIZED_IO
10107    {"SC_PRIORITIZED_IO",       _SC_PRIORITIZED_IO},
10108#endif
10109#ifdef _SC_PRIORITY_SCHEDULING
10110    {"SC_PRIORITY_SCHEDULING",  _SC_PRIORITY_SCHEDULING},
10111#endif
10112#ifdef _SC_REALTIME_SIGNALS
10113    {"SC_REALTIME_SIGNALS",     _SC_REALTIME_SIGNALS},
10114#endif
10115#ifdef _SC_RE_DUP_MAX
10116    {"SC_RE_DUP_MAX",   _SC_RE_DUP_MAX},
10117#endif
10118#ifdef _SC_RTSIG_MAX
10119    {"SC_RTSIG_MAX",    _SC_RTSIG_MAX},
10120#endif
10121#ifdef _SC_SAVED_IDS
10122    {"SC_SAVED_IDS",    _SC_SAVED_IDS},
10123#endif
10124#ifdef _SC_SCHAR_MAX
10125    {"SC_SCHAR_MAX",    _SC_SCHAR_MAX},
10126#endif
10127#ifdef _SC_SCHAR_MIN
10128    {"SC_SCHAR_MIN",    _SC_SCHAR_MIN},
10129#endif
10130#ifdef _SC_SELECT
10131    {"SC_SELECT",       _SC_SELECT},
10132#endif
10133#ifdef _SC_SEMAPHORES
10134    {"SC_SEMAPHORES",   _SC_SEMAPHORES},
10135#endif
10136#ifdef _SC_SEM_NSEMS_MAX
10137    {"SC_SEM_NSEMS_MAX",        _SC_SEM_NSEMS_MAX},
10138#endif
10139#ifdef _SC_SEM_VALUE_MAX
10140    {"SC_SEM_VALUE_MAX",        _SC_SEM_VALUE_MAX},
10141#endif
10142#ifdef _SC_SHARED_MEMORY_OBJECTS
10143    {"SC_SHARED_MEMORY_OBJECTS",        _SC_SHARED_MEMORY_OBJECTS},
10144#endif
10145#ifdef _SC_SHRT_MAX
10146    {"SC_SHRT_MAX",     _SC_SHRT_MAX},
10147#endif
10148#ifdef _SC_SHRT_MIN
10149    {"SC_SHRT_MIN",     _SC_SHRT_MIN},
10150#endif
10151#ifdef _SC_SIGQUEUE_MAX
10152    {"SC_SIGQUEUE_MAX", _SC_SIGQUEUE_MAX},
10153#endif
10154#ifdef _SC_SIGRT_MAX
10155    {"SC_SIGRT_MAX",    _SC_SIGRT_MAX},
10156#endif
10157#ifdef _SC_SIGRT_MIN
10158    {"SC_SIGRT_MIN",    _SC_SIGRT_MIN},
10159#endif
10160#ifdef _SC_SOFTPOWER
10161    {"SC_SOFTPOWER",    _SC_SOFTPOWER},
10162#endif
10163#ifdef _SC_SPLIT_CACHE
10164    {"SC_SPLIT_CACHE",  _SC_SPLIT_CACHE},
10165#endif
10166#ifdef _SC_SSIZE_MAX
10167    {"SC_SSIZE_MAX",    _SC_SSIZE_MAX},
10168#endif
10169#ifdef _SC_STACK_PROT
10170    {"SC_STACK_PROT",   _SC_STACK_PROT},
10171#endif
10172#ifdef _SC_STREAM_MAX
10173    {"SC_STREAM_MAX",   _SC_STREAM_MAX},
10174#endif
10175#ifdef _SC_SYNCHRONIZED_IO
10176    {"SC_SYNCHRONIZED_IO",      _SC_SYNCHRONIZED_IO},
10177#endif
10178#ifdef _SC_THREADS
10179    {"SC_THREADS",      _SC_THREADS},
10180#endif
10181#ifdef _SC_THREAD_ATTR_STACKADDR
10182    {"SC_THREAD_ATTR_STACKADDR",        _SC_THREAD_ATTR_STACKADDR},
10183#endif
10184#ifdef _SC_THREAD_ATTR_STACKSIZE
10185    {"SC_THREAD_ATTR_STACKSIZE",        _SC_THREAD_ATTR_STACKSIZE},
10186#endif
10187#ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS
10188    {"SC_THREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS},
10189#endif
10190#ifdef _SC_THREAD_KEYS_MAX
10191    {"SC_THREAD_KEYS_MAX",      _SC_THREAD_KEYS_MAX},
10192#endif
10193#ifdef _SC_THREAD_PRIORITY_SCHEDULING
10194    {"SC_THREAD_PRIORITY_SCHEDULING",   _SC_THREAD_PRIORITY_SCHEDULING},
10195#endif
10196#ifdef _SC_THREAD_PRIO_INHERIT
10197    {"SC_THREAD_PRIO_INHERIT",  _SC_THREAD_PRIO_INHERIT},
10198#endif
10199#ifdef _SC_THREAD_PRIO_PROTECT
10200    {"SC_THREAD_PRIO_PROTECT",  _SC_THREAD_PRIO_PROTECT},
10201#endif
10202#ifdef _SC_THREAD_PROCESS_SHARED
10203    {"SC_THREAD_PROCESS_SHARED",        _SC_THREAD_PROCESS_SHARED},
10204#endif
10205#ifdef _SC_THREAD_SAFE_FUNCTIONS
10206    {"SC_THREAD_SAFE_FUNCTIONS",        _SC_THREAD_SAFE_FUNCTIONS},
10207#endif
10208#ifdef _SC_THREAD_STACK_MIN
10209    {"SC_THREAD_STACK_MIN",     _SC_THREAD_STACK_MIN},
10210#endif
10211#ifdef _SC_THREAD_THREADS_MAX
10212    {"SC_THREAD_THREADS_MAX",   _SC_THREAD_THREADS_MAX},
10213#endif
10214#ifdef _SC_TIMERS
10215    {"SC_TIMERS",       _SC_TIMERS},
10216#endif
10217#ifdef _SC_TIMER_MAX
10218    {"SC_TIMER_MAX",    _SC_TIMER_MAX},
10219#endif
10220#ifdef _SC_TTY_NAME_MAX
10221    {"SC_TTY_NAME_MAX", _SC_TTY_NAME_MAX},
10222#endif
10223#ifdef _SC_TZNAME_MAX
10224    {"SC_TZNAME_MAX",   _SC_TZNAME_MAX},
10225#endif
10226#ifdef _SC_T_IOV_MAX
10227    {"SC_T_IOV_MAX",    _SC_T_IOV_MAX},
10228#endif
10229#ifdef _SC_UCHAR_MAX
10230    {"SC_UCHAR_MAX",    _SC_UCHAR_MAX},
10231#endif
10232#ifdef _SC_UINT_MAX
10233    {"SC_UINT_MAX",     _SC_UINT_MAX},
10234#endif
10235#ifdef _SC_UIO_MAXIOV
10236    {"SC_UIO_MAXIOV",   _SC_UIO_MAXIOV},
10237#endif
10238#ifdef _SC_ULONG_MAX
10239    {"SC_ULONG_MAX",    _SC_ULONG_MAX},
10240#endif
10241#ifdef _SC_USHRT_MAX
10242    {"SC_USHRT_MAX",    _SC_USHRT_MAX},
10243#endif
10244#ifdef _SC_VERSION
10245    {"SC_VERSION",      _SC_VERSION},
10246#endif
10247#ifdef _SC_WORD_BIT
10248    {"SC_WORD_BIT",     _SC_WORD_BIT},
10249#endif
10250#ifdef _SC_XBS5_ILP32_OFF32
10251    {"SC_XBS5_ILP32_OFF32",     _SC_XBS5_ILP32_OFF32},
10252#endif
10253#ifdef _SC_XBS5_ILP32_OFFBIG
10254    {"SC_XBS5_ILP32_OFFBIG",    _SC_XBS5_ILP32_OFFBIG},
10255#endif
10256#ifdef _SC_XBS5_LP64_OFF64
10257    {"SC_XBS5_LP64_OFF64",      _SC_XBS5_LP64_OFF64},
10258#endif
10259#ifdef _SC_XBS5_LPBIG_OFFBIG
10260    {"SC_XBS5_LPBIG_OFFBIG",    _SC_XBS5_LPBIG_OFFBIG},
10261#endif
10262#ifdef _SC_XOPEN_CRYPT
10263    {"SC_XOPEN_CRYPT",  _SC_XOPEN_CRYPT},
10264#endif
10265#ifdef _SC_XOPEN_ENH_I18N
10266    {"SC_XOPEN_ENH_I18N",       _SC_XOPEN_ENH_I18N},
10267#endif
10268#ifdef _SC_XOPEN_LEGACY
10269    {"SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY},
10270#endif
10271#ifdef _SC_XOPEN_REALTIME
10272    {"SC_XOPEN_REALTIME",       _SC_XOPEN_REALTIME},
10273#endif
10274#ifdef _SC_XOPEN_REALTIME_THREADS
10275    {"SC_XOPEN_REALTIME_THREADS",       _SC_XOPEN_REALTIME_THREADS},
10276#endif
10277#ifdef _SC_XOPEN_SHM
10278    {"SC_XOPEN_SHM",    _SC_XOPEN_SHM},
10279#endif
10280#ifdef _SC_XOPEN_UNIX
10281    {"SC_XOPEN_UNIX",   _SC_XOPEN_UNIX},
10282#endif
10283#ifdef _SC_XOPEN_VERSION
10284    {"SC_XOPEN_VERSION",        _SC_XOPEN_VERSION},
10285#endif
10286#ifdef _SC_XOPEN_XCU_VERSION
10287    {"SC_XOPEN_XCU_VERSION",    _SC_XOPEN_XCU_VERSION},
10288#endif
10289#ifdef _SC_XOPEN_XPG2
10290    {"SC_XOPEN_XPG2",   _SC_XOPEN_XPG2},
10291#endif
10292#ifdef _SC_XOPEN_XPG3
10293    {"SC_XOPEN_XPG3",   _SC_XOPEN_XPG3},
10294#endif
10295#ifdef _SC_XOPEN_XPG4
10296    {"SC_XOPEN_XPG4",   _SC_XOPEN_XPG4},
10297#endif
10298};
10299
10300static int
10301conv_sysconf_confname(PyObject *arg, int *valuep)
10302{
10303    return conv_confname(arg, valuep, posix_constants_sysconf,
10304                         sizeof(posix_constants_sysconf)
10305                           / sizeof(struct constdef));
10306}
10307
10308PyDoc_STRVAR(posix_sysconf__doc__,
10309"sysconf(name) -> integer\n\n\
10310Return an integer-valued system configuration variable.");
10311
10312static PyObject *
10313posix_sysconf(PyObject *self, PyObject *args)
10314{
10315    PyObject *result = NULL;
10316    int name;
10317
10318    if (PyArg_ParseTuple(args, "O&:sysconf", conv_sysconf_confname, &name)) {
10319        long value;
10320
10321        errno = 0;
10322        value = sysconf(name);
10323        if (value == -1 && errno != 0)
10324            posix_error();
10325        else
10326            result = PyLong_FromLong(value);
10327    }
10328    return result;
10329}
10330#endif
10331
10332
10333/* This code is used to ensure that the tables of configuration value names
10334 * are in sorted order as required by conv_confname(), and also to build
10335 * the exported dictionaries that are used to publish information about the
10336 * names available on the host platform.
10337 *
10338 * Sorting the table at runtime ensures that the table is properly ordered
10339 * when used, even for platforms we're not able to test on.  It also makes
10340 * it easier to add additional entries to the tables.
10341 */
10342
10343static int
10344cmp_constdefs(const void *v1,  const void *v2)
10345{
10346    const struct constdef *c1 =
10347    (const struct constdef *) v1;
10348    const struct constdef *c2 =
10349    (const struct constdef *) v2;
10350
10351    return strcmp(c1->name, c2->name);
10352}
10353
10354static int
10355setup_confname_table(struct constdef *table, size_t tablesize,
10356                     char *tablename, PyObject *module)
10357{
10358    PyObject *d = NULL;
10359    size_t i;
10360
10361    qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs);
10362    d = PyDict_New();
10363    if (d == NULL)
10364        return -1;
10365
10366    for (i=0; i < tablesize; ++i) {
10367        PyObject *o = PyLong_FromLong(table[i].value);
10368        if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) {
10369            Py_XDECREF(o);
10370            Py_DECREF(d);
10371            return -1;
10372        }
10373        Py_DECREF(o);
10374    }
10375    return PyModule_AddObject(module, tablename, d);
10376}
10377
10378/* Return -1 on failure, 0 on success. */
10379static int
10380setup_confname_tables(PyObject *module)
10381{
10382#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
10383    if (setup_confname_table(posix_constants_pathconf,
10384                             sizeof(posix_constants_pathconf)
10385                               / sizeof(struct constdef),
10386                             "pathconf_names", module))
10387        return -1;
10388#endif
10389#ifdef HAVE_CONFSTR
10390    if (setup_confname_table(posix_constants_confstr,
10391                             sizeof(posix_constants_confstr)
10392                               / sizeof(struct constdef),
10393                             "confstr_names", module))
10394        return -1;
10395#endif
10396#ifdef HAVE_SYSCONF
10397    if (setup_confname_table(posix_constants_sysconf,
10398                             sizeof(posix_constants_sysconf)
10399                               / sizeof(struct constdef),
10400                             "sysconf_names", module))
10401        return -1;
10402#endif
10403    return 0;
10404}
10405
10406
10407PyDoc_STRVAR(posix_abort__doc__,
10408"abort() -> does not return!\n\n\
10409Abort the interpreter immediately.  This 'dumps core' or otherwise fails\n\
10410in the hardest way possible on the hosting operating system.");
10411
10412static PyObject *
10413posix_abort(PyObject *self, PyObject *noargs)
10414{
10415    abort();
10416    /*NOTREACHED*/
10417    Py_FatalError("abort() called from Python code didn't abort!");
10418    return NULL;
10419}
10420
10421#ifdef MS_WINDOWS
10422PyDoc_STRVAR(win32_startfile__doc__,
10423"startfile(filepath [, operation]) - Start a file with its associated\n\
10424application.\n\
10425\n\
10426When \"operation\" is not specified or \"open\", this acts like\n\
10427double-clicking the file in Explorer, or giving the file name as an\n\
10428argument to the DOS \"start\" command: the file is opened with whatever\n\
10429application (if any) its extension is associated.\n\
10430When another \"operation\" is given, it specifies what should be done with\n\
10431the file.  A typical operation is \"print\".\n\
10432\n\
10433startfile returns as soon as the associated application is launched.\n\
10434There is no option to wait for the application to close, and no way\n\
10435to retrieve the application's exit status.\n\
10436\n\
10437The filepath is relative to the current directory.  If you want to use\n\
10438an absolute path, make sure the first character is not a slash (\"/\");\n\
10439the underlying Win32 ShellExecute function doesn't work if it is.");
10440
10441static PyObject *
10442win32_startfile(PyObject *self, PyObject *args)
10443{
10444    PyObject *ofilepath;
10445    char *filepath;
10446    char *operation = NULL;
10447    wchar_t *wpath, *woperation;
10448    HINSTANCE rc;
10449
10450    PyObject *unipath, *uoperation = NULL;
10451    if (!PyArg_ParseTuple(args, "U|s:startfile",
10452                          &unipath, &operation)) {
10453        PyErr_Clear();
10454        goto normal;
10455    }
10456
10457    if (operation) {
10458        uoperation = PyUnicode_DecodeASCII(operation,
10459                                           strlen(operation), NULL);
10460        if (!uoperation) {
10461            PyErr_Clear();
10462            operation = NULL;
10463            goto normal;
10464        }
10465    }
10466
10467    wpath = PyUnicode_AsUnicode(unipath);
10468    if (wpath == NULL)
10469        goto normal;
10470    if (uoperation) {
10471        woperation = PyUnicode_AsUnicode(uoperation);
10472        if (woperation == NULL)
10473            goto normal;
10474    }
10475    else
10476        woperation = NULL;
10477
10478    Py_BEGIN_ALLOW_THREADS
10479    rc = ShellExecuteW((HWND)0, woperation, wpath,
10480                       NULL, NULL, SW_SHOWNORMAL);
10481    Py_END_ALLOW_THREADS
10482
10483    Py_XDECREF(uoperation);
10484    if (rc <= (HINSTANCE)32) {
10485        win32_error_object("startfile", unipath);
10486        return NULL;
10487    }
10488    Py_INCREF(Py_None);
10489    return Py_None;
10490
10491normal:
10492    if (!PyArg_ParseTuple(args, "O&|s:startfile",
10493                          PyUnicode_FSConverter, &ofilepath,
10494                          &operation))
10495        return NULL;
10496    if (win32_warn_bytes_api()) {
10497        Py_DECREF(ofilepath);
10498        return NULL;
10499    }
10500    filepath = PyBytes_AsString(ofilepath);
10501    Py_BEGIN_ALLOW_THREADS
10502    rc = ShellExecute((HWND)0, operation, filepath,
10503                      NULL, NULL, SW_SHOWNORMAL);
10504    Py_END_ALLOW_THREADS
10505    if (rc <= (HINSTANCE)32) {
10506        PyObject *errval = win32_error("startfile", filepath);
10507        Py_DECREF(ofilepath);
10508        return errval;
10509    }
10510    Py_DECREF(ofilepath);
10511    Py_INCREF(Py_None);
10512    return Py_None;
10513}
10514#endif
10515
10516#ifdef HAVE_GETLOADAVG
10517PyDoc_STRVAR(posix_getloadavg__doc__,
10518"getloadavg() -> (float, float, float)\n\n\
10519Return the number of processes in the system run queue averaged over\n\
10520the last 1, 5, and 15 minutes or raises OSError if the load average\n\
10521was unobtainable");
10522
10523static PyObject *
10524posix_getloadavg(PyObject *self, PyObject *noargs)
10525{
10526    double loadavg[3];
10527    if (getloadavg(loadavg, 3)!=3) {
10528        PyErr_SetString(PyExc_OSError, "Load averages are unobtainable");
10529        return NULL;
10530    } else
10531        return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]);
10532}
10533#endif
10534
10535PyDoc_STRVAR(device_encoding__doc__,
10536"device_encoding(fd) -> str\n\n\
10537Return a string describing the encoding of the device\n\
10538if the output is a terminal; else return None.");
10539
10540static PyObject *
10541device_encoding(PyObject *self, PyObject *args)
10542{
10543    int fd;
10544
10545    if (!PyArg_ParseTuple(args, "i:device_encoding", &fd))
10546        return NULL;
10547
10548    return _Py_device_encoding(fd);
10549}
10550
10551#ifdef HAVE_SETRESUID
10552PyDoc_STRVAR(posix_setresuid__doc__,
10553"setresuid(ruid, euid, suid)\n\n\
10554Set the current process's real, effective, and saved user ids.");
10555
10556static PyObject*
10557posix_setresuid (PyObject *self, PyObject *args)
10558{
10559    /* We assume uid_t is no larger than a long. */
10560    uid_t ruid, euid, suid;
10561    if (!PyArg_ParseTuple(args, "O&O&O&:setresuid",
10562                          _Py_Uid_Converter, &ruid,
10563                          _Py_Uid_Converter, &euid,
10564                          _Py_Uid_Converter, &suid))
10565        return NULL;
10566    if (setresuid(ruid, euid, suid) < 0)
10567        return posix_error();
10568    Py_RETURN_NONE;
10569}
10570#endif
10571
10572#ifdef HAVE_SETRESGID
10573PyDoc_STRVAR(posix_setresgid__doc__,
10574"setresgid(rgid, egid, sgid)\n\n\
10575Set the current process's real, effective, and saved group ids.");
10576
10577static PyObject*
10578posix_setresgid (PyObject *self, PyObject *args)
10579{
10580    gid_t rgid, egid, sgid;
10581    if (!PyArg_ParseTuple(args, "O&O&O&:setresgid",
10582                          _Py_Gid_Converter, &rgid,
10583                          _Py_Gid_Converter, &egid,
10584                          _Py_Gid_Converter, &sgid))
10585        return NULL;
10586    if (setresgid(rgid, egid, sgid) < 0)
10587        return posix_error();
10588    Py_RETURN_NONE;
10589}
10590#endif
10591
10592#ifdef HAVE_GETRESUID
10593PyDoc_STRVAR(posix_getresuid__doc__,
10594"getresuid() -> (ruid, euid, suid)\n\n\
10595Get tuple of the current process's real, effective, and saved user ids.");
10596
10597static PyObject*
10598posix_getresuid (PyObject *self, PyObject *noargs)
10599{
10600    uid_t ruid, euid, suid;
10601    if (getresuid(&ruid, &euid, &suid) < 0)
10602        return posix_error();
10603    return Py_BuildValue("(NNN)", _PyLong_FromUid(ruid),
10604                                  _PyLong_FromUid(euid),
10605                                  _PyLong_FromUid(suid));
10606}
10607#endif
10608
10609#ifdef HAVE_GETRESGID
10610PyDoc_STRVAR(posix_getresgid__doc__,
10611"getresgid() -> (rgid, egid, sgid)\n\n\
10612Get tuple of the current process's real, effective, and saved group ids.");
10613
10614static PyObject*
10615posix_getresgid (PyObject *self, PyObject *noargs)
10616{
10617    uid_t rgid, egid, sgid;
10618    if (getresgid(&rgid, &egid, &sgid) < 0)
10619        return posix_error();
10620    return Py_BuildValue("(NNN)", _PyLong_FromGid(rgid),
10621                                  _PyLong_FromGid(egid),
10622                                  _PyLong_FromGid(sgid));
10623}
10624#endif
10625
10626#ifdef USE_XATTRS
10627
10628PyDoc_STRVAR(posix_getxattr__doc__,
10629"getxattr(path, attribute, *, follow_symlinks=True) -> value\n\n\
10630Return the value of extended attribute attribute on path.\n\
10631\n\
10632path may be either a string or an open file descriptor.\n\
10633If follow_symlinks is False, and the last element of the path is a symbolic\n\
10634  link, getxattr will examine the symbolic link itself instead of the file\n\
10635  the link points to.");
10636
10637static PyObject *
10638posix_getxattr(PyObject *self, PyObject *args, PyObject *kwargs)
10639{
10640    path_t path;
10641    path_t attribute;
10642    int follow_symlinks = 1;
10643    PyObject *buffer = NULL;
10644    int i;
10645    static char *keywords[] = {"path", "attribute", "follow_symlinks", NULL};
10646
10647    memset(&path, 0, sizeof(path));
10648    memset(&attribute, 0, sizeof(attribute));
10649    path.function_name = "getxattr";
10650    attribute.function_name = "getxattr";
10651    path.allow_fd = 1;
10652    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|$p:getxattr", keywords,
10653        path_converter, &path,
10654        path_converter, &attribute,
10655        &follow_symlinks))
10656        return NULL;
10657
10658    if (fd_and_follow_symlinks_invalid("getxattr", path.fd, follow_symlinks))
10659        goto exit;
10660
10661    for (i = 0; ; i++) {
10662        void *ptr;
10663        ssize_t result;
10664        static Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0};
10665        Py_ssize_t buffer_size = buffer_sizes[i];
10666        if (!buffer_size) {
10667            path_error(&path);
10668            goto exit;
10669        }
10670        buffer = PyBytes_FromStringAndSize(NULL, buffer_size);
10671        if (!buffer)
10672            goto exit;
10673        ptr = PyBytes_AS_STRING(buffer);
10674
10675        Py_BEGIN_ALLOW_THREADS;
10676        if (path.fd >= 0)
10677            result = fgetxattr(path.fd, attribute.narrow, ptr, buffer_size);
10678        else if (follow_symlinks)
10679            result = getxattr(path.narrow, attribute.narrow, ptr, buffer_size);
10680        else
10681            result = lgetxattr(path.narrow, attribute.narrow, ptr, buffer_size);
10682        Py_END_ALLOW_THREADS;
10683
10684        if (result < 0) {
10685            Py_DECREF(buffer);
10686            buffer = NULL;
10687            if (errno == ERANGE)
10688                continue;
10689            path_error(&path);
10690            goto exit;
10691        }
10692
10693        if (result != buffer_size) {
10694            /* Can only shrink. */
10695            _PyBytes_Resize(&buffer, result);
10696        }
10697        break;
10698    }
10699
10700exit:
10701    path_cleanup(&path);
10702    path_cleanup(&attribute);
10703    return buffer;
10704}
10705
10706PyDoc_STRVAR(posix_setxattr__doc__,
10707"setxattr(path, attribute, value, flags=0, *, follow_symlinks=True)\n\n\
10708Set extended attribute attribute on path to value.\n\
10709path may be either a string or an open file descriptor.\n\
10710If follow_symlinks is False, and the last element of the path is a symbolic\n\
10711  link, setxattr will modify the symbolic link itself instead of the file\n\
10712  the link points to.");
10713
10714static PyObject *
10715posix_setxattr(PyObject *self, PyObject *args, PyObject *kwargs)
10716{
10717    path_t path;
10718    path_t attribute;
10719    Py_buffer value;
10720    int flags = 0;
10721    int follow_symlinks = 1;
10722    int result;
10723    PyObject *return_value = NULL;
10724    static char *keywords[] = {"path", "attribute", "value",
10725                               "flags", "follow_symlinks", NULL};
10726
10727    memset(&path, 0, sizeof(path));
10728    path.function_name = "setxattr";
10729    path.allow_fd = 1;
10730    memset(&attribute, 0, sizeof(attribute));
10731    memset(&value, 0, sizeof(value));
10732    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&y*|i$p:setxattr",
10733        keywords,
10734        path_converter, &path,
10735        path_converter, &attribute,
10736        &value, &flags,
10737        &follow_symlinks))
10738        return NULL;
10739
10740    if (fd_and_follow_symlinks_invalid("setxattr", path.fd, follow_symlinks))
10741        goto exit;
10742
10743    Py_BEGIN_ALLOW_THREADS;
10744    if (path.fd > -1)
10745        result = fsetxattr(path.fd, attribute.narrow,
10746                           value.buf, value.len, flags);
10747    else if (follow_symlinks)
10748        result = setxattr(path.narrow, attribute.narrow,
10749                           value.buf, value.len, flags);
10750    else
10751        result = lsetxattr(path.narrow, attribute.narrow,
10752                           value.buf, value.len, flags);
10753    Py_END_ALLOW_THREADS;
10754
10755    if (result) {
10756        return_value = path_error(&path);
10757        goto exit;
10758    }
10759
10760    return_value = Py_None;
10761    Py_INCREF(return_value);
10762
10763exit:
10764    path_cleanup(&path);
10765    path_cleanup(&attribute);
10766    PyBuffer_Release(&value);
10767
10768    return return_value;
10769}
10770
10771PyDoc_STRVAR(posix_removexattr__doc__,
10772"removexattr(path, attribute, *, follow_symlinks=True)\n\n\
10773Remove extended attribute attribute on path.\n\
10774path may be either a string or an open file descriptor.\n\
10775If follow_symlinks is False, and the last element of the path is a symbolic\n\
10776  link, removexattr will modify the symbolic link itself instead of the file\n\
10777  the link points to.");
10778
10779static PyObject *
10780posix_removexattr(PyObject *self, PyObject *args, PyObject *kwargs)
10781{
10782    path_t path;
10783    path_t attribute;
10784    int follow_symlinks = 1;
10785    int result;
10786    PyObject *return_value = NULL;
10787    static char *keywords[] = {"path", "attribute", "follow_symlinks", NULL};
10788
10789    memset(&path, 0, sizeof(path));
10790    path.function_name = "removexattr";
10791    memset(&attribute, 0, sizeof(attribute));
10792    attribute.function_name = "removexattr";
10793    path.allow_fd = 1;
10794    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|$p:removexattr",
10795                                     keywords,
10796                                     path_converter, &path,
10797                                     path_converter, &attribute,
10798                                     &follow_symlinks))
10799        return NULL;
10800
10801    if (fd_and_follow_symlinks_invalid("removexattr", path.fd, follow_symlinks))
10802        goto exit;
10803
10804    Py_BEGIN_ALLOW_THREADS;
10805    if (path.fd > -1)
10806        result = fremovexattr(path.fd, attribute.narrow);
10807    else if (follow_symlinks)
10808        result = removexattr(path.narrow, attribute.narrow);
10809    else
10810        result = lremovexattr(path.narrow, attribute.narrow);
10811    Py_END_ALLOW_THREADS;
10812
10813    if (result) {
10814        return_value = path_error(&path);
10815        goto exit;
10816    }
10817
10818    return_value = Py_None;
10819    Py_INCREF(return_value);
10820
10821exit:
10822    path_cleanup(&path);
10823    path_cleanup(&attribute);
10824
10825    return return_value;
10826}
10827
10828PyDoc_STRVAR(posix_listxattr__doc__,
10829"listxattr(path='.', *, follow_symlinks=True)\n\n\
10830Return a list of extended attributes on path.\n\
10831\n\
10832path may be either None, a string, or an open file descriptor.\n\
10833if path is None, listxattr will examine the current directory.\n\
10834If follow_symlinks is False, and the last element of the path is a symbolic\n\
10835  link, listxattr will examine the symbolic link itself instead of the file\n\
10836  the link points to.");
10837
10838static PyObject *
10839posix_listxattr(PyObject *self, PyObject *args, PyObject *kwargs)
10840{
10841    path_t path;
10842    int follow_symlinks = 1;
10843    Py_ssize_t i;
10844    PyObject *result = NULL;
10845    char *buffer = NULL;
10846    char *name;
10847    static char *keywords[] = {"path", "follow_symlinks", NULL};
10848
10849    memset(&path, 0, sizeof(path));
10850    path.function_name = "listxattr";
10851    path.allow_fd = 1;
10852    path.fd = -1;
10853    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&$p:listxattr", keywords,
10854        path_converter, &path,
10855        &follow_symlinks))
10856        return NULL;
10857
10858    if (fd_and_follow_symlinks_invalid("listxattr", path.fd, follow_symlinks))
10859        goto exit;
10860
10861    name = path.narrow ? path.narrow : ".";
10862    for (i = 0; ; i++) {
10863        char *start, *trace, *end;
10864        ssize_t length;
10865        static Py_ssize_t buffer_sizes[] = { 256, XATTR_LIST_MAX, 0 };
10866        Py_ssize_t buffer_size = buffer_sizes[i];
10867        if (!buffer_size) {
10868            /* ERANGE */
10869            path_error(&path);
10870            break;
10871        }
10872        buffer = PyMem_MALLOC(buffer_size);
10873        if (!buffer) {
10874            PyErr_NoMemory();
10875            break;
10876        }
10877
10878        Py_BEGIN_ALLOW_THREADS;
10879        if (path.fd > -1)
10880            length = flistxattr(path.fd, buffer, buffer_size);
10881        else if (follow_symlinks)
10882            length = listxattr(name, buffer, buffer_size);
10883        else
10884            length = llistxattr(name, buffer, buffer_size);
10885        Py_END_ALLOW_THREADS;
10886
10887        if (length < 0) {
10888            if (errno == ERANGE) {
10889                PyMem_FREE(buffer);
10890                buffer = NULL;
10891                continue;
10892            }
10893            path_error(&path);
10894            break;
10895        }
10896
10897        result = PyList_New(0);
10898        if (!result) {
10899            goto exit;
10900        }
10901
10902        end = buffer + length;
10903        for (trace = start = buffer; trace != end; trace++) {
10904            if (!*trace) {
10905                int error;
10906                PyObject *attribute = PyUnicode_DecodeFSDefaultAndSize(start,
10907                                                                 trace - start);
10908                if (!attribute) {
10909                    Py_DECREF(result);
10910                    result = NULL;
10911                    goto exit;
10912                }
10913                error = PyList_Append(result, attribute);
10914                Py_DECREF(attribute);
10915                if (error) {
10916                    Py_DECREF(result);
10917                    result = NULL;
10918                    goto exit;
10919                }
10920                start = trace + 1;
10921            }
10922        }
10923    break;
10924    }
10925exit:
10926    path_cleanup(&path);
10927    if (buffer)
10928        PyMem_FREE(buffer);
10929    return result;
10930}
10931
10932#endif /* USE_XATTRS */
10933
10934
10935PyDoc_STRVAR(posix_urandom__doc__,
10936"urandom(n) -> str\n\n\
10937Return n random bytes suitable for cryptographic use.");
10938
10939static PyObject *
10940posix_urandom(PyObject *self, PyObject *args)
10941{
10942    Py_ssize_t size;
10943    PyObject *result;
10944    int ret;
10945
10946     /* Read arguments */
10947    if (!PyArg_ParseTuple(args, "n:urandom", &size))
10948        return NULL;
10949    if (size < 0)
10950        return PyErr_Format(PyExc_ValueError,
10951                            "negative argument not allowed");
10952    result = PyBytes_FromStringAndSize(NULL, size);
10953    if (result == NULL)
10954        return NULL;
10955
10956    ret = _PyOS_URandom(PyBytes_AS_STRING(result),
10957                        PyBytes_GET_SIZE(result));
10958    if (ret == -1) {
10959        Py_DECREF(result);
10960        return NULL;
10961    }
10962    return result;
10963}
10964
10965/* Terminal size querying */
10966
10967static PyTypeObject TerminalSizeType;
10968
10969PyDoc_STRVAR(TerminalSize_docstring,
10970    "A tuple of (columns, lines) for holding terminal window size");
10971
10972static PyStructSequence_Field TerminalSize_fields[] = {
10973    {"columns", "width of the terminal window in characters"},
10974    {"lines", "height of the terminal window in characters"},
10975    {NULL, NULL}
10976};
10977
10978static PyStructSequence_Desc TerminalSize_desc = {
10979    "os.terminal_size",
10980    TerminalSize_docstring,
10981    TerminalSize_fields,
10982    2,
10983};
10984
10985#if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL)
10986PyDoc_STRVAR(termsize__doc__,
10987    "Return the size of the terminal window as (columns, lines).\n"        \
10988    "\n"                                                                   \
10989    "The optional argument fd (default standard output) specifies\n"       \
10990    "which file descriptor should be queried.\n"                           \
10991    "\n"                                                                   \
10992    "If the file descriptor is not connected to a terminal, an OSError\n"  \
10993    "is thrown.\n"                                                         \
10994    "\n"                                                                   \
10995    "This function will only be defined if an implementation is\n"         \
10996    "available for this system.\n"                                         \
10997    "\n"                                                                   \
10998    "shutil.get_terminal_size is the high-level function which should \n"  \
10999    "normally be used, os.get_terminal_size is the low-level implementation.");
11000
11001static PyObject*
11002get_terminal_size(PyObject *self, PyObject *args)
11003{
11004    int columns, lines;
11005    PyObject *termsize;
11006
11007    int fd = fileno(stdout);
11008    /* Under some conditions stdout may not be connected and
11009     * fileno(stdout) may point to an invalid file descriptor. For example
11010     * GUI apps don't have valid standard streams by default.
11011     *
11012     * If this happens, and the optional fd argument is not present,
11013     * the ioctl below will fail returning EBADF. This is what we want.
11014     */
11015
11016    if (!PyArg_ParseTuple(args, "|i", &fd))
11017        return NULL;
11018
11019#ifdef TERMSIZE_USE_IOCTL
11020    {
11021        struct winsize w;
11022        if (ioctl(fd, TIOCGWINSZ, &w))
11023            return PyErr_SetFromErrno(PyExc_OSError);
11024        columns = w.ws_col;
11025        lines = w.ws_row;
11026    }
11027#endif /* TERMSIZE_USE_IOCTL */
11028
11029#ifdef TERMSIZE_USE_CONIO
11030    {
11031        DWORD nhandle;
11032        HANDLE handle;
11033        CONSOLE_SCREEN_BUFFER_INFO csbi;
11034        switch (fd) {
11035        case 0: nhandle = STD_INPUT_HANDLE;
11036            break;
11037        case 1: nhandle = STD_OUTPUT_HANDLE;
11038            break;
11039        case 2: nhandle = STD_ERROR_HANDLE;
11040            break;
11041        default:
11042            return PyErr_Format(PyExc_ValueError, "bad file descriptor");
11043        }
11044        handle = GetStdHandle(nhandle);
11045        if (handle == NULL)
11046            return PyErr_Format(PyExc_OSError, "handle cannot be retrieved");
11047        if (handle == INVALID_HANDLE_VALUE)
11048            return PyErr_SetFromWindowsErr(0);
11049
11050        if (!GetConsoleScreenBufferInfo(handle, &csbi))
11051            return PyErr_SetFromWindowsErr(0);
11052
11053        columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
11054        lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
11055    }
11056#endif /* TERMSIZE_USE_CONIO */
11057
11058    termsize = PyStructSequence_New(&TerminalSizeType);
11059    if (termsize == NULL)
11060        return NULL;
11061    PyStructSequence_SET_ITEM(termsize, 0, PyLong_FromLong(columns));
11062    PyStructSequence_SET_ITEM(termsize, 1, PyLong_FromLong(lines));
11063    if (PyErr_Occurred()) {
11064        Py_DECREF(termsize);
11065        return NULL;
11066    }
11067    return termsize;
11068}
11069#endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */
11070
11071PyDoc_STRVAR(posix_cpu_count__doc__,
11072"cpu_count() -> integer\n\n\
11073Return the number of CPUs in the system, or None if this value cannot be\n\
11074established.");
11075
11076static PyObject *
11077posix_cpu_count(PyObject *self)
11078{
11079    int ncpu = 0;
11080#ifdef MS_WINDOWS
11081    SYSTEM_INFO sysinfo;
11082    GetSystemInfo(&sysinfo);
11083    ncpu = sysinfo.dwNumberOfProcessors;
11084#elif defined(__hpux)
11085    ncpu = mpctl(MPC_GETNUMSPUS, NULL, NULL);
11086#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
11087    ncpu = sysconf(_SC_NPROCESSORS_ONLN);
11088#elif defined(__DragonFly__) || \
11089      defined(__OpenBSD__)   || \
11090      defined(__FreeBSD__)   || \
11091      defined(__NetBSD__)    || \
11092      defined(__APPLE__)
11093    int mib[2];
11094    size_t len = sizeof(ncpu);
11095    mib[0] = CTL_HW;
11096    mib[1] = HW_NCPU;
11097    if (sysctl(mib, 2, &ncpu, &len, NULL, 0) != 0)
11098        ncpu = 0;
11099#endif
11100    if (ncpu >= 1)
11101        return PyLong_FromLong(ncpu);
11102    else
11103        Py_RETURN_NONE;
11104}
11105
11106PyDoc_STRVAR(get_inheritable__doc__,
11107    "get_inheritable(fd) -> bool\n" \
11108    "\n" \
11109    "Get the close-on-exe flag of the specified file descriptor.");
11110
11111static PyObject*
11112posix_get_inheritable(PyObject *self, PyObject *args)
11113{
11114    int fd;
11115    int inheritable;
11116
11117    if (!PyArg_ParseTuple(args, "i:get_inheritable", &fd))
11118        return NULL;
11119
11120    if (!_PyVerify_fd(fd))
11121        return posix_error();
11122
11123    inheritable = _Py_get_inheritable(fd);
11124    if (inheritable < 0)
11125        return NULL;
11126    return PyBool_FromLong(inheritable);
11127}
11128
11129PyDoc_STRVAR(set_inheritable__doc__,
11130    "set_inheritable(fd, inheritable)\n" \
11131    "\n" \
11132    "Set the inheritable flag of the specified file descriptor.");
11133
11134static PyObject*
11135posix_set_inheritable(PyObject *self, PyObject *args)
11136{
11137    int fd, inheritable;
11138
11139    if (!PyArg_ParseTuple(args, "ii:set_inheritable", &fd, &inheritable))
11140        return NULL;
11141
11142    if (!_PyVerify_fd(fd))
11143        return posix_error();
11144
11145    if (_Py_set_inheritable(fd, inheritable, NULL) < 0)
11146        return NULL;
11147    Py_RETURN_NONE;
11148}
11149
11150
11151#ifdef MS_WINDOWS
11152PyDoc_STRVAR(get_handle_inheritable__doc__,
11153    "get_handle_inheritable(fd) -> bool\n" \
11154    "\n" \
11155    "Get the close-on-exe flag of the specified file descriptor.");
11156
11157static PyObject*
11158posix_get_handle_inheritable(PyObject *self, PyObject *args)
11159{
11160    Py_intptr_t handle;
11161    DWORD flags;
11162
11163    if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR ":get_handle_inheritable", &handle))
11164        return NULL;
11165
11166    if (!GetHandleInformation((HANDLE)handle, &flags)) {
11167        PyErr_SetFromWindowsErr(0);
11168        return NULL;
11169    }
11170
11171    return PyBool_FromLong(flags & HANDLE_FLAG_INHERIT);
11172}
11173
11174PyDoc_STRVAR(set_handle_inheritable__doc__,
11175    "set_handle_inheritable(fd, inheritable)\n" \
11176    "\n" \
11177    "Set the inheritable flag of the specified handle.");
11178
11179static PyObject*
11180posix_set_handle_inheritable(PyObject *self, PyObject *args)
11181{
11182    int inheritable = 1;
11183    Py_intptr_t handle;
11184    DWORD flags;
11185
11186    if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:set_handle_inheritable",
11187                          &handle, &inheritable))
11188        return NULL;
11189
11190    if (inheritable)
11191        flags = HANDLE_FLAG_INHERIT;
11192    else
11193        flags = 0;
11194    if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) {
11195        PyErr_SetFromWindowsErr(0);
11196        return NULL;
11197    }
11198    Py_RETURN_NONE;
11199}
11200#endif   /* MS_WINDOWS */
11201
11202
11203/*[clinic input]
11204dump buffer
11205[clinic start generated code]*/
11206
11207#ifndef OS_TTYNAME_METHODDEF
11208    #define OS_TTYNAME_METHODDEF
11209#endif /* !defined(OS_TTYNAME_METHODDEF) */
11210/*[clinic end generated code: output=5d071bbc8f49ea12 input=524ce2e021e4eba6]*/
11211
11212
11213static PyMethodDef posix_methods[] = {
11214
11215    OS_STAT_METHODDEF
11216    OS_ACCESS_METHODDEF
11217    OS_TTYNAME_METHODDEF
11218
11219    {"chdir",           (PyCFunction)posix_chdir,
11220                        METH_VARARGS | METH_KEYWORDS,
11221                        posix_chdir__doc__},
11222#ifdef HAVE_CHFLAGS
11223    {"chflags",         (PyCFunction)posix_chflags,
11224                        METH_VARARGS | METH_KEYWORDS,
11225                        posix_chflags__doc__},
11226#endif /* HAVE_CHFLAGS */
11227    {"chmod",           (PyCFunction)posix_chmod,
11228                        METH_VARARGS | METH_KEYWORDS,
11229                        posix_chmod__doc__},
11230#ifdef HAVE_FCHMOD
11231    {"fchmod",          posix_fchmod, METH_VARARGS, posix_fchmod__doc__},
11232#endif /* HAVE_FCHMOD */
11233#ifdef HAVE_CHOWN
11234    {"chown",           (PyCFunction)posix_chown,
11235                        METH_VARARGS | METH_KEYWORDS,
11236                        posix_chown__doc__},
11237#endif /* HAVE_CHOWN */
11238#ifdef HAVE_LCHMOD
11239    {"lchmod",          posix_lchmod, METH_VARARGS, posix_lchmod__doc__},
11240#endif /* HAVE_LCHMOD */
11241#ifdef HAVE_FCHOWN
11242    {"fchown",          posix_fchown, METH_VARARGS, posix_fchown__doc__},
11243#endif /* HAVE_FCHOWN */
11244#ifdef HAVE_LCHFLAGS
11245    {"lchflags",        posix_lchflags, METH_VARARGS, posix_lchflags__doc__},
11246#endif /* HAVE_LCHFLAGS */
11247#ifdef HAVE_LCHOWN
11248    {"lchown",          posix_lchown, METH_VARARGS, posix_lchown__doc__},
11249#endif /* HAVE_LCHOWN */
11250#ifdef HAVE_CHROOT
11251    {"chroot",          posix_chroot, METH_VARARGS, posix_chroot__doc__},
11252#endif
11253#ifdef HAVE_CTERMID
11254    {"ctermid",         posix_ctermid, METH_NOARGS, posix_ctermid__doc__},
11255#endif
11256    {"getcwd",          (PyCFunction)posix_getcwd_unicode,
11257    METH_NOARGS, posix_getcwd__doc__},
11258    {"getcwdb",         (PyCFunction)posix_getcwd_bytes,
11259    METH_NOARGS, posix_getcwdb__doc__},
11260#if defined(HAVE_LINK) || defined(MS_WINDOWS)
11261    {"link",            (PyCFunction)posix_link,
11262                        METH_VARARGS | METH_KEYWORDS,
11263                        posix_link__doc__},
11264#endif /* HAVE_LINK */
11265    {"listdir",         (PyCFunction)posix_listdir,
11266                        METH_VARARGS | METH_KEYWORDS,
11267                        posix_listdir__doc__},
11268    {"lstat",           (PyCFunction)posix_lstat,
11269                        METH_VARARGS | METH_KEYWORDS,
11270                        posix_lstat__doc__},
11271    {"mkdir",           (PyCFunction)posix_mkdir,
11272                        METH_VARARGS | METH_KEYWORDS,
11273                        posix_mkdir__doc__},
11274#ifdef HAVE_NICE
11275    {"nice",            posix_nice, METH_VARARGS, posix_nice__doc__},
11276#endif /* HAVE_NICE */
11277#ifdef HAVE_GETPRIORITY
11278    {"getpriority",     posix_getpriority, METH_VARARGS, posix_getpriority__doc__},
11279#endif /* HAVE_GETPRIORITY */
11280#ifdef HAVE_SETPRIORITY
11281    {"setpriority",     posix_setpriority, METH_VARARGS, posix_setpriority__doc__},
11282#endif /* HAVE_SETPRIORITY */
11283#ifdef HAVE_READLINK
11284    {"readlink",        (PyCFunction)posix_readlink,
11285                        METH_VARARGS | METH_KEYWORDS,
11286                        readlink__doc__},
11287#endif /* HAVE_READLINK */
11288#if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
11289    {"readlink",        (PyCFunction)win_readlink,
11290                        METH_VARARGS | METH_KEYWORDS,
11291                        readlink__doc__},
11292#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
11293    {"rename",          (PyCFunction)posix_rename,
11294                        METH_VARARGS | METH_KEYWORDS,
11295                        posix_rename__doc__},
11296    {"replace",         (PyCFunction)posix_replace,
11297                        METH_VARARGS | METH_KEYWORDS,
11298                        posix_replace__doc__},
11299    {"rmdir",           (PyCFunction)posix_rmdir,
11300                        METH_VARARGS | METH_KEYWORDS,
11301                        posix_rmdir__doc__},
11302    {"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},
11303#if defined(HAVE_SYMLINK)
11304    {"symlink",         (PyCFunction)posix_symlink,
11305                        METH_VARARGS | METH_KEYWORDS,
11306                        posix_symlink__doc__},
11307#endif /* HAVE_SYMLINK */
11308#ifdef HAVE_SYSTEM
11309    {"system",          posix_system, METH_VARARGS, posix_system__doc__},
11310#endif
11311    {"umask",           posix_umask, METH_VARARGS, posix_umask__doc__},
11312#ifdef HAVE_UNAME
11313    {"uname",           posix_uname, METH_NOARGS, posix_uname__doc__},
11314#endif /* HAVE_UNAME */
11315    {"unlink",          (PyCFunction)posix_unlink,
11316                        METH_VARARGS | METH_KEYWORDS,
11317                        posix_unlink__doc__},
11318    {"remove",          (PyCFunction)posix_unlink,
11319                        METH_VARARGS | METH_KEYWORDS,
11320                        posix_remove__doc__},
11321    {"utime",           (PyCFunction)posix_utime,
11322                        METH_VARARGS | METH_KEYWORDS, posix_utime__doc__},
11323#ifdef HAVE_TIMES
11324    {"times",           posix_times, METH_NOARGS, posix_times__doc__},
11325#endif /* HAVE_TIMES */
11326    {"_exit",           posix__exit, METH_VARARGS, posix__exit__doc__},
11327#ifdef HAVE_EXECV
11328    {"execv",           posix_execv, METH_VARARGS, posix_execv__doc__},
11329    {"execve",          (PyCFunction)posix_execve,
11330                        METH_VARARGS | METH_KEYWORDS,
11331                        posix_execve__doc__},
11332#endif /* HAVE_EXECV */
11333#ifdef HAVE_SPAWNV
11334    {"spawnv",          posix_spawnv, METH_VARARGS, posix_spawnv__doc__},
11335    {"spawnve",         posix_spawnve, METH_VARARGS, posix_spawnve__doc__},
11336#endif /* HAVE_SPAWNV */
11337#ifdef HAVE_FORK1
11338    {"fork1",       posix_fork1, METH_NOARGS, posix_fork1__doc__},
11339#endif /* HAVE_FORK1 */
11340#ifdef HAVE_FORK
11341    {"fork",            posix_fork, METH_NOARGS, posix_fork__doc__},
11342#endif /* HAVE_FORK */
11343#ifdef HAVE_SCHED_H
11344#ifdef HAVE_SCHED_GET_PRIORITY_MAX
11345    {"sched_get_priority_max", posix_sched_get_priority_max, METH_VARARGS, posix_sched_get_priority_max__doc__},
11346    {"sched_get_priority_min", posix_sched_get_priority_min, METH_VARARGS, posix_sched_get_priority_min__doc__},
11347#endif
11348#ifdef HAVE_SCHED_SETPARAM
11349    {"sched_getparam", posix_sched_getparam, METH_VARARGS, posix_sched_getparam__doc__},
11350#endif
11351#ifdef HAVE_SCHED_SETSCHEDULER
11352    {"sched_getscheduler", posix_sched_getscheduler, METH_VARARGS, posix_sched_getscheduler__doc__},
11353#endif
11354#ifdef HAVE_SCHED_RR_GET_INTERVAL
11355    {"sched_rr_get_interval", posix_sched_rr_get_interval, METH_VARARGS, posix_sched_rr_get_interval__doc__},
11356#endif
11357#ifdef HAVE_SCHED_SETPARAM
11358    {"sched_setparam", posix_sched_setparam, METH_VARARGS, posix_sched_setparam__doc__},
11359#endif
11360#ifdef HAVE_SCHED_SETSCHEDULER
11361    {"sched_setscheduler", posix_sched_setscheduler, METH_VARARGS, posix_sched_setscheduler__doc__},
11362#endif
11363    {"sched_yield",     posix_sched_yield, METH_NOARGS, posix_sched_yield__doc__},
11364#ifdef HAVE_SCHED_SETAFFINITY
11365    {"sched_setaffinity", posix_sched_setaffinity, METH_VARARGS, posix_sched_setaffinity__doc__},
11366    {"sched_getaffinity", posix_sched_getaffinity, METH_VARARGS, posix_sched_getaffinity__doc__},
11367#endif
11368#endif /* HAVE_SCHED_H */
11369#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)
11370    {"openpty",         posix_openpty, METH_NOARGS, posix_openpty__doc__},
11371#endif /* HAVE_OPENPTY || HAVE__GETPTY || HAVE_DEV_PTMX */
11372#ifdef HAVE_FORKPTY
11373    {"forkpty",         posix_forkpty, METH_NOARGS, posix_forkpty__doc__},
11374#endif /* HAVE_FORKPTY */
11375#ifdef HAVE_GETEGID
11376    {"getegid",         posix_getegid, METH_NOARGS, posix_getegid__doc__},
11377#endif /* HAVE_GETEGID */
11378#ifdef HAVE_GETEUID
11379    {"geteuid",         posix_geteuid, METH_NOARGS, posix_geteuid__doc__},
11380#endif /* HAVE_GETEUID */
11381#ifdef HAVE_GETGID
11382    {"getgid",          posix_getgid, METH_NOARGS, posix_getgid__doc__},
11383#endif /* HAVE_GETGID */
11384#ifdef HAVE_GETGROUPLIST
11385    {"getgrouplist",    posix_getgrouplist, METH_VARARGS, posix_getgrouplist__doc__},
11386#endif
11387#ifdef HAVE_GETGROUPS
11388    {"getgroups",       posix_getgroups, METH_NOARGS, posix_getgroups__doc__},
11389#endif
11390    {"getpid",          posix_getpid, METH_NOARGS, posix_getpid__doc__},
11391#ifdef HAVE_GETPGRP
11392    {"getpgrp",         posix_getpgrp, METH_NOARGS, posix_getpgrp__doc__},
11393#endif /* HAVE_GETPGRP */
11394#ifdef HAVE_GETPPID
11395    {"getppid",         posix_getppid, METH_NOARGS, posix_getppid__doc__},
11396#endif /* HAVE_GETPPID */
11397#ifdef HAVE_GETUID
11398    {"getuid",          posix_getuid, METH_NOARGS, posix_getuid__doc__},
11399#endif /* HAVE_GETUID */
11400#ifdef HAVE_GETLOGIN
11401    {"getlogin",        posix_getlogin, METH_NOARGS, posix_getlogin__doc__},
11402#endif
11403#ifdef HAVE_KILL
11404    {"kill",            posix_kill, METH_VARARGS, posix_kill__doc__},
11405#endif /* HAVE_KILL */
11406#ifdef HAVE_KILLPG
11407    {"killpg",          posix_killpg, METH_VARARGS, posix_killpg__doc__},
11408#endif /* HAVE_KILLPG */
11409#ifdef HAVE_PLOCK
11410    {"plock",           posix_plock, METH_VARARGS, posix_plock__doc__},
11411#endif /* HAVE_PLOCK */
11412#ifdef MS_WINDOWS
11413    {"startfile",       win32_startfile, METH_VARARGS, win32_startfile__doc__},
11414    {"kill",    win32_kill, METH_VARARGS, win32_kill__doc__},
11415#endif
11416#ifdef HAVE_SETUID
11417    {"setuid",          posix_setuid, METH_VARARGS, posix_setuid__doc__},
11418#endif /* HAVE_SETUID */
11419#ifdef HAVE_SETEUID
11420    {"seteuid",         posix_seteuid, METH_VARARGS, posix_seteuid__doc__},
11421#endif /* HAVE_SETEUID */
11422#ifdef HAVE_SETEGID
11423    {"setegid",         posix_setegid, METH_VARARGS, posix_setegid__doc__},
11424#endif /* HAVE_SETEGID */
11425#ifdef HAVE_SETREUID
11426    {"setreuid",        posix_setreuid, METH_VARARGS, posix_setreuid__doc__},
11427#endif /* HAVE_SETREUID */
11428#ifdef HAVE_SETREGID
11429    {"setregid",        posix_setregid, METH_VARARGS, posix_setregid__doc__},
11430#endif /* HAVE_SETREGID */
11431#ifdef HAVE_SETGID
11432    {"setgid",          posix_setgid, METH_VARARGS, posix_setgid__doc__},
11433#endif /* HAVE_SETGID */
11434#ifdef HAVE_SETGROUPS
11435    {"setgroups",       posix_setgroups, METH_O, posix_setgroups__doc__},
11436#endif /* HAVE_SETGROUPS */
11437#ifdef HAVE_INITGROUPS
11438    {"initgroups",      posix_initgroups, METH_VARARGS, posix_initgroups__doc__},
11439#endif /* HAVE_INITGROUPS */
11440#ifdef HAVE_GETPGID
11441    {"getpgid",         posix_getpgid, METH_VARARGS, posix_getpgid__doc__},
11442#endif /* HAVE_GETPGID */
11443#ifdef HAVE_SETPGRP
11444    {"setpgrp",         posix_setpgrp, METH_NOARGS, posix_setpgrp__doc__},
11445#endif /* HAVE_SETPGRP */
11446#ifdef HAVE_WAIT
11447    {"wait",            posix_wait, METH_NOARGS, posix_wait__doc__},
11448#endif /* HAVE_WAIT */
11449#ifdef HAVE_WAIT3
11450    {"wait3",           posix_wait3, METH_VARARGS, posix_wait3__doc__},
11451#endif /* HAVE_WAIT3 */
11452#ifdef HAVE_WAIT4
11453    {"wait4",           posix_wait4, METH_VARARGS, posix_wait4__doc__},
11454#endif /* HAVE_WAIT4 */
11455#if defined(HAVE_WAITID) && !defined(__APPLE__)
11456    {"waitid",          posix_waitid, METH_VARARGS, posix_waitid__doc__},
11457#endif
11458#if defined(HAVE_WAITPID) || defined(HAVE_CWAIT)
11459    {"waitpid",         posix_waitpid, METH_VARARGS, posix_waitpid__doc__},
11460#endif /* HAVE_WAITPID */
11461#ifdef HAVE_GETSID
11462    {"getsid",          posix_getsid, METH_VARARGS, posix_getsid__doc__},
11463#endif /* HAVE_GETSID */
11464#ifdef HAVE_SETSID
11465    {"setsid",          posix_setsid, METH_NOARGS, posix_setsid__doc__},
11466#endif /* HAVE_SETSID */
11467#ifdef HAVE_SETPGID
11468    {"setpgid",         posix_setpgid, METH_VARARGS, posix_setpgid__doc__},
11469#endif /* HAVE_SETPGID */
11470#ifdef HAVE_TCGETPGRP
11471    {"tcgetpgrp",       posix_tcgetpgrp, METH_VARARGS, posix_tcgetpgrp__doc__},
11472#endif /* HAVE_TCGETPGRP */
11473#ifdef HAVE_TCSETPGRP
11474    {"tcsetpgrp",       posix_tcsetpgrp, METH_VARARGS, posix_tcsetpgrp__doc__},
11475#endif /* HAVE_TCSETPGRP */
11476    {"open",            (PyCFunction)posix_open,\
11477                        METH_VARARGS | METH_KEYWORDS,
11478                        posix_open__doc__},
11479    {"close",           posix_close_, METH_VARARGS, posix_close__doc__},
11480    {"closerange",      posix_closerange, METH_VARARGS, posix_closerange__doc__},
11481    {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__},
11482    {"dup",             posix_dup, METH_VARARGS, posix_dup__doc__},
11483    {"dup2",            (PyCFunction)posix_dup2,
11484                        METH_VARARGS | METH_KEYWORDS, posix_dup2__doc__},
11485#ifdef HAVE_LOCKF
11486    {"lockf",           posix_lockf, METH_VARARGS, posix_lockf__doc__},
11487#endif
11488    {"lseek",           posix_lseek, METH_VARARGS, posix_lseek__doc__},
11489    {"read",            posix_read, METH_VARARGS, posix_read__doc__},
11490#ifdef HAVE_READV
11491    {"readv",           posix_readv, METH_VARARGS, posix_readv__doc__},
11492#endif
11493#ifdef HAVE_PREAD
11494    {"pread",           posix_pread, METH_VARARGS, posix_pread__doc__},
11495#endif
11496    {"write",           posix_write, METH_VARARGS, posix_write__doc__},
11497#ifdef HAVE_WRITEV
11498    {"writev",          posix_writev, METH_VARARGS, posix_writev__doc__},
11499#endif
11500#ifdef HAVE_PWRITE
11501    {"pwrite",          posix_pwrite, METH_VARARGS, posix_pwrite__doc__},
11502#endif
11503#ifdef HAVE_SENDFILE
11504    {"sendfile",        (PyCFunction)posix_sendfile, METH_VARARGS | METH_KEYWORDS,
11505                            posix_sendfile__doc__},
11506#endif
11507    {"fstat",           posix_fstat, METH_VARARGS, posix_fstat__doc__},
11508    {"isatty",          posix_isatty, METH_VARARGS, posix_isatty__doc__},
11509#ifdef HAVE_PIPE
11510    {"pipe",            posix_pipe, METH_NOARGS, posix_pipe__doc__},
11511#endif
11512#ifdef HAVE_PIPE2
11513    {"pipe2",           posix_pipe2, METH_O, posix_pipe2__doc__},
11514#endif
11515#ifdef HAVE_MKFIFO
11516    {"mkfifo",          (PyCFunction)posix_mkfifo,
11517                        METH_VARARGS | METH_KEYWORDS,
11518                        posix_mkfifo__doc__},
11519#endif
11520#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
11521    {"mknod",           (PyCFunction)posix_mknod,
11522                        METH_VARARGS | METH_KEYWORDS,
11523                        posix_mknod__doc__},
11524#endif
11525#ifdef HAVE_DEVICE_MACROS
11526    {"major",           posix_major, METH_VARARGS, posix_major__doc__},
11527    {"minor",           posix_minor, METH_VARARGS, posix_minor__doc__},
11528    {"makedev",         posix_makedev, METH_VARARGS, posix_makedev__doc__},
11529#endif
11530#ifdef HAVE_FTRUNCATE
11531    {"ftruncate",       posix_ftruncate, METH_VARARGS, posix_ftruncate__doc__},
11532#endif
11533#ifdef HAVE_TRUNCATE
11534    {"truncate",        (PyCFunction)posix_truncate,
11535                        METH_VARARGS | METH_KEYWORDS,
11536                        posix_truncate__doc__},
11537#endif
11538#if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG)
11539    {"posix_fallocate", posix_posix_fallocate, METH_VARARGS, posix_posix_fallocate__doc__},
11540#endif
11541#if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG)
11542    {"posix_fadvise",   posix_posix_fadvise, METH_VARARGS, posix_posix_fadvise__doc__},
11543#endif
11544#ifdef HAVE_PUTENV
11545    {"putenv",          posix_putenv, METH_VARARGS, posix_putenv__doc__},
11546#endif
11547#ifdef HAVE_UNSETENV
11548    {"unsetenv",        posix_unsetenv, METH_VARARGS, posix_unsetenv__doc__},
11549#endif
11550    {"strerror",        posix_strerror, METH_VARARGS, posix_strerror__doc__},
11551#ifdef HAVE_FCHDIR
11552    {"fchdir",          posix_fchdir, METH_O, posix_fchdir__doc__},
11553#endif
11554#ifdef HAVE_FSYNC
11555    {"fsync",       posix_fsync, METH_O, posix_fsync__doc__},
11556#endif
11557#ifdef HAVE_SYNC
11558    {"sync",        posix_sync, METH_NOARGS, posix_sync__doc__},
11559#endif
11560#ifdef HAVE_FDATASYNC
11561    {"fdatasync",   posix_fdatasync,  METH_O, posix_fdatasync__doc__},
11562#endif
11563#ifdef HAVE_SYS_WAIT_H
11564#ifdef WCOREDUMP
11565    {"WCOREDUMP",       posix_WCOREDUMP, METH_VARARGS, posix_WCOREDUMP__doc__},
11566#endif /* WCOREDUMP */
11567#ifdef WIFCONTINUED
11568    {"WIFCONTINUED",posix_WIFCONTINUED, METH_VARARGS, posix_WIFCONTINUED__doc__},
11569#endif /* WIFCONTINUED */
11570#ifdef WIFSTOPPED
11571    {"WIFSTOPPED",      posix_WIFSTOPPED, METH_VARARGS, posix_WIFSTOPPED__doc__},
11572#endif /* WIFSTOPPED */
11573#ifdef WIFSIGNALED
11574    {"WIFSIGNALED",     posix_WIFSIGNALED, METH_VARARGS, posix_WIFSIGNALED__doc__},
11575#endif /* WIFSIGNALED */
11576#ifdef WIFEXITED
11577    {"WIFEXITED",       posix_WIFEXITED, METH_VARARGS, posix_WIFEXITED__doc__},
11578#endif /* WIFEXITED */
11579#ifdef WEXITSTATUS
11580    {"WEXITSTATUS",     posix_WEXITSTATUS, METH_VARARGS, posix_WEXITSTATUS__doc__},
11581#endif /* WEXITSTATUS */
11582#ifdef WTERMSIG
11583    {"WTERMSIG",        posix_WTERMSIG, METH_VARARGS, posix_WTERMSIG__doc__},
11584#endif /* WTERMSIG */
11585#ifdef WSTOPSIG
11586    {"WSTOPSIG",        posix_WSTOPSIG, METH_VARARGS, posix_WSTOPSIG__doc__},
11587#endif /* WSTOPSIG */
11588#endif /* HAVE_SYS_WAIT_H */
11589#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H)
11590    {"fstatvfs",        posix_fstatvfs, METH_VARARGS, posix_fstatvfs__doc__},
11591#endif
11592#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
11593    {"statvfs",         (PyCFunction)posix_statvfs,
11594                        METH_VARARGS | METH_KEYWORDS,
11595                        posix_statvfs__doc__},
11596#endif
11597#ifdef HAVE_CONFSTR
11598    {"confstr",         posix_confstr, METH_VARARGS, posix_confstr__doc__},
11599#endif
11600#ifdef HAVE_SYSCONF
11601    {"sysconf",         posix_sysconf, METH_VARARGS, posix_sysconf__doc__},
11602#endif
11603#ifdef HAVE_FPATHCONF
11604    {"fpathconf",       posix_fpathconf, METH_VARARGS, posix_fpathconf__doc__},
11605#endif
11606#ifdef HAVE_PATHCONF
11607    {"pathconf",        (PyCFunction)posix_pathconf,
11608                        METH_VARARGS | METH_KEYWORDS,
11609                        posix_pathconf__doc__},
11610#endif
11611    {"abort",           posix_abort, METH_NOARGS, posix_abort__doc__},
11612#ifdef MS_WINDOWS
11613    {"_getfullpathname",        posix__getfullpathname, METH_VARARGS, NULL},
11614    {"_getfinalpathname",       posix__getfinalpathname, METH_VARARGS, NULL},
11615    {"_isdir",                  posix__isdir, METH_VARARGS, posix__isdir__doc__},
11616    {"_getdiskusage",           win32__getdiskusage, METH_VARARGS, win32__getdiskusage__doc__},
11617    {"_getvolumepathname",      posix__getvolumepathname, METH_VARARGS, posix__getvolumepathname__doc__},
11618#endif
11619#ifdef HAVE_GETLOADAVG
11620    {"getloadavg",      posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},
11621#endif
11622    {"urandom",         posix_urandom,   METH_VARARGS, posix_urandom__doc__},
11623#ifdef HAVE_SETRESUID
11624    {"setresuid",       posix_setresuid, METH_VARARGS, posix_setresuid__doc__},
11625#endif
11626#ifdef HAVE_SETRESGID
11627    {"setresgid",       posix_setresgid, METH_VARARGS, posix_setresgid__doc__},
11628#endif
11629#ifdef HAVE_GETRESUID
11630    {"getresuid",       posix_getresuid, METH_NOARGS, posix_getresuid__doc__},
11631#endif
11632#ifdef HAVE_GETRESGID
11633    {"getresgid",       posix_getresgid, METH_NOARGS, posix_getresgid__doc__},
11634#endif
11635
11636#ifdef USE_XATTRS
11637    {"setxattr", (PyCFunction)posix_setxattr,
11638                 METH_VARARGS | METH_KEYWORDS,
11639                 posix_setxattr__doc__},
11640    {"getxattr", (PyCFunction)posix_getxattr,
11641                 METH_VARARGS | METH_KEYWORDS,
11642                 posix_getxattr__doc__},
11643    {"removexattr", (PyCFunction)posix_removexattr,
11644                 METH_VARARGS | METH_KEYWORDS,
11645                 posix_removexattr__doc__},
11646    {"listxattr", (PyCFunction)posix_listxattr,
11647                 METH_VARARGS | METH_KEYWORDS,
11648                 posix_listxattr__doc__},
11649#endif
11650#if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL)
11651    {"get_terminal_size", get_terminal_size, METH_VARARGS, termsize__doc__},
11652#endif
11653    {"cpu_count", (PyCFunction)posix_cpu_count,
11654                  METH_NOARGS, posix_cpu_count__doc__},
11655    {"get_inheritable", posix_get_inheritable, METH_VARARGS, get_inheritable__doc__},
11656    {"set_inheritable", posix_set_inheritable, METH_VARARGS, set_inheritable__doc__},
11657#ifdef MS_WINDOWS
11658    {"get_handle_inheritable", posix_get_handle_inheritable,
11659     METH_VARARGS, get_handle_inheritable__doc__},
11660    {"set_handle_inheritable", posix_set_handle_inheritable,
11661     METH_VARARGS, set_handle_inheritable__doc__},
11662#endif
11663    {NULL,              NULL}            /* Sentinel */
11664};
11665
11666
11667#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
11668static int
11669enable_symlink()
11670{
11671    HANDLE tok;
11672    TOKEN_PRIVILEGES tok_priv;
11673    LUID luid;
11674    int meth_idx = 0;
11675
11676    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &tok))
11677        return 0;
11678
11679    if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid))
11680        return 0;
11681
11682    tok_priv.PrivilegeCount = 1;
11683    tok_priv.Privileges[0].Luid = luid;
11684    tok_priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
11685
11686    if (!AdjustTokenPrivileges(tok, FALSE, &tok_priv,
11687                               sizeof(TOKEN_PRIVILEGES),
11688                               (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL))
11689        return 0;
11690
11691    /* ERROR_NOT_ALL_ASSIGNED returned when the privilege can't be assigned. */
11692    return GetLastError() == ERROR_NOT_ALL_ASSIGNED ? 0 : 1;
11693}
11694#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
11695
11696static int
11697all_ins(PyObject *m)
11698{
11699#ifdef F_OK
11700    if (PyModule_AddIntMacro(m, F_OK)) return -1;
11701#endif
11702#ifdef R_OK
11703    if (PyModule_AddIntMacro(m, R_OK)) return -1;
11704#endif
11705#ifdef W_OK
11706    if (PyModule_AddIntMacro(m, W_OK)) return -1;
11707#endif
11708#ifdef X_OK
11709    if (PyModule_AddIntMacro(m, X_OK)) return -1;
11710#endif
11711#ifdef NGROUPS_MAX
11712    if (PyModule_AddIntMacro(m, NGROUPS_MAX)) return -1;
11713#endif
11714#ifdef TMP_MAX
11715    if (PyModule_AddIntMacro(m, TMP_MAX)) return -1;
11716#endif
11717#ifdef WCONTINUED
11718    if (PyModule_AddIntMacro(m, WCONTINUED)) return -1;
11719#endif
11720#ifdef WNOHANG
11721    if (PyModule_AddIntMacro(m, WNOHANG)) return -1;
11722#endif
11723#ifdef WUNTRACED
11724    if (PyModule_AddIntMacro(m, WUNTRACED)) return -1;
11725#endif
11726#ifdef O_RDONLY
11727    if (PyModule_AddIntMacro(m, O_RDONLY)) return -1;
11728#endif
11729#ifdef O_WRONLY
11730    if (PyModule_AddIntMacro(m, O_WRONLY)) return -1;
11731#endif
11732#ifdef O_RDWR
11733    if (PyModule_AddIntMacro(m, O_RDWR)) return -1;
11734#endif
11735#ifdef O_NDELAY
11736    if (PyModule_AddIntMacro(m, O_NDELAY)) return -1;
11737#endif
11738#ifdef O_NONBLOCK
11739    if (PyModule_AddIntMacro(m, O_NONBLOCK)) return -1;
11740#endif
11741#ifdef O_APPEND
11742    if (PyModule_AddIntMacro(m, O_APPEND)) return -1;
11743#endif
11744#ifdef O_DSYNC
11745    if (PyModule_AddIntMacro(m, O_DSYNC)) return -1;
11746#endif
11747#ifdef O_RSYNC
11748    if (PyModule_AddIntMacro(m, O_RSYNC)) return -1;
11749#endif
11750#ifdef O_SYNC
11751    if (PyModule_AddIntMacro(m, O_SYNC)) return -1;
11752#endif
11753#ifdef O_NOCTTY
11754    if (PyModule_AddIntMacro(m, O_NOCTTY)) return -1;
11755#endif
11756#ifdef O_CREAT
11757    if (PyModule_AddIntMacro(m, O_CREAT)) return -1;
11758#endif
11759#ifdef O_EXCL
11760    if (PyModule_AddIntMacro(m, O_EXCL)) return -1;
11761#endif
11762#ifdef O_TRUNC
11763    if (PyModule_AddIntMacro(m, O_TRUNC)) return -1;
11764#endif
11765#ifdef O_BINARY
11766    if (PyModule_AddIntMacro(m, O_BINARY)) return -1;
11767#endif
11768#ifdef O_TEXT
11769    if (PyModule_AddIntMacro(m, O_TEXT)) return -1;
11770#endif
11771#ifdef O_XATTR
11772    if (PyModule_AddIntMacro(m, O_XATTR)) return -1;
11773#endif
11774#ifdef O_LARGEFILE
11775    if (PyModule_AddIntMacro(m, O_LARGEFILE)) return -1;
11776#endif
11777#ifdef O_SHLOCK
11778    if (PyModule_AddIntMacro(m, O_SHLOCK)) return -1;
11779#endif
11780#ifdef O_EXLOCK
11781    if (PyModule_AddIntMacro(m, O_EXLOCK)) return -1;
11782#endif
11783#ifdef O_EXEC
11784    if (PyModule_AddIntMacro(m, O_EXEC)) return -1;
11785#endif
11786#ifdef O_SEARCH
11787    if (PyModule_AddIntMacro(m, O_SEARCH)) return -1;
11788#endif
11789#ifdef O_PATH
11790    if (PyModule_AddIntMacro(m, O_PATH)) return -1;
11791#endif
11792#ifdef O_TTY_INIT
11793    if (PyModule_AddIntMacro(m, O_TTY_INIT)) return -1;
11794#endif
11795#ifdef O_TMPFILE
11796    if (PyModule_AddIntMacro(m, O_TMPFILE)) return -1;
11797#endif
11798#ifdef PRIO_PROCESS
11799    if (PyModule_AddIntMacro(m, PRIO_PROCESS)) return -1;
11800#endif
11801#ifdef PRIO_PGRP
11802    if (PyModule_AddIntMacro(m, PRIO_PGRP)) return -1;
11803#endif
11804#ifdef PRIO_USER
11805    if (PyModule_AddIntMacro(m, PRIO_USER)) return -1;
11806#endif
11807#ifdef O_CLOEXEC
11808    if (PyModule_AddIntMacro(m, O_CLOEXEC)) return -1;
11809#endif
11810#ifdef O_ACCMODE
11811    if (PyModule_AddIntMacro(m, O_ACCMODE)) return -1;
11812#endif
11813
11814
11815#ifdef SEEK_HOLE
11816    if (PyModule_AddIntMacro(m, SEEK_HOLE)) return -1;
11817#endif
11818#ifdef SEEK_DATA
11819    if (PyModule_AddIntMacro(m, SEEK_DATA)) return -1;
11820#endif
11821
11822/* MS Windows */
11823#ifdef O_NOINHERIT
11824    /* Don't inherit in child processes. */
11825    if (PyModule_AddIntMacro(m, O_NOINHERIT)) return -1;
11826#endif
11827#ifdef _O_SHORT_LIVED
11828    /* Optimize for short life (keep in memory). */
11829    /* MS forgot to define this one with a non-underscore form too. */
11830    if (PyModule_AddIntConstant(m, "O_SHORT_LIVED", _O_SHORT_LIVED)) return -1;
11831#endif
11832#ifdef O_TEMPORARY
11833    /* Automatically delete when last handle is closed. */
11834    if (PyModule_AddIntMacro(m, O_TEMPORARY)) return -1;
11835#endif
11836#ifdef O_RANDOM
11837    /* Optimize for random access. */
11838    if (PyModule_AddIntMacro(m, O_RANDOM)) return -1;
11839#endif
11840#ifdef O_SEQUENTIAL
11841    /* Optimize for sequential access. */
11842    if (PyModule_AddIntMacro(m, O_SEQUENTIAL)) return -1;
11843#endif
11844
11845/* GNU extensions. */
11846#ifdef O_ASYNC
11847    /* Send a SIGIO signal whenever input or output
11848       becomes available on file descriptor */
11849    if (PyModule_AddIntMacro(m, O_ASYNC)) return -1;
11850#endif
11851#ifdef O_DIRECT
11852    /* Direct disk access. */
11853    if (PyModule_AddIntMacro(m, O_DIRECT)) return -1;
11854#endif
11855#ifdef O_DIRECTORY
11856    /* Must be a directory.      */
11857    if (PyModule_AddIntMacro(m, O_DIRECTORY)) return -1;
11858#endif
11859#ifdef O_NOFOLLOW
11860    /* Do not follow links.      */
11861    if (PyModule_AddIntMacro(m, O_NOFOLLOW)) return -1;
11862#endif
11863#ifdef O_NOLINKS
11864    /* Fails if link count of the named file is greater than 1 */
11865    if (PyModule_AddIntMacro(m, O_NOLINKS)) return -1;
11866#endif
11867#ifdef O_NOATIME
11868    /* Do not update the access time. */
11869    if (PyModule_AddIntMacro(m, O_NOATIME)) return -1;
11870#endif
11871
11872    /* These come from sysexits.h */
11873#ifdef EX_OK
11874    if (PyModule_AddIntMacro(m, EX_OK)) return -1;
11875#endif /* EX_OK */
11876#ifdef EX_USAGE
11877    if (PyModule_AddIntMacro(m, EX_USAGE)) return -1;
11878#endif /* EX_USAGE */
11879#ifdef EX_DATAERR
11880    if (PyModule_AddIntMacro(m, EX_DATAERR)) return -1;
11881#endif /* EX_DATAERR */
11882#ifdef EX_NOINPUT
11883    if (PyModule_AddIntMacro(m, EX_NOINPUT)) return -1;
11884#endif /* EX_NOINPUT */
11885#ifdef EX_NOUSER
11886    if (PyModule_AddIntMacro(m, EX_NOUSER)) return -1;
11887#endif /* EX_NOUSER */
11888#ifdef EX_NOHOST
11889    if (PyModule_AddIntMacro(m, EX_NOHOST)) return -1;
11890#endif /* EX_NOHOST */
11891#ifdef EX_UNAVAILABLE
11892    if (PyModule_AddIntMacro(m, EX_UNAVAILABLE)) return -1;
11893#endif /* EX_UNAVAILABLE */
11894#ifdef EX_SOFTWARE
11895    if (PyModule_AddIntMacro(m, EX_SOFTWARE)) return -1;
11896#endif /* EX_SOFTWARE */
11897#ifdef EX_OSERR
11898    if (PyModule_AddIntMacro(m, EX_OSERR)) return -1;
11899#endif /* EX_OSERR */
11900#ifdef EX_OSFILE
11901    if (PyModule_AddIntMacro(m, EX_OSFILE)) return -1;
11902#endif /* EX_OSFILE */
11903#ifdef EX_CANTCREAT
11904    if (PyModule_AddIntMacro(m, EX_CANTCREAT)) return -1;
11905#endif /* EX_CANTCREAT */
11906#ifdef EX_IOERR
11907    if (PyModule_AddIntMacro(m, EX_IOERR)) return -1;
11908#endif /* EX_IOERR */
11909#ifdef EX_TEMPFAIL
11910    if (PyModule_AddIntMacro(m, EX_TEMPFAIL)) return -1;
11911#endif /* EX_TEMPFAIL */
11912#ifdef EX_PROTOCOL
11913    if (PyModule_AddIntMacro(m, EX_PROTOCOL)) return -1;
11914#endif /* EX_PROTOCOL */
11915#ifdef EX_NOPERM
11916    if (PyModule_AddIntMacro(m, EX_NOPERM)) return -1;
11917#endif /* EX_NOPERM */
11918#ifdef EX_CONFIG
11919    if (PyModule_AddIntMacro(m, EX_CONFIG)) return -1;
11920#endif /* EX_CONFIG */
11921#ifdef EX_NOTFOUND
11922    if (PyModule_AddIntMacro(m, EX_NOTFOUND)) return -1;
11923#endif /* EX_NOTFOUND */
11924
11925    /* statvfs */
11926#ifdef ST_RDONLY
11927    if (PyModule_AddIntMacro(m, ST_RDONLY)) return -1;
11928#endif /* ST_RDONLY */
11929#ifdef ST_NOSUID
11930    if (PyModule_AddIntMacro(m, ST_NOSUID)) return -1;
11931#endif /* ST_NOSUID */
11932
11933       /* GNU extensions */
11934#ifdef ST_NODEV
11935    if (PyModule_AddIntMacro(m, ST_NODEV)) return -1;
11936#endif /* ST_NODEV */
11937#ifdef ST_NOEXEC
11938    if (PyModule_AddIntMacro(m, ST_NOEXEC)) return -1;
11939#endif /* ST_NOEXEC */
11940#ifdef ST_SYNCHRONOUS
11941    if (PyModule_AddIntMacro(m, ST_SYNCHRONOUS)) return -1;
11942#endif /* ST_SYNCHRONOUS */
11943#ifdef ST_MANDLOCK
11944    if (PyModule_AddIntMacro(m, ST_MANDLOCK)) return -1;
11945#endif /* ST_MANDLOCK */
11946#ifdef ST_WRITE
11947    if (PyModule_AddIntMacro(m, ST_WRITE)) return -1;
11948#endif /* ST_WRITE */
11949#ifdef ST_APPEND
11950    if (PyModule_AddIntMacro(m, ST_APPEND)) return -1;
11951#endif /* ST_APPEND */
11952#ifdef ST_NOATIME
11953    if (PyModule_AddIntMacro(m, ST_NOATIME)) return -1;
11954#endif /* ST_NOATIME */
11955#ifdef ST_NODIRATIME
11956    if (PyModule_AddIntMacro(m, ST_NODIRATIME)) return -1;
11957#endif /* ST_NODIRATIME */
11958#ifdef ST_RELATIME
11959    if (PyModule_AddIntMacro(m, ST_RELATIME)) return -1;
11960#endif /* ST_RELATIME */
11961
11962    /* FreeBSD sendfile() constants */
11963#ifdef SF_NODISKIO
11964    if (PyModule_AddIntMacro(m, SF_NODISKIO)) return -1;
11965#endif
11966#ifdef SF_MNOWAIT
11967    if (PyModule_AddIntMacro(m, SF_MNOWAIT)) return -1;
11968#endif
11969#ifdef SF_SYNC
11970    if (PyModule_AddIntMacro(m, SF_SYNC)) return -1;
11971#endif
11972
11973    /* constants for posix_fadvise */
11974#ifdef POSIX_FADV_NORMAL
11975    if (PyModule_AddIntMacro(m, POSIX_FADV_NORMAL)) return -1;
11976#endif
11977#ifdef POSIX_FADV_SEQUENTIAL
11978    if (PyModule_AddIntMacro(m, POSIX_FADV_SEQUENTIAL)) return -1;
11979#endif
11980#ifdef POSIX_FADV_RANDOM
11981    if (PyModule_AddIntMacro(m, POSIX_FADV_RANDOM)) return -1;
11982#endif
11983#ifdef POSIX_FADV_NOREUSE
11984    if (PyModule_AddIntMacro(m, POSIX_FADV_NOREUSE)) return -1;
11985#endif
11986#ifdef POSIX_FADV_WILLNEED
11987    if (PyModule_AddIntMacro(m, POSIX_FADV_WILLNEED)) return -1;
11988#endif
11989#ifdef POSIX_FADV_DONTNEED
11990    if (PyModule_AddIntMacro(m, POSIX_FADV_DONTNEED)) return -1;
11991#endif
11992
11993    /* constants for waitid */
11994#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_WAITID)
11995    if (PyModule_AddIntMacro(m, P_PID)) return -1;
11996    if (PyModule_AddIntMacro(m, P_PGID)) return -1;
11997    if (PyModule_AddIntMacro(m, P_ALL)) return -1;
11998#endif
11999#ifdef WEXITED
12000    if (PyModule_AddIntMacro(m, WEXITED)) return -1;
12001#endif
12002#ifdef WNOWAIT
12003    if (PyModule_AddIntMacro(m, WNOWAIT)) return -1;
12004#endif
12005#ifdef WSTOPPED
12006    if (PyModule_AddIntMacro(m, WSTOPPED)) return -1;
12007#endif
12008#ifdef CLD_EXITED
12009    if (PyModule_AddIntMacro(m, CLD_EXITED)) return -1;
12010#endif
12011#ifdef CLD_DUMPED
12012    if (PyModule_AddIntMacro(m, CLD_DUMPED)) return -1;
12013#endif
12014#ifdef CLD_TRAPPED
12015    if (PyModule_AddIntMacro(m, CLD_TRAPPED)) return -1;
12016#endif
12017#ifdef CLD_CONTINUED
12018    if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1;
12019#endif
12020
12021    /* constants for lockf */
12022#ifdef F_LOCK
12023    if (PyModule_AddIntMacro(m, F_LOCK)) return -1;
12024#endif
12025#ifdef F_TLOCK
12026    if (PyModule_AddIntMacro(m, F_TLOCK)) return -1;
12027#endif
12028#ifdef F_ULOCK
12029    if (PyModule_AddIntMacro(m, F_ULOCK)) return -1;
12030#endif
12031#ifdef F_TEST
12032    if (PyModule_AddIntMacro(m, F_TEST)) return -1;
12033#endif
12034
12035#ifdef HAVE_SPAWNV
12036    if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1;
12037    if (PyModule_AddIntConstant(m, "P_NOWAIT", _P_NOWAIT)) return -1;
12038    if (PyModule_AddIntConstant(m, "P_OVERLAY", _OLD_P_OVERLAY)) return -1;
12039    if (PyModule_AddIntConstant(m, "P_NOWAITO", _P_NOWAITO)) return -1;
12040    if (PyModule_AddIntConstant(m, "P_DETACH", _P_DETACH)) return -1;
12041#endif
12042
12043#ifdef HAVE_SCHED_H
12044    if (PyModule_AddIntMacro(m, SCHED_OTHER)) return -1;
12045    if (PyModule_AddIntMacro(m, SCHED_FIFO)) return -1;
12046    if (PyModule_AddIntMacro(m, SCHED_RR)) return -1;
12047#ifdef SCHED_SPORADIC
12048    if (PyModule_AddIntMacro(m, SCHED_SPORADIC) return -1;
12049#endif
12050#ifdef SCHED_BATCH
12051    if (PyModule_AddIntMacro(m, SCHED_BATCH)) return -1;
12052#endif
12053#ifdef SCHED_IDLE
12054    if (PyModule_AddIntMacro(m, SCHED_IDLE)) return -1;
12055#endif
12056#ifdef SCHED_RESET_ON_FORK
12057    if (PyModule_AddIntMacro(m, SCHED_RESET_ON_FORK)) return -1;
12058#endif
12059#ifdef SCHED_SYS
12060    if (PyModule_AddIntMacro(m, SCHED_SYS)) return -1;
12061#endif
12062#ifdef SCHED_IA
12063    if (PyModule_AddIntMacro(m, SCHED_IA)) return -1;
12064#endif
12065#ifdef SCHED_FSS
12066    if (PyModule_AddIntMacro(m, SCHED_FSS)) return -1;
12067#endif
12068#ifdef SCHED_FX
12069    if (PyModule_AddIntConstant(m, "SCHED_FX", SCHED_FSS)) return -1;
12070#endif
12071#endif
12072
12073#ifdef USE_XATTRS
12074    if (PyModule_AddIntMacro(m, XATTR_CREATE)) return -1;
12075    if (PyModule_AddIntMacro(m, XATTR_REPLACE)) return -1;
12076    if (PyModule_AddIntMacro(m, XATTR_SIZE_MAX)) return -1;
12077#endif
12078
12079#ifdef RTLD_LAZY
12080    if (PyModule_AddIntMacro(m, RTLD_LAZY)) return -1;
12081#endif
12082#ifdef RTLD_NOW
12083    if (PyModule_AddIntMacro(m, RTLD_NOW)) return -1;
12084#endif
12085#ifdef RTLD_GLOBAL
12086    if (PyModule_AddIntMacro(m, RTLD_GLOBAL)) return -1;
12087#endif
12088#ifdef RTLD_LOCAL
12089    if (PyModule_AddIntMacro(m, RTLD_LOCAL)) return -1;
12090#endif
12091#ifdef RTLD_NODELETE
12092    if (PyModule_AddIntMacro(m, RTLD_NODELETE)) return -1;
12093#endif
12094#ifdef RTLD_NOLOAD
12095    if (PyModule_AddIntMacro(m, RTLD_NOLOAD)) return -1;
12096#endif
12097#ifdef RTLD_DEEPBIND
12098    if (PyModule_AddIntMacro(m, RTLD_DEEPBIND)) return -1;
12099#endif
12100
12101    return 0;
12102}
12103
12104
12105#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__)) && !defined(__QNX__)
12106#define INITFUNC PyInit_nt
12107#define MODNAME "nt"
12108
12109#else
12110#define INITFUNC PyInit_posix
12111#define MODNAME "posix"
12112#endif
12113
12114static struct PyModuleDef posixmodule = {
12115    PyModuleDef_HEAD_INIT,
12116    MODNAME,
12117    posix__doc__,
12118    -1,
12119    posix_methods,
12120    NULL,
12121    NULL,
12122    NULL,
12123    NULL
12124};
12125
12126
12127static char *have_functions[] = {
12128
12129#ifdef HAVE_FACCESSAT
12130    "HAVE_FACCESSAT",
12131#endif
12132
12133#ifdef HAVE_FCHDIR
12134    "HAVE_FCHDIR",
12135#endif
12136
12137#ifdef HAVE_FCHMOD
12138    "HAVE_FCHMOD",
12139#endif
12140
12141#ifdef HAVE_FCHMODAT
12142    "HAVE_FCHMODAT",
12143#endif
12144
12145#ifdef HAVE_FCHOWN
12146    "HAVE_FCHOWN",
12147#endif
12148
12149#ifdef HAVE_FCHOWNAT
12150    "HAVE_FCHOWNAT",
12151#endif
12152
12153#ifdef HAVE_FEXECVE
12154    "HAVE_FEXECVE",
12155#endif
12156
12157#ifdef HAVE_FDOPENDIR
12158    "HAVE_FDOPENDIR",
12159#endif
12160
12161#ifdef HAVE_FPATHCONF
12162    "HAVE_FPATHCONF",
12163#endif
12164
12165#ifdef HAVE_FSTATAT
12166    "HAVE_FSTATAT",
12167#endif
12168
12169#ifdef HAVE_FSTATVFS
12170    "HAVE_FSTATVFS",
12171#endif
12172
12173#ifdef HAVE_FTRUNCATE
12174    "HAVE_FTRUNCATE",
12175#endif
12176
12177#ifdef HAVE_FUTIMENS
12178    "HAVE_FUTIMENS",
12179#endif
12180
12181#ifdef HAVE_FUTIMES
12182    "HAVE_FUTIMES",
12183#endif
12184
12185#ifdef HAVE_FUTIMESAT
12186    "HAVE_FUTIMESAT",
12187#endif
12188
12189#ifdef HAVE_LINKAT
12190    "HAVE_LINKAT",
12191#endif
12192
12193#ifdef HAVE_LCHFLAGS
12194    "HAVE_LCHFLAGS",
12195#endif
12196
12197#ifdef HAVE_LCHMOD
12198    "HAVE_LCHMOD",
12199#endif
12200
12201#ifdef HAVE_LCHOWN
12202    "HAVE_LCHOWN",
12203#endif
12204
12205#ifdef HAVE_LSTAT
12206    "HAVE_LSTAT",
12207#endif
12208
12209#ifdef HAVE_LUTIMES
12210    "HAVE_LUTIMES",
12211#endif
12212
12213#ifdef HAVE_MKDIRAT
12214    "HAVE_MKDIRAT",
12215#endif
12216
12217#ifdef HAVE_MKFIFOAT
12218    "HAVE_MKFIFOAT",
12219#endif
12220
12221#ifdef HAVE_MKNODAT
12222    "HAVE_MKNODAT",
12223#endif
12224
12225#ifdef HAVE_OPENAT
12226    "HAVE_OPENAT",
12227#endif
12228
12229#ifdef HAVE_READLINKAT
12230    "HAVE_READLINKAT",
12231#endif
12232
12233#ifdef HAVE_RENAMEAT
12234    "HAVE_RENAMEAT",
12235#endif
12236
12237#ifdef HAVE_SYMLINKAT
12238    "HAVE_SYMLINKAT",
12239#endif
12240
12241#ifdef HAVE_UNLINKAT
12242    "HAVE_UNLINKAT",
12243#endif
12244
12245#ifdef HAVE_UTIMENSAT
12246    "HAVE_UTIMENSAT",
12247#endif
12248
12249#ifdef MS_WINDOWS
12250    "MS_WINDOWS",
12251#endif
12252
12253    NULL
12254};
12255
12256
12257PyMODINIT_FUNC
12258INITFUNC(void)
12259{
12260    PyObject *m, *v;
12261    PyObject *list;
12262    char **trace;
12263
12264#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
12265    win32_can_symlink = enable_symlink();
12266#endif
12267
12268    m = PyModule_Create(&posixmodule);
12269    if (m == NULL)
12270        return NULL;
12271
12272    /* Initialize environ dictionary */
12273    v = convertenviron();
12274    Py_XINCREF(v);
12275    if (v == NULL || PyModule_AddObject(m, "environ", v) != 0)
12276        return NULL;
12277    Py_DECREF(v);
12278
12279    if (all_ins(m))
12280        return NULL;
12281
12282    if (setup_confname_tables(m))
12283        return NULL;
12284
12285    Py_INCREF(PyExc_OSError);
12286    PyModule_AddObject(m, "error", PyExc_OSError);
12287
12288#ifdef HAVE_PUTENV
12289    if (posix_putenv_garbage == NULL)
12290        posix_putenv_garbage = PyDict_New();
12291#endif
12292
12293    if (!initialized) {
12294#if defined(HAVE_WAITID) && !defined(__APPLE__)
12295        waitid_result_desc.name = MODNAME ".waitid_result";
12296        if (PyStructSequence_InitType2(&WaitidResultType, &waitid_result_desc) < 0)
12297            return NULL;
12298#endif
12299
12300        stat_result_desc.name = "os.stat_result"; /* see issue #19209 */
12301        stat_result_desc.fields[7].name = PyStructSequence_UnnamedField;
12302        stat_result_desc.fields[8].name = PyStructSequence_UnnamedField;
12303        stat_result_desc.fields[9].name = PyStructSequence_UnnamedField;
12304        if (PyStructSequence_InitType2(&StatResultType, &stat_result_desc) < 0)
12305            return NULL;
12306        structseq_new = StatResultType.tp_new;
12307        StatResultType.tp_new = statresult_new;
12308
12309        statvfs_result_desc.name = "os.statvfs_result"; /* see issue #19209 */
12310        if (PyStructSequence_InitType2(&StatVFSResultType,
12311                                       &statvfs_result_desc) < 0)
12312            return NULL;
12313#ifdef NEED_TICKS_PER_SECOND
12314#  if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
12315        ticks_per_second = sysconf(_SC_CLK_TCK);
12316#  elif defined(HZ)
12317        ticks_per_second = HZ;
12318#  else
12319        ticks_per_second = 60; /* magic fallback value; may be bogus */
12320#  endif
12321#endif
12322
12323#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER)
12324        sched_param_desc.name = MODNAME ".sched_param";
12325        if (PyStructSequence_InitType2(&SchedParamType, &sched_param_desc) < 0)
12326            return NULL;
12327        SchedParamType.tp_new = sched_param_new;
12328#endif
12329
12330        /* initialize TerminalSize_info */
12331        if (PyStructSequence_InitType2(&TerminalSizeType,
12332                                       &TerminalSize_desc) < 0)
12333            return NULL;
12334    }
12335#if defined(HAVE_WAITID) && !defined(__APPLE__)
12336    Py_INCREF((PyObject*) &WaitidResultType);
12337    PyModule_AddObject(m, "waitid_result", (PyObject*) &WaitidResultType);
12338#endif
12339    Py_INCREF((PyObject*) &StatResultType);
12340    PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType);
12341    Py_INCREF((PyObject*) &StatVFSResultType);
12342    PyModule_AddObject(m, "statvfs_result",
12343                       (PyObject*) &StatVFSResultType);
12344
12345#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER)
12346    Py_INCREF(&SchedParamType);
12347    PyModule_AddObject(m, "sched_param", (PyObject *)&SchedParamType);
12348#endif
12349
12350    times_result_desc.name = MODNAME ".times_result";
12351    if (PyStructSequence_InitType2(&TimesResultType, &times_result_desc) < 0)
12352        return NULL;
12353    PyModule_AddObject(m, "times_result", (PyObject *)&TimesResultType);
12354
12355    uname_result_desc.name = MODNAME ".uname_result";
12356    if (PyStructSequence_InitType2(&UnameResultType, &uname_result_desc) < 0)
12357        return NULL;
12358    PyModule_AddObject(m, "uname_result", (PyObject *)&UnameResultType);
12359
12360#ifdef __APPLE__
12361    /*
12362     * Step 2 of weak-linking support on Mac OS X.
12363     *
12364     * The code below removes functions that are not available on the
12365     * currently active platform.
12366     *
12367     * This block allow one to use a python binary that was build on
12368     * OSX 10.4 on OSX 10.3, without losing access to new APIs on
12369     * OSX 10.4.
12370     */
12371#ifdef HAVE_FSTATVFS
12372    if (fstatvfs == NULL) {
12373        if (PyObject_DelAttrString(m, "fstatvfs") == -1) {
12374            return NULL;
12375        }
12376    }
12377#endif /* HAVE_FSTATVFS */
12378
12379#ifdef HAVE_STATVFS
12380    if (statvfs == NULL) {
12381        if (PyObject_DelAttrString(m, "statvfs") == -1) {
12382            return NULL;
12383        }
12384    }
12385#endif /* HAVE_STATVFS */
12386
12387# ifdef HAVE_LCHOWN
12388    if (lchown == NULL) {
12389        if (PyObject_DelAttrString(m, "lchown") == -1) {
12390            return NULL;
12391        }
12392    }
12393#endif /* HAVE_LCHOWN */
12394
12395
12396#endif /* __APPLE__ */
12397
12398    Py_INCREF(&TerminalSizeType);
12399    PyModule_AddObject(m, "terminal_size", (PyObject*) &TerminalSizeType);
12400
12401    billion = PyLong_FromLong(1000000000);
12402    if (!billion)
12403        return NULL;
12404
12405    /* suppress "function not used" warnings */
12406    {
12407    int ignored;
12408    fd_specified("", -1);
12409    follow_symlinks_specified("", 1);
12410    dir_fd_and_follow_symlinks_invalid("chmod", DEFAULT_DIR_FD, 1);
12411    dir_fd_converter(Py_None, &ignored);
12412    dir_fd_unavailable(Py_None, &ignored);
12413    }
12414
12415    /*
12416     * provide list of locally available functions
12417     * so os.py can populate support_* lists
12418     */
12419    list = PyList_New(0);
12420    if (!list)
12421        return NULL;
12422    for (trace = have_functions; *trace; trace++) {
12423        PyObject *unicode = PyUnicode_DecodeASCII(*trace, strlen(*trace), NULL);
12424        if (!unicode)
12425            return NULL;
12426        if (PyList_Append(list, unicode))
12427            return NULL;
12428        Py_DECREF(unicode);
12429    }
12430    PyModule_AddObject(m, "_have_functions", list);
12431
12432    initialized = 1;
12433
12434    return m;
12435}
12436
12437#ifdef __cplusplus
12438}
12439#endif
12440