Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1)

Delta Between Two Patch Sets: Modules/posixmodule.c

Issue 26826: Expose new copy_file_range() syscal in os module and use it to improve shutils.copy()
Left Patch Set: Created 3 years, 7 months ago
Right Patch Set: Created 3 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/test_os.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 1
2 /* POSIX module implementation */ 2 /* POSIX module implementation */
3 3
4 /* This file is also used for Windows NT/MS-Win. In that case the 4 /* This file is also used for Windows NT/MS-Win. In that case the
5 module actually calls itself 'nt', not 'posix', and a few 5 module actually calls itself 'nt', not 'posix', and a few
6 functions are either unimplemented or implemented differently. The source 6 functions are either unimplemented or implemented differently. The source
7 assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent 7 assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent
8 of the compiler used. Different compilers define their own feature 8 of the compiler used. Different compilers define their own feature
9 test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */ 9 test macro, e.g. '_MSC_VER'. */
10 10
11 11
12 12
13 #ifdef __APPLE__ 13 #ifdef __APPLE__
14 /* 14 /*
15 * Step 1 of support for weak-linking a number of symbols existing on 15 * Step 1 of support for weak-linking a number of symbols existing on
16 * OSX 10.4 and later, see the comment in the #ifdef __APPLE__ block 16 * OSX 10.4 and later, see the comment in the #ifdef __APPLE__ block
17 * at the end of this file for more information. 17 * at the end of this file for more information.
18 */ 18 */
19 # pragma weak lchown 19 # pragma weak lchown
20 # pragma weak statvfs 20 # pragma weak statvfs
21 # pragma weak fstatvfs 21 # pragma weak fstatvfs
22 22
23 #endif /* __APPLE__ */ 23 #endif /* __APPLE__ */
24 24
25 #define PY_SSIZE_T_CLEAN 25 #define PY_SSIZE_T_CLEAN
26 26
27 #include "Python.h" 27 #include "Python.h"
28 #include "structmember.h"
28 #ifndef MS_WINDOWS 29 #ifndef MS_WINDOWS
29 #include "posixmodule.h" 30 #include "posixmodule.h"
30 #endif 31 #else
32 #include "winreparse.h"
33 #endif
34
35 /* On android API level 21, 'AT_EACCESS' is not declared although
36 * HAVE_FACCESSAT is defined. */
37 #ifdef __ANDROID__
38 #undef HAVE_FACCESSAT
39 #endif
40
41 #include <stdio.h> /* needed for ctermid() */
31 42
32 #ifdef __cplusplus 43 #ifdef __cplusplus
33 extern "C" { 44 extern "C" {
34 #endif 45 #endif
35 46
36 PyDoc_STRVAR(posix__doc__, 47 PyDoc_STRVAR(posix__doc__,
37 "This module provides access to operating system functionality that is\n\ 48 "This module provides access to operating system functionality that is\n\
38 standardized by the C Standard and the POSIX standard (a thinly\n\ 49 standardized by the C Standard and the POSIX standard (a thinly\n\
39 disguised Unix interface). Refer to the library manual and\n\ 50 disguised Unix interface). Refer to the library manual and\n\
40 corresponding Unix manual entries for more information on calls."); 51 corresponding Unix manual entries for more information on calls.");
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 # define TERMSIZE_USE_IOCTL 149 # define TERMSIZE_USE_IOCTL
139 # endif 150 # endif
140 #endif /* MS_WINDOWS */ 151 #endif /* MS_WINDOWS */
141 152
142 /* Various compilers have only certain posix functions */ 153 /* Various compilers have only certain posix functions */
143 /* XXX Gosh I wish these were all moved into pyconfig.h */ 154 /* XXX Gosh I wish these were all moved into pyconfig.h */
144 #if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */ 155 #if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */
145 #define HAVE_OPENDIR 1 156 #define HAVE_OPENDIR 1
146 #define HAVE_SYSTEM 1 157 #define HAVE_SYSTEM 1
147 #include <process.h> 158 #include <process.h>
148 #else
149 #ifdef __BORLANDC__ /* Borland compiler */
150 #define HAVE_EXECV 1
151 #define HAVE_OPENDIR 1
152 #define HAVE_PIPE 1
153 #define HAVE_SYSTEM 1
154 #define HAVE_WAIT 1
155 #else 159 #else
156 #ifdef _MSC_VER /* Microsoft compiler */ 160 #ifdef _MSC_VER /* Microsoft compiler */
157 #define HAVE_GETPPID 1 161 #define HAVE_GETPPID 1
158 #define HAVE_GETLOGIN 1 162 #define HAVE_GETLOGIN 1
159 #define HAVE_SPAWNV 1 163 #define HAVE_SPAWNV 1
160 #define HAVE_EXECV 1 164 #define HAVE_EXECV 1
161 #define HAVE_PIPE 1 165 #define HAVE_PIPE 1
162 #define HAVE_SYSTEM 1 166 #define HAVE_SYSTEM 1
163 #define HAVE_CWAIT 1 167 #define HAVE_CWAIT 1
164 #define HAVE_FSYNC 1 168 #define HAVE_FSYNC 1
(...skipping 10 matching lines...) Expand all
175 #define HAVE_GETGID 1 179 #define HAVE_GETGID 1
176 #define HAVE_GETPPID 1 180 #define HAVE_GETPPID 1
177 #define HAVE_GETUID 1 181 #define HAVE_GETUID 1
178 #define HAVE_KILL 1 182 #define HAVE_KILL 1
179 #define HAVE_OPENDIR 1 183 #define HAVE_OPENDIR 1
180 #define HAVE_PIPE 1 184 #define HAVE_PIPE 1
181 #define HAVE_SYSTEM 1 185 #define HAVE_SYSTEM 1
182 #define HAVE_WAIT 1 186 #define HAVE_WAIT 1
183 #define HAVE_TTYNAME 1 187 #define HAVE_TTYNAME 1
184 #endif /* _MSC_VER */ 188 #endif /* _MSC_VER */
185 #endif /* __BORLANDC__ */
186 #endif /* ! __WATCOMC__ || __QNX__ */ 189 #endif /* ! __WATCOMC__ || __QNX__ */
187 190
188 191
189 /*[clinic input] 192 /*[clinic input]
193 # one of the few times we lie about this name!
190 module os 194 module os
191 [clinic start generated code]*/ 195 [clinic start generated code]*/
192 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=8cff096d1133288f]*/ 196 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/
193 197
194 #ifndef _MSC_VER 198 #ifndef _MSC_VER
195 199
196 #if defined(__sgi)&&_COMPILER_VERSION>=700 200 #if defined(__sgi)&&_COMPILER_VERSION>=700
197 /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode 201 /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode
198 (default) */ 202 (default) */
199 extern char *ctermid_r(char *); 203 extern char *ctermid_r(char *);
200 #endif 204 #endif
201 205
202 #ifndef HAVE_UNISTD_H 206 #ifndef HAVE_UNISTD_H
203 #if defined(PYCC_VACPP) 207 #if defined(PYCC_VACPP)
204 extern int mkdir(char *); 208 extern int mkdir(char *);
205 #else 209 #else
206 #if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__) 210 #if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__)
207 extern int mkdir(const char *); 211 extern int mkdir(const char *);
208 #else 212 #else
209 extern int mkdir(const char *, mode_t); 213 extern int mkdir(const char *, mode_t);
210 #endif 214 #endif
211 #endif 215 #endif
212 #if defined(__IBMC__) || defined(__IBMCPP__) 216 #if defined(__IBMC__) || defined(__IBMCPP__)
213 extern int chdir(char *); 217 extern int chdir(char *);
214 extern int rmdir(char *); 218 extern int rmdir(char *);
215 #else 219 #else
216 extern int chdir(const char *); 220 extern int chdir(const char *);
217 extern int rmdir(const char *); 221 extern int rmdir(const char *);
218 #endif 222 #endif
219 #ifdef __BORLANDC__
220 extern int chmod(const char *, int);
221 #else
222 extern int chmod(const char *, mode_t); 223 extern int chmod(const char *, mode_t);
223 #endif
224 /*#ifdef HAVE_FCHMOD 224 /*#ifdef HAVE_FCHMOD
225 extern int fchmod(int, mode_t); 225 extern int fchmod(int, mode_t);
226 #endif*/ 226 #endif*/
227 /*#ifdef HAVE_LCHMOD 227 /*#ifdef HAVE_LCHMOD
228 extern int lchmod(const char *, mode_t); 228 extern int lchmod(const char *, mode_t);
229 #endif*/ 229 #endif*/
230 extern int chown(const char *, uid_t, gid_t); 230 extern int chown(const char *, uid_t, gid_t);
231 extern char *getcwd(char *, int); 231 extern char *getcwd(char *, int);
232 extern char *strerror(int); 232 extern char *strerror(int);
233 extern int link(const char *, const char *); 233 extern int link(const char *, const char *);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 #endif 299 #endif
300 #ifndef VOLUME_NAME_DOS 300 #ifndef VOLUME_NAME_DOS
301 #define VOLUME_NAME_DOS 0x0 301 #define VOLUME_NAME_DOS 0x0
302 #endif 302 #endif
303 #ifndef VOLUME_NAME_NT 303 #ifndef VOLUME_NAME_NT
304 #define VOLUME_NAME_NT 0x2 304 #define VOLUME_NAME_NT 0x2
305 #endif 305 #endif
306 #ifndef IO_REPARSE_TAG_SYMLINK 306 #ifndef IO_REPARSE_TAG_SYMLINK
307 #define IO_REPARSE_TAG_SYMLINK (0xA000000CL) 307 #define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
308 #endif 308 #endif
309 #ifndef IO_REPARSE_TAG_MOUNT_POINT
310 #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
311 #endif
309 #include "osdefs.h" 312 #include "osdefs.h"
310 #include <malloc.h> 313 #include <malloc.h>
311 #include <windows.h> 314 #include <windows.h>
312 #include <shellapi.h> /* for ShellExecute() */ 315 #include <shellapi.h> /* for ShellExecute() */
313 #include <lmcons.h> /* for UNLEN */ 316 #include <lmcons.h> /* for UNLEN */
314 #ifdef SE_CREATE_SYMBOLIC_LINK_NAME /* Available starting with Vista */ 317 #ifdef SE_CREATE_SYMBOLIC_LINK_NAME /* Available starting with Vista */
315 #define HAVE_SYMLINK 318 #define HAVE_SYMLINK
316 static int win32_can_symlink = 0; 319 static int win32_can_symlink = 0;
317 #endif 320 #endif
318 #endif /* _MSC_VER */ 321 #endif /* _MSC_VER */
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 #define USE_CTERMID_R 357 #define USE_CTERMID_R
355 #endif 358 #endif
356 359
357 /* choose the appropriate stat and fstat functions and return structs */ 360 /* choose the appropriate stat and fstat functions and return structs */
358 #undef STAT 361 #undef STAT
359 #undef FSTAT 362 #undef FSTAT
360 #undef STRUCT_STAT 363 #undef STRUCT_STAT
361 #ifdef MS_WINDOWS 364 #ifdef MS_WINDOWS
362 # define STAT win32_stat 365 # define STAT win32_stat
363 # define LSTAT win32_lstat 366 # define LSTAT win32_lstat
364 # define FSTAT win32_fstat 367 # define FSTAT _Py_fstat_noraise
365 # define STRUCT_STAT struct win32_stat 368 # define STRUCT_STAT struct _Py_stat_struct
366 #else 369 #else
367 # define STAT stat 370 # define STAT stat
368 # define LSTAT lstat 371 # define LSTAT lstat
369 # define FSTAT fstat 372 # define FSTAT fstat
370 # define STRUCT_STAT struct stat 373 # define STRUCT_STAT struct stat
371 #endif 374 #endif
372 375
373 #if defined(MAJOR_IN_MKDEV) 376 #if defined(MAJOR_IN_MKDEV)
374 #include <sys/mkdev.h> 377 #include <sys/mkdev.h>
375 #else 378 #else
376 #if defined(MAJOR_IN_SYSMACROS) 379 #if defined(MAJOR_IN_SYSMACROS)
377 #include <sys/sysmacros.h> 380 #include <sys/sysmacros.h>
378 #endif 381 #endif
379 #if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H) 382 #if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H)
380 #include <sys/mkdev.h> 383 #include <sys/mkdev.h>
381 #endif 384 #endif
382 #endif 385 #endif
383 386
384 #define DWORD_MAX 4294967295U 387 #define DWORD_MAX 4294967295U
385 388
389 #ifdef MS_WINDOWS
390 #define INITFUNC PyInit_nt
391 #define MODNAME "nt"
392 #else
393 #define INITFUNC PyInit_posix
394 #define MODNAME "posix"
395 #endif
396
397 #ifdef MS_WINDOWS
398 /* defined in fileutils.c */
399 PyAPI_FUNC(void) _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *);
400 PyAPI_FUNC(void) _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *,
401 ULONG, struct _Py_stat_struct *);
402 #endif
386 403
387 #ifdef MS_WINDOWS 404 #ifdef MS_WINDOWS
388 static int 405 static int
389 win32_warn_bytes_api() 406 win32_warn_bytes_api()
390 { 407 {
391 return PyErr_WarnEx(PyExc_DeprecationWarning, 408 return PyErr_WarnEx(PyExc_DeprecationWarning,
392 "The Windows bytes API has been deprecated, " 409 "The Windows bytes API has been deprecated, "
393 "use Unicode filenames instead", 410 "use Unicode filenames instead",
394 1); 411 1);
395 } 412 }
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 * which doesn't play nicely with all the initializer lines in this file that 675 * which doesn't play nicely with all the initializer lines in this file that
659 * look like this: 676 * look like this:
660 * int dir_fd = DEFAULT_DIR_FD; 677 * int dir_fd = DEFAULT_DIR_FD;
661 */ 678 */
662 #define DEFAULT_DIR_FD (int)AT_FDCWD 679 #define DEFAULT_DIR_FD (int)AT_FDCWD
663 #else 680 #else
664 #define DEFAULT_DIR_FD (-100) 681 #define DEFAULT_DIR_FD (-100)
665 #endif 682 #endif
666 683
667 static int 684 static int
668 _fd_converter(PyObject *o, int *p, const char *allowed) 685 _fd_converter(PyObject *o, int *p)
669 { 686 {
670 int overflow; 687 int overflow;
671 long long_value; 688 long long_value;
672 689
673 PyObject *index = PyNumber_Index(o); 690 PyObject *index = PyNumber_Index(o);
674 if (index == NULL) { 691 if (index == NULL) {
675 PyErr_Format(PyExc_TypeError,
676 "argument should be %s, not %.200s",
677 allowed, Py_TYPE(o)->tp_name);
678 return 0; 692 return 0;
679 } 693 }
680 694
695 assert(PyLong_Check(index));
681 long_value = PyLong_AsLongAndOverflow(index, &overflow); 696 long_value = PyLong_AsLongAndOverflow(index, &overflow);
682 Py_DECREF(index); 697 Py_DECREF(index);
698 assert(!PyErr_Occurred());
683 if (overflow > 0 || long_value > INT_MAX) { 699 if (overflow > 0 || long_value > INT_MAX) {
684 PyErr_SetString(PyExc_OverflowError, 700 PyErr_SetString(PyExc_OverflowError,
685 "fd is greater than maximum"); 701 "fd is greater than maximum");
686 return 0; 702 return 0;
687 } 703 }
688 if (overflow < 0 || long_value < INT_MIN) { 704 if (overflow < 0 || long_value < INT_MIN) {
689 PyErr_SetString(PyExc_OverflowError, 705 PyErr_SetString(PyExc_OverflowError,
690 "fd is less than minimum"); 706 "fd is less than minimum");
691 return 0; 707 return 0;
692 } 708 }
693 709
694 *p = (int)long_value; 710 *p = (int)long_value;
695 return 1; 711 return 1;
696 } 712 }
697 713
698 static int 714 static int
699 dir_fd_converter(PyObject *o, void *p) 715 dir_fd_converter(PyObject *o, void *p)
700 { 716 {
701 if (o == Py_None) { 717 if (o == Py_None) {
702 *(int *)p = DEFAULT_DIR_FD; 718 *(int *)p = DEFAULT_DIR_FD;
703 return 1; 719 return 1;
704 } 720 }
705 return _fd_converter(o, (int *)p, "integer"); 721 else if (PyIndex_Check(o)) {
706 } 722 return _fd_converter(o, (int *)p);
707 723 }
724 else {
725 PyErr_Format(PyExc_TypeError,
726 "argument should be integer or None, not %.200s",
727 Py_TYPE(o)->tp_name);
728 return 0;
729 }
730 }
708 731
709 732
710 /* 733 /*
711 * A PyArg_ParseTuple "converter" function 734 * A PyArg_ParseTuple "converter" function
712 * that handles filesystem paths in the manner 735 * that handles filesystem paths in the manner
713 * preferred by the os module. 736 * preferred by the os module.
714 * 737 *
715 * path_converter accepts (Unicode) strings and their 738 * path_converter accepts (Unicode) strings and their
716 * subclasses, and bytes and their subclasses. What 739 * subclasses, and bytes and their subclasses. What
717 * it does with the argument depends on the platform: 740 * it does with the argument depends on the platform:
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 * path_cleanup(&path); 810 * path_cleanup(&path);
788 * 811 *
789 * (Note that if PyArg_Parse fails you don't need to call 812 * (Note that if PyArg_Parse fails you don't need to call
790 * path_cleanup(). However it is safe to do so.) 813 * path_cleanup(). However it is safe to do so.)
791 */ 814 */
792 typedef struct { 815 typedef struct {
793 const char *function_name; 816 const char *function_name;
794 const char *argument_name; 817 const char *argument_name;
795 int nullable; 818 int nullable;
796 int allow_fd; 819 int allow_fd;
797 wchar_t *wide; 820 const wchar_t *wide;
798 char *narrow; 821 const char *narrow;
799 int fd; 822 int fd;
800 Py_ssize_t length; 823 Py_ssize_t length;
801 PyObject *object; 824 PyObject *object;
802 PyObject *cleanup; 825 PyObject *cleanup;
803 } path_t; 826 } path_t;
804 827
805 #define PATH_T_INITIALIZE(function_name, nullable, allow_fd) \ 828 #define PATH_T_INITIALIZE(function_name, argument_name, nullable, allow_fd) \
806 {function_name, NULL, nullable, allow_fd, NULL, NULL, 0, 0, NULL, NULL} 829 {function_name, argument_name, nullable, allow_fd, NULL, NULL, -1, 0, NULL, NULL}
807 830
808 static void 831 static void
809 path_cleanup(path_t *path) { 832 path_cleanup(path_t *path) {
810 if (path->cleanup) { 833 if (path->cleanup) {
811 Py_CLEAR(path->cleanup); 834 Py_CLEAR(path->cleanup);
812 } 835 }
813 } 836 }
814 837
815 static int 838 static int
816 path_converter(PyObject *o, void *p) { 839 path_converter(PyObject *o, void *p)
840 {
817 path_t *path = (path_t *)p; 841 path_t *path = (path_t *)p;
818 PyObject *unicode, *bytes; 842 PyObject *bytes;
819 Py_ssize_t length; 843 Py_ssize_t length;
820 char *narrow; 844 const char *narrow;
821 845
822 #define FORMAT_EXCEPTION(exc, fmt) \ 846 #define FORMAT_EXCEPTION(exc, fmt) \
823 PyErr_Format(exc, "%s%s" fmt, \ 847 PyErr_Format(exc, "%s%s" fmt, \
824 path->function_name ? path->function_name : "", \ 848 path->function_name ? path->function_name : "", \
825 path->function_name ? ": " : "", \ 849 path->function_name ? ": " : "", \
826 path->argument_name ? path->argument_name : "path") 850 path->argument_name ? path->argument_name : "path")
827 851
828 /* Py_CLEANUP_SUPPORTED support */ 852 /* Py_CLEANUP_SUPPORTED support */
829 if (o == NULL) { 853 if (o == NULL) {
830 path_cleanup(path); 854 path_cleanup(path);
831 return 1; 855 return 1;
832 } 856 }
833 857
834 /* ensure it's always safe to call path_cleanup() */ 858 /* ensure it's always safe to call path_cleanup() */
835 path->cleanup = NULL; 859 path->cleanup = NULL;
836 860
837 if (o == Py_None) { 861 if ((o == Py_None) && path->nullable) {
838 if (!path->nullable) { 862 path->wide = NULL;
839 FORMAT_EXCEPTION(PyExc_TypeError, 863 path->narrow = NULL;
840 "can't specify None for %s argument"); 864 path->length = 0;
865 path->object = o;
866 path->fd = -1;
867 return 1;
868 }
869
870 if (PyUnicode_Check(o)) {
871 #ifdef MS_WINDOWS
872 const wchar_t *wide;
873
874 wide = PyUnicode_AsUnicodeAndSize(o, &length);
875 if (!wide) {
876 return 0;
877 }
878 if (length > 32767) {
879 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
880 return 0;
881 }
882 if (wcslen(wide) != length) {
883 FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
884 return 0;
885 }
886
887 path->wide = wide;
888 path->narrow = NULL;
889 path->length = length;
890 path->object = o;
891 path->fd = -1;
892 return 1;
893 #else
894 if (!PyUnicode_FSConverter(o, &bytes)) {
895 return 0;
896 }
897 #endif
898 }
899 else if (PyObject_CheckBuffer(o)) {
900 #ifdef MS_WINDOWS
901 if (win32_warn_bytes_api()) {
902 return 0;
903 }
904 #endif
905 bytes = PyBytes_FromObject(o);
906 if (!bytes) {
907 return 0;
908 }
909 }
910 else if (path->allow_fd && PyIndex_Check(o)) {
911 if (!_fd_converter(o, &path->fd)) {
841 return 0; 912 return 0;
842 } 913 }
843 path->wide = NULL; 914 path->wide = NULL;
844 path->narrow = NULL; 915 path->narrow = NULL;
845 path->length = 0; 916 path->length = 0;
846 path->object = o; 917 path->object = o;
847 path->fd = -1;
848 return 1; 918 return 1;
849 } 919 }
850
851 unicode = PyUnicode_FromObject(o);
852 if (unicode) {
853 #ifdef MS_WINDOWS
854 wchar_t *wide;
855
856 wide = PyUnicode_AsUnicodeAndSize(unicode, &length);
857 if (!wide) {
858 Py_DECREF(unicode);
859 return 0;
860 }
861 if (length > 32767) {
862 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
863 Py_DECREF(unicode);
864 return 0;
865 }
866 if (wcslen(wide) != length) {
867 FORMAT_EXCEPTION(PyExc_TypeError, "embedded null character");
868 Py_DECREF(unicode);
869 return 0;
870 }
871
872 path->wide = wide;
873 path->narrow = NULL;
874 path->length = length;
875 path->object = o;
876 path->fd = -1;
877 path->cleanup = unicode;
878 return Py_CLEANUP_SUPPORTED;
879 #else
880 int converted = PyUnicode_FSConverter(unicode, &bytes);
881 Py_DECREF(unicode);
882 if (!converted)
883 bytes = NULL;
884 #endif
885 }
886 else { 920 else {
887 PyErr_Clear(); 921 PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s",
888 if (PyObject_CheckBuffer(o)) 922 path->function_name ? path->function_name : "",
889 bytes = PyBytes_FromObject(o); 923 path->function_name ? ": " : "",
890 else 924 path->argument_name ? path->argument_name : "path",
891 bytes = NULL; 925 path->allow_fd && path->nullable ? "string, bytes, integer or None" :
892 if (!bytes) { 926 path->allow_fd ? "string, bytes or integer" :
893 PyErr_Clear(); 927 path->nullable ? "string, bytes or None" :
894 if (path->allow_fd) { 928 "string or bytes",
895 int fd; 929 Py_TYPE(o)->tp_name);
896 int result = _fd_converter(o, &fd,
897 "string, bytes or integer");
898 if (result) {
899 path->wide = NULL;
900 path->narrow = NULL;
901 path->length = 0;
902 path->object = o;
903 path->fd = fd;
904 return result;
905 }
906 }
907 }
908 }
909
910 if (!bytes) {
911 if (!PyErr_Occurred())
912 FORMAT_EXCEPTION(PyExc_TypeError, "illegal type for %s parameter");
913 return 0; 930 return 0;
914 } 931 }
915
916 #ifdef MS_WINDOWS
917 if (win32_warn_bytes_api()) {
918 Py_DECREF(bytes);
919 return 0;
920 }
921 #endif
922 932
923 length = PyBytes_GET_SIZE(bytes); 933 length = PyBytes_GET_SIZE(bytes);
924 #ifdef MS_WINDOWS 934 #ifdef MS_WINDOWS
925 if (length > MAX_PATH-1) { 935 if (length > MAX_PATH-1) {
926 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows"); 936 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
927 Py_DECREF(bytes); 937 Py_DECREF(bytes);
928 return 0; 938 return 0;
929 } 939 }
930 #endif 940 #endif
931 941
932 narrow = PyBytes_AS_STRING(bytes); 942 narrow = PyBytes_AS_STRING(bytes);
933 if (length != strlen(narrow)) { 943 if ((size_t)length != strlen(narrow)) {
934 FORMAT_EXCEPTION(PyExc_ValueError, "embedded NUL character in %s"); 944 FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
935 Py_DECREF(bytes); 945 Py_DECREF(bytes);
936 return 0; 946 return 0;
937 } 947 }
938 948
939 path->wide = NULL; 949 path->wide = NULL;
940 path->narrow = narrow; 950 path->narrow = narrow;
941 path->length = length; 951 path->length = length;
942 path->object = o; 952 path->object = o;
943 path->fd = -1; 953 path->fd = -1;
944 path->cleanup = bytes; 954 path->cleanup = bytes;
945 return Py_CLEANUP_SUPPORTED; 955 return Py_CLEANUP_SUPPORTED;
946 } 956 }
947 957
948 static void 958 static void
949 argument_unavailable_error(char *function_name, char *argument_name) { 959 argument_unavailable_error(const char *function_name, const char *argument_name)
960 {
950 PyErr_Format(PyExc_NotImplementedError, 961 PyErr_Format(PyExc_NotImplementedError,
951 "%s%s%s unavailable on this platform", 962 "%s%s%s unavailable on this platform",
952 (function_name != NULL) ? function_name : "", 963 (function_name != NULL) ? function_name : "",
953 (function_name != NULL) ? ": ": "", 964 (function_name != NULL) ? ": ": "",
954 argument_name); 965 argument_name);
955 } 966 }
956 967
957 static int 968 static int
958 dir_fd_unavailable(PyObject *o, void *p) 969 dir_fd_unavailable(PyObject *o, void *p)
959 { 970 {
960 int dir_fd; 971 int dir_fd;
961 if (!dir_fd_converter(o, &dir_fd)) 972 if (!dir_fd_converter(o, &dir_fd))
962 return 0; 973 return 0;
963 if (dir_fd != DEFAULT_DIR_FD) { 974 if (dir_fd != DEFAULT_DIR_FD) {
964 argument_unavailable_error(NULL, "dir_fd"); 975 argument_unavailable_error(NULL, "dir_fd");
965 return 0; 976 return 0;
966 } 977 }
967 *(int *)p = dir_fd; 978 *(int *)p = dir_fd;
968 return 1; 979 return 1;
969 } 980 }
970 981
971 static int 982 static int
972 fd_specified(char *function_name, int fd) { 983 fd_specified(const char *function_name, int fd)
984 {
973 if (fd == -1) 985 if (fd == -1)
974 return 0; 986 return 0;
975 987
976 argument_unavailable_error(function_name, "fd"); 988 argument_unavailable_error(function_name, "fd");
977 return 1; 989 return 1;
978 } 990 }
979 991
980 static int 992 static int
981 follow_symlinks_specified(char *function_name, int follow_symlinks) { 993 follow_symlinks_specified(const char *function_name, int follow_symlinks)
994 {
982 if (follow_symlinks) 995 if (follow_symlinks)
983 return 0; 996 return 0;
984 997
985 argument_unavailable_error(function_name, "follow_symlinks"); 998 argument_unavailable_error(function_name, "follow_symlinks");
986 return 1; 999 return 1;
987 } 1000 }
988 1001
989 static int 1002 static int
990 path_and_dir_fd_invalid(char *function_name, path_t *path, int dir_fd) { 1003 path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd)
1004 {
991 if (!path->narrow && !path->wide && (dir_fd != DEFAULT_DIR_FD)) { 1005 if (!path->narrow && !path->wide && (dir_fd != DEFAULT_DIR_FD)) {
992 PyErr_Format(PyExc_ValueError, 1006 PyErr_Format(PyExc_ValueError,
993 "%s: can't specify dir_fd without matching path", 1007 "%s: can't specify dir_fd without matching path",
994 function_name); 1008 function_name);
995 return 1; 1009 return 1;
996 } 1010 }
997 return 0; 1011 return 0;
998 } 1012 }
999 1013
1000 static int 1014 static int
1001 dir_fd_and_fd_invalid(char *function_name, int dir_fd, int fd) { 1015 dir_fd_and_fd_invalid(const char *function_name, int dir_fd, int fd)
1016 {
1002 if ((dir_fd != DEFAULT_DIR_FD) && (fd != -1)) { 1017 if ((dir_fd != DEFAULT_DIR_FD) && (fd != -1)) {
1003 PyErr_Format(PyExc_ValueError, 1018 PyErr_Format(PyExc_ValueError,
1004 "%s: can't specify both dir_fd and fd", 1019 "%s: can't specify both dir_fd and fd",
1005 function_name); 1020 function_name);
1006 return 1; 1021 return 1;
1007 } 1022 }
1008 return 0; 1023 return 0;
1009 } 1024 }
1010 1025
1011 static int 1026 static int
1012 fd_and_follow_symlinks_invalid(char *function_name, int fd, 1027 fd_and_follow_symlinks_invalid(const char *function_name, int fd,
1013 int follow_symlinks) { 1028 int follow_symlinks)
1029 {
1014 if ((fd > 0) && (!follow_symlinks)) { 1030 if ((fd > 0) && (!follow_symlinks)) {
1015 PyErr_Format(PyExc_ValueError, 1031 PyErr_Format(PyExc_ValueError,
1016 "%s: cannot use fd and follow_symlinks together", 1032 "%s: cannot use fd and follow_symlinks together",
1017 function_name); 1033 function_name);
1018 return 1; 1034 return 1;
1019 } 1035 }
1020 return 0; 1036 return 0;
1021 } 1037 }
1022 1038
1023 static int 1039 static int
1024 dir_fd_and_follow_symlinks_invalid(char *function_name, int dir_fd, 1040 dir_fd_and_follow_symlinks_invalid(const char *function_name, int dir_fd,
1025 int follow_symlinks) { 1041 int follow_symlinks)
1042 {
1026 if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) { 1043 if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
1027 PyErr_Format(PyExc_ValueError, 1044 PyErr_Format(PyExc_ValueError,
1028 "%s: cannot use dir_fd and follow_symlinks together", 1045 "%s: cannot use dir_fd and follow_symlinks together",
1029 function_name); 1046 function_name);
1030 return 1; 1047 return 1;
1031 } 1048 }
1032 return 0; 1049 return 0;
1033 } 1050 }
1034 1051
1035 /* A helper used by a number of POSIX-only functions */ 1052 #ifdef MS_WINDOWS
1036 #ifndef MS_WINDOWS 1053 typedef PY_LONG_LONG Py_off_t;
1054 #else
1055 typedef off_t Py_off_t;
1056 #endif
1057
1037 static int 1058 static int
1038 _parse_off_t(PyObject* arg, void* addr) 1059 Py_off_t_converter(PyObject *arg, void *addr)
1039 { 1060 {
1040 #if !defined(HAVE_LARGEFILE_SUPPORT) 1061 #ifdef HAVE_LARGEFILE_SUPPORT
1041 *((off_t*)addr) = PyLong_AsLong(arg); 1062 *((Py_off_t *)addr) = PyLong_AsLongLong(arg);
1042 #else 1063 #else
1043 *((off_t*)addr) = PyLong_AsLongLong(arg); 1064 *((Py_off_t *)addr) = PyLong_AsLong(arg);
1044 #endif 1065 #endif
1045 if (PyErr_Occurred()) 1066 if (PyErr_Occurred())
1046 return 0; 1067 return 0;
1047 return 1; 1068 return 1;
1048 } 1069 }
1049 #endif 1070
1050 1071 static PyObject *
1051 #if defined _MSC_VER && _MSC_VER >= 1400 1072 PyLong_FromPy_off_t(Py_off_t offset)
1052 /* Microsoft CRT in VS2005 and higher will verify that a filehandle is 1073 {
1053 * valid and raise an assertion if it isn't. 1074 #ifdef HAVE_LARGEFILE_SUPPORT
1054 * Normally, an invalid fd is likely to be a C program error and therefore 1075 return PyLong_FromLongLong(offset);
1055 * an assertion can be useful, but it does contradict the POSIX standard 1076 #else
1056 * which for write(2) states: 1077 return PyLong_FromLong(offset);
1057 * "Otherwise, -1 shall be returned and errno set to indicate the error." 1078 #endif
1058 * "[EBADF] The fildes argument is not a valid file descriptor open for 1079 }
1059 * writing." 1080
1060 * Furthermore, python allows the user to enter any old integer 1081
1061 * as a fd and should merely raise a python exception on error. 1082 #if defined _MSC_VER && _MSC_VER >= 1400 && _MSC_VER < 1900
1062 * The Microsoft CRT doesn't provide an official way to check for the 1083 /* Legacy implementation of _PyVerify_fd_dup2 while transitioning to
1063 * validity of a file descriptor, but we can emulate its internal behaviour 1084 * MSVC 14.0. This should eventually be removed. (issue23524)
1064 * by using the exported __pinfo data member and knowledge of the
1065 * internal structures involved.
1066 * The structures below must be updated for each version of visual studio
1067 * according to the file internal.h in the CRT source, until MS comes
1068 * up with a less hacky way to do this.
1069 * (all of this is to avoid globally modifying the CRT behaviour using
1070 * _set_invalid_parameter_handler() and _CrtSetReportMode())
1071 */ 1085 */
1072 /* The actual size of the structure is determined at runtime.
1073 * Only the first items must be present.
1074 */
1075 typedef struct {
1076 intptr_t osfhnd;
1077 char osfile;
1078 } my_ioinfo;
1079
1080 extern __declspec(dllimport) char * __pioinfo[];
1081 #define IOINFO_L2E 5 1086 #define IOINFO_L2E 5
1087 #define IOINFO_ARRAYS 64
1082 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) 1088 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
1083 #define IOINFO_ARRAYS 64
1084 #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS) 1089 #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
1085 #define FOPEN 0x01
1086 #define _NO_CONSOLE_FILENO (intptr_t)-2 1090 #define _NO_CONSOLE_FILENO (intptr_t)-2
1087
1088 /* This function emulates what the windows CRT does to validate file handles */
1089 int
1090 _PyVerify_fd(int fd)
1091 {
1092 const int i1 = fd >> IOINFO_L2E;
1093 const int i2 = fd & ((1 << IOINFO_L2E) - 1);
1094
1095 static size_t sizeof_ioinfo = 0;
1096
1097 /* Determine the actual size of the ioinfo structure,
1098 * as used by the CRT loaded in memory
1099 */
1100 if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
1101 sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
1102 }
1103 if (sizeof_ioinfo == 0) {
1104 /* This should not happen... */
1105 goto fail;
1106 }
1107
1108 /* See that it isn't a special CLEAR fileno */
1109 if (fd != _NO_CONSOLE_FILENO) {
1110 /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead
1111 * we check pointer validity and other info
1112 */
1113 if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) {
1114 /* finally, check that the file is open */
1115 my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo);
1116 if (info->osfile & FOPEN) {
1117 return 1;
1118 }
1119 }
1120 }
1121 fail:
1122 errno = EBADF;
1123 return 0;
1124 }
1125 1091
1126 /* the special case of checking dup2. The target fd must be in a sensible range */ 1092 /* the special case of checking dup2. The target fd must be in a sensible range */
1127 static int 1093 static int
1128 _PyVerify_fd_dup2(int fd1, int fd2) 1094 _PyVerify_fd_dup2(int fd1, int fd2)
1129 { 1095 {
1130 if (!_PyVerify_fd(fd1)) 1096 if (!_PyVerify_fd(fd1))
1131 return 0; 1097 return 0;
1132 if (fd2 == _NO_CONSOLE_FILENO) 1098 if (fd2 == _NO_CONSOLE_FILENO)
1133 return 0; 1099 return 0;
1134 if ((unsigned)fd2 < _NHANDLE_) 1100 if ((unsigned)fd2 < _NHANDLE_)
1135 return 1; 1101 return 1;
1136 else 1102 else
1137 return 0; 1103 return 0;
1138 } 1104 }
1139 #else 1105 #else
1140 /* dummy version. _PyVerify_fd() is already defined in fileobject.h */ 1106 #define _PyVerify_fd_dup2(fd1, fd2) (_PyVerify_fd(fd1) && (fd2) >= 0)
1141 #define _PyVerify_fd_dup2(A, B) (1)
1142 #endif 1107 #endif
1143 1108
1144 #ifdef MS_WINDOWS 1109 #ifdef MS_WINDOWS
1145 /* The following structure was copied from
1146 http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required
1147 include doesn't seem to be present in the Windows SDK (at least as included
1148 with Visual Studio Express). */
1149 typedef struct _REPARSE_DATA_BUFFER {
1150 ULONG ReparseTag;
1151 USHORT ReparseDataLength;
1152 USHORT Reserved;
1153 union {
1154 struct {
1155 USHORT SubstituteNameOffset;
1156 USHORT SubstituteNameLength;
1157 USHORT PrintNameOffset;
1158 USHORT PrintNameLength;
1159 ULONG Flags;
1160 WCHAR PathBuffer[1];
1161 } SymbolicLinkReparseBuffer;
1162
1163 struct {
1164 USHORT SubstituteNameOffset;
1165 USHORT SubstituteNameLength;
1166 USHORT PrintNameOffset;
1167 USHORT PrintNameLength;
1168 WCHAR PathBuffer[1];
1169 } MountPointReparseBuffer;
1170
1171 struct {
1172 UCHAR DataBuffer[1];
1173 } GenericReparseBuffer;
1174 };
1175 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
1176
1177 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\
1178 GenericReparseBuffer)
1179 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
1180 1110
1181 static int 1111 static int
1182 win32_get_reparse_tag(HANDLE reparse_point_handle, ULONG *reparse_tag) 1112 win32_get_reparse_tag(HANDLE reparse_point_handle, ULONG *reparse_tag)
1183 { 1113 {
1184 char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; 1114 char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1185 REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer; 1115 REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
1186 DWORD n_bytes_returned; 1116 DWORD n_bytes_returned;
1187 1117
1188 if (0 == DeviceIoControl( 1118 if (0 == DeviceIoControl(
1189 reparse_point_handle, 1119 reparse_point_handle,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1234 #ifdef MS_WINDOWS 1164 #ifdef MS_WINDOWS
1235 /* _wenviron must be initialized in this way if the program is started 1165 /* _wenviron must be initialized in this way if the program is started
1236 through main() instead of wmain(). */ 1166 through main() instead of wmain(). */
1237 _wgetenv(L""); 1167 _wgetenv(L"");
1238 if (_wenviron == NULL) 1168 if (_wenviron == NULL)
1239 return d; 1169 return d;
1240 /* This part ignores errors */ 1170 /* This part ignores errors */
1241 for (e = _wenviron; *e != NULL; e++) { 1171 for (e = _wenviron; *e != NULL; e++) {
1242 PyObject *k; 1172 PyObject *k;
1243 PyObject *v; 1173 PyObject *v;
1244 wchar_t *p = wcschr(*e, L'='); 1174 const wchar_t *p = wcschr(*e, L'=');
1245 if (p == NULL) 1175 if (p == NULL)
1246 continue; 1176 continue;
1247 k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e)); 1177 k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e));
1248 if (k == NULL) { 1178 if (k == NULL) {
1249 PyErr_Clear(); 1179 PyErr_Clear();
1250 continue; 1180 continue;
1251 } 1181 }
1252 v = PyUnicode_FromWideChar(p+1, wcslen(p+1)); 1182 v = PyUnicode_FromWideChar(p+1, wcslen(p+1));
1253 if (v == NULL) { 1183 if (v == NULL) {
1254 PyErr_Clear(); 1184 PyErr_Clear();
1255 Py_DECREF(k); 1185 Py_DECREF(k);
1256 continue; 1186 continue;
1257 } 1187 }
1258 if (PyDict_GetItem(d, k) == NULL) { 1188 if (PyDict_GetItem(d, k) == NULL) {
1259 if (PyDict_SetItem(d, k, v) != 0) 1189 if (PyDict_SetItem(d, k, v) != 0)
1260 PyErr_Clear(); 1190 PyErr_Clear();
1261 } 1191 }
1262 Py_DECREF(k); 1192 Py_DECREF(k);
1263 Py_DECREF(v); 1193 Py_DECREF(v);
1264 } 1194 }
1265 #else 1195 #else
1266 if (environ == NULL) 1196 if (environ == NULL)
1267 return d; 1197 return d;
1268 /* This part ignores errors */ 1198 /* This part ignores errors */
1269 for (e = environ; *e != NULL; e++) { 1199 for (e = environ; *e != NULL; e++) {
1270 PyObject *k; 1200 PyObject *k;
1271 PyObject *v; 1201 PyObject *v;
1272 char *p = strchr(*e, '='); 1202 const char *p = strchr(*e, '=');
1273 if (p == NULL) 1203 if (p == NULL)
1274 continue; 1204 continue;
1275 k = PyBytes_FromStringAndSize(*e, (int)(p-*e)); 1205 k = PyBytes_FromStringAndSize(*e, (int)(p-*e));
1276 if (k == NULL) { 1206 if (k == NULL) {
1277 PyErr_Clear(); 1207 PyErr_Clear();
1278 continue; 1208 continue;
1279 } 1209 }
1280 v = PyBytes_FromStringAndSize(p+1, strlen(p+1)); 1210 v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
1281 if (v == NULL) { 1211 if (v == NULL) {
1282 PyErr_Clear(); 1212 PyErr_Clear();
(...skipping 14 matching lines...) Expand all
1297 /* Set a POSIX-specific error from errno, and return NULL */ 1227 /* Set a POSIX-specific error from errno, and return NULL */
1298 1228
1299 static PyObject * 1229 static PyObject *
1300 posix_error(void) 1230 posix_error(void)
1301 { 1231 {
1302 return PyErr_SetFromErrno(PyExc_OSError); 1232 return PyErr_SetFromErrno(PyExc_OSError);
1303 } 1233 }
1304 1234
1305 #ifdef MS_WINDOWS 1235 #ifdef MS_WINDOWS
1306 static PyObject * 1236 static PyObject *
1307 win32_error(char* function, const char* filename) 1237 win32_error(const char* function, const char* filename)
1308 { 1238 {
1309 /* XXX We should pass the function name along in the future. 1239 /* XXX We should pass the function name along in the future.
1310 (winreg.c also wants to pass the function name.) 1240 (winreg.c also wants to pass the function name.)
1311 This would however require an additional param to the 1241 This would however require an additional param to the
1312 Windows error object, which is non-trivial. 1242 Windows error object, which is non-trivial.
1313 */ 1243 */
1314 errno = GetLastError(); 1244 errno = GetLastError();
1315 if (filename) 1245 if (filename)
1316 return PyErr_SetFromWindowsErrWithFilename(errno, filename); 1246 return PyErr_SetFromWindowsErrWithFilename(errno, filename);
1317 else 1247 else
1318 return PyErr_SetFromWindowsErr(errno); 1248 return PyErr_SetFromWindowsErr(errno);
1319 } 1249 }
1320 1250
1321 static PyObject * 1251 static PyObject *
1322 win32_error_object(char* function, PyObject* filename) 1252 win32_error_object(const char* function, PyObject* filename)
1323 { 1253 {
1324 /* XXX - see win32_error for comments on 'function' */ 1254 /* XXX - see win32_error for comments on 'function' */
1325 errno = GetLastError(); 1255 errno = GetLastError();
1326 if (filename) 1256 if (filename)
1327 return PyErr_SetExcFromWindowsErrWithFilenameObject( 1257 return PyErr_SetExcFromWindowsErrWithFilenameObject(
1328 PyExc_OSError, 1258 PyExc_OSError,
1329 errno, 1259 errno,
1330 filename); 1260 filename);
1331 else 1261 else
1332 return PyErr_SetFromWindowsErr(errno); 1262 return PyErr_SetFromWindowsErr(errno);
(...skipping 21 matching lines...) Expand all
1354 0, path->object, path2->object); 1284 0, path->object, path2->object);
1355 #else 1285 #else
1356 return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, 1286 return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError,
1357 path->object, path2->object); 1287 path->object, path2->object);
1358 #endif 1288 #endif
1359 } 1289 }
1360 1290
1361 1291
1362 /* POSIX generic methods */ 1292 /* POSIX generic methods */
1363 1293
1364 static PyObject * 1294 static int
1365 posix_fildes(PyObject *fdobj, int (*func)(int)) 1295 fildes_converter(PyObject *o, void *p)
1366 { 1296 {
1367 int fd; 1297 int fd;
1298 int *pointer = (int *)p;
1299 fd = PyObject_AsFileDescriptor(o);
1300 if (fd < 0)
1301 return 0;
1302 *pointer = fd;
1303 return 1;
1304 }
1305
1306 static PyObject *
1307 posix_fildes_fd(int fd, int (*func)(int))
1308 {
1368 int res; 1309 int res;
1369 fd = PyObject_AsFileDescriptor(fdobj); 1310 int async_err = 0;
1370 if (fd < 0) 1311
1371 return NULL;
1372 if (!_PyVerify_fd(fd)) 1312 if (!_PyVerify_fd(fd))
1373 return posix_error(); 1313 return posix_error();
1374 Py_BEGIN_ALLOW_THREADS 1314
1375 res = (*func)(fd); 1315 do {
1376 Py_END_ALLOW_THREADS 1316 Py_BEGIN_ALLOW_THREADS
1377 if (res < 0) 1317 _Py_BEGIN_SUPPRESS_IPH
1378 return posix_error(); 1318 res = (*func)(fd);
1379 Py_INCREF(Py_None); 1319 _Py_END_SUPPRESS_IPH
1380 return Py_None; 1320 Py_END_ALLOW_THREADS
1381 } 1321 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
1382 1322 if (res != 0)
1383 static PyObject * 1323 return (!async_err) ? posix_error() : NULL;
1384 posix_1str(const char *func_name, PyObject *args, char *format, 1324 Py_RETURN_NONE;
1385 int (*func)(const char*))
1386 {
1387 path_t path;
1388 int res;
1389 memset(&path, 0, sizeof(path));
1390 path.function_name = func_name;
1391 if (!PyArg_ParseTuple(args, format,
1392 path_converter, &path))
1393 return NULL;
1394 Py_BEGIN_ALLOW_THREADS
1395 res = (*func)(path.narrow);
1396 Py_END_ALLOW_THREADS
1397 if (res < 0) {
1398 path_error(&path);
1399 path_cleanup(&path);
1400 return NULL;
1401 }
1402 path_cleanup(&path);
1403 Py_INCREF(Py_None);
1404 return Py_None;
1405 } 1325 }
1406 1326
1407 1327
1408 #ifdef MS_WINDOWS 1328 #ifdef MS_WINDOWS
1409 /* This is a reimplementation of the C library's chdir function, 1329 /* This is a reimplementation of the C library's chdir function,
1410 but one that produces Win32 errors instead of DOS error codes. 1330 but one that produces Win32 errors instead of DOS error codes.
1411 chdir is essentially a wrapper around SetCurrentDirectory; however, 1331 chdir is essentially a wrapper around SetCurrentDirectory; however,
1412 it also needs to set "magic" environment variables indicating 1332 it also needs to set "magic" environment variables indicating
1413 the per-drive current directory, which are of the form =<drive>: */ 1333 the per-drive current directory, which are of the form =<drive>: */
1414 static BOOL __stdcall 1334 static BOOL __stdcall
(...skipping 17 matching lines...) Expand all
1432 return TRUE; 1352 return TRUE;
1433 env[1] = new_path[0]; 1353 env[1] = new_path[0];
1434 return SetEnvironmentVariableA(env, new_path); 1354 return SetEnvironmentVariableA(env, new_path);
1435 } 1355 }
1436 1356
1437 /* The Unicode version differs from the ANSI version 1357 /* The Unicode version differs from the ANSI version
1438 since the current directory might exceed MAX_PATH characters */ 1358 since the current directory might exceed MAX_PATH characters */
1439 static BOOL __stdcall 1359 static BOOL __stdcall
1440 win32_wchdir(LPCWSTR path) 1360 win32_wchdir(LPCWSTR path)
1441 { 1361 {
1442 wchar_t _new_path[MAX_PATH], *new_path = _new_path; 1362 wchar_t path_buf[MAX_PATH], *new_path = path_buf;
1443 int result; 1363 int result;
1444 wchar_t env[4] = L"=x:"; 1364 wchar_t env[4] = L"=x:";
1445 1365
1446 if(!SetCurrentDirectoryW(path)) 1366 if(!SetCurrentDirectoryW(path))
1447 return FALSE; 1367 return FALSE;
1448 result = GetCurrentDirectoryW(Py_ARRAY_LENGTH(new_path), new_path); 1368 result = GetCurrentDirectoryW(Py_ARRAY_LENGTH(path_buf), new_path);
1449 if (!result) 1369 if (!result)
1450 return FALSE; 1370 return FALSE;
1451 if (result > Py_ARRAY_LENGTH(new_path)) { 1371 if (result > Py_ARRAY_LENGTH(path_buf)) {
1452 new_path = PyMem_RawMalloc(result * sizeof(wchar_t)); 1372 new_path = PyMem_RawMalloc(result * sizeof(wchar_t));
1453 if (!new_path) { 1373 if (!new_path) {
1454 SetLastError(ERROR_OUTOFMEMORY); 1374 SetLastError(ERROR_OUTOFMEMORY);
1455 return FALSE; 1375 return FALSE;
1456 } 1376 }
1457 result = GetCurrentDirectoryW(result, new_path); 1377 result = GetCurrentDirectoryW(result, new_path);
1458 if (!result) { 1378 if (!result) {
1459 PyMem_RawFree(new_path); 1379 PyMem_RawFree(new_path);
1460 return FALSE; 1380 return FALSE;
1461 } 1381 }
1462 } 1382 }
1463 if (wcsncmp(new_path, L"\\\\", 2) == 0 || 1383 if (wcsncmp(new_path, L"\\\\", 2) == 0 ||
1464 wcsncmp(new_path, L"//", 2) == 0) 1384 wcsncmp(new_path, L"//", 2) == 0)
1465 /* UNC path, nothing to do. */ 1385 /* UNC path, nothing to do. */
1466 return TRUE; 1386 return TRUE;
1467 env[1] = new_path[0]; 1387 env[1] = new_path[0];
1468 result = SetEnvironmentVariableW(env, new_path); 1388 result = SetEnvironmentVariableW(env, new_path);
1469 if (new_path != _new_path) 1389 if (new_path != path_buf)
1470 PyMem_RawFree(new_path); 1390 PyMem_RawFree(new_path);
1471 return result; 1391 return result;
1472 } 1392 }
1473 #endif 1393 #endif
1474 1394
1475 #ifdef MS_WINDOWS 1395 #ifdef MS_WINDOWS
1476 /* The CRT of Windows has a number of flaws wrt. its stat() implementation: 1396 /* The CRT of Windows has a number of flaws wrt. its stat() implementation:
1477 - time stamps are restricted to second resolution 1397 - time stamps are restricted to second resolution
1478 - file modification times suffer from forth-and-back conversions between 1398 - file modification times suffer from forth-and-back conversions between
1479 UTC and local time 1399 UTC and local time
1480 Therefore, we implement our own stat, based on the Win32 API directly. 1400 Therefore, we implement our own stat, based on the Win32 API directly.
1481 */ 1401 */
1482 #define HAVE_STAT_NSEC 1 1402 #define HAVE_STAT_NSEC 1
1483 1403 #define HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES 1
1484 struct win32_stat{
1485 unsigned long st_dev;
1486 __int64 st_ino;
1487 unsigned short st_mode;
1488 int st_nlink;
1489 int st_uid;
1490 int st_gid;
1491 unsigned long st_rdev;
1492 __int64 st_size;
1493 time_t st_atime;
1494 int st_atime_nsec;
1495 time_t st_mtime;
1496 int st_mtime_nsec;
1497 time_t st_ctime;
1498 int st_ctime_nsec;
1499 };
1500
1501 static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 an d 1.1.1970 */
1502
1503 static void
1504 FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out)
1505 {
1506 /* XXX endianness. Shouldn't matter, as all Windows implementations are litt le-endian */
1507 /* Cannot simply cast and dereference in_ptr,
1508 since it might not be aligned properly */
1509 __int64 in;
1510 memcpy(&in, in_ptr, sizeof(in));
1511 *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */
1512 *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t);
1513 }
1514
1515 static void
1516 time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr)
1517 {
1518 /* XXX endianness */
1519 __int64 out;
1520 out = time_in + secs_between_epochs;
1521 out = out * 10000000 + nsec_in / 100;
1522 memcpy(out_ptr, &out, sizeof(out));
1523 }
1524
1525 /* Below, we *know* that ugo+r is 0444 */
1526 #if _S_IREAD != 0400
1527 #error Unsupported C library
1528 #endif
1529 static int
1530 attributes_to_mode(DWORD attr)
1531 {
1532 int m = 0;
1533 if (attr & FILE_ATTRIBUTE_DIRECTORY)
1534 m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */
1535 else
1536 m |= _S_IFREG;
1537 if (attr & FILE_ATTRIBUTE_READONLY)
1538 m |= 0444;
1539 else
1540 m |= 0666;
1541 return m;
1542 }
1543
1544 static int
1545 attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, stru ct win32_stat *result)
1546 {
1547 memset(result, 0, sizeof(*result));
1548 result->st_mode = attributes_to_mode(info->dwFileAttributes);
1549 result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
1550 result->st_dev = info->dwVolumeSerialNumber;
1551 result->st_rdev = result->st_dev;
1552 FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result-> st_ctime_nsec);
1553 FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result- >st_mtime_nsec);
1554 FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result ->st_atime_nsec);
1555 result->st_nlink = info->nNumberOfLinks;
1556 result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow ;
1557 if (reparse_tag == IO_REPARSE_TAG_SYMLINK) {
1558 /* first clear the S_IFMT bits */
1559 result->st_mode ^= (result->st_mode & S_IFMT);
1560 /* now set the bits that make this a symlink */
1561 result->st_mode |= S_IFLNK;
1562 }
1563
1564 return 0;
1565 }
1566 1404
1567 static BOOL 1405 static BOOL
1568 attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *rep arse_tag) 1406 attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *rep arse_tag)
1569 { 1407 {
1570 HANDLE hFindFile; 1408 HANDLE hFindFile;
1571 WIN32_FIND_DATAA FileData; 1409 WIN32_FIND_DATAA FileData;
1572 hFindFile = FindFirstFileA(pszFile, &FileData); 1410 hFindFile = FindFirstFileA(pszFile, &FileData);
1573 if (hFindFile == INVALID_HANDLE_VALUE) 1411 if (hFindFile == INVALID_HANDLE_VALUE)
1574 return FALSE; 1412 return FALSE;
1575 FindClose(hFindFile); 1413 FindClose(hFindFile);
1576 memset(info, 0, sizeof(*info)); 1414 memset(info, 0, sizeof(*info));
1577 *reparse_tag = 0; 1415 *reparse_tag = 0;
1578 info->dwFileAttributes = FileData.dwFileAttributes; 1416 info->dwFileAttributes = FileData.dwFileAttributes;
1579 info->ftCreationTime = FileData.ftCreationTime; 1417 info->ftCreationTime = FileData.ftCreationTime;
1580 info->ftLastAccessTime = FileData.ftLastAccessTime; 1418 info->ftLastAccessTime = FileData.ftLastAccessTime;
1581 info->ftLastWriteTime = FileData.ftLastWriteTime; 1419 info->ftLastWriteTime = FileData.ftLastWriteTime;
1582 info->nFileSizeHigh = FileData.nFileSizeHigh; 1420 info->nFileSizeHigh = FileData.nFileSizeHigh;
1583 info->nFileSizeLow = FileData.nFileSizeLow; 1421 info->nFileSizeLow = FileData.nFileSizeLow;
1584 /* info->nNumberOfLinks = 1; */ 1422 /* info->nNumberOfLinks = 1; */
1585 if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) 1423 if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1586 *reparse_tag = FileData.dwReserved0; 1424 *reparse_tag = FileData.dwReserved0;
1587 return TRUE; 1425 return TRUE;
1588 } 1426 }
1589 1427
1428 static void
1429 find_data_to_file_info_w(WIN32_FIND_DATAW *pFileData,
1430 BY_HANDLE_FILE_INFORMATION *info,
1431 ULONG *reparse_tag)
1432 {
1433 memset(info, 0, sizeof(*info));
1434 info->dwFileAttributes = pFileData->dwFileAttributes;
1435 info->ftCreationTime = pFileData->ftCreationTime;
1436 info->ftLastAccessTime = pFileData->ftLastAccessTime;
1437 info->ftLastWriteTime = pFileData->ftLastWriteTime;
1438 info->nFileSizeHigh = pFileData->nFileSizeHigh;
1439 info->nFileSizeLow = pFileData->nFileSizeLow;
1440 /* info->nNumberOfLinks = 1; */
1441 if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1442 *reparse_tag = pFileData->dwReserved0;
1443 else
1444 *reparse_tag = 0;
1445 }
1446
1590 static BOOL 1447 static BOOL
1591 attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG * reparse_tag) 1448 attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG * reparse_tag)
1592 { 1449 {
1593 HANDLE hFindFile; 1450 HANDLE hFindFile;
1594 WIN32_FIND_DATAW FileData; 1451 WIN32_FIND_DATAW FileData;
1595 hFindFile = FindFirstFileW(pszFile, &FileData); 1452 hFindFile = FindFirstFileW(pszFile, &FileData);
1596 if (hFindFile == INVALID_HANDLE_VALUE) 1453 if (hFindFile == INVALID_HANDLE_VALUE)
1597 return FALSE; 1454 return FALSE;
1598 FindClose(hFindFile); 1455 FindClose(hFindFile);
1599 memset(info, 0, sizeof(*info)); 1456 find_data_to_file_info_w(&FileData, info, reparse_tag);
1600 *reparse_tag = 0;
1601 info->dwFileAttributes = FileData.dwFileAttributes;
1602 info->ftCreationTime = FileData.ftCreationTime;
1603 info->ftLastAccessTime = FileData.ftLastAccessTime;
1604 info->ftLastWriteTime = FileData.ftLastWriteTime;
1605 info->nFileSizeHigh = FileData.nFileSizeHigh;
1606 info->nFileSizeLow = FileData.nFileSizeLow;
1607 /* info->nNumberOfLinks = 1; */
1608 if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1609 *reparse_tag = FileData.dwReserved0;
1610 return TRUE; 1457 return TRUE;
1611 }
1612
1613 /* Grab GetFinalPathNameByHandle dynamically from kernel32 */
1614 static int has_GetFinalPathNameByHandle = -1;
1615 static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD,
1616 DWORD);
1617 static int
1618 check_GetFinalPathNameByHandle()
1619 {
1620 HINSTANCE hKernel32;
1621 DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD,
1622 DWORD);
1623
1624 /* only recheck */
1625 if (-1 == has_GetFinalPathNameByHandle)
1626 {
1627 hKernel32 = GetModuleHandleW(L"KERNEL32");
1628 *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32,
1629 "GetFinalPathNameByHandleA");
1630 *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32,
1631 "GetFinalPathNameByHandleW");
1632 has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA &&
1633 Py_GetFinalPathNameByHandleW;
1634 }
1635 return has_GetFinalPathNameByHandle;
1636 } 1458 }
1637 1459
1638 static BOOL 1460 static BOOL
1639 get_target_path(HANDLE hdl, wchar_t **target_path) 1461 get_target_path(HANDLE hdl, wchar_t **target_path)
1640 { 1462 {
1641 int buf_size, result_length; 1463 int buf_size, result_length;
1642 wchar_t *buf; 1464 wchar_t *buf;
1643 1465
1644 /* We have a good handle to the target, use it to determine 1466 /* We have a good handle to the target, use it to determine
1645 the target path name (then we'll call lstat on it). */ 1467 the target path name (then we'll call lstat on it). */
1646 buf_size = Py_GetFinalPathNameByHandleW(hdl, 0, 0, 1468 buf_size = GetFinalPathNameByHandleW(hdl, 0, 0,
1647 VOLUME_NAME_DOS); 1469 VOLUME_NAME_DOS);
1648 if(!buf_size) 1470 if(!buf_size)
1649 return FALSE; 1471 return FALSE;
1650 1472
1651 buf = PyMem_New(wchar_t, buf_size+1); 1473 buf = (wchar_t *)PyMem_RawMalloc((buf_size + 1) * sizeof(wchar_t));
1652 if (!buf) { 1474 if (!buf) {
1653 SetLastError(ERROR_OUTOFMEMORY); 1475 SetLastError(ERROR_OUTOFMEMORY);
1654 return FALSE; 1476 return FALSE;
1655 } 1477 }
1656 1478
1657 result_length = Py_GetFinalPathNameByHandleW(hdl, 1479 result_length = GetFinalPathNameByHandleW(hdl,
1658 buf, buf_size, VOLUME_NAME_DOS); 1480 buf, buf_size, VOLUME_NAME_DOS);
1659 1481
1660 if(!result_length) { 1482 if(!result_length) {
1661 PyMem_Free(buf); 1483 PyMem_RawFree(buf);
1662 return FALSE; 1484 return FALSE;
1663 } 1485 }
1664 1486
1665 if(!CloseHandle(hdl)) { 1487 if(!CloseHandle(hdl)) {
1666 PyMem_Free(buf); 1488 PyMem_RawFree(buf);
1667 return FALSE; 1489 return FALSE;
1668 } 1490 }
1669 1491
1670 buf[result_length] = 0; 1492 buf[result_length] = 0;
1671 1493
1672 *target_path = buf; 1494 *target_path = buf;
1673 return TRUE; 1495 return TRUE;
1674 } 1496 }
1675 1497
1676 static int 1498 static int
1677 win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, 1499 win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result,
1678 BOOL traverse); 1500 BOOL traverse);
1679 static int 1501 static int
1680 win32_xstat_impl(const char *path, struct win32_stat *result, 1502 win32_xstat_impl(const char *path, struct _Py_stat_struct *result,
1681 BOOL traverse) 1503 BOOL traverse)
1682 { 1504 {
1683 int code; 1505 int code;
1684 HANDLE hFile, hFile2; 1506 HANDLE hFile, hFile2;
1685 BY_HANDLE_FILE_INFORMATION info; 1507 BY_HANDLE_FILE_INFORMATION info;
1686 ULONG reparse_tag = 0; 1508 ULONG reparse_tag = 0;
1687 wchar_t *target_path; 1509 wchar_t *target_path;
1688 const char *dot; 1510 const char *dot;
1689
1690 if(!check_GetFinalPathNameByHandle()) {
1691 /* If the OS doesn't have GetFinalPathNameByHandle, don't
1692 traverse reparse point. */
1693 traverse = FALSE;
1694 }
1695 1511
1696 hFile = CreateFileA( 1512 hFile = CreateFileA(
1697 path, 1513 path,
1698 FILE_READ_ATTRIBUTES, /* desired access */ 1514 FILE_READ_ATTRIBUTES, /* desired access */
1699 0, /* share mode */ 1515 0, /* share mode */
1700 NULL, /* security attributes */ 1516 NULL, /* security attributes */
1701 OPEN_EXISTING, 1517 OPEN_EXISTING,
1702 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 1518 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1703 /* FILE_FLAG_OPEN_REPARSE_POINT does not follow the symlink. 1519 /* FILE_FLAG_OPEN_REPARSE_POINT does not follow the symlink.
1704 Because of this, calls like GetFinalPathNameByHandle will return 1520 Because of this, calls like GetFinalPathNameByHandle will return
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1747 NULL, OPEN_EXISTING, 1563 NULL, OPEN_EXISTING,
1748 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 1564 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,
1749 NULL); 1565 NULL);
1750 if (hFile2 == INVALID_HANDLE_VALUE) 1566 if (hFile2 == INVALID_HANDLE_VALUE)
1751 return -1; 1567 return -1;
1752 1568
1753 if (!get_target_path(hFile2, &target_path)) 1569 if (!get_target_path(hFile2, &target_path))
1754 return -1; 1570 return -1;
1755 1571
1756 code = win32_xstat_impl_w(target_path, result, FALSE); 1572 code = win32_xstat_impl_w(target_path, result, FALSE);
1757 PyMem_Free(target_path); 1573 PyMem_RawFree(target_path);
1758 return code; 1574 return code;
1759 } 1575 }
1760 } else 1576 } else
1761 CloseHandle(hFile); 1577 CloseHandle(hFile);
1762 } 1578 }
1763 attribute_data_to_stat(&info, reparse_tag, result); 1579 _Py_attribute_data_to_stat(&info, reparse_tag, result);
1764 1580
1765 /* Set S_IEXEC if it is an .exe, .bat, ... */ 1581 /* Set S_IEXEC if it is an .exe, .bat, ... */
1766 dot = strrchr(path, '.'); 1582 dot = strrchr(path, '.');
1767 if (dot) { 1583 if (dot) {
1768 if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 || 1584 if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 ||
1769 stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0) 1585 stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0)
1770 result->st_mode |= 0111; 1586 result->st_mode |= 0111;
1771 } 1587 }
1772 return 0; 1588 return 0;
1773 } 1589 }
1774 1590
1775 static int 1591 static int
1776 win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, 1592 win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result,
1777 BOOL traverse) 1593 BOOL traverse)
1778 { 1594 {
1779 int code; 1595 int code;
1780 HANDLE hFile, hFile2; 1596 HANDLE hFile, hFile2;
1781 BY_HANDLE_FILE_INFORMATION info; 1597 BY_HANDLE_FILE_INFORMATION info;
1782 ULONG reparse_tag = 0; 1598 ULONG reparse_tag = 0;
1783 wchar_t *target_path; 1599 wchar_t *target_path;
1784 const wchar_t *dot; 1600 const wchar_t *dot;
1785
1786 if(!check_GetFinalPathNameByHandle()) {
1787 /* If the OS doesn't have GetFinalPathNameByHandle, don't
1788 traverse reparse point. */
1789 traverse = FALSE;
1790 }
1791 1601
1792 hFile = CreateFileW( 1602 hFile = CreateFileW(
1793 path, 1603 path,
1794 FILE_READ_ATTRIBUTES, /* desired access */ 1604 FILE_READ_ATTRIBUTES, /* desired access */
1795 0, /* share mode */ 1605 0, /* share mode */
1796 NULL, /* security attributes */ 1606 NULL, /* security attributes */
1797 OPEN_EXISTING, 1607 OPEN_EXISTING,
1798 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 1608 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
1799 /* FILE_FLAG_OPEN_REPARSE_POINT does not follow the symlink. 1609 /* FILE_FLAG_OPEN_REPARSE_POINT does not follow the symlink.
1800 Because of this, calls like GetFinalPathNameByHandle will return 1610 Because of this, calls like GetFinalPathNameByHandle will return
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1843 NULL, OPEN_EXISTING, 1653 NULL, OPEN_EXISTING,
1844 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 1654 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,
1845 NULL); 1655 NULL);
1846 if (hFile2 == INVALID_HANDLE_VALUE) 1656 if (hFile2 == INVALID_HANDLE_VALUE)
1847 return -1; 1657 return -1;
1848 1658
1849 if (!get_target_path(hFile2, &target_path)) 1659 if (!get_target_path(hFile2, &target_path))
1850 return -1; 1660 return -1;
1851 1661
1852 code = win32_xstat_impl_w(target_path, result, FALSE); 1662 code = win32_xstat_impl_w(target_path, result, FALSE);
1853 PyMem_Free(target_path); 1663 PyMem_RawFree(target_path);
1854 return code; 1664 return code;
1855 } 1665 }
1856 } else 1666 } else
1857 CloseHandle(hFile); 1667 CloseHandle(hFile);
1858 } 1668 }
1859 attribute_data_to_stat(&info, reparse_tag, result); 1669 _Py_attribute_data_to_stat(&info, reparse_tag, result);
1860 1670
1861 /* Set S_IEXEC if it is an .exe, .bat, ... */ 1671 /* Set S_IEXEC if it is an .exe, .bat, ... */
1862 dot = wcsrchr(path, '.'); 1672 dot = wcsrchr(path, '.');
1863 if (dot) { 1673 if (dot) {
1864 if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 || 1674 if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 ||
1865 _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0) 1675 _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0)
1866 result->st_mode |= 0111; 1676 result->st_mode |= 0111;
1867 } 1677 }
1868 return 0; 1678 return 0;
1869 } 1679 }
1870 1680
1871 static int 1681 static int
1872 win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) 1682 win32_xstat(const char *path, struct _Py_stat_struct *result, BOOL traverse)
1873 { 1683 {
1874 /* Protocol violation: we explicitly clear errno, instead of 1684 /* Protocol violation: we explicitly clear errno, instead of
1875 setting it to a POSIX error. Callers should use GetLastError. */ 1685 setting it to a POSIX error. Callers should use GetLastError. */
1876 int code = win32_xstat_impl(path, result, traverse); 1686 int code = win32_xstat_impl(path, result, traverse);
1877 errno = 0; 1687 errno = 0;
1878 return code; 1688 return code;
1879 } 1689 }
1880 1690
1881 static int 1691 static int
1882 win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) 1692 win32_xstat_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse )
1883 { 1693 {
1884 /* Protocol violation: we explicitly clear errno, instead of 1694 /* Protocol violation: we explicitly clear errno, instead of
1885 setting it to a POSIX error. Callers should use GetLastError. */ 1695 setting it to a POSIX error. Callers should use GetLastError. */
1886 int code = win32_xstat_impl_w(path, result, traverse); 1696 int code = win32_xstat_impl_w(path, result, traverse);
1887 errno = 0; 1697 errno = 0;
1888 return code; 1698 return code;
1889 } 1699 }
1890 /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w 1700 /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w
1891 1701
1892 In Posix, stat automatically traverses symlinks and returns the stat 1702 In Posix, stat automatically traverses symlinks and returns the stat
1893 structure for the target. In Windows, the equivalent GetFileAttributes by 1703 structure for the target. In Windows, the equivalent GetFileAttributes by
1894 default does not traverse symlinks and instead returns attributes for 1704 default does not traverse symlinks and instead returns attributes for
1895 the symlink. 1705 the symlink.
1896 1706
1897 Therefore, win32_lstat will get the attributes traditionally, and 1707 Therefore, win32_lstat will get the attributes traditionally, and
1898 win32_stat will first explicitly resolve the symlink target and then will 1708 win32_stat will first explicitly resolve the symlink target and then will
1899 call win32_lstat on that result. 1709 call win32_lstat on that result.
1900 1710
1901 The _w represent Unicode equivalents of the aforementioned ANSI functions. */ 1711 The _w represent Unicode equivalents of the aforementioned ANSI functions. */
1902 1712
1903 static int 1713 static int
1904 win32_lstat(const char* path, struct win32_stat *result) 1714 win32_lstat(const char* path, struct _Py_stat_struct *result)
1905 { 1715 {
1906 return win32_xstat(path, result, FALSE); 1716 return win32_xstat(path, result, FALSE);
1907 } 1717 }
1908 1718
1909 static int 1719 static int
1910 win32_lstat_w(const wchar_t* path, struct win32_stat *result) 1720 win32_lstat_w(const wchar_t* path, struct _Py_stat_struct *result)
1911 { 1721 {
1912 return win32_xstat_w(path, result, FALSE); 1722 return win32_xstat_w(path, result, FALSE);
1913 } 1723 }
1914 1724
1915 static int 1725 static int
1916 win32_stat(const char* path, struct win32_stat *result) 1726 win32_stat(const char* path, struct _Py_stat_struct *result)
1917 { 1727 {
1918 return win32_xstat(path, result, TRUE); 1728 return win32_xstat(path, result, TRUE);
1919 } 1729 }
1920 1730
1921 static int 1731 static int
1922 win32_stat_w(const wchar_t* path, struct win32_stat *result) 1732 win32_stat_w(const wchar_t* path, struct _Py_stat_struct *result)
1923 { 1733 {
1924 return win32_xstat_w(path, result, TRUE); 1734 return win32_xstat_w(path, result, TRUE);
1925 }
1926
1927 static int
1928 win32_fstat(int file_number, struct win32_stat *result)
1929 {
1930 BY_HANDLE_FILE_INFORMATION info;
1931 HANDLE h;
1932 int type;
1933
1934 if (!_PyVerify_fd(file_number))
1935 h = INVALID_HANDLE_VALUE;
1936 else
1937 h = (HANDLE)_get_osfhandle(file_number);
1938
1939 /* Protocol violation: we explicitly clear errno, instead of
1940 setting it to a POSIX error. Callers should use GetLastError. */
1941 errno = 0;
1942
1943 if (h == INVALID_HANDLE_VALUE) {
1944 /* This is really a C library error (invalid file handle).
1945 We set the Win32 error to the closes one matching. */
1946 SetLastError(ERROR_INVALID_HANDLE);
1947 return -1;
1948 }
1949 memset(result, 0, sizeof(*result));
1950
1951 type = GetFileType(h);
1952 if (type == FILE_TYPE_UNKNOWN) {
1953 DWORD error = GetLastError();
1954 if (error != 0) {
1955 return -1;
1956 }
1957 /* else: valid but unknown file */
1958 }
1959
1960 if (type != FILE_TYPE_DISK) {
1961 if (type == FILE_TYPE_CHAR)
1962 result->st_mode = _S_IFCHR;
1963 else if (type == FILE_TYPE_PIPE)
1964 result->st_mode = _S_IFIFO;
1965 return 0;
1966 }
1967
1968 if (!GetFileInformationByHandle(h, &info)) {
1969 return -1;
1970 }
1971
1972 attribute_data_to_stat(&info, 0, result);
1973 /* specific to fstat() */
1974 result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
1975 return 0;
1976 } 1735 }
1977 1736
1978 #endif /* MS_WINDOWS */ 1737 #endif /* MS_WINDOWS */
1979 1738
1980 PyDoc_STRVAR(stat_result__doc__, 1739 PyDoc_STRVAR(stat_result__doc__,
1981 "stat_result: Result from stat, fstat, or lstat.\n\n\ 1740 "stat_result: Result from stat, fstat, or lstat.\n\n\
1982 This object may be accessed either as a tuple of\n\ 1741 This object may be accessed either as a tuple of\n\
1983 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\ 1742 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
1984 or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\ 1743 or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\
1985 \n\ 1744 \n\
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2017 #endif 1776 #endif
2018 #ifdef HAVE_STRUCT_STAT_ST_FLAGS 1777 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2019 {"st_flags", "user defined flags for file"}, 1778 {"st_flags", "user defined flags for file"},
2020 #endif 1779 #endif
2021 #ifdef HAVE_STRUCT_STAT_ST_GEN 1780 #ifdef HAVE_STRUCT_STAT_ST_GEN
2022 {"st_gen", "generation number"}, 1781 {"st_gen", "generation number"},
2023 #endif 1782 #endif
2024 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME 1783 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2025 {"st_birthtime", "time of creation"}, 1784 {"st_birthtime", "time of creation"},
2026 #endif 1785 #endif
1786 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
1787 {"st_file_attributes", "Windows file attribute bits"},
1788 #endif
2027 {0} 1789 {0}
2028 }; 1790 };
2029 1791
2030 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE 1792 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2031 #define ST_BLKSIZE_IDX 16 1793 #define ST_BLKSIZE_IDX 16
2032 #else 1794 #else
2033 #define ST_BLKSIZE_IDX 15 1795 #define ST_BLKSIZE_IDX 15
2034 #endif 1796 #endif
2035 1797
2036 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS 1798 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
(...skipping 17 matching lines...) Expand all
2054 #ifdef HAVE_STRUCT_STAT_ST_GEN 1816 #ifdef HAVE_STRUCT_STAT_ST_GEN
2055 #define ST_GEN_IDX (ST_FLAGS_IDX+1) 1817 #define ST_GEN_IDX (ST_FLAGS_IDX+1)
2056 #else 1818 #else
2057 #define ST_GEN_IDX ST_FLAGS_IDX 1819 #define ST_GEN_IDX ST_FLAGS_IDX
2058 #endif 1820 #endif
2059 1821
2060 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME 1822 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2061 #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1) 1823 #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
2062 #else 1824 #else
2063 #define ST_BIRTHTIME_IDX ST_GEN_IDX 1825 #define ST_BIRTHTIME_IDX ST_GEN_IDX
1826 #endif
1827
1828 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
1829 #define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_IDX+1)
1830 #else
1831 #define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_IDX
2064 #endif 1832 #endif
2065 1833
2066 static PyStructSequence_Desc stat_result_desc = { 1834 static PyStructSequence_Desc stat_result_desc = {
2067 "stat_result", /* name */ 1835 "stat_result", /* name */
2068 stat_result__doc__, /* doc */ 1836 stat_result__doc__, /* doc */
2069 stat_result_fields, 1837 stat_result_fields,
2070 10 1838 10
2071 }; 1839 };
2072 1840
2073 PyDoc_STRVAR(statvfs_result__doc__, 1841 PyDoc_STRVAR(statvfs_result__doc__,
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2157 } 1925 }
2158 1926
2159 1927
2160 1928
2161 /* If true, st_?time is float. */ 1929 /* If true, st_?time is float. */
2162 static int _stat_float_times = 1; 1930 static int _stat_float_times = 1;
2163 1931
2164 PyDoc_STRVAR(stat_float_times__doc__, 1932 PyDoc_STRVAR(stat_float_times__doc__,
2165 "stat_float_times([newval]) -> oldval\n\n\ 1933 "stat_float_times([newval]) -> oldval\n\n\
2166 Determine whether os.[lf]stat represents time stamps as float objects.\n\ 1934 Determine whether os.[lf]stat represents time stamps as float objects.\n\
2167 If newval is True, future calls to stat() return floats, if it is False,\n\ 1935 \n\
2168 future calls return ints. \n\ 1936 If value is True, future calls to stat() return floats; if it is False,\n\
2169 If newval is omitted, return the current setting.\n"); 1937 future calls return ints.\n\
2170 1938 If value is omitted, return the current setting.\n");
1939
1940 /* AC 3.5: the public default value should be None, not ready for that yet */
2171 static PyObject* 1941 static PyObject*
2172 stat_float_times(PyObject* self, PyObject *args) 1942 stat_float_times(PyObject* self, PyObject *args)
2173 { 1943 {
2174 int newval = -1; 1944 int newval = -1;
2175 if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval)) 1945 if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval))
2176 return NULL; 1946 return NULL;
2177 if (PyErr_WarnEx(PyExc_DeprecationWarning, 1947 if (PyErr_WarnEx(PyExc_DeprecationWarning,
2178 "stat_float_times() is deprecated", 1948 "stat_float_times() is deprecated",
2179 1)) 1949 1))
2180 return NULL; 1950 return NULL;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
2320 val = PyLong_FromLong((long)bsec); 2090 val = PyLong_FromLong((long)bsec);
2321 } 2091 }
2322 PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, 2092 PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
2323 val); 2093 val);
2324 } 2094 }
2325 #endif 2095 #endif
2326 #ifdef HAVE_STRUCT_STAT_ST_FLAGS 2096 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2327 PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, 2097 PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
2328 PyLong_FromLong((long)st->st_flags)); 2098 PyLong_FromLong((long)st->st_flags));
2329 #endif 2099 #endif
2100 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2101 PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX,
2102 PyLong_FromUnsignedLong(st->st_file_attributes));
2103 #endif
2330 2104
2331 if (PyErr_Occurred()) { 2105 if (PyErr_Occurred()) {
2332 Py_DECREF(v); 2106 Py_DECREF(v);
2333 return NULL; 2107 return NULL;
2334 } 2108 }
2335 2109
2336 return v; 2110 return v;
2337 } 2111 }
2338 2112
2339 /* POSIX methods */ 2113 /* POSIX methods */
2340 2114
2341 2115
2342 static PyObject * 2116 static PyObject *
2343 posix_do_stat(char *function_name, path_t *path, 2117 posix_do_stat(const char *function_name, path_t *path,
2344 int dir_fd, int follow_symlinks) 2118 int dir_fd, int follow_symlinks)
2345 { 2119 {
2346 STRUCT_STAT st; 2120 STRUCT_STAT st;
2347 int result; 2121 int result;
2348 2122
2349 #if !defined(MS_WINDOWS) && !defined(HAVE_FSTATAT) && !defined(HAVE_LSTAT) 2123 #if !defined(MS_WINDOWS) && !defined(HAVE_FSTATAT) && !defined(HAVE_LSTAT)
2350 if (follow_symlinks_specified(function_name, follow_symlinks)) 2124 if (follow_symlinks_specified(function_name, follow_symlinks))
2351 return NULL; 2125 return NULL;
2352 #endif 2126 #endif
2353 2127
(...skipping 29 matching lines...) Expand all
2383 result = STAT(path->narrow, &st); 2157 result = STAT(path->narrow, &st);
2384 Py_END_ALLOW_THREADS 2158 Py_END_ALLOW_THREADS
2385 2159
2386 if (result != 0) { 2160 if (result != 0) {
2387 return path_error(path); 2161 return path_error(path);
2388 } 2162 }
2389 2163
2390 return _pystat_fromstructstat(&st); 2164 return _pystat_fromstructstat(&st);
2391 } 2165 }
2392 2166
2167 /*[python input]
2168
2169 for s in """
2170
2171 FACCESSAT
2172 FCHMODAT
2173 FCHOWNAT
2174 FSTATAT
2175 LINKAT
2176 MKDIRAT
2177 MKFIFOAT
2178 MKNODAT
2179 OPENAT
2180 READLINKAT
2181 SYMLINKAT
2182 UNLINKAT
2183
2184 """.strip().split():
2185 s = s.strip()
2186 print("""
2187 #ifdef HAVE_{s}
2188 #define {s}_DIR_FD_CONVERTER dir_fd_converter
2189 #else
2190 #define {s}_DIR_FD_CONVERTER dir_fd_unavailable
2191 #endif
2192 """.rstrip().format(s=s))
2193
2194 for s in """
2195
2196 FCHDIR
2197 FCHMOD
2198 FCHOWN
2199 FDOPENDIR
2200 FEXECVE
2201 FPATHCONF
2202 FSTATVFS
2203 FTRUNCATE
2204
2205 """.strip().split():
2206 s = s.strip()
2207 print("""
2208 #ifdef HAVE_{s}
2209 #define PATH_HAVE_{s} 1
2210 #else
2211 #define PATH_HAVE_{s} 0
2212 #endif
2213
2214 """.rstrip().format(s=s))
2215 [python start generated code]*/
2216
2217 #ifdef HAVE_FACCESSAT
2218 #define FACCESSAT_DIR_FD_CONVERTER dir_fd_converter
2219 #else
2220 #define FACCESSAT_DIR_FD_CONVERTER dir_fd_unavailable
2221 #endif
2222
2223 #ifdef HAVE_FCHMODAT
2224 #define FCHMODAT_DIR_FD_CONVERTER dir_fd_converter
2225 #else
2226 #define FCHMODAT_DIR_FD_CONVERTER dir_fd_unavailable
2227 #endif
2228
2229 #ifdef HAVE_FCHOWNAT
2230 #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_converter
2231 #else
2232 #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_unavailable
2233 #endif
2234
2393 #ifdef HAVE_FSTATAT 2235 #ifdef HAVE_FSTATAT
2394 #define OS_STAT_DIR_FD_CONVERTER dir_fd_converter 2236 #define FSTATAT_DIR_FD_CONVERTER dir_fd_converter
2395 #else 2237 #else
2396 #define OS_STAT_DIR_FD_CONVERTER dir_fd_unavailable 2238 #define FSTATAT_DIR_FD_CONVERTER dir_fd_unavailable
2397 #endif 2239 #endif
2398 2240
2241 #ifdef HAVE_LINKAT
2242 #define LINKAT_DIR_FD_CONVERTER dir_fd_converter
2243 #else
2244 #define LINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2245 #endif
2246
2247 #ifdef HAVE_MKDIRAT
2248 #define MKDIRAT_DIR_FD_CONVERTER dir_fd_converter
2249 #else
2250 #define MKDIRAT_DIR_FD_CONVERTER dir_fd_unavailable
2251 #endif
2252
2253 #ifdef HAVE_MKFIFOAT
2254 #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_converter
2255 #else
2256 #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_unavailable
2257 #endif
2258
2259 #ifdef HAVE_MKNODAT
2260 #define MKNODAT_DIR_FD_CONVERTER dir_fd_converter
2261 #else
2262 #define MKNODAT_DIR_FD_CONVERTER dir_fd_unavailable
2263 #endif
2264
2265 #ifdef HAVE_OPENAT
2266 #define OPENAT_DIR_FD_CONVERTER dir_fd_converter
2267 #else
2268 #define OPENAT_DIR_FD_CONVERTER dir_fd_unavailable
2269 #endif
2270
2271 #ifdef HAVE_READLINKAT
2272 #define READLINKAT_DIR_FD_CONVERTER dir_fd_converter
2273 #else
2274 #define READLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2275 #endif
2276
2277 #ifdef HAVE_SYMLINKAT
2278 #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_converter
2279 #else
2280 #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2281 #endif
2282
2283 #ifdef HAVE_UNLINKAT
2284 #define UNLINKAT_DIR_FD_CONVERTER dir_fd_converter
2285 #else
2286 #define UNLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2287 #endif
2288
2289 #ifdef HAVE_FCHDIR
2290 #define PATH_HAVE_FCHDIR 1
2291 #else
2292 #define PATH_HAVE_FCHDIR 0
2293 #endif
2294
2295 #ifdef HAVE_FCHMOD
2296 #define PATH_HAVE_FCHMOD 1
2297 #else
2298 #define PATH_HAVE_FCHMOD 0
2299 #endif
2300
2301 #ifdef HAVE_FCHOWN
2302 #define PATH_HAVE_FCHOWN 1
2303 #else
2304 #define PATH_HAVE_FCHOWN 0
2305 #endif
2306
2307 #ifdef HAVE_FDOPENDIR
2308 #define PATH_HAVE_FDOPENDIR 1
2309 #else
2310 #define PATH_HAVE_FDOPENDIR 0
2311 #endif
2312
2313 #ifdef HAVE_FEXECVE
2314 #define PATH_HAVE_FEXECVE 1
2315 #else
2316 #define PATH_HAVE_FEXECVE 0
2317 #endif
2318
2319 #ifdef HAVE_FPATHCONF
2320 #define PATH_HAVE_FPATHCONF 1
2321 #else
2322 #define PATH_HAVE_FPATHCONF 0
2323 #endif
2324
2325 #ifdef HAVE_FSTATVFS
2326 #define PATH_HAVE_FSTATVFS 1
2327 #else
2328 #define PATH_HAVE_FSTATVFS 0
2329 #endif
2330
2331 #ifdef HAVE_FTRUNCATE
2332 #define PATH_HAVE_FTRUNCATE 1
2333 #else
2334 #define PATH_HAVE_FTRUNCATE 0
2335 #endif
2336 /*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/
2337
2338 #ifdef MS_WINDOWS
2339 #undef PATH_HAVE_FTRUNCATE
2340 #define PATH_HAVE_FTRUNCATE 1
2341 #endif
2399 2342
2400 /*[python input] 2343 /*[python input]
2401 2344
2402 class path_t_converter(CConverter): 2345 class path_t_converter(CConverter):
2403 2346
2404 type = "path_t" 2347 type = "path_t"
2405 impl_by_reference = True 2348 impl_by_reference = True
2406 parse_by_reference = True 2349 parse_by_reference = True
2407 2350
2408 converter = 'path_converter' 2351 converter = 'path_converter'
2409 2352
2410 def converter_init(self, *, allow_fd=False, nullable=False): 2353 def converter_init(self, *, allow_fd=False, nullable=False):
2411 # right now path_t doesn't support default values. 2354 # right now path_t doesn't support default values.
2412 # to support a default value, you'll need to override initialize(). 2355 # to support a default value, you'll need to override initialize().
2413 if self.default is not unspecified: 2356 if self.default not in (unspecified, None):
2414 fail("Can't specify a default to the path_t converter!") 2357 fail("Can't specify a default to the path_t converter!")
2415 2358
2416 if self.c_default is not None: 2359 if self.c_default not in (None, 'Py_None'):
2417 fail("Can't specify a c_default to the path_t converter!") 2360 raise RuntimeError("Can't specify a c_default to the path_t converte r!")
2418 2361
2419 self.nullable = nullable 2362 self.nullable = nullable
2420 self.allow_fd = allow_fd 2363 self.allow_fd = allow_fd
2421 2364
2422 def pre_render(self): 2365 def pre_render(self):
2423 def strify(value): 2366 def strify(value):
2367 if isinstance(value, str):
2368 return value
2424 return str(int(bool(value))) 2369 return str(int(bool(value)))
2425 2370
2426 # add self.py_name here when merging with posixmodule conversion 2371 # add self.py_name here when merging with posixmodule conversion
2427 self.c_default = 'PATH_T_INITIALIZE("{}", {}, {})'.format( 2372 self.c_default = 'PATH_T_INITIALIZE("{}", "{}", {}, {})'.format(
2428 self.function.name, 2373 self.function.name,
2374 self.name,
2429 strify(self.nullable), 2375 strify(self.nullable),
2430 strify(self.allow_fd), 2376 strify(self.allow_fd),
2431 ) 2377 )
2432 2378
2433 def cleanup(self): 2379 def cleanup(self):
2434 return "path_cleanup(&" + self.name + ");\n" 2380 return "path_cleanup(&" + self.name + ");\n"
2435 2381
2436 2382
2437 class dir_fd_converter(CConverter): 2383 class dir_fd_converter(CConverter):
2438 type = 'int' 2384 type = 'int'
2439 converter = 'OS_STAT_DIR_FD_CONVERTER' 2385
2440 2386 def converter_init(self, requires=None):
2441 def converter_init(self):
2442 if self.default in (unspecified, None): 2387 if self.default in (unspecified, None):
2443 self.c_default = 'DEFAULT_DIR_FD' 2388 self.c_default = 'DEFAULT_DIR_FD'
2444 2389 if isinstance(requires, str):
2390 self.converter = requires.upper() + '_DIR_FD_CONVERTER'
2391 else:
2392 self.converter = 'dir_fd_converter'
2393
2394 class fildes_converter(CConverter):
2395 type = 'int'
2396 converter = 'fildes_converter'
2397
2398 class uid_t_converter(CConverter):
2399 type = "uid_t"
2400 converter = '_Py_Uid_Converter'
2401
2402 class gid_t_converter(CConverter):
2403 type = "gid_t"
2404 converter = '_Py_Gid_Converter'
2405
2406 class dev_t_converter(CConverter):
2407 type = 'dev_t'
2408 converter = '_Py_Dev_Converter'
2409
2410 class dev_t_return_converter(unsigned_long_return_converter):
2411 type = 'dev_t'
2412 conversion_fn = '_PyLong_FromDev'
2413 unsigned_cast = '(dev_t)'
2414
2415 class FSConverter_converter(CConverter):
2416 type = 'PyObject *'
2417 converter = 'PyUnicode_FSConverter'
2418 def converter_init(self):
2419 if self.default is not unspecified:
2420 fail("FSConverter_converter does not support default values")
2421 self.c_default = 'NULL'
2422
2423 def cleanup(self):
2424 return "Py_XDECREF(" + self.name + ");\n"
2425
2426 class pid_t_converter(CConverter):
2427 type = 'pid_t'
2428 format_unit = '" _Py_PARSE_PID "'
2429
2430 class idtype_t_converter(int_converter):
2431 type = 'idtype_t'
2432
2433 class id_t_converter(CConverter):
2434 type = 'id_t'
2435 format_unit = '" _Py_PARSE_PID "'
2436
2437 class Py_intptr_t_converter(CConverter):
2438 type = 'Py_intptr_t'
2439 format_unit = '" _Py_PARSE_INTPTR "'
2440
2441 class Py_off_t_converter(CConverter):
2442 type = 'Py_off_t'
2443 converter = 'Py_off_t_converter'
2444
2445 class Py_off_t_return_converter(long_return_converter):
2446 type = 'Py_off_t'
2447 conversion_fn = 'PyLong_FromPy_off_t'
2448
2449 class path_confname_converter(CConverter):
2450 type="int"
2451 converter="conv_path_confname"
2452
2453 class confstr_confname_converter(path_confname_converter):
2454 converter='conv_confstr_confname'
2455
2456 class sysconf_confname_converter(path_confname_converter):
2457 converter="conv_sysconf_confname"
2458
2459 class sched_param_converter(CConverter):
2460 type = 'struct sched_param'
2461 converter = 'convert_sched_param'
2462 impl_by_reference = True;
2445 2463
2446 [python start generated code]*/ 2464 [python start generated code]*/
2447 /*[python end generated code: output=da39a3ee5e6b4b0d input=5c9f456f53244fc3]*/ 2465 /*[python end generated code: output=da39a3ee5e6b4b0d input=affe68316f160401]*/
2448 2466
2449 /*[clinic input] 2467 /*[clinic input]
2450 2468
2451 os.stat 2469 os.stat
2452 2470
2453 path : path_t(allow_fd=True) 2471 path : path_t(allow_fd=True)
2454 Path to be examined; can be string, bytes, or open-file-descriptor int. 2472 Path to be examined; can be string, bytes, or open-file-descriptor int.
2455 2473
2456 * 2474 *
2457 2475
2458 dir_fd : dir_fd = None 2476 dir_fd : dir_fd(requires='fstatat') = None
2459 If not None, it should be a file descriptor open to a directory, 2477 If not None, it should be a file descriptor open to a directory,
2460 and path should be a relative string; path will then be relative to 2478 and path should be a relative string; path will then be relative to
2461 that directory. 2479 that directory.
2462 2480
2463 follow_symlinks: bool = True 2481 follow_symlinks: bool = True
2464 If False, and the last element of the path is a symbolic link, 2482 If False, and the last element of the path is a symbolic link,
2465 stat will examine the symbolic link itself instead of the file 2483 stat will examine the symbolic link itself instead of the file
2466 the link points to. 2484 the link points to.
2467 2485
2468 Perform a stat system call on the given path. 2486 Perform a stat system call on the given path.
2469 2487
2470 dir_fd and follow_symlinks may not be implemented 2488 dir_fd and follow_symlinks may not be implemented
2471 on your platform. If they are unavailable, using them will raise a 2489 on your platform. If they are unavailable, using them will raise a
2472 NotImplementedError. 2490 NotImplementedError.
2473 2491
2474 It's an error to use dir_fd or follow_symlinks when specifying path as 2492 It's an error to use dir_fd or follow_symlinks when specifying path as
2475 an open file descriptor. 2493 an open file descriptor.
2476 2494
2477 [clinic start generated code]*/ 2495 [clinic start generated code]*/
2478 2496
2479 PyDoc_STRVAR(os_stat__doc__, 2497 static PyObject *
2480 "stat($module, /, path, *, dir_fd=None, follow_symlinks=True)\n" 2498 os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd,
2481 "--\n" 2499 int follow_symlinks)
2482 "\n" 2500 /*[clinic end generated code: output=e4f7569f95d523ca input=099d356c306fa24a]*/
2483 "Perform a stat system call on the given path.\n"
2484 "\n"
2485 " path\n"
2486 " Path to be examined; can be string, bytes, or open-file-descriptor int.\n"
2487 " dir_fd\n"
2488 " If not None, it should be a file descriptor open to a directory,\n"
2489 " and path should be a relative string; path will then be relative to\n"
2490 " that directory.\n"
2491 " follow_symlinks\n"
2492 " If False, and the last element of the path is a symbolic link,\n"
2493 " stat will examine the symbolic link itself instead of the file\n"
2494 " the link points to.\n"
2495 "\n"
2496 "dir_fd and follow_symlinks may not be implemented\n"
2497 " on your platform. If they are unavailable, using them will raise a\n"
2498 " NotImplementedError.\n"
2499 "\n"
2500 "It\'s an error to use dir_fd or follow_symlinks when specifying path as\n"
2501 " an open file descriptor.");
2502
2503 #define OS_STAT_METHODDEF \
2504 {"stat", (PyCFunction)os_stat, METH_VARARGS|METH_KEYWORDS, os_stat__doc__},
2505
2506 static PyObject *
2507 os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) ;
2508
2509 static PyObject *
2510 os_stat(PyModuleDef *module, PyObject *args, PyObject *kwargs)
2511 {
2512 PyObject *return_value = NULL;
2513 static char *_keywords[] = {"path", "dir_fd", "follow_symlinks", NULL};
2514 path_t path = PATH_T_INITIALIZE("stat", 0, 1);
2515 int dir_fd = DEFAULT_DIR_FD;
2516 int follow_symlinks = 1;
2517
2518 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
2519 "O&|$O&p:stat", _keywords,
2520 path_converter, &path, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &follow_symlin ks))
2521 goto exit;
2522 return_value = os_stat_impl(module, &path, dir_fd, follow_symlinks);
2523
2524 exit:
2525 /* Cleanup for path */
2526 path_cleanup(&path);
2527
2528 return return_value;
2529 }
2530
2531 static PyObject *
2532 os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks)
2533 /*[clinic end generated code: output=f1dcaa5e24db9882 input=5ae155bd475fd20a]*/
2534 { 2501 {
2535 return posix_do_stat("stat", path, dir_fd, follow_symlinks); 2502 return posix_do_stat("stat", path, dir_fd, follow_symlinks);
2536 } 2503 }
2537 2504
2538 PyDoc_STRVAR(posix_lstat__doc__, 2505
2539 "lstat(path, *, dir_fd=None) -> stat result\n\n\ 2506 /*[clinic input]
2540 Like stat(), but do not follow symbolic links.\n\ 2507 os.lstat
2541 Equivalent to stat(path, follow_symlinks=False)."); 2508
2542 2509 path : path_t
2543 static PyObject * 2510
2544 posix_lstat(PyObject *self, PyObject *args, PyObject *kwargs) 2511 *
2545 { 2512
2546 static char *keywords[] = {"path", "dir_fd", NULL}; 2513 dir_fd : dir_fd(requires='fstatat') = None
2547 path_t path; 2514
2548 int dir_fd = DEFAULT_DIR_FD; 2515 Perform a stat system call on the given path, without following symbolic links.
2516
2517 Like stat(), but do not follow symbolic links.
2518 Equivalent to stat(path, follow_symlinks=False).
2519 [clinic start generated code]*/
2520
2521 static PyObject *
2522 os_lstat_impl(PyModuleDef *module, path_t *path, int dir_fd)
2523 /*[clinic end generated code: output=7a748e333fcb39bd input=0b7474765927b925]*/
2524 {
2549 int follow_symlinks = 0; 2525 int follow_symlinks = 0;
2550 PyObject *return_value; 2526 return posix_do_stat("lstat", path, dir_fd, follow_symlinks);
2551 2527 }
2552 memset(&path, 0, sizeof(path)); 2528
2553 path.function_name = "lstat"; 2529
2554 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:lstat", keywords, 2530 /*[clinic input]
2555 path_converter, &path, 2531 os.access -> bool
2556 #ifdef HAVE_FSTATAT
2557 dir_fd_converter, &dir_fd
2558 #else
2559 dir_fd_unavailable, &dir_fd
2560 #endif
2561 ))
2562 return NULL;
2563 return_value = posix_do_stat("lstat", &path, dir_fd, follow_symlinks);
2564 path_cleanup(&path);
2565 return return_value;
2566 }
2567
2568
2569 #ifdef HAVE_FACCESSAT
2570 #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_converter
2571 #else
2572 #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable
2573 #endif
2574 /*[clinic input]
2575 os.access
2576 2532
2577 path: path_t(allow_fd=True) 2533 path: path_t(allow_fd=True)
2578 Path to be tested; can be string, bytes, or open-file-descriptor int. 2534 Path to be tested; can be string, bytes, or open-file-descriptor int.
2579 2535
2580 mode: int 2536 mode: int
2581 Operating-system mode bitfield. Can be F_OK to test existence, 2537 Operating-system mode bitfield. Can be F_OK to test existence,
2582 or the inclusive-OR of R_OK, W_OK, and X_OK. 2538 or the inclusive-OR of R_OK, W_OK, and X_OK.
2583 2539
2584 * 2540 *
2585 2541
2586 dir_fd : dir_fd = None 2542 dir_fd : dir_fd(requires='faccessat') = None
2587 If not None, it should be a file descriptor open to a directory, 2543 If not None, it should be a file descriptor open to a directory,
2588 and path should be relative; path will then be relative to that 2544 and path should be relative; path will then be relative to that
2589 directory. 2545 directory.
2590 2546
2591 effective_ids: bool = False 2547 effective_ids: bool = False
2592 If True, access will use the effective uid/gid instead of 2548 If True, access will use the effective uid/gid instead of
2593 the real uid/gid. 2549 the real uid/gid.
2594 2550
2595 follow_symlinks: bool = True 2551 follow_symlinks: bool = True
2596 If False, and the last element of the path is a symbolic link, 2552 If False, and the last element of the path is a symbolic link,
2597 access will examine the symbolic link itself instead of the file 2553 access will examine the symbolic link itself instead of the file
2598 the link points to. 2554 the link points to.
2599 2555
2600 Use the real uid/gid to test for access to a path. 2556 Use the real uid/gid to test for access to a path.
2601 2557
2602 {parameters} 2558 {parameters}
2603 dir_fd, effective_ids, and follow_symlinks may not be implemented 2559 dir_fd, effective_ids, and follow_symlinks may not be implemented
2604 on your platform. If they are unavailable, using them will raise a 2560 on your platform. If they are unavailable, using them will raise a
2605 NotImplementedError. 2561 NotImplementedError.
2606 2562
2607 Note that most operations will use the effective uid/gid, therefore this 2563 Note that most operations will use the effective uid/gid, therefore this
2608 routine can be used in a suid/sgid environment to test if the invoking user 2564 routine can be used in a suid/sgid environment to test if the invoking user
2609 has the specified access to the path. 2565 has the specified access to the path.
2610 2566
2611 [clinic start generated code]*/ 2567 [clinic start generated code]*/
2612 2568
2613 PyDoc_STRVAR(os_access__doc__, 2569 static int
2614 "access($module, /, path, mode, *, dir_fd=None, effective_ids=False,\n" 2570 os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd,
2615 " follow_symlinks=True)\n" 2571 int effective_ids, int follow_symlinks)
2616 "--\n" 2572 /*[clinic end generated code: output=abaa53340210088d input=b75a756797af45ec]*/
2617 "\n" 2573 {
2618 "Use the real uid/gid to test for access to a path.\n" 2574 int return_value;
2619 "\n"
2620 " path\n"
2621 " Path to be tested; can be string, bytes, or open-file-descriptor int.\n"
2622 " mode\n"
2623 " Operating-system mode bitfield. Can be F_OK to test existence,\n"
2624 " or the inclusive-OR of R_OK, W_OK, and X_OK.\n"
2625 " dir_fd\n"
2626 " If not None, it should be a file descriptor open to a directory,\n"
2627 " and path should be relative; path will then be relative to that\n"
2628 " directory.\n"
2629 " effective_ids\n"
2630 " If True, access will use the effective uid/gid instead of\n"
2631 " the real uid/gid.\n"
2632 " follow_symlinks\n"
2633 " If False, and the last element of the path is a symbolic link,\n"
2634 " access will examine the symbolic link itself instead of the file\n"
2635 " the link points to.\n"
2636 "\n"
2637 "dir_fd, effective_ids, and follow_symlinks may not be implemented\n"
2638 " on your platform. If they are unavailable, using them will raise a\n"
2639 " NotImplementedError.\n"
2640 "\n"
2641 "Note that most operations will use the effective uid/gid, therefore this\n"
2642 " routine can be used in a suid/sgid environment to test if the invoking user\n "
2643 " has the specified access to the path.");
2644
2645 #define OS_ACCESS_METHODDEF \
2646 {"access", (PyCFunction)os_access, METH_VARARGS|METH_KEYWORDS, os_access__do c__},
2647
2648 static PyObject *
2649 os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effe ctive_ids, int follow_symlinks);
2650
2651 static PyObject *
2652 os_access(PyModuleDef *module, PyObject *args, PyObject *kwargs)
2653 {
2654 PyObject *return_value = NULL;
2655 static char *_keywords[] = {"path", "mode", "dir_fd", "effective_ids", "foll ow_symlinks", NULL};
2656 path_t path = PATH_T_INITIALIZE("access", 0, 1);
2657 int mode;
2658 int dir_fd = DEFAULT_DIR_FD;
2659 int effective_ids = 0;
2660 int follow_symlinks = 1;
2661
2662 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
2663 "O&i|$O&pp:access", _keywords,
2664 path_converter, &path, &mode, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &effect ive_ids, &follow_symlinks))
2665 goto exit;
2666 return_value = os_access_impl(module, &path, mode, dir_fd, effective_ids, fo llow_symlinks);
2667
2668 exit:
2669 /* Cleanup for path */
2670 path_cleanup(&path);
2671
2672 return return_value;
2673 }
2674
2675 static PyObject *
2676 os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effe ctive_ids, int follow_symlinks)
2677 /*[clinic end generated code: output=a6ed4f151be9df0f input=2e2e7594371f5b7e]*/
2678 {
2679 PyObject *return_value = NULL;
2680 2575
2681 #ifdef MS_WINDOWS 2576 #ifdef MS_WINDOWS
2682 DWORD attr; 2577 DWORD attr;
2683 #else 2578 #else
2684 int result; 2579 int result;
2685 #endif 2580 #endif
2686 2581
2687 #ifndef HAVE_FACCESSAT 2582 #ifndef HAVE_FACCESSAT
2688 if (follow_symlinks_specified("access", follow_symlinks)) 2583 if (follow_symlinks_specified("access", follow_symlinks))
2689 goto exit; 2584 return -1;
2690 2585
2691 if (effective_ids) { 2586 if (effective_ids) {
2692 argument_unavailable_error("access", "effective_ids"); 2587 argument_unavailable_error("access", "effective_ids");
2693 goto exit; 2588 return -1;
2694 } 2589 }
2695 #endif 2590 #endif
2696 2591
2697 #ifdef MS_WINDOWS 2592 #ifdef MS_WINDOWS
2698 Py_BEGIN_ALLOW_THREADS 2593 Py_BEGIN_ALLOW_THREADS
2699 if (path->wide != NULL) 2594 if (path->wide != NULL)
2700 attr = GetFileAttributesW(path->wide); 2595 attr = GetFileAttributesW(path->wide);
2701 else 2596 else
2702 attr = GetFileAttributesA(path->narrow); 2597 attr = GetFileAttributesA(path->narrow);
2703 Py_END_ALLOW_THREADS 2598 Py_END_ALLOW_THREADS
2704 2599
2705 /* 2600 /*
2706 * Access is possible if 2601 * Access is possible if
2707 * * we didn't get a -1, and 2602 * * we didn't get a -1, and
2708 * * write access wasn't requested, 2603 * * write access wasn't requested,
2709 * * or the file isn't read-only, 2604 * * or the file isn't read-only,
2710 * * or it's a directory. 2605 * * or it's a directory.
2711 * (Directories cannot be read-only on Windows.) 2606 * (Directories cannot be read-only on Windows.)
2712 */ 2607 */
2713 return_value = PyBool_FromLong( 2608 return_value = (attr != INVALID_FILE_ATTRIBUTES) &&
2714 (attr != INVALID_FILE_ATTRIBUTES) &&
2715 (!(mode & 2) || 2609 (!(mode & 2) ||
2716 !(attr & FILE_ATTRIBUTE_READONLY) || 2610 !(attr & FILE_ATTRIBUTE_READONLY) ||
2717 (attr & FILE_ATTRIBUTE_DIRECTORY))); 2611 (attr & FILE_ATTRIBUTE_DIRECTORY));
2718 #else 2612 #else
2719 2613
2720 Py_BEGIN_ALLOW_THREADS 2614 Py_BEGIN_ALLOW_THREADS
2721 #ifdef HAVE_FACCESSAT 2615 #ifdef HAVE_FACCESSAT
2722 if ((dir_fd != DEFAULT_DIR_FD) || 2616 if ((dir_fd != DEFAULT_DIR_FD) ||
2723 effective_ids || 2617 effective_ids ||
2724 !follow_symlinks) { 2618 !follow_symlinks) {
2725 int flags = 0; 2619 int flags = 0;
2726 if (!follow_symlinks) 2620 if (!follow_symlinks)
2727 flags |= AT_SYMLINK_NOFOLLOW; 2621 flags |= AT_SYMLINK_NOFOLLOW;
2728 if (effective_ids) 2622 if (effective_ids)
2729 flags |= AT_EACCESS; 2623 flags |= AT_EACCESS;
2730 result = faccessat(dir_fd, path->narrow, mode, flags); 2624 result = faccessat(dir_fd, path->narrow, mode, flags);
2731 } 2625 }
2732 else 2626 else
2733 #endif 2627 #endif
2734 result = access(path->narrow, mode); 2628 result = access(path->narrow, mode);
2735 Py_END_ALLOW_THREADS 2629 Py_END_ALLOW_THREADS
2736 return_value = PyBool_FromLong(!result); 2630 return_value = !result;
2737 #endif 2631 #endif
2738 2632
2739 #ifndef HAVE_FACCESSAT
2740 exit:
2741 #endif
2742 return return_value; 2633 return return_value;
2743 } 2634 }
2744 2635
2745 #ifndef F_OK 2636 #ifndef F_OK
2746 #define F_OK 0 2637 #define F_OK 0
2747 #endif 2638 #endif
2748 #ifndef R_OK 2639 #ifndef R_OK
2749 #define R_OK 4 2640 #define R_OK 4
2750 #endif 2641 #endif
2751 #ifndef W_OK 2642 #ifndef W_OK
2752 #define W_OK 2 2643 #define W_OK 2
2753 #endif 2644 #endif
2754 #ifndef X_OK 2645 #ifndef X_OK
2755 #define X_OK 1 2646 #define X_OK 1
2756 #endif 2647 #endif
2757 2648
2758 2649
2759 #ifdef HAVE_TTYNAME 2650 #ifdef HAVE_TTYNAME
2760
2761 /*[clinic input] 2651 /*[clinic input]
2762 os.ttyname -> DecodeFSDefault 2652 os.ttyname -> DecodeFSDefault
2763 2653
2764 fd: int 2654 fd: int
2765 Integer file descriptor handle. 2655 Integer file descriptor handle.
2766 2656
2767 / 2657 /
2768 2658
2769 Return the name of the terminal device connected to 'fd'. 2659 Return the name of the terminal device connected to 'fd'.
2770 [clinic start generated code]*/ 2660 [clinic start generated code]*/
2771 2661
2772 PyDoc_STRVAR(os_ttyname__doc__,
2773 "ttyname($module, fd, /)\n"
2774 "--\n"
2775 "\n"
2776 "Return the name of the terminal device connected to \'fd\'.\n"
2777 "\n"
2778 " fd\n"
2779 " Integer file descriptor handle.");
2780
2781 #define OS_TTYNAME_METHODDEF \
2782 {"ttyname", (PyCFunction)os_ttyname, METH_VARARGS, os_ttyname__doc__},
2783
2784 static char *
2785 os_ttyname_impl(PyModuleDef *module, int fd);
2786
2787 static PyObject *
2788 os_ttyname(PyModuleDef *module, PyObject *args)
2789 {
2790 PyObject *return_value = NULL;
2791 int fd;
2792 char *_return_value;
2793
2794 if (!PyArg_ParseTuple(args,
2795 "i:ttyname",
2796 &fd))
2797 goto exit;
2798 _return_value = os_ttyname_impl(module, fd);
2799 if (_return_value == NULL)
2800 goto exit;
2801 return_value = PyUnicode_DecodeFSDefault(_return_value);
2802
2803 exit:
2804 return return_value;
2805 }
2806
2807 static char * 2662 static char *
2808 os_ttyname_impl(PyModuleDef *module, int fd) 2663 os_ttyname_impl(PyModuleDef *module, int fd)
2809 /*[clinic end generated code: output=cee7bc4cffec01a2 input=5f72ca83e76b3b45]*/ 2664 /*[clinic end generated code: output=03ad3d5ccaef75c3 input=5f72ca83e76b3b45]*/
2810 { 2665 {
2811 char *ret; 2666 char *ret;
2812 2667
2813 ret = ttyname(fd); 2668 ret = ttyname(fd);
2814 if (ret == NULL) 2669 if (ret == NULL)
2815 posix_error(); 2670 posix_error();
2816 return ret; 2671 return ret;
2817 } 2672 }
2818 #else
2819 #define OS_TTYNAME_METHODDEF
2820 #endif 2673 #endif
2821 2674
2822 #ifdef HAVE_CTERMID 2675 #ifdef HAVE_CTERMID
2823 PyDoc_STRVAR(posix_ctermid__doc__, 2676 /*[clinic input]
2824 "ctermid() -> string\n\n\ 2677 os.ctermid
2825 Return the name of the controlling terminal for this process."); 2678
2826 2679 Return the name of the controlling terminal for this process.
2827 static PyObject * 2680 [clinic start generated code]*/
2828 posix_ctermid(PyObject *self, PyObject *noargs) 2681
2682 static PyObject *
2683 os_ctermid_impl(PyModuleDef *module)
2684 /*[clinic end generated code: output=1b73788201e0aebd input=3b87fdd52556382d]*/
2829 { 2685 {
2830 char *ret; 2686 char *ret;
2831 char buffer[L_ctermid]; 2687 char buffer[L_ctermid];
2832 2688
2833 #ifdef USE_CTERMID_R 2689 #ifdef USE_CTERMID_R
2834 ret = ctermid_r(buffer); 2690 ret = ctermid_r(buffer);
2835 #else 2691 #else
2836 ret = ctermid(buffer); 2692 ret = ctermid(buffer);
2837 #endif 2693 #endif
2838 if (ret == NULL) 2694 if (ret == NULL)
2839 return posix_error(); 2695 return posix_error();
2840 return PyUnicode_DecodeFSDefault(buffer); 2696 return PyUnicode_DecodeFSDefault(buffer);
2841 } 2697 }
2842 #endif 2698 #endif /* HAVE_CTERMID */
2843 2699
2844 PyDoc_STRVAR(posix_chdir__doc__, 2700
2845 "chdir(path)\n\n\ 2701 /*[clinic input]
2846 Change the current working directory to the specified path.\n\ 2702 os.chdir
2847 \n\ 2703
2848 path may always be specified as a string.\n\ 2704 path: path_t(allow_fd='PATH_HAVE_FCHDIR')
2849 On some platforms, path may also be specified as an open file descriptor.\n\ 2705
2850 If this functionality is unavailable, using it raises an exception."); 2706 Change the current working directory to the specified path.
2851 2707
2852 static PyObject * 2708 path may always be specified as a string.
2853 posix_chdir(PyObject *self, PyObject *args, PyObject *kwargs) 2709 On some platforms, path may also be specified as an open file descriptor.
2854 { 2710 If this functionality is unavailable, using it raises an exception.
2855 path_t path; 2711 [clinic start generated code]*/
2712
2713 static PyObject *
2714 os_chdir_impl(PyModuleDef *module, path_t *path)
2715 /*[clinic end generated code: output=7358e3a20fb5aa93 input=1a4a15b4d12cb15d]*/
2716 {
2856 int result; 2717 int result;
2857 PyObject *return_value = NULL;
2858 static char *keywords[] = {"path", NULL};
2859
2860 memset(&path, 0, sizeof(path));
2861 path.function_name = "chdir";
2862 #ifdef HAVE_FCHDIR
2863 path.allow_fd = 1;
2864 #endif
2865 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:chdir", keywords,
2866 path_converter, &path
2867 ))
2868 return NULL;
2869 2718
2870 Py_BEGIN_ALLOW_THREADS 2719 Py_BEGIN_ALLOW_THREADS
2871 #ifdef MS_WINDOWS 2720 #ifdef MS_WINDOWS
2872 if (path.wide) 2721 if (path->wide)
2873 result = win32_wchdir(path.wide); 2722 result = win32_wchdir(path->wide);
2874 else 2723 else
2875 result = win32_chdir(path.narrow); 2724 result = win32_chdir(path->narrow);
2876 result = !result; /* on unix, success = 0, on windows, success = !0 */ 2725 result = !result; /* on unix, success = 0, on windows, success = !0 */
2877 #else 2726 #else
2878 #ifdef HAVE_FCHDIR 2727 #ifdef HAVE_FCHDIR
2879 if (path.fd != -1) 2728 if (path->fd != -1)
2880 result = fchdir(path.fd); 2729 result = fchdir(path->fd);
2881 else 2730 else
2882 #endif 2731 #endif
2883 result = chdir(path.narrow); 2732 result = chdir(path->narrow);
2884 #endif 2733 #endif
2885 Py_END_ALLOW_THREADS 2734 Py_END_ALLOW_THREADS
2886 2735
2887 if (result) { 2736 if (result) {
2888 return_value = path_error(&path); 2737 return path_error(path);
2889 goto exit; 2738 }
2890 } 2739
2891 2740 Py_RETURN_NONE;
2892 return_value = Py_None; 2741 }
2893 Py_INCREF(Py_None); 2742
2894
2895 exit:
2896 path_cleanup(&path);
2897 return return_value;
2898 }
2899 2743
2900 #ifdef HAVE_FCHDIR 2744 #ifdef HAVE_FCHDIR
2901 PyDoc_STRVAR(posix_fchdir__doc__, 2745 /*[clinic input]
2902 "fchdir(fd)\n\n\ 2746 os.fchdir
2903 Change to the directory of the given file descriptor. fd must be\n\ 2747
2904 opened on a directory, not a file. Equivalent to os.chdir(fd)."); 2748 fd: fildes
2905 2749
2906 static PyObject * 2750 Change to the directory of the given file descriptor.
2907 posix_fchdir(PyObject *self, PyObject *fdobj) 2751
2908 { 2752 fd must be opened on a directory, not a file.
2909 return posix_fildes(fdobj, fchdir); 2753 Equivalent to os.chdir(fd).
2754
2755 [clinic start generated code]*/
2756
2757 static PyObject *
2758 os_fchdir_impl(PyModuleDef *module, int fd)
2759 /*[clinic end generated code: output=361d30df6b2d3418 input=18e816479a2fa985]*/
2760 {
2761 return posix_fildes_fd(fd, fchdir);
2910 } 2762 }
2911 #endif /* HAVE_FCHDIR */ 2763 #endif /* HAVE_FCHDIR */
2912 2764
2913 2765
2914 PyDoc_STRVAR(posix_chmod__doc__, 2766 /*[clinic input]
2915 "chmod(path, mode, *, dir_fd=None, follow_symlinks=True)\n\n\ 2767 os.chmod
2916 Change the access permissions of a file.\n\ 2768
2917 \n\ 2769 path: path_t(allow_fd='PATH_HAVE_FCHMOD')
2918 path may always be specified as a string.\n\ 2770 Path to be modified. May always be specified as a str or bytes.
2919 On some platforms, path may also be specified as an open file descriptor.\n\ 2771 On some platforms, path may also be specified as an open file descriptor .
2920 If this functionality is unavailable, using it raises an exception.\n\ 2772 If this functionality is unavailable, using it raises an exception.
2921 If dir_fd is not None, it should be a file descriptor open to a directory,\n\ 2773
2922 and path should be relative; path will then be relative to that directory.\n\ 2774 mode: int
2923 If follow_symlinks is False, and the last element of the path is a symbolic\n\ 2775 Operating-system mode bitfield.
2924 link, chmod will modify the symbolic link itself instead of the file the\n\ 2776
2925 link points to.\n\ 2777 *
2926 It is an error to use dir_fd or follow_symlinks when specifying path as\n\ 2778
2927 an open file descriptor.\n\ 2779 dir_fd : dir_fd(requires='fchmodat') = None
2928 dir_fd and follow_symlinks may not be implemented on your platform.\n\ 2780 If not None, it should be a file descriptor open to a directory,
2929 If they are unavailable, using them will raise a NotImplementedError."); 2781 and path should be relative; path will then be relative to that
2930 2782 directory.
2931 static PyObject * 2783
2932 posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) 2784 follow_symlinks: bool = True
2933 { 2785 If False, and the last element of the path is a symbolic link,
2934 path_t path; 2786 chmod will modify the symbolic link itself instead of the file
2935 int mode; 2787 the link points to.
2936 int dir_fd = DEFAULT_DIR_FD; 2788
2937 int follow_symlinks = 1; 2789 Change the access permissions of a file.
2790
2791 It is an error to use dir_fd or follow_symlinks when specifying path as
2792 an open file descriptor.
2793 dir_fd and follow_symlinks may not be implemented on your platform.
2794 If they are unavailable, using them will raise a NotImplementedError.
2795
2796 [clinic start generated code]*/
2797
2798 static PyObject *
2799 os_chmod_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd,
2800 int follow_symlinks)
2801 /*[clinic end generated code: output=05e7f73b1a843ba2 input=7f1618e5e15cc196]*/
2802 {
2938 int result; 2803 int result;
2939 PyObject *return_value = NULL;
2940 static char *keywords[] = {"path", "mode", "dir_fd",
2941 "follow_symlinks", NULL};
2942 2804
2943 #ifdef MS_WINDOWS 2805 #ifdef MS_WINDOWS
2944 DWORD attr; 2806 DWORD attr;
2945 #endif 2807 #endif
2946 2808
2947 #ifdef HAVE_FCHMODAT 2809 #ifdef HAVE_FCHMODAT
2948 int fchmodat_nofollow_unsupported = 0; 2810 int fchmodat_nofollow_unsupported = 0;
2949 #endif 2811 #endif
2950 2812
2951 memset(&path, 0, sizeof(path));
2952 path.function_name = "chmod";
2953 #ifdef HAVE_FCHMOD
2954 path.allow_fd = 1;
2955 #endif
2956 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|$O&p:chmod", keywords,
2957 path_converter, &path,
2958 &mode,
2959 #ifdef HAVE_FCHMODAT
2960 dir_fd_converter, &dir_fd,
2961 #else
2962 dir_fd_unavailable, &dir_fd,
2963 #endif
2964 &follow_symlinks))
2965 return NULL;
2966
2967 #if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD)) 2813 #if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD))
2968 if (follow_symlinks_specified("chmod", follow_symlinks)) 2814 if (follow_symlinks_specified("chmod", follow_symlinks))
2969 goto exit; 2815 return NULL;
2970 #endif 2816 #endif
2971 2817
2972 #ifdef MS_WINDOWS 2818 #ifdef MS_WINDOWS
2973 Py_BEGIN_ALLOW_THREADS 2819 Py_BEGIN_ALLOW_THREADS
2974 if (path.wide) 2820 if (path->wide)
2975 attr = GetFileAttributesW(path.wide); 2821 attr = GetFileAttributesW(path->wide);
2976 else 2822 else
2977 attr = GetFileAttributesA(path.narrow); 2823 attr = GetFileAttributesA(path->narrow);
2978 if (attr == INVALID_FILE_ATTRIBUTES) 2824 if (attr == INVALID_FILE_ATTRIBUTES)
2979 result = 0; 2825 result = 0;
2980 else { 2826 else {
2981 if (mode & _S_IWRITE) 2827 if (mode & _S_IWRITE)
2982 attr &= ~FILE_ATTRIBUTE_READONLY; 2828 attr &= ~FILE_ATTRIBUTE_READONLY;
2983 else 2829 else
2984 attr |= FILE_ATTRIBUTE_READONLY; 2830 attr |= FILE_ATTRIBUTE_READONLY;
2985 if (path.wide) 2831 if (path->wide)
2986 result = SetFileAttributesW(path.wide, attr); 2832 result = SetFileAttributesW(path->wide, attr);
2987 else 2833 else
2988 result = SetFileAttributesA(path.narrow, attr); 2834 result = SetFileAttributesA(path->narrow, attr);
2989 } 2835 }
2990 Py_END_ALLOW_THREADS 2836 Py_END_ALLOW_THREADS
2991 2837
2992 if (!result) { 2838 if (!result) {
2993 return_value = path_error(&path); 2839 return path_error(path);
2994 goto exit;
2995 } 2840 }
2996 #else /* MS_WINDOWS */ 2841 #else /* MS_WINDOWS */
2997 Py_BEGIN_ALLOW_THREADS 2842 Py_BEGIN_ALLOW_THREADS
2998 #ifdef HAVE_FCHMOD 2843 #ifdef HAVE_FCHMOD
2999 if (path.fd != -1) 2844 if (path->fd != -1)
3000 result = fchmod(path.fd, mode); 2845 result = fchmod(path->fd, mode);
3001 else 2846 else
3002 #endif 2847 #endif
3003 #ifdef HAVE_LCHMOD 2848 #ifdef HAVE_LCHMOD
3004 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) 2849 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3005 result = lchmod(path.narrow, mode); 2850 result = lchmod(path->narrow, mode);
3006 else 2851 else
3007 #endif 2852 #endif
3008 #ifdef HAVE_FCHMODAT 2853 #ifdef HAVE_FCHMODAT
3009 if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) { 2854 if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) {
3010 /* 2855 /*
3011 * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW! 2856 * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW!
3012 * The documentation specifically shows how to use it, 2857 * The documentation specifically shows how to use it,
3013 * and then says it isn't implemented yet. 2858 * and then says it isn't implemented yet.
3014 * (true on linux with glibc 2.15, and openindiana 3.x) 2859 * (true on linux with glibc 2.15, and openindiana 3.x)
3015 * 2860 *
3016 * Once it is supported, os.chmod will automatically 2861 * Once it is supported, os.chmod will automatically
3017 * support dir_fd and follow_symlinks=False. (Hopefully.) 2862 * support dir_fd and follow_symlinks=False. (Hopefully.)
3018 * Until then, we need to be careful what exception we raise. 2863 * Until then, we need to be careful what exception we raise.
3019 */ 2864 */
3020 result = fchmodat(dir_fd, path.narrow, mode, 2865 result = fchmodat(dir_fd, path->narrow, mode,
3021 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); 2866 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3022 /* 2867 /*
3023 * But wait! We can't throw the exception without allowing threads, 2868 * But wait! We can't throw the exception without allowing threads,
3024 * and we can't do that in this nested scope. (Macro trickery, sigh.) 2869 * and we can't do that in this nested scope. (Macro trickery, sigh.)
3025 */ 2870 */
3026 fchmodat_nofollow_unsupported = 2871 fchmodat_nofollow_unsupported =
3027 result && 2872 result &&
3028 ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) && 2873 ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) &&
3029 !follow_symlinks; 2874 !follow_symlinks;
3030 } 2875 }
3031 else 2876 else
3032 #endif 2877 #endif
3033 result = chmod(path.narrow, mode); 2878 result = chmod(path->narrow, mode);
3034 Py_END_ALLOW_THREADS 2879 Py_END_ALLOW_THREADS
3035 2880
3036 if (result) { 2881 if (result) {
3037 #ifdef HAVE_FCHMODAT 2882 #ifdef HAVE_FCHMODAT
3038 if (fchmodat_nofollow_unsupported) { 2883 if (fchmodat_nofollow_unsupported) {
3039 if (dir_fd != DEFAULT_DIR_FD) 2884 if (dir_fd != DEFAULT_DIR_FD)
3040 dir_fd_and_follow_symlinks_invalid("chmod", 2885 dir_fd_and_follow_symlinks_invalid("chmod",
3041 dir_fd, follow_symlinks); 2886 dir_fd, follow_symlinks);
3042 else 2887 else
3043 follow_symlinks_specified("chmod", follow_symlinks); 2888 follow_symlinks_specified("chmod", follow_symlinks);
3044 } 2889 }
3045 else 2890 else
3046 #endif 2891 #endif
3047 return_value = path_error(&path); 2892 return path_error(path);
3048 goto exit; 2893 }
3049 } 2894 #endif
3050 #endif 2895
3051 2896 Py_RETURN_NONE;
3052 Py_INCREF(Py_None);
3053 return_value = Py_None;
3054 exit:
3055 path_cleanup(&path);
3056 return return_value;
3057 } 2897 }
3058 2898
3059 2899
3060 #ifdef HAVE_FCHMOD 2900 #ifdef HAVE_FCHMOD
3061 PyDoc_STRVAR(posix_fchmod__doc__, 2901 /*[clinic input]
3062 "fchmod(fd, mode)\n\n\ 2902 os.fchmod
3063 Change the access permissions of the file given by file\n\ 2903
3064 descriptor fd. Equivalent to os.chmod(fd, mode)."); 2904 fd: int
3065 2905 mode: int
3066 static PyObject * 2906
3067 posix_fchmod(PyObject *self, PyObject *args) 2907 Change the access permissions of the file given by file descriptor fd.
3068 { 2908
3069 int fd, mode, res; 2909 Equivalent to os.chmod(fd, mode).
3070 if (!PyArg_ParseTuple(args, "ii:fchmod", &fd, &mode)) 2910 [clinic start generated code]*/
3071 return NULL; 2911
2912 static PyObject *
2913 os_fchmod_impl(PyModuleDef *module, int fd, int mode)
2914 /*[clinic end generated code: output=2ee31ca226d1ed33 input=8ab11975ca01ee5b]*/
2915 {
2916 int res;
2917 int async_err = 0;
2918
2919 do {
2920 Py_BEGIN_ALLOW_THREADS
2921 res = fchmod(fd, mode);
2922 Py_END_ALLOW_THREADS
2923 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
2924 if (res != 0)
2925 return (!async_err) ? posix_error() : NULL;
2926
2927 Py_RETURN_NONE;
2928 }
2929 #endif /* HAVE_FCHMOD */
2930
2931
2932 #ifdef HAVE_LCHMOD
2933 /*[clinic input]
2934 os.lchmod
2935
2936 path: path_t
2937 mode: int
2938
2939 Change the access permissions of a file, without following symbolic links.
2940
2941 If path is a symlink, this affects the link itself rather than the target.
2942 Equivalent to chmod(path, mode, follow_symlinks=False)."
2943 [clinic start generated code]*/
2944
2945 static PyObject *
2946 os_lchmod_impl(PyModuleDef *module, path_t *path, int mode)
2947 /*[clinic end generated code: output=7c0cc46588d89e46 input=90c5663c7465d24f]*/
2948 {
2949 int res;
3072 Py_BEGIN_ALLOW_THREADS 2950 Py_BEGIN_ALLOW_THREADS
3073 res = fchmod(fd, mode); 2951 res = lchmod(path->narrow, mode);
3074 Py_END_ALLOW_THREADS
3075 if (res < 0)
3076 return posix_error();
3077 Py_RETURN_NONE;
3078 }
3079 #endif /* HAVE_FCHMOD */
3080
3081 #ifdef HAVE_LCHMOD
3082 PyDoc_STRVAR(posix_lchmod__doc__,
3083 "lchmod(path, mode)\n\n\
3084 Change the access permissions of a file. If path is a symlink, this\n\
3085 affects the link itself rather than the target.\n\
3086 Equivalent to chmod(path, mode, follow_symlinks=False).");
3087
3088 static PyObject *
3089 posix_lchmod(PyObject *self, PyObject *args)
3090 {
3091 path_t path;
3092 int i;
3093 int res;
3094 memset(&path, 0, sizeof(path));
3095 path.function_name = "lchmod";
3096 if (!PyArg_ParseTuple(args, "O&i:lchmod",
3097 path_converter, &path, &i))
3098 return NULL;
3099 Py_BEGIN_ALLOW_THREADS
3100 res = lchmod(path.narrow, i);
3101 Py_END_ALLOW_THREADS 2952 Py_END_ALLOW_THREADS
3102 if (res < 0) { 2953 if (res < 0) {
3103 path_error(&path); 2954 path_error(path);
3104 path_cleanup(&path);
3105 return NULL; 2955 return NULL;
3106 } 2956 }
3107 path_cleanup(&path);
3108 Py_RETURN_NONE; 2957 Py_RETURN_NONE;
3109 } 2958 }
3110 #endif /* HAVE_LCHMOD */ 2959 #endif /* HAVE_LCHMOD */
3111 2960
3112 2961
3113 #ifdef HAVE_CHFLAGS 2962 #ifdef HAVE_CHFLAGS
3114 PyDoc_STRVAR(posix_chflags__doc__, 2963 /*[clinic input]
3115 "chflags(path, flags, *, follow_symlinks=True)\n\n\ 2964 os.chflags
3116 Set file flags.\n\ 2965
3117 \n\ 2966 path: path_t
3118 If follow_symlinks is False, and the last element of the path is a symbolic\n\ 2967 flags: unsigned_long(bitwise=True)
3119 link, chflags will change flags on the symbolic link itself instead of the\n\ 2968 follow_symlinks: bool=True
3120 file the link points to.\n\ 2969
3121 follow_symlinks may not be implemented on your platform. If it is\n\ 2970 Set file flags.
3122 unavailable, using it will raise a NotImplementedError."); 2971
3123 2972 If follow_symlinks is False, and the last element of the path is a symbolic
3124 static PyObject * 2973 link, chflags will change flags on the symbolic link itself instead of the
3125 posix_chflags(PyObject *self, PyObject *args, PyObject *kwargs) 2974 file the link points to.
3126 { 2975 follow_symlinks may not be implemented on your platform. If it is
3127 path_t path; 2976 unavailable, using it will raise a NotImplementedError.
3128 unsigned long flags; 2977
3129 int follow_symlinks = 1; 2978 [clinic start generated code]*/
2979
2980 static PyObject *
2981 os_chflags_impl(PyModuleDef *module, path_t *path, unsigned long flags,
2982 int follow_symlinks)
2983 /*[clinic end generated code: output=ff2d6e73534a95b9 input=0327e29feb876236]*/
2984 {
3130 int result; 2985 int result;
3131 PyObject *return_value = NULL;
3132 static char *keywords[] = {"path", "flags", "follow_symlinks", NULL};
3133
3134 memset(&path, 0, sizeof(path));
3135 path.function_name = "chflags";
3136 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&k|$i:chflags", keywords,
3137 path_converter, &path,
3138 &flags, &follow_symlinks))
3139 return NULL;
3140 2986
3141 #ifndef HAVE_LCHFLAGS 2987 #ifndef HAVE_LCHFLAGS
3142 if (follow_symlinks_specified("chflags", follow_symlinks)) 2988 if (follow_symlinks_specified("chflags", follow_symlinks))
3143 goto exit; 2989 return NULL;
3144 #endif 2990 #endif
3145 2991
3146 Py_BEGIN_ALLOW_THREADS 2992 Py_BEGIN_ALLOW_THREADS
3147 #ifdef HAVE_LCHFLAGS 2993 #ifdef HAVE_LCHFLAGS
3148 if (!follow_symlinks) 2994 if (!follow_symlinks)
3149 result = lchflags(path.narrow, flags); 2995 result = lchflags(path->narrow, flags);
3150 else 2996 else
3151 #endif 2997 #endif
3152 result = chflags(path.narrow, flags); 2998 result = chflags(path->narrow, flags);
3153 Py_END_ALLOW_THREADS 2999 Py_END_ALLOW_THREADS
3154 3000
3155 if (result) { 3001 if (result)
3156 return_value = path_error(&path); 3002 return path_error(path);
3157 goto exit; 3003
3158 } 3004 Py_RETURN_NONE;
3159
3160 return_value = Py_None;
3161 Py_INCREF(Py_None);
3162
3163 exit:
3164 path_cleanup(&path);
3165 return return_value;
3166 } 3005 }
3167 #endif /* HAVE_CHFLAGS */ 3006 #endif /* HAVE_CHFLAGS */
3168 3007
3008
3169 #ifdef HAVE_LCHFLAGS 3009 #ifdef HAVE_LCHFLAGS
3170 PyDoc_STRVAR(posix_lchflags__doc__, 3010 /*[clinic input]
3171 "lchflags(path, flags)\n\n\ 3011 os.lchflags
3172 Set file flags.\n\ 3012
3173 This function will not follow symbolic links.\n\ 3013 path: path_t
3174 Equivalent to chflags(path, flags, follow_symlinks=False)."); 3014 flags: unsigned_long(bitwise=True)
3175 3015
3176 static PyObject * 3016 Set file flags.
3177 posix_lchflags(PyObject *self, PyObject *args) 3017
3178 { 3018 This function will not follow symbolic links.
3179 path_t path; 3019 Equivalent to chflags(path, flags, follow_symlinks=False).
3180 unsigned long flags; 3020 [clinic start generated code]*/
3021
3022 static PyObject *
3023 os_lchflags_impl(PyModuleDef *module, path_t *path, unsigned long flags)
3024 /*[clinic end generated code: output=6741322fb949661b input=f9f82ea8b585ca9d]*/
3025 {
3181 int res; 3026 int res;
3182 memset(&path, 0, sizeof(path));
3183 path.function_name = "lchflags";
3184 if (!PyArg_ParseTuple(args, "O&k:lchflags",
3185 path_converter, &path, &flags))
3186 return NULL;
3187 Py_BEGIN_ALLOW_THREADS 3027 Py_BEGIN_ALLOW_THREADS
3188 res = lchflags(path.narrow, flags); 3028 res = lchflags(path->narrow, flags);
3189 Py_END_ALLOW_THREADS 3029 Py_END_ALLOW_THREADS
3190 if (res < 0) { 3030 if (res < 0) {
3191 path_error(&path); 3031 return path_error(path);
3192 path_cleanup(&path); 3032 }
3193 return NULL;
3194 }
3195 path_cleanup(&path);
3196 Py_RETURN_NONE; 3033 Py_RETURN_NONE;
3197 } 3034 }
3198 #endif /* HAVE_LCHFLAGS */ 3035 #endif /* HAVE_LCHFLAGS */
3199 3036
3037
3200 #ifdef HAVE_CHROOT 3038 #ifdef HAVE_CHROOT
3201 PyDoc_STRVAR(posix_chroot__doc__, 3039 /*[clinic input]
3202 "chroot(path)\n\n\ 3040 os.chroot
3203 Change root directory to path."); 3041 path: path_t
3204 3042
3205 static PyObject * 3043 Change root directory to path.
3206 posix_chroot(PyObject *self, PyObject *args) 3044
3207 { 3045 [clinic start generated code]*/
3208 return posix_1str("chroot", args, "O&:chroot", chroot); 3046
3209 } 3047 static PyObject *
3210 #endif 3048 os_chroot_impl(PyModuleDef *module, path_t *path)
3049 /*[clinic end generated code: output=b6dbfabe74ecaa9d input=14822965652c3dc3]*/
3050 {
3051 int res;
3052 Py_BEGIN_ALLOW_THREADS
3053 res = chroot(path->narrow);
3054 Py_END_ALLOW_THREADS
3055 if (res < 0)
3056 return path_error(path);
3057 Py_RETURN_NONE;
3058 }
3059 #endif /* HAVE_CHROOT */
3060
3211 3061
3212 #ifdef HAVE_FSYNC 3062 #ifdef HAVE_FSYNC
3213 PyDoc_STRVAR(posix_fsync__doc__, 3063 /*[clinic input]
3214 "fsync(fildes)\n\n\ 3064 os.fsync
3215 force write of file with filedescriptor to disk."); 3065
3216 3066 fd: fildes
3217 static PyObject * 3067
3218 posix_fsync(PyObject *self, PyObject *fdobj) 3068 Force write of fd to disk.
3219 { 3069 [clinic start generated code]*/
3220 return posix_fildes(fdobj, fsync); 3070
3071 static PyObject *
3072 os_fsync_impl(PyModuleDef *module, int fd)
3073 /*[clinic end generated code: output=83a350851064aea7 input=21c3645c056967f2]*/
3074 {
3075 return posix_fildes_fd(fd, fsync);
3221 } 3076 }
3222 #endif /* HAVE_FSYNC */ 3077 #endif /* HAVE_FSYNC */
3223 3078
3079
3224 #ifdef HAVE_SYNC 3080 #ifdef HAVE_SYNC
3225 PyDoc_STRVAR(posix_sync__doc__, 3081 /*[clinic input]
3226 "sync()\n\n\ 3082 os.sync
3227 Force write of everything to disk."); 3083
3228 3084 Force write of everything to disk.
3229 static PyObject * 3085 [clinic start generated code]*/
3230 posix_sync(PyObject *self, PyObject *noargs) 3086
3087 static PyObject *
3088 os_sync_impl(PyModuleDef *module)
3089 /*[clinic end generated code: output=ba524f656c201c40 input=84749fe5e9b404ff]*/
3231 { 3090 {
3232 Py_BEGIN_ALLOW_THREADS 3091 Py_BEGIN_ALLOW_THREADS
3233 sync(); 3092 sync();
3234 Py_END_ALLOW_THREADS 3093 Py_END_ALLOW_THREADS
3235 Py_RETURN_NONE; 3094 Py_RETURN_NONE;
3236 } 3095 }
3237 #endif 3096 #endif /* HAVE_SYNC */
3097
3238 3098
3239 #ifdef HAVE_FDATASYNC 3099 #ifdef HAVE_FDATASYNC
3240
3241 #ifdef __hpux 3100 #ifdef __hpux
3242 extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */ 3101 extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */
3243 #endif 3102 #endif
3244 3103
3245 PyDoc_STRVAR(posix_fdatasync__doc__, 3104 /*[clinic input]
3246 "fdatasync(fildes)\n\n\ 3105 os.fdatasync
3247 force write of file with filedescriptor to disk.\n\ 3106
3248 does not force update of metadata."); 3107 fd: fildes
3249 3108
3250 static PyObject * 3109 Force write of fd to disk without forcing update of metadata.
3251 posix_fdatasync(PyObject *self, PyObject *fdobj) 3110 [clinic start generated code]*/
3252 { 3111
3253 return posix_fildes(fdobj, fdatasync); 3112 static PyObject *
3113 os_fdatasync_impl(PyModuleDef *module, int fd)
3114 /*[clinic end generated code: output=e0f04a3aff515b75 input=bc74791ee54dd291]*/
3115 {
3116 return posix_fildes_fd(fd, fdatasync);
3254 } 3117 }
3255 #endif /* HAVE_FDATASYNC */ 3118 #endif /* HAVE_FDATASYNC */
3256 3119
3257 3120
3258 #ifdef HAVE_CHOWN 3121 #ifdef HAVE_CHOWN
3259 PyDoc_STRVAR(posix_chown__doc__, 3122 /*[clinic input]
3260 "chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)\n\n\ 3123 os.chown
3261 Change the owner and group id of path to the numeric uid and gid.\n\ 3124
3262 \n\ 3125 path : path_t(allow_fd='PATH_HAVE_FCHOWN')
3263 path may always be specified as a string.\n\ 3126 Path to be examined; can be string, bytes, or open-file-descriptor int.
3264 On some platforms, path may also be specified as an open file descriptor.\n\ 3127
3265 If this functionality is unavailable, using it raises an exception.\n\ 3128 uid: uid_t
3266 If dir_fd is not None, it should be a file descriptor open to a directory,\n\ 3129
3267 and path should be relative; path will then be relative to that directory.\n\ 3130 gid: gid_t
3268 If follow_symlinks is False, and the last element of the path is a symbolic\n\ 3131
3269 link, chown will modify the symbolic link itself instead of the file the\n\ 3132 *
3270 link points to.\n\ 3133
3271 It is an error to use dir_fd or follow_symlinks when specifying path as\n\ 3134 dir_fd : dir_fd(requires='fchownat') = None
3272 an open file descriptor.\n\ 3135 If not None, it should be a file descriptor open to a directory,
3273 dir_fd and follow_symlinks may not be implemented on your platform.\n\ 3136 and path should be relative; path will then be relative to that
3274 If they are unavailable, using them will raise a NotImplementedError."); 3137 directory.
3275 3138
3276 static PyObject * 3139 follow_symlinks: bool = True
3277 posix_chown(PyObject *self, PyObject *args, PyObject *kwargs) 3140 If False, and the last element of the path is a symbolic link,
3278 { 3141 stat will examine the symbolic link itself instead of the file
3279 path_t path; 3142 the link points to.
3280 uid_t uid; 3143
3281 gid_t gid; 3144 Change the owner and group id of path to the numeric uid and gid.\
3282 int dir_fd = DEFAULT_DIR_FD; 3145
3283 int follow_symlinks = 1; 3146 path may always be specified as a string.
3147 On some platforms, path may also be specified as an open file descriptor.
3148 If this functionality is unavailable, using it raises an exception.
3149 If dir_fd is not None, it should be a file descriptor open to a directory,
3150 and path should be relative; path will then be relative to that directory.
3151 If follow_symlinks is False, and the last element of the path is a symbolic
3152 link, chown will modify the symbolic link itself instead of the file the
3153 link points to.
3154 It is an error to use dir_fd or follow_symlinks when specifying path as
3155 an open file descriptor.
3156 dir_fd and follow_symlinks may not be implemented on your platform.
3157 If they are unavailable, using them will raise a NotImplementedError.
3158
3159 [clinic start generated code]*/
3160
3161 static PyObject *
3162 os_chown_impl(PyModuleDef *module, path_t *path, uid_t uid, gid_t gid,
3163 int dir_fd, int follow_symlinks)
3164 /*[clinic end generated code: output=e0a4559f394dbd91 input=a61cc35574814d5d]*/
3165 {
3284 int result; 3166 int result;
3285 PyObject *return_value = NULL;
3286 static char *keywords[] = {"path", "uid", "gid", "dir_fd",
3287 "follow_symlinks", NULL};
3288
3289 memset(&path, 0, sizeof(path));
3290 path.function_name = "chown";
3291 #ifdef HAVE_FCHOWN
3292 path.allow_fd = 1;
3293 #endif
3294 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&O&|$O&p:chown", keywords ,
3295 path_converter, &path,
3296 _Py_Uid_Converter, &uid,
3297 _Py_Gid_Converter, &gid,
3298 #ifdef HAVE_FCHOWNAT
3299 dir_fd_converter, &dir_fd,
3300 #else
3301 dir_fd_unavailable, &dir_fd,
3302 #endif
3303 &follow_symlinks))
3304 return NULL;
3305 3167
3306 #if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT)) 3168 #if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT))
3307 if (follow_symlinks_specified("chown", follow_symlinks)) 3169 if (follow_symlinks_specified("chown", follow_symlinks))
3308 goto exit; 3170 return NULL;
3309 #endif 3171 #endif
3310 if (dir_fd_and_fd_invalid("chown", dir_fd, path.fd) || 3172 if (dir_fd_and_fd_invalid("chown", dir_fd, path->fd) ||
3311 fd_and_follow_symlinks_invalid("chown", path.fd, follow_symlinks)) 3173 fd_and_follow_symlinks_invalid("chown", path->fd, follow_symlinks))
3312 goto exit; 3174 return NULL;
3313 3175
3314 #ifdef __APPLE__ 3176 #ifdef __APPLE__
3315 /* 3177 /*
3316 * This is for Mac OS X 10.3, which doesn't have lchown. 3178 * This is for Mac OS X 10.3, which doesn't have lchown.
3317 * (But we still have an lchown symbol because of weak-linking.) 3179 * (But we still have an lchown symbol because of weak-linking.)
3318 * It doesn't have fchownat either. So there's no possibility 3180 * It doesn't have fchownat either. So there's no possibility
3319 * of a graceful failover. 3181 * of a graceful failover.
3320 */ 3182 */
3321 if ((!follow_symlinks) && (lchown == NULL)) { 3183 if ((!follow_symlinks) && (lchown == NULL)) {
3322 follow_symlinks_specified("chown", follow_symlinks); 3184 follow_symlinks_specified("chown", follow_symlinks);
3323 goto exit; 3185 return NULL;
3324 } 3186 }
3325 #endif 3187 #endif
3326 3188
3327 Py_BEGIN_ALLOW_THREADS 3189 Py_BEGIN_ALLOW_THREADS
3328 #ifdef HAVE_FCHOWN 3190 #ifdef HAVE_FCHOWN
3329 if (path.fd != -1) 3191 if (path->fd != -1)
3330 result = fchown(path.fd, uid, gid); 3192 result = fchown(path->fd, uid, gid);
3331 else 3193 else
3332 #endif 3194 #endif
3333 #ifdef HAVE_LCHOWN 3195 #ifdef HAVE_LCHOWN
3334 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) 3196 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3335 result = lchown(path.narrow, uid, gid); 3197 result = lchown(path->narrow, uid, gid);
3336 else 3198 else
3337 #endif 3199 #endif
3338 #ifdef HAVE_FCHOWNAT 3200 #ifdef HAVE_FCHOWNAT
3339 if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) 3201 if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks))
3340 result = fchownat(dir_fd, path.narrow, uid, gid, 3202 result = fchownat(dir_fd, path->narrow, uid, gid,
3341 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); 3203 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3342 else 3204 else
3343 #endif 3205 #endif
3344 result = chown(path.narrow, uid, gid); 3206 result = chown(path->narrow, uid, gid);
3345 Py_END_ALLOW_THREADS 3207 Py_END_ALLOW_THREADS
3346 3208
3347 if (result) { 3209 if (result)
3348 return_value = path_error(&path); 3210 return path_error(path);
3349 goto exit; 3211
3350 } 3212 Py_RETURN_NONE;
3351
3352 return_value = Py_None;
3353 Py_INCREF(Py_None);
3354
3355 exit:
3356 path_cleanup(&path);
3357 return return_value;
3358 } 3213 }
3359 #endif /* HAVE_CHOWN */ 3214 #endif /* HAVE_CHOWN */
3360 3215
3216
3361 #ifdef HAVE_FCHOWN 3217 #ifdef HAVE_FCHOWN
3362 PyDoc_STRVAR(posix_fchown__doc__, 3218 /*[clinic input]
3363 "fchown(fd, uid, gid)\n\n\ 3219 os.fchown
3364 Change the owner and group id of the file given by file descriptor\n\ 3220
3365 fd to the numeric uid and gid. Equivalent to os.chown(fd, uid, gid)."); 3221 fd: int
3366 3222 uid: uid_t
3367 static PyObject * 3223 gid: gid_t
3368 posix_fchown(PyObject *self, PyObject *args) 3224
3369 { 3225 Change the owner and group id of the file specified by file descriptor.
3370 int fd; 3226
3371 uid_t uid; 3227 Equivalent to os.chown(fd, uid, gid).
3372 gid_t gid; 3228
3229 [clinic start generated code]*/
3230
3231 static PyObject *
3232 os_fchown_impl(PyModuleDef *module, int fd, uid_t uid, gid_t gid)
3233 /*[clinic end generated code: output=7545abf8f6086d76 input=3af544ba1b13a0d7]*/
3234 {
3373 int res; 3235 int res;
3374 if (!PyArg_ParseTuple(args, "iO&O&:fchown", &fd, 3236 int async_err = 0;
3375 _Py_Uid_Converter, &uid, 3237
3376 _Py_Gid_Converter, &gid)) 3238 do {
3377 return NULL; 3239 Py_BEGIN_ALLOW_THREADS
3240 res = fchown(fd, uid, gid);
3241 Py_END_ALLOW_THREADS
3242 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
3243 if (res != 0)
3244 return (!async_err) ? posix_error() : NULL;
3245
3246 Py_RETURN_NONE;
3247 }
3248 #endif /* HAVE_FCHOWN */
3249
3250
3251 #ifdef HAVE_LCHOWN
3252 /*[clinic input]
3253 os.lchown
3254
3255 path : path_t
3256 uid: uid_t
3257 gid: gid_t
3258
3259 Change the owner and group id of path to the numeric uid and gid.
3260
3261 This function will not follow symbolic links.
3262 Equivalent to os.chown(path, uid, gid, follow_symlinks=False).
3263 [clinic start generated code]*/
3264
3265 static PyObject *
3266 os_lchown_impl(PyModuleDef *module, path_t *path, uid_t uid, gid_t gid)
3267 /*[clinic end generated code: output=bb0d2da1579ac275 input=b1c6014d563a7161]*/
3268 {
3269 int res;
3378 Py_BEGIN_ALLOW_THREADS 3270 Py_BEGIN_ALLOW_THREADS
3379 res = fchown(fd, uid, gid); 3271 res = lchown(path->narrow, uid, gid);
3380 Py_END_ALLOW_THREADS
3381 if (res < 0)
3382 return posix_error();
3383 Py_RETURN_NONE;
3384 }
3385 #endif /* HAVE_FCHOWN */
3386
3387 #ifdef HAVE_LCHOWN
3388 PyDoc_STRVAR(posix_lchown__doc__,
3389 "lchown(path, uid, gid)\n\n\
3390 Change the owner and group id of path to the numeric uid and gid.\n\
3391 This function will not follow symbolic links.\n\
3392 Equivalent to os.chown(path, uid, gid, follow_symlinks=False).");
3393
3394 static PyObject *
3395 posix_lchown(PyObject *self, PyObject *args)
3396 {
3397 path_t path;
3398 uid_t uid;
3399 gid_t gid;
3400 int res;
3401 memset(&path, 0, sizeof(path));
3402 path.function_name = "lchown";
3403 if (!PyArg_ParseTuple(args, "O&O&O&:lchown",
3404 path_converter, &path,
3405 _Py_Uid_Converter, &uid,
3406 _Py_Gid_Converter, &gid))
3407 return NULL;
3408 Py_BEGIN_ALLOW_THREADS
3409 res = lchown(path.narrow, uid, gid);
3410 Py_END_ALLOW_THREADS 3272 Py_END_ALLOW_THREADS
3411 if (res < 0) { 3273 if (res < 0) {
3412 path_error(&path); 3274 return path_error(path);
3413 path_cleanup(&path); 3275 }
3414 return NULL; 3276 Py_RETURN_NONE;
3415 }
3416 path_cleanup(&path);
3417 Py_INCREF(Py_None);
3418 return Py_None;
3419 } 3277 }
3420 #endif /* HAVE_LCHOWN */ 3278 #endif /* HAVE_LCHOWN */
3421 3279
3422 3280
3423 static PyObject * 3281 static PyObject *
3424 posix_getcwd(int use_bytes) 3282 posix_getcwd(int use_bytes)
3425 { 3283 {
3426 char *buf, *tmpbuf; 3284 char *buf, *tmpbuf;
3427 char *cwd; 3285 char *cwd;
3428 const size_t chunk = 1024; 3286 const size_t chunk = 1024;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
3462 } 3320 }
3463 3321
3464 if (win32_warn_bytes_api()) 3322 if (win32_warn_bytes_api())
3465 return NULL; 3323 return NULL;
3466 #endif 3324 #endif
3467 3325
3468 buf = cwd = NULL; 3326 buf = cwd = NULL;
3469 Py_BEGIN_ALLOW_THREADS 3327 Py_BEGIN_ALLOW_THREADS
3470 do { 3328 do {
3471 buflen += chunk; 3329 buflen += chunk;
3330 #ifdef MS_WINDOWS
3331 if (buflen > INT_MAX) {
3332 PyErr_NoMemory();
3333 break;
3334 }
3335 #endif
3472 tmpbuf = PyMem_RawRealloc(buf, buflen); 3336 tmpbuf = PyMem_RawRealloc(buf, buflen);
3473 if (tmpbuf == NULL) 3337 if (tmpbuf == NULL)
3474 break; 3338 break;
3475 3339
3476 buf = tmpbuf; 3340 buf = tmpbuf;
3341 #ifdef MS_WINDOWS
3342 cwd = getcwd(buf, (int)buflen);
3343 #else
3477 cwd = getcwd(buf, buflen); 3344 cwd = getcwd(buf, buflen);
3345 #endif
3478 } while (cwd == NULL && errno == ERANGE); 3346 } while (cwd == NULL && errno == ERANGE);
3479 Py_END_ALLOW_THREADS 3347 Py_END_ALLOW_THREADS
3480 3348
3481 if (cwd == NULL) { 3349 if (cwd == NULL) {
3482 PyMem_RawFree(buf); 3350 PyMem_RawFree(buf);
3483 return posix_error(); 3351 return posix_error();
3484 } 3352 }
3485 3353
3486 if (use_bytes) 3354 if (use_bytes)
3487 obj = PyBytes_FromStringAndSize(buf, strlen(buf)); 3355 obj = PyBytes_FromStringAndSize(buf, strlen(buf));
3488 else 3356 else
3489 obj = PyUnicode_DecodeFSDefault(buf); 3357 obj = PyUnicode_DecodeFSDefault(buf);
3490 PyMem_RawFree(buf); 3358 PyMem_RawFree(buf);
3491 3359
3492 return obj; 3360 return obj;
3493 } 3361 }
3494 3362
3495 PyDoc_STRVAR(posix_getcwd__doc__, 3363
3496 "getcwd() -> path\n\n\ 3364 /*[clinic input]
3497 Return a unicode string representing the current working directory."); 3365 os.getcwd
3498 3366
3499 static PyObject * 3367 Return a unicode string representing the current working directory.
3500 posix_getcwd_unicode(PyObject *self) 3368 [clinic start generated code]*/
3369
3370 static PyObject *
3371 os_getcwd_impl(PyModuleDef *module)
3372 /*[clinic end generated code: output=efe3a8c0121525ea input=f069211bb70e3d39]*/
3501 { 3373 {
3502 return posix_getcwd(0); 3374 return posix_getcwd(0);
3503 } 3375 }
3504 3376
3505 PyDoc_STRVAR(posix_getcwdb__doc__, 3377
3506 "getcwdb() -> path\n\n\ 3378 /*[clinic input]
3507 Return a bytes string representing the current working directory."); 3379 os.getcwdb
3508 3380
3509 static PyObject * 3381 Return a bytes string representing the current working directory.
3510 posix_getcwd_bytes(PyObject *self) 3382 [clinic start generated code]*/
3383
3384 static PyObject *
3385 os_getcwdb_impl(PyModuleDef *module)
3386 /*[clinic end generated code: output=7fce42ee4b2a296a input=f6f6a378dad3d9cb]*/
3511 { 3387 {
3512 return posix_getcwd(1); 3388 return posix_getcwd(1);
3513 } 3389 }
3390
3514 3391
3515 #if ((!defined(HAVE_LINK)) && defined(MS_WINDOWS)) 3392 #if ((!defined(HAVE_LINK)) && defined(MS_WINDOWS))
3516 #define HAVE_LINK 1 3393 #define HAVE_LINK 1
3517 #endif 3394 #endif
3518 3395
3519 #ifdef HAVE_LINK 3396 #ifdef HAVE_LINK
3520 PyDoc_STRVAR(posix_link__doc__, 3397 /*[clinic input]
3521 "link(src, dst, *, src_dir_fd=None, dst_dir_fd=None, follow_symlinks=True)\n\n\ 3398
3522 Create a hard link to a file.\n\ 3399 os.link
3523 \n\ 3400
3524 If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\ 3401 src : path_t
3525 descriptor open to a directory, and the respective path string (src or dst)\n\ 3402 dst : path_t
3526 should be relative; the path will then be relative to that directory.\n\ 3403 *
3527 If follow_symlinks is False, and the last element of src is a symbolic\n\ 3404 src_dir_fd : dir_fd = None
3528 link, link will create a link to the symbolic link itself instead of the\n\ 3405 dst_dir_fd : dir_fd = None
3529 file the link points to.\n\ 3406 follow_symlinks: bool = True
3530 src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your\n\ 3407
3531 platform. If they are unavailable, using them will raise a\n\ 3408 Create a hard link to a file.
3532 NotImplementedError."); 3409
3533 3410 If either src_dir_fd or dst_dir_fd is not None, it should be a file
3534 static PyObject * 3411 descriptor open to a directory, and the respective path string (src or dst)
3535 posix_link(PyObject *self, PyObject *args, PyObject *kwargs) 3412 should be relative; the path will then be relative to that directory.
3536 { 3413 If follow_symlinks is False, and the last element of src is a symbolic
3537 path_t src, dst; 3414 link, link will create a link to the symbolic link itself instead of the
3538 int src_dir_fd = DEFAULT_DIR_FD; 3415 file the link points to.
3539 int dst_dir_fd = DEFAULT_DIR_FD; 3416 src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your
3540 int follow_symlinks = 1; 3417 platform. If they are unavailable, using them will raise a
3541 PyObject *return_value = NULL; 3418 NotImplementedError.
3542 static char *keywords[] = {"src", "dst", "src_dir_fd", "dst_dir_fd", 3419 [clinic start generated code]*/
3543 "follow_symlinks", NULL}; 3420
3421 static PyObject *
3422 os_link_impl(PyModuleDef *module, path_t *src, path_t *dst, int src_dir_fd,
3423 int dst_dir_fd, int follow_symlinks)
3424 /*[clinic end generated code: output=f47a7e88f7b391b6 input=b0095ebbcbaa7e04]*/
3425 {
3544 #ifdef MS_WINDOWS 3426 #ifdef MS_WINDOWS
3545 BOOL result; 3427 BOOL result;
3546 #else 3428 #else
3547 int result; 3429 int result;
3548 #endif 3430 #endif
3549 3431
3550 memset(&src, 0, sizeof(src));
3551 memset(&dst, 0, sizeof(dst));
3552 src.function_name = "link";
3553 dst.function_name = "link";
3554 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|O&O&p:link", keywords,
3555 path_converter, &src,
3556 path_converter, &dst,
3557 dir_fd_converter, &src_dir_fd,
3558 dir_fd_converter, &dst_dir_fd,
3559 &follow_symlinks))
3560 return NULL;
3561
3562 #ifndef HAVE_LINKAT 3432 #ifndef HAVE_LINKAT
3563 if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) { 3433 if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) {
3564 argument_unavailable_error("link", "src_dir_fd and dst_dir_fd"); 3434 argument_unavailable_error("link", "src_dir_fd and dst_dir_fd");
3565 goto exit; 3435 return NULL;
3566 } 3436 }
3567 #endif 3437 #endif
3568 3438
3569 if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) { 3439 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
3570 PyErr_SetString(PyExc_NotImplementedError, 3440 PyErr_SetString(PyExc_NotImplementedError,
3571 "link: src and dst must be the same type"); 3441 "link: src and dst must be the same type");
3572 goto exit; 3442 return NULL;
3573 } 3443 }
3574 3444
3575 #ifdef MS_WINDOWS 3445 #ifdef MS_WINDOWS
3576 Py_BEGIN_ALLOW_THREADS 3446 Py_BEGIN_ALLOW_THREADS
3577 if (src.wide) 3447 if (src->wide)
3578 result = CreateHardLinkW(dst.wide, src.wide, NULL); 3448 result = CreateHardLinkW(dst->wide, src->wide, NULL);
3579 else 3449 else
3580 result = CreateHardLinkA(dst.narrow, src.narrow, NULL); 3450 result = CreateHardLinkA(dst->narrow, src->narrow, NULL);
3581 Py_END_ALLOW_THREADS 3451 Py_END_ALLOW_THREADS
3582 3452
3583 if (!result) { 3453 if (!result)
3584 return_value = path_error2(&src, &dst); 3454 return path_error2(src, dst);
3585 goto exit;
3586 }
3587 #else 3455 #else
3588 Py_BEGIN_ALLOW_THREADS 3456 Py_BEGIN_ALLOW_THREADS
3589 #ifdef HAVE_LINKAT 3457 #ifdef HAVE_LINKAT
3590 if ((src_dir_fd != DEFAULT_DIR_FD) || 3458 if ((src_dir_fd != DEFAULT_DIR_FD) ||
3591 (dst_dir_fd != DEFAULT_DIR_FD) || 3459 (dst_dir_fd != DEFAULT_DIR_FD) ||
3592 (!follow_symlinks)) 3460 (!follow_symlinks))
3593 result = linkat(src_dir_fd, src.narrow, 3461 result = linkat(src_dir_fd, src->narrow,
3594 dst_dir_fd, dst.narrow, 3462 dst_dir_fd, dst->narrow,
3595 follow_symlinks ? AT_SYMLINK_FOLLOW : 0); 3463 follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
3596 else 3464 else
3597 #endif 3465 #endif
3598 result = link(src.narrow, dst.narrow); 3466 result = link(src->narrow, dst->narrow);
3599 Py_END_ALLOW_THREADS 3467 Py_END_ALLOW_THREADS
3600 3468
3601 if (result) { 3469 if (result)
3602 return_value = path_error2(&src, &dst); 3470 return path_error2(src, dst);
3603 goto exit; 3471 #endif
3604 } 3472
3605 #endif 3473 Py_RETURN_NONE;
3606 3474 }
3607 return_value = Py_None; 3475 #endif
3608 Py_INCREF(Py_None); 3476
3609
3610 exit:
3611 path_cleanup(&src);
3612 path_cleanup(&dst);
3613 return return_value;
3614 }
3615 #endif
3616
3617
3618
3619 PyDoc_STRVAR(posix_listdir__doc__,
3620 "listdir(path='.') -> list_of_filenames\n\n\
3621 Return a list containing the names of the files in the directory.\n\
3622 The list is in arbitrary order. It does not include the special\n\
3623 entries '.' and '..' even if they are present in the directory.\n\
3624 \n\
3625 path can be specified as either str or bytes. If path is bytes,\n\
3626 the filenames returned will also be bytes; in all other circumstances\n\
3627 the filenames returned will be str.\n\
3628 On some platforms, path may also be specified as an open file descriptor;\n\
3629 the file descriptor must refer to a directory.\n\
3630 If this functionality is unavailable, using it raises NotImplementedError.");
3631 3477
3632 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) 3478 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
3633 static PyObject * 3479 static PyObject *
3634 _listdir_windows_no_opendir(path_t *path, PyObject *list) 3480 _listdir_windows_no_opendir(path_t *path, PyObject *list)
3635 { 3481 {
3636 static char *keywords[] = {"path", NULL};
3637 PyObject *v; 3482 PyObject *v;
3638 HANDLE hFindFile = INVALID_HANDLE_VALUE; 3483 HANDLE hFindFile = INVALID_HANDLE_VALUE;
3639 BOOL result; 3484 BOOL result;
3640 WIN32_FIND_DATA FileData; 3485 WIN32_FIND_DATA FileData;
3641 char namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */ 3486 char namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */
3642 char *bufptr = namebuf;
3643 /* only claim to have space for MAX_PATH */ 3487 /* only claim to have space for MAX_PATH */
3644 Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4; 3488 Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4;
3645 PyObject *po = NULL;
3646 wchar_t *wnamebuf = NULL; 3489 wchar_t *wnamebuf = NULL;
3647 3490
3648 if (!path->narrow) { 3491 if (!path->narrow) {
3649 WIN32_FIND_DATAW wFileData; 3492 WIN32_FIND_DATAW wFileData;
3650 wchar_t *po_wchars; 3493 const wchar_t *po_wchars;
3651 3494
3652 if (!path->wide) { /* Default arg: "." */ 3495 if (!path->wide) { /* Default arg: "." */
3653 po_wchars = L"."; 3496 po_wchars = L".";
3654 len = 1; 3497 len = 1;
3655 } else { 3498 } else {
3656 po_wchars = path->wide; 3499 po_wchars = path->wide;
3657 len = wcslen(path->wide); 3500 len = wcslen(path->wide);
3658 } 3501 }
3659 /* The +5 is so we can append "\\*.*\0" */ 3502 /* The +5 is so we can append "\\*.*\0" */
3660 wnamebuf = PyMem_New(wchar_t, len + 5); 3503 wnamebuf = PyMem_New(wchar_t, len + 5);
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
3806 3649
3807 return_str = 1; 3650 return_str = 1;
3808 3651
3809 Py_BEGIN_ALLOW_THREADS 3652 Py_BEGIN_ALLOW_THREADS
3810 dirp = fdopendir(fd); 3653 dirp = fdopendir(fd);
3811 Py_END_ALLOW_THREADS 3654 Py_END_ALLOW_THREADS
3812 } 3655 }
3813 else 3656 else
3814 #endif 3657 #endif
3815 { 3658 {
3816 char *name; 3659 const char *name;
3817 if (path->narrow) { 3660 if (path->narrow) {
3818 name = path->narrow; 3661 name = path->narrow;
3819 /* only return bytes if they specified a bytes object */ 3662 /* only return bytes if they specified a bytes object */
3820 return_str = !(PyBytes_Check(path->object)); 3663 return_str = !(PyBytes_Check(path->object));
3821 } 3664 }
3822 else { 3665 else {
3823 name = "."; 3666 name = ".";
3824 return_str = 1; 3667 return_str = 1;
3825 } 3668 }
3826 3669
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
3885 rewinddir(dirp); 3728 rewinddir(dirp);
3886 #endif 3729 #endif
3887 closedir(dirp); 3730 closedir(dirp);
3888 Py_END_ALLOW_THREADS 3731 Py_END_ALLOW_THREADS
3889 } 3732 }
3890 3733
3891 return list; 3734 return list;
3892 } /* end of _posix_listdir */ 3735 } /* end of _posix_listdir */
3893 #endif /* which OS */ 3736 #endif /* which OS */
3894 3737
3895 static PyObject * 3738
3896 posix_listdir(PyObject *self, PyObject *args, PyObject *kwargs) 3739 /*[clinic input]
3897 { 3740 os.listdir
3898 path_t path; 3741
3899 PyObject *list = NULL; 3742 path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None
3900 static char *keywords[] = {"path", NULL}; 3743
3901 PyObject *return_value; 3744 Return a list containing the names of the files in the directory.
3902 3745
3903 memset(&path, 0, sizeof(path)); 3746 path can be specified as either str or bytes. If path is bytes,
3904 path.function_name = "listdir"; 3747 the filenames returned will also be bytes; in all other circumstances
3905 path.nullable = 1; 3748 the filenames returned will be str.
3906 #ifdef HAVE_FDOPENDIR 3749 If path is None, uses the path='.'.
3907 path.allow_fd = 1; 3750 On some platforms, path may also be specified as an open file descriptor;\
3908 path.fd = -1; 3751 the file descriptor must refer to a directory.
3909 #endif 3752 If this functionality is unavailable, using it raises NotImplementedError.
3910 3753
3911 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:listdir", keywords, 3754 The list is in arbitrary order. It does not include the special
3912 path_converter, &path)) { 3755 entries '.' and '..' even if they are present in the directory.
3913 return NULL; 3756
3914 } 3757
3915 3758 [clinic start generated code]*/
3759
3760 static PyObject *
3761 os_listdir_impl(PyModuleDef *module, path_t *path)
3762 /*[clinic end generated code: output=1fbe67c1f780c8b7 input=09e300416e3cd729]*/
3763 {
3916 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) 3764 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
3917 return_value = _listdir_windows_no_opendir(&path, list); 3765 return _listdir_windows_no_opendir(path, NULL);
3918 #else 3766 #else
3919 return_value = _posix_listdir(&path, list); 3767 return _posix_listdir(path, NULL);
3920 #endif 3768 #endif
3921 path_cleanup(&path);
3922 return return_value;
3923 } 3769 }
3924 3770
3925 #ifdef MS_WINDOWS 3771 #ifdef MS_WINDOWS
3926 /* A helper function for abspath on win32 */ 3772 /* A helper function for abspath on win32 */
3927 static PyObject * 3773 /*[clinic input]
3928 posix__getfullpathname(PyObject *self, PyObject *args) 3774 os._getfullpathname
3929 { 3775
3930 const char *path; 3776 path: path_t
3931 char outbuf[MAX_PATH]; 3777 /
3932 char *temp; 3778
3933 PyObject *po; 3779 [clinic start generated code]*/
3934 3780
3935 if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po)) 3781 static PyObject *
3782 os__getfullpathname_impl(PyModuleDef *module, path_t *path)
3783 /*[clinic end generated code: output=b90b1f103b08773f input=332ed537c29d0a3e]*/
3784 {
3785 if (!path->narrow)
3936 { 3786 {
3937 wchar_t *wpath;
3938 wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf; 3787 wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf;
3939 wchar_t *wtemp; 3788 wchar_t *wtemp;
3940 DWORD result; 3789 DWORD result;
3941 PyObject *v; 3790 PyObject *v;
3942 3791
3943 wpath = PyUnicode_AsUnicode(po); 3792 result = GetFullPathNameW(path->wide,
3944 if (wpath == NULL)
3945 return NULL;
3946 result = GetFullPathNameW(wpath,
3947 Py_ARRAY_LENGTH(woutbuf), 3793 Py_ARRAY_LENGTH(woutbuf),
3948 woutbuf, &wtemp); 3794 woutbuf, &wtemp);
3949 if (result > Py_ARRAY_LENGTH(woutbuf)) { 3795 if (result > Py_ARRAY_LENGTH(woutbuf)) {
3950 woutbufp = PyMem_New(wchar_t, result); 3796 woutbufp = PyMem_New(wchar_t, result);
3951 if (!woutbufp) 3797 if (!woutbufp)
3952 return PyErr_NoMemory(); 3798 return PyErr_NoMemory();
3953 result = GetFullPathNameW(wpath, result, woutbufp, &wtemp); 3799 result = GetFullPathNameW(path->wide, result, woutbufp, &wtemp);
3954 } 3800 }
3955 if (result) 3801 if (result)
3956 v = PyUnicode_FromWideChar(woutbufp, wcslen(woutbufp)); 3802 v = PyUnicode_FromWideChar(woutbufp, wcslen(woutbufp));
3957 else 3803 else
3958 v = win32_error_object("GetFullPathNameW", po); 3804 v = win32_error_object("GetFullPathNameW", path->object);
3959 if (woutbufp != woutbuf) 3805 if (woutbufp != woutbuf)
3960 PyMem_Free(woutbufp); 3806 PyMem_Free(woutbufp);
3961 return v; 3807 return v;
3962 } 3808 }
3963 /* Drop the argument parsing error as narrow strings 3809 else {
3964 are also valid. */ 3810 char outbuf[MAX_PATH];
3965 PyErr_Clear(); 3811 char *temp;
3966 3812
3967 if (!PyArg_ParseTuple (args, "y:_getfullpathname", 3813 if (!GetFullPathName(path->narrow, Py_ARRAY_LENGTH(outbuf),
3968 &path)) 3814 outbuf, &temp)) {
3969 return NULL; 3815 win32_error_object("GetFullPathName", path->object);
3970 if (win32_warn_bytes_api()) 3816 return NULL;
3971 return NULL; 3817 }
3972 if (!GetFullPathName(path, Py_ARRAY_LENGTH(outbuf), 3818 return PyBytes_FromString(outbuf);
3973 outbuf, &temp)) { 3819 }
3974 win32_error("GetFullPathName", path); 3820 }
3975 return NULL; 3821
3976 } 3822
3977 if (PyUnicode_Check(PyTuple_GetItem(args, 0))) { 3823 /*[clinic input]
3978 return PyUnicode_Decode(outbuf, strlen(outbuf), 3824 os._getfinalpathname
3979 Py_FileSystemDefaultEncoding, NULL); 3825
3980 } 3826 path: unicode
3981 return PyBytes_FromString(outbuf); 3827 /
3982 } /* end of posix__getfullpathname */ 3828
3983 3829 A helper function for samepath on windows.
3984 3830 [clinic start generated code]*/
3985 3831
3986 /* A helper function for samepath on windows */ 3832 static PyObject *
3987 static PyObject * 3833 os__getfinalpathname_impl(PyModuleDef *module, PyObject *path)
3988 posix__getfinalpathname(PyObject *self, PyObject *args) 3834 /*[clinic end generated code: output=8be81a5f51a34bcf input=71d5e89334891bf4]*/
3989 { 3835 {
3990 HANDLE hFile; 3836 HANDLE hFile;
3991 int buf_size; 3837 int buf_size;
3992 wchar_t *target_path; 3838 wchar_t *target_path;
3993 int result_length; 3839 int result_length;
3994 PyObject *po, *result; 3840 PyObject *result;
3995 wchar_t *path; 3841 const wchar_t *path_wchar;
3996 3842
3997 if (!PyArg_ParseTuple(args, "U|:_getfinalpathname", &po)) 3843 path_wchar = PyUnicode_AsUnicode(path);
3844 if (path_wchar == NULL)
3998 return NULL; 3845 return NULL;
3999 path = PyUnicode_AsUnicode(po);
4000 if (path == NULL)
4001 return NULL;
4002
4003 if(!check_GetFinalPathNameByHandle()) {
4004 /* If the OS doesn't have GetFinalPathNameByHandle, return a
4005 NotImplementedError. */
4006 return PyErr_Format(PyExc_NotImplementedError,
4007 "GetFinalPathNameByHandle not available on this platform");
4008 }
4009 3846
4010 hFile = CreateFileW( 3847 hFile = CreateFileW(
4011 path, 3848 path_wchar,
4012 0, /* desired access */ 3849 0, /* desired access */
4013 0, /* share mode */ 3850 0, /* share mode */
4014 NULL, /* security attributes */ 3851 NULL, /* security attributes */
4015 OPEN_EXISTING, 3852 OPEN_EXISTING,
4016 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ 3853 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
4017 FILE_FLAG_BACKUP_SEMANTICS, 3854 FILE_FLAG_BACKUP_SEMANTICS,
4018 NULL); 3855 NULL);
4019 3856
4020 if(hFile == INVALID_HANDLE_VALUE) 3857 if(hFile == INVALID_HANDLE_VALUE)
4021 return win32_error_object("CreateFileW", po); 3858 return win32_error_object("CreateFileW", path);
4022 3859
4023 /* We have a good handle to the target, use it to determine the 3860 /* We have a good handle to the target, use it to determine the
4024 target path name. */ 3861 target path name. */
4025 buf_size = Py_GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_NT); 3862 buf_size = GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_NT);
4026 3863
4027 if(!buf_size) 3864 if(!buf_size)
4028 return win32_error_object("GetFinalPathNameByHandle", po); 3865 return win32_error_object("GetFinalPathNameByHandle", path);
4029 3866
4030 target_path = PyMem_New(wchar_t, buf_size+1); 3867 target_path = PyMem_New(wchar_t, buf_size+1);
4031 if(!target_path) 3868 if(!target_path)
4032 return PyErr_NoMemory(); 3869 return PyErr_NoMemory();
4033 3870
4034 result_length = Py_GetFinalPathNameByHandleW(hFile, target_path, 3871 result_length = GetFinalPathNameByHandleW(hFile, target_path,
4035 buf_size, VOLUME_NAME_DOS); 3872 buf_size, VOLUME_NAME_DOS);
4036 if(!result_length) 3873 if(!result_length)
4037 return win32_error_object("GetFinalPathNamyByHandle", po); 3874 return win32_error_object("GetFinalPathNamyByHandle", path);
4038 3875
4039 if(!CloseHandle(hFile)) 3876 if(!CloseHandle(hFile))
4040 return win32_error_object("CloseHandle", po); 3877 return win32_error_object("CloseHandle", path);
4041 3878
4042 target_path[result_length] = 0; 3879 target_path[result_length] = 0;
4043 result = PyUnicode_FromWideChar(target_path, result_length); 3880 result = PyUnicode_FromWideChar(target_path, result_length);
4044 PyMem_Free(target_path); 3881 PyMem_Free(target_path);
4045 return result; 3882 return result;
4046 3883 }
4047 } /* end of posix__getfinalpathname */
4048 3884
4049 PyDoc_STRVAR(posix__isdir__doc__, 3885 PyDoc_STRVAR(posix__isdir__doc__,
4050 "Return true if the pathname refers to an existing directory."); 3886 "Return true if the pathname refers to an existing directory.");
4051 3887
4052 static PyObject * 3888 /*[clinic input]
4053 posix__isdir(PyObject *self, PyObject *args) 3889 os._isdir
4054 { 3890
4055 const char *path; 3891 path: path_t
4056 PyObject *po; 3892 /
3893
3894 [clinic start generated code]*/
3895
3896 static PyObject *
3897 os__isdir_impl(PyModuleDef *module, path_t *path)
3898 /*[clinic end generated code: output=f17b2d4e1994b0ff input=e794f12faab62a2a]*/
3899 {
4057 DWORD attributes; 3900 DWORD attributes;
4058 3901
4059 if (PyArg_ParseTuple(args, "U|:_isdir", &po)) { 3902 if (!path->narrow)
4060 wchar_t *wpath = PyUnicode_AsUnicode(po); 3903 attributes = GetFileAttributesW(path->wide);
4061 if (wpath == NULL) 3904 else
4062 return NULL; 3905 attributes = GetFileAttributesA(path->narrow);
4063 3906
4064 attributes = GetFileAttributesW(wpath);
4065 if (attributes == INVALID_FILE_ATTRIBUTES)
4066 Py_RETURN_FALSE;
4067 goto check;
4068 }
4069 /* Drop the argument parsing error as narrow strings
4070 are also valid. */
4071 PyErr_Clear();
4072
4073 if (!PyArg_ParseTuple(args, "y:_isdir", &path))
4074 return NULL;
4075 if (win32_warn_bytes_api())
4076 return NULL;
4077 attributes = GetFileAttributesA(path);
4078 if (attributes == INVALID_FILE_ATTRIBUTES) 3907 if (attributes == INVALID_FILE_ATTRIBUTES)
4079 Py_RETURN_FALSE; 3908 Py_RETURN_FALSE;
4080 3909
4081 check:
4082 if (attributes & FILE_ATTRIBUTE_DIRECTORY) 3910 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
4083 Py_RETURN_TRUE; 3911 Py_RETURN_TRUE;
4084 else 3912 else
4085 Py_RETURN_FALSE; 3913 Py_RETURN_FALSE;
4086 } 3914 }
4087 3915
4088 PyDoc_STRVAR(posix__getvolumepathname__doc__, 3916
4089 "Return volume mount point of the specified path."); 3917 /*[clinic input]
4090 3918 os._getvolumepathname
4091 /* A helper function for ismount on windows */ 3919
4092 static PyObject * 3920 path: unicode
4093 posix__getvolumepathname(PyObject *self, PyObject *args) 3921
4094 { 3922 A helper function for ismount on Win32.
4095 PyObject *po, *result; 3923 [clinic start generated code]*/
4096 wchar_t *path, *mountpath=NULL; 3924
3925 static PyObject *
3926 os__getvolumepathname_impl(PyModuleDef *module, PyObject *path)
3927 /*[clinic end generated code: output=79a0ba729f956dbe input=7eacadc40acbda6b]*/
3928 {
3929 PyObject *result;
3930 const wchar_t *path_wchar;
3931 wchar_t *mountpath=NULL;
4097 size_t buflen; 3932 size_t buflen;
4098 BOOL ret; 3933 BOOL ret;
4099 3934
4100 if (!PyArg_ParseTuple(args, "U|:_getvolumepathname", &po)) 3935 path_wchar = PyUnicode_AsUnicodeAndSize(path, &buflen);
4101 return NULL; 3936 if (path_wchar == NULL)
4102 path = PyUnicode_AsUnicodeAndSize(po, &buflen);
4103 if (path == NULL)
4104 return NULL; 3937 return NULL;
4105 buflen += 1; 3938 buflen += 1;
4106 3939
4107 /* Volume path should be shorter than entire path */ 3940 /* Volume path should be shorter than entire path */
4108 buflen = Py_MAX(buflen, MAX_PATH); 3941 buflen = Py_MAX(buflen, MAX_PATH);
4109 3942
4110 if (buflen > DWORD_MAX) { 3943 if (buflen > DWORD_MAX) {
4111 PyErr_SetString(PyExc_OverflowError, "path too long"); 3944 PyErr_SetString(PyExc_OverflowError, "path too long");
4112 return NULL; 3945 return NULL;
4113 } 3946 }
4114 3947
4115 mountpath = PyMem_New(wchar_t, buflen); 3948 mountpath = PyMem_New(wchar_t, buflen);
4116 if (mountpath == NULL) 3949 if (mountpath == NULL)
4117 return PyErr_NoMemory(); 3950 return PyErr_NoMemory();
4118 3951
4119 Py_BEGIN_ALLOW_THREADS 3952 Py_BEGIN_ALLOW_THREADS
4120 ret = GetVolumePathNameW(path, mountpath, 3953 ret = GetVolumePathNameW(path_wchar, mountpath,
4121 Py_SAFE_DOWNCAST(buflen, size_t, DWORD)); 3954 Py_SAFE_DOWNCAST(buflen, size_t, DWORD));
4122 Py_END_ALLOW_THREADS 3955 Py_END_ALLOW_THREADS
4123 3956
4124 if (!ret) { 3957 if (!ret) {
4125 result = win32_error_object("_getvolumepathname", po); 3958 result = win32_error_object("_getvolumepathname", path);
4126 goto exit; 3959 goto exit;
4127 } 3960 }
4128 result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath)); 3961 result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath));
4129 3962
4130 exit: 3963 exit:
4131 PyMem_Free(mountpath); 3964 PyMem_Free(mountpath);
4132 return result; 3965 return result;
4133 } 3966 }
4134 /* end of posix__getvolumepathname */
4135 3967
4136 #endif /* MS_WINDOWS */ 3968 #endif /* MS_WINDOWS */
4137 3969
4138 PyDoc_STRVAR(posix_mkdir__doc__, 3970
4139 "mkdir(path, mode=0o777, *, dir_fd=None)\n\n\ 3971 /*[clinic input]
4140 Create a directory.\n\ 3972 os.mkdir
4141 \n\ 3973
4142 If dir_fd is not None, it should be a file descriptor open to a directory,\n\ 3974 path : path_t
4143 and path should be relative; path will then be relative to that directory.\n\ 3975
4144 dir_fd may not be implemented on your platform.\n\ 3976 mode: int = 0o777
4145 If it is unavailable, using it will raise a NotImplementedError.\n\ 3977
4146 \n\ 3978 *
4147 The mode argument is ignored on Windows."); 3979
4148 3980 dir_fd : dir_fd(requires='mkdirat') = None
4149 static PyObject * 3981
4150 posix_mkdir(PyObject *self, PyObject *args, PyObject *kwargs) 3982 # "mkdir(path, mode=0o777, *, dir_fd=None)\n\n\
4151 { 3983
4152 path_t path; 3984 Create a directory.
4153 int mode = 0777; 3985
4154 int dir_fd = DEFAULT_DIR_FD; 3986 If dir_fd is not None, it should be a file descriptor open to a directory,
4155 static char *keywords[] = {"path", "mode", "dir_fd", NULL}; 3987 and path should be relative; path will then be relative to that directory.
4156 PyObject *return_value = NULL; 3988 dir_fd may not be implemented on your platform.
3989 If it is unavailable, using it will raise a NotImplementedError.
3990
3991 The mode argument is ignored on Windows.
3992 [clinic start generated code]*/
3993
3994 static PyObject *
3995 os_mkdir_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd)
3996 /*[clinic end generated code: output=8bf1f738873ef2c5 input=e965f68377e9b1ce]*/
3997 {
4157 int result; 3998 int result;
4158
4159 memset(&path, 0, sizeof(path));
4160 path.function_name = "mkdir";
4161 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i$O&:mkdir", keywords,
4162 path_converter, &path, &mode,
4163 #ifdef HAVE_MKDIRAT
4164 dir_fd_converter, &dir_fd
4165 #else
4166 dir_fd_unavailable, &dir_fd
4167 #endif
4168 ))
4169 return NULL;
4170 3999
4171 #ifdef MS_WINDOWS 4000 #ifdef MS_WINDOWS
4172 Py_BEGIN_ALLOW_THREADS 4001 Py_BEGIN_ALLOW_THREADS
4173 if (path.wide) 4002 if (path->wide)
4174 result = CreateDirectoryW(path.wide, NULL); 4003 result = CreateDirectoryW(path->wide, NULL);
4175 else 4004 else
4176 result = CreateDirectoryA(path.narrow, NULL); 4005 result = CreateDirectoryA(path->narrow, NULL);
4177 Py_END_ALLOW_THREADS 4006 Py_END_ALLOW_THREADS
4178 4007
4179 if (!result) { 4008 if (!result)
4180 return_value = path_error(&path); 4009 return path_error(path);
4181 goto exit;
4182 }
4183 #else 4010 #else
4184 Py_BEGIN_ALLOW_THREADS 4011 Py_BEGIN_ALLOW_THREADS
4185 #if HAVE_MKDIRAT 4012 #if HAVE_MKDIRAT
4186 if (dir_fd != DEFAULT_DIR_FD) 4013 if (dir_fd != DEFAULT_DIR_FD)
4187 result = mkdirat(dir_fd, path.narrow, mode); 4014 result = mkdirat(dir_fd, path->narrow, mode);
4188 else 4015 else
4189 #endif 4016 #endif
4190 #if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__) 4017 #if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__)
4191 result = mkdir(path.narrow); 4018 result = mkdir(path->narrow);
4192 #else 4019 #else
4193 result = mkdir(path.narrow, mode); 4020 result = mkdir(path->narrow, mode);
4194 #endif 4021 #endif
4195 Py_END_ALLOW_THREADS 4022 Py_END_ALLOW_THREADS
4196 if (result < 0) { 4023 if (result < 0)
4197 return_value = path_error(&path); 4024 return path_error(path);
4198 goto exit; 4025 #endif
4199 } 4026 Py_RETURN_NONE;
4200 #endif
4201 return_value = Py_None;
4202 Py_INCREF(Py_None);
4203 exit:
4204 path_cleanup(&path);
4205 return return_value;
4206 } 4027 }
4207 4028
4208 4029
4209 /* sys/resource.h is needed for at least: wait3(), wait4(), broken nice. */ 4030 /* sys/resource.h is needed for at least: wait3(), wait4(), broken nice. */
4210 #if defined(HAVE_SYS_RESOURCE_H) 4031 #if defined(HAVE_SYS_RESOURCE_H)
4211 #include <sys/resource.h> 4032 #include <sys/resource.h>
4212 #endif 4033 #endif
4213 4034
4214 4035
4215 #ifdef HAVE_NICE 4036 #ifdef HAVE_NICE
4216 PyDoc_STRVAR(posix_nice__doc__, 4037 /*[clinic input]
4217 "nice(inc) -> new_priority\n\n\ 4038 os.nice
4218 Decrease the priority of process by inc and return the new priority."); 4039
4219 4040 increment: int
4220 static PyObject * 4041 /
4221 posix_nice(PyObject *self, PyObject *args) 4042
4222 { 4043 Add increment to the priority of process and return the new priority.
4223 int increment, value; 4044 [clinic start generated code]*/
4224 4045
4225 if (!PyArg_ParseTuple(args, "i:nice", &increment)) 4046 static PyObject *
4226 return NULL; 4047 os_nice_impl(PyModuleDef *module, int increment)
4048 /*[clinic end generated code: output=8870418a3fc07b51 input=864be2d402a21da2]*/
4049 {
4050 int value;
4227 4051
4228 /* There are two flavours of 'nice': one that returns the new 4052 /* There are two flavours of 'nice': one that returns the new
4229 priority (as required by almost all standards out there) and the 4053 priority (as required by almost all standards out there) and the
4230 Linux/FreeBSD/BSDI one, which returns '0' on success and advices 4054 Linux/FreeBSD/BSDI one, which returns '0' on success and advices
4231 the use of getpriority() to get the new priority. 4055 the use of getpriority() to get the new priority.
4232 4056
4233 If we are of the nice family that returns the new priority, we 4057 If we are of the nice family that returns the new priority, we
4234 need to clear errno before the c