]> granicus.if.org Git - python/commitdiff
Merge 3.2: Issue #13703 plus some related test suite fixes.
authorGeorg Brandl <georg@python.org>
Mon, 20 Feb 2012 23:33:36 +0000 (00:33 +0100)
committerGeorg Brandl <georg@python.org>
Mon, 20 Feb 2012 23:33:36 +0000 (00:33 +0100)
30 files changed:
1  2 
Doc/library/sys.rst
Doc/reference/datamodel.rst
Doc/using/cmdline.rst
Include/object.h
Include/pydebug.h
Include/pythonrun.h
Lib/os.py
Lib/test/datetimetester.py
Lib/test/script_helper.py
Lib/test/support.py
Lib/test/test_cmd_line.py
Lib/test/test_dis.py
Lib/test/test_gdb.py
Lib/test/test_hash.py
Lib/test/test_os.py
Lib/test/test_strlit.py
Lib/test/test_subprocess.py
Lib/test/test_sys.py
Lib/test/test_urllib.py
Makefile.pre.in
Misc/NEWS
Misc/python.man
Modules/main.c
Modules/posixmodule.c
Objects/object.c
Objects/unicodeobject.c
PCbuild/pythoncore.vcproj
Python/pythonrun.c
Python/sysmodule.c
Tools/scripts/run_tests.py

index c2b7423e0c341863a35fee3fa60353a855358f6a,063e0a52c081d45c2b6ad4ceb9fce81ec305fa43..3af43543c4094898a69b02f1d833465b15894729
@@@ -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
  
Simple merge
Simple merge
index 844ff9f14a871bd431d0b6292c3c48bef06dea75,a54c400774800b5a3c277fff2dbaffb944941f82..c69becec51a1c999952a342c33194fa14b9430c4
@@@ -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))
  
Simple merge
Simple merge
diff --cc Lib/os.py
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index c5dbb95629ca4d514a5ffc3f4814726feac0b29c,8bc8ba9fa625e0e3e9be7e3a08da3e9c36e6f200..a0f13fd790b0bd6183d00b0f25e278b035ce8324
@@@ -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
Simple merge
Simple merge
index f065bf72e6cf59513d2a78373feb81a10b4b2649,3268b1a141c8dea16d07cc55dce112ce40f96a47..bf22df2269f5bf896d5dbb6a1c77cc9fd965a982
@@@ -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)
Simple merge
diff --cc Makefile.pre.in
Simple merge
diff --cc Misc/NEWS
index 6e010b7a2f0a54c9867d598f44e011807e58b76b,0e3595a221257c73c86ab5bd28bf5719adcbdc15..1a6ce289fd3918d489e890bf27fb318cca986e6d
+++ 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 eaa3ec7646813d2917ca6c1836f50a650576a123,fc3566fcacce49876e876a6a0a809ee5d2dda6a8..ef42c4ef94b04ce97e5bffb6913fd4e14af643cf
@@@ -37,6 -37,13 +37,9 @@@ python \- an interpreted, interactive, 
  .B \-OO
  ]
  [
 -.B -Q
 -.I argument
 -]
 -[
+ .B \-R
+ ]
+ [
  .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
 -.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 \-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
  .B \-s
  Don't add user site directory to sys.path.
  .TP
diff --cc Modules/main.c
index d8c5172108513724fb0c5f0bfe18413424e89b11,ed84aa028604600dc8c3cc59cf088d752dcc89c6..a820a9eb44e184b619d083bf21cfddc81b329ce3
@@@ -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)
index 0553c761bd306c33942be6eddca30ce01899996a,9f57673fbe42a2a26bacb4d5edd9d4b5c525d049..dbace1a8911ffdf2e788451a4a55064b33dd9af7
@@@ -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);
  }
  
 -#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.");
 +#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;
+ }
 +/* 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__},
index 81348258a4a091d0d2c3761e79e0d641584cfbc4,84ec2f34f582ea623dbb4759ec9440844aefd08c..bb18d471912f719e141437d21b63c7170a8b6fae
@@@ -753,21 -746,6 +753,30 @@@ _Py_HashPointer(void *p
      return x;
  }
  
-     x = (Py_uhash_t) *p << 7;
 +Py_hash_t
 +_Py_HashBytes(unsigned char *p, Py_ssize_t len)
 +{
 +    Py_uhash_t x;
 +    Py_ssize_t i;
 +
++    /*
++      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)
  {
index 07d3eb85696194f288c1b54f7bc0159aa1d87f08,467f95c444f5ddf58531b03f0d86d81293eb3555..716ca3f26a435cd8225ad05adef52204bfd06b67
@@@ -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\
Simple merge
index 44b817f5468b3f2cc54d52498bfd4fdc2093f673,718362d479229c56e9abe221bdb25e9137768823..54d39a5a91f37fb84de0317d9cbe60bc2280a00e
@@@ -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 *);
index 955219f22888551e5cf9f86a1b4c7bfe89c3238b,c4f27d0868772874456344be0635f078be32a090..c434b5a81eb30081f73e6e17137e5da35e48507e
@@@ -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
  };
  
index f750e192a0ead1d4ce25b8391987b31b0c5877cc,0000000000000000000000000000000000000000..fb7ce5c07cbf5bdcd6280d517729011111b77329
mode 100755,000000..100755
--- /dev/null
@@@ -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:])