LCOV - code coverage report
Current view: | top level - Python - fileutils.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 317 | 723 | 43.8 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 36 | 55 | 65.5 %
|  |  | Branches: | 151 | 493 | 30.6 %

               Branch data     Line data    Source code
           1                 :            : #include "Python.h"
           2                 :            : #include "pycore_fileutils.h"     // fileutils definitions
           3                 :            : #include "pycore_runtime.h"       // _PyRuntime
           4                 :            : #include "osdefs.h"               // SEP
           5                 :            : #include <locale.h>
           6                 :            : #include <stdlib.h>               // mbstowcs()
           7                 :            :
           8                 :            : #ifdef MS_WINDOWS
           9                 :            : #  include <malloc.h>
          10                 :            : #  include <windows.h>
          11                 :            : #  include <winioctl.h>             // FILE_DEVICE_* constants
          12                 :            : #  include "pycore_fileutils_windows.h" // FILE_STAT_BASIC_INFORMATION
          13                 :            : #  if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP)
          14                 :            : #    define PATHCCH_ALLOW_LONG_PATHS 0x01
          15                 :            : #  else
          16                 :            : #    include <pathcch.h>            // PathCchCombineEx
          17                 :            : #  endif
          18                 :            : extern int winerror_to_errno(int);
          19                 :            : #endif
          20                 :            :
          21                 :            : #ifdef HAVE_LANGINFO_H
          22                 :            : #include <langinfo.h>
          23                 :            : #endif
          24                 :            :
          25                 :            : #ifdef HAVE_SYS_IOCTL_H
          26                 :            : #include <sys/ioctl.h>
          27                 :            : #endif
          28                 :            :
          29                 :            : #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION
          30                 :            : #include <iconv.h>
          31                 :            : #endif
          32                 :            :
          33                 :            : #ifdef HAVE_FCNTL_H
          34                 :            : #include <fcntl.h>
          35                 :            : #endif /* HAVE_FCNTL_H */
          36                 :            :
          37                 :            : #ifdef O_CLOEXEC
          38                 :            : /* Does open() support the O_CLOEXEC flag? Possible values:
          39                 :            :
          40                 :            :    -1: unknown
          41                 :            :     0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23
          42                 :            :     1: open() supports O_CLOEXEC flag, close-on-exec is set
          43                 :            :
          44                 :            :    The flag is used by _Py_open(), _Py_open_noraise(), io.FileIO
          45                 :            :    and os.open(). */
          46                 :            : int _Py_open_cloexec_works = -1;
          47                 :            : #endif
          48                 :            :
          49                 :            : // The value must be the same in unicodeobject.c.
          50                 :            : #define MAX_UNICODE 0x10ffff
          51                 :            :
          52                 :            : // mbstowcs() and mbrtowc() errors
          53                 :            : static const size_t DECODE_ERROR = ((size_t)-1);
          54                 :            : static const size_t INCOMPLETE_CHARACTER = (size_t)-2;
          55                 :            :
          56                 :            :
          57                 :            : static int
          58                 :      10406 : get_surrogateescape(_Py_error_handler errors, int *surrogateescape)
          59                 :            : {
          60      [ +  +  - ]:      10406 :     switch (errors)
          61                 :            :     {
          62                 :         28 :     case _Py_ERROR_STRICT:
          63                 :         28 :         *surrogateescape = 0;
          64                 :         28 :         return 0;
          65                 :      10378 :     case _Py_ERROR_SURROGATEESCAPE:
          66                 :      10378 :         *surrogateescape = 1;
          67                 :      10378 :         return 0;
          68                 :          0 :     default:
          69                 :          0 :         return -1;
          70                 :            :     }
          71                 :            : }
          72                 :            :
          73                 :            :
          74                 :            : PyObject *
          75                 :          0 : _Py_device_encoding(int fd)
          76                 :            : {
          77                 :            :     int valid;
          78                 :          0 :     Py_BEGIN_ALLOW_THREADS
          79                 :            :     _Py_BEGIN_SUPPRESS_IPH
          80                 :          0 :     valid = isatty(fd);
          81                 :            :     _Py_END_SUPPRESS_IPH
          82                 :          0 :     Py_END_ALLOW_THREADS
          83         [ #  # ]:          0 :     if (!valid)
          84                 :          0 :         Py_RETURN_NONE;
          85                 :            :
          86                 :            : #ifdef MS_WINDOWS
          87                 :            : #ifdef HAVE_WINDOWS_CONSOLE_IO
          88                 :            :     UINT cp;
          89                 :            :     if (fd == 0)
          90                 :            :         cp = GetConsoleCP();
          91                 :            :     else if (fd == 1 || fd == 2)
          92                 :            :         cp = GetConsoleOutputCP();
          93                 :            :     else
          94                 :            :         cp = 0;
          95                 :            :     /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application
          96                 :            :        has no console */
          97                 :            :     if (cp == 0) {
          98                 :            :         Py_RETURN_NONE;
          99                 :            :     }
         100                 :            :
         101                 :            :     return PyUnicode_FromFormat("cp%u", (unsigned int)cp);
         102                 :            : #else
         103                 :            :     Py_RETURN_NONE;
         104                 :            : #endif /* HAVE_WINDOWS_CONSOLE_IO */
         105                 :            : #else
         106         [ #  # ]:          0 :     if (_PyRuntime.preconfig.utf8_mode) {
         107                 :            :         _Py_DECLARE_STR(utf_8, "utf-8");
         108                 :          0 :         return Py_NewRef(&_Py_STR(utf_8));
         109                 :            :     }
         110                 :          0 :     return _Py_GetLocaleEncodingObject();
         111                 :            : #endif
         112                 :            : }
         113                 :            :
         114                 :            :
         115                 :            : static size_t
         116                 :     112679 : is_valid_wide_char(wchar_t ch)
         117                 :            : {
         118                 :            : #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION
         119                 :            :     /* Oracle Solaris doesn't use Unicode code points as wchar_t encoding
         120                 :            :        for non-Unicode locales, which makes values higher than MAX_UNICODE
         121                 :            :        possibly valid. */
         122                 :            :     return 1;
         123                 :            : #endif
         124         [ -  + ]:     112679 :     if (Py_UNICODE_IS_SURROGATE(ch)) {
         125                 :            :         // Reject lone surrogate characters
         126                 :          0 :         return 0;
         127                 :            :     }
         128         [ -  + ]:     112679 :     if (ch > MAX_UNICODE) {
         129                 :            :         // bpo-35883: Reject characters outside [U+0000; U+10ffff] range.
         130                 :            :         // The glibc mbstowcs() UTF-8 decoder does not respect the RFC 3629,
         131                 :            :         // it creates characters outside the [U+0000; U+10ffff] range:
         132                 :            :         // https://sourceware.org/bugzilla/show_bug.cgi?id=2373
         133                 :          0 :         return 0;
         134                 :            :     }
         135                 :     112679 :     return 1;
         136                 :            : }
         137                 :            :
         138                 :            :
         139                 :            : static size_t
         140                 :      22106 : _Py_mbstowcs(wchar_t *dest, const char *src, size_t n)
         141                 :            : {
         142                 :      22106 :     size_t count = mbstowcs(dest, src, n);
         143   [ +  +  +  + ]:      22106 :     if (dest != NULL && count != DECODE_ERROR) {
         144         [ +  + ]:     122132 :         for (size_t i=0; i < count; i++) {
         145                 :     112679 :             wchar_t ch = dest[i];
         146         [ -  + ]:     112679 :             if (!is_valid_wide_char(ch)) {
         147                 :          0 :                 return DECODE_ERROR;
         148                 :            :             }
         149                 :            :         }
         150                 :            :     }
         151                 :      22106 :     return count;
         152                 :            : }
         153                 :            :
         154                 :            :
         155                 :            : #ifdef HAVE_MBRTOWC
         156                 :            : static size_t
         157                 :          0 : _Py_mbrtowc(wchar_t *pwc, const char *str, size_t len, mbstate_t *pmbs)
         158                 :            : {
         159                 :            :     assert(pwc != NULL);
         160                 :          0 :     size_t count = mbrtowc(pwc, str, len, pmbs);
         161   [ #  #  #  #  :          0 :     if (count != 0 && count != DECODE_ERROR && count != INCOMPLETE_CHARACTER) {
                       #  # ]
         162         [ #  # ]:          0 :         if (!is_valid_wide_char(*pwc)) {
         163                 :          0 :             return DECODE_ERROR;
         164                 :            :         }
         165                 :            :     }
         166                 :          0 :     return count;
         167                 :            : }
         168                 :            : #endif
         169                 :            :
         170                 :            :
         171                 :            : #if !defined(_Py_FORCE_UTF8_FS_ENCODING) && !defined(MS_WINDOWS)
         172                 :            :
         173                 :            : #define USE_FORCE_ASCII
         174                 :            :
         175                 :            : extern int _Py_normalize_encoding(const char *, char *, size_t);
         176                 :            :
         177                 :            : /* Workaround FreeBSD and OpenIndiana locale encoding issue with the C locale
         178                 :            :    and POSIX locale. nl_langinfo(CODESET) announces an alias of the
         179                 :            :    ASCII encoding, whereas mbstowcs() and wcstombs() functions use the
         180                 :            :    ISO-8859-1 encoding. The problem is that os.fsencode() and os.fsdecode() use
         181                 :            :    locale.getpreferredencoding() codec. For example, if command line arguments
         182                 :            :    are decoded by mbstowcs() and encoded back by os.fsencode(), we get a
         183                 :            :    UnicodeEncodeError instead of retrieving the original byte string.
         184                 :            :
         185                 :            :    The workaround is enabled if setlocale(LC_CTYPE, NULL) returns "C",
         186                 :            :    nl_langinfo(CODESET) announces "ascii" (or an alias to ASCII), and at least
         187                 :            :    one byte in range 0x80-0xff can be decoded from the locale encoding. The
         188                 :            :    workaround is also enabled on error, for example if getting the locale
         189                 :            :    failed.
         190                 :            :
         191                 :            :    On HP-UX with the C locale or the POSIX locale, nl_langinfo(CODESET)
         192                 :            :    announces "roman8" but mbstowcs() uses Latin1 in practice. Force also the
         193                 :            :    ASCII encoding in this case.
         194                 :            :
         195                 :            :    Values of force_ascii:
         196                 :            :
         197                 :            :        1: the workaround is used: Py_EncodeLocale() uses
         198                 :            :           encode_ascii_surrogateescape() and Py_DecodeLocale() uses
         199                 :            :           decode_ascii()
         200                 :            :        0: the workaround is not used: Py_EncodeLocale() uses wcstombs() and
         201                 :            :           Py_DecodeLocale() uses mbstowcs()
         202                 :            :       -1: unknown, need to call check_force_ascii() to get the value
         203                 :            : */
         204                 :            : #define force_ascii (_PyRuntime.fileutils.force_ascii)
         205                 :            :
         206                 :            : static int
         207                 :         33 : check_force_ascii(void)
         208                 :            : {
         209                 :         33 :     char *loc = setlocale(LC_CTYPE, NULL);
         210         [ -  + ]:         33 :     if (loc == NULL) {
         211                 :          0 :         goto error;
         212                 :            :     }
         213   [ +  +  +  - ]:         33 :     if (strcmp(loc, "C") != 0 && strcmp(loc, "POSIX") != 0) {
         214                 :            :         /* the LC_CTYPE locale is different than C and POSIX */
         215                 :          8 :         return 0;
         216                 :            :     }
         217                 :            :
         218                 :            : #if defined(HAVE_LANGINFO_H) && defined(CODESET)
         219                 :         25 :     const char *codeset = nl_langinfo(CODESET);
         220   [ +  -  -  + ]:         25 :     if (!codeset || codeset[0] == '\0') {
         221                 :            :         /* CODESET is not set or empty */
         222                 :          0 :         goto error;
         223                 :            :     }
         224                 :            :
         225                 :            :     char encoding[20];   /* longest name: "iso_646.irv_1991\0" */
         226         [ -  + ]:         25 :     if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding))) {
         227                 :          0 :         goto error;
         228                 :            :     }
         229                 :            :
         230                 :            : #ifdef __hpux
         231                 :            :     if (strcmp(encoding, "roman8") == 0) {
         232                 :            :         unsigned char ch;
         233                 :            :         wchar_t wch;
         234                 :            :         size_t res;
         235                 :            :
         236                 :            :         ch = (unsigned char)0xA7;
         237                 :            :         res = _Py_mbstowcs(&wch, (char*)&ch, 1);
         238                 :            :         if (res != DECODE_ERROR && wch == L'\xA7') {
         239                 :            :             /* On HP-UX with C locale or the POSIX locale,
         240                 :            :                nl_langinfo(CODESET) announces "roman8", whereas mbstowcs() uses
         241                 :            :                Latin1 encoding in practice. Force ASCII in this case.
         242                 :            :
         243                 :            :                Roman8 decodes 0xA7 to U+00CF. Latin1 decodes 0xA7 to U+00A7. */
         244                 :            :             return 1;
         245                 :            :         }
         246                 :            :     }
         247                 :            : #else
         248                 :         25 :     const char* ascii_aliases[] = {
         249                 :            :         "ascii",
         250                 :            :         /* Aliases from Lib/encodings/aliases.py */
         251                 :            :         "646",
         252                 :            :         "ansi_x3.4_1968",
         253                 :            :         "ansi_x3.4_1986",
         254                 :            :         "ansi_x3_4_1968",
         255                 :            :         "cp367",
         256                 :            :         "csascii",
         257                 :            :         "ibm367",
         258                 :            :         "iso646_us",
         259                 :            :         "iso_646.irv_1991",
         260                 :            :         "iso_ir_6",
         261                 :            :         "us",
         262                 :            :         "us_ascii",
         263                 :            :         NULL
         264                 :            :     };
         265                 :            :
         266                 :         25 :     int is_ascii = 0;
         267         [ +  - ]:         75 :     for (const char **alias=ascii_aliases; *alias != NULL; alias++) {
         268         [ +  + ]:         75 :         if (strcmp(encoding, *alias) == 0) {
         269                 :         25 :             is_ascii = 1;
         270                 :         25 :             break;
         271                 :            :         }
         272                 :            :     }
         273         [ -  + ]:         25 :     if (!is_ascii) {
         274                 :            :         /* nl_langinfo(CODESET) is not "ascii" or an alias of ASCII */
         275                 :          0 :         return 0;
         276                 :            :     }
         277                 :            :
         278         [ +  + ]:       3225 :     for (unsigned int i=0x80; i<=0xff; i++) {
         279                 :            :         char ch[1];
         280                 :            :         wchar_t wch[1];
         281                 :            :         size_t res;
         282                 :            :
         283                 :       3200 :         unsigned uch = (unsigned char)i;
         284                 :       3200 :         ch[0] = (char)uch;
         285                 :       3200 :         res = _Py_mbstowcs(wch, ch, 1);
         286         [ -  + ]:       3200 :         if (res != DECODE_ERROR) {
         287                 :            :             /* decoding a non-ASCII character from the locale encoding succeed:
         288                 :            :                the locale encoding is not ASCII, force ASCII */
         289                 :          0 :             return 1;
         290                 :            :         }
         291                 :            :     }
         292                 :            :     /* None of the bytes in the range 0x80-0xff can be decoded from the locale
         293                 :            :        encoding: the locale encoding is really ASCII */
         294                 :            : #endif   /* !defined(__hpux) */
         295                 :         25 :     return 0;
         296                 :            : #else
         297                 :            :     /* nl_langinfo(CODESET) is not available: always force ASCII */
         298                 :            :     return 1;
         299                 :            : #endif   /* defined(HAVE_LANGINFO_H) && defined(CODESET) */
         300                 :            :
         301                 :          0 : error:
         302                 :            :     /* if an error occurred, force the ASCII encoding */
         303                 :          0 :     return 1;
         304                 :            : }
         305                 :            :
         306                 :            :
         307                 :            : int
         308                 :         29 : _Py_GetForceASCII(void)
         309                 :            : {
         310         [ +  + ]:         29 :     if (force_ascii == -1) {
         311                 :          4 :         force_ascii = check_force_ascii();
         312                 :            :     }
         313                 :         29 :     return force_ascii;
         314                 :            : }
         315                 :            :
         316                 :            :
         317                 :            : void
         318                 :          8 : _Py_ResetForceASCII(void)
         319                 :            : {
         320                 :          8 :     force_ascii = -1;
         321                 :          8 : }
         322                 :            :
         323                 :            :
         324                 :            : static int
         325                 :          0 : encode_ascii(const wchar_t *text, char **str,
         326                 :            :              size_t *error_pos, const char **reason,
         327                 :            :              int raw_malloc, _Py_error_handler errors)
         328                 :            : {
         329                 :          0 :     char *result = NULL, *out;
         330                 :            :     size_t len, i;
         331                 :            :     wchar_t ch;
         332                 :            :
         333                 :            :     int surrogateescape;
         334         [ #  # ]:          0 :     if (get_surrogateescape(errors, &surrogateescape) < 0) {
         335                 :          0 :         return -3;
         336                 :            :     }
         337                 :            :
         338                 :          0 :     len = wcslen(text);
         339                 :            :
         340                 :            :     /* +1 for NULL byte */
         341         [ #  # ]:          0 :     if (raw_malloc) {
         342                 :          0 :         result = PyMem_RawMalloc(len + 1);
         343                 :            :     }
         344                 :            :     else {
         345                 :          0 :         result = PyMem_Malloc(len + 1);
         346                 :            :     }
         347         [ #  # ]:          0 :     if (result == NULL) {
         348                 :          0 :         return -1;
         349                 :            :     }
         350                 :            :
         351                 :          0 :     out = result;
         352         [ #  # ]:          0 :     for (i=0; i<len; i++) {
         353                 :          0 :         ch = text[i];
         354                 :            :
         355         [ #  # ]:          0 :         if (ch <= 0x7f) {
         356                 :            :             /* ASCII character */
         357                 :          0 :             *out++ = (char)ch;
         358                 :            :         }
         359   [ #  #  #  #  :          0 :         else if (surrogateescape && 0xdc80 <= ch && ch <= 0xdcff) {
                       #  # ]
         360                 :            :             /* UTF-8b surrogate */
         361                 :          0 :             *out++ = (char)(ch - 0xdc00);
         362                 :            :         }
         363                 :            :         else {
         364         [ #  # ]:          0 :             if (raw_malloc) {
         365                 :          0 :                 PyMem_RawFree(result);
         366                 :            :             }
         367                 :            :             else {
         368                 :          0 :                 PyMem_Free(result);
         369                 :            :             }
         370         [ #  # ]:          0 :             if (error_pos != NULL) {
         371                 :          0 :                 *error_pos = i;
         372                 :            :             }
         373         [ #  # ]:          0 :             if (reason) {
         374                 :          0 :                 *reason = "encoding error";
         375                 :            :             }
         376                 :          0 :             return -2;
         377                 :            :         }
         378                 :            :     }
         379                 :          0 :     *out = '\0';
         380                 :          0 :     *str = result;
         381                 :          0 :     return 0;
         382                 :            : }
         383                 :            : #else
         384                 :            : int
         385                 :            : _Py_GetForceASCII(void)
         386                 :            : {
         387                 :            :     return 0;
         388                 :            : }
         389                 :            :
         390                 :            : void
         391                 :            : _Py_ResetForceASCII(void)
         392                 :            : {
         393                 :            :     /* nothing to do */
         394                 :            : }
         395                 :            : #endif   /* !defined(_Py_FORCE_UTF8_FS_ENCODING) && !defined(MS_WINDOWS) */
         396                 :            :
         397                 :            :
         398                 :            : #if !defined(HAVE_MBRTOWC) || defined(USE_FORCE_ASCII)
         399                 :            : static int
         400                 :          0 : decode_ascii(const char *arg, wchar_t **wstr, size_t *wlen,
         401                 :            :              const char **reason, _Py_error_handler errors)
         402                 :            : {
         403                 :            :     wchar_t *res;
         404                 :            :     unsigned char *in;
         405                 :            :     wchar_t *out;
         406                 :          0 :     size_t argsize = strlen(arg) + 1;
         407                 :            :
         408                 :            :     int surrogateescape;
         409         [ #  # ]:          0 :     if (get_surrogateescape(errors, &surrogateescape) < 0) {
         410                 :          0 :         return -3;
         411                 :            :     }
         412                 :            :
         413         [ #  # ]:          0 :     if (argsize > PY_SSIZE_T_MAX / sizeof(wchar_t)) {
         414                 :          0 :         return -1;
         415                 :            :     }
         416                 :          0 :     res = PyMem_RawMalloc(argsize * sizeof(wchar_t));
         417         [ #  # ]:          0 :     if (!res) {
         418                 :          0 :         return -1;
         419                 :            :     }
         420                 :            :
         421                 :          0 :     out = res;
         422         [ #  # ]:          0 :     for (in = (unsigned char*)arg; *in; in++) {
         423                 :          0 :         unsigned char ch = *in;
         424         [ #  # ]:          0 :         if (ch < 128) {
         425                 :          0 :             *out++ = ch;
         426                 :            :         }
         427                 :            :         else {
         428         [ #  # ]:          0 :             if (!surrogateescape) {
         429                 :          0 :                 PyMem_RawFree(res);
         430         [ #  # ]:          0 :                 if (wlen) {
         431                 :          0 :                     *wlen = in - (unsigned char*)arg;
         432                 :            :                 }
         433         [ #  # ]:          0 :                 if (reason) {
         434                 :          0 :                     *reason = "decoding error";
         435                 :            :                 }
         436                 :          0 :                 return -2;
         437                 :            :             }
         438                 :          0 :             *out++ = 0xdc00 + ch;
         439                 :            :         }
         440                 :            :     }
         441                 :          0 :     *out = 0;
         442                 :            :
         443         [ #  # ]:          0 :     if (wlen != NULL) {
         444                 :          0 :         *wlen = out - res;
         445                 :            :     }
         446                 :          0 :     *wstr = res;
         447                 :          0 :     return 0;
         448                 :            : }
         449                 :            : #endif   /* !HAVE_MBRTOWC */
         450                 :            :
         451                 :            : static int
         452                 :       9453 : decode_current_locale(const char* arg, wchar_t **wstr, size_t *wlen,
         453                 :            :                       const char **reason, _Py_error_handler errors)
         454                 :            : {
         455                 :            :     wchar_t *res;
         456                 :            :     size_t argsize;
         457                 :            :     size_t count;
         458                 :            : #ifdef HAVE_MBRTOWC
         459                 :            :     unsigned char *in;
         460                 :            :     wchar_t *out;
         461                 :            :     mbstate_t mbs;
         462                 :            : #endif
         463                 :            :
         464                 :            :     int surrogateescape;
         465         [ -  + ]:       9453 :     if (get_surrogateescape(errors, &surrogateescape) < 0) {
         466                 :          0 :         return -3;
         467                 :            :     }
         468                 :            :
         469                 :            : #ifdef HAVE_BROKEN_MBSTOWCS
         470                 :            :     /* Some platforms have a broken implementation of
         471                 :            :      * mbstowcs which does not count the characters that
         472                 :            :      * would result from conversion.  Use an upper bound.
         473                 :            :      */
         474                 :            :     argsize = strlen(arg);
         475                 :            : #else
         476                 :       9453 :     argsize = _Py_mbstowcs(NULL, arg, 0);
         477                 :            : #endif
         478         [ +  - ]:       9453 :     if (argsize != DECODE_ERROR) {
         479         [ -  + ]:       9453 :         if (argsize > PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) {
         480                 :          0 :             return -1;
         481                 :            :         }
         482                 :       9453 :         res = (wchar_t *)PyMem_RawMalloc((argsize + 1) * sizeof(wchar_t));
         483         [ -  + ]:       9453 :         if (!res) {
         484                 :          0 :             return -1;
         485                 :            :         }
         486                 :            :
         487                 :       9453 :         count = _Py_mbstowcs(res, arg, argsize + 1);
         488         [ +  - ]:       9453 :         if (count != DECODE_ERROR) {
         489                 :       9453 :             *wstr = res;
         490         [ +  + ]:       9453 :             if (wlen != NULL) {
         491                 :       9375 :                 *wlen = count;
         492                 :            :             }
         493                 :       9453 :             return 0;
         494                 :            :         }
         495                 :          0 :         PyMem_RawFree(res);
         496                 :            :     }
         497                 :            :
         498                 :            :     /* Conversion failed. Fall back to escaping with surrogateescape. */
         499                 :            : #ifdef HAVE_MBRTOWC
         500                 :            :     /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
         501                 :            :
         502                 :            :     /* Overallocate; as multi-byte characters are in the argument, the
         503                 :            :        actual output could use less memory. */
         504                 :          0 :     argsize = strlen(arg) + 1;
         505         [ #  # ]:          0 :     if (argsize > PY_SSIZE_T_MAX / sizeof(wchar_t)) {
         506                 :          0 :         return -1;
         507                 :            :     }
         508                 :          0 :     res = (wchar_t*)PyMem_RawMalloc(argsize * sizeof(wchar_t));
         509         [ #  # ]:          0 :     if (!res) {
         510                 :          0 :         return -1;
         511                 :            :     }
         512                 :            :
         513                 :          0 :     in = (unsigned char*)arg;
         514                 :          0 :     out = res;
         515                 :          0 :     memset(&mbs, 0, sizeof mbs);
         516         [ #  # ]:          0 :     while (argsize) {
         517                 :          0 :         size_t converted = _Py_mbrtowc(out, (char*)in, argsize, &mbs);
         518         [ #  # ]:          0 :         if (converted == 0) {
         519                 :            :             /* Reached end of string; null char stored. */
         520                 :          0 :             break;
         521                 :            :         }
         522                 :            :
         523         [ #  # ]:          0 :         if (converted == INCOMPLETE_CHARACTER) {
         524                 :            :             /* Incomplete character. This should never happen,
         525                 :            :                since we provide everything that we have -
         526                 :            :                unless there is a bug in the C library, or I
         527                 :            :                misunderstood how mbrtowc works. */
         528                 :          0 :             goto decode_error;
         529                 :            :         }
         530                 :            :
         531         [ #  # ]:          0 :         if (converted == DECODE_ERROR) {
         532         [ #  # ]:          0 :             if (!surrogateescape) {
         533                 :          0 :                 goto decode_error;
         534                 :            :             }
         535                 :            :
         536                 :            :             /* Decoding error. Escape as UTF-8b, and start over in the initial
         537                 :            :                shift state. */
         538                 :          0 :             *out++ = 0xdc00 + *in++;
         539                 :          0 :             argsize--;
         540                 :          0 :             memset(&mbs, 0, sizeof mbs);
         541                 :          0 :             continue;
         542                 :            :         }
         543                 :            :
         544                 :            :         // _Py_mbrtowc() reject lone surrogate characters
         545                 :            :         assert(!Py_UNICODE_IS_SURROGATE(*out));
         546                 :            :
         547                 :            :         /* successfully converted some bytes */
         548                 :          0 :         in += converted;
         549                 :          0 :         argsize -= converted;
         550                 :          0 :         out++;
         551                 :            :     }
         552         [ #  # ]:          0 :     if (wlen != NULL) {
         553                 :          0 :         *wlen = out - res;
         554                 :            :     }
         555                 :          0 :     *wstr = res;
         556                 :          0 :     return 0;
         557                 :            :
         558                 :          0 : decode_error:
         559                 :          0 :     PyMem_RawFree(res);
         560         [ #  # ]:          0 :     if (wlen) {
         561                 :          0 :         *wlen = in - (unsigned char*)arg;
         562                 :            :     }
         563         [ #  # ]:          0 :     if (reason) {
         564                 :          0 :         *reason = "decoding error";
         565                 :            :     }
         566                 :          0 :     return -2;
         567                 :            : #else   /* HAVE_MBRTOWC */
         568                 :            :     /* Cannot use C locale for escaping; manually escape as if charset
         569                 :            :        is ASCII (i.e. escape all bytes > 128. This will still roundtrip
         570                 :            :        correctly in the locale's charset, which must be an ASCII superset. */
         571                 :            :     return decode_ascii(arg, wstr, wlen, reason, errors);
         572                 :            : #endif   /* HAVE_MBRTOWC */
         573                 :            : }
         574                 :            :
         575                 :            :
         576                 :            : /* Decode a byte string from the locale encoding.
         577                 :            :
         578                 :            :    Use the strict error handler if 'surrogateescape' is zero.  Use the
         579                 :            :    surrogateescape error handler if 'surrogateescape' is non-zero: undecodable
         580                 :            :    bytes are decoded as characters in range U+DC80..U+DCFF. If a byte sequence
         581                 :            :    can be decoded as a surrogate character, escape the bytes using the
         582                 :            :    surrogateescape error handler instead of decoding them.
         583                 :            :
         584                 :            :    On success, return 0 and write the newly allocated wide character string into
         585                 :            :    *wstr (use PyMem_RawFree() to free the memory). If wlen is not NULL, write
         586                 :            :    the number of wide characters excluding the null character into *wlen.
         587                 :            :
         588                 :            :    On memory allocation failure, return -1.
         589                 :            :
         590                 :            :    On decoding error, return -2. If wlen is not NULL, write the start of
         591                 :            :    invalid byte sequence in the input string into *wlen. If reason is not NULL,
         592                 :            :    write the decoding error message into *reason.
         593                 :            :
         594                 :            :    Return -3 if the error handler 'errors' is not supported.
         595                 :            :
         596                 :            :    Use the Py_EncodeLocaleEx() function to encode the character string back to
         597                 :            :    a byte string. */
         598                 :            : int
         599                 :       9375 : _Py_DecodeLocaleEx(const char* arg, wchar_t **wstr, size_t *wlen,
         600                 :            :                    const char **reason,
         601                 :            :                    int current_locale, _Py_error_handler errors)
         602                 :            : {
         603         [ +  + ]:       9375 :     if (current_locale) {
         604                 :            : #ifdef _Py_FORCE_UTF8_LOCALE
         605                 :            :         return _Py_DecodeUTF8Ex(arg, strlen(arg), wstr, wlen, reason,
         606                 :            :                                 errors);
         607                 :            : #else
         608                 :        809 :         return decode_current_locale(arg, wstr, wlen, reason, errors);
         609                 :            : #endif
         610                 :            :     }
         611                 :            :
         612                 :            : #ifdef _Py_FORCE_UTF8_FS_ENCODING
         613                 :            :     return _Py_DecodeUTF8Ex(arg, strlen(arg), wstr, wlen, reason,
         614                 :            :                             errors);
         615                 :            : #else
         616                 :       8566 :     int use_utf8 = (_PyRuntime.preconfig.utf8_mode >= 1);
         617                 :            : #ifdef MS_WINDOWS
         618                 :            :     use_utf8 |= (_PyRuntime.preconfig.legacy_windows_fs_encoding == 0);
         619                 :            : #endif
         620         [ -  + ]:       8566 :     if (use_utf8) {
         621                 :          0 :         return _Py_DecodeUTF8Ex(arg, strlen(arg), wstr, wlen, reason,
         622                 :            :                                 errors);
         623                 :            :     }
         624                 :            :
         625                 :            : #ifdef USE_FORCE_ASCII
         626         [ +  + ]:       8566 :     if (force_ascii == -1) {
         627                 :         29 :         force_ascii = check_force_ascii();
         628                 :            :     }
         629                 :            :
         630         [ -  + ]:       8566 :     if (force_ascii) {
         631                 :            :         /* force ASCII encoding to workaround mbstowcs() issue */
         632                 :          0 :         return decode_ascii(arg, wstr, wlen, reason, errors);
         633                 :            :     }
         634                 :            : #endif
         635                 :            :
         636                 :       8566 :     return decode_current_locale(arg, wstr, wlen, reason, errors);
         637                 :            : #endif   /* !_Py_FORCE_UTF8_FS_ENCODING */
         638                 :            : }
         639                 :            :
         640                 :            :
         641                 :            : /* Decode a byte string from the locale encoding with the
         642                 :            :    surrogateescape error handler: undecodable bytes are decoded as characters
         643                 :            :    in range U+DC80..U+DCFF. If a byte sequence can be decoded as a surrogate
         644                 :            :    character, escape the bytes using the surrogateescape error handler instead
         645                 :            :    of decoding them.
         646                 :            :
         647                 :            :    Return a pointer to a newly allocated wide character string, use
         648                 :            :    PyMem_RawFree() to free the memory. If size is not NULL, write the number of
         649                 :            :    wide characters excluding the null character into *size
         650                 :            :
         651                 :            :    Return NULL on decoding error or memory allocation error. If *size* is not
         652                 :            :    NULL, *size is set to (size_t)-1 on memory error or set to (size_t)-2 on
         653                 :            :    decoding error.
         654                 :            :
         655                 :            :    Decoding errors should never happen, unless there is a bug in the C
         656                 :            :    library.
         657                 :            :
         658                 :            :    Use the Py_EncodeLocale() function to encode the character string back to a
         659                 :            :    byte string. */
         660                 :            : wchar_t*
         661                 :        484 : Py_DecodeLocale(const char* arg, size_t *wlen)
         662                 :            : {
         663                 :            :     wchar_t *wstr;
         664                 :        484 :     int res = _Py_DecodeLocaleEx(arg, &wstr, wlen,
         665                 :            :                                  NULL, 0,
         666                 :            :                                  _Py_ERROR_SURROGATEESCAPE);
         667         [ -  + ]:        484 :     if (res != 0) {
         668                 :            :         assert(res != -3);
         669         [ #  # ]:          0 :         if (wlen != NULL) {
         670                 :          0 :             *wlen = (size_t)res;
         671                 :            :         }
         672                 :          0 :         return NULL;
         673                 :            :     }
         674                 :        484 :     return wstr;
         675                 :            : }
         676                 :            :
         677                 :            :
         678                 :            : static int
         679                 :        953 : encode_current_locale(const wchar_t *text, char **str,
         680                 :            :                       size_t *error_pos, const char **reason,
         681                 :            :                       int raw_malloc, _Py_error_handler errors)
         682                 :            : {
         683                 :        953 :     const size_t len = wcslen(text);
         684                 :        953 :     char *result = NULL, *bytes = NULL;
         685                 :            :     size_t i, size, converted;
         686                 :            :     wchar_t c, buf[2];
         687                 :            :
         688                 :            :     int surrogateescape;
         689         [ -  + ]:        953 :     if (get_surrogateescape(errors, &surrogateescape) < 0) {
         690                 :          0 :         return -3;
         691                 :            :     }
         692                 :            :
         693                 :            :     /* The function works in two steps:
         694                 :            :        1. compute the length of the output buffer in bytes (size)
         695                 :            :        2. outputs the bytes */
         696                 :        953 :     size = 0;
         697                 :        953 :     buf[1] = 0;
         698                 :            :     while (1) {
         699         [ +  + ]:      76794 :         for (i=0; i < len; i++) {
         700                 :      74888 :             c = text[i];
         701   [ -  +  -  - ]:      74888 :             if (c >= 0xdc80 && c <= 0xdcff) {
         702         [ #  # ]:          0 :                 if (!surrogateescape) {
         703                 :          0 :                     goto encode_error;
         704                 :            :                 }
         705                 :            :                 /* UTF-8b surrogate */
         706         [ #  # ]:          0 :                 if (bytes != NULL) {
         707                 :          0 :                     *bytes++ = c - 0xdc00;
         708                 :          0 :                     size--;
         709                 :            :                 }
         710                 :            :                 else {
         711                 :          0 :                     size++;
         712                 :            :                 }
         713                 :          0 :                 continue;
         714                 :            :             }
         715                 :            :             else {
         716                 :      74888 :                 buf[0] = c;
         717         [ +  + ]:      74888 :                 if (bytes != NULL) {
         718                 :      37444 :                     converted = wcstombs(bytes, buf, size);
         719                 :            :                 }
         720                 :            :                 else {
         721                 :      37444 :                     converted = wcstombs(NULL, buf, 0);
         722                 :            :                 }
         723         [ -  + ]:      74888 :                 if (converted == DECODE_ERROR) {
         724                 :          0 :                     goto encode_error;
         725                 :            :                 }
         726         [ +  + ]:      74888 :                 if (bytes != NULL) {
         727                 :      37444 :                     bytes += converted;
         728                 :      37444 :                     size -= converted;
         729                 :            :                 }
         730                 :            :                 else {
         731                 :      37444 :                     size += converted;
         732                 :            :                 }
         733                 :            :             }
         734                 :            :         }
         735         [ +  + ]:       1906 :         if (result != NULL) {
         736                 :        953 :             *bytes = '\0';
         737                 :        953 :             break;
         738                 :            :         }
         739                 :            :
         740                 :        953 :         size += 1; /* nul byte at the end */
         741         [ +  - ]:        953 :         if (raw_malloc) {
         742                 :        953 :             result = PyMem_RawMalloc(size);
         743                 :            :         }
         744                 :            :         else {
         745                 :          0 :             result = PyMem_Malloc(size);
         746                 :            :         }
         747         [ -  + ]:        953 :         if (result == NULL) {
         748                 :          0 :             return -1;
         749                 :            :         }
         750                 :        953 :         bytes = result;
         751                 :            :     }
         752                 :        953 :     *str = result;
         753                 :        953 :     return 0;
         754                 :            :
         755                 :          0 : encode_error:
         756         [ #  # ]:          0 :     if (raw_malloc) {
         757                 :          0 :         PyMem_RawFree(result);
         758                 :            :     }
         759                 :            :     else {
         760                 :          0 :         PyMem_Free(result);
         761                 :            :     }
         762         [ #  # ]:          0 :     if (error_pos != NULL) {
         763                 :          0 :         *error_pos = i;
         764                 :            :     }
         765         [ #  # ]:          0 :     if (reason) {
         766                 :          0 :         *reason = "encoding error";
         767                 :            :     }
         768                 :          0 :     return -2;
         769                 :            : }
         770                 :            :
         771                 :            :
         772                 :            : /* Encode a string to the locale encoding.
         773                 :            :
         774                 :            :    Parameters:
         775                 :            :
         776                 :            :    * raw_malloc: if non-zero, allocate memory using PyMem_RawMalloc() instead
         777                 :            :      of PyMem_Malloc().
         778                 :            :    * current_locale: if non-zero, use the current LC_CTYPE, otherwise use
         779                 :            :      Python filesystem encoding.
         780                 :            :    * errors: error handler like "strict" or "surrogateescape".
         781                 :            :
         782                 :            :    Return value:
         783                 :            :
         784                 :            :     0: success, *str is set to a newly allocated decoded string.
         785                 :            :    -1: memory allocation failure
         786                 :            :    -2: encoding error, set *error_pos and *reason (if set).
         787                 :            :    -3: the error handler 'errors' is not supported.
         788                 :            :  */
         789                 :            : static int
         790                 :        953 : encode_locale_ex(const wchar_t *text, char **str, size_t *error_pos,
         791                 :            :                  const char **reason,
         792                 :            :                  int raw_malloc, int current_locale, _Py_error_handler errors)
         793                 :            : {
         794         [ +  + ]:        953 :     if (current_locale) {
         795                 :            : #ifdef _Py_FORCE_UTF8_LOCALE
         796                 :            :         return _Py_EncodeUTF8Ex(text, str, error_pos, reason,
         797                 :            :                                 raw_malloc, errors);
         798                 :            : #else
         799                 :          1 :         return encode_current_locale(text, str, error_pos, reason,
         800                 :            :                                      raw_malloc, errors);
         801                 :            : #endif
         802                 :            :     }
         803                 :            :
         804                 :            : #ifdef _Py_FORCE_UTF8_FS_ENCODING
         805                 :            :     return _Py_EncodeUTF8Ex(text, str, error_pos, reason,
         806                 :            :                             raw_malloc, errors);
         807                 :            : #else
         808                 :        952 :     int use_utf8 = (_PyRuntime.preconfig.utf8_mode >= 1);
         809                 :            : #ifdef MS_WINDOWS
         810                 :            :     use_utf8 |= (_PyRuntime.preconfig.legacy_windows_fs_encoding == 0);
         811                 :            : #endif
         812         [ -  + ]:        952 :     if (use_utf8) {
         813                 :          0 :         return _Py_EncodeUTF8Ex(text, str, error_pos, reason,
         814                 :            :                                 raw_malloc, errors);
         815                 :            :     }
         816                 :            :
         817                 :            : #ifdef USE_FORCE_ASCII
         818         [ -  + ]:        952 :     if (force_ascii == -1) {
         819                 :          0 :         force_ascii = check_force_ascii();
         820                 :            :     }
         821                 :            :
         822         [ -  + ]:        952 :     if (force_ascii) {
         823                 :          0 :         return encode_ascii(text, str, error_pos, reason,
         824                 :            :                             raw_malloc, errors);
         825                 :            :     }
         826                 :            : #endif
         827                 :            :
         828                 :        952 :     return encode_current_locale(text, str, error_pos, reason,
         829                 :            :                                  raw_malloc, errors);
         830                 :            : #endif   /* _Py_FORCE_UTF8_FS_ENCODING */
         831                 :            : }
         832                 :            :
         833                 :            : static char*
         834                 :        240 : encode_locale(const wchar_t *text, size_t *error_pos,
         835                 :            :               int raw_malloc, int current_locale)
         836                 :            : {
         837                 :            :     char *str;
         838                 :        240 :     int res = encode_locale_ex(text, &str, error_pos, NULL,
         839                 :            :                                raw_malloc, current_locale,
         840                 :            :                                _Py_ERROR_SURROGATEESCAPE);
         841   [ +  -  -  + ]:        240 :     if (res != -2 && error_pos) {
         842                 :          0 :         *error_pos = (size_t)-1;
         843                 :            :     }
         844         [ -  + ]:        240 :     if (res != 0) {
         845                 :          0 :         return NULL;
         846                 :            :     }
         847                 :        240 :     return str;
         848                 :            : }
         849                 :            :
         850                 :            : /* Encode a wide character string to the locale encoding with the
         851                 :            :    surrogateescape error handler: surrogate characters in the range
         852                 :            :    U+DC80..U+DCFF are converted to bytes 0x80..0xFF.
         853                 :            :
         854                 :            :    Return a pointer to a newly allocated byte string, use PyMem_Free() to free
         855                 :            :    the memory. Return NULL on encoding or memory allocation error.
         856                 :            :
         857                 :            :    If error_pos is not NULL, *error_pos is set to (size_t)-1 on success, or set
         858                 :            :    to the index of the invalid character on encoding error.
         859                 :            :
         860                 :            :    Use the Py_DecodeLocale() function to decode the bytes string back to a wide
         861                 :            :    character string. */
         862                 :            : char*
         863                 :          0 : Py_EncodeLocale(const wchar_t *text, size_t *error_pos)
         864                 :            : {
         865                 :          0 :     return encode_locale(text, error_pos, 0, 0);
         866                 :            : }
         867                 :            :
         868                 :            :
         869                 :            : /* Similar to Py_EncodeLocale(), but result must be freed by PyMem_RawFree()
         870                 :            :    instead of PyMem_Free(). */
         871                 :            : char*
         872                 :        240 : _Py_EncodeLocaleRaw(const wchar_t *text, size_t *error_pos)
         873                 :            : {
         874                 :        240 :     return encode_locale(text, error_pos, 1, 0);
         875                 :            : }
         876                 :            :
         877                 :            :
         878                 :            : int
         879                 :        713 : _Py_EncodeLocaleEx(const wchar_t *text, char **str,
         880                 :            :                    size_t *error_pos, const char **reason,
         881                 :            :                    int current_locale, _Py_error_handler errors)
         882                 :            : {
         883                 :        713 :     return encode_locale_ex(text, str, error_pos, reason, 1,
         884                 :            :                             current_locale, errors);
         885                 :            : }
         886                 :            :
         887                 :            :
         888                 :            : // Get the current locale encoding name:
         889                 :            : //
         890                 :            : // - Return "utf-8" if _Py_FORCE_UTF8_LOCALE macro is defined (ex: on Android)
         891                 :            : // - Return "utf-8" if the UTF-8 Mode is enabled
         892                 :            : // - On Windows, return the ANSI code page (ex: "cp1250")
         893                 :            : // - Return "utf-8" if nl_langinfo(CODESET) returns an empty string.
         894                 :            : // - Otherwise, return nl_langinfo(CODESET).
         895                 :            : //
         896                 :            : // Return NULL on memory allocation failure.
         897                 :            : //
         898                 :            : // See also config_get_locale_encoding()
         899                 :            : wchar_t*
         900                 :         78 : _Py_GetLocaleEncoding(void)
         901                 :            : {
         902                 :            : #ifdef _Py_FORCE_UTF8_LOCALE
         903                 :            :     // On Android langinfo.h and CODESET are missing,
         904                 :            :     // and UTF-8 is always used in mbstowcs() and wcstombs().
         905                 :            :     return _PyMem_RawWcsdup(L"utf-8");
         906                 :            : #else
         907                 :            :
         908                 :            : #ifdef MS_WINDOWS
         909                 :            :     wchar_t encoding[23];
         910                 :            :     unsigned int ansi_codepage = GetACP();
         911                 :            :     swprintf(encoding, Py_ARRAY_LENGTH(encoding), L"cp%u", ansi_codepage);
         912                 :            :     encoding[Py_ARRAY_LENGTH(encoding) - 1] = 0;
         913                 :            :     return _PyMem_RawWcsdup(encoding);
         914                 :            : #else
         915                 :         78 :     const char *encoding = nl_langinfo(CODESET);
         916   [ +  -  -  + ]:         78 :     if (!encoding || encoding[0] == '\0') {
         917                 :            :         // Use UTF-8 if nl_langinfo() returns an empty string. It can happen on
         918                 :            :         // macOS if the LC_CTYPE locale is not supported.
         919                 :          0 :         return _PyMem_RawWcsdup(L"utf-8");
         920                 :            :     }
         921                 :            :
         922                 :            :     wchar_t *wstr;
         923                 :         78 :     int res = decode_current_locale(encoding, &wstr, NULL,
         924                 :            :                                     NULL, _Py_ERROR_SURROGATEESCAPE);
         925         [ -  + ]:         78 :     if (res < 0) {
         926                 :          0 :         return NULL;
         927                 :            :     }
         928                 :         78 :     return wstr;
         929                 :            : #endif  // !MS_WINDOWS
         930                 :            :
         931                 :            : #endif  // !_Py_FORCE_UTF8_LOCALE
         932                 :            : }
         933                 :            :
         934                 :            :
         935                 :            : PyObject *
         936                 :         20 : _Py_GetLocaleEncodingObject(void)
         937                 :            : {
         938                 :         20 :     wchar_t *encoding = _Py_GetLocaleEncoding();
         939         [ -  + ]:         20 :     if (encoding == NULL) {
         940                 :          0 :         PyErr_NoMemory();
         941                 :          0 :         return NULL;
         942                 :            :     }
         943                 :            :
         944                 :         20 :     PyObject *str = PyUnicode_FromWideChar(encoding, -1);
         945                 :         20 :     PyMem_RawFree(encoding);
         946                 :         20 :     return str;
         947                 :            : }
         948                 :            :
         949                 :            : #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION
         950                 :            :
         951                 :            : /* Check whether current locale uses Unicode as internal wchar_t form. */
         952                 :            : int
         953                 :            : _Py_LocaleUsesNonUnicodeWchar(void)
         954                 :            : {
         955                 :            :     /* Oracle Solaris uses non-Unicode internal wchar_t form for
         956                 :            :        non-Unicode locales and hence needs conversion to UTF first. */
         957                 :            :     char* codeset = nl_langinfo(CODESET);
         958                 :            :     if (!codeset) {
         959                 :            :         return 0;
         960                 :            :     }
         961                 :            :     /* 646 refers to ISO/IEC 646 standard that corresponds to ASCII encoding */
         962                 :            :     return (strcmp(codeset, "UTF-8") != 0 && strcmp(codeset, "646") != 0);
         963                 :            : }
         964                 :            :
         965                 :            : static wchar_t *
         966                 :            : _Py_ConvertWCharForm(const wchar_t *source, Py_ssize_t size,
         967                 :            :                      const char *tocode, const char *fromcode)
         968                 :            : {
         969                 :            :     static_assert(sizeof(wchar_t) == 4, "wchar_t must be 32-bit");
         970                 :            :
         971                 :            :     /* Ensure we won't overflow the size. */
         972                 :            :     if (size > (PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(wchar_t))) {
         973                 :            :         PyErr_NoMemory();
         974                 :            :         return NULL;
         975                 :            :     }
         976                 :            :
         977                 :            :     /* the string doesn't have to be NULL terminated */
         978                 :            :     wchar_t* target = PyMem_Malloc(size * sizeof(wchar_t));
         979                 :            :     if (target == NULL) {
         980                 :            :         PyErr_NoMemory();
         981                 :            :         return NULL;
         982                 :            :     }
         983                 :            :
         984                 :            :     iconv_t cd = iconv_open(tocode, fromcode);
         985                 :            :     if (cd == (iconv_t)-1) {
         986                 :            :         PyErr_Format(PyExc_ValueError, "iconv_open() failed");
         987                 :            :         PyMem_Free(target);
         988                 :            :         return NULL;
         989                 :            :     }
         990                 :            :
         991                 :            :     char *inbuf = (char *) source;
         992                 :            :     char *outbuf = (char *) target;
         993                 :            :     size_t inbytesleft = sizeof(wchar_t) * size;
         994                 :            :     size_t outbytesleft = inbytesleft;
         995                 :            :
         996                 :            :     size_t ret = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
         997                 :            :     if (ret == DECODE_ERROR) {
         998                 :            :         PyErr_Format(PyExc_ValueError, "iconv() failed");
         999                 :            :         PyMem_Free(target);
        1000                 :            :         iconv_close(cd);
        1001                 :            :         return NULL;
        1002                 :            :     }
        1003                 :            :
        1004                 :            :     iconv_close(cd);
        1005                 :            :     return target;
        1006                 :            : }
        1007                 :            :
        1008                 :            : /* Convert a wide character string to the UCS-4 encoded string. This
        1009                 :            :    is necessary on systems where internal form of wchar_t are not Unicode
        1010                 :            :    code points (e.g. Oracle Solaris).
        1011                 :            :
        1012                 :            :    Return a pointer to a newly allocated string, use PyMem_Free() to free
        1013                 :            :    the memory. Return NULL and raise exception on conversion or memory
        1014                 :            :    allocation error. */
        1015                 :            : wchar_t *
        1016                 :            : _Py_DecodeNonUnicodeWchar(const wchar_t *native, Py_ssize_t size)
        1017                 :            : {
        1018                 :            :     return _Py_ConvertWCharForm(native, size, "UCS-4-INTERNAL", "wchar_t");
        1019                 :            : }
        1020                 :            :
        1021                 :            : /* Convert a UCS-4 encoded string to native wide character string. This
        1022                 :            :    is necessary on systems where internal form of wchar_t are not Unicode
        1023                 :            :    code points (e.g. Oracle Solaris).
        1024                 :            :
        1025                 :            :    The conversion is done in place. This can be done because both wchar_t
        1026                 :            :    and UCS-4 use 4-byte encoding, and one wchar_t symbol always correspond
        1027                 :            :    to a single UCS-4 symbol and vice versa. (This is true for Oracle Solaris,
        1028                 :            :    which is currently the only system using these functions; it doesn't have
        1029                 :            :    to be for other systems).
        1030                 :            :
        1031                 :            :    Return 0 on success. Return -1 and raise exception on conversion
        1032                 :            :    or memory allocation error. */
        1033                 :            : int
        1034                 :            : _Py_EncodeNonUnicodeWchar_InPlace(wchar_t *unicode, Py_ssize_t size)
        1035                 :            : {
        1036                 :            :     wchar_t* result = _Py_ConvertWCharForm(unicode, size, "wchar_t", "UCS-4-INTERNAL");
        1037                 :            :     if (!result) {
        1038                 :            :         return -1;
        1039                 :            :     }
        1040                 :            :     memcpy(unicode, result, size * sizeof(wchar_t));
        1041                 :            :     PyMem_Free(result);
        1042                 :            :     return 0;
        1043                 :            : }
        1044                 :            : #endif /* HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION */
        1045                 :            :
        1046                 :            : #ifdef MS_WINDOWS
        1047                 :            : static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */
        1048                 :            :
        1049                 :            : static void
        1050                 :            : FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out)
        1051                 :            : {
        1052                 :            :     /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */
        1053                 :            :     /* Cannot simply cast and dereference in_ptr,
        1054                 :            :        since it might not be aligned properly */
        1055                 :            :     __int64 in;
        1056                 :            :     memcpy(&in, in_ptr, sizeof(in));
        1057                 :            :     *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */
        1058                 :            :     *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t);
        1059                 :            : }
        1060                 :            :
        1061                 :            : static void
        1062                 :            : LARGE_INTEGER_to_time_t_nsec(LARGE_INTEGER *in_ptr, time_t *time_out, int* nsec_out)
        1063                 :            : {
        1064                 :            :     *nsec_out = (int)(in_ptr->QuadPart % 10000000) * 100; /* FILETIME is in units of 100 nsec. */
        1065                 :            :     *time_out = Py_SAFE_DOWNCAST((in_ptr->QuadPart / 10000000) - secs_between_epochs, __int64, time_t);
        1066                 :            : }
        1067                 :            :
        1068                 :            : void
        1069                 :            : _Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr)
        1070                 :            : {
        1071                 :            :     /* XXX endianness */
        1072                 :            :     __int64 out;
        1073                 :            :     out = time_in + secs_between_epochs;
        1074                 :            :     out = out * 10000000 + nsec_in / 100;
        1075                 :            :     memcpy(out_ptr, &out, sizeof(out));
        1076                 :            : }
        1077                 :            :
        1078                 :            : /* Below, we *know* that ugo+r is 0444 */
        1079                 :            : #if _S_IREAD != 0400
        1080                 :            : #error Unsupported C library
        1081                 :            : #endif
        1082                 :            : static int
        1083                 :            : attributes_to_mode(DWORD attr)
        1084                 :            : {
        1085                 :            :     int m = 0;
        1086                 :            :     if (attr & FILE_ATTRIBUTE_DIRECTORY)
        1087                 :            :         m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */
        1088                 :            :     else
        1089                 :            :         m |= _S_IFREG;
        1090                 :            :     if (attr & FILE_ATTRIBUTE_READONLY)
        1091                 :            :         m |= 0444;
        1092                 :            :     else
        1093                 :            :         m |= 0666;
        1094                 :            :     return m;
        1095                 :            : }
        1096                 :            :
        1097                 :            :
        1098                 :            : typedef union {
        1099                 :            :     FILE_ID_128 id;
        1100                 :            :     struct {
        1101                 :            :         uint64_t st_ino;
        1102                 :            :         uint64_t st_ino_high;
        1103                 :            :     };
        1104                 :            : } id_128_to_ino;
        1105                 :            :
        1106                 :            :
        1107                 :            : void
        1108                 :            : _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag,
        1109                 :            :                            FILE_BASIC_INFO *basic_info, FILE_ID_INFO *id_info,
        1110                 :            :                            struct _Py_stat_struct *result)
        1111                 :            : {
        1112                 :            :     memset(result, 0, sizeof(*result));
        1113                 :            :     result->st_mode = attributes_to_mode(info->dwFileAttributes);
        1114                 :            :     result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
        1115                 :            :     result->st_dev = id_info ? id_info->VolumeSerialNumber : info->dwVolumeSerialNumber;
        1116                 :            :     result->st_rdev = 0;
        1117                 :            :     /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */
        1118                 :            :     if (basic_info) {
        1119                 :            :         LARGE_INTEGER_to_time_t_nsec(&basic_info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec);
        1120                 :            :         LARGE_INTEGER_to_time_t_nsec(&basic_info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec);
        1121                 :            :         LARGE_INTEGER_to_time_t_nsec(&basic_info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec);
        1122                 :            :         LARGE_INTEGER_to_time_t_nsec(&basic_info->LastAccessTime, &result->st_atime, &result->st_atime_nsec);
        1123                 :            :     } else {
        1124                 :            :         FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_birthtime, &result->st_birthtime_nsec);
        1125                 :            :         FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec);
        1126                 :            :         FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec);
        1127                 :            :     }
        1128                 :            :     result->st_nlink = info->nNumberOfLinks;
        1129                 :            :
        1130                 :            :     if (id_info) {
        1131                 :            :         id_128_to_ino file_id;
        1132                 :            :         file_id.id = id_info->FileId;
        1133                 :            :         result->st_ino = file_id.st_ino;
        1134                 :            :         result->st_ino_high = file_id.st_ino_high;
        1135                 :            :     } else {
        1136                 :            :         /* should only occur for DirEntry_from_find_data, in which case the
        1137                 :            :            index is likely to be zero anyway. */
        1138                 :            :         result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow;
        1139                 :            :     }
        1140                 :            :
        1141                 :            :     /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will
        1142                 :            :        open other name surrogate reparse points without traversing them. To
        1143                 :            :        detect/handle these, check st_file_attributes and st_reparse_tag. */
        1144                 :            :     result->st_reparse_tag = reparse_tag;
        1145                 :            :     if (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
        1146                 :            :         reparse_tag == IO_REPARSE_TAG_SYMLINK) {
        1147                 :            :         /* set the bits that make this a symlink */
        1148                 :            :         result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK;
        1149                 :            :     }
        1150                 :            :     result->st_file_attributes = info->dwFileAttributes;
        1151                 :            : }
        1152                 :            :
        1153                 :            : void
        1154                 :            : _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *info,
        1155                 :            :                             struct _Py_stat_struct *result)
        1156                 :            : {
        1157                 :            :     memset(result, 0, sizeof(*result));
        1158                 :            :     result->st_mode = attributes_to_mode(info->FileAttributes);
        1159                 :            :     result->st_size = info->EndOfFile.QuadPart;
        1160                 :            :     LARGE_INTEGER_to_time_t_nsec(&info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec);
        1161                 :            :     LARGE_INTEGER_to_time_t_nsec(&info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec);
        1162                 :            :     LARGE_INTEGER_to_time_t_nsec(&info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec);
        1163                 :            :     LARGE_INTEGER_to_time_t_nsec(&info->LastAccessTime, &result->st_atime, &result->st_atime_nsec);
        1164                 :            :     result->st_nlink = info->NumberOfLinks;
        1165                 :            :     result->st_dev = info->VolumeSerialNumber.QuadPart;
        1166                 :            :     /* File systems with less than 128-bits zero pad into this field */
        1167                 :            :     id_128_to_ino file_id;
        1168                 :            :     file_id.id = info->FileId128;
        1169                 :            :     result->st_ino = file_id.st_ino;
        1170                 :            :     result->st_ino_high = file_id.st_ino_high;
        1171                 :            :     /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will
        1172                 :            :        open other name surrogate reparse points without traversing them. To
        1173                 :            :        detect/handle these, check st_file_attributes and st_reparse_tag. */
        1174                 :            :     result->st_reparse_tag = info->ReparseTag;
        1175                 :            :     if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
        1176                 :            :         info->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
        1177                 :            :         /* set the bits that make this a symlink */
        1178                 :            :         result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK;
        1179                 :            :     }
        1180                 :            :     result->st_file_attributes = info->FileAttributes;
        1181                 :            :     switch (info->DeviceType) {
        1182                 :            :     case FILE_DEVICE_DISK:
        1183                 :            :     case FILE_DEVICE_VIRTUAL_DISK:
        1184                 :            :     case FILE_DEVICE_DFS:
        1185                 :            :     case FILE_DEVICE_CD_ROM:
        1186                 :            :     case FILE_DEVICE_CONTROLLER:
        1187                 :            :     case FILE_DEVICE_DATALINK:
        1188                 :            :         break;
        1189                 :            :     case FILE_DEVICE_DISK_FILE_SYSTEM:
        1190                 :            :     case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
        1191                 :            :     case FILE_DEVICE_NETWORK_FILE_SYSTEM:
        1192                 :            :         result->st_mode = (result->st_mode & ~S_IFMT) | 0x6000; /* _S_IFBLK */
        1193                 :            :         break;
        1194                 :            :     case FILE_DEVICE_CONSOLE:
        1195                 :            :     case FILE_DEVICE_NULL:
        1196                 :            :     case FILE_DEVICE_KEYBOARD:
        1197                 :            :     case FILE_DEVICE_MODEM:
        1198                 :            :     case FILE_DEVICE_MOUSE:
        1199                 :            :     case FILE_DEVICE_PARALLEL_PORT:
        1200                 :            :     case FILE_DEVICE_PRINTER:
        1201                 :            :     case FILE_DEVICE_SCREEN:
        1202                 :            :     case FILE_DEVICE_SERIAL_PORT:
        1203                 :            :     case FILE_DEVICE_SOUND:
        1204                 :            :         result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFCHR;
        1205                 :            :         break;
        1206                 :            :     case FILE_DEVICE_NAMED_PIPE:
        1207                 :            :         result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFIFO;
        1208                 :            :         break;
        1209                 :            :     default:
        1210                 :            :         if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
        1211                 :            :             result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFDIR;
        1212                 :            :         }
        1213                 :            :         break;
        1214                 :            :     }
        1215                 :            : }
        1216                 :            :
        1217                 :            : #endif
        1218                 :            :
        1219                 :            : /* Return information about a file.
        1220                 :            :
        1221                 :            :    On POSIX, use fstat().
        1222                 :            :
        1223                 :            :    On Windows, use GetFileType() and GetFileInformationByHandle() which support
        1224                 :            :    files larger than 2 GiB.  fstat() may fail with EOVERFLOW on files larger
        1225                 :            :    than 2 GiB because the file size type is a signed 32-bit integer: see issue
        1226                 :            :    #23152.
        1227                 :            :
        1228                 :            :    On Windows, set the last Windows error and return nonzero on error. On
        1229                 :            :    POSIX, set errno and return nonzero on error. Fill status and return 0 on
        1230                 :            :    success. */
        1231                 :            : int
        1232                 :       2163 : _Py_fstat_noraise(int fd, struct _Py_stat_struct *status)
        1233                 :            : {
        1234                 :            : #ifdef MS_WINDOWS
        1235                 :            :     BY_HANDLE_FILE_INFORMATION info;
        1236                 :            :     FILE_BASIC_INFO basicInfo;
        1237                 :            :     FILE_ID_INFO idInfo;
        1238                 :            :     HANDLE h;
        1239                 :            :     int type;
        1240                 :            :
        1241                 :            :     h = _Py_get_osfhandle_noraise(fd);
        1242                 :            :
        1243                 :            :     if (h == INVALID_HANDLE_VALUE) {
        1244                 :            :         /* errno is already set by _get_osfhandle, but we also set
        1245                 :            :            the Win32 error for callers who expect that */
        1246                 :            :         SetLastError(ERROR_INVALID_HANDLE);
        1247                 :            :         return -1;
        1248                 :            :     }
        1249                 :            :     memset(status, 0, sizeof(*status));
        1250                 :            :
        1251                 :            :     type = GetFileType(h);
        1252                 :            :     if (type == FILE_TYPE_UNKNOWN) {
        1253                 :            :         DWORD error = GetLastError();
        1254                 :            :         if (error != 0) {
        1255                 :            :             errno = winerror_to_errno(error);
        1256                 :            :             return -1;
        1257                 :            :         }
        1258                 :            :         /* else: valid but unknown file */
        1259                 :            :     }
        1260                 :            :
        1261                 :            :     if (type != FILE_TYPE_DISK) {
        1262                 :            :         if (type == FILE_TYPE_CHAR)
        1263                 :            :             status->st_mode = _S_IFCHR;
        1264                 :            :         else if (type == FILE_TYPE_PIPE)
        1265                 :            :             status->st_mode = _S_IFIFO;
        1266                 :            :         return 0;
        1267                 :            :     }
        1268                 :            :
        1269                 :            :     if (!GetFileInformationByHandle(h, &info) ||
        1270                 :            :         !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo)) ||
        1271                 :            :         !GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) {
        1272                 :            :         /* The Win32 error is already set, but we also set errno for
        1273                 :            :            callers who expect it */
        1274                 :            :         errno = winerror_to_errno(GetLastError());
        1275                 :            :         return -1;
        1276                 :            :     }
        1277                 :            :
        1278                 :            :     _Py_attribute_data_to_stat(&info, 0, &basicInfo, &idInfo, status);
        1279                 :            :     return 0;
        1280                 :            : #else
        1281                 :       2163 :     return fstat(fd, status);
        1282                 :            : #endif
        1283                 :            : }
        1284                 :            :
        1285                 :            : /* Return information about a file.
        1286                 :            :
        1287                 :            :    On POSIX, use fstat().
        1288                 :            :
        1289                 :            :    On Windows, use GetFileType() and GetFileInformationByHandle() which support
        1290                 :            :    files larger than 2 GiB.  fstat() may fail with EOVERFLOW on files larger
        1291                 :            :    than 2 GiB because the file size type is a signed 32-bit integer: see issue
        1292                 :            :    #23152.
        1293                 :            :
        1294                 :            :    Raise an exception and return -1 on error. On Windows, set the last Windows
        1295                 :            :    error on error. On POSIX, set errno on error. Fill status and return 0 on
        1296                 :            :    success.
        1297                 :            :
        1298                 :            :    Release the GIL to call GetFileType() and GetFileInformationByHandle(), or
        1299                 :            :    to call fstat(). The caller must hold the GIL. */
        1300                 :            : int
        1301                 :          0 : _Py_fstat(int fd, struct _Py_stat_struct *status)
        1302                 :            : {
        1303                 :            :     int res;
        1304                 :            :
        1305                 :            :     assert(PyGILState_Check());
        1306                 :            :
        1307                 :          0 :     Py_BEGIN_ALLOW_THREADS
        1308                 :          0 :     res = _Py_fstat_noraise(fd, status);
        1309                 :          0 :     Py_END_ALLOW_THREADS
        1310                 :            :
        1311         [ #  # ]:          0 :     if (res != 0) {
        1312                 :            : #ifdef MS_WINDOWS
        1313                 :            :         PyErr_SetFromWindowsErr(0);
        1314                 :            : #else
        1315                 :          0 :         PyErr_SetFromErrno(PyExc_OSError);
        1316                 :            : #endif
        1317                 :          0 :         return -1;
        1318                 :            :     }
        1319                 :          0 :     return 0;
        1320                 :            : }
        1321                 :            :
        1322                 :            : /* Like _Py_stat() but with a raw filename. */
        1323                 :            : int
        1324                 :         46 : _Py_wstat(const wchar_t* path, struct stat *buf)
        1325                 :            : {
        1326                 :            :     int err;
        1327                 :            : #ifdef MS_WINDOWS
        1328                 :            :     struct _stat wstatbuf;
        1329                 :            :     err = _wstat(path, &wstatbuf);
        1330                 :            :     if (!err) {
        1331                 :            :         buf->st_mode = wstatbuf.st_mode;
        1332                 :            :     }
        1333                 :            : #else
        1334                 :            :     char *fname;
        1335                 :         46 :     fname = _Py_EncodeLocaleRaw(path, NULL);
        1336         [ -  + ]:         46 :     if (fname == NULL) {
        1337                 :          0 :         errno = EINVAL;
        1338                 :          0 :         return -1;
        1339                 :            :     }
        1340                 :         46 :     err = stat(fname, buf);
        1341                 :         46 :     PyMem_RawFree(fname);
        1342                 :            : #endif
        1343                 :         46 :     return err;
        1344                 :            : }
        1345                 :            :
        1346                 :            :
        1347                 :            : /* Call _wstat() on Windows, or encode the path to the filesystem encoding and
        1348                 :            :    call stat() otherwise. Only fill st_mode attribute on Windows.
        1349                 :            :
        1350                 :            :    Return 0 on success, -1 on _wstat() / stat() error, -2 if an exception was
        1351                 :            :    raised. */
        1352                 :            :
        1353                 :            : int
        1354                 :          0 : _Py_stat(PyObject *path, struct stat *statbuf)
        1355                 :            : {
        1356                 :            : #ifdef MS_WINDOWS
        1357                 :            :     int err;
        1358                 :            :
        1359                 :            :     wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL);
        1360                 :            :     if (wpath == NULL)
        1361                 :            :         return -2;
        1362                 :            :
        1363                 :            :     err = _Py_wstat(wpath, statbuf);
        1364                 :            :     PyMem_Free(wpath);
        1365                 :            :     return err;
        1366                 :            : #else
        1367                 :            :     int ret;
        1368                 :            :     PyObject *bytes;
        1369                 :            :     char *cpath;
        1370                 :            :
        1371                 :          0 :     bytes = PyUnicode_EncodeFSDefault(path);
        1372         [ #  # ]:          0 :     if (bytes == NULL)
        1373                 :          0 :         return -2;
        1374                 :            :
        1375                 :            :     /* check for embedded null bytes */
        1376         [ #  # ]:          0 :     if (PyBytes_AsStringAndSize(bytes, &cpath, NULL) == -1) {
        1377                 :          0 :         Py_DECREF(bytes);
        1378                 :          0 :         return -2;
        1379                 :            :     }
        1380                 :            :
        1381                 :          0 :     ret = stat(cpath, statbuf);
        1382                 :          0 :     Py_DECREF(bytes);
        1383                 :          0 :     return ret;
        1384                 :            : #endif
        1385                 :            : }
        1386                 :            :
        1387                 :            : #ifdef MS_WINDOWS
        1388                 :            : // For some Windows API partitions, SetHandleInformation() is declared
        1389                 :            : // but none of the handle flags are defined.
        1390                 :            : #ifndef HANDLE_FLAG_INHERIT
        1391                 :            : #define HANDLE_FLAG_INHERIT 0x00000001
        1392                 :            : #endif
        1393                 :            : #endif
        1394                 :            :
        1395                 :            : /* This function MUST be kept async-signal-safe on POSIX when raise=0. */
        1396                 :            : static int
        1397                 :         25 : get_inheritable(int fd, int raise)
        1398                 :            : {
        1399                 :            : #ifdef MS_WINDOWS
        1400                 :            :     HANDLE handle;
        1401                 :            :     DWORD flags;
        1402                 :            :
        1403                 :            :     handle = _Py_get_osfhandle_noraise(fd);
        1404                 :            :     if (handle == INVALID_HANDLE_VALUE) {
        1405                 :            :         if (raise)
        1406                 :            :             PyErr_SetFromErrno(PyExc_OSError);
        1407                 :            :         return -1;
        1408                 :            :     }
        1409                 :            :
        1410                 :            :     if (!GetHandleInformation(handle, &flags)) {
        1411                 :            :         if (raise)
        1412                 :            :             PyErr_SetFromWindowsErr(0);
        1413                 :            :         return -1;
        1414                 :            :     }
        1415                 :            :
        1416                 :            :     return (flags & HANDLE_FLAG_INHERIT);
        1417                 :            : #else
        1418                 :            :     int flags;
        1419                 :            :
        1420                 :         25 :     flags = fcntl(fd, F_GETFD, 0);
        1421         [ -  + ]:         25 :     if (flags == -1) {
        1422         [ #  # ]:          0 :         if (raise)
        1423                 :          0 :             PyErr_SetFromErrno(PyExc_OSError);
        1424                 :          0 :         return -1;
        1425                 :            :     }
        1426                 :         25 :     return !(flags & FD_CLOEXEC);
        1427                 :            : #endif
        1428                 :            : }
        1429                 :            :
        1430                 :            : /* Get the inheritable flag of the specified file descriptor.
        1431                 :            :    Return 1 if the file descriptor can be inherited, 0 if it cannot,
        1432                 :            :    raise an exception and return -1 on error. */
        1433                 :            : int
        1434                 :          0 : _Py_get_inheritable(int fd)
        1435                 :            : {
        1436                 :          0 :     return get_inheritable(fd, 1);
        1437                 :            : }
        1438                 :            :
        1439                 :            :
        1440                 :            : /* This function MUST be kept async-signal-safe on POSIX when raise=0. */
        1441                 :            : static int
        1442                 :       1451 : set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works)
        1443                 :            : {
        1444                 :            : #ifdef MS_WINDOWS
        1445                 :            :     HANDLE handle;
        1446                 :            :     DWORD flags;
        1447                 :            : #else
        1448                 :            : #if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
        1449                 :            :     static int ioctl_works = -1;
        1450                 :            :     int request;
        1451                 :            :     int err;
        1452                 :            : #endif
        1453                 :            :     int flags, new_flags;
        1454                 :            :     int res;
        1455                 :            : #endif
        1456                 :            :
        1457                 :            :     /* atomic_flag_works can only be used to make the file descriptor
        1458                 :            :        non-inheritable */
        1459                 :            :     assert(!(atomic_flag_works != NULL && inheritable));
        1460                 :            :
        1461   [ +  +  +  - ]:       1451 :     if (atomic_flag_works != NULL && !inheritable) {
        1462         [ +  + ]:       1425 :         if (*atomic_flag_works == -1) {
        1463                 :         25 :             int isInheritable = get_inheritable(fd, raise);
        1464         [ -  + ]:         25 :             if (isInheritable == -1)
        1465                 :          0 :                 return -1;
        1466                 :         25 :             *atomic_flag_works = !isInheritable;
        1467                 :            :         }
        1468                 :            :
        1469         [ +  - ]:       1425 :         if (*atomic_flag_works)
        1470                 :       1425 :             return 0;
        1471                 :            :     }
        1472                 :            :
        1473                 :            : #ifdef MS_WINDOWS
        1474                 :            :     handle = _Py_get_osfhandle_noraise(fd);
        1475                 :            :     if (handle == INVALID_HANDLE_VALUE) {
        1476                 :            :         if (raise)
        1477                 :            :             PyErr_SetFromErrno(PyExc_OSError);
        1478                 :            :         return -1;
        1479                 :            :     }
        1480                 :            :
        1481                 :            :     if (inheritable)
        1482                 :            :         flags = HANDLE_FLAG_INHERIT;
        1483                 :            :     else
        1484                 :            :         flags = 0;
        1485                 :            :
        1486                 :            :     if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, flags)) {
        1487                 :            :         if (raise)
        1488                 :            :             PyErr_SetFromWindowsErr(0);
        1489                 :            :         return -1;
        1490                 :            :     }
        1491                 :            :     return 0;
        1492                 :            :
        1493                 :            : #else
        1494                 :            :
        1495                 :            : #if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
        1496   [ +  -  +  + ]:         26 :     if (ioctl_works != 0 && raise != 0) {
        1497                 :            :         /* fast-path: ioctl() only requires one syscall */
        1498                 :            :         /* caveat: raise=0 is an indicator that we must be async-signal-safe
        1499                 :            :          * thus avoid using ioctl() so we skip the fast-path. */
        1500         [ -  + ]:         22 :         if (inheritable)
        1501                 :          0 :             request = FIONCLEX;
        1502                 :            :         else
        1503                 :         22 :             request = FIOCLEX;
        1504                 :         22 :         err = ioctl(fd, request, NULL);
        1505         [ +  - ]:         22 :         if (!err) {
        1506                 :         22 :             ioctl_works = 1;
        1507                 :         22 :             return 0;
        1508                 :            :         }
        1509                 :            :
        1510                 :            : #ifdef O_PATH
        1511         [ #  # ]:          0 :         if (errno == EBADF) {
        1512                 :            :             // bpo-44849: On Linux and FreeBSD, ioctl(FIOCLEX) fails with EBADF
        1513                 :            :             // on O_PATH file descriptors. Fall through to the fcntl()
        1514                 :            :             // implementation.
        1515                 :            :         }
        1516                 :            :         else
        1517                 :            : #endif
        1518   [ #  #  #  # ]:          0 :         if (errno != ENOTTY && errno != EACCES) {
        1519         [ #  # ]:          0 :             if (raise)
        1520                 :          0 :                 PyErr_SetFromErrno(PyExc_OSError);
        1521                 :          0 :             return -1;
        1522                 :            :         }
        1523                 :            :         else {
        1524                 :            :             /* Issue #22258: Here, ENOTTY means "Inappropriate ioctl for
        1525                 :            :                device". The ioctl is declared but not supported by the kernel.
        1526                 :            :                Remember that ioctl() doesn't work. It is the case on
        1527                 :            :                Illumos-based OS for example.
        1528                 :            :
        1529                 :            :                Issue #27057: When SELinux policy disallows ioctl it will fail
        1530                 :            :                with EACCES. While FIOCLEX is safe operation it may be
        1531                 :            :                unavailable because ioctl was denied altogether.
        1532                 :            :                This can be the case on Android. */
        1533                 :          0 :             ioctl_works = 0;
        1534                 :            :         }
        1535                 :            :         /* fallback to fcntl() if ioctl() does not work */
        1536                 :            :     }
        1537                 :            : #endif
        1538                 :            :
        1539                 :            :     /* slow-path: fcntl() requires two syscalls */
        1540                 :          4 :     flags = fcntl(fd, F_GETFD);
        1541         [ -  + ]:          4 :     if (flags < 0) {
        1542         [ #  # ]:          0 :         if (raise)
        1543                 :          0 :             PyErr_SetFromErrno(PyExc_OSError);
        1544                 :          0 :         return -1;
        1545                 :            :     }
        1546                 :            :
        1547         [ -  + ]:          4 :     if (inheritable) {
        1548                 :          0 :         new_flags = flags & ~FD_CLOEXEC;
        1549                 :            :     }
        1550                 :            :     else {
        1551                 :          4 :         new_flags = flags | FD_CLOEXEC;
        1552                 :            :     }
        1553                 :            :
        1554         [ -  + ]:          4 :     if (new_flags == flags) {
        1555                 :            :         /* FD_CLOEXEC flag already set/cleared: nothing to do */
        1556                 :          0 :         return 0;
        1557                 :            :     }
        1558                 :            :
        1559                 :          4 :     res = fcntl(fd, F_SETFD, new_flags);
        1560         [ -  + ]:          4 :     if (res < 0) {
        1561         [ #  # ]:          0 :         if (raise)
        1562                 :          0 :             PyErr_SetFromErrno(PyExc_OSError);
        1563                 :          0 :         return -1;
        1564                 :            :     }
        1565                 :          4 :     return 0;
        1566                 :            : #endif
        1567                 :            : }
        1568                 :            :
        1569                 :            : /* Make the file descriptor non-inheritable.
        1570                 :            :    Return 0 on success, set errno and return -1 on error. */
        1571                 :            : static int
        1572                 :          4 : make_non_inheritable(int fd)
        1573                 :            : {
        1574                 :          4 :     return set_inheritable(fd, 0, 0, NULL);
        1575                 :            : }
        1576                 :            :
        1577                 :            : /* Set the inheritable flag of the specified file descriptor.
        1578                 :            :    On success: return 0, on error: raise an exception and return -1.
        1579                 :            :
        1580                 :            :    If atomic_flag_works is not NULL:
        1581                 :            :
        1582                 :            :     * if *atomic_flag_works==-1, check if the inheritable is set on the file
        1583                 :            :       descriptor: if yes, set *atomic_flag_works to 1, otherwise set to 0 and
        1584                 :            :       set the inheritable flag
        1585                 :            :     * if *atomic_flag_works==1: do nothing
        1586                 :            :     * if *atomic_flag_works==0: set inheritable flag to False
        1587                 :            :
        1588                 :            :    Set atomic_flag_works to NULL if no atomic flag was used to create the
        1589                 :            :    file descriptor.
        1590                 :            :
        1591                 :            :    atomic_flag_works can only be used to make a file descriptor
        1592                 :            :    non-inheritable: atomic_flag_works must be NULL if inheritable=1. */
        1593                 :            : int
        1594                 :       1425 : _Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works)
        1595                 :            : {
        1596                 :       1425 :     return set_inheritable(fd, inheritable, 1, atomic_flag_works);
        1597                 :            : }
        1598                 :            :
        1599                 :            : /* Same as _Py_set_inheritable() but on error, set errno and
        1600                 :            :    don't raise an exception.
        1601                 :            :    This function is async-signal-safe. */
        1602                 :            : int
        1603                 :          0 : _Py_set_inheritable_async_safe(int fd, int inheritable, int *atomic_flag_works)
        1604                 :            : {
        1605                 :          0 :     return set_inheritable(fd, inheritable, 0, atomic_flag_works);
        1606                 :            : }
        1607                 :            :
        1608                 :            : static int
        1609                 :          0 : _Py_open_impl(const char *pathname, int flags, int gil_held)
        1610                 :            : {
        1611                 :            :     int fd;
        1612                 :          0 :     int async_err = 0;
        1613                 :            : #ifndef MS_WINDOWS
        1614                 :            :     int *atomic_flag_works;
        1615                 :            : #endif
        1616                 :            :
        1617                 :            : #ifdef MS_WINDOWS
        1618                 :            :     flags |= O_NOINHERIT;
        1619                 :            : #elif defined(O_CLOEXEC)
        1620                 :          0 :     atomic_flag_works = &_Py_open_cloexec_works;
        1621                 :          0 :     flags |= O_CLOEXEC;
        1622                 :            : #else
        1623                 :            :     atomic_flag_works = NULL;
        1624                 :            : #endif
        1625                 :            :
        1626         [ #  # ]:          0 :     if (gil_held) {
        1627                 :          0 :         PyObject *pathname_obj = PyUnicode_DecodeFSDefault(pathname);
        1628         [ #  # ]:          0 :         if (pathname_obj == NULL) {
        1629                 :          0 :             return -1;
        1630                 :            :         }
        1631         [ #  # ]:          0 :         if (PySys_Audit("open", "OOi", pathname_obj, Py_None, flags) < 0) {
        1632                 :          0 :             Py_DECREF(pathname_obj);
        1633                 :          0 :             return -1;
        1634                 :            :         }
        1635                 :            :
        1636                 :            :         do {
        1637                 :          0 :             Py_BEGIN_ALLOW_THREADS
        1638                 :          0 :             fd = open(pathname, flags);
        1639                 :          0 :             Py_END_ALLOW_THREADS
        1640                 :            :         } while (fd < 0
        1641   [ #  #  #  #  :          0 :                  && errno == EINTR && !(async_err = PyErr_CheckSignals()));
                       #  # ]
        1642         [ #  # ]:          0 :         if (async_err) {
        1643                 :          0 :             Py_DECREF(pathname_obj);
        1644                 :          0 :             return -1;
        1645                 :            :         }
        1646         [ #  # ]:          0 :         if (fd < 0) {
        1647                 :          0 :             PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, pathname_obj, NULL);
        1648                 :          0 :             Py_DECREF(pathname_obj);
        1649                 :          0 :             return -1;
        1650                 :            :         }
        1651                 :          0 :         Py_DECREF(pathname_obj);
        1652                 :            :     }
        1653                 :            :     else {
        1654                 :          0 :         fd = open(pathname, flags);
        1655         [ #  # ]:          0 :         if (fd < 0)
        1656                 :          0 :             return -1;
        1657                 :            :     }
        1658                 :            :
        1659                 :            : #ifndef MS_WINDOWS
        1660         [ #  # ]:          0 :     if (set_inheritable(fd, 0, gil_held, atomic_flag_works) < 0) {
        1661                 :          0 :         close(fd);
        1662                 :          0 :         return -1;
        1663                 :            :     }
        1664                 :            : #endif
        1665                 :            :
        1666                 :          0 :     return fd;
        1667                 :            : }
        1668                 :            :
        1669                 :            : /* Open a file with the specified flags (wrapper to open() function).
        1670                 :            :    Return a file descriptor on success. Raise an exception and return -1 on
        1671                 :            :    error.
        1672                 :            :
        1673                 :            :    The file descriptor is created non-inheritable.
        1674                 :            :
        1675                 :            :    When interrupted by a signal (open() fails with EINTR), retry the syscall,
        1676                 :            :    except if the Python signal handler raises an exception.
        1677                 :            :
        1678                 :            :    Release the GIL to call open(). The caller must hold the GIL. */
        1679                 :            : int
        1680                 :          0 : _Py_open(const char *pathname, int flags)
        1681                 :            : {
        1682                 :            :     /* _Py_open() must be called with the GIL held. */
        1683                 :            :     assert(PyGILState_Check());
        1684                 :          0 :     return _Py_open_impl(pathname, flags, 1);
        1685                 :            : }
        1686                 :            :
        1687                 :            : /* Open a file with the specified flags (wrapper to open() function).
        1688                 :            :    Return a file descriptor on success. Set errno and return -1 on error.
        1689                 :            :
        1690                 :            :    The file descriptor is created non-inheritable.
        1691                 :            :
        1692                 :            :    If interrupted by a signal, fail with EINTR. */
        1693                 :            : int
        1694                 :          0 : _Py_open_noraise(const char *pathname, int flags)
        1695                 :            : {
        1696                 :          0 :     return _Py_open_impl(pathname, flags, 0);
        1697                 :            : }
        1698                 :            :
        1699                 :            : /* Open a file. Use _wfopen() on Windows, encode the path to the locale
        1700                 :            :    encoding and use fopen() otherwise.
        1701                 :            :
        1702                 :            :    The file descriptor is created non-inheritable.
        1703                 :            :
        1704                 :            :    If interrupted by a signal, fail with EINTR. */
        1705                 :            : FILE *
        1706                 :        125 : _Py_wfopen(const wchar_t *path, const wchar_t *mode)
        1707                 :            : {
        1708                 :            :     FILE *f;
        1709         [ -  + ]:        125 :     if (PySys_Audit("open", "uui", path, mode, 0) < 0) {
        1710                 :          0 :         return NULL;
        1711                 :            :     }
        1712                 :            : #ifndef MS_WINDOWS
        1713                 :            :     char *cpath;
        1714                 :            :     char cmode[10];
        1715                 :            :     size_t r;
        1716                 :        125 :     r = wcstombs(cmode, mode, 10);
        1717   [ +  -  -  + ]:        125 :     if (r == DECODE_ERROR || r >= 10) {
        1718                 :          0 :         errno = EINVAL;
        1719                 :          0 :         return NULL;
        1720                 :            :     }
        1721                 :        125 :     cpath = _Py_EncodeLocaleRaw(path, NULL);
        1722         [ -  + ]:        125 :     if (cpath == NULL) {
        1723                 :          0 :         return NULL;
        1724                 :            :     }
        1725                 :        125 :     f = fopen(cpath, cmode);
        1726                 :        125 :     PyMem_RawFree(cpath);
        1727                 :            : #else
        1728                 :            :     f = _wfopen(path, mode);
        1729                 :            : #endif
        1730         [ +  + ]:        125 :     if (f == NULL)
        1731                 :        121 :         return NULL;
        1732         [ -  + ]:          4 :     if (make_non_inheritable(fileno(f)) < 0) {
        1733                 :          0 :         fclose(f);
        1734                 :          0 :         return NULL;
        1735                 :            :     }
        1736                 :          4 :     return f;
        1737                 :            : }
        1738                 :            :
        1739                 :            :
        1740                 :            : /* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem
        1741                 :            :    encoding and call fopen() otherwise.
        1742                 :            :
        1743                 :            :    Return the new file object on success. Raise an exception and return NULL
        1744                 :            :    on error.
        1745                 :            :
        1746                 :            :    The file descriptor is created non-inheritable.
        1747                 :            :
        1748                 :            :    When interrupted by a signal (open() fails with EINTR), retry the syscall,
        1749                 :            :    except if the Python signal handler raises an exception.
        1750                 :            :
        1751                 :            :    Release the GIL to call _wfopen() or fopen(). The caller must hold
        1752                 :            :    the GIL. */
        1753                 :            : FILE*
        1754                 :         22 : _Py_fopen_obj(PyObject *path, const char *mode)
        1755                 :            : {
        1756                 :            :     FILE *f;
        1757                 :         22 :     int async_err = 0;
        1758                 :            : #ifdef MS_WINDOWS
        1759                 :            :     wchar_t wmode[10];
        1760                 :            :     int usize;
        1761                 :            :
        1762                 :            :     assert(PyGILState_Check());
        1763                 :            :
        1764                 :            :     if (PySys_Audit("open", "Osi", path, mode, 0) < 0) {
        1765                 :            :         return NULL;
        1766                 :            :     }
        1767                 :            :     if (!PyUnicode_Check(path)) {
        1768                 :            :         PyErr_Format(PyExc_TypeError,
        1769                 :            :                      "str file path expected under Windows, got %R",
        1770                 :            :                      Py_TYPE(path));
        1771                 :            :         return NULL;
        1772                 :            :     }
        1773                 :            :
        1774                 :            :     wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL);
        1775                 :            :     if (wpath == NULL)
        1776                 :            :         return NULL;
        1777                 :            :
        1778                 :            :     usize = MultiByteToWideChar(CP_ACP, 0, mode, -1,
        1779                 :            :                                 wmode, Py_ARRAY_LENGTH(wmode));
        1780                 :            :     if (usize == 0) {
        1781                 :            :         PyErr_SetFromWindowsErr(0);
        1782                 :            :         PyMem_Free(wpath);
        1783                 :            :         return NULL;
        1784                 :            :     }
        1785                 :            :
        1786                 :            :     do {
        1787                 :            :         Py_BEGIN_ALLOW_THREADS
        1788                 :            :         f = _wfopen(wpath, wmode);
        1789                 :            :         Py_END_ALLOW_THREADS
        1790                 :            :     } while (f == NULL
        1791                 :            :              && errno == EINTR && !(async_err = PyErr_CheckSignals()));
        1792                 :            :     PyMem_Free(wpath);
        1793                 :            : #else
        1794                 :            :     PyObject *bytes;
        1795                 :            :     const char *path_bytes;
        1796                 :            :
        1797                 :            :     assert(PyGILState_Check());
        1798                 :            :
        1799         [ -  + ]:         22 :     if (!PyUnicode_FSConverter(path, &bytes))
        1800                 :          0 :         return NULL;
        1801                 :         22 :     path_bytes = PyBytes_AS_STRING(bytes);
        1802                 :            :
        1803         [ -  + ]:         22 :     if (PySys_Audit("open", "Osi", path, mode, 0) < 0) {
        1804                 :          0 :         Py_DECREF(bytes);
        1805                 :          0 :         return NULL;
        1806                 :            :     }
        1807                 :            :
        1808                 :            :     do {
        1809                 :         22 :         Py_BEGIN_ALLOW_THREADS
        1810                 :         22 :         f = fopen(path_bytes, mode);
        1811                 :         22 :         Py_END_ALLOW_THREADS
        1812                 :            :     } while (f == NULL
        1813   [ -  +  -  -  :         22 :              && errno == EINTR && !(async_err = PyErr_CheckSignals()));
                       -  - ]
        1814                 :            :
        1815                 :         22 :     Py_DECREF(bytes);
        1816                 :            : #endif
        1817         [ -  + ]:         22 :     if (async_err)
        1818                 :          0 :         return NULL;
        1819                 :            :
        1820         [ -  + ]:         22 :     if (f == NULL) {
        1821                 :          0 :         PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
        1822                 :          0 :         return NULL;
        1823                 :            :     }
        1824                 :            :
        1825         [ -  + ]:         22 :     if (set_inheritable(fileno(f), 0, 1, NULL) < 0) {
        1826                 :          0 :         fclose(f);
        1827                 :          0 :         return NULL;
        1828                 :            :     }
        1829                 :         22 :     return f;
        1830                 :            : }
        1831                 :            :
        1832                 :            : /* Read count bytes from fd into buf.
        1833                 :            :
        1834                 :            :    On success, return the number of read bytes, it can be lower than count.
        1835                 :            :    If the current file offset is at or past the end of file, no bytes are read,
        1836                 :            :    and read() returns zero.
        1837                 :            :
        1838                 :            :    On error, raise an exception, set errno and return -1.
        1839                 :            :
        1840                 :            :    When interrupted by a signal (read() fails with EINTR), retry the syscall.
        1841                 :            :    If the Python signal handler raises an exception, the function returns -1
        1842                 :            :    (the syscall is not retried).
        1843                 :            :
        1844                 :            :    Release the GIL to call read(). The caller must hold the GIL. */
        1845                 :            : Py_ssize_t
        1846                 :       5313 : _Py_read(int fd, void *buf, size_t count)
        1847                 :            : {
        1848                 :            :     Py_ssize_t n;
        1849                 :            :     int err;
        1850                 :       5313 :     int async_err = 0;
        1851                 :            :
        1852                 :            :     assert(PyGILState_Check());
        1853                 :            :
        1854                 :            :     /* _Py_read() must not be called with an exception set, otherwise the
        1855                 :            :      * caller may think that read() was interrupted by a signal and the signal
        1856                 :            :      * handler raised an exception. */
        1857                 :            :     assert(!PyErr_Occurred());
        1858                 :            :
        1859         [ -  + ]:       5313 :     if (count > _PY_READ_MAX) {
        1860                 :          0 :         count = _PY_READ_MAX;
        1861                 :            :     }
        1862                 :            :
        1863                 :            :     _Py_BEGIN_SUPPRESS_IPH
        1864                 :            :     do {
        1865                 :       5313 :         Py_BEGIN_ALLOW_THREADS
        1866                 :       5313 :         errno = 0;
        1867                 :            : #ifdef MS_WINDOWS
        1868                 :            :         _doserrno = 0;
        1869                 :            :         n = read(fd, buf, (int)count);
        1870                 :            :         // read() on a non-blocking empty pipe fails with EINVAL, which is
        1871                 :            :         // mapped from the Windows error code ERROR_NO_DATA.
        1872                 :            :         if (n < 0 && errno == EINVAL) {
        1873                 :            :             if (_doserrno == ERROR_NO_DATA) {
        1874                 :            :                 errno = EAGAIN;
        1875                 :            :             }
        1876                 :            :         }
        1877                 :            : #else
        1878                 :       5313 :         n = read(fd, buf, count);
        1879                 :            : #endif
        1880                 :            :         /* save/restore errno because PyErr_CheckSignals()
        1881                 :            :          * and PyErr_SetFromErrno() can modify it */
        1882                 :       5313 :         err = errno;
        1883                 :       5313 :         Py_END_ALLOW_THREADS
        1884   [ #  #  #  # ]:          0 :     } while (n < 0 && err == EINTR &&
        1885         [ -  + ]:       5313 :             !(async_err = PyErr_CheckSignals()));
        1886                 :            :     _Py_END_SUPPRESS_IPH
        1887                 :            :
        1888         [ -  + ]:       5313 :     if (async_err) {
        1889                 :            :         /* read() was interrupted by a signal (failed with EINTR)
        1890                 :            :          * and the Python signal handler raised an exception */
        1891                 :          0 :         errno = err;
        1892                 :            :         assert(errno == EINTR && PyErr_Occurred());
        1893                 :          0 :         return -1;
        1894                 :            :     }
        1895         [ -  + ]:       5313 :     if (n < 0) {
        1896                 :          0 :         PyErr_SetFromErrno(PyExc_OSError);
        1897                 :          0 :         errno = err;
        1898                 :          0 :         return -1;
        1899                 :            :     }
        1900                 :            :
        1901                 :       5313 :     return n;
        1902                 :            : }
        1903                 :            :
        1904                 :            : static Py_ssize_t
        1905                 :        919 : _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
        1906                 :            : {
        1907                 :            :     Py_ssize_t n;
        1908                 :            :     int err;
        1909                 :        919 :     int async_err = 0;
        1910                 :            :
        1911                 :            :     _Py_BEGIN_SUPPRESS_IPH
        1912                 :            : #ifdef MS_WINDOWS
        1913                 :            :     if (count > 32767) {
        1914                 :            :         /* Issue #11395: the Windows console returns an error (12: not
        1915                 :            :            enough space error) on writing into stdout if stdout mode is
        1916                 :            :            binary and the length is greater than 66,000 bytes (or less,
        1917                 :            :            depending on heap usage). */
        1918                 :            :         if (gil_held) {
        1919                 :            :             Py_BEGIN_ALLOW_THREADS
        1920                 :            :             if (isatty(fd)) {
        1921                 :            :                 count = 32767;
        1922                 :            :             }
        1923                 :            :             Py_END_ALLOW_THREADS
        1924                 :            :         } else {
        1925                 :            :             if (isatty(fd)) {
        1926                 :            :                 count = 32767;
        1927                 :            :             }
        1928                 :            :         }
        1929                 :            :     }
        1930                 :            :
        1931                 :            : #endif
        1932         [ -  + ]:        919 :     if (count > _PY_WRITE_MAX) {
        1933                 :          0 :         count = _PY_WRITE_MAX;
        1934                 :            :     }
        1935                 :            :
        1936         [ +  - ]:        919 :     if (gil_held) {
        1937                 :            :         do {
        1938                 :        919 :             Py_BEGIN_ALLOW_THREADS
        1939                 :        919 :             errno = 0;
        1940                 :            : #ifdef MS_WINDOWS
        1941                 :            :             // write() on a non-blocking pipe fails with ENOSPC on Windows if
        1942                 :            :             // the pipe lacks available space for the entire buffer.
        1943                 :            :             int c = (int)count;
        1944                 :            :             do {
        1945                 :            :                 _doserrno = 0;
        1946                 :            :                 n = write(fd, buf, c);
        1947                 :            :                 if (n >= 0 || errno != ENOSPC || _doserrno != 0) {
        1948                 :            :                     break;
        1949                 :            :                 }
        1950                 :            :                 errno = EAGAIN;
        1951                 :            :                 c /= 2;
        1952                 :            :             } while (c > 0);
        1953                 :            : #else
        1954                 :        919 :             n = write(fd, buf, count);
        1955                 :            : #endif
        1956                 :            :             /* save/restore errno because PyErr_CheckSignals()
        1957                 :            :              * and PyErr_SetFromErrno() can modify it */
        1958                 :        919 :             err = errno;
        1959                 :        919 :             Py_END_ALLOW_THREADS
        1960   [ #  #  #  # ]:          0 :         } while (n < 0 && err == EINTR &&
        1961         [ -  + ]:        919 :                 !(async_err = PyErr_CheckSignals()));
        1962                 :            :     }
        1963                 :            :     else {
        1964                 :            :         do {
        1965                 :          0 :             errno = 0;
        1966                 :            : #ifdef MS_WINDOWS
        1967                 :            :             // write() on a non-blocking pipe fails with ENOSPC on Windows if
        1968                 :            :             // the pipe lacks available space for the entire buffer.
        1969                 :            :             int c = (int)count;
        1970                 :            :             do {
        1971                 :            :                 _doserrno = 0;
        1972                 :            :                 n = write(fd, buf, c);
        1973                 :            :                 if (n >= 0 || errno != ENOSPC || _doserrno != 0) {
        1974                 :            :                     break;
        1975                 :            :                 }
        1976                 :            :                 errno = EAGAIN;
        1977                 :            :                 c /= 2;
        1978                 :            :             } while (c > 0);
        1979                 :            : #else
        1980                 :          0 :             n = write(fd, buf, count);
        1981                 :            : #endif
        1982                 :          0 :             err = errno;
        1983   [ #  #  #  # ]:          0 :         } while (n < 0 && err == EINTR);
        1984                 :            :     }
        1985                 :            :     _Py_END_SUPPRESS_IPH
        1986                 :            :
        1987         [ -  + ]:        919 :     if (async_err) {
        1988                 :            :         /* write() was interrupted by a signal (failed with EINTR)
        1989                 :            :            and the Python signal handler raised an exception (if gil_held is
        1990                 :            :            nonzero). */
        1991                 :          0 :         errno = err;
        1992                 :            :         assert(errno == EINTR && (!gil_held || PyErr_Occurred()));
        1993                 :          0 :         return -1;
        1994                 :            :     }
        1995         [ -  + ]:        919 :     if (n < 0) {
        1996         [ #  # ]:          0 :         if (gil_held)
        1997                 :          0 :             PyErr_SetFromErrno(PyExc_OSError);
        1998                 :          0 :         errno = err;
        1999                 :          0 :         return -1;
        2000                 :            :     }
        2001                 :            :
        2002                 :        919 :     return n;
        2003                 :            : }
        2004                 :            :
        2005                 :            : /* Write count bytes of buf into fd.
        2006                 :            :
        2007                 :            :    On success, return the number of written bytes, it can be lower than count
        2008                 :            :    including 0. On error, raise an exception, set errno and return -1.
        2009                 :            :
        2010                 :            :    When interrupted by a signal (write() fails with EINTR), retry the syscall.
        2011                 :            :    If the Python signal handler raises an exception, the function returns -1
        2012                 :            :    (the syscall is not retried).
        2013                 :            :
        2014                 :            :    Release the GIL to call write(). The caller must hold the GIL. */
        2015                 :            : Py_ssize_t
        2016                 :        919 : _Py_write(int fd, const void *buf, size_t count)
        2017                 :            : {
        2018                 :            :     assert(PyGILState_Check());
        2019                 :            :
        2020                 :            :     /* _Py_write() must not be called with an exception set, otherwise the
        2021                 :            :      * caller may think that write() was interrupted by a signal and the signal
        2022                 :            :      * handler raised an exception. */
        2023                 :            :     assert(!PyErr_Occurred());
        2024                 :            :
        2025                 :        919 :     return _Py_write_impl(fd, buf, count, 1);
        2026                 :            : }
        2027                 :            :
        2028                 :            : /* Write count bytes of buf into fd.
        2029                 :            :  *
        2030                 :            :  * On success, return the number of written bytes, it can be lower than count
        2031                 :            :  * including 0. On error, set errno and return -1.
        2032                 :            :  *
        2033                 :            :  * When interrupted by a signal (write() fails with EINTR), retry the syscall
        2034                 :            :  * without calling the Python signal handler. */
        2035                 :            : Py_ssize_t
        2036                 :          0 : _Py_write_noraise(int fd, const void *buf, size_t count)
        2037                 :            : {
        2038                 :          0 :     return _Py_write_impl(fd, buf, count, 0);
        2039                 :            : }
        2040                 :            :
        2041                 :            : #ifdef HAVE_READLINK
        2042                 :            :
        2043                 :            : /* Read value of symbolic link. Encode the path to the locale encoding, decode
        2044                 :            :    the result from the locale encoding.
        2045                 :            :
        2046                 :            :    Return -1 on encoding error, on readlink() error, if the internal buffer is
        2047                 :            :    too short, on decoding error, or if 'buf' is too short. */
        2048                 :            : int
        2049                 :         47 : _Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t buflen)
        2050                 :            : {
        2051                 :            :     char *cpath;
        2052                 :            :     char cbuf[MAXPATHLEN];
        2053                 :         47 :     size_t cbuf_len = Py_ARRAY_LENGTH(cbuf);
        2054                 :            :     wchar_t *wbuf;
        2055                 :            :     Py_ssize_t res;
        2056                 :            :     size_t r1;
        2057                 :            :
        2058                 :         47 :     cpath = _Py_EncodeLocaleRaw(path, NULL);
        2059         [ -  + ]:         47 :     if (cpath == NULL) {
        2060                 :          0 :         errno = EINVAL;
        2061                 :          0 :         return -1;
        2062                 :            :     }
        2063                 :         47 :     res = readlink(cpath, cbuf, cbuf_len);
        2064                 :         47 :     PyMem_RawFree(cpath);
        2065         [ +  - ]:         47 :     if (res == -1) {
        2066                 :         47 :         return -1;
        2067                 :            :     }
        2068         [ #  # ]:          0 :     if ((size_t)res == cbuf_len) {
        2069                 :          0 :         errno = EINVAL;
        2070                 :          0 :         return -1;
        2071                 :            :     }
        2072                 :          0 :     cbuf[res] = '\0'; /* buf will be null terminated */
        2073                 :          0 :     wbuf = Py_DecodeLocale(cbuf, &r1);
        2074         [ #  # ]:          0 :     if (wbuf == NULL) {
        2075                 :          0 :         errno = EINVAL;
        2076                 :          0 :         return -1;
        2077                 :            :     }
        2078                 :            :     /* wbuf must have space to store the trailing NUL character */
        2079         [ #  # ]:          0 :     if (buflen <= r1) {
        2080                 :          0 :         PyMem_RawFree(wbuf);
        2081                 :          0 :         errno = EINVAL;
        2082                 :          0 :         return -1;
        2083                 :            :     }
        2084                 :          0 :     wcsncpy(buf, wbuf, buflen);
        2085                 :          0 :     PyMem_RawFree(wbuf);
        2086                 :          0 :     return (int)r1;
        2087                 :            : }
        2088                 :            : #endif
        2089                 :            :
        2090                 :            : #ifdef HAVE_REALPATH
        2091                 :            :
        2092                 :            : /* Return the canonicalized absolute pathname. Encode path to the locale
        2093                 :            :    encoding, decode the result from the locale encoding.
        2094                 :            :
        2095                 :            :    Return NULL on encoding error, realpath() error, decoding error
        2096                 :            :    or if 'resolved_path' is too short. */
        2097                 :            : wchar_t*
        2098                 :         22 : _Py_wrealpath(const wchar_t *path,
        2099                 :            :               wchar_t *resolved_path, size_t resolved_path_len)
        2100                 :            : {
        2101                 :            :     char *cpath;
        2102                 :            :     char cresolved_path[MAXPATHLEN];
        2103                 :            :     wchar_t *wresolved_path;
        2104                 :            :     char *res;
        2105                 :            :     size_t r;
        2106                 :         22 :     cpath = _Py_EncodeLocaleRaw(path, NULL);
        2107         [ -  + ]:         22 :     if (cpath == NULL) {
        2108                 :          0 :         errno = EINVAL;
        2109                 :          0 :         return NULL;
        2110                 :            :     }
        2111                 :         22 :     res = realpath(cpath, cresolved_path);
        2112                 :         22 :     PyMem_RawFree(cpath);
        2113         [ -  + ]:         22 :     if (res == NULL)
        2114                 :          0 :         return NULL;
        2115                 :            :
        2116                 :         22 :     wresolved_path = Py_DecodeLocale(cresolved_path, &r);
        2117         [ -  + ]:         22 :     if (wresolved_path == NULL) {
        2118                 :          0 :         errno = EINVAL;
        2119                 :          0 :         return NULL;
        2120                 :            :     }
        2121                 :            :     /* wresolved_path must have space to store the trailing NUL character */
        2122         [ -  + ]:         22 :     if (resolved_path_len <= r) {
        2123                 :          0 :         PyMem_RawFree(wresolved_path);
        2124                 :          0 :         errno = EINVAL;
        2125                 :          0 :         return NULL;
        2126                 :            :     }
        2127                 :         22 :     wcsncpy(resolved_path, wresolved_path, resolved_path_len);
        2128                 :         22 :     PyMem_RawFree(wresolved_path);
        2129                 :         22 :     return resolved_path;
        2130                 :            : }
        2131                 :            : #endif
        2132                 :            :
        2133                 :            :
        2134                 :            : int
        2135                 :        507 : _Py_isabs(const wchar_t *path)
        2136                 :            : {
        2137                 :            : #ifdef MS_WINDOWS
        2138                 :            :     const wchar_t *tail;
        2139                 :            :     HRESULT hr = PathCchSkipRoot(path, &tail);
        2140                 :            :     if (FAILED(hr) || path == tail) {
        2141                 :            :         return 0;
        2142                 :            :     }
        2143                 :            :     if (tail == &path[1] && (path[0] == SEP || path[0] == ALTSEP)) {
        2144                 :            :         // Exclude paths with leading SEP
        2145                 :            :         return 0;
        2146                 :            :     }
        2147                 :            :     if (tail == &path[2] && path[1] == L':') {
        2148                 :            :         // Exclude drive-relative paths (e.g. C:filename.ext)
        2149                 :            :         return 0;
        2150                 :            :     }
        2151                 :            :     return 1;
        2152                 :            : #else
        2153                 :        507 :     return (path[0] == SEP);
        2154                 :            : #endif
        2155                 :            : }
        2156                 :            :
        2157                 :            :
        2158                 :            : /* Get an absolute path.
        2159                 :            :    On error (ex: fail to get the current directory), return -1.
        2160                 :            :    On memory allocation failure, set *abspath_p to NULL and return 0.
        2161                 :            :    On success, return a newly allocated to *abspath_p to and return 0.
        2162                 :            :    The string must be freed by PyMem_RawFree(). */
        2163                 :            : int
        2164                 :         47 : _Py_abspath(const wchar_t *path, wchar_t **abspath_p)
        2165                 :            : {
        2166   [ +  -  -  + ]:         47 :     if (path[0] == '\0' || !wcscmp(path, L".")) {
        2167                 :            :         wchar_t cwd[MAXPATHLEN + 1];
        2168                 :          0 :         cwd[Py_ARRAY_LENGTH(cwd) - 1] = 0;
        2169         [ #  # ]:          0 :         if (!_Py_wgetcwd(cwd, Py_ARRAY_LENGTH(cwd) - 1)) {
        2170                 :            :             /* unable to get the current directory */
        2171                 :          0 :             return -1;
        2172                 :            :         }
        2173                 :          0 :         *abspath_p = _PyMem_RawWcsdup(cwd);
        2174                 :          0 :         return 0;
        2175                 :            :     }
        2176                 :            :
        2177         [ -  + ]:         47 :     if (_Py_isabs(path)) {
        2178                 :          0 :         *abspath_p = _PyMem_RawWcsdup(path);
        2179                 :          0 :         return 0;
        2180                 :            :     }
        2181                 :            :
        2182                 :            : #ifdef MS_WINDOWS
        2183                 :            :     return _PyOS_getfullpathname(path, abspath_p);
        2184                 :            : #else
        2185                 :            :     wchar_t cwd[MAXPATHLEN + 1];
        2186                 :         47 :     cwd[Py_ARRAY_LENGTH(cwd) - 1] = 0;
        2187         [ -  + ]:         47 :     if (!_Py_wgetcwd(cwd, Py_ARRAY_LENGTH(cwd) - 1)) {
        2188                 :            :         /* unable to get the current directory */
        2189                 :          0 :         return -1;
        2190                 :            :     }
        2191                 :            :
        2192                 :         47 :     size_t cwd_len = wcslen(cwd);
        2193                 :         47 :     size_t path_len = wcslen(path);
        2194                 :         47 :     size_t len = cwd_len + 1 + path_len + 1;
        2195         [ +  - ]:         47 :     if (len <= (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) {
        2196                 :         47 :         *abspath_p = PyMem_RawMalloc(len * sizeof(wchar_t));
        2197                 :            :     }
        2198                 :            :     else {
        2199                 :          0 :         *abspath_p = NULL;
        2200                 :            :     }
        2201         [ -  + ]:         47 :     if (*abspath_p == NULL) {
        2202                 :          0 :         return 0;
        2203                 :            :     }
        2204                 :            :
        2205                 :         47 :     wchar_t *abspath = *abspath_p;
        2206                 :         47 :     memcpy(abspath, cwd, cwd_len * sizeof(wchar_t));
        2207                 :         47 :     abspath += cwd_len;
        2208                 :            :
        2209                 :         47 :     *abspath = (wchar_t)SEP;
        2210                 :         47 :     abspath++;
        2211                 :            :
        2212                 :         47 :     memcpy(abspath, path, path_len * sizeof(wchar_t));
        2213                 :         47 :     abspath += path_len;
        2214                 :            :
        2215                 :         47 :     *abspath = 0;
        2216                 :         47 :     return 0;
        2217                 :            : #endif
        2218                 :            : }
        2219                 :            :
        2220                 :            : // The Windows Games API family implements the PathCch* APIs in the Xbox OS,
        2221                 :            : // but does not expose them yet. Load them dynamically until
        2222                 :            : // 1) they are officially exposed
        2223                 :            : // 2) we stop supporting older versions of the GDK which do not expose them
        2224                 :            : #if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP)
        2225                 :            : HRESULT
        2226                 :            : PathCchSkipRoot(const wchar_t *path, const wchar_t **rootEnd)
        2227                 :            : {
        2228                 :            :     static int initialized = 0;
        2229                 :            :     typedef HRESULT(__stdcall *PPathCchSkipRoot) (PCWSTR pszPath,
        2230                 :            :                                                   PCWSTR *ppszRootEnd);
        2231                 :            :     static PPathCchSkipRoot _PathCchSkipRoot;
        2232                 :            :
        2233                 :            :     if (initialized == 0) {
        2234                 :            :         HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL,
        2235                 :            :                                          LOAD_LIBRARY_SEARCH_SYSTEM32);
        2236                 :            :         if (pathapi) {
        2237                 :            :             _PathCchSkipRoot = (PPathCchSkipRoot)GetProcAddress(
        2238                 :            :                 pathapi, "PathCchSkipRoot");
        2239                 :            :         }
        2240                 :            :         else {
        2241                 :            :             _PathCchSkipRoot = NULL;
        2242                 :            :         }
        2243                 :            :         initialized = 1;
        2244                 :            :     }
        2245                 :            :
        2246                 :            :     if (!_PathCchSkipRoot) {
        2247                 :            :         return E_NOINTERFACE;
        2248                 :            :     }
        2249                 :            :
        2250                 :            :     return _PathCchSkipRoot(path, rootEnd);
        2251                 :            : }
        2252                 :            :
        2253                 :            : static HRESULT
        2254                 :            : PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname,
        2255                 :            :                  const wchar_t *relfile, unsigned long flags)
        2256                 :            : {
        2257                 :            :     static int initialized = 0;
        2258                 :            :     typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut,
        2259                 :            :                                                    size_t cchPathOut,
        2260                 :            :                                                    PCWSTR pszPathIn,
        2261                 :            :                                                    PCWSTR pszMore,
        2262                 :            :                                                    unsigned long dwFlags);
        2263                 :            :     static PPathCchCombineEx _PathCchCombineEx;
        2264                 :            :
        2265                 :            :     if (initialized == 0) {
        2266                 :            :         HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL,
        2267                 :            :                                          LOAD_LIBRARY_SEARCH_SYSTEM32);
        2268                 :            :         if (pathapi) {
        2269                 :            :             _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(
        2270                 :            :                 pathapi, "PathCchCombineEx");
        2271                 :            :         }
        2272                 :            :         else {
        2273                 :            :             _PathCchCombineEx = NULL;
        2274                 :            :         }
        2275                 :            :         initialized = 1;
        2276                 :            :     }
        2277                 :            :
        2278                 :            :     if (!_PathCchCombineEx) {
        2279                 :            :         return E_NOINTERFACE;
        2280                 :            :     }
        2281                 :            :
        2282                 :            :     return _PathCchCombineEx(buffer, bufsize, dirname, relfile, flags);
        2283                 :            : }
        2284                 :            :
        2285                 :            : #endif /* defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) */
        2286                 :            :
        2287                 :            : // The caller must ensure "buffer" is big enough.
        2288                 :            : static int
        2289                 :        196 : join_relfile(wchar_t *buffer, size_t bufsize,
        2290                 :            :              const wchar_t *dirname, const wchar_t *relfile)
        2291                 :            : {
        2292                 :            : #ifdef MS_WINDOWS
        2293                 :            :     if (FAILED(PathCchCombineEx(buffer, bufsize, dirname, relfile,
        2294                 :            :         PATHCCH_ALLOW_LONG_PATHS))) {
        2295                 :            :         return -1;
        2296                 :            :     }
        2297                 :            : #else
        2298                 :            :     assert(!_Py_isabs(relfile));
        2299                 :        196 :     size_t dirlen = wcslen(dirname);
        2300                 :        196 :     size_t rellen = wcslen(relfile);
        2301                 :        196 :     size_t maxlen = bufsize - 1;
        2302   [ +  -  +  -  :        196 :     if (maxlen > MAXPATHLEN || dirlen >= maxlen || rellen >= maxlen - dirlen) {
                       -  + ]
        2303                 :          0 :         return -1;
        2304                 :            :     }
        2305         [ -  + ]:        196 :     if (dirlen == 0) {
        2306                 :            :         // We do not add a leading separator.
        2307                 :          0 :         wcscpy(buffer, relfile);
        2308                 :            :     }
        2309                 :            :     else {
        2310         [ -  + ]:        196 :         if (dirname != buffer) {
        2311                 :          0 :             wcscpy(buffer, dirname);
        2312                 :            :         }
        2313                 :        196 :         size_t relstart = dirlen;
        2314   [ +  -  +  - ]:        196 :         if (dirlen > 1 && dirname[dirlen - 1] != SEP) {
        2315                 :        196 :             buffer[dirlen] = SEP;
        2316                 :        196 :             relstart += 1;
        2317                 :            :         }
        2318                 :        196 :         wcscpy(&buffer[relstart], relfile);
        2319                 :            :     }
        2320                 :            : #endif
        2321                 :        196 :     return 0;
        2322                 :            : }
        2323                 :            :
        2324                 :            : /* Join the two paths together, like os.path.join().  Return NULL
        2325                 :            :    if memory could not be allocated.  The caller is responsible
        2326                 :            :    for calling PyMem_RawFree() on the result. */
        2327                 :            : wchar_t *
        2328                 :          0 : _Py_join_relfile(const wchar_t *dirname, const wchar_t *relfile)
        2329                 :            : {
        2330                 :            :     assert(dirname != NULL && relfile != NULL);
        2331                 :            : #ifndef MS_WINDOWS
        2332                 :            :     assert(!_Py_isabs(relfile));
        2333                 :            : #endif
        2334                 :          0 :     size_t maxlen = wcslen(dirname) + 1 + wcslen(relfile);
        2335                 :          0 :     size_t bufsize = maxlen + 1;
        2336                 :          0 :     wchar_t *filename = PyMem_RawMalloc(bufsize * sizeof(wchar_t));
        2337         [ #  # ]:          0 :     if (filename == NULL) {
        2338                 :          0 :         return NULL;
        2339                 :            :     }
        2340                 :            :     assert(wcslen(dirname) < MAXPATHLEN);
        2341                 :            :     assert(wcslen(relfile) < MAXPATHLEN - wcslen(dirname));
        2342         [ #  # ]:          0 :     if (join_relfile(filename, bufsize, dirname, relfile) < 0) {
        2343                 :          0 :         PyMem_RawFree(filename);
        2344                 :          0 :         return NULL;
        2345                 :            :     }
        2346                 :          0 :     return filename;
        2347                 :            : }
        2348                 :            :
        2349                 :            : /* Join the two paths together, like os.path.join().
        2350                 :            :      dirname: the target buffer with the dirname already in place,
        2351                 :            :               including trailing NUL
        2352                 :            :      relfile: this must be a relative path
        2353                 :            :      bufsize: total allocated size of the buffer
        2354                 :            :    Return -1 if anything is wrong with the path lengths. */
        2355                 :            : int
        2356                 :        196 : _Py_add_relfile(wchar_t *dirname, const wchar_t *relfile, size_t bufsize)
        2357                 :            : {
        2358                 :            :     assert(dirname != NULL && relfile != NULL);
        2359                 :            :     assert(bufsize > 0);
        2360                 :        196 :     return join_relfile(dirname, bufsize, dirname, relfile);
        2361                 :            : }
        2362                 :            :
        2363                 :            :
        2364                 :            : size_t
        2365                 :          0 : _Py_find_basename(const wchar_t *filename)
        2366                 :            : {
        2367         [ #  # ]:          0 :     for (size_t i = wcslen(filename); i > 0; --i) {
        2368         [ #  # ]:          0 :         if (filename[i] == SEP) {
        2369                 :          0 :             return i + 1;
        2370                 :            :         }
        2371                 :            :     }
        2372                 :          0 :     return 0;
        2373                 :            : }
        2374                 :            :
        2375                 :            : /* In-place path normalisation. Returns the start of the normalized
        2376                 :            :    path, which will be within the original buffer. Guaranteed to not
        2377                 :            :    make the path longer, and will not fail. 'size' is the length of
        2378                 :            :    the path, if known. If -1, the first null character will be assumed
        2379                 :            :    to be the end of the path. */
        2380                 :            : wchar_t *
        2381                 :        495 : _Py_normpath(wchar_t *path, Py_ssize_t size)
        2382                 :            : {
        2383                 :            :     assert(path != NULL);
        2384   [ +  -  -  + ]:        495 :     if (!path[0] || size == 0) {
        2385                 :          0 :         return path;
        2386                 :            :     }
        2387         [ +  + ]:        495 :     wchar_t *pEnd = size >= 0 ? &path[size] : NULL;
        2388                 :        495 :     wchar_t *p1 = path;     // sequentially scanned address in the path
        2389                 :        495 :     wchar_t *p2 = path;     // destination of a scanned character to be ljusted
        2390                 :        495 :     wchar_t *minP2 = path;  // the beginning of the destination range
        2391                 :        495 :     wchar_t lastC = L'\0';  // the last ljusted character, p2[-1] in most cases
        2392                 :            :
        2393                 :            : #define IS_END(x) (pEnd ? (x) == pEnd : !*(x))
        2394                 :            : #ifdef ALTSEP
        2395                 :            : #define IS_SEP(x) (*(x) == SEP || *(x) == ALTSEP)
        2396                 :            : #else
        2397                 :            : #define IS_SEP(x) (*(x) == SEP)
        2398                 :            : #endif
        2399                 :            : #define SEP_OR_END(x) (IS_SEP(x) || IS_END(x))
        2400                 :            :
        2401                 :            :     // Skip leading '.\'
        2402   [ +  +  +  - ]:        495 :     if (p1[0] == L'.' && IS_SEP(&p1[1])) {
        2403                 :         25 :         path = &path[2];
        2404   [ -  +  -  -  :         25 :         while (IS_SEP(path) && !IS_END(path)) {
                 -  -  -  - ]
        2405                 :          0 :             path++;
        2406                 :            :         }
        2407                 :         25 :         p1 = p2 = minP2 = path;
        2408                 :         25 :         lastC = SEP;
        2409                 :            :     }
        2410                 :            : #ifdef MS_WINDOWS
        2411                 :            :     // Skip past drive segment and update minP2
        2412                 :            :     else if (p1[0] && p1[1] == L':') {
        2413                 :            :         *p2++ = *p1++;
        2414                 :            :         *p2++ = *p1++;
        2415                 :            :         minP2 = p2;
        2416                 :            :         lastC = L':';
        2417                 :            :     }
        2418                 :            :     // Skip past all \\-prefixed paths, including \\?\, \\.\,
        2419                 :            :     // and network paths, including the first segment.
        2420                 :            :     else if (IS_SEP(&p1[0]) && IS_SEP(&p1[1])) {
        2421                 :            :         int sepCount = 2;
        2422                 :            :         *p2++ = SEP;
        2423                 :            :         *p2++ = SEP;
        2424                 :            :         p1 += 2;
        2425                 :            :         for (; !IS_END(p1) && sepCount; ++p1) {
        2426                 :            :             if (IS_SEP(p1)) {
        2427                 :            :                 --sepCount;
        2428                 :            :                 *p2++ = lastC = SEP;
        2429                 :            :             } else {
        2430                 :            :                 *p2++ = lastC = *p1;
        2431                 :            :             }
        2432                 :            :         }
        2433                 :            :         if (sepCount) {
        2434                 :            :             minP2 = p2;      // Invalid path
        2435                 :            :         } else {
        2436                 :            :             minP2 = p2 - 1;  // Absolute path has SEP at minP2
        2437                 :            :         }
        2438                 :            :     }
        2439                 :            : #else
        2440                 :            :     // Skip past two leading SEPs
        2441   [ +  +  -  +  :        470 :     else if (IS_SEP(&p1[0]) && IS_SEP(&p1[1]) && !IS_SEP(&p1[2])) {
                       -  - ]
        2442                 :          0 :         *p2++ = *p1++;
        2443                 :          0 :         *p2++ = *p1++;
        2444                 :          0 :         minP2 = p2 - 1;  // Absolute path has SEP at minP2
        2445                 :          0 :         lastC = SEP;
        2446                 :            :     }
        2447                 :            : #endif /* MS_WINDOWS */
        2448                 :            :
        2449                 :            :     /* if pEnd is specified, check that. Else, check for null terminator */
        2450   [ +  +  +  + ]:      17100 :     for (; !IS_END(p1); ++p1) {
        2451                 :      16605 :         wchar_t c = *p1;
        2452                 :            : #ifdef ALTSEP
        2453                 :            :         if (c == ALTSEP) {
        2454                 :            :             c = SEP;
        2455                 :            :         }
        2456                 :            : #endif
        2457         [ +  + ]:      16605 :         if (lastC == SEP) {
        2458         [ -  + ]:       2563 :             if (c == L'.') {
        2459   [ #  #  #  #  :          0 :                 int sep_at_1 = SEP_OR_END(&p1[1]);
                 #  #  #  # ]
        2460   [ #  #  #  #  :          0 :                 int sep_at_2 = !sep_at_1 && SEP_OR_END(&p1[2]);
              #  #  #  #  #
                          # ]
        2461   [ #  #  #  # ]:          0 :                 if (sep_at_2 && p1[1] == L'.') {
        2462                 :          0 :                     wchar_t *p3 = p2;
        2463   [ #  #  #  # ]:          0 :                     while (p3 != minP2 && *--p3 == SEP) { }
        2464   [ #  #  #  # ]:          0 :                     while (p3 != minP2 && *(p3 - 1) != SEP) { --p3; }
        2465         [ #  # ]:          0 :                     if (p2 == minP2
        2466   [ #  #  #  #  :          0 :                         || (p3[0] == L'.' && p3[1] == L'.' && IS_SEP(&p3[2])))
                       #  # ]
        2467                 :            :                     {
        2468                 :            :                         // Previous segment is also ../, so append instead.
        2469                 :            :                         // Relative path does not absorb ../ at minP2 as well.
        2470                 :          0 :                         *p2++ = L'.';
        2471                 :          0 :                         *p2++ = L'.';
        2472                 :          0 :                         lastC = L'.';
        2473         [ #  # ]:          0 :                     } else if (p3[0] == SEP) {
        2474                 :            :                         // Absolute path, so absorb segment
        2475                 :          0 :                         p2 = p3 + 1;
        2476                 :            :                     } else {
        2477                 :          0 :                         p2 = p3;
        2478                 :            :                     }
        2479                 :          0 :                     p1 += 1;
        2480         [ #  # ]:          0 :                 } else if (sep_at_1) {
        2481                 :            :                 } else {
        2482                 :          0 :                     *p2++ = lastC = c;
        2483                 :            :                 }
        2484         [ +  - ]:       2563 :             } else if (c == SEP) {
        2485                 :            :             } else {
        2486                 :       2563 :                 *p2++ = lastC = c;
        2487                 :            :             }
        2488                 :            :         } else {
        2489                 :      14042 :             *p2++ = lastC = c;
        2490                 :            :         }
        2491                 :            :     }
        2492                 :        495 :     *p2 = L'\0';
        2493         [ +  - ]:        495 :     if (p2 != minP2) {
        2494   [ +  -  -  + ]:        495 :         while (--p2 != minP2 && *p2 == SEP) {
        2495                 :          0 :             *p2 = L'\0';
        2496                 :            :         }
        2497                 :            :     }
        2498                 :            : #undef SEP_OR_END
        2499                 :            : #undef IS_SEP
        2500                 :            : #undef IS_END
        2501                 :        495 :     return path;
        2502                 :            : }
        2503                 :            :
        2504                 :            :
        2505                 :            : /* Get the current directory. buflen is the buffer size in wide characters
        2506                 :            :    including the null character. Decode the path from the locale encoding.
        2507                 :            :
        2508                 :            :    Return NULL on getcwd() error, on decoding error, or if 'buf' is
        2509                 :            :    too short. */
        2510                 :            : wchar_t*
        2511                 :         49 : _Py_wgetcwd(wchar_t *buf, size_t buflen)
        2512                 :            : {
        2513                 :            : #ifdef MS_WINDOWS
        2514                 :            :     int ibuflen = (int)Py_MIN(buflen, INT_MAX);
        2515                 :            :     return _wgetcwd(buf, ibuflen);
        2516                 :            : #else
        2517                 :            :     char fname[MAXPATHLEN];
        2518                 :            :     wchar_t *wname;
        2519                 :            :     size_t len;
        2520                 :            :
        2521         [ -  + ]:         49 :     if (getcwd(fname, Py_ARRAY_LENGTH(fname)) == NULL)
        2522                 :          0 :         return NULL;
        2523                 :         49 :     wname = Py_DecodeLocale(fname, &len);
        2524         [ -  + ]:         49 :     if (wname == NULL)
        2525                 :          0 :         return NULL;
        2526                 :            :     /* wname must have space to store the trailing NUL character */
        2527         [ -  + ]:         49 :     if (buflen <= len) {
        2528                 :          0 :         PyMem_RawFree(wname);
        2529                 :          0 :         return NULL;
        2530                 :            :     }
        2531                 :         49 :     wcsncpy(buf, wname, buflen);
        2532                 :         49 :     PyMem_RawFree(wname);
        2533                 :         49 :     return buf;
        2534                 :            : #endif
        2535                 :            : }
        2536                 :            :
        2537                 :            : /* Duplicate a file descriptor. The new file descriptor is created as
        2538                 :            :    non-inheritable. Return a new file descriptor on success, raise an OSError
        2539                 :            :    exception and return -1 on error.
        2540                 :            :
        2541                 :            :    The GIL is released to call dup(). The caller must hold the GIL. */
        2542                 :            : int
        2543                 :          1 : _Py_dup(int fd)
        2544                 :            : {
        2545                 :            : #ifdef MS_WINDOWS
        2546                 :            :     HANDLE handle;
        2547                 :            : #endif
        2548                 :            :
        2549                 :            :     assert(PyGILState_Check());
        2550                 :            :
        2551                 :            : #ifdef MS_WINDOWS
        2552                 :            :     handle = _Py_get_osfhandle(fd);
        2553                 :            :     if (handle == INVALID_HANDLE_VALUE)
        2554                 :            :         return -1;
        2555                 :            :
        2556                 :            :     Py_BEGIN_ALLOW_THREADS
        2557                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2558                 :            :     fd = dup(fd);
        2559                 :            :     _Py_END_SUPPRESS_IPH
        2560                 :            :     Py_END_ALLOW_THREADS
        2561                 :            :     if (fd < 0) {
        2562                 :            :         PyErr_SetFromErrno(PyExc_OSError);
        2563                 :            :         return -1;
        2564                 :            :     }
        2565                 :            :
        2566                 :            :     if (_Py_set_inheritable(fd, 0, NULL) < 0) {
        2567                 :            :         _Py_BEGIN_SUPPRESS_IPH
        2568                 :            :         close(fd);
        2569                 :            :         _Py_END_SUPPRESS_IPH
        2570                 :            :         return -1;
        2571                 :            :     }
        2572                 :            : #elif defined(HAVE_FCNTL_H) && defined(F_DUPFD_CLOEXEC)
        2573                 :          1 :     Py_BEGIN_ALLOW_THREADS
        2574                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2575                 :          1 :     fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
        2576                 :            :     _Py_END_SUPPRESS_IPH
        2577                 :          1 :     Py_END_ALLOW_THREADS
        2578         [ -  + ]:          1 :     if (fd < 0) {
        2579                 :          0 :         PyErr_SetFromErrno(PyExc_OSError);
        2580                 :          0 :         return -1;
        2581                 :            :     }
        2582                 :            :
        2583                 :            : #elif HAVE_DUP
        2584                 :            :     Py_BEGIN_ALLOW_THREADS
        2585                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2586                 :            :     fd = dup(fd);
        2587                 :            :     _Py_END_SUPPRESS_IPH
        2588                 :            :     Py_END_ALLOW_THREADS
        2589                 :            :     if (fd < 0) {
        2590                 :            :         PyErr_SetFromErrno(PyExc_OSError);
        2591                 :            :         return -1;
        2592                 :            :     }
        2593                 :            :
        2594                 :            :     if (_Py_set_inheritable(fd, 0, NULL) < 0) {
        2595                 :            :         _Py_BEGIN_SUPPRESS_IPH
        2596                 :            :         close(fd);
        2597                 :            :         _Py_END_SUPPRESS_IPH
        2598                 :            :         return -1;
        2599                 :            :     }
        2600                 :            : #else
        2601                 :            :     errno = ENOTSUP;
        2602                 :            :     PyErr_SetFromErrno(PyExc_OSError);
        2603                 :            :     return -1;
        2604                 :            : #endif
        2605                 :          1 :     return fd;
        2606                 :            : }
        2607                 :            :
        2608                 :            : #ifndef MS_WINDOWS
        2609                 :            : /* Get the blocking mode of the file descriptor.
        2610                 :            :    Return 0 if the O_NONBLOCK flag is set, 1 if the flag is cleared,
        2611                 :            :    raise an exception and return -1 on error. */
        2612                 :            : int
        2613                 :          0 : _Py_get_blocking(int fd)
        2614                 :            : {
        2615                 :            :     int flags;
        2616                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2617                 :          0 :     flags = fcntl(fd, F_GETFL, 0);
        2618                 :            :     _Py_END_SUPPRESS_IPH
        2619         [ #  # ]:          0 :     if (flags < 0) {
        2620                 :          0 :         PyErr_SetFromErrno(PyExc_OSError);
        2621                 :          0 :         return -1;
        2622                 :            :     }
        2623                 :            :
        2624                 :          0 :     return !(flags & O_NONBLOCK);
        2625                 :            : }
        2626                 :            :
        2627                 :            : /* Set the blocking mode of the specified file descriptor.
        2628                 :            :
        2629                 :            :    Set the O_NONBLOCK flag if blocking is False, clear the O_NONBLOCK flag
        2630                 :            :    otherwise.
        2631                 :            :
        2632                 :            :    Return 0 on success, raise an exception and return -1 on error. */
        2633                 :            : int
        2634                 :          0 : _Py_set_blocking(int fd, int blocking)
        2635                 :            : {
        2636                 :            : /* bpo-41462: On VxWorks, ioctl(FIONBIO) only works on sockets.
        2637                 :            :    Use fcntl() instead. */
        2638                 :            : #if defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO) && !defined(__VXWORKS__)
        2639                 :          0 :     int arg = !blocking;
        2640         [ #  # ]:          0 :     if (ioctl(fd, FIONBIO, &arg) < 0)
        2641                 :          0 :         goto error;
        2642                 :            : #else
        2643                 :            :     int flags, res;
        2644                 :            :
        2645                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2646                 :            :     flags = fcntl(fd, F_GETFL, 0);
        2647                 :            :     if (flags >= 0) {
        2648                 :            :         if (blocking)
        2649                 :            :             flags = flags & (~O_NONBLOCK);
        2650                 :            :         else
        2651                 :            :             flags = flags | O_NONBLOCK;
        2652                 :            :
        2653                 :            :         res = fcntl(fd, F_SETFL, flags);
        2654                 :            :     } else {
        2655                 :            :         res = -1;
        2656                 :            :     }
        2657                 :            :     _Py_END_SUPPRESS_IPH
        2658                 :            :
        2659                 :            :     if (res < 0)
        2660                 :            :         goto error;
        2661                 :            : #endif
        2662                 :          0 :     return 0;
        2663                 :            :
        2664                 :          0 : error:
        2665                 :          0 :     PyErr_SetFromErrno(PyExc_OSError);
        2666                 :          0 :     return -1;
        2667                 :            : }
        2668                 :            : #else   /* MS_WINDOWS */
        2669                 :            : int
        2670                 :            : _Py_get_blocking(int fd)
        2671                 :            : {
        2672                 :            :     HANDLE handle;
        2673                 :            :     DWORD mode;
        2674                 :            :     BOOL success;
        2675                 :            :
        2676                 :            :     handle = _Py_get_osfhandle(fd);
        2677                 :            :     if (handle == INVALID_HANDLE_VALUE) {
        2678                 :            :         return -1;
        2679                 :            :     }
        2680                 :            :
        2681                 :            :     Py_BEGIN_ALLOW_THREADS
        2682                 :            :     success = GetNamedPipeHandleStateW(handle, &mode,
        2683                 :            :                                        NULL, NULL, NULL, NULL, 0);
        2684                 :            :     Py_END_ALLOW_THREADS
        2685                 :            :
        2686                 :            :     if (!success) {
        2687                 :            :         PyErr_SetFromWindowsErr(0);
        2688                 :            :         return -1;
        2689                 :            :     }
        2690                 :            :
        2691                 :            :     return !(mode & PIPE_NOWAIT);
        2692                 :            : }
        2693                 :            :
        2694                 :            : int
        2695                 :            : _Py_set_blocking(int fd, int blocking)
        2696                 :            : {
        2697                 :            :     HANDLE handle;
        2698                 :            :     DWORD mode;
        2699                 :            :     BOOL success;
        2700                 :            :
        2701                 :            :     handle = _Py_get_osfhandle(fd);
        2702                 :            :     if (handle == INVALID_HANDLE_VALUE) {
        2703                 :            :         return -1;
        2704                 :            :     }
        2705                 :            :
        2706                 :            :     Py_BEGIN_ALLOW_THREADS
        2707                 :            :     success = GetNamedPipeHandleStateW(handle, &mode,
        2708                 :            :                                        NULL, NULL, NULL, NULL, 0);
        2709                 :            :     if (success) {
        2710                 :            :         if (blocking) {
        2711                 :            :             mode &= ~PIPE_NOWAIT;
        2712                 :            :         }
        2713                 :            :         else {
        2714                 :            :             mode |= PIPE_NOWAIT;
        2715                 :            :         }
        2716                 :            :         success = SetNamedPipeHandleState(handle, &mode, NULL, NULL);
        2717                 :            :     }
        2718                 :            :     Py_END_ALLOW_THREADS
        2719                 :            :
        2720                 :            :     if (!success) {
        2721                 :            :         PyErr_SetFromWindowsErr(0);
        2722                 :            :         return -1;
        2723                 :            :     }
        2724                 :            :     return 0;
        2725                 :            : }
        2726                 :            :
        2727                 :            : void*
        2728                 :            : _Py_get_osfhandle_noraise(int fd)
        2729                 :            : {
        2730                 :            :     void *handle;
        2731                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2732                 :            :     handle = (void*)_get_osfhandle(fd);
        2733                 :            :     _Py_END_SUPPRESS_IPH
        2734                 :            :     return handle;
        2735                 :            : }
        2736                 :            :
        2737                 :            : void*
        2738                 :            : _Py_get_osfhandle(int fd)
        2739                 :            : {
        2740                 :            :     void *handle = _Py_get_osfhandle_noraise(fd);
        2741                 :            :     if (handle == INVALID_HANDLE_VALUE)
        2742                 :            :         PyErr_SetFromErrno(PyExc_OSError);
        2743                 :            :
        2744                 :            :     return handle;
        2745                 :            : }
        2746                 :            :
        2747                 :            : int
        2748                 :            : _Py_open_osfhandle_noraise(void *handle, int flags)
        2749                 :            : {
        2750                 :            :     int fd;
        2751                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2752                 :            :     fd = _open_osfhandle((intptr_t)handle, flags);
        2753                 :            :     _Py_END_SUPPRESS_IPH
        2754                 :            :     return fd;
        2755                 :            : }
        2756                 :            :
        2757                 :            : int
        2758                 :            : _Py_open_osfhandle(void *handle, int flags)
        2759                 :            : {
        2760                 :            :     int fd = _Py_open_osfhandle_noraise(handle, flags);
        2761                 :            :     if (fd == -1)
        2762                 :            :         PyErr_SetFromErrno(PyExc_OSError);
        2763                 :            :
        2764                 :            :     return fd;
        2765                 :            : }
        2766                 :            : #endif  /* MS_WINDOWS */
        2767                 :            :
        2768                 :            : int
        2769                 :          0 : _Py_GetLocaleconvNumeric(struct lconv *lc,
        2770                 :            :                          PyObject **decimal_point, PyObject **thousands_sep)
        2771                 :            : {
        2772                 :            :     assert(decimal_point != NULL);
        2773                 :            :     assert(thousands_sep != NULL);
        2774                 :            :
        2775                 :            : #ifndef MS_WINDOWS
        2776                 :          0 :     int change_locale = 0;
        2777   [ #  #  #  # ]:          0 :     if ((strlen(lc->decimal_point) > 1 || ((unsigned char)lc->decimal_point[0]) > 127)) {
        2778                 :          0 :         change_locale = 1;
        2779                 :            :     }
        2780   [ #  #  #  # ]:          0 :     if ((strlen(lc->thousands_sep) > 1 || ((unsigned char)lc->thousands_sep[0]) > 127)) {
        2781                 :          0 :         change_locale = 1;
        2782                 :            :     }
        2783                 :            :
        2784                 :            :     /* Keep a copy of the LC_CTYPE locale */
        2785                 :          0 :     char *oldloc = NULL, *loc = NULL;
        2786         [ #  # ]:          0 :     if (change_locale) {
        2787                 :          0 :         oldloc = setlocale(LC_CTYPE, NULL);
        2788         [ #  # ]:          0 :         if (!oldloc) {
        2789                 :          0 :             PyErr_SetString(PyExc_RuntimeWarning,
        2790                 :            :                             "failed to get LC_CTYPE locale");
        2791                 :          0 :             return -1;
        2792                 :            :         }
        2793                 :            :
        2794                 :          0 :         oldloc = _PyMem_Strdup(oldloc);
        2795         [ #  # ]:          0 :         if (!oldloc) {
        2796                 :          0 :             PyErr_NoMemory();
        2797                 :          0 :             return -1;
        2798                 :            :         }
        2799                 :            :
        2800                 :          0 :         loc = setlocale(LC_NUMERIC, NULL);
        2801   [ #  #  #  # ]:          0 :         if (loc != NULL && strcmp(loc, oldloc) == 0) {
        2802                 :          0 :             loc = NULL;
        2803                 :            :         }
        2804                 :            :
        2805         [ #  # ]:          0 :         if (loc != NULL) {
        2806                 :            :             /* Only set the locale temporarily the LC_CTYPE locale
        2807                 :            :                if LC_NUMERIC locale is different than LC_CTYPE locale and
        2808                 :            :                decimal_point and/or thousands_sep are non-ASCII or longer than
        2809                 :            :                1 byte */
        2810                 :          0 :             setlocale(LC_CTYPE, loc);
        2811                 :            :         }
        2812                 :            :     }
        2813                 :            :
        2814                 :            : #define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL)
        2815                 :            : #else /* MS_WINDOWS */
        2816                 :            : /* Use _W_* fields of Windows strcut lconv */
        2817                 :            : #define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1)
        2818                 :            : #endif /* MS_WINDOWS */
        2819                 :            :
        2820                 :          0 :     int res = -1;
        2821                 :            :
        2822                 :          0 :     *decimal_point = GET_LOCALE_STRING(decimal_point);
        2823         [ #  # ]:          0 :     if (*decimal_point == NULL) {
        2824                 :          0 :         goto done;
        2825                 :            :     }
        2826                 :            :
        2827                 :          0 :     *thousands_sep = GET_LOCALE_STRING(thousands_sep);
        2828         [ #  # ]:          0 :     if (*thousands_sep == NULL) {
        2829                 :          0 :         goto done;
        2830                 :            :     }
        2831                 :            :
        2832                 :          0 :     res = 0;
        2833                 :            :
        2834                 :          0 : done:
        2835                 :            : #ifndef MS_WINDOWS
        2836         [ #  # ]:          0 :     if (loc != NULL) {
        2837                 :          0 :         setlocale(LC_CTYPE, oldloc);
        2838                 :            :     }
        2839                 :          0 :     PyMem_Free(oldloc);
        2840                 :            : #endif
        2841                 :          0 :     return res;
        2842                 :            :
        2843                 :            : #undef GET_LOCALE_STRING
        2844                 :            : }
        2845                 :            :
        2846                 :            : /* Our selection logic for which function to use is as follows:
        2847                 :            :  * 1. If close_range(2) is available, always prefer that; it's better for
        2848                 :            :  *    contiguous ranges like this than fdwalk(3) which entails iterating over
        2849                 :            :  *    the entire fd space and simply doing nothing for those outside the range.
        2850                 :            :  * 2. If closefrom(2) is available, we'll attempt to use that next if we're
        2851                 :            :  *    closing up to sysconf(_SC_OPEN_MAX).
        2852                 :            :  * 2a. Fallback to fdwalk(3) if we're not closing up to sysconf(_SC_OPEN_MAX),
        2853                 :            :  *    as that will be more performant if the range happens to have any chunk of
        2854                 :            :  *    non-opened fd in the middle.
        2855                 :            :  * 2b. If fdwalk(3) isn't available, just do a plain close(2) loop.
        2856                 :            :  */
        2857                 :            : #ifdef __FreeBSD__
        2858                 :            : #  define USE_CLOSEFROM
        2859                 :            : #endif /* __FreeBSD__ */
        2860                 :            :
        2861                 :            : #ifdef HAVE_FDWALK
        2862                 :            : #  define USE_FDWALK
        2863                 :            : #endif /* HAVE_FDWALK */
        2864                 :            :
        2865                 :            : #ifdef USE_FDWALK
        2866                 :            : static int
        2867                 :            : _fdwalk_close_func(void *lohi, int fd)
        2868                 :            : {
        2869                 :            :     int lo = ((int *)lohi)[0];
        2870                 :            :     int hi = ((int *)lohi)[1];
        2871                 :            :
        2872                 :            :     if (fd >= hi) {
        2873                 :            :         return 1;
        2874                 :            :     }
        2875                 :            :     else if (fd >= lo) {
        2876                 :            :         /* Ignore errors */
        2877                 :            :         (void)close(fd);
        2878                 :            :     }
        2879                 :            :     return 0;
        2880                 :            : }
        2881                 :            : #endif /* USE_FDWALK */
        2882                 :            :
        2883                 :            : /* Closes all file descriptors in [first, last], ignoring errors. */
        2884                 :            : void
        2885                 :          0 : _Py_closerange(int first, int last)
        2886                 :            : {
        2887                 :          0 :     first = Py_MAX(first, 0);
        2888                 :            :     _Py_BEGIN_SUPPRESS_IPH
        2889                 :            : #ifdef HAVE_CLOSE_RANGE
        2890                 :            :     if (close_range(first, last, 0) == 0) {
        2891                 :            :         /* close_range() ignores errors when it closes file descriptors.
        2892                 :            :          * Possible reasons of an error return are lack of kernel support
        2893                 :            :          * or denial of the underlying syscall by a seccomp sandbox on Linux.
        2894                 :            :          * Fallback to other methods in case of any error. */
        2895                 :            :     }
        2896                 :            :     else
        2897                 :            : #endif /* HAVE_CLOSE_RANGE */
        2898                 :            : #ifdef USE_CLOSEFROM
        2899                 :            :     if (last >= sysconf(_SC_OPEN_MAX)) {
        2900                 :            :         /* Any errors encountered while closing file descriptors are ignored */
        2901                 :            :         closefrom(first);
        2902                 :            :     }
        2903                 :            :     else
        2904                 :            : #endif /* USE_CLOSEFROM */
        2905                 :            : #ifdef USE_FDWALK
        2906                 :            :     {
        2907                 :            :         int lohi[2];
        2908                 :            :         lohi[0] = first;
        2909                 :            :         lohi[1] = last + 1;
        2910                 :            :         fdwalk(_fdwalk_close_func, lohi);
        2911                 :            :     }
        2912                 :            : #else
        2913                 :            :     {
        2914         [ #  # ]:          0 :         for (int i = first; i <= last; i++) {
        2915                 :            :             /* Ignore errors */
        2916                 :          0 :             (void)close(i);
        2917                 :            :         }
        2918                 :            :     }
        2919                 :            : #endif /* USE_FDWALK */
        2920                 :            :     _Py_END_SUPPRESS_IPH
        2921                 :          0 : }

Generated by: LCOV version 1.14