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 : }
|