Home | History | Annotate | Download | only in Python
      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>
      8 extern 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__)
     24 extern 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(). */
     36 int _Py_open_cloexec_works = -1;
     37 #endif
     38 
     39 PyObject *
     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)
     74 extern 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 */
     99 static int force_ascii = -1;
    100 
    101 static int
    102 check_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 
    179 error:
    180     /* if an error occurred, force the ASCII encoding */
    181     return 1;
    182 }
    183 
    184 static char*
    185 encode_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))
    225 static wchar_t*
    226 decode_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. */
    273 wchar_t*
    274 Py_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;
    405 oom:
    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. */
    424 char*
    425 Py_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
    530 static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */
    531 
    532 static void
    533 FILE_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 
    544 void
    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
    558 static int
    559 attributes_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 
    573 void
    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. */
    609 int
    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. */
    678 int
    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 
    708 int
    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 
    735 static int
    736 get_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. */
    774 int
    775 _Py_get_inheritable(int fd)
    776 {
    777     return get_inheritable(fd, 1);
    778 }
    779 
    780 static int
    781 set_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. */
    901 static int
    902 make_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. */
    924 int
    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 
    930 static 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. */
    988 int
    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. */
   1004 int
   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. */
   1016 FILE *
   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. */
   1051 FILE*
   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. */
   1077 FILE*
   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. */
   1162 Py_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 
   1224 static 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. */
   1307 Py_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. */
   1329 Py_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 
   1340 int
   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 
   1385 wchar_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 
   1424 wchar_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. */
   1455 int
   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. */
   1534 int
   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. */
   1555 int
   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 
   1584 error:
   1585     PyErr_SetFromErrno(PyExc_OSError);
   1586     return -1;
   1587 }
   1588 #endif
   1589