summaryrefslogtreecommitdiff
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c594
1 files changed, 429 insertions, 165 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index b854cafb6f..f9693e8d57 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -32,6 +32,12 @@
#include "winreparse.h"
#endif
+/* On android API level 21, 'AT_EACCESS' is not declared although
+ * HAVE_FACCESSAT is defined. */
+#ifdef __ANDROID__
+#undef HAVE_FACCESSAT
+#endif
+
#include <stdio.h> /* needed for ctermid() */
#ifdef __cplusplus
@@ -671,21 +677,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");
@@ -708,7 +713,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;
+ }
}
@@ -799,8 +812,8 @@ typedef struct {
const char *argument_name;
int nullable;
int allow_fd;
- wchar_t *wide;
- char *narrow;
+ const wchar_t *wide;
+ const char *narrow;
int fd;
Py_ssize_t length;
PyObject *object;
@@ -818,11 +831,15 @@ 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, *to_cleanup = NULL;
Py_ssize_t length;
- char *narrow;
+ int is_index, is_buffer, is_bytes, is_unicode;
+ /* Default to failure, forcing explicit signaling of succcess. */
+ int ret = 0;
+ const char *narrow;
#define FORMAT_EXCEPTION(exc, fmt) \
PyErr_Format(exc, "%s%s" fmt, \
@@ -836,15 +853,10 @@ path_converter(PyObject *o, void *p) {
return 1;
}
- /* ensure it's always safe to call path_cleanup() */
+ /* 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;
@@ -853,25 +865,54 @@ path_converter(PyObject *o, void *p) {
return 1;
}
- unicode = PyUnicode_FromObject(o);
- if (unicode) {
+ /* Only call this here so that we don't treat the return value of
+ os.fspath() as an fd or buffer. */
+ is_index = path->allow_fd && PyIndex_Check(o);
+ is_buffer = PyObject_CheckBuffer(o);
+ is_bytes = PyBytes_Check(o);
+ is_unicode = PyUnicode_Check(o);
+
+ if (!is_index && !is_buffer && !is_unicode && !is_bytes) {
+ /* Inline PyOS_FSPath() for better error messages. */
+ _Py_IDENTIFIER(__fspath__);
+ PyObject *func = NULL;
+
+ func = _PyObject_LookupSpecial(o, &PyId___fspath__);
+ if (NULL == func) {
+ goto error_exit;
+ }
+
+ o = to_cleanup = PyObject_CallFunctionObjArgs(func, NULL);
+ Py_DECREF(func);
+ if (NULL == o) {
+ goto error_exit;
+ }
+ else if (PyUnicode_Check(o)) {
+ is_unicode = 1;
+ }
+ else if (PyBytes_Check(o)) {
+ is_bytes = 1;
+ }
+ else {
+ goto error_exit;
+ }
+ }
+
+ if (is_unicode) {
#ifdef MS_WINDOWS
- wchar_t *wide;
+ const wchar_t *wide;
- wide = PyUnicode_AsUnicodeAndSize(unicode, &length);
+ wide = PyUnicode_AsUnicodeAndSize(o, &length);
if (!wide) {
- Py_DECREF(unicode);
- return 0;
+ goto exit;
}
if (length > 32767) {
FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
- Py_DECREF(unicode);
- return 0;
+ goto exit;
}
if (wcslen(wide) != length) {
- FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character");
- Py_DECREF(unicode);
- return 0;
+ FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
+ goto exit;
}
path->wide = wide;
@@ -879,58 +920,79 @@ path_converter(PyObject *o, void *p) {
path->length = length;
path->object = o;
path->fd = -1;
- path->cleanup = unicode;
- return Py_CLEANUP_SUPPORTED;
+ ret = 1;
+ goto exit;
#else
- int converted = PyUnicode_FSConverter(unicode, &bytes);
- Py_DECREF(unicode);
- if (!converted)
- bytes = NULL;
+ if (!PyUnicode_FSConverter(o, &bytes)) {
+ goto exit;
+ }
#endif
}
- else {
- PyErr_Clear();
- if (PyObject_CheckBuffer(o))
- bytes = PyBytes_FromObject(o);
- else
- bytes = NULL;
+ else if (is_bytes) {
+#ifdef MS_WINDOWS
+ if (win32_warn_bytes_api()) {
+ goto exit;
+ }
+#endif
+ bytes = o;
+ Py_INCREF(bytes);
+ }
+ else if (is_buffer) {
+ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+ "%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, os.PathLike, "
+ "integer or None" :
+ path->allow_fd ? "string, bytes, os.PathLike or integer" :
+ path->nullable ? "string, bytes, os.PathLike or None" :
+ "string, bytes or os.PathLike",
+ Py_TYPE(o)->tp_name)) {
+ goto exit;
+ }
+#ifdef MS_WINDOWS
+ if (win32_warn_bytes_api()) {
+ goto exit;
+ }
+#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;
- }
- }
+ goto exit;
}
}
-
- 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)) {
+ goto exit;
+ }
+ path->wide = NULL;
+ path->narrow = NULL;
+ path->length = 0;
+ path->object = o;
+ ret = 1;
+ goto exit;
}
-
-#ifdef MS_WINDOWS
- if (win32_warn_bytes_api()) {
- Py_DECREF(bytes);
- return 0;
+ else {
+ error_exit:
+ 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, os.PathLike, "
+ "integer or None" :
+ path->allow_fd ? "string, bytes, os.PathLike or integer" :
+ path->nullable ? "string, bytes, os.PathLike or None" :
+ "string, bytes or os.PathLike",
+ Py_TYPE(o)->tp_name);
+ goto exit;
}
-#endif
length = PyBytes_GET_SIZE(bytes);
#ifdef MS_WINDOWS
if (length > MAX_PATH-1) {
FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
Py_DECREF(bytes);
- return 0;
+ goto exit;
}
#endif
@@ -938,7 +1000,7 @@ path_converter(PyObject *o, void *p) {
if ((size_t)length != strlen(narrow)) {
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
Py_DECREF(bytes);
- return 0;
+ goto exit;
}
path->wide = NULL;
@@ -946,12 +1008,22 @@ path_converter(PyObject *o, void *p) {
path->length = length;
path->object = o;
path->fd = -1;
- path->cleanup = bytes;
- return Py_CLEANUP_SUPPORTED;
+ if (bytes == o) {
+ Py_DECREF(bytes);
+ ret = 1;
+ }
+ else {
+ path->cleanup = bytes;
+ ret = Py_CLEANUP_SUPPORTED;
+ }
+ exit:
+ Py_XDECREF(to_cleanup);
+ return ret;
}
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 : "",
@@ -974,7 +1046,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;
@@ -983,7 +1056,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;
@@ -992,7 +1066,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",
@@ -1003,7 +1078,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",
@@ -1014,8 +1090,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",
@@ -1026,8 +1103,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",
@@ -1099,8 +1177,8 @@ _PyVerify_fd_dup2(int fd1, int fd2)
static int
win32_get_reparse_tag(HANDLE reparse_point_handle, ULONG *reparse_tag)
{
- char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
- REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
+ char target_buffer[_Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ _Py_REPARSE_DATA_BUFFER *rdb = (_Py_REPARSE_DATA_BUFFER *)target_buffer;
DWORD n_bytes_returned;
if (0 == DeviceIoControl(
@@ -1159,7 +1237,7 @@ convertenviron(void)
for (e = _wenviron; *e != NULL; e++) {
PyObject *k;
PyObject *v;
- wchar_t *p = wcschr(*e, L'=');
+ const wchar_t *p = wcschr(*e, L'=');
if (p == NULL)
continue;
k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e));
@@ -1187,7 +1265,7 @@ convertenviron(void)
for (e = environ; *e != NULL; e++) {
PyObject *k;
PyObject *v;
- char *p = strchr(*e, '=');
+ const char *p = strchr(*e, '=');
if (p == NULL)
continue;
k = PyBytes_FromStringAndSize(*e, (int)(p-*e));
@@ -1222,7 +1300,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.)
@@ -1237,7 +1315,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();
@@ -1458,7 +1536,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;
@@ -1468,12 +1546,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;
}
@@ -1558,7 +1636,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
@@ -1648,7 +1726,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
@@ -2102,7 +2180,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;
@@ -3314,12 +3392,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
@@ -3461,15 +3549,13 @@ _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) {
WIN32_FIND_DATAW wFileData;
- wchar_t *po_wchars;
+ const wchar_t *po_wchars;
if (!path->wide) { /* Default arg: "." */
po_wchars = L".";
@@ -3635,7 +3721,7 @@ _posix_listdir(path_t *path, PyObject *list)
else
#endif
{
- char *name;
+ const char *name;
if (path->narrow) {
name = path->narrow;
/* only return bytes if they specified a bytes object */
@@ -3817,7 +3903,7 @@ os__getfinalpathname_impl(PyObject *module, PyObject *path)
wchar_t *target_path;
int result_length;
PyObject *result;
- wchar_t *path_wchar;
+ const wchar_t *path_wchar;
path_wchar = PyUnicode_AsUnicode(path);
if (path_wchar == NULL)
@@ -3908,7 +3994,8 @@ os__getvolumepathname_impl(PyObject *module, PyObject *path)
/*[clinic end generated code: output=cbdcbd1059ceef4c input=7eacadc40acbda6b]*/
{
PyObject *result;
- wchar_t *path_wchar, *mountpath=NULL;
+ const wchar_t *path_wchar;
+ wchar_t *mountpath=NULL;
size_t buflen;
BOOL ret;
@@ -4106,7 +4193,7 @@ os_setpriority_impl(PyObject *module, int which, int who, int priority)
static PyObject *
internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is_replace)
{
- char *function_name = is_replace ? "replace" : "rename";
+ const char *function_name = is_replace ? "replace" : "rename";
int dir_fd_specified;
#ifdef MS_WINDOWS
@@ -4286,7 +4373,7 @@ os_system_impl(PyObject *module, PyObject *command)
/*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
{
long result;
- char *bytes = PyBytes_AsString(command);
+ const char *bytes = PyBytes_AsString(command);
Py_BEGIN_ALLOW_THREADS
result = system(bytes);
Py_END_ALLOW_THREADS
@@ -4566,7 +4653,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;
@@ -4608,14 +4695,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;
@@ -4631,7 +4718,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;
@@ -4774,7 +4861,7 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
utime.now = 1;
}
-#if !UTIME_HAVE_NOFOLLOW_SYMLINKS
+#if !defined(UTIME_HAVE_NOFOLLOW_SYMLINKS)
if (follow_symlinks_specified("utime", follow_symlinks))
goto exit;
#endif
@@ -4828,7 +4915,7 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
#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
@@ -4925,7 +5012,8 @@ parse_envlist(PyObject* env, Py_ssize_t *envc_ptr)
Py_ssize_t i, pos, envc;
PyObject *keys=NULL, *vals=NULL;
PyObject *key, *val, *key2, *val2;
- char *p, *k, *v;
+ char *p;
+ const char *k, *v;
size_t len;
i = PyMapping_Size(env);
@@ -5040,7 +5128,7 @@ static PyObject *
os_execv_impl(PyObject *module, PyObject *path, PyObject *argv)
/*[clinic end generated code: output=b21dc34deeb5b004 input=96041559925e5229]*/
{
- char *path_char;
+ const char *path_char;
char **argvlist;
Py_ssize_t argc;
@@ -5160,7 +5248,7 @@ static PyObject *
os_spawnv_impl(PyObject *module, int mode, PyObject *path, PyObject *argv)
/*[clinic end generated code: output=c427c0ce40f10638 input=042c91dfc1e6debc]*/
{
- char *path_char;
+ const char *path_char;
char **argvlist;
int i;
Py_ssize_t argc;
@@ -5238,7 +5326,7 @@ os_spawnve_impl(PyObject *module, int mode, PyObject *path, PyObject *argv,
PyObject *env)
/*[clinic end generated code: output=ebcfa5f7ba2f4219 input=02362fd937963f8f]*/
{
- char *path_char;
+ const char *path_char;
char **argvlist;
char **envlist;
PyObject *res = NULL;
@@ -5758,14 +5846,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(PyObject *module, pid_t pid)
-/*[clinic end generated code: output=f726f2c193c17a4f input=eaf161936874b8a1]*/
+/*[clinic end generated code: output=f726f2c193c17a4f input=983ce7cb4a565980]*/
{
int cpu, ncpus, count;
size_t setsize;
@@ -5926,7 +6014,7 @@ os_openpty_impl(PyObject *module)
if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
goto posix_error;
-#if !defined(__CYGWIN__) && !defined(HAVE_DEV_PTC)
+#if !defined(__CYGWIN__) && !defined(__ANDROID__) && !defined(HAVE_DEV_PTC)
ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */
ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */
#ifndef __hpux
@@ -6251,7 +6339,7 @@ static PyObject *
posix_initgroups(PyObject *self, PyObject *args)
{
PyObject *oname;
- char *username;
+ const char *username;
int res;
#ifdef __APPLE__
int gid;
@@ -7125,16 +7213,16 @@ exit:
static PyObject *
win_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
{
- wchar_t *path;
+ const wchar_t *path;
DWORD n_bytes_returned;
DWORD io_result;
PyObject *po, *result;
- int dir_fd;
+ int dir_fd;
HANDLE reparse_point_handle;
- char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
- REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
- wchar_t *print_name;
+ char target_buffer[_Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ _Py_REPARSE_DATA_BUFFER *rdb = (_Py_REPARSE_DATA_BUFFER *)target_buffer;
+ const wchar_t *print_name;
static char *keywords[] = {"path", "dir_fd", NULL};
@@ -7202,8 +7290,8 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs)
#if defined(MS_WINDOWS)
/* Grab CreateSymbolicLinkW dynamically from kernel32 */
-static DWORD (CALLBACK *Py_CreateSymbolicLinkW)(LPWSTR, LPWSTR, DWORD) = NULL;
-static DWORD (CALLBACK *Py_CreateSymbolicLinkA)(LPSTR, LPSTR, DWORD) = NULL;
+static DWORD (CALLBACK *Py_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD) = NULL;
+static DWORD (CALLBACK *Py_CreateSymbolicLinkA)(LPCSTR, LPCSTR, DWORD) = NULL;
static int
check_CreateSymbolicLink(void)
@@ -7308,7 +7396,7 @@ _joinA(char *dest_path, const char *root, const char *rest)
/* Return True if the path at src relative to dest is a directory */
static int
-_check_dirW(WCHAR *src, WCHAR *dest)
+_check_dirW(LPCWSTR src, LPCWSTR dest)
{
WIN32_FILE_ATTRIBUTE_DATA src_info;
WCHAR dest_parent[MAX_PATH];
@@ -7327,7 +7415,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(LPCSTR src, LPCSTR dest)
{
WIN32_FILE_ATTRIBUTE_DATA src_info;
char dest_parent[MAX_PATH];
@@ -9015,7 +9103,7 @@ static PyObject *
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
/*[clinic end generated code: output=d29a567d6b2327d2 input=ba586581c2e6105f]*/
{
- wchar_t *env;
+ const wchar_t *env;
PyObject *unicode = PyUnicode_FromFormat("%U=%U", name, value);
if (unicode == NULL) {
@@ -9061,8 +9149,8 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
{
PyObject *bytes = NULL;
char *env;
- char *name_string = PyBytes_AsString(name);
- char *value_string = PyBytes_AsString(value);
+ const char *name_string = PyBytes_AsString(name);
+ const char *value_string = PyBytes_AsString(value);
bytes = PyBytes_FromFormat("%s=%s", name_string, value_string);
if (bytes == NULL) {
@@ -9481,8 +9569,8 @@ os__getdiskusage_impl(PyObject *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 +9578,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 {
@@ -10451,7 +10542,7 @@ cmp_constdefs(const void *v1, const void *v2)
static int
setup_confname_table(struct constdef *table, size_t tablesize,
- char *tablename, PyObject *module)
+ const char *tablename, PyObject *module)
{
PyObject *d = NULL;
size_t i;
@@ -10578,9 +10669,9 @@ static PyObject *
win32_startfile(PyObject *self, PyObject *args)
{
PyObject *ofilepath;
- char *filepath;
- char *operation = NULL;
- wchar_t *wpath, *woperation;
+ const char *filepath;
+ const char *operation = NULL;
+ const wchar_t *wpath, *woperation;
HINSTANCE rc;
PyObject *unipath, *uoperation = NULL;
@@ -10821,7 +10912,7 @@ os_getxattr_impl(PyObject *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);
@@ -10985,9 +11076,9 @@ os_listxattr_impl(PyObject *module, path_t *path, int follow_symlinks)
name = path->narrow ? path->narrow : ".";
for (i = 0; ; i++) {
- char *start, *trace, *end;
+ const 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 +11290,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(PyObject *module)
-/*[clinic end generated code: output=5fc29463c3936a9c input=d55e2f8f3823a628]*/
+/*[clinic end generated code: output=5fc29463c3936a9c input=e7c8f4ba6dbbadd3]*/
{
int ncpu = 0;
#ifdef MS_WINDOWS
@@ -11460,7 +11555,7 @@ DirEntry_fetch_stat(DirEntry *self, int follow_symlinks)
struct _Py_stat_struct st;
#ifdef MS_WINDOWS
- wchar_t *path;
+ const wchar_t *path;
path = PyUnicode_AsUnicode(self->path);
if (!path)
@@ -11477,7 +11572,7 @@ DirEntry_fetch_stat(DirEntry *self, int follow_symlinks)
}
#else /* POSIX */
PyObject *bytes;
- char *path;
+ const char *path;
if (!PyUnicode_FSConverter(self->path, &bytes))
return NULL;
@@ -11661,7 +11756,7 @@ DirEntry_inode(DirEntry *self)
{
#ifdef MS_WINDOWS
if (!self->got_file_index) {
- wchar_t *path;
+ const wchar_t *path;
struct _Py_stat_struct stat;
path = PyUnicode_AsUnicode(self->path);
@@ -11692,6 +11787,13 @@ DirEntry_repr(DirEntry *self)
return PyUnicode_FromFormat("<DirEntry %R>", self->name);
}
+static PyObject *
+DirEntry_fspath(DirEntry *self)
+{
+ Py_INCREF(self->path);
+ return self->path;
+}
+
static PyMemberDef DirEntry_members[] = {
{"name", T_OBJECT_EX, offsetof(DirEntry, name), READONLY,
"the entry's base filename, relative to scandir() \"path\" argument"},
@@ -11716,6 +11818,9 @@ static PyMethodDef DirEntry_methods[] = {
{"inode", (PyCFunction)DirEntry_inode, METH_NOARGS,
"return inode of the entry; cached per entry",
},
+ {"__fspath__", (PyCFunction)DirEntry_fspath, METH_NOARGS,
+ "returns the path for the entry",
+ },
{NULL}
};
@@ -11755,7 +11860,7 @@ static PyTypeObject DirEntryType = {
#ifdef MS_WINDOWS
static wchar_t *
-join_path_filenameW(wchar_t *path_wide, wchar_t* filename)
+join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename)
{
Py_ssize_t path_len;
Py_ssize_t size;
@@ -11830,7 +11935,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 +11967,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 +12030,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 +12057,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 +12088,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 +12123,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 +12160,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 +12251,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 +12260,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 *
@@ -12097,7 +12291,7 @@ posix_scandir(PyObject *self, PyObject *args, PyObject *kwargs)
#ifdef MS_WINDOWS
wchar_t *path_strW;
#else
- char *path;
+ const char *path;
#endif
iterator = PyObject_New(ScandirIterator, &ScandirIteratorType);
@@ -12169,6 +12363,71 @@ error:
return NULL;
}
+/*
+ Return the file system path representation of the object.
+
+ If the object is str or bytes, then allow it to pass through with
+ an incremented refcount. If the object defines __fspath__(), then
+ return the result of that method. All other types raise a TypeError.
+*/
+PyObject *
+PyOS_FSPath(PyObject *path)
+{
+ /* For error message reasons, this function is manually inlined in
+ path_converter(). */
+ _Py_IDENTIFIER(__fspath__);
+ PyObject *func = NULL;
+ PyObject *path_repr = NULL;
+
+ if (PyUnicode_Check(path) || PyBytes_Check(path)) {
+ Py_INCREF(path);
+ return path;
+ }
+
+ func = _PyObject_LookupSpecial(path, &PyId___fspath__);
+ if (NULL == func) {
+ return PyErr_Format(PyExc_TypeError,
+ "expected str, bytes or os.PathLike object, "
+ "not %.200s",
+ Py_TYPE(path)->tp_name);
+ }
+
+ path_repr = PyObject_CallFunctionObjArgs(func, NULL);
+ Py_DECREF(func);
+ if (NULL == path_repr) {
+ return NULL;
+ }
+
+ if (!(PyUnicode_Check(path_repr) || PyBytes_Check(path_repr))) {
+ PyErr_Format(PyExc_TypeError,
+ "expected %.200s.__fspath__() to return str or bytes, "
+ "not %.200s", Py_TYPE(path)->tp_name,
+ Py_TYPE(path_repr)->tp_name);
+ Py_DECREF(path_repr);
+ return NULL;
+ }
+
+ return path_repr;
+}
+
+/*[clinic input]
+os.fspath
+
+ path: object
+
+Return the file system path representation of the object.
+
+If the object is str or bytes, then allow it to pass through as-is. If the
+object defines __fspath__(), then return the result of that method. All other
+types raise a TypeError.
+[clinic start generated code]*/
+
+static PyObject *
+os_fspath_impl(PyObject *module, PyObject *path)
+/*[clinic end generated code: output=c3c3b78ecff2914f input=e357165f7b22490f]*/
+{
+ return PyOS_FSPath(path);
+}
#include "clinic/posixmodule.c.h"
@@ -12369,6 +12628,7 @@ static PyMethodDef posix_methods[] = {
{"scandir", (PyCFunction)posix_scandir,
METH_VARARGS | METH_KEYWORDS,
posix_scandir__doc__},
+ OS_FSPATH_METHODDEF
{NULL, NULL} /* Sentinel */
};
@@ -12380,7 +12640,6 @@ enable_symlink()
HANDLE tok;
TOKEN_PRIVILEGES tok_priv;
LUID luid;
- int meth_idx = 0;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &tok))
return 0;
@@ -12483,12 +12742,14 @@ all_ins(PyObject *m)
#ifdef O_LARGEFILE
if (PyModule_AddIntMacro(m, O_LARGEFILE)) return -1;
#endif
+#ifndef __GNU__
#ifdef O_SHLOCK
if (PyModule_AddIntMacro(m, O_SHLOCK)) return -1;
#endif
#ifdef O_EXLOCK
if (PyModule_AddIntMacro(m, O_EXLOCK)) return -1;
#endif
+#endif
#ifdef O_EXEC
if (PyModule_AddIntMacro(m, O_EXEC)) return -1;
#endif
@@ -12791,25 +13052,25 @@ all_ins(PyObject *m)
if (PyModule_AddIntMacro(m, XATTR_SIZE_MAX)) return -1;
#endif
-#ifdef RTLD_LAZY
+#if HAVE_DECL_RTLD_LAZY
if (PyModule_AddIntMacro(m, RTLD_LAZY)) return -1;
#endif
-#ifdef RTLD_NOW
+#if HAVE_DECL_RTLD_NOW
if (PyModule_AddIntMacro(m, RTLD_NOW)) return -1;
#endif
-#ifdef RTLD_GLOBAL
+#if HAVE_DECL_RTLD_GLOBAL
if (PyModule_AddIntMacro(m, RTLD_GLOBAL)) return -1;
#endif
-#ifdef RTLD_LOCAL
+#if HAVE_DECL_RTLD_LOCAL
if (PyModule_AddIntMacro(m, RTLD_LOCAL)) return -1;
#endif
-#ifdef RTLD_NODELETE
+#if HAVE_DECL_RTLD_NODELETE
if (PyModule_AddIntMacro(m, RTLD_NODELETE)) return -1;
#endif
-#ifdef RTLD_NOLOAD
+#if HAVE_DECL_RTLD_NOLOAD
if (PyModule_AddIntMacro(m, RTLD_NOLOAD)) return -1;
#endif
-#ifdef RTLD_DEEPBIND
+#if HAVE_DECL_RTLD_DEEPBIND
if (PyModule_AddIntMacro(m, RTLD_DEEPBIND)) return -1;
#endif
@@ -12830,7 +13091,7 @@ static struct PyModuleDef posixmodule = {
};
-static char *have_functions[] = {
+static const char * const have_functions[] = {
#ifdef HAVE_FACCESSAT
"HAVE_FACCESSAT",
@@ -12965,7 +13226,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();
@@ -13141,6 +13402,9 @@ INITFUNC(void)
}
PyModule_AddObject(m, "_have_functions", list);
+ Py_INCREF((PyObject *) &DirEntryType);
+ PyModule_AddObject(m, "DirEntry", (PyObject *)&DirEntryType);
+
initialized = 1;
return m;