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