diff options
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r-- | Modules/posixmodule.c | 320 |
1 files changed, 212 insertions, 108 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index c95668b..a87bbbd 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -669,21 +669,20 @@ _Py_Dev_Converter(PyObject *obj, void *p) #endif static int -_fd_converter(PyObject *o, int *p, const char *allowed) +_fd_converter(PyObject *o, int *p) { int overflow; long long_value; PyObject *index = PyNumber_Index(o); if (index == NULL) { - PyErr_Format(PyExc_TypeError, - "argument should be %s, not %.200s", - allowed, Py_TYPE(o)->tp_name); return 0; } + assert(PyLong_Check(index)); long_value = PyLong_AsLongAndOverflow(index, &overflow); Py_DECREF(index); + assert(!PyErr_Occurred()); if (overflow > 0 || long_value > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "fd is greater than maximum"); @@ -706,7 +705,15 @@ dir_fd_converter(PyObject *o, void *p) *(int *)p = DEFAULT_DIR_FD; return 1; } - return _fd_converter(o, (int *)p, "integer"); + else if (PyIndex_Check(o)) { + return _fd_converter(o, (int *)p); + } + else { + PyErr_Format(PyExc_TypeError, + "argument should be integer or None, not %.200s", + Py_TYPE(o)->tp_name); + return 0; + } } @@ -816,9 +823,10 @@ path_cleanup(path_t *path) { } static int -path_converter(PyObject *o, void *p) { +path_converter(PyObject *o, void *p) +{ path_t *path = (path_t *)p; - PyObject *unicode, *bytes; + PyObject *bytes; Py_ssize_t length; char *narrow; @@ -837,12 +845,7 @@ path_converter(PyObject *o, void *p) { /* ensure it's always safe to call path_cleanup() */ path->cleanup = NULL; - if (o == Py_None) { - if (!path->nullable) { - FORMAT_EXCEPTION(PyExc_TypeError, - "can't specify None for %s argument"); - return 0; - } + if ((o == Py_None) && path->nullable) { path->wide = NULL; path->narrow = NULL; path->length = 0; @@ -851,24 +854,20 @@ path_converter(PyObject *o, void *p) { return 1; } - unicode = PyUnicode_FromObject(o); - if (unicode) { + if (PyUnicode_Check(o)) { #ifdef MS_WINDOWS wchar_t *wide; - wide = PyUnicode_AsUnicodeAndSize(unicode, &length); + wide = PyUnicode_AsUnicodeAndSize(o, &length); if (!wide) { - Py_DECREF(unicode); return 0; } if (length > 32767) { FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows"); - Py_DECREF(unicode); return 0; } if (wcslen(wide) != length) { - FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character"); - Py_DECREF(unicode); + FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s"); return 0; } @@ -877,51 +876,46 @@ path_converter(PyObject *o, void *p) { path->length = length; path->object = o; path->fd = -1; - path->cleanup = unicode; - return Py_CLEANUP_SUPPORTED; + return 1; #else - int converted = PyUnicode_FSConverter(unicode, &bytes); - Py_DECREF(unicode); - if (!converted) - bytes = NULL; + if (!PyUnicode_FSConverter(o, &bytes)) { + return 0; + } #endif } - else { - PyErr_Clear(); - if (PyObject_CheckBuffer(o)) - bytes = PyBytes_FromObject(o); - else - bytes = NULL; + else if (PyObject_CheckBuffer(o)) { +#ifdef MS_WINDOWS + if (win32_warn_bytes_api()) { + return 0; + } +#endif + bytes = PyBytes_FromObject(o); if (!bytes) { - PyErr_Clear(); - if (path->allow_fd) { - int fd; - int result = _fd_converter(o, &fd, - "string, bytes or integer"); - if (result) { - path->wide = NULL; - path->narrow = NULL; - path->length = 0; - path->object = o; - path->fd = fd; - return result; - } - } + return 0; } } - - if (!bytes) { - if (!PyErr_Occurred()) - FORMAT_EXCEPTION(PyExc_TypeError, "illegal type for %s parameter"); - return 0; + else if (path->allow_fd && PyIndex_Check(o)) { + if (!_fd_converter(o, &path->fd)) { + return 0; + } + path->wide = NULL; + path->narrow = NULL; + path->length = 0; + path->object = o; + return 1; } - -#ifdef MS_WINDOWS - if (win32_warn_bytes_api()) { - Py_DECREF(bytes); + else { + PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s", + path->function_name ? path->function_name : "", + path->function_name ? ": " : "", + path->argument_name ? path->argument_name : "path", + path->allow_fd && path->nullable ? "string, bytes, integer or None" : + path->allow_fd ? "string, bytes or integer" : + path->nullable ? "string, bytes or None" : + "string or bytes", + Py_TYPE(o)->tp_name); return 0; } -#endif length = PyBytes_GET_SIZE(bytes); #ifdef MS_WINDOWS @@ -949,7 +943,8 @@ path_converter(PyObject *o, void *p) { } static void -argument_unavailable_error(char *function_name, char *argument_name) { +argument_unavailable_error(const char *function_name, const char *argument_name) +{ PyErr_Format(PyExc_NotImplementedError, "%s%s%s unavailable on this platform", (function_name != NULL) ? function_name : "", @@ -972,7 +967,8 @@ dir_fd_unavailable(PyObject *o, void *p) } static int -fd_specified(char *function_name, int fd) { +fd_specified(const char *function_name, int fd) +{ if (fd == -1) return 0; @@ -981,7 +977,8 @@ fd_specified(char *function_name, int fd) { } static int -follow_symlinks_specified(char *function_name, int follow_symlinks) { +follow_symlinks_specified(const char *function_name, int follow_symlinks) +{ if (follow_symlinks) return 0; @@ -990,7 +987,8 @@ follow_symlinks_specified(char *function_name, int follow_symlinks) { } static int -path_and_dir_fd_invalid(char *function_name, path_t *path, int dir_fd) { +path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd) +{ if (!path->narrow && !path->wide && (dir_fd != DEFAULT_DIR_FD)) { PyErr_Format(PyExc_ValueError, "%s: can't specify dir_fd without matching path", @@ -1001,7 +999,8 @@ path_and_dir_fd_invalid(char *function_name, path_t *path, int dir_fd) { } static int -dir_fd_and_fd_invalid(char *function_name, int dir_fd, int fd) { +dir_fd_and_fd_invalid(const char *function_name, int dir_fd, int fd) +{ if ((dir_fd != DEFAULT_DIR_FD) && (fd != -1)) { PyErr_Format(PyExc_ValueError, "%s: can't specify both dir_fd and fd", @@ -1012,8 +1011,9 @@ dir_fd_and_fd_invalid(char *function_name, int dir_fd, int fd) { } static int -fd_and_follow_symlinks_invalid(char *function_name, int fd, - int follow_symlinks) { +fd_and_follow_symlinks_invalid(const char *function_name, int fd, + int follow_symlinks) +{ if ((fd > 0) && (!follow_symlinks)) { PyErr_Format(PyExc_ValueError, "%s: cannot use fd and follow_symlinks together", @@ -1024,8 +1024,9 @@ fd_and_follow_symlinks_invalid(char *function_name, int fd, } static int -dir_fd_and_follow_symlinks_invalid(char *function_name, int dir_fd, - int follow_symlinks) { +dir_fd_and_follow_symlinks_invalid(const char *function_name, int dir_fd, + int follow_symlinks) +{ if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) { PyErr_Format(PyExc_ValueError, "%s: cannot use dir_fd and follow_symlinks together", @@ -1220,7 +1221,7 @@ posix_error(void) #ifdef MS_WINDOWS static PyObject * -win32_error(char* function, const char* filename) +win32_error(const char* function, const char* filename) { /* XXX We should pass the function name along in the future. (winreg.c also wants to pass the function name.) @@ -1235,7 +1236,7 @@ win32_error(char* function, const char* filename) } static PyObject * -win32_error_object(char* function, PyObject* filename) +win32_error_object(const char* function, PyObject* filename) { /* XXX - see win32_error for comments on 'function' */ errno = GetLastError(); @@ -1456,7 +1457,7 @@ get_target_path(HANDLE hdl, wchar_t **target_path) if(!buf_size) return FALSE; - buf = PyMem_New(wchar_t, buf_size+1); + buf = (wchar_t *)PyMem_RawMalloc((buf_size + 1) * sizeof(wchar_t)); if (!buf) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -1466,12 +1467,12 @@ get_target_path(HANDLE hdl, wchar_t **target_path) buf, buf_size, VOLUME_NAME_DOS); if(!result_length) { - PyMem_Free(buf); + PyMem_RawFree(buf); return FALSE; } if(!CloseHandle(hdl)) { - PyMem_Free(buf); + PyMem_RawFree(buf); return FALSE; } @@ -1556,7 +1557,7 @@ win32_xstat_impl(const char *path, struct _Py_stat_struct *result, return -1; code = win32_xstat_impl_w(target_path, result, FALSE); - PyMem_Free(target_path); + PyMem_RawFree(target_path); return code; } } else @@ -1646,7 +1647,7 @@ win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, return -1; code = win32_xstat_impl_w(target_path, result, FALSE); - PyMem_Free(target_path); + PyMem_RawFree(target_path); return code; } } else @@ -2100,7 +2101,7 @@ _pystat_fromstructstat(STRUCT_STAT *st) static PyObject * -posix_do_stat(char *function_name, path_t *path, +posix_do_stat(const char *function_name, path_t *path, int dir_fd, int follow_symlinks) { STRUCT_STAT st; @@ -3313,12 +3314,22 @@ posix_getcwd(int use_bytes) Py_BEGIN_ALLOW_THREADS do { buflen += chunk; +#ifdef MS_WINDOWS + if (buflen > INT_MAX) { + PyErr_NoMemory(); + break; + } +#endif tmpbuf = PyMem_RawRealloc(buf, buflen); if (tmpbuf == NULL) break; buf = tmpbuf; +#ifdef MS_WINDOWS + cwd = getcwd(buf, (int)buflen); +#else cwd = getcwd(buf, buflen); +#endif } while (cwd == NULL && errno == ERANGE); Py_END_ALLOW_THREADS @@ -3460,10 +3471,8 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list) BOOL result; WIN32_FIND_DATA FileData; char namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */ - char *bufptr = namebuf; /* only claim to have space for MAX_PATH */ Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4; - PyObject *po = NULL; wchar_t *wnamebuf = NULL; if (!path->narrow) { @@ -4563,7 +4572,7 @@ typedef struct { #if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT) static int -utime_dir_fd(utime_t *ut, int dir_fd, char *path, int follow_symlinks) +utime_dir_fd(utime_t *ut, int dir_fd, const char *path, int follow_symlinks) { #ifdef HAVE_UTIMENSAT int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW; @@ -4605,14 +4614,14 @@ utime_fd(utime_t *ut, int fd) #define PATH_UTIME_HAVE_FD 0 #endif +#if defined(HAVE_UTIMENSAT) || defined(HAVE_LUTIMES) +# define UTIME_HAVE_NOFOLLOW_SYMLINKS +#endif -#define UTIME_HAVE_NOFOLLOW_SYMLINKS \ - (defined(HAVE_UTIMENSAT) || defined(HAVE_LUTIMES)) - -#if UTIME_HAVE_NOFOLLOW_SYMLINKS +#ifdef UTIME_HAVE_NOFOLLOW_SYMLINKS static int -utime_nofollow_symlinks(utime_t *ut, char *path) +utime_nofollow_symlinks(utime_t *ut, const char *path) { #ifdef HAVE_UTIMENSAT UTIME_TO_TIMESPEC; @@ -4628,7 +4637,7 @@ utime_nofollow_symlinks(utime_t *ut, char *path) #ifndef MS_WINDOWS static int -utime_default(utime_t *ut, char *path) +utime_default(utime_t *ut, const char *path) { #ifdef HAVE_UTIMENSAT UTIME_TO_TIMESPEC; @@ -4771,7 +4780,7 @@ os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, utime.now = 1; } -#if !UTIME_HAVE_NOFOLLOW_SYMLINKS +#if !defined(UTIME_HAVE_NOFOLLOW_SYMLINKS) if (follow_symlinks_specified("utime", follow_symlinks)) goto exit; #endif @@ -4825,7 +4834,7 @@ os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, #else /* MS_WINDOWS */ Py_BEGIN_ALLOW_THREADS -#if UTIME_HAVE_NOFOLLOW_SYMLINKS +#ifdef UTIME_HAVE_NOFOLLOW_SYMLINKS if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) result = utime_nofollow_symlinks(&utime, path->narrow); else @@ -5756,14 +5765,14 @@ os.sched_getaffinity pid: pid_t / -Return the affinity of the process identified by pid. +Return the affinity of the process identified by pid (or the current process if zero). The affinity is returned as a set of CPU identifiers. [clinic start generated code]*/ static PyObject * os_sched_getaffinity_impl(PyModuleDef *module, pid_t pid) -/*[clinic end generated code: output=b431a8f310e369e7 input=eaf161936874b8a1]*/ +/*[clinic end generated code: output=b431a8f310e369e7 input=983ce7cb4a565980]*/ { int cpu, ncpus, count; size_t setsize; @@ -7325,7 +7334,7 @@ _check_dirW(WCHAR *src, WCHAR *dest) /* Return True if the path at src relative to dest is a directory */ static int -_check_dirA(char *src, char *dest) +_check_dirA(const char *src, char *dest) { WIN32_FILE_ATTRIBUTE_DATA src_info; char dest_parent[MAX_PATH]; @@ -9481,8 +9490,8 @@ os__getdiskusage_impl(PyModuleDef *module, Py_UNICODE *path) * sufficiently pervasive that it's not worth the loss of readability. */ struct constdef { - char *name; - long value; + const char *name; + int value; }; static int @@ -9490,7 +9499,10 @@ conv_confname(PyObject *arg, int *valuep, struct constdef *table, size_t tablesize) { if (PyLong_Check(arg)) { - *valuep = PyLong_AS_LONG(arg); + int value = _PyLong_AsInt(arg); + if (value == -1 && PyErr_Occurred()) + return 0; + *valuep = value; return 1; } else { @@ -10821,7 +10833,7 @@ os_getxattr_impl(PyModuleDef *module, path_t *path, path_t *attribute, for (i = 0; ; i++) { void *ptr; ssize_t result; - static Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0}; + static const Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0}; Py_ssize_t buffer_size = buffer_sizes[i]; if (!buffer_size) { path_error(path); @@ -10987,7 +10999,7 @@ os_listxattr_impl(PyModuleDef *module, path_t *path, int follow_symlinks) for (i = 0; ; i++) { char *start, *trace, *end; ssize_t length; - static Py_ssize_t buffer_sizes[] = { 256, XATTR_LIST_MAX, 0 }; + static const Py_ssize_t buffer_sizes[] = { 256, XATTR_LIST_MAX, 0 }; Py_ssize_t buffer_size = buffer_sizes[i]; if (!buffer_size) { /* ERANGE */ @@ -11199,11 +11211,15 @@ get_terminal_size(PyObject *self, PyObject *args) os.cpu_count Return the number of CPUs in the system; return None if indeterminable. + +This number is not equivalent to the number of CPUs the current process can +use. The number of usable CPUs can be obtained with +``len(os.sched_getaffinity(0))`` [clinic start generated code]*/ static PyObject * os_cpu_count_impl(PyModuleDef *module) -/*[clinic end generated code: output=c59ee7f6bce832b8 input=d55e2f8f3823a628]*/ +/*[clinic end generated code: output=c59ee7f6bce832b8 input=e7c8f4ba6dbbadd3]*/ { int ncpu = 0; #ifdef MS_WINDOWS @@ -11830,7 +11846,7 @@ error: #else /* POSIX */ static char * -join_path_filename(char *path_narrow, char* filename, Py_ssize_t filename_len) +join_path_filename(const char *path_narrow, const char* filename, Py_ssize_t filename_len) { Py_ssize_t path_len; Py_ssize_t size; @@ -11862,7 +11878,7 @@ join_path_filename(char *path_narrow, char* filename, Py_ssize_t filename_len) } static PyObject * -DirEntry_from_posix_info(path_t *path, char *name, Py_ssize_t name_len, +DirEntry_from_posix_info(path_t *path, const char *name, Py_ssize_t name_len, ino_t d_ino #ifdef HAVE_DIRENT_D_TYPE , unsigned char d_type @@ -11925,8 +11941,14 @@ typedef struct { #ifdef MS_WINDOWS +static int +ScandirIterator_is_closed(ScandirIterator *iterator) +{ + return iterator->handle == INVALID_HANDLE_VALUE; +} + static void -ScandirIterator_close(ScandirIterator *iterator) +ScandirIterator_closedir(ScandirIterator *iterator) { HANDLE handle = iterator->handle; @@ -11946,7 +11968,7 @@ ScandirIterator_iternext(ScandirIterator *iterator) BOOL success; PyObject *entry; - /* Happens if the iterator is iterated twice */ + /* Happens if the iterator is iterated twice, or closed explicitly */ if (iterator->handle == INVALID_HANDLE_VALUE) return NULL; @@ -11977,14 +11999,20 @@ ScandirIterator_iternext(ScandirIterator *iterator) } /* Error or no more files */ - ScandirIterator_close(iterator); + ScandirIterator_closedir(iterator); return NULL; } #else /* POSIX */ +static int +ScandirIterator_is_closed(ScandirIterator *iterator) +{ + return !iterator->dirp; +} + static void -ScandirIterator_close(ScandirIterator *iterator) +ScandirIterator_closedir(ScandirIterator *iterator) { DIR *dirp = iterator->dirp; @@ -12006,7 +12034,7 @@ ScandirIterator_iternext(ScandirIterator *iterator) int is_dot; PyObject *entry; - /* Happens if the iterator is iterated twice */ + /* Happens if the iterator is iterated twice, or closed explicitly */ if (!iterator->dirp) return NULL; @@ -12043,21 +12071,76 @@ ScandirIterator_iternext(ScandirIterator *iterator) } /* Error or no more files */ - ScandirIterator_close(iterator); + ScandirIterator_closedir(iterator); return NULL; } #endif +static PyObject * +ScandirIterator_close(ScandirIterator *self, PyObject *args) +{ + ScandirIterator_closedir(self); + Py_RETURN_NONE; +} + +static PyObject * +ScandirIterator_enter(PyObject *self, PyObject *args) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +ScandirIterator_exit(ScandirIterator *self, PyObject *args) +{ + ScandirIterator_closedir(self); + Py_RETURN_NONE; +} + static void -ScandirIterator_dealloc(ScandirIterator *iterator) +ScandirIterator_finalize(ScandirIterator *iterator) { - ScandirIterator_close(iterator); - Py_XDECREF(iterator->path.object); + PyObject *error_type, *error_value, *error_traceback; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + if (!ScandirIterator_is_closed(iterator)) { + ScandirIterator_closedir(iterator); + + if (PyErr_ResourceWarning((PyObject *)iterator, 1, + "unclosed scandir iterator %R", iterator)) { + /* Spurious errors can appear at shutdown */ + if (PyErr_ExceptionMatches(PyExc_Warning)) { + PyErr_WriteUnraisable((PyObject *) iterator); + } + } + } + + Py_CLEAR(iterator->path.object); path_cleanup(&iterator->path); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + +static void +ScandirIterator_dealloc(ScandirIterator *iterator) +{ + if (PyObject_CallFinalizerFromDealloc((PyObject *)iterator) < 0) + return; + Py_TYPE(iterator)->tp_free((PyObject *)iterator); } +static PyMethodDef ScandirIterator_methods[] = { + {"__enter__", (PyCFunction)ScandirIterator_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)ScandirIterator_exit, METH_VARARGS}, + {"close", (PyCFunction)ScandirIterator_close, METH_NOARGS}, + {NULL} +}; + static PyTypeObject ScandirIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) MODNAME ".ScandirIterator", /* tp_name */ @@ -12079,7 +12162,8 @@ static PyTypeObject ScandirIteratorType = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -12087,6 +12171,27 @@ static PyTypeObject ScandirIteratorType = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)ScandirIterator_iternext, /* tp_iternext */ + ScandirIterator_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + (destructor)ScandirIterator_finalize, /* tp_finalize */ }; static PyObject * @@ -12380,7 +12485,6 @@ enable_symlink() HANDLE tok; TOKEN_PRIVILEGES tok_priv; LUID luid; - int meth_idx = 0; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &tok)) return 0; @@ -12824,7 +12928,7 @@ static struct PyModuleDef posixmodule = { }; -static char *have_functions[] = { +static const char * const have_functions[] = { #ifdef HAVE_FACCESSAT "HAVE_FACCESSAT", @@ -12959,7 +13063,7 @@ INITFUNC(void) { PyObject *m, *v; PyObject *list; - char **trace; + const char * const *trace; #if defined(HAVE_SYMLINK) && defined(MS_WINDOWS) win32_can_symlink = enable_symlink(); |