1#include "Python.h"
2#include "osdefs.h"
3#include <locale.h>
4
5#ifdef MS_WINDOWS
6#  include <malloc.h>
7#  include <windows.h>
8extern int winerror_to_errno(int);
9#endif
10
11#ifdef HAVE_LANGINFO_H
12#include <langinfo.h>
13#endif
14
15#ifdef HAVE_SYS_IOCTL_H
16#include <sys/ioctl.h>
17#endif
18
19#ifdef HAVE_FCNTL_H
20#include <fcntl.h>
21#endif /* HAVE_FCNTL_H */
22
23#if defined(__APPLE__) || defined(__ANDROID__)
24extern wchar_t* _Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size);
25#endif
26
27#ifdef O_CLOEXEC
28/* Does open() support the O_CLOEXEC flag? Possible values:
29
30   -1: unknown
31    0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23
32    1: open() supports O_CLOEXEC flag, close-on-exec is set
33
34   The flag is used by _Py_open(), _Py_open_noraise(), io.FileIO
35   and os.open(). */
36int _Py_open_cloexec_works = -1;
37#endif
38
39PyObject *
40_Py_device_encoding(int fd)
41{
42#if defined(MS_WINDOWS)
43    UINT cp;
44#endif
45    int valid;
46    _Py_BEGIN_SUPPRESS_IPH
47    valid = isatty(fd);
48    _Py_END_SUPPRESS_IPH
49    if (!valid)
50        Py_RETURN_NONE;
51
52#if defined(MS_WINDOWS)
53    if (fd == 0)
54        cp = GetConsoleCP();
55    else if (fd == 1 || fd == 2)
56        cp = GetConsoleOutputCP();
57    else
58        cp = 0;
59    /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application
60       has no console */
61    if (cp != 0)
62        return PyUnicode_FromFormat("cp%u", (unsigned int)cp);
63#elif defined(CODESET)
64    {
65        char *codeset = nl_langinfo(CODESET);
66        if (codeset != NULL && codeset[0] != 0)
67            return PyUnicode_FromString(codeset);
68    }
69#endif
70    Py_RETURN_NONE;
71}
72
73#if !defined(__APPLE__) && !defined(MS_WINDOWS)
74extern int _Py_normalize_encoding(const char *, char *, size_t);
75
76/* Workaround FreeBSD and OpenIndiana locale encoding issue with the C locale.
77   On these operating systems, nl_langinfo(CODESET) announces an alias of the
78   ASCII encoding, whereas mbstowcs() and wcstombs() functions use the
79   ISO-8859-1 encoding. The problem is that os.fsencode() and os.fsdecode() use
80   locale.getpreferredencoding() codec. For example, if command line arguments
81   are decoded by mbstowcs() and encoded back by os.fsencode(), we get a
82   UnicodeEncodeError instead of retrieving the original byte string.
83
84   The workaround is enabled if setlocale(LC_CTYPE, NULL) returns "C",
85   nl_langinfo(CODESET) announces "ascii" (or an alias to ASCII), and at least
86   one byte in range 0x80-0xff can be decoded from the locale encoding. The
87   workaround is also enabled on error, for example if getting the locale
88   failed.
89
90   Values of force_ascii:
91
92       1: the workaround is used: Py_EncodeLocale() uses
93          encode_ascii_surrogateescape() and Py_DecodeLocale() uses
94          decode_ascii_surrogateescape()
95       0: the workaround is not used: Py_EncodeLocale() uses wcstombs() and
96          Py_DecodeLocale() uses mbstowcs()
97      -1: unknown, need to call check_force_ascii() to get the value
98*/
99static int force_ascii = -1;
100
101static int
102check_force_ascii(void)
103{
104    char *loc;
105#if defined(HAVE_LANGINFO_H) && defined(CODESET)
106    char *codeset, **alias;
107    char encoding[20];   /* longest name: "iso_646.irv_1991\0" */
108    int is_ascii;
109    unsigned int i;
110    char* ascii_aliases[] = {
111        "ascii",
112        /* Aliases from Lib/encodings/aliases.py */
113        "646",
114        "ansi_x3.4_1968",
115        "ansi_x3.4_1986",
116        "ansi_x3_4_1968",
117        "cp367",
118        "csascii",
119        "ibm367",
120        "iso646_us",
121        "iso_646.irv_1991",
122        "iso_ir_6",
123        "us",
124        "us_ascii",
125        NULL
126    };
127#endif
128
129    loc = setlocale(LC_CTYPE, NULL);
130    if (loc == NULL)
131        goto error;
132    if (strcmp(loc, "C") != 0) {
133        /* the LC_CTYPE locale is different than C */
134        return 0;
135    }
136
137#if defined(HAVE_LANGINFO_H) && defined(CODESET)
138    codeset = nl_langinfo(CODESET);
139    if (!codeset || codeset[0] == '\0') {
140        /* CODESET is not set or empty */
141        goto error;
142    }
143    if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding)))
144        goto error;
145
146    is_ascii = 0;
147    for (alias=ascii_aliases; *alias != NULL; alias++) {
148        if (strcmp(encoding, *alias) == 0) {
149            is_ascii = 1;
150            break;
151        }
152    }
153    if (!is_ascii) {
154        /* nl_langinfo(CODESET) is not "ascii" or an alias of ASCII */
155        return 0;
156    }
157
158    for (i=0x80; i<0xff; i++) {
159        unsigned char ch;
160        wchar_t wch;
161        size_t res;
162
163        ch = (unsigned char)i;
164        res = mbstowcs(&wch, (char*)&ch, 1);
165        if (res != (size_t)-1) {
166            /* decoding a non-ASCII character from the locale encoding succeed:
167               the locale encoding is not ASCII, force ASCII */
168            return 1;
169        }
170    }
171    /* None of the bytes in the range 0x80-0xff can be decoded from the locale
172       encoding: the locale encoding is really ASCII */
173    return 0;
174#else
175    /* nl_langinfo(CODESET) is not available: always force ASCII */
176    return 1;
177#endif
178
179error:
180    /* if an error occurred, force the ASCII encoding */
181    return 1;
182}
183
184static char*
185encode_ascii_surrogateescape(const wchar_t *text, size_t *error_pos)
186{
187    char *result = NULL, *out;
188    size_t len, i;
189    wchar_t ch;
190
191    if (error_pos != NULL)
192        *error_pos = (size_t)-1;
193
194    len = wcslen(text);
195
196    result = PyMem_Malloc(len + 1);  /* +1 for NUL byte */
197    if (result == NULL)
198        return NULL;
199
200    out = result;
201    for (i=0; i<len; i++) {
202        ch = text[i];
203
204        if (ch <= 0x7f) {
205            /* ASCII character */
206            *out++ = (char)ch;
207        }
208        else if (0xdc80 <= ch && ch <= 0xdcff) {
209            /* UTF-8b surrogate */
210            *out++ = (char)(ch - 0xdc00);
211        }
212        else {
213            if (error_pos != NULL)
214                *error_pos = i;
215            PyMem_Free(result);
216            return NULL;
217        }
218    }
219    *out = '\0';
220    return result;
221}
222#endif   /* !defined(__APPLE__) && !defined(MS_WINDOWS) */
223
224#if !defined(__APPLE__) && (!defined(MS_WINDOWS) || !defined(HAVE_MBRTOWC))
225static wchar_t*
226decode_ascii_surrogateescape(const char *arg, size_t *size)
227{
228    wchar_t *res;
229    unsigned char *in;
230    wchar_t *out;
231    size_t argsize = strlen(arg) + 1;
232
233    if (argsize > PY_SSIZE_T_MAX/sizeof(wchar_t))
234        return NULL;
235    res = PyMem_RawMalloc(argsize*sizeof(wchar_t));
236    if (!res)
237        return NULL;
238
239    in = (unsigned char*)arg;
240    out = res;
241    while(*in)
242        if(*in < 128)
243            *out++ = *in++;
244        else
245            *out++ = 0xdc00 + *in++;
246    *out = 0;
247    if (size != NULL)
248        *size = out - res;
249    return res;
250}
251#endif
252
253
254/* Decode a byte string from the locale encoding with the
255   surrogateescape error handler: undecodable bytes are decoded as characters
256   in range U+DC80..U+DCFF. If a byte sequence can be decoded as a surrogate
257   character, escape the bytes using the surrogateescape error handler instead
258   of decoding them.
259
260   Return a pointer to a newly allocated wide character string, use
261   PyMem_RawFree() to free the memory. If size is not NULL, write the number of
262   wide characters excluding the null character into *size
263
264   Return NULL on decoding error or memory allocation error. If *size* is not
265   NULL, *size is set to (size_t)-1 on memory error or set to (size_t)-2 on
266   decoding error.
267
268   Decoding errors should never happen, unless there is a bug in the C
269   library.
270
271   Use the Py_EncodeLocale() function to encode the character string back to a
272   byte string. */
273wchar_t*
274Py_DecodeLocale(const char* arg, size_t *size)
275{
276#if defined(__APPLE__) || defined(__ANDROID__)
277    wchar_t *wstr;
278    wstr = _Py_DecodeUTF8_surrogateescape(arg, strlen(arg));
279    if (size != NULL) {
280        if (wstr != NULL)
281            *size = wcslen(wstr);
282        else
283            *size = (size_t)-1;
284    }
285    return wstr;
286#else
287    wchar_t *res;
288    size_t argsize;
289    size_t count;
290#ifdef HAVE_MBRTOWC
291    unsigned char *in;
292    wchar_t *out;
293    mbstate_t mbs;
294#endif
295
296#ifndef MS_WINDOWS
297    if (force_ascii == -1)
298        force_ascii = check_force_ascii();
299
300    if (force_ascii) {
301        /* force ASCII encoding to workaround mbstowcs() issue */
302        res = decode_ascii_surrogateescape(arg, size);
303        if (res == NULL)
304            goto oom;
305        return res;
306    }
307#endif
308
309#ifdef HAVE_BROKEN_MBSTOWCS
310    /* Some platforms have a broken implementation of
311     * mbstowcs which does not count the characters that
312     * would result from conversion.  Use an upper bound.
313     */
314    argsize = strlen(arg);
315#else
316    argsize = mbstowcs(NULL, arg, 0);
317#endif
318    if (argsize != (size_t)-1) {
319        if (argsize == PY_SSIZE_T_MAX)
320            goto oom;
321        argsize += 1;
322        if (argsize > PY_SSIZE_T_MAX/sizeof(wchar_t))
323            goto oom;
324        res = (wchar_t *)PyMem_RawMalloc(argsize*sizeof(wchar_t));
325        if (!res)
326            goto oom;
327        count = mbstowcs(res, arg, argsize);
328        if (count != (size_t)-1) {
329            wchar_t *tmp;
330            /* Only use the result if it contains no
331               surrogate characters. */
332            for (tmp = res; *tmp != 0 &&
333                         !Py_UNICODE_IS_SURROGATE(*tmp); tmp++)
334                ;
335            if (*tmp == 0) {
336                if (size != NULL)
337                    *size = count;
338                return res;
339            }
340        }
341        PyMem_RawFree(res);
342    }
343    /* Conversion failed. Fall back to escaping with surrogateescape. */
344#ifdef HAVE_MBRTOWC
345    /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
346
347    /* Overallocate; as multi-byte characters are in the argument, the
348       actual output could use less memory. */
349    argsize = strlen(arg) + 1;
350    if (argsize > PY_SSIZE_T_MAX/sizeof(wchar_t))
351        goto oom;
352    res = (wchar_t*)PyMem_RawMalloc(argsize*sizeof(wchar_t));
353    if (!res)
354        goto oom;
355    in = (unsigned char*)arg;
356    out = res;
357    memset(&mbs, 0, sizeof mbs);
358    while (argsize) {
359        size_t converted = mbrtowc(out, (char*)in, argsize, &mbs);
360        if (converted == 0)
361            /* Reached end of string; null char stored. */
362            break;
363        if (converted == (size_t)-2) {
364            /* Incomplete character. This should never happen,
365               since we provide everything that we have -
366               unless there is a bug in the C library, or I
367               misunderstood how mbrtowc works. */
368            PyMem_RawFree(res);
369            if (size != NULL)
370                *size = (size_t)-2;
371            return NULL;
372        }
373        if (converted == (size_t)-1) {
374            /* Conversion error. Escape as UTF-8b, and start over
375               in the initial shift state. */
376            *out++ = 0xdc00 + *in++;
377            argsize--;
378            memset(&mbs, 0, sizeof mbs);
379            continue;
380        }
381        if (Py_UNICODE_IS_SURROGATE(*out)) {
382            /* Surrogate character.  Escape the original
383               byte sequence with surrogateescape. */
384            argsize -= converted;
385            while (converted--)
386                *out++ = 0xdc00 + *in++;
387            continue;
388        }
389        /* successfully converted some bytes */
390        in += converted;
391        argsize -= converted;
392        out++;
393    }
394    if (size != NULL)
395        *size = out - res;
396#else   /* HAVE_MBRTOWC */
397    /* Cannot use C locale for escaping; manually escape as if charset
398       is ASCII (i.e. escape all bytes > 128. This will still roundtrip
399       correctly in the locale's charset, which must be an ASCII superset. */
400    res = decode_ascii_surrogateescape(arg, size);
401    if (res == NULL)
402        goto oom;
403#endif   /* HAVE_MBRTOWC */
404    return res;
405oom:
406    if (size != NULL)
407        *size = (size_t)-1;
408    return NULL;
409#endif   /* __APPLE__ or __ANDROID__ */
410}
411
412/* Encode a wide character string to the locale encoding with the
413   surrogateescape error handler: surrogate characters in the range
414   U+DC80..U+DCFF are converted to bytes 0x80..0xFF.
415
416   Return a pointer to a newly allocated byte string, use PyMem_Free() to free
417   the memory. Return NULL on encoding or memory allocation error.
418
419   If error_pos is not NULL, *error_pos is set to the index of the invalid
420   character on encoding error, or set to (size_t)-1 otherwise.
421
422   Use the Py_DecodeLocale() function to decode the bytes string back to a wide
423   character string. */
424char*
425Py_EncodeLocale(const wchar_t *text, size_t *error_pos)
426{
427#if defined(__APPLE__) || defined(__ANDROID__)
428    Py_ssize_t len;
429    PyObject *unicode, *bytes = NULL;
430    char *cpath;
431
432    unicode = PyUnicode_FromWideChar(text, wcslen(text));
433    if (unicode == NULL)
434        return NULL;
435
436    bytes = _PyUnicode_AsUTF8String(unicode, "surrogateescape");
437    Py_DECREF(unicode);
438    if (bytes == NULL) {
439        PyErr_Clear();
440        if (error_pos != NULL)
441            *error_pos = (size_t)-1;
442        return NULL;
443    }
444
445    len = PyBytes_GET_SIZE(bytes);
446    cpath = PyMem_Malloc(len+1);
447    if (cpath == NULL) {
448        PyErr_Clear();
449        Py_DECREF(bytes);
450        if (error_pos != NULL)
451            *error_pos = (size_t)-1;
452        return NULL;
453    }
454    memcpy(cpath, PyBytes_AsString(bytes), len + 1);
455    Py_DECREF(bytes);
456    return cpath;
457#else   /* __APPLE__ */
458    const size_t len = wcslen(text);
459    char *result = NULL, *bytes = NULL;
460    size_t i, size, converted;
461    wchar_t c, buf[2];
462
463#ifndef MS_WINDOWS
464    if (force_ascii == -1)
465        force_ascii = check_force_ascii();
466
467    if (force_ascii)
468        return encode_ascii_surrogateescape(text, error_pos);
469#endif
470
471    /* The function works in two steps:
472       1. compute the length of the output buffer in bytes (size)
473       2. outputs the bytes */
474    size = 0;
475    buf[1] = 0;
476    while (1) {
477        for (i=0; i < len; i++) {
478            c = text[i];
479            if (c >= 0xdc80 && c <= 0xdcff) {
480                /* UTF-8b surrogate */
481                if (bytes != NULL) {
482                    *bytes++ = c - 0xdc00;
483                    size--;
484                }
485                else
486                    size++;
487                continue;
488            }
489            else {
490                buf[0] = c;
491                if (bytes != NULL)
492                    converted = wcstombs(bytes, buf, size);
493                else
494                    converted = wcstombs(NULL, buf, 0);
495                if (converted == (size_t)-1) {
496                    if (result != NULL)
497                        PyMem_Free(result);
498                    if (error_pos != NULL)
499                        *error_pos = i;
500                    return NULL;
501                }
502                if (bytes != NULL) {
503                    bytes += converted;
504                    size -= converted;
505                }
506                else
507                    size += converted;
508            }
509        }
510        if (result != NULL) {
511            *bytes = '\0';
512            break;
513        }
514
515        size += 1; /* nul byte at the end */
516        result = PyMem_Malloc(size);
517        if (result == NULL) {
518            if (error_pos != NULL)
519                *error_pos = (size_t)-1;
520            return NULL;
521        }
522        bytes = result;
523    }
524    return result;
525#endif   /* __APPLE__ or __ANDROID__ */
526}
527
528
529#ifdef MS_WINDOWS
530static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */
531
532static void
533FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out)
534{
535    /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */
536    /* Cannot simply cast and dereference in_ptr,
537       since it might not be aligned properly */
538    __int64 in;
539    memcpy(&in, in_ptr, sizeof(in));
540    *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */
541    *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t);
542}
543
544void
545_Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr)
546{
547    /* XXX endianness */
548    __int64 out;
549    out = time_in + secs_between_epochs;
550    out = out * 10000000 + nsec_in / 100;
551    memcpy(out_ptr, &out, sizeof(out));
552}
553
554/* Below, we *know* that ugo+r is 0444 */
555#if _S_IREAD != 0400
556#error Unsupported C library
557#endif
558static int
559attributes_to_mode(DWORD attr)
560{
561    int m = 0;
562    if (attr & FILE_ATTRIBUTE_DIRECTORY)
563        m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */
564    else
565        m |= _S_IFREG;
566    if (attr & FILE_ATTRIBUTE_READONLY)
567        m |= 0444;
568    else
569        m |= 0666;
570    return m;
571}
572
573void
574_Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag,
575                           struct _Py_stat_struct *result)
576{
577    memset(result, 0, sizeof(*result));
578    result->st_mode = attributes_to_mode(info->dwFileAttributes);
579    result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
580    result->st_dev = info->dwVolumeSerialNumber;
581    result->st_rdev = result->st_dev;
582    FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec);
583    FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec);
584    FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec);
585    result->st_nlink = info->nNumberOfLinks;
586    result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow;
587    if (reparse_tag == IO_REPARSE_TAG_SYMLINK) {
588        /* first clear the S_IFMT bits */
589        result->st_mode ^= (result->st_mode & S_IFMT);
590        /* now set the bits that make this a symlink */
591        result->st_mode |= S_IFLNK;
592    }
593    result->st_file_attributes = info->dwFileAttributes;
594}
595#endif
596
597/* Return information about a file.
598
599   On POSIX, use fstat().
600
601   On Windows, use GetFileType() and GetFileInformationByHandle() which support
602   files larger than 2 GB.  fstat() may fail with EOVERFLOW on files larger
603   than 2 GB because the file size type is a signed 32-bit integer: see issue
604   #23152.
605
606   On Windows, set the last Windows error and return nonzero on error. On
607   POSIX, set errno and return nonzero on error. Fill status and return 0 on
608   success. */
609int
610_Py_fstat_noraise(int fd, struct _Py_stat_struct *status)
611{
612#ifdef MS_WINDOWS
613    BY_HANDLE_FILE_INFORMATION info;
614    HANDLE h;
615    int type;
616
617    _Py_BEGIN_SUPPRESS_IPH
618    h = (HANDLE)_get_osfhandle(fd);
619    _Py_END_SUPPRESS_IPH
620
621    if (h == INVALID_HANDLE_VALUE) {
622        /* errno is already set by _get_osfhandle, but we also set
623           the Win32 error for callers who expect that */
624        SetLastError(ERROR_INVALID_HANDLE);
625        return -1;
626    }
627    memset(status, 0, sizeof(*status));
628
629    type = GetFileType(h);
630    if (type == FILE_TYPE_UNKNOWN) {
631        DWORD error = GetLastError();
632        if (error != 0) {
633            errno = winerror_to_errno(error);
634            return -1;
635        }
636        /* else: valid but unknown file */
637    }
638
639    if (type != FILE_TYPE_DISK) {
640        if (type == FILE_TYPE_CHAR)
641            status->st_mode = _S_IFCHR;
642        else if (type == FILE_TYPE_PIPE)
643            status->st_mode = _S_IFIFO;
644        return 0;
645    }
646
647    if (!GetFileInformationByHandle(h, &info)) {
648        /* The Win32 error is already set, but we also set errno for
649           callers who expect it */
650        errno = winerror_to_errno(GetLastError());
651        return -1;
652    }
653
654    _Py_attribute_data_to_stat(&info, 0, status);
655    /* specific to fstat() */
656    status->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
657    return 0;
658#else
659    return fstat(fd, status);
660#endif
661}
662
663/* Return information about a file.
664
665   On POSIX, use fstat().
666
667   On Windows, use GetFileType() and GetFileInformationByHandle() which support
668   files larger than 2 GB.  fstat() may fail with EOVERFLOW on files larger
669   than 2 GB because the file size type is a signed 32-bit integer: see issue
670   #23152.
671
672   Raise an exception and return -1 on error. On Windows, set the last Windows
673   error on error. On POSIX, set errno on error. Fill status and return 0 on
674   success.
675
676   Release the GIL to call GetFileType() and GetFileInformationByHandle(), or
677   to call fstat(). The caller must hold the GIL. */
678int
679_Py_fstat(int fd, struct _Py_stat_struct *status)
680{
681    int res;
682
683#ifdef WITH_THREAD
684    assert(PyGILState_Check());
685#endif
686
687    Py_BEGIN_ALLOW_THREADS
688    res = _Py_fstat_noraise(fd, status);
689    Py_END_ALLOW_THREADS
690
691    if (res != 0) {
692#ifdef MS_WINDOWS
693        PyErr_SetFromWindowsErr(0);
694#else
695        PyErr_SetFromErrno(PyExc_OSError);
696#endif
697        return -1;
698    }
699    return 0;
700}
701
702/* Call _wstat() on Windows, or encode the path to the filesystem encoding and
703   call stat() otherwise. Only fill st_mode attribute on Windows.
704
705   Return 0 on success, -1 on _wstat() / stat() error, -2 if an exception was
706   raised. */
707
708int
709_Py_stat(PyObject *path, struct stat *statbuf)
710{
711#ifdef MS_WINDOWS
712    int err;
713    struct _stat wstatbuf;
714    wchar_t *wpath;
715
716    wpath = PyUnicode_AsUnicode(path);
717    if (wpath == NULL)
718        return -2;
719    err = _wstat(wpath, &wstatbuf);
720    if (!err)
721        statbuf->st_mode = wstatbuf.st_mode;
722    return err;
723#else
724    int ret;
725    PyObject *bytes = PyUnicode_EncodeFSDefault(path);
726    if (bytes == NULL)
727        return -2;
728    ret = stat(PyBytes_AS_STRING(bytes), statbuf);
729    Py_DECREF(bytes);
730    return ret;
731#endif
732}
733
734
735static int
736get_inheritable(int fd, int raise)
737{
738#ifdef MS_WINDOWS
739    HANDLE handle;
740    DWORD flags;
741
742    _Py_BEGIN_SUPPRESS_IPH
743    handle = (HANDLE)_get_osfhandle(fd);
744    _Py_END_SUPPRESS_IPH
745    if (handle == INVALID_HANDLE_VALUE) {
746        if (raise)
747            PyErr_SetFromErrno(PyExc_OSError);
748        return -1;
749    }
750
751    if (!GetHandleInformation(handle, &flags)) {
752        if (raise)
753            PyErr_SetFromWindowsErr(0);
754        return -1;
755    }
756
757    return (flags & HANDLE_FLAG_INHERIT);
758#else
759    int flags;
760
761    flags = fcntl(fd, F_GETFD, 0);
762    if (flags == -1) {
763        if (raise)
764            PyErr_SetFromErrno(PyExc_OSError);
765        return -1;
766    }
767    return !(flags & FD_CLOEXEC);
768#endif
769}
770
771/* Get the inheritable flag of the specified file descriptor.
772   Return 1 if the file descriptor can be inherited, 0 if it cannot,
773   raise an exception and return -1 on error. */
774int
775_Py_get_inheritable(int fd)
776{
777    return get_inheritable(fd, 1);
778}
779
780static int
781set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works)
782{
783#ifdef MS_WINDOWS
784    HANDLE handle;
785    DWORD flags;
786#else
787#if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
788    static int ioctl_works = -1;
789    int request;
790    int err;
791#endif
792    int flags, new_flags;
793    int res;
794#endif
795
796    /* atomic_flag_works can only be used to make the file descriptor
797       non-inheritable */
798    assert(!(atomic_flag_works != NULL && inheritable));
799
800    if (atomic_flag_works != NULL && !inheritable) {
801        if (*atomic_flag_works == -1) {
802            int isInheritable = get_inheritable(fd, raise);
803            if (isInheritable == -1)
804                return -1;
805            *atomic_flag_works = !isInheritable;
806        }
807
808        if (*atomic_flag_works)
809            return 0;
810    }
811
812#ifdef MS_WINDOWS
813    _Py_BEGIN_SUPPRESS_IPH
814    handle = (HANDLE)_get_osfhandle(fd);
815    _Py_END_SUPPRESS_IPH
816    if (handle == INVALID_HANDLE_VALUE) {
817        if (raise)
818            PyErr_SetFromErrno(PyExc_OSError);
819        return -1;
820    }
821
822    if (inheritable)
823        flags = HANDLE_FLAG_INHERIT;
824    else
825        flags = 0;
826    if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, flags)) {
827        if (raise)
828            PyErr_SetFromWindowsErr(0);
829        return -1;
830    }
831    return 0;
832
833#else
834
835#if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
836    if (ioctl_works != 0) {
837        /* fast-path: ioctl() only requires one syscall */
838        if (inheritable)
839            request = FIONCLEX;
840        else
841            request = FIOCLEX;
842        err = ioctl(fd, request, NULL);
843        if (!err) {
844            ioctl_works = 1;
845            return 0;
846        }
847
848        if (errno != ENOTTY && errno != EACCES) {
849            if (raise)
850                PyErr_SetFromErrno(PyExc_OSError);
851            return -1;
852        }
853        else {
854            /* Issue #22258: Here, ENOTTY means "Inappropriate ioctl for
855               device". The ioctl is declared but not supported by the kernel.
856               Remember that ioctl() doesn't work. It is the case on
857               Illumos-based OS for example.
858
859               Issue #27057: When SELinux policy disallows ioctl it will fail
860               with EACCES. While FIOCLEX is safe operation it may be
861               unavailable because ioctl was denied altogether.
862               This can be the case on Android. */
863            ioctl_works = 0;
864        }
865        /* fallback to fcntl() if ioctl() does not work */
866    }
867#endif
868
869    /* slow-path: fcntl() requires two syscalls */
870    flags = fcntl(fd, F_GETFD);
871    if (flags < 0) {
872        if (raise)
873            PyErr_SetFromErrno(PyExc_OSError);
874        return -1;
875    }
876
877    if (inheritable) {
878        new_flags = flags & ~FD_CLOEXEC;
879    }
880    else {
881        new_flags = flags | FD_CLOEXEC;
882    }
883
884    if (new_flags == flags) {
885        /* FD_CLOEXEC flag already set/cleared: nothing to do */
886        return 0;
887    }
888
889    res = fcntl(fd, F_SETFD, new_flags);
890    if (res < 0) {
891        if (raise)
892            PyErr_SetFromErrno(PyExc_OSError);
893        return -1;
894    }
895    return 0;
896#endif
897}
898
899/* Make the file descriptor non-inheritable.
900   Return 0 on success, set errno and return -1 on error. */
901static int
902make_non_inheritable(int fd)
903{
904    return set_inheritable(fd, 0, 0, NULL);
905}
906
907/* Set the inheritable flag of the specified file descriptor.
908   On success: return 0, on error: raise an exception if raise is nonzero
909   and return -1.
910
911   If atomic_flag_works is not NULL:
912
913    * if *atomic_flag_works==-1, check if the inheritable is set on the file
914      descriptor: if yes, set *atomic_flag_works to 1, otherwise set to 0 and
915      set the inheritable flag
916    * if *atomic_flag_works==1: do nothing
917    * if *atomic_flag_works==0: set inheritable flag to False
918
919   Set atomic_flag_works to NULL if no atomic flag was used to create the
920   file descriptor.
921
922   atomic_flag_works can only be used to make a file descriptor
923   non-inheritable: atomic_flag_works must be NULL if inheritable=1. */
924int
925_Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works)
926{
927    return set_inheritable(fd, inheritable, 1, atomic_flag_works);
928}
929
930static int
931_Py_open_impl(const char *pathname, int flags, int gil_held)
932{
933    int fd;
934    int async_err = 0;
935#ifndef MS_WINDOWS
936    int *atomic_flag_works;
937#endif
938
939#ifdef MS_WINDOWS
940    flags |= O_NOINHERIT;
941#elif defined(O_CLOEXEC)
942    atomic_flag_works = &_Py_open_cloexec_works;
943    flags |= O_CLOEXEC;
944#else
945    atomic_flag_works = NULL;
946#endif
947
948    if (gil_held) {
949        do {
950            Py_BEGIN_ALLOW_THREADS
951            fd = open(pathname, flags);
952            Py_END_ALLOW_THREADS
953        } while (fd < 0
954                 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
955        if (async_err)
956            return -1;
957        if (fd < 0) {
958            PyErr_SetFromErrnoWithFilename(PyExc_OSError, pathname);
959            return -1;
960        }
961    }
962    else {
963        fd = open(pathname, flags);
964        if (fd < 0)
965            return -1;
966    }
967
968#ifndef MS_WINDOWS
969    if (set_inheritable(fd, 0, gil_held, atomic_flag_works) < 0) {
970        close(fd);
971        return -1;
972    }
973#endif
974
975    return fd;
976}
977
978/* Open a file with the specified flags (wrapper to open() function).
979   Return a file descriptor on success. Raise an exception and return -1 on
980   error.
981
982   The file descriptor is created non-inheritable.
983
984   When interrupted by a signal (open() fails with EINTR), retry the syscall,
985   except if the Python signal handler raises an exception.
986
987   Release the GIL to call open(). The caller must hold the GIL. */
988int
989_Py_open(const char *pathname, int flags)
990{
991#ifdef WITH_THREAD
992    /* _Py_open() must be called with the GIL held. */
993    assert(PyGILState_Check());
994#endif
995    return _Py_open_impl(pathname, flags, 1);
996}
997
998/* Open a file with the specified flags (wrapper to open() function).
999   Return a file descriptor on success. Set errno and return -1 on error.
1000
1001   The file descriptor is created non-inheritable.
1002
1003   If interrupted by a signal, fail with EINTR. */
1004int
1005_Py_open_noraise(const char *pathname, int flags)
1006{
1007    return _Py_open_impl(pathname, flags, 0);
1008}
1009
1010/* Open a file. Use _wfopen() on Windows, encode the path to the locale
1011   encoding and use fopen() otherwise.
1012
1013   The file descriptor is created non-inheritable.
1014
1015   If interrupted by a signal, fail with EINTR. */
1016FILE *
1017_Py_wfopen(const wchar_t *path, const wchar_t *mode)
1018{
1019    FILE *f;
1020#ifndef MS_WINDOWS
1021    char *cpath;
1022    char cmode[10];
1023    size_t r;
1024    r = wcstombs(cmode, mode, 10);
1025    if (r == (size_t)-1 || r >= 10) {
1026        errno = EINVAL;
1027        return NULL;
1028    }
1029    cpath = Py_EncodeLocale(path, NULL);
1030    if (cpath == NULL)
1031        return NULL;
1032    f = fopen(cpath, cmode);
1033    PyMem_Free(cpath);
1034#else
1035    f = _wfopen(path, mode);
1036#endif
1037    if (f == NULL)
1038        return NULL;
1039    if (make_non_inheritable(fileno(f)) < 0) {
1040        fclose(f);
1041        return NULL;
1042    }
1043    return f;
1044}
1045
1046/* Wrapper to fopen().
1047
1048   The file descriptor is created non-inheritable.
1049
1050   If interrupted by a signal, fail with EINTR. */
1051FILE*
1052_Py_fopen(const char *pathname, const char *mode)
1053{
1054    FILE *f = fopen(pathname, mode);
1055    if (f == NULL)
1056        return NULL;
1057    if (make_non_inheritable(fileno(f)) < 0) {
1058        fclose(f);
1059        return NULL;
1060    }
1061    return f;
1062}
1063
1064/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem
1065   encoding and call fopen() otherwise.
1066
1067   Return the new file object on success. Raise an exception and return NULL
1068   on error.
1069
1070   The file descriptor is created non-inheritable.
1071
1072   When interrupted by a signal (open() fails with EINTR), retry the syscall,
1073   except if the Python signal handler raises an exception.
1074
1075   Release the GIL to call _wfopen() or fopen(). The caller must hold
1076   the GIL. */
1077FILE*
1078_Py_fopen_obj(PyObject *path, const char *mode)
1079{
1080    FILE *f;
1081    int async_err = 0;
1082#ifdef MS_WINDOWS
1083    wchar_t *wpath;
1084    wchar_t wmode[10];
1085    int usize;
1086
1087#ifdef WITH_THREAD
1088    assert(PyGILState_Check());
1089#endif
1090
1091    if (!PyUnicode_Check(path)) {
1092        PyErr_Format(PyExc_TypeError,
1093                     "str file path expected under Windows, got %R",
1094                     Py_TYPE(path));
1095        return NULL;
1096    }
1097    wpath = PyUnicode_AsUnicode(path);
1098    if (wpath == NULL)
1099        return NULL;
1100
1101    usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, wmode, sizeof(wmode));
1102    if (usize == 0) {
1103        PyErr_SetFromWindowsErr(0);
1104        return NULL;
1105    }
1106
1107    do {
1108        Py_BEGIN_ALLOW_THREADS
1109        f = _wfopen(wpath, wmode);
1110        Py_END_ALLOW_THREADS
1111    } while (f == NULL
1112             && errno == EINTR && !(async_err = PyErr_CheckSignals()));
1113#else
1114    PyObject *bytes;
1115    char *path_bytes;
1116
1117#ifdef WITH_THREAD
1118    assert(PyGILState_Check());
1119#endif
1120
1121    if (!PyUnicode_FSConverter(path, &bytes))
1122        return NULL;
1123    path_bytes = PyBytes_AS_STRING(bytes);
1124
1125    do {
1126        Py_BEGIN_ALLOW_THREADS
1127        f = fopen(path_bytes, mode);
1128        Py_END_ALLOW_THREADS
1129    } while (f == NULL
1130             && errno == EINTR && !(async_err = PyErr_CheckSignals()));
1131
1132    Py_DECREF(bytes);
1133#endif
1134    if (async_err)
1135        return NULL;
1136
1137    if (f == NULL) {
1138        PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
1139        return NULL;
1140    }
1141
1142    if (set_inheritable(fileno(f), 0, 1, NULL) < 0) {
1143        fclose(f);
1144        return NULL;
1145    }
1146    return f;
1147}
1148
1149/* Read count bytes from fd into buf.
1150
1151   On success, return the number of read bytes, it can be lower than count.
1152   If the current file offset is at or past the end of file, no bytes are read,
1153   and read() returns zero.
1154
1155   On error, raise an exception, set errno and return -1.
1156
1157   When interrupted by a signal (read() fails with EINTR), retry the syscall.
1158   If the Python signal handler raises an exception, the function returns -1
1159   (the syscall is not retried).
1160
1161   Release the GIL to call read(). The caller must hold the GIL. */
1162Py_ssize_t
1163_Py_read(int fd, void *buf, size_t count)
1164{
1165    Py_ssize_t n;
1166    int err;
1167    int async_err = 0;
1168
1169#ifdef WITH_THREAD
1170    assert(PyGILState_Check());
1171#endif
1172
1173    /* _Py_read() must not be called with an exception set, otherwise the
1174     * caller may think that read() was interrupted by a signal and the signal
1175     * handler raised an exception. */
1176    assert(!PyErr_Occurred());
1177
1178#ifdef MS_WINDOWS
1179    if (count > INT_MAX) {
1180        /* On Windows, the count parameter of read() is an int */
1181        count = INT_MAX;
1182    }
1183#else
1184    if (count > PY_SSIZE_T_MAX) {
1185        /* if count is greater than PY_SSIZE_T_MAX,
1186         * read() result is undefined */
1187        count = PY_SSIZE_T_MAX;
1188    }
1189#endif
1190
1191    _Py_BEGIN_SUPPRESS_IPH
1192    do {
1193        Py_BEGIN_ALLOW_THREADS
1194        errno = 0;
1195#ifdef MS_WINDOWS
1196        n = read(fd, buf, (int)count);
1197#else
1198        n = read(fd, buf, count);
1199#endif
1200        /* save/restore errno because PyErr_CheckSignals()
1201         * and PyErr_SetFromErrno() can modify it */
1202        err = errno;
1203        Py_END_ALLOW_THREADS
1204    } while (n < 0 && err == EINTR &&
1205            !(async_err = PyErr_CheckSignals()));
1206    _Py_END_SUPPRESS_IPH
1207
1208    if (async_err) {
1209        /* read() was interrupted by a signal (failed with EINTR)
1210         * and the Python signal handler raised an exception */
1211        errno = err;
1212        assert(errno == EINTR && PyErr_Occurred());
1213        return -1;
1214    }
1215    if (n < 0) {
1216        PyErr_SetFromErrno(PyExc_OSError);
1217        errno = err;
1218        return -1;
1219    }
1220
1221    return n;
1222}
1223
1224static Py_ssize_t
1225_Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
1226{
1227    Py_ssize_t n;
1228    int err;
1229    int async_err = 0;
1230
1231    _Py_BEGIN_SUPPRESS_IPH
1232#ifdef MS_WINDOWS
1233    if (count > 32767 && isatty(fd)) {
1234        /* Issue #11395: the Windows console returns an error (12: not
1235           enough space error) on writing into stdout if stdout mode is
1236           binary and the length is greater than 66,000 bytes (or less,
1237           depending on heap usage). */
1238        count = 32767;
1239    }
1240    else if (count > INT_MAX)
1241        count = INT_MAX;
1242#else
1243    if (count > PY_SSIZE_T_MAX) {
1244        /* write() should truncate count to PY_SSIZE_T_MAX, but it's safer
1245         * to do it ourself to have a portable behaviour. */
1246        count = PY_SSIZE_T_MAX;
1247    }
1248#endif
1249
1250    if (gil_held) {
1251        do {
1252            Py_BEGIN_ALLOW_THREADS
1253            errno = 0;
1254#ifdef MS_WINDOWS
1255            n = write(fd, buf, (int)count);
1256#else
1257            n = write(fd, buf, count);
1258#endif
1259            /* save/restore errno because PyErr_CheckSignals()
1260             * and PyErr_SetFromErrno() can modify it */
1261            err = errno;
1262            Py_END_ALLOW_THREADS
1263        } while (n < 0 && err == EINTR &&
1264                !(async_err = PyErr_CheckSignals()));
1265    }
1266    else {
1267        do {
1268            errno = 0;
1269#ifdef MS_WINDOWS
1270            n = write(fd, buf, (int)count);
1271#else
1272            n = write(fd, buf, count);
1273#endif
1274            err = errno;
1275        } while (n < 0 && err == EINTR);
1276    }
1277    _Py_END_SUPPRESS_IPH
1278
1279    if (async_err) {
1280        /* write() was interrupted by a signal (failed with EINTR)
1281           and the Python signal handler raised an exception (if gil_held is
1282           nonzero). */
1283        errno = err;
1284        assert(errno == EINTR && (!gil_held || PyErr_Occurred()));
1285        return -1;
1286    }
1287    if (n < 0) {
1288        if (gil_held)
1289            PyErr_SetFromErrno(PyExc_OSError);
1290        errno = err;
1291        return -1;
1292    }
1293
1294    return n;
1295}
1296
1297/* Write count bytes of buf into fd.
1298
1299   On success, return the number of written bytes, it can be lower than count
1300   including 0. On error, raise an exception, set errno and return -1.
1301
1302   When interrupted by a signal (write() fails with EINTR), retry the syscall.
1303   If the Python signal handler raises an exception, the function returns -1
1304   (the syscall is not retried).
1305
1306   Release the GIL to call write(). The caller must hold the GIL. */
1307Py_ssize_t
1308_Py_write(int fd, const void *buf, size_t count)
1309{
1310#ifdef WITH_THREAD
1311    assert(PyGILState_Check());
1312#endif
1313
1314    /* _Py_write() must not be called with an exception set, otherwise the
1315     * caller may think that write() was interrupted by a signal and the signal
1316     * handler raised an exception. */
1317    assert(!PyErr_Occurred());
1318
1319    return _Py_write_impl(fd, buf, count, 1);
1320}
1321
1322/* Write count bytes of buf into fd.
1323 *
1324 * On success, return the number of written bytes, it can be lower than count
1325 * including 0. On error, set errno and return -1.
1326 *
1327 * When interrupted by a signal (write() fails with EINTR), retry the syscall
1328 * without calling the Python signal handler. */
1329Py_ssize_t
1330_Py_write_noraise(int fd, const void *buf, size_t count)
1331{
1332    return _Py_write_impl(fd, buf, count, 0);
1333}
1334
1335#ifdef HAVE_READLINK
1336
1337/* Read value of symbolic link. Encode the path to the locale encoding, decode
1338   the result from the locale encoding. Return -1 on error. */
1339
1340int
1341_Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz)
1342{
1343    char *cpath;
1344    char cbuf[MAXPATHLEN];
1345    wchar_t *wbuf;
1346    int res;
1347    size_t r1;
1348
1349    cpath = Py_EncodeLocale(path, NULL);
1350    if (cpath == NULL) {
1351        errno = EINVAL;
1352        return -1;
1353    }
1354    res = (int)readlink(cpath, cbuf, Py_ARRAY_LENGTH(cbuf));
1355    PyMem_Free(cpath);
1356    if (res == -1)
1357        return -1;
1358    if (res == Py_ARRAY_LENGTH(cbuf)) {
1359        errno = EINVAL;
1360        return -1;
1361    }
1362    cbuf[res] = '\0'; /* buf will be null terminated */
1363    wbuf = Py_DecodeLocale(cbuf, &r1);
1364    if (wbuf == NULL) {
1365        errno = EINVAL;
1366        return -1;
1367    }
1368    if (bufsiz <= r1) {
1369        PyMem_RawFree(wbuf);
1370        errno = EINVAL;
1371        return -1;
1372    }
1373    wcsncpy(buf, wbuf, bufsiz);
1374    PyMem_RawFree(wbuf);
1375    return (int)r1;
1376}
1377#endif
1378
1379#ifdef HAVE_REALPATH
1380
1381/* Return the canonicalized absolute pathname. Encode path to the locale
1382   encoding, decode the result from the locale encoding.
1383   Return NULL on error. */
1384
1385wchar_t*
1386_Py_wrealpath(const wchar_t *path,
1387              wchar_t *resolved_path, size_t resolved_path_size)
1388{
1389    char *cpath;
1390    char cresolved_path[MAXPATHLEN];
1391    wchar_t *wresolved_path;
1392    char *res;
1393    size_t r;
1394    cpath = Py_EncodeLocale(path, NULL);
1395    if (cpath == NULL) {
1396        errno = EINVAL;
1397        return NULL;
1398    }
1399    res = realpath(cpath, cresolved_path);
1400    PyMem_Free(cpath);
1401    if (res == NULL)
1402        return NULL;
1403
1404    wresolved_path = Py_DecodeLocale(cresolved_path, &r);
1405    if (wresolved_path == NULL) {
1406        errno = EINVAL;
1407        return NULL;
1408    }
1409    if (resolved_path_size <= r) {
1410        PyMem_RawFree(wresolved_path);
1411        errno = EINVAL;
1412        return NULL;
1413    }
1414    wcsncpy(resolved_path, wresolved_path, resolved_path_size);
1415    PyMem_RawFree(wresolved_path);
1416    return resolved_path;
1417}
1418#endif
1419
1420/* Get the current directory. size is the buffer size in wide characters
1421   including the null character. Decode the path from the locale encoding.
1422   Return NULL on error. */
1423
1424wchar_t*
1425_Py_wgetcwd(wchar_t *buf, size_t size)
1426{
1427#ifdef MS_WINDOWS
1428    int isize = (int)Py_MIN(size, INT_MAX);
1429    return _wgetcwd(buf, isize);
1430#else
1431    char fname[MAXPATHLEN];
1432    wchar_t *wname;
1433    size_t len;
1434
1435    if (getcwd(fname, Py_ARRAY_LENGTH(fname)) == NULL)
1436        return NULL;
1437    wname = Py_DecodeLocale(fname, &len);
1438    if (wname == NULL)
1439        return NULL;
1440    if (size <= len) {
1441        PyMem_RawFree(wname);
1442        return NULL;
1443    }
1444    wcsncpy(buf, wname, size);
1445    PyMem_RawFree(wname);
1446    return buf;
1447#endif
1448}
1449
1450/* Duplicate a file descriptor. The new file descriptor is created as
1451   non-inheritable. Return a new file descriptor on success, raise an OSError
1452   exception and return -1 on error.
1453
1454   The GIL is released to call dup(). The caller must hold the GIL. */
1455int
1456_Py_dup(int fd)
1457{
1458#ifdef MS_WINDOWS
1459    HANDLE handle;
1460    DWORD ftype;
1461#endif
1462
1463#ifdef WITH_THREAD
1464    assert(PyGILState_Check());
1465#endif
1466
1467#ifdef MS_WINDOWS
1468    _Py_BEGIN_SUPPRESS_IPH
1469    handle = (HANDLE)_get_osfhandle(fd);
1470    _Py_END_SUPPRESS_IPH
1471    if (handle == INVALID_HANDLE_VALUE) {
1472        PyErr_SetFromErrno(PyExc_OSError);
1473        return -1;
1474    }
1475
1476    /* get the file type, ignore the error if it failed */
1477    ftype = GetFileType(handle);
1478
1479    Py_BEGIN_ALLOW_THREADS
1480    _Py_BEGIN_SUPPRESS_IPH
1481    fd = dup(fd);
1482    _Py_END_SUPPRESS_IPH
1483    Py_END_ALLOW_THREADS
1484    if (fd < 0) {
1485        PyErr_SetFromErrno(PyExc_OSError);
1486        return -1;
1487    }
1488
1489    /* Character files like console cannot be make non-inheritable */
1490    if (ftype != FILE_TYPE_CHAR) {
1491        if (_Py_set_inheritable(fd, 0, NULL) < 0) {
1492            _Py_BEGIN_SUPPRESS_IPH
1493            close(fd);
1494            _Py_END_SUPPRESS_IPH
1495            return -1;
1496        }
1497    }
1498#elif defined(HAVE_FCNTL_H) && defined(F_DUPFD_CLOEXEC)
1499    Py_BEGIN_ALLOW_THREADS
1500    _Py_BEGIN_SUPPRESS_IPH
1501    fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
1502    _Py_END_SUPPRESS_IPH
1503    Py_END_ALLOW_THREADS
1504    if (fd < 0) {
1505        PyErr_SetFromErrno(PyExc_OSError);
1506        return -1;
1507    }
1508
1509#else
1510    Py_BEGIN_ALLOW_THREADS
1511    _Py_BEGIN_SUPPRESS_IPH
1512    fd = dup(fd);
1513    _Py_END_SUPPRESS_IPH
1514    Py_END_ALLOW_THREADS
1515    if (fd < 0) {
1516        PyErr_SetFromErrno(PyExc_OSError);
1517        return -1;
1518    }
1519
1520    if (_Py_set_inheritable(fd, 0, NULL) < 0) {
1521        _Py_BEGIN_SUPPRESS_IPH
1522        close(fd);
1523        _Py_END_SUPPRESS_IPH
1524        return -1;
1525    }
1526#endif
1527    return fd;
1528}
1529
1530#ifndef MS_WINDOWS
1531/* Get the blocking mode of the file descriptor.
1532   Return 0 if the O_NONBLOCK flag is set, 1 if the flag is cleared,
1533   raise an exception and return -1 on error. */
1534int
1535_Py_get_blocking(int fd)
1536{
1537    int flags;
1538    _Py_BEGIN_SUPPRESS_IPH
1539    flags = fcntl(fd, F_GETFL, 0);
1540    _Py_END_SUPPRESS_IPH
1541    if (flags < 0) {
1542        PyErr_SetFromErrno(PyExc_OSError);
1543        return -1;
1544    }
1545
1546    return !(flags & O_NONBLOCK);
1547}
1548
1549/* Set the blocking mode of the specified file descriptor.
1550
1551   Set the O_NONBLOCK flag if blocking is False, clear the O_NONBLOCK flag
1552   otherwise.
1553
1554   Return 0 on success, raise an exception and return -1 on error. */
1555int
1556_Py_set_blocking(int fd, int blocking)
1557{
1558#if defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO)
1559    int arg = !blocking;
1560    if (ioctl(fd, FIONBIO, &arg) < 0)
1561        goto error;
1562#else
1563    int flags, res;
1564
1565    _Py_BEGIN_SUPPRESS_IPH
1566    flags = fcntl(fd, F_GETFL, 0);
1567    if (flags >= 0) {
1568        if (blocking)
1569            flags = flags & (~O_NONBLOCK);
1570        else
1571            flags = flags | O_NONBLOCK;
1572
1573        res = fcntl(fd, F_SETFL, flags);
1574    } else {
1575        res = -1;
1576    }
1577    _Py_END_SUPPRESS_IPH
1578
1579    if (res < 0)
1580        goto error;
1581#endif
1582    return 0;
1583
1584error:
1585    PyErr_SetFromErrno(PyExc_OSError);
1586    return -1;
1587}
1588#endif
1589