From: Georg Brandl <georg@python.org> Date: Mon, 20 Feb 2012 23:33:36 +0000 (+0100) Subject: Merge 3.2: Issue #13703 plus some related test suite fixes. X-Git-Tag: v3.3.0a1~120 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2fb477c0f0284439d40cb3f46eea45ef42446e53;p=python Merge 3.2: Issue #13703 plus some related test suite fixes. --- 2fb477c0f0284439d40cb3f46eea45ef42446e53 diff --cc Doc/library/sys.rst index c2b7423e0c,063e0a52c0..3af43543c4 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@@ -257,9 -259,9 +258,12 @@@ always available .. versionchanged:: 3.2 Added ``quiet`` attribute for the new :option:`-q` flag. + .. versionadded:: 3.2.3 + The ``hash_randomization`` attribute. + + .. versionchanged:: 3.3 + Removed obsolete ``division_warning`` attribute. + .. data:: float_info diff --cc Include/object.h index 844ff9f14a,a54c400774..c69becec51 --- a/Include/object.h +++ b/Include/object.h @@@ -551,9 -515,14 +551,15 @@@ PyAPI_FUNC(void) Py_ReprLeave(PyObject #ifndef Py_LIMITED_API PyAPI_FUNC(Py_hash_t) _Py_HashDouble(double); PyAPI_FUNC(Py_hash_t) _Py_HashPointer(void*); +PyAPI_FUNC(Py_hash_t) _Py_HashBytes(unsigned char*, Py_ssize_t); #endif + typedef struct { + Py_hash_t prefix; + Py_hash_t suffix; + } _Py_HashSecret_t; + PyAPI_DATA(_Py_HashSecret_t) _Py_HashSecret; + /* Helper for passing objects to printf and the like */ #define PyObject_REPR(obj) _PyUnicode_AsString(PyObject_Repr(obj)) diff --cc Lib/test/test_os.py index c5dbb95629,8bc8ba9fa6..a0f13fd790 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@@ -14,27 -14,9 +14,28 @@@ import shuti from test import support import contextlib import mmap +import platform +import re import uuid +import asyncore +import asynchat +import socket +import itertools +import stat +try: + import threading +except ImportError: + threading = None + from test.script_helper import assert_python_ok +os.stat_float_times(True) +st = os.stat(__file__) +stat_supports_subsecond = ( + # check if float and int timestamps are different + (st.st_atime != st[7]) + or (st.st_mtime != st[8]) + or (st.st_ctime != st[9])) + # Detect whether we're on a Linux system that uses the (now outdated # and unmaintained) linuxthreads threading library. There's an issue # when combining linuxthreads with a failed execv call: see diff --cc Lib/test/test_sys.py index f065bf72e6,3268b1a141..bf22df2269 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@@ -510,10 -500,10 +510,10 @@@ class SysModuleTest(unittest.TestCase) def test_sys_flags(self): self.assertTrue(sys.flags) - attrs = ("debug", "division_warning", + attrs = ("debug", "inspect", "interactive", "optimize", "dont_write_bytecode", "no_user_site", "no_site", "ignore_environment", "verbose", - "bytes_warning", "quiet") + "bytes_warning", "quiet", "hash_randomization") for attr in attrs: self.assertTrue(hasattr(sys.flags, attr), attr) self.assertEqual(type(getattr(sys.flags, attr)), int, attr) diff --cc Misc/NEWS index 6e010b7a2f,0e3595a221..1a6ce289fd --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -10,12 -10,11 +10,17 @@@ What's New in Python 3.3 Alpha 1 Core and Builtins ----------------- +- Issue #14040: Remove rarely used file name suffixes for C extensions + (under POSIX mainly). + +- Issue #14051: Allow arbitrary attributes to be set of classmethod and + staticmethod. + + - Issue #13703: oCERT-2011-003: add -R command-line option and PYTHONHASHSEED + environment variable, to provide an opt-in way to protect against denial of + service attacks due to hash collisions within the dict and set types. Patch + by David Malcolm, based on work by Victor Stinner. + - Issue #13020: Fix a reference leak when allocating a structsequence object fails. Patch by Suman Saha. diff --cc Misc/python.man index eaa3ec7646,fc3566fcac..ef42c4ef94 --- a/Misc/python.man +++ b/Misc/python.man @@@ -37,6 -37,13 +37,9 @@@ python \- an interpreted, interactive, .B \-OO ] [ + .B \-R + ] + [ -.B -Q -.I argument -] -[ .B \-s ] [ @@@ -148,6 -155,27 +151,18 @@@ Discard docstrings in addition to the \ Do not print the version and copyright messages. These messages are also suppressed in non-interactive mode. .TP + .B \-R + Turn on "hash randomization", so that the hash() values of str, bytes and + datetime objects are "salted" with an unpredictable pseudo-random value. + Although they remain constant within an individual Python process, they are + not predictable between repeated invocations of Python. + .IP + This is intended to provide protection against a denial of service + caused by carefully-chosen inputs that exploit the worst case performance + of a dict insertion, O(n^2) complexity. See + http://www.ocert.org/advisories/ocert-2011-003.html + for details. + .TP -.BI "\-Q " argument -Division control; see PEP 238. The argument must be one of "old" (the -default, int/int and long/long return an int or long), "new" (new -division semantics, i.e. int/int and long/long returns a float), -"warn" (old division semantics with a warning for int/int and -long/long), or "warnall" (old division semantics with a warning for -all use of the division operator). For a use of "warnall", see the -Tools/scripts/fixdiv.py script. -.TP .B \-s Don't add user site directory to sys.path. .TP diff --cc Modules/main.c index d8c5172108,ed84aa0286..a820a9eb44 --- a/Modules/main.c +++ b/Modules/main.c @@@ -100,9 -102,14 +103,15 @@@ static char *usage_5 "PYTHONHOME : alternate <prefix> directory (or <prefix>%c<exec_prefix>).\n" " The default module search path uses %s.\n" "PYTHONCASEOK : ignore case in 'import' statements (Windows).\n" -"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n\ +"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n" - "PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n" - ; ++"PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n\ + "; + static char *usage_6 = "\ + PYTHONHASHSEED: if this variable is set to ``random``, the effect is the same \n\ + as specifying the :option:`-R` option: a random value is used to seed the\n\ + hashes of str, bytes and datetime objects. It can also be set to an integer\n\ + in the range [0,4294967295] to get hash values with a predictable seed.\n\ + "; static int usage(int exitcode, wchar_t* program) diff --cc Modules/posixmodule.c index 0553c761bd,9f57673fbe..dbace1a891 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@@ -9023,1579 -7334,428 +9023,1533 @@@ static struct constdef posix_constants_ #ifdef _SC_ULONG_MAX {"SC_ULONG_MAX", _SC_ULONG_MAX}, #endif -#ifdef _SC_USHRT_MAX - {"SC_USHRT_MAX", _SC_USHRT_MAX}, +#ifdef _SC_USHRT_MAX + {"SC_USHRT_MAX", _SC_USHRT_MAX}, +#endif +#ifdef _SC_VERSION + {"SC_VERSION", _SC_VERSION}, +#endif +#ifdef _SC_WORD_BIT + {"SC_WORD_BIT", _SC_WORD_BIT}, +#endif +#ifdef _SC_XBS5_ILP32_OFF32 + {"SC_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32}, +#endif +#ifdef _SC_XBS5_ILP32_OFFBIG + {"SC_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG}, +#endif +#ifdef _SC_XBS5_LP64_OFF64 + {"SC_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64}, +#endif +#ifdef _SC_XBS5_LPBIG_OFFBIG + {"SC_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG}, +#endif +#ifdef _SC_XOPEN_CRYPT + {"SC_XOPEN_CRYPT", _SC_XOPEN_CRYPT}, +#endif +#ifdef _SC_XOPEN_ENH_I18N + {"SC_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N}, +#endif +#ifdef _SC_XOPEN_LEGACY + {"SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY}, +#endif +#ifdef _SC_XOPEN_REALTIME + {"SC_XOPEN_REALTIME", _SC_XOPEN_REALTIME}, +#endif +#ifdef _SC_XOPEN_REALTIME_THREADS + {"SC_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS}, +#endif +#ifdef _SC_XOPEN_SHM + {"SC_XOPEN_SHM", _SC_XOPEN_SHM}, +#endif +#ifdef _SC_XOPEN_UNIX + {"SC_XOPEN_UNIX", _SC_XOPEN_UNIX}, +#endif +#ifdef _SC_XOPEN_VERSION + {"SC_XOPEN_VERSION", _SC_XOPEN_VERSION}, +#endif +#ifdef _SC_XOPEN_XCU_VERSION + {"SC_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION}, +#endif +#ifdef _SC_XOPEN_XPG2 + {"SC_XOPEN_XPG2", _SC_XOPEN_XPG2}, +#endif +#ifdef _SC_XOPEN_XPG3 + {"SC_XOPEN_XPG3", _SC_XOPEN_XPG3}, +#endif +#ifdef _SC_XOPEN_XPG4 + {"SC_XOPEN_XPG4", _SC_XOPEN_XPG4}, +#endif +}; + +static int +conv_sysconf_confname(PyObject *arg, int *valuep) +{ + return conv_confname(arg, valuep, posix_constants_sysconf, + sizeof(posix_constants_sysconf) + / sizeof(struct constdef)); +} + +PyDoc_STRVAR(posix_sysconf__doc__, +"sysconf(name) -> integer\n\n\ +Return an integer-valued system configuration variable."); + +static PyObject * +posix_sysconf(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + int name; + + if (PyArg_ParseTuple(args, "O&:sysconf", conv_sysconf_confname, &name)) { + int value; + + errno = 0; + value = sysconf(name); + if (value == -1 && errno != 0) + posix_error(); + else + result = PyLong_FromLong(value); + } + return result; +} +#endif + + +/* This code is used to ensure that the tables of configuration value names + * are in sorted order as required by conv_confname(), and also to build the + * the exported dictionaries that are used to publish information about the + * names available on the host platform. + * + * Sorting the table at runtime ensures that the table is properly ordered + * when used, even for platforms we're not able to test on. It also makes + * it easier to add additional entries to the tables. + */ + +static int +cmp_constdefs(const void *v1, const void *v2) +{ + const struct constdef *c1 = + (const struct constdef *) v1; + const struct constdef *c2 = + (const struct constdef *) v2; + + return strcmp(c1->name, c2->name); +} + +static int +setup_confname_table(struct constdef *table, size_t tablesize, + char *tablename, PyObject *module) +{ + PyObject *d = NULL; + size_t i; + + qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs); + d = PyDict_New(); + if (d == NULL) + return -1; + + for (i=0; i < tablesize; ++i) { + PyObject *o = PyLong_FromLong(table[i].value); + if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) { + Py_XDECREF(o); + Py_DECREF(d); + return -1; + } + Py_DECREF(o); + } + return PyModule_AddObject(module, tablename, d); +} + +/* Return -1 on failure, 0 on success. */ +static int +setup_confname_tables(PyObject *module) +{ +#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF) + if (setup_confname_table(posix_constants_pathconf, + sizeof(posix_constants_pathconf) + / sizeof(struct constdef), + "pathconf_names", module)) + return -1; +#endif +#ifdef HAVE_CONFSTR + if (setup_confname_table(posix_constants_confstr, + sizeof(posix_constants_confstr) + / sizeof(struct constdef), + "confstr_names", module)) + return -1; +#endif +#ifdef HAVE_SYSCONF + if (setup_confname_table(posix_constants_sysconf, + sizeof(posix_constants_sysconf) + / sizeof(struct constdef), + "sysconf_names", module)) + return -1; +#endif + return 0; +} + + +PyDoc_STRVAR(posix_abort__doc__, +"abort() -> does not return!\n\n\ +Abort the interpreter immediately. This 'dumps core' or otherwise fails\n\ +in the hardest way possible on the hosting operating system."); + +static PyObject * +posix_abort(PyObject *self, PyObject *noargs) +{ + abort(); + /*NOTREACHED*/ + Py_FatalError("abort() called from Python code didn't abort!"); + return NULL; +} + +#ifdef MS_WINDOWS +PyDoc_STRVAR(win32_startfile__doc__, +"startfile(filepath [, operation]) - Start a file with its associated\n\ +application.\n\ +\n\ +When \"operation\" is not specified or \"open\", this acts like\n\ +double-clicking the file in Explorer, or giving the file name as an\n\ +argument to the DOS \"start\" command: the file is opened with whatever\n\ +application (if any) its extension is associated.\n\ +When another \"operation\" is given, it specifies what should be done with\n\ +the file. A typical operation is \"print\".\n\ +\n\ +startfile returns as soon as the associated application is launched.\n\ +There is no option to wait for the application to close, and no way\n\ +to retrieve the application's exit status.\n\ +\n\ +The filepath is relative to the current directory. If you want to use\n\ +an absolute path, make sure the first character is not a slash (\"/\");\n\ +the underlying Win32 ShellExecute function doesn't work if it is."); + +static PyObject * +win32_startfile(PyObject *self, PyObject *args) +{ + PyObject *ofilepath; + char *filepath; + char *operation = NULL; + wchar_t *wpath, *woperation; + HINSTANCE rc; + + PyObject *unipath, *uoperation = NULL; + if (!PyArg_ParseTuple(args, "U|s:startfile", + &unipath, &operation)) { + PyErr_Clear(); + goto normal; + } + + if (operation) { + uoperation = PyUnicode_DecodeASCII(operation, + strlen(operation), NULL); + if (!uoperation) { + PyErr_Clear(); + operation = NULL; + goto normal; + } + } + + wpath = PyUnicode_AsUnicode(unipath); + if (wpath == NULL) + goto normal; + if (uoperation) { + woperation = PyUnicode_AsUnicode(uoperation); + if (woperation == NULL) + goto normal; + } + else + woperation = NULL; + + Py_BEGIN_ALLOW_THREADS + rc = ShellExecuteW((HWND)0, woperation, wpath, + NULL, NULL, SW_SHOWNORMAL); + Py_END_ALLOW_THREADS + + Py_XDECREF(uoperation); + if (rc <= (HINSTANCE)32) { + win32_error_object("startfile", unipath); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; + +normal: + if (!PyArg_ParseTuple(args, "O&|s:startfile", + PyUnicode_FSConverter, &ofilepath, + &operation)) + return NULL; + if (win32_warn_bytes_api()) { + Py_DECREF(ofilepath); + return NULL; + } + filepath = PyBytes_AsString(ofilepath); + Py_BEGIN_ALLOW_THREADS + rc = ShellExecute((HWND)0, operation, filepath, + NULL, NULL, SW_SHOWNORMAL); + Py_END_ALLOW_THREADS + if (rc <= (HINSTANCE)32) { + PyObject *errval = win32_error("startfile", filepath); + Py_DECREF(ofilepath); + return errval; + } + Py_DECREF(ofilepath); + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_GETLOADAVG +PyDoc_STRVAR(posix_getloadavg__doc__, +"getloadavg() -> (float, float, float)\n\n\ +Return the number of processes in the system run queue averaged over\n\ +the last 1, 5, and 15 minutes or raises OSError if the load average\n\ +was unobtainable"); + +static PyObject * +posix_getloadavg(PyObject *self, PyObject *noargs) +{ + double loadavg[3]; + if (getloadavg(loadavg, 3)!=3) { + PyErr_SetString(PyExc_OSError, "Load averages are unobtainable"); + return NULL; + } else + return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]); +} #endif -#ifdef _SC_VERSION - {"SC_VERSION", _SC_VERSION}, + - #ifdef MS_WINDOWS - - PyDoc_STRVAR(win32_urandom__doc__, - "urandom(n) -> str\n\n\ - Return n random bytes suitable for cryptographic use."); - - typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\ - LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\ - DWORD dwFlags ); - typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\ - BYTE *pbBuffer ); - - static CRYPTGENRANDOM pCryptGenRandom = NULL; - /* This handle is never explicitly released. Instead, the operating - system will release it when the process terminates. */ - static HCRYPTPROV hCryptProv = 0; - - static PyObject* - win32_urandom(PyObject *self, PyObject *args) - { - int howMany; - PyObject* result; - - /* Read arguments */ - if (! PyArg_ParseTuple(args, "i:urandom", &howMany)) - return NULL; - if (howMany < 0) - return PyErr_Format(PyExc_ValueError, - "negative argument not allowed"); - - if (hCryptProv == 0) { - HINSTANCE hAdvAPI32 = NULL; - CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; - - /* Obtain handle to the DLL containing CryptoAPI - This should not fail */ - hAdvAPI32 = GetModuleHandleW(L"advapi32.dll"); - if(hAdvAPI32 == NULL) - return win32_error("GetModuleHandle", NULL); - - /* Obtain pointers to the CryptoAPI functions - This will fail on some early versions of Win95 */ - pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress( - hAdvAPI32, - "CryptAcquireContextA"); - if (pCryptAcquireContext == NULL) - return PyErr_Format(PyExc_NotImplementedError, - "CryptAcquireContextA not found"); - - pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress( - hAdvAPI32, "CryptGenRandom"); - if (pCryptGenRandom == NULL) - return PyErr_Format(PyExc_NotImplementedError, - "CryptGenRandom not found"); - - /* Acquire context */ - if (! pCryptAcquireContext(&hCryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - return win32_error("CryptAcquireContext", NULL); - } - - /* Allocate bytes */ - result = PyBytes_FromStringAndSize(NULL, howMany); - if (result != NULL) { - /* Get random data */ - memset(PyBytes_AS_STRING(result), 0, howMany); /* zero seed */ - if (! pCryptGenRandom(hCryptProv, howMany, (unsigned char*) - PyBytes_AS_STRING(result))) { - Py_DECREF(result); - return win32_error("CryptGenRandom", NULL); - } - } - return result; - } - #endif - +PyDoc_STRVAR(device_encoding__doc__, +"device_encoding(fd) -> str\n\n\ +Return a string describing the encoding of the device\n\ +if the output is a terminal; else return None."); + +static PyObject * +device_encoding(PyObject *self, PyObject *args) +{ + int fd; +#if defined(MS_WINDOWS) || defined(MS_WIN64) + UINT cp; #endif -#ifdef _SC_WORD_BIT - {"SC_WORD_BIT", _SC_WORD_BIT}, + if (!PyArg_ParseTuple(args, "i:device_encoding", &fd)) + return NULL; + if (!_PyVerify_fd(fd) || !isatty(fd)) { + Py_INCREF(Py_None); + return Py_None; + } +#if defined(MS_WINDOWS) || defined(MS_WIN64) + if (fd == 0) + cp = GetConsoleCP(); + else if (fd == 1 || fd == 2) + cp = GetConsoleOutputCP(); + else + cp = 0; + /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application + has no console */ + if (cp != 0) + return PyUnicode_FromFormat("cp%u", (unsigned int)cp); +#elif defined(CODESET) + { + char *codeset = nl_langinfo(CODESET); + if (codeset != NULL && codeset[0] != 0) + return PyUnicode_FromString(codeset); + } #endif -#ifdef _SC_XBS5_ILP32_OFF32 - {"SC_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32}, + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef __VMS +/* Use openssl random routine */ +#include <openssl/rand.h> +PyDoc_STRVAR(vms_urandom__doc__, +"urandom(n) -> str\n\n\ +Return n random bytes suitable for cryptographic use."); + +static PyObject* +vms_urandom(PyObject *self, PyObject *args) +{ + int howMany; + PyObject* result; + + /* Read arguments */ + if (! PyArg_ParseTuple(args, "i:urandom", &howMany)) + return NULL; + if (howMany < 0) + return PyErr_Format(PyExc_ValueError, + "negative argument not allowed"); + + /* Allocate bytes */ + result = PyBytes_FromStringAndSize(NULL, howMany); + if (result != NULL) { + /* Get random data */ + if (RAND_pseudo_bytes((unsigned char*) + PyBytes_AS_STRING(result), + howMany) < 0) { + Py_DECREF(result); + return PyErr_Format(PyExc_ValueError, + "RAND_pseudo_bytes"); + } + } + return result; +} #endif -#ifdef _SC_XBS5_ILP32_OFFBIG - {"SC_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG}, + +#ifdef HAVE_SETRESUID +PyDoc_STRVAR(posix_setresuid__doc__, +"setresuid(ruid, euid, suid)\n\n\ +Set the current process's real, effective, and saved user ids."); + +static PyObject* +posix_setresuid (PyObject *self, PyObject *args) +{ + /* We assume uid_t is no larger than a long. */ + long ruid, euid, suid; + if (!PyArg_ParseTuple(args, "lll", &ruid, &euid, &suid)) + return NULL; + if (setresuid(ruid, euid, suid) < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -#ifdef _SC_XBS5_LP64_OFF64 - {"SC_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64}, + +#ifdef HAVE_SETRESGID +PyDoc_STRVAR(posix_setresgid__doc__, +"setresgid(rgid, egid, sgid)\n\n\ +Set the current process's real, effective, and saved group ids."); + +static PyObject* +posix_setresgid (PyObject *self, PyObject *args) +{ + /* We assume uid_t is no larger than a long. */ + long rgid, egid, sgid; + if (!PyArg_ParseTuple(args, "lll", &rgid, &egid, &sgid)) + return NULL; + if (setresgid(rgid, egid, sgid) < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -#ifdef _SC_XBS5_LPBIG_OFFBIG - {"SC_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG}, + +#ifdef HAVE_GETRESUID +PyDoc_STRVAR(posix_getresuid__doc__, +"getresuid() -> (ruid, euid, suid)\n\n\ +Get tuple of the current process's real, effective, and saved user ids."); + +static PyObject* +posix_getresuid (PyObject *self, PyObject *noargs) +{ + uid_t ruid, euid, suid; + long l_ruid, l_euid, l_suid; + if (getresuid(&ruid, &euid, &suid) < 0) + return posix_error(); + /* Force the values into long's as we don't know the size of uid_t. */ + l_ruid = ruid; + l_euid = euid; + l_suid = suid; + return Py_BuildValue("(lll)", l_ruid, l_euid, l_suid); +} #endif -#ifdef _SC_XOPEN_CRYPT - {"SC_XOPEN_CRYPT", _SC_XOPEN_CRYPT}, + +#ifdef HAVE_GETRESGID +PyDoc_STRVAR(posix_getresgid__doc__, +"getresgid() -> (rgid, egid, sgid)\n\n\ +Get tuple of the current process's real, effective, and saved group ids."); + +static PyObject* +posix_getresgid (PyObject *self, PyObject *noargs) +{ + uid_t rgid, egid, sgid; + long l_rgid, l_egid, l_sgid; + if (getresgid(&rgid, &egid, &sgid) < 0) + return posix_error(); + /* Force the values into long's as we don't know the size of uid_t. */ + l_rgid = rgid; + l_egid = egid; + l_sgid = sgid; + return Py_BuildValue("(lll)", l_rgid, l_egid, l_sgid); +} #endif -#ifdef _SC_XOPEN_ENH_I18N - {"SC_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N}, + +/* Posix *at family of functions: + faccessat, fchmodat, fchownat, fstatat, futimesat, + linkat, mkdirat, mknodat, openat, readlinkat, renameat, symlinkat, + unlinkat, utimensat, mkfifoat */ + +#ifdef HAVE_FACCESSAT +PyDoc_STRVAR(posix_faccessat__doc__, +"faccessat(dirfd, path, mode, flags=0) -> True if granted, False otherwise\n\n\ +Like access() but if path is relative, it is taken as relative to dirfd.\n\ +flags is optional and can be constructed by ORing together zero or more\n\ +of these values: AT_SYMLINK_NOFOLLOW, AT_EACCESS.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_faccessat(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *path; + int mode; + int res; + int dirfd, flags = 0; + if (!PyArg_ParseTuple(args, "iO&i|i:faccessat", + &dirfd, PyUnicode_FSConverter, &opath, &mode, &flags)) + return NULL; + path = PyBytes_AsString(opath); + Py_BEGIN_ALLOW_THREADS + res = faccessat(dirfd, path, mode, flags); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + return PyBool_FromLong(res == 0); +} #endif -#ifdef _SC_XOPEN_LEGACY - {"SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY}, + +#ifdef HAVE_FCHMODAT +PyDoc_STRVAR(posix_fchmodat__doc__, +"fchmodat(dirfd, path, mode, flags=0)\n\n\ +Like chmod() but if path is relative, it is taken as relative to dirfd.\n\ +flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_fchmodat(PyObject *self, PyObject *args) +{ + int dirfd, mode, res; + int flags = 0; + PyObject *opath; + char *path; + + if (!PyArg_ParseTuple(args, "iO&i|i:fchmodat", + &dirfd, PyUnicode_FSConverter, &opath, &mode, &flags)) + return NULL; + + path = PyBytes_AsString(opath); + + Py_BEGIN_ALLOW_THREADS + res = fchmodat(dirfd, path, mode, flags); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} +#endif /* HAVE_FCHMODAT */ + +#ifdef HAVE_FCHOWNAT +PyDoc_STRVAR(posix_fchownat__doc__, +"fchownat(dirfd, path, uid, gid, flags=0)\n\n\ +Like chown() but if path is relative, it is taken as relative to dirfd.\n\ +flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_fchownat(PyObject *self, PyObject *args) +{ + PyObject *opath; + int dirfd, res; + long uid, gid; + int flags = 0; + char *path; + + if (!PyArg_ParseTuple(args, "iO&ll|i:fchownat", + &dirfd, PyUnicode_FSConverter, &opath, &uid, &gid, &flags)) + return NULL; + + path = PyBytes_AsString(opath); + + Py_BEGIN_ALLOW_THREADS + res = fchownat(dirfd, path, (uid_t) uid, (gid_t) gid, flags); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} +#endif /* HAVE_FCHOWNAT */ + +#ifdef HAVE_FSTATAT +PyDoc_STRVAR(posix_fstatat__doc__, +"fstatat(dirfd, path, flags=0) -> stat result\n\n\ +Like stat() but if path is relative, it is taken as relative to dirfd.\n\ +flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_fstatat(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *path; + STRUCT_STAT st; + int dirfd, res, flags = 0; + + if (!PyArg_ParseTuple(args, "iO&|i:fstatat", + &dirfd, PyUnicode_FSConverter, &opath, &flags)) + return NULL; + path = PyBytes_AsString(opath); + + Py_BEGIN_ALLOW_THREADS + res = fstatat(dirfd, path, &st, flags); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res != 0) + return posix_error(); + + return _pystat_fromstructstat(&st); +} #endif -#ifdef _SC_XOPEN_REALTIME - {"SC_XOPEN_REALTIME", _SC_XOPEN_REALTIME}, + +#ifdef HAVE_FUTIMESAT +PyDoc_STRVAR(posix_futimesat__doc__, +"futimesat(dirfd, path[, (atime, mtime)])\n\ +Like utime() but if path is relative, it is taken as relative to dirfd.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_futimesat(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *path; + int res, dirfd; + PyObject* arg = Py_None; + time_t atime, mtime; + long ansec, mnsec; + + if (!PyArg_ParseTuple(args, "iO&|O:futimesat", + &dirfd, PyUnicode_FSConverter, &opath, &arg)) + return NULL; + path = PyBytes_AsString(opath); + if (arg == Py_None) { + /* optional time values not given */ + Py_BEGIN_ALLOW_THREADS + res = futimesat(dirfd, path, NULL); + Py_END_ALLOW_THREADS + } + else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) { + PyErr_SetString(PyExc_TypeError, + "futimesat() arg 3 must be a tuple (atime, mtime)"); + Py_DECREF(opath); + return NULL; + } + else { + if (extract_time(PyTuple_GET_ITEM(arg, 0), + &atime, &ansec) == -1) { + Py_DECREF(opath); + return NULL; + } + if (extract_time(PyTuple_GET_ITEM(arg, 1), + &mtime, &mnsec) == -1) { + Py_DECREF(opath); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + { +#ifdef HAVE_UTIMENSAT + struct timespec buf[2]; + buf[0].tv_sec = atime; + buf[0].tv_nsec = ansec; + buf[1].tv_sec = mtime; + buf[1].tv_nsec = mnsec; + res = utimensat(dirfd, path, buf, 0); +#else + struct timeval buf[2]; + buf[0].tv_sec = atime; + buf[0].tv_usec = ansec / 1000; + buf[1].tv_sec = mtime; + buf[1].tv_usec = mnsec / 1000; + res = futimesat(dirfd, path, buf); #endif -#ifdef _SC_XOPEN_REALTIME_THREADS - {"SC_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS}, + } + Py_END_ALLOW_THREADS + } + Py_DECREF(opath); + if (res < 0) { + return posix_error(); + } + Py_RETURN_NONE; +} #endif -#ifdef _SC_XOPEN_SHM - {"SC_XOPEN_SHM", _SC_XOPEN_SHM}, + +#ifdef HAVE_LINKAT +PyDoc_STRVAR(posix_linkat__doc__, +"linkat(srcfd, srcpath, dstfd, dstpath, flags=0)\n\n\ +Like link() but if srcpath is relative, it is taken as relative to srcfd\n\ +and if dstpath is relative, it is taken as relative to dstfd.\n\ +flags is optional and may be 0 or AT_SYMLINK_FOLLOW.\n\ +If srcpath is relative and srcfd is the special value AT_FDCWD, then\n\ +srcpath is interpreted relative to the current working directory. This\n\ +also applies for dstpath."); + +static PyObject * +posix_linkat(PyObject *self, PyObject *args) +{ + PyObject *osrc, *odst; + char *src, *dst; + int res, srcfd, dstfd; + int flags = 0; + + if (!PyArg_ParseTuple(args, "iO&iO&|i:linkat", + &srcfd, PyUnicode_FSConverter, &osrc, &dstfd, PyUnicode_FSConverter, &odst, &flags)) + return NULL; + src = PyBytes_AsString(osrc); + dst = PyBytes_AsString(odst); + Py_BEGIN_ALLOW_THREADS + res = linkat(srcfd, src, dstfd, dst, flags); + Py_END_ALLOW_THREADS + Py_DECREF(osrc); + Py_DECREF(odst); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} +#endif /* HAVE_LINKAT */ + +#ifdef HAVE_MKDIRAT +PyDoc_STRVAR(posix_mkdirat__doc__, +"mkdirat(dirfd, path, mode=0o777)\n\n\ +Like mkdir() but if path is relative, it is taken as relative to dirfd.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_mkdirat(PyObject *self, PyObject *args) +{ + int res, dirfd; + PyObject *opath; + char *path; + int mode = 0777; + + if (!PyArg_ParseTuple(args, "iO&|i:mkdirat", + &dirfd, PyUnicode_FSConverter, &opath, &mode)) + return NULL; + path = PyBytes_AsString(opath); + Py_BEGIN_ALLOW_THREADS + res = mkdirat(dirfd, path, mode); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -#ifdef _SC_XOPEN_UNIX - {"SC_XOPEN_UNIX", _SC_XOPEN_UNIX}, + +#if defined(HAVE_MKNODAT) && defined(HAVE_MAKEDEV) +PyDoc_STRVAR(posix_mknodat__doc__, +"mknodat(dirfd, path, mode=0o600, device=0)\n\n\ +Like mknod() but if path is relative, it is taken as relative to dirfd.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_mknodat(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *filename; + int mode = 0600; + int device = 0; + int res, dirfd; + if (!PyArg_ParseTuple(args, "iO&|ii:mknodat", &dirfd, + PyUnicode_FSConverter, &opath, &mode, &device)) + return NULL; + filename = PyBytes_AS_STRING(opath); + Py_BEGIN_ALLOW_THREADS + res = mknodat(dirfd, filename, mode, device); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -#ifdef _SC_XOPEN_VERSION - {"SC_XOPEN_VERSION", _SC_XOPEN_VERSION}, + +#ifdef HAVE_OPENAT +PyDoc_STRVAR(posix_openat__doc__, +"openat(dirfd, path, flag, mode=0o777) -> fd\n\n\ +Like open() but if path is relative, it is taken as relative to dirfd.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_openat(PyObject *self, PyObject *args) +{ + PyObject *ofile; + char *file; + int flag, dirfd, fd; + int mode = 0777; + + if (!PyArg_ParseTuple(args, "iO&i|i:openat", + &dirfd, PyUnicode_FSConverter, &ofile, + &flag, &mode)) + return NULL; + file = PyBytes_AsString(ofile); + Py_BEGIN_ALLOW_THREADS + fd = openat(dirfd, file, flag, mode); + Py_END_ALLOW_THREADS + Py_DECREF(ofile); + if (fd < 0) + return posix_error(); + return PyLong_FromLong((long)fd); +} #endif -#ifdef _SC_XOPEN_XCU_VERSION - {"SC_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION}, + +#ifdef HAVE_READLINKAT +PyDoc_STRVAR(posix_readlinkat__doc__, +"readlinkat(dirfd, path) -> path\n\n\ +Like readlink() but if path is relative, it is taken as relative to dirfd.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_readlinkat(PyObject *self, PyObject *args) +{ + PyObject *v, *opath; + char buf[MAXPATHLEN]; + char *path; + int n, dirfd; + int arg_is_unicode = 0; + + if (!PyArg_ParseTuple(args, "iO&:readlinkat", + &dirfd, PyUnicode_FSConverter, &opath)) + return NULL; + path = PyBytes_AsString(opath); + v = PySequence_GetItem(args, 1); + if (v == NULL) { + Py_DECREF(opath); + return NULL; + } + + if (PyUnicode_Check(v)) { + arg_is_unicode = 1; + } + Py_DECREF(v); + + Py_BEGIN_ALLOW_THREADS + n = readlinkat(dirfd, path, buf, (int) sizeof buf); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (n < 0) + return posix_error(); + + if (arg_is_unicode) + return PyUnicode_DecodeFSDefaultAndSize(buf, n); + else + return PyBytes_FromStringAndSize(buf, n); +} +#endif /* HAVE_READLINKAT */ + +#ifdef HAVE_RENAMEAT +PyDoc_STRVAR(posix_renameat__doc__, +"renameat(olddirfd, oldpath, newdirfd, newpath)\n\n\ +Like rename() but if oldpath is relative, it is taken as relative to\n\ +olddirfd and if newpath is relative, it is taken as relative to newdirfd.\n\ +If oldpath is relative and olddirfd is the special value AT_FDCWD, then\n\ +oldpath is interpreted relative to the current working directory. This\n\ +also applies for newpath."); + +static PyObject * +posix_renameat(PyObject *self, PyObject *args) +{ + int res; + PyObject *opathold, *opathnew; + char *opath, *npath; + int oldfd, newfd; + + if (!PyArg_ParseTuple(args, "iO&iO&:renameat", + &oldfd, PyUnicode_FSConverter, &opathold, &newfd, PyUnicode_FSConverter, &opathnew)) + return NULL; + opath = PyBytes_AsString(opathold); + npath = PyBytes_AsString(opathnew); + Py_BEGIN_ALLOW_THREADS + res = renameat(oldfd, opath, newfd, npath); + Py_END_ALLOW_THREADS + Py_DECREF(opathold); + Py_DECREF(opathnew); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -#ifdef _SC_XOPEN_XPG2 - {"SC_XOPEN_XPG2", _SC_XOPEN_XPG2}, + +#if HAVE_SYMLINKAT +PyDoc_STRVAR(posix_symlinkat__doc__, +"symlinkat(src, dstfd, dst)\n\n\ +Like symlink() but if dst is relative, it is taken as relative to dstfd.\n\ +If dst is relative and dstfd is the special value AT_FDCWD, then dst\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_symlinkat(PyObject *self, PyObject *args) +{ + int res, dstfd; + PyObject *osrc, *odst; + char *src, *dst; + + if (!PyArg_ParseTuple(args, "O&iO&:symlinkat", + PyUnicode_FSConverter, &osrc, &dstfd, PyUnicode_FSConverter, &odst)) + return NULL; + src = PyBytes_AsString(osrc); + dst = PyBytes_AsString(odst); + Py_BEGIN_ALLOW_THREADS + res = symlinkat(src, dstfd, dst); + Py_END_ALLOW_THREADS + Py_DECREF(osrc); + Py_DECREF(odst); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} +#endif /* HAVE_SYMLINKAT */ + +#ifdef HAVE_UNLINKAT +PyDoc_STRVAR(posix_unlinkat__doc__, +"unlinkat(dirfd, path, flags=0)\n\n\ +Like unlink() but if path is relative, it is taken as relative to dirfd.\n\ +flags is optional and may be 0 or AT_REMOVEDIR. If AT_REMOVEDIR is\n\ +specified, unlinkat() behaves like rmdir().\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_unlinkat(PyObject *self, PyObject *args) +{ + int dirfd, res, flags = 0; + PyObject *opath; + char *path; + + if (!PyArg_ParseTuple(args, "iO&|i:unlinkat", + &dirfd, PyUnicode_FSConverter, &opath, &flags)) + return NULL; + path = PyBytes_AsString(opath); + Py_BEGIN_ALLOW_THREADS + res = unlinkat(dirfd, path, flags); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -#ifdef _SC_XOPEN_XPG3 - {"SC_XOPEN_XPG3", _SC_XOPEN_XPG3}, + +#ifdef HAVE_UTIMENSAT +PyDoc_STRVAR(posix_utimensat__doc__, +"utimensat(dirfd, path[, atime=(atime_sec, atime_nsec),\n\ + mtime=(mtime_sec, mtime_nsec), flags=0])\n\ +utimensat(dirfd, path, None, None, flags)\n\n\ +Updates the timestamps of a file with nanosecond precision. If path is\n\ +relative, it is taken as relative to dirfd.\n\ +If atime and mtime are both None, which is the default, set atime and\n\ +mtime to the current time.\n\ +flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory.\n\ +If *_nsec is specified as UTIME_NOW, the timestamp is updated to the\n\ +current time.\n\ +If *_nsec is specified as UTIME_OMIT, the timestamp is not updated."); + +static PyObject * +posix_utimensat(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *opath; + char *path; + int res, dirfd, flags = 0; + PyObject *atime = Py_None; + PyObject *mtime = Py_None; + + static char *kwlist[] = {"dirfd", "path", "atime", "mtime", "flags", NULL}; + + struct timespec buf[2]; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO&|OOi:utimensat", kwlist, + &dirfd, PyUnicode_FSConverter, &opath, &atime, &mtime, &flags)) + return NULL; + path = PyBytes_AsString(opath); + if (atime == Py_None && mtime == Py_None) { + /* optional time values not given */ + Py_BEGIN_ALLOW_THREADS + res = utimensat(dirfd, path, NULL, flags); + Py_END_ALLOW_THREADS + } + else if (!PyTuple_Check(atime) || PyTuple_Size(atime) != 2) { + PyErr_SetString(PyExc_TypeError, + "utimensat() arg 3 must be a tuple (atime_sec, atime_nsec)"); + Py_DECREF(opath); + return NULL; + } + else if (!PyTuple_Check(mtime) || PyTuple_Size(mtime) != 2) { + PyErr_SetString(PyExc_TypeError, + "utimensat() arg 4 must be a tuple (mtime_sec, mtime_nsec)"); + Py_DECREF(opath); + return NULL; + } + else { + if (!PyArg_ParseTuple(atime, "ll:utimensat", + &(buf[0].tv_sec), &(buf[0].tv_nsec))) { + Py_DECREF(opath); + return NULL; + } + if (!PyArg_ParseTuple(mtime, "ll:utimensat", + &(buf[1].tv_sec), &(buf[1].tv_nsec))) { + Py_DECREF(opath); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + res = utimensat(dirfd, path, buf, flags); + Py_END_ALLOW_THREADS + } + Py_DECREF(opath); + if (res < 0) { + return posix_error(); + } + Py_RETURN_NONE; +} #endif -#ifdef _SC_XOPEN_XPG4 - {"SC_XOPEN_XPG4", _SC_XOPEN_XPG4}, + +#ifdef HAVE_MKFIFOAT +PyDoc_STRVAR(posix_mkfifoat__doc__, +"mkfifoat(dirfd, path, mode=0o666)\n\n\ +Like mkfifo() but if path is relative, it is taken as relative to dirfd.\n\ +If path is relative and dirfd is the special value AT_FDCWD, then path\n\ +is interpreted relative to the current working directory."); + +static PyObject * +posix_mkfifoat(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *filename; + int mode = 0666; + int res, dirfd; + if (!PyArg_ParseTuple(args, "iO&|i:mkfifoat", + &dirfd, PyUnicode_FSConverter, &opath, &mode)) + return NULL; + filename = PyBytes_AS_STRING(opath); + Py_BEGIN_ALLOW_THREADS + res = mkfifoat(dirfd, filename, mode); + Py_END_ALLOW_THREADS + Py_DECREF(opath); + if (res < 0) + return posix_error(); + Py_RETURN_NONE; +} #endif -}; + +#ifdef USE_XATTRS static int -conv_sysconf_confname(PyObject *arg, int *valuep) +try_getxattr(const char *path, const char *name, + ssize_t (*get)(const char *, const char *, void *, size_t), + Py_ssize_t buf_size, PyObject **res) { - return conv_confname(arg, valuep, posix_constants_sysconf, - sizeof(posix_constants_sysconf) - / sizeof(struct constdef)); + PyObject *value; + Py_ssize_t len; + + assert(buf_size <= XATTR_SIZE_MAX); + value = PyBytes_FromStringAndSize(NULL, buf_size); + if (!value) + return 0; + Py_BEGIN_ALLOW_THREADS; + len = get(path, name, PyBytes_AS_STRING(value), buf_size); + Py_END_ALLOW_THREADS; + if (len < 0) { + Py_DECREF(value); + if (errno == ERANGE) { + value = NULL; + } + else { + posix_error(); + return 0; + } + } + else if (len != buf_size) { + /* Can only shrink. */ + _PyBytes_Resize(&value, len); + } + *res = value; + return 1; } -PyDoc_STRVAR(posix_sysconf__doc__, -"sysconf(name) -> integer\n\n\ -Return an integer-valued system configuration variable."); +static PyObject * +getxattr_common(const char *path, PyObject *name_obj, + ssize_t (*get)(const char *, const char *, void *, size_t)) +{ + PyObject *value; + const char *name = PyBytes_AS_STRING(name_obj); + + /* Try a small value first. */ + if (!try_getxattr(path, name, get, 128, &value)) + return NULL; + if (value) + return value; + /* Now the maximum possible one. */ + if (!try_getxattr(path, name, get, XATTR_SIZE_MAX, &value)) + return NULL; + assert(value); + return value; +} + +PyDoc_STRVAR(posix_getxattr__doc__, +"getxattr(path, attr) -> value\n\n\ +Return the value of extended attribute *name* on *path*."); static PyObject * -posix_sysconf(PyObject *self, PyObject *args) +posix_getxattr(PyObject *self, PyObject *args) { - PyObject *result = NULL; - int name; + PyObject *path, *res, *name; - if (PyArg_ParseTuple(args, "O&:sysconf", conv_sysconf_confname, &name)) { - int value; + if (!PyArg_ParseTuple(args, "O&O&:getxattr", PyUnicode_FSConverter, &path, + PyUnicode_FSConverter, &name)) + return NULL; + res = getxattr_common(PyBytes_AS_STRING(path), name, getxattr); + Py_DECREF(path); + Py_DECREF(name); + return res; +} - errno = 0; - value = sysconf(name); - if (value == -1 && errno != 0) - posix_error(); - else - result = PyLong_FromLong(value); - } - return result; +PyDoc_STRVAR(posix_lgetxattr__doc__, +"lgetxattr(path, attr) -> value\n\n\ +Like getxattr but don't follow symlinks."); + +static PyObject * +posix_lgetxattr(PyObject *self, PyObject *args) +{ + PyObject *path, *res, *name; + + if (!PyArg_ParseTuple(args, "O&O&:lgetxattr", PyUnicode_FSConverter, &path, + PyUnicode_FSConverter, &name)) + return NULL; + res = getxattr_common(PyBytes_AS_STRING(path), name, lgetxattr); + Py_DECREF(path); + Py_DECREF(name); + return res; } -#endif +static ssize_t +wrap_fgetxattr(const char *path, const char *name, void *value, size_t size) +{ + /* Hack to share code. */ + return fgetxattr((int)(Py_uintptr_t)path, name, value, size); +} -/* This code is used to ensure that the tables of configuration value names - * are in sorted order as required by conv_confname(), and also to build the - * the exported dictionaries that are used to publish information about the - * names available on the host platform. - * - * Sorting the table at runtime ensures that the table is properly ordered - * when used, even for platforms we're not able to test on. It also makes - * it easier to add additional entries to the tables. - */ +PyDoc_STRVAR(posix_fgetxattr__doc__, +"fgetxattr(fd, attr) -> value\n\n\ +Like getxattr but operate on a fd instead of a path."); -static int -cmp_constdefs(const void *v1, const void *v2) +static PyObject * +posix_fgetxattr(PyObject *self, PyObject *args) { - const struct constdef *c1 = - (const struct constdef *) v1; - const struct constdef *c2 = - (const struct constdef *) v2; + PyObject *res, *name; + int fd; - return strcmp(c1->name, c2->name); + if (!PyArg_ParseTuple(args, "iO&:fgetxattr", &fd, PyUnicode_FSConverter, &name)) + return NULL; + res = getxattr_common((const char *)(Py_uintptr_t)fd, name, wrap_fgetxattr); + Py_DECREF(name); + return res; } -static int -setup_confname_table(struct constdef *table, size_t tablesize, - char *tablename, PyObject *module) +PyDoc_STRVAR(posix_setxattr__doc__, +"setxattr(path, attr, value, flags=0)\n\n\ +Set extended attribute *attr* on *path* to *value*."); + +static PyObject * +posix_setxattr(PyObject *self, PyObject *args) { - PyObject *d = NULL; - size_t i; + PyObject *path, *name; + Py_buffer data; + int flags = 0, err; - qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs); - d = PyDict_New(); - if (d == NULL) - return -1; + if (!PyArg_ParseTuple(args, "O&O&y*|i:setxattr", PyUnicode_FSConverter, + &path, PyUnicode_FSConverter, &name, &data, &flags)) + return NULL; + Py_BEGIN_ALLOW_THREADS; + err = setxattr(PyBytes_AS_STRING(path), PyBytes_AS_STRING(name), + data.buf, data.len, flags); + Py_END_ALLOW_THREADS; + Py_DECREF(path); + Py_DECREF(name); + PyBuffer_Release(&data); + if (err) + return posix_error(); + Py_RETURN_NONE; +} - for (i=0; i < tablesize; ++i) { - PyObject *o = PyLong_FromLong(table[i].value); - if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) { - Py_XDECREF(o); - Py_DECREF(d); - return -1; - } - Py_DECREF(o); - } - return PyModule_AddObject(module, tablename, d); +PyDoc_STRVAR(posix_lsetxattr__doc__, +"lsetxattr(path, attr, value, flags=0)\n\n\ +Like setxattr but don't follow symlinks."); + +static PyObject * +posix_lsetxattr(PyObject *self, PyObject *args) +{ + PyObject *path, *name; + Py_buffer data; + int flags = 0, err; + + if (!PyArg_ParseTuple(args, "O&O&y*|i:lsetxattr", PyUnicode_FSConverter, + &path, PyUnicode_FSConverter, &name, &data, &flags)) + return NULL; + Py_BEGIN_ALLOW_THREADS; + err = lsetxattr(PyBytes_AS_STRING(path), PyBytes_AS_STRING(name), + data.buf, data.len, flags); + Py_END_ALLOW_THREADS; + Py_DECREF(path); + Py_DECREF(name); + PyBuffer_Release(&data); + if (err) + return posix_error(); + Py_RETURN_NONE; } -/* Return -1 on failure, 0 on success. */ -static int -setup_confname_tables(PyObject *module) +PyDoc_STRVAR(posix_fsetxattr__doc__, +"fsetxattr(fd, attr, value, flags=0)\n\n\ +Like setxattr but operates on *fd* instead of a path."); + +static PyObject * +posix_fsetxattr(PyObject *self, PyObject *args) { -#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF) - if (setup_confname_table(posix_constants_pathconf, - sizeof(posix_constants_pathconf) - / sizeof(struct constdef), - "pathconf_names", module)) - return -1; -#endif -#ifdef HAVE_CONFSTR - if (setup_confname_table(posix_constants_confstr, - sizeof(posix_constants_confstr) - / sizeof(struct constdef), - "confstr_names", module)) - return -1; -#endif -#ifdef HAVE_SYSCONF - if (setup_confname_table(posix_constants_sysconf, - sizeof(posix_constants_sysconf) - / sizeof(struct constdef), - "sysconf_names", module)) - return -1; -#endif - return 0; + Py_buffer data; + const char *name; + int fd, flags = 0, err; + + if (!PyArg_ParseTuple(args, "iO&y*|i:fsetxattr", &fd, PyUnicode_FSConverter, + &name, &data, &flags)) + return NULL; + Py_BEGIN_ALLOW_THREADS; + err = fsetxattr(fd, PyBytes_AS_STRING(name), data.buf, data.len, flags); + Py_END_ALLOW_THREADS; + Py_DECREF(name); + PyBuffer_Release(&data); + if (err) + return posix_error(); + Py_RETURN_NONE; } +PyDoc_STRVAR(posix_removexattr__doc__, +"removexattr(path, attr)\n\n\ +Remove extended attribute *attr* on *path*."); -PyDoc_STRVAR(posix_abort__doc__, -"abort() -> does not return!\n\n\ -Abort the interpreter immediately. This 'dumps core' or otherwise fails\n\ -in the hardest way possible on the hosting operating system."); +static PyObject * +posix_removexattr(PyObject *self, PyObject *args) +{ + PyObject *path, *name; + int err; + + if (!PyArg_ParseTuple(args, "O&O&:removexattr", PyUnicode_FSConverter, &path, + PyUnicode_FSConverter, &name)) + return NULL; + Py_BEGIN_ALLOW_THREADS; + err = removexattr(PyBytes_AS_STRING(path), PyBytes_AS_STRING(name)); + Py_END_ALLOW_THREADS; + Py_DECREF(path); + Py_DECREF(name); + if (err) + return posix_error(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(posix_lremovexattr__doc__, +"lremovexattr(path, attr)\n\n\ +Like removexattr but don't follow symlinks."); static PyObject * -posix_abort(PyObject *self, PyObject *noargs) +posix_lremovexattr(PyObject *self, PyObject *args) { - abort(); - /*NOTREACHED*/ - Py_FatalError("abort() called from Python code didn't abort!"); - return NULL; + PyObject *path, *name; + int err; + + if (!PyArg_ParseTuple(args, "O&O&:lremovexattr", PyUnicode_FSConverter, &path, + PyUnicode_FSConverter, &name)) + return NULL; + Py_BEGIN_ALLOW_THREADS; + err = lremovexattr(PyBytes_AS_STRING(path), PyBytes_AS_STRING(name)); + Py_END_ALLOW_THREADS; + Py_DECREF(path); + Py_DECREF(name); + if (err) + return posix_error(); + Py_RETURN_NONE; } -#ifdef MS_WINDOWS -PyDoc_STRVAR(win32_startfile__doc__, -"startfile(filepath [, operation]) - Start a file with its associated\n\ -application.\n\ -\n\ -When \"operation\" is not specified or \"open\", this acts like\n\ -double-clicking the file in Explorer, or giving the file name as an\n\ -argument to the DOS \"start\" command: the file is opened with whatever\n\ -application (if any) its extension is associated.\n\ -When another \"operation\" is given, it specifies what should be done with\n\ -the file. A typical operation is \"print\".\n\ -\n\ -startfile returns as soon as the associated application is launched.\n\ -There is no option to wait for the application to close, and no way\n\ -to retrieve the application's exit status.\n\ -\n\ -The filepath is relative to the current directory. If you want to use\n\ -an absolute path, make sure the first character is not a slash (\"/\");\n\ -the underlying Win32 ShellExecute function doesn't work if it is."); +PyDoc_STRVAR(posix_fremovexattr__doc__, +"fremovexattr(fd, attr)\n\n\ +Like removexattr but operates on a file descriptor."); static PyObject * -win32_startfile(PyObject *self, PyObject *args) +posix_fremovexattr(PyObject *self, PyObject *args) { - PyObject *ofilepath; - char *filepath; - char *operation = NULL; - HINSTANCE rc; + PyObject *name; + int fd, err; - PyObject *unipath, *woperation = NULL; - if (!PyArg_ParseTuple(args, "U|s:startfile", - &unipath, &operation)) { - PyErr_Clear(); - goto normal; - } + if (!PyArg_ParseTuple(args, "iO&:fremovexattr", &fd, + PyUnicode_FSConverter, &name)) + return NULL; + Py_BEGIN_ALLOW_THREADS; + err = fremovexattr(fd, PyBytes_AS_STRING(name)); + Py_END_ALLOW_THREADS; + Py_DECREF(name); + if (err) + return posix_error(); + Py_RETURN_NONE; +} - if (operation) { - woperation = PyUnicode_DecodeASCII(operation, - strlen(operation), NULL); - if (!woperation) { - PyErr_Clear(); - operation = NULL; - goto normal; - } +static Py_ssize_t +try_listxattr(const char *path, ssize_t (*list)(const char *, char *, size_t), + Py_ssize_t buf_size, char **buf) +{ + Py_ssize_t len; + + *buf = PyMem_MALLOC(buf_size); + if (!*buf) { + PyErr_NoMemory(); + return -1; + } + Py_BEGIN_ALLOW_THREADS; + len = list(path, *buf, buf_size); + Py_END_ALLOW_THREADS; + if (len < 0) { + PyMem_FREE(*buf); + if (errno != ERANGE) + posix_error(); + return -1; } + return len; +} - Py_BEGIN_ALLOW_THREADS - rc = ShellExecuteW((HWND)0, woperation ? PyUnicode_AS_UNICODE(woperation) : 0, - PyUnicode_AS_UNICODE(unipath), - NULL, NULL, SW_SHOWNORMAL); - Py_END_ALLOW_THREADS +static PyObject * +listxattr_common(const char *path, ssize_t (*list)(const char *, char *, size_t)) +{ + PyObject *res, *attr; + Py_ssize_t len, err, start, i; + char *buf; - Py_XDECREF(woperation); - if (rc <= (HINSTANCE)32) { - PyObject *errval = win32_error_unicode("startfile", - PyUnicode_AS_UNICODE(unipath)); - return errval; + len = try_listxattr(path, list, 256, &buf); + if (len < 0) { + if (PyErr_Occurred()) + return NULL; + len = try_listxattr(path, list, XATTR_LIST_MAX, &buf); + if (len < 0) + return NULL; } - Py_INCREF(Py_None); - return Py_None; + res = PyList_New(0); + if (!res) { + PyMem_FREE(buf); + return NULL; + } + for (start = i = 0; i < len; i++) { + if (!buf[i]) { + attr = PyUnicode_DecodeFSDefaultAndSize(&buf[start], i - start); + if (!attr) { + Py_DECREF(res); + PyMem_FREE(buf); + return NULL; + } + err = PyList_Append(res, attr); + Py_DECREF(attr); + if (err) { + Py_DECREF(res); + PyMem_FREE(buf); + return NULL; + } + start = i + 1; + } + } + PyMem_FREE(buf); + return res; +} -normal: - if (!PyArg_ParseTuple(args, "O&|s:startfile", - PyUnicode_FSConverter, &ofilepath, - &operation)) +PyDoc_STRVAR(posix_listxattr__doc__, +"listxattr(path)\n\n\ +Return a list of extended attributes on *path*."); + +static PyObject * +posix_listxattr(PyObject *self, PyObject *args) +{ + PyObject *path, *res; + + if (!PyArg_ParseTuple(args, "O&:listxattr", PyUnicode_FSConverter, &path)) return NULL; - filepath = PyBytes_AsString(ofilepath); - Py_BEGIN_ALLOW_THREADS - rc = ShellExecute((HWND)0, operation, filepath, - NULL, NULL, SW_SHOWNORMAL); - Py_END_ALLOW_THREADS - if (rc <= (HINSTANCE)32) { - PyObject *errval = win32_error("startfile", filepath); - Py_DECREF(ofilepath); - return errval; - } - Py_DECREF(ofilepath); - Py_INCREF(Py_None); - return Py_None; + res = listxattr_common(PyBytes_AS_STRING(path), listxattr); + Py_DECREF(path); + return res; } -#endif -#ifdef HAVE_GETLOADAVG -PyDoc_STRVAR(posix_getloadavg__doc__, -"getloadavg() -> (float, float, float)\n\n\ -Return the number of processes in the system run queue averaged over\n\ -the last 1, 5, and 15 minutes or raises OSError if the load average\n\ -was unobtainable"); +PyDoc_STRVAR(posix_llistxattr__doc__, +"llistxattr(path)\n\n\ +Like listxattr but don't follow symlinks.."); static PyObject * -posix_getloadavg(PyObject *self, PyObject *noargs) +posix_llistxattr(PyObject *self, PyObject *args) { - double loadavg[3]; - if (getloadavg(loadavg, 3)!=3) { - PyErr_SetString(PyExc_OSError, "Load averages are unobtainable"); + PyObject *path, *res; + + if (!PyArg_ParseTuple(args, "O&:llistxattr", PyUnicode_FSConverter, &path)) return NULL; - } else - return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]); + res = listxattr_common(PyBytes_AS_STRING(path), llistxattr); + Py_DECREF(path); + return res; } -#endif -PyDoc_STRVAR(device_encoding__doc__, -"device_encoding(fd) -> str\n\n\ -Return a string describing the encoding of the device\n\ -if the output is a terminal; else return None."); +static ssize_t +wrap_flistxattr(const char *path, char *buf, size_t len) +{ + /* Hack to share code. */ + return flistxattr((int)(Py_uintptr_t)path, buf, len); +} + +PyDoc_STRVAR(posix_flistxattr__doc__, +"flistxattr(path)\n\n\ +Like flistxattr but operates on a file descriptor."); static PyObject * -device_encoding(PyObject *self, PyObject *args) +posix_flistxattr(PyObject *self, PyObject *args) { - int fd; - if (!PyArg_ParseTuple(args, "i:device_encoding", &fd)) + long fd; + + if (!PyArg_ParseTuple(args, "i:flistxattr", &fd)) return NULL; - if (!_PyVerify_fd(fd) || !isatty(fd)) { - Py_INCREF(Py_None); - return Py_None; - } -#if defined(MS_WINDOWS) || defined(MS_WIN64) - if (fd == 0) { - char buf[100]; - sprintf(buf, "cp%d", GetConsoleCP()); - return PyUnicode_FromString(buf); - } - if (fd == 1 || fd == 2) { - char buf[100]; - sprintf(buf, "cp%d", GetConsoleOutputCP()); - return PyUnicode_FromString(buf); - } -#elif defined(CODESET) - { - char *codeset = nl_langinfo(CODESET); - if (codeset != NULL && codeset[0] != 0) - return PyUnicode_FromString(codeset); - } -#endif - Py_INCREF(Py_None); - return Py_None; + return listxattr_common((const char *)(Py_uintptr_t)fd, wrap_flistxattr); } +#endif /* USE_XATTRS */ + + + PyDoc_STRVAR(posix_urandom__doc__, + "urandom(n) -> str\n\n\ + Return n random bytes suitable for cryptographic use."); + + static PyObject * + posix_urandom(PyObject *self, PyObject *args) + { + Py_ssize_t size; + PyObject *result; + int ret; + + /* Read arguments */ + if (!PyArg_ParseTuple(args, "n:urandom", &size)) + return NULL; + if (size < 0) + return PyErr_Format(PyExc_ValueError, + "negative argument not allowed"); + result = PyBytes_FromStringAndSize(NULL, size); + if (result == NULL) + return NULL; + + ret = _PyOS_URandom(PyBytes_AS_STRING(result), + PyBytes_GET_SIZE(result)); + if (ret == -1) { + Py_DECREF(result); + return NULL; + } + return result; + } + -#ifdef HAVE_SETRESUID -PyDoc_STRVAR(posix_setresuid__doc__, -"setresuid(ruid, euid, suid)\n\n\ -Set the current process's real, effective, and saved user ids."); +/* Terminal size querying */ -static PyObject* -posix_setresuid (PyObject *self, PyObject *args) -{ - /* We assume uid_t is no larger than a long. */ - long ruid, euid, suid; - if (!PyArg_ParseTuple(args, "lll", &ruid, &euid, &suid)) - return NULL; - if (setresuid(ruid, euid, suid) < 0) - return posix_error(); - Py_RETURN_NONE; -} -#endif +static PyTypeObject TerminalSizeType; -#ifdef HAVE_SETRESGID -PyDoc_STRVAR(posix_setresgid__doc__, -"setresgid(rgid, egid, sgid)\n\n\ -Set the current process's real, effective, and saved group ids."); +PyDoc_STRVAR(TerminalSize_docstring, + "A tuple of (columns, lines) for holding terminal window size"); + +static PyStructSequence_Field TerminalSize_fields[] = { + {"columns", "width of the terminal window in characters"}, + {"lines", "height of the terminal window in characters"}, + {NULL, NULL} +}; + +static PyStructSequence_Desc TerminalSize_desc = { + "os.terminal_size", + TerminalSize_docstring, + TerminalSize_fields, + 2, +}; + +#if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) +PyDoc_STRVAR(termsize__doc__, + "Return the size of the terminal window as (columns, lines).\n" \ + "\n" \ + "The optional argument fd (default standard output) specifies\n" \ + "which file descriptor should be queried.\n" \ + "\n" \ + "If the file descriptor is not connected to a terminal, an OSError\n" \ + "is thrown.\n" \ + "\n" \ + "This function will only be defined if an implementation is\n" \ + "available for this system.\n" \ + "\n" \ + "shutil.get_terminal_size is the high-level function which should \n" \ + "normally be used, os.get_terminal_size is the low-level implementation."); static PyObject* -posix_setresgid (PyObject *self, PyObject *args) +get_terminal_size(PyObject *self, PyObject *args) { - /* We assume uid_t is no larger than a long. */ - long rgid, egid, sgid; - if (!PyArg_ParseTuple(args, "lll", &rgid, &egid, &sgid)) + int columns, lines; + PyObject *termsize; + + int fd = fileno(stdout); + /* Under some conditions stdout may not be connected and + * fileno(stdout) may point to an invalid file descriptor. For example + * GUI apps don't have valid standard streams by default. + * + * If this happens, and the optional fd argument is not present, + * the ioctl below will fail returning EBADF. This is what we want. + */ + + if (!PyArg_ParseTuple(args, "|i", &fd)) return NULL; - if (setresgid(rgid, egid, sgid) < 0) - return posix_error(); - Py_RETURN_NONE; -} -#endif -#ifdef HAVE_GETRESUID -PyDoc_STRVAR(posix_getresuid__doc__, -"getresuid() -> (ruid, euid, suid)\n\n\ -Get tuple of the current process's real, effective, and saved user ids."); +#ifdef TERMSIZE_USE_IOCTL + { + struct winsize w; + if (ioctl(fd, TIOCGWINSZ, &w)) + return PyErr_SetFromErrno(PyExc_OSError); + columns = w.ws_col; + lines = w.ws_row; + } +#endif /* TERMSIZE_USE_IOCTL */ -static PyObject* -posix_getresuid (PyObject *self, PyObject *noargs) -{ - uid_t ruid, euid, suid; - long l_ruid, l_euid, l_suid; - if (getresuid(&ruid, &euid, &suid) < 0) - return posix_error(); - /* Force the values into long's as we don't know the size of uid_t. */ - l_ruid = ruid; - l_euid = euid; - l_suid = suid; - return Py_BuildValue("(lll)", l_ruid, l_euid, l_suid); -} -#endif +#ifdef TERMSIZE_USE_CONIO + { + DWORD nhandle; + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO csbi; + switch (fd) { + case 0: nhandle = STD_INPUT_HANDLE; + break; + case 1: nhandle = STD_OUTPUT_HANDLE; + break; + case 2: nhandle = STD_ERROR_HANDLE; + break; + default: + return PyErr_Format(PyExc_ValueError, "bad file descriptor"); + } + handle = GetStdHandle(nhandle); + if (handle == NULL) + return PyErr_Format(PyExc_OSError, "handle cannot be retrieved"); + if (handle == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(0); -#ifdef HAVE_GETRESGID -PyDoc_STRVAR(posix_getresgid__doc__, -"getresgid() -> (rgid, egid, sgid)\n\n\ -Get tuple of the current process's real, effective, and saved group ids."); + if (!GetConsoleScreenBufferInfo(handle, &csbi)) + return PyErr_SetFromWindowsErr(0); -static PyObject* -posix_getresgid (PyObject *self, PyObject *noargs) -{ - uid_t rgid, egid, sgid; - long l_rgid, l_egid, l_sgid; - if (getresgid(&rgid, &egid, &sgid) < 0) - return posix_error(); - /* Force the values into long's as we don't know the size of uid_t. */ - l_rgid = rgid; - l_egid = egid; - l_sgid = sgid; - return Py_BuildValue("(lll)", l_rgid, l_egid, l_sgid); + columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; + lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + } +#endif /* TERMSIZE_USE_CONIO */ + + termsize = PyStructSequence_New(&TerminalSizeType); + if (termsize == NULL) + return NULL; + PyStructSequence_SET_ITEM(termsize, 0, PyLong_FromLong(columns)); + PyStructSequence_SET_ITEM(termsize, 1, PyLong_FromLong(lines)); + if (PyErr_Occurred()) { + Py_DECREF(termsize); + return NULL; + } + return termsize; } -#endif +#endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */ + static PyMethodDef posix_methods[] = { {"access", posix_access, METH_VARARGS, posix_access__doc__}, diff --cc Objects/object.c index 81348258a4,84ec2f34f5..bb18d47191 --- a/Objects/object.c +++ b/Objects/object.c @@@ -753,21 -746,6 +753,30 @@@ _Py_HashPointer(void *p return x; } +Py_hash_t +_Py_HashBytes(unsigned char *p, Py_ssize_t len) +{ + Py_uhash_t x; + Py_ssize_t i; + - x = (Py_uhash_t) *p << 7; ++ /* ++ We make the hash of the empty string be 0, rather than using ++ (prefix ^ suffix), since this slightly obfuscates the hash secret ++ */ ++ if (len == 0) { ++ return 0; ++ } ++ x = (Py_uhash_t) _Py_HashSecret.prefix; ++ x ^= (Py_uhash_t) *p << 7; + for (i = 0; i < len; i++) + x = (_PyHASH_MULTIPLIER * x) ^ (Py_uhash_t) *p++; + x ^= (Py_uhash_t) len; ++ x ^= (Py_uhash_t) _Py_HashSecret.suffix; + if (x == -1) + x = -2; + return x; +} + Py_hash_t PyObject_HashNotImplemented(PyObject *v) { diff --cc Objects/unicodeobject.c index 07d3eb8569,467f95c444..716ca3f26a --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@@ -11207,53 -7665,37 +11207,55 @@@ unicode_getitem(PyObject *self, Py_ssiz } /* Believe it or not, this produces the same value for ASCII strings - as string_hash(). */ + as bytes_hash(). */ static Py_hash_t -unicode_hash(PyUnicodeObject *self) +unicode_hash(PyObject *self) { Py_ssize_t len; - Py_UNICODE *p; - Py_hash_t x; - - if (self->hash != -1) - return self->hash; - len = Py_SIZE(self); - /* - We make the hash of the empty string be 0, rather than using - (prefix ^ suffix), since this slightly obfuscates the hash secret - */ - if (len == 0) { - self->hash = 0; - return 0; + Py_uhash_t x; + + if (_PyUnicode_HASH(self) != -1) + return _PyUnicode_HASH(self); + if (PyUnicode_READY(self) == -1) + return -1; + len = PyUnicode_GET_LENGTH(self); + + /* The hash function as a macro, gets expanded three times below. */ - #define HASH(P) \ - x = (Py_uhash_t)*P << 7; \ - while (--len >= 0) \ - x = (_PyHASH_MULTIPLIER*x) ^ (Py_uhash_t)*P++; ++#define HASH(P) \ ++ x ^= (Py_uhash_t) *P << 7; \ ++ while (--len >= 0) \ ++ x = (_PyHASH_MULTIPLIER * x) ^ (Py_uhash_t) *P++; \ + ++ x = (Py_uhash_t) _Py_HashSecret.prefix; + switch (PyUnicode_KIND(self)) { + case PyUnicode_1BYTE_KIND: { + const unsigned char *c = PyUnicode_1BYTE_DATA(self); + HASH(c); + break; + } + case PyUnicode_2BYTE_KIND: { + const Py_UCS2 *s = PyUnicode_2BYTE_DATA(self); + HASH(s); + break; } - p = self->str; - x = _Py_HashSecret.prefix; - x ^= *p << 7; - while (--len >= 0) - x = (_PyHASH_MULTIPLIER*x) ^ *p++; - x ^= Py_SIZE(self); - x ^= _Py_HashSecret.suffix; + default: { + Py_UCS4 *l; + assert(PyUnicode_KIND(self) == PyUnicode_4BYTE_KIND && + "Impossible switch case in unicode_hash"); + l = PyUnicode_4BYTE_DATA(self); + HASH(l); + break; + } + } - x ^= (Py_uhash_t)PyUnicode_GET_LENGTH(self); ++ x ^= (Py_uhash_t) PyUnicode_GET_LENGTH(self); ++ x ^= (Py_uhash_t) _Py_HashSecret.suffix; + if (x == -1) x = -2; - self->hash = x; + _PyUnicode_HASH(self) = x; return x; } +#undef HASH PyDoc_STRVAR(index__doc__, "S.index(sub[, start[, end]]) -> int\n\ diff --cc Python/pythonrun.c index 44b817f546,718362d479..54d39a5a91 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@@ -71,8 -70,7 +71,9 @@@ extern int _PyUnicode_Init(void) extern void _PyUnicode_Fini(void); extern int _PyLong_Init(void); extern void PyLong_Fini(void); +extern int _PyFaulthandler_Init(void); +extern void _PyFaulthandler_Fini(void); + extern void _PyRandom_Init(void); #ifdef WITH_THREAD extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); diff --cc Python/sysmodule.c index 955219f228,c4f27d0868..c434b5a81e --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@@ -1340,9 -1377,9 +1341,9 @@@ static PyStructSequence_Desc flags_des flags__doc__, /* doc */ flags_fields, /* fields */ #ifdef RISCOS - 12 - 14 -#else + 13 +#else - 11 ++ 12 #endif }; diff --cc Tools/scripts/run_tests.py index f750e192a0,0000000000..fb7ce5c07c mode 100755,000000..100755 --- a/Tools/scripts/run_tests.py +++ b/Tools/scripts/run_tests.py @@@ -1,47 -1,0 +1,48 @@@ +"""Run Python's test suite in a fast, rigorous way. + +The defaults are meant to be reasonably thorough, while skipping certain +tests that can be time-consuming or resource-intensive (e.g. largefile), +or distracting (e.g. audio and gui). These defaults can be overridden by +simply passing a -u option to this script. + +""" + +import os +import sys +import test.support + + +def is_multiprocess_flag(arg): + return arg.startswith('-j') or arg.startswith('--multiprocess') + + +def is_resource_use_flag(arg): + return arg.startswith('-u') or arg.startswith('--use') + + +def main(regrtest_args): + args = [sys.executable, + '-W', 'default', # Warnings set to 'default' + '-bb', # Warnings about bytes/bytearray + '-E', # Ignore environment variables ++ '-R', # Randomize hashing + ] + # Allow user-specified interpreter options to override our defaults. + args.extend(test.support.args_from_interpreter_flags()) + args.extend(['-m', 'test', # Run the test suite + '-r', # Randomize test order + '-w', # Re-run failed tests in verbose mode + ]) + if sys.platform == 'win32': + args.append('-n') # Silence alerts under Windows + if not any(is_multiprocess_flag(arg) for arg in regrtest_args): + args.extend(['-j', '0']) # Use all CPU cores + if not any(is_resource_use_flag(arg) for arg in regrtest_args): + args.extend(['-u', 'all,-largefile,-audio,-gui']) + args.extend(regrtest_args) + print(' '.join(args)) + os.execv(sys.executable, args) + + +if __name__ == '__main__': + main(sys.argv[1:])