summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/codecs.rst9
-rw-r--r--Doc/library/os.rst153
-rw-r--r--Include/descrobject.h1
-rw-r--r--Lib/idlelib/PyShell.py35
-rw-r--r--Lib/idlelib/ScriptBinding.py33
-rw-r--r--Lib/subprocess.py56
-rw-r--r--Lib/test/test_exceptions.py8
-rw-r--r--Lib/test/test_faulthandler.py3
-rw-r--r--Lib/test/test_os.py94
-rw-r--r--Misc/NEWS11
-rw-r--r--Modules/posixmodule.c402
-rw-r--r--Objects/descrobject.c9
-rw-r--r--Objects/object.c3
-rw-r--r--PC/errmap.h1
-rw-r--r--PC/generrmap.c21
-rw-r--r--Python/import.c2
-rwxr-xr-xconfigure2
-rw-r--r--configure.in2
-rw-r--r--pyconfig.h.in3
19 files changed, 765 insertions, 83 deletions
diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst
index 90bd0dd..84593f2 100644
--- a/Doc/library/codecs.rst
+++ b/Doc/library/codecs.rst
@@ -840,7 +840,7 @@ There's another encoding that is able to encoding the full range of Unicode
characters: UTF-8. UTF-8 is an 8-bit encoding, which means there are no issues
with byte order in UTF-8. Each byte in a UTF-8 byte sequence consists of two
parts: Marker bits (the most significant bits) and payload bits. The marker bits
-are a sequence of zero to six 1 bits followed by a 0 bit. Unicode characters are
+are a sequence of zero to four ``1`` bits followed by a ``0`` bit. Unicode characters are
encoded like this (with x being payload bits, which when concatenated give the
Unicode character):
@@ -853,12 +853,7 @@ Unicode character):
+-----------------------------------+----------------------------------------------+
| ``U-00000800`` ... ``U-0000FFFF`` | 1110xxxx 10xxxxxx 10xxxxxx |
+-----------------------------------+----------------------------------------------+
-| ``U-00010000`` ... ``U-001FFFFF`` | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
-+-----------------------------------+----------------------------------------------+
-| ``U-00200000`` ... ``U-03FFFFFF`` | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
-+-----------------------------------+----------------------------------------------+
-| ``U-04000000`` ... ``U-7FFFFFFF`` | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
-| | 10xxxxxx |
+| ``U-00010000`` ... ``U-0010FFFF`` | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
+-----------------------------------+----------------------------------------------+
The least significant bit of the Unicode character is the rightmost x bit.
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 0c5c40c..636ac24 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -29,11 +29,6 @@ Notes on the availability of these functions:
objects, and result in an object of the same type, if a path or file name is
returned.
-.. note::
-
- If not separately noted, all functions that claim "Availability: Unix" are
- supported on Mac OS X, which builds on a Unix core.
-
* An "Availability: Unix" note means that this function is commonly found on
Unix systems. It does not make any claims about its existence on a specific
operating system.
@@ -751,6 +746,26 @@ as internal buffering of data.
This function is not available on MacOS.
+.. function:: fgetxattr(fd, attr)
+
+ This works exactly like :func:`getxattr` but operates on a file descriptor,
+ *fd*, instead of a path.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
+.. function:: flistxattr(fd)
+
+ This is exactly like :func:`listxattr` but operates on a file descriptor,
+ *fd*, instead of a path.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
.. function:: fdlistdir(fd)
Like :func:`listdir`, but uses a file descriptor instead and always returns
@@ -836,6 +851,27 @@ as internal buffering of data.
Availability: Unix.
+.. function:: fremovexattr(fd, attr)
+
+ This works exactly like :func:`removexattr` but operates on a file
+ descriptor, *fd*, instead of a path.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
+.. function:: fsetxattr(fd, attr, value, flags=0)
+
+ This works exactly like :func:`setxattr` but on a file descriptor, *fd*,
+ instead of a path.
+
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
.. function:: futimesat(dirfd, path, (atime, mtime))
futimesat(dirfd, path, None)
@@ -1536,6 +1572,17 @@ Files and Directories
Availability: Unix.
+.. function:: getxattr(path, attr)
+
+ Return the value of the extended filesystem attribute *attr* for
+ *path*. *attr* can be bytes or str. If it is str, it is encoded with the
+ filesystem encoding.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
.. function:: lchflags(path, flags)
Set the flags of *path* to the numeric *flags*, like :func:`chflags`, but do not
@@ -1561,6 +1608,15 @@ Files and Directories
Availability: Unix.
+.. function:: lgetxattr(path, attr)
+
+ This works exactly like :func:`getxattr` but doesn't follow symlinks.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
.. function:: link(source, link_name)
Create a hard link pointing to *source* named *link_name*.
@@ -1585,6 +1641,44 @@ Files and Directories
.. versionchanged:: 3.2
The *path* parameter became optional.
+
+.. function:: listxattr(path)
+
+ Return a list of the extended filesystem attributes on *path*. Attributes are
+ returned as string decoded with the filesystem encoding.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
+.. function:: llistxattr(path)
+
+ This works exactly like :func:`listxattr` but doesn't follow symlinks.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
+.. function:: lremoveattr(path, attr)
+
+ This works exactly like :func:`removeattr` but doesn't follow symlinks.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
+.. function:: lsetxattr(path, attr, value, flags=0)
+
+ This works exactly like :func:`setxattr` but doesn't follow symlinks.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
.. function:: lstat(path)
Perform the equivalent of an :c:func:`lstat` system call on the given path.
@@ -1758,6 +1852,17 @@ Files and Directories
successfully removed.
+.. function:: removexattr(path, attr)
+
+ Removes the extended filesystem attribute *attr* from *path*. *attr* should
+ be bytes or str. If it is a string, it is encoded with the filesystem
+ encoding.
+
+ Availability: Linux
+
+ .. versionadded:: 3.3
+
+
.. function:: rename(src, dst)
Rename the file or directory *src* to *dst*. If *dst* is a directory,
@@ -1794,6 +1899,44 @@ Files and Directories
Availability: Unix, Windows.
+.. data:: XATTR_SIZE_MAX
+
+ The maximum size the value of an extended attribute can be. Currently, this
+ is 64 kilobytes on Linux.
+
+
+.. data:: XATTR_CREATE
+
+ This is a possible value for the flags argument in :func:`setxattr`. It
+ indicates the operation must create an attribute.
+
+
+.. data:: XATTR_REPLACE
+
+ This is a possible value for the flags argument in :func:`setxattr`. It
+ indicates the operation must replace an existing attribute.
+
+
+.. function:: setxattr(path, attr, value, flags=0)
+
+ Set the extended filesystem attribute *attr* on *path* to *value*. *attr*
+ must be a bytes or str with no embedded NULs. If it is str, it is encoded
+ with the filesystem encoding. *flags* may be :data:`XATTR_REPLACE` or
+ :data:`XATTR_CREATE`. If :data:`XATTR_REPLACE` is given and the attribute
+ does not exist, ``EEXISTS`` will be raised. If :data:`XATTR_CREATE` is given
+ and the attribute already exists, the attribute will not be created and
+ ``ENODATA`` will be raised.
+
+ Availability: Linux
+
+ .. note::
+
+ A bug in Linux kernel versions less than 2.6.39 caused the flags argument
+ to be ignored on some filesystems.
+
+ .. versionadded:: 3.3
+
+
.. function:: stat(path)
Perform the equivalent of a :c:func:`stat` system call on the given path.
diff --git a/Include/descrobject.h b/Include/descrobject.h
index f715fe1..646b3cc 100644
--- a/Include/descrobject.h
+++ b/Include/descrobject.h
@@ -77,6 +77,7 @@ PyAPI_DATA(PyTypeObject) PyMemberDescr_Type;
PyAPI_DATA(PyTypeObject) PyMethodDescr_Type;
PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type;
PyAPI_DATA(PyTypeObject) PyDictProxy_Type;
+PyAPI_DATA(PyTypeObject) _PyMethodWrapper_Type;
PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *);
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index dcce2eb..da74729 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -1,16 +1,17 @@
#! /usr/bin/env python3
+import getopt
import os
import os.path
-import sys
-import getopt
import re
import socket
-import time
+import subprocess
+import sys
import threading
+import time
+import tokenize
import traceback
import types
-import subprocess
import linecache
from code import InteractiveInterpreter
@@ -201,18 +202,18 @@ class PyShellEditorWindow(EditorWindow):
breaks = self.breakpoints
filename = self.io.filename
try:
- lines = open(self.breakpointPath,"r").readlines()
+ with open(self.breakpointPath, "r") as fp:
+ lines = fp.readlines()
except IOError:
lines = []
- new_file = open(self.breakpointPath,"w")
- for line in lines:
- if not line.startswith(filename + '='):
- new_file.write(line)
- self.update_breakpoints()
- breaks = self.breakpoints
- if breaks:
- new_file.write(filename + '=' + str(breaks) + '\n')
- new_file.close()
+ with open(self.breakpointPath, "w") as new_file:
+ for line in lines:
+ if not line.startswith(filename + '='):
+ new_file.write(line)
+ self.update_breakpoints()
+ breaks = self.breakpoints
+ if breaks:
+ new_file.write(filename + '=' + str(breaks) + '\n')
def restore_file_breaks(self):
self.text.update() # this enables setting "BREAK" tags to be visible
@@ -220,7 +221,8 @@ class PyShellEditorWindow(EditorWindow):
if filename is None:
return
if os.path.isfile(self.breakpointPath):
- lines = open(self.breakpointPath,"r").readlines()
+ with open(self.breakpointPath, "r") as fp:
+ lines = fp.readlines()
for line in lines:
if line.startswith(filename + '='):
breakpoint_linenumbers = eval(line[len(filename)+1:])
@@ -571,7 +573,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
def execfile(self, filename, source=None):
"Execute an existing file"
if source is None:
- source = open(filename, "r").read()
+ with tokenize.open(filename) as fp:
+ source = fp.read()
try:
code = compile(source, filename, "exec")
except (OverflowError, SyntaxError):
diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py
index 90972b5..915e56e 100644
--- a/Lib/idlelib/ScriptBinding.py
+++ b/Lib/idlelib/ScriptBinding.py
@@ -67,25 +67,20 @@ class ScriptBinding:
def tabnanny(self, filename):
# XXX: tabnanny should work on binary files as well
- with open(filename, 'r', encoding='iso-8859-1') as f:
- two_lines = f.readline() + f.readline()
- encoding = IOBinding.coding_spec(two_lines)
- if not encoding:
- encoding = 'utf-8'
- f = open(filename, 'r', encoding=encoding)
- try:
- tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
- except tokenize.TokenError as msg:
- msgtxt, (lineno, start) = msg
- self.editwin.gotoline(lineno)
- self.errorbox("Tabnanny Tokenizing Error",
- "Token Error: %s" % msgtxt)
- return False
- except tabnanny.NannyNag as nag:
- # The error messages from tabnanny are too confusing...
- self.editwin.gotoline(nag.get_lineno())
- self.errorbox("Tab/space error", indent_message)
- return False
+ with tokenize.open(filename) as f:
+ try:
+ tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
+ except tokenize.TokenError as msg:
+ msgtxt, (lineno, start) = msg
+ self.editwin.gotoline(lineno)
+ self.errorbox("Tabnanny Tokenizing Error",
+ "Token Error: %s" % msgtxt)
+ return False
+ except tabnanny.NannyNag as nag:
+ # The error messages from tabnanny are too confusing...
+ self.editwin.gotoline(nag.get_lineno())
+ self.errorbox("Tab/space error", indent_message)
+ return False
return True
def checksyntax(self, filename):
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index db64588..2c5c888 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -464,13 +464,13 @@ def call(*popenargs, timeout=None, **kwargs):
retcode = call(["ls", "-l"])
"""
- p = Popen(*popenargs, **kwargs)
- try:
- return p.wait(timeout=timeout)
- except TimeoutExpired:
- p.kill()
- p.wait()
- raise
+ with Popen(*popenargs, **kwargs) as p:
+ try:
+ return p.wait(timeout=timeout)
+ except:
+ p.kill()
+ p.wait()
+ raise
def check_call(*popenargs, **kwargs):
@@ -514,16 +514,20 @@ def check_output(*popenargs, timeout=None, **kwargs):
"""
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
- process = Popen(*popenargs, stdout=PIPE, **kwargs)
- try:
- output, unused_err = process.communicate(timeout=timeout)
- except TimeoutExpired:
- process.kill()
- output, unused_err = process.communicate()
- raise TimeoutExpired(process.args, timeout, output=output)
- retcode = process.poll()
- if retcode:
- raise CalledProcessError(retcode, process.args, output=output)
+ with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
+ try:
+ output, unused_err = process.communicate(timeout=timeout)
+ except TimeoutExpired:
+ process.kill()
+ output, unused_err = process.communicate()
+ raise TimeoutExpired(process.args, timeout, output=output)
+ except:
+ process.kill()
+ process.wait()
+ raise
+ retcode = process.poll()
+ if retcode:
+ raise CalledProcessError(retcode, process.args, output=output)
return output
@@ -618,11 +622,19 @@ def getstatusoutput(cmd):
>>> subprocess.getstatusoutput('/bin/junk')
(256, 'sh: /bin/junk: not found')
"""
- pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
- text = pipe.read()
- sts = pipe.close()
- if sts is None: sts = 0
- if text[-1:] == '\n': text = text[:-1]
+ with os.popen('{ ' + cmd + '; } 2>&1', 'r') as pipe:
+ try:
+ text = pipe.read()
+ sts = pipe.close()
+ except:
+ process = pipe._proc
+ process.kill()
+ process.wait()
+ raise
+ if sts is None:
+ sts = 0
+ if text[-1:] == '\n':
+ text = text[:-1]
return sts, text
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 718d05c..9be6958 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -5,6 +5,7 @@ import sys
import unittest
import pickle
import weakref
+import errno
from test.support import (TESTFN, unlink, run_unittest, captured_output,
gc_collect, cpython_only, no_tracing)
@@ -852,6 +853,13 @@ class ExceptionTests(unittest.TestCase):
self.fail("RuntimeError not raised")
self.assertEqual(wr(), None)
+ def test_errno_ENOTDIR(self):
+ # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
+ with self.assertRaises(OSError) as cm:
+ os.listdir(__file__)
+ self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception)
+
+
def test_main():
run_unittest(ExceptionTests)
diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
index 331dd2e..977cb39 100644
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -174,6 +174,9 @@ faulthandler._fatal_error(b'xyz')
2,
'xyz')
+ @unittest.skipIf(sys.platform.startswith('openbsd') and HAVE_THREADS,
+ "Issue #12868: sigaltstack() doesn't work on "
+ "OpenBSD if Python is compiled with pthread")
@unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
'need faulthandler._stack_overflow()')
def test_stack_overflow(self):
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 1d5f11c..569b218 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -14,6 +14,8 @@ import shutil
from test import support
import contextlib
import mmap
+import platform
+import re
import uuid
import asyncore
import asynchat
@@ -1506,6 +1508,97 @@ class TestSendfile(unittest.TestCase):
raise
+def supports_extended_attributes():
+ if not hasattr(os, "setxattr"):
+ return False
+ try:
+ with open(support.TESTFN, "wb") as fp:
+ try:
+ os.fsetxattr(fp.fileno(), b"user.test", b"")
+ except OSError as e:
+ if e.errno != errno.ENOTSUP:
+ raise
+ return False
+ finally:
+ support.unlink(support.TESTFN)
+ # Kernels < 2.6.39 don't respect setxattr flags.
+ kernel_version = platform.release()
+ m = re.match("2.6.(\d{1,2})", kernel_version)
+ return m is None or int(m.group(1)) >= 39
+
+
+@unittest.skipUnless(supports_extended_attributes(),
+ "no non-broken extended attribute support")
+class ExtendedAttributeTests(unittest.TestCase):
+
+ def tearDown(self):
+ support.unlink(support.TESTFN)
+
+ def _check_xattrs_str(self, s, getxattr, setxattr, removexattr, listxattr):
+ fn = support.TESTFN
+ open(fn, "wb").close()
+ with self.assertRaises(OSError) as cm:
+ getxattr(fn, s("user.test"))
+ self.assertEqual(cm.exception.errno, errno.ENODATA)
+ self.assertEqual(listxattr(fn), [])
+ setxattr(fn, s("user.test"), b"")
+ self.assertEqual(listxattr(fn), ["user.test"])
+ self.assertEqual(getxattr(fn, b"user.test"), b"")
+ setxattr(fn, s("user.test"), b"hello", os.XATTR_REPLACE)
+ self.assertEqual(getxattr(fn, b"user.test"), b"hello")
+ with self.assertRaises(OSError) as cm:
+ setxattr(fn, s("user.test"), b"bye", os.XATTR_CREATE)
+ self.assertEqual(cm.exception.errno, errno.EEXIST)
+ with self.assertRaises(OSError) as cm:
+ setxattr(fn, s("user.test2"), b"bye", os.XATTR_REPLACE)
+ self.assertEqual(cm.exception.errno, errno.ENODATA)
+ setxattr(fn, s("user.test2"), b"foo", os.XATTR_CREATE)
+ self.assertEqual(sorted(listxattr(fn)), ["user.test", "user.test2"])
+ removexattr(fn, s("user.test"))
+ with self.assertRaises(OSError) as cm:
+ getxattr(fn, s("user.test"))
+ self.assertEqual(cm.exception.errno, errno.ENODATA)
+ self.assertEqual(listxattr(fn), ["user.test2"])
+ self.assertEqual(getxattr(fn, s("user.test2")), b"foo")
+ setxattr(fn, s("user.test"), b"a"*1024)
+ self.assertEqual(getxattr(fn, s("user.test")), b"a"*1024)
+ removexattr(fn, s("user.test"))
+ many = sorted("user.test{}".format(i) for i in range(100))
+ for thing in many:
+ setxattr(fn, thing, b"x")
+ self.assertEqual(sorted(listxattr(fn)), many)
+
+ def _check_xattrs(self, *args):
+ def make_bytes(s):
+ return bytes(s, "ascii")
+ self._check_xattrs_str(str, *args)
+ support.unlink(support.TESTFN)
+ self._check_xattrs_str(make_bytes, *args)
+
+ def test_simple(self):
+ self._check_xattrs(os.getxattr, os.setxattr, os.removexattr,
+ os.listxattr)
+
+ def test_lpath(self):
+ self._check_xattrs(os.lgetxattr, os.lsetxattr, os.lremovexattr,
+ os.llistxattr)
+
+ def test_fds(self):
+ def getxattr(path, *args):
+ with open(path, "rb") as fp:
+ return os.fgetxattr(fp.fileno(), *args)
+ def setxattr(path, *args):
+ with open(path, "wb") as fp:
+ os.fsetxattr(fp.fileno(), *args)
+ def removexattr(path, *args):
+ with open(path, "wb") as fp:
+ os.fremovexattr(fp.fileno(), *args)
+ def listxattr(path, *args):
+ with open(path, "rb") as fp:
+ return os.flistxattr(fp.fileno(), *args)
+ self._check_xattrs(getxattr, setxattr, removexattr, listxattr)
+
+
@support.reap_threads
def test_main():
support.run_unittest(
@@ -1529,6 +1622,7 @@ def test_main():
LinkTests,
TestSendfile,
ProgramPriorityTests,
+ ExtendedAttributeTests,
)
if __name__ == "__main__":
diff --git a/Misc/NEWS b/Misc/NEWS
index 08a2078..d83c122 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins
-----------------
+- Issue #12802: the Windows error ERROR_DIRECTORY (numbered 267) is now
+ mapped to POSIX errno ENOTDIR (previously EINVAL).
+
- Issue #9200: The str.is* methods now work with strings that contain non-BMP
characters even in narrow Unicode builds.
@@ -268,6 +271,14 @@ Core and Builtins
Library
-------
+- Issue #12636: IDLE reads the coding cookie when executing a Python script.
+
+- Issue #12494: On error, call(), check_call(), check_output() and
+ getstatusoutput() functions of the subprocess module now kill the process,
+ read its status (to avoid zombis) and close pipes.
+
+- Issue #12720: Expose low-level Linux extended file attribute functions in os.
+
- Issue #10946: The distutils commands bdist_dumb, bdist_wininst and bdist_msi
now respect a --skip-build option given to bdist. The packaging commands
were fixed too.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index d701690..1416a7c 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -107,6 +107,10 @@ corresponding Unix manual entries for more information on calls.");
#include <sched.h>
#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
+
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@@ -9950,6 +9954,384 @@ posix_mkfifoat(PyObject *self, PyObject *args)
}
#endif
+#ifdef HAVE_ATTR_XATTR_H
+
+static int
+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)
+{
+ 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;
+}
+
+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_getxattr(PyObject *self, PyObject *args)
+{
+ PyObject *path, *res, *name;
+
+ 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;
+}
+
+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;
+}
+
+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);
+}
+
+PyDoc_STRVAR(posix_fgetxattr__doc__,
+"fgetxattr(fd, attr) -> value\n\n\
+Like getxattr but operate on a fd instead of a path.");
+
+static PyObject *
+posix_fgetxattr(PyObject *self, PyObject *args)
+{
+ PyObject *res, *name;
+ int fd;
+
+ 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;
+}
+
+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 *path, *name;
+ Py_buffer data;
+ int flags = 0, err;
+
+ 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;
+}
+
+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;
+}
+
+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)
+{
+ 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*.");
+
+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_lremovexattr(PyObject *self, PyObject *args)
+{
+ 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;
+}
+
+PyDoc_STRVAR(posix_fremovexattr__doc__,
+"fremovexattr(fd, attr)\n\n\
+Like removexattr but operates on a file descriptor.");
+
+static PyObject *
+posix_fremovexattr(PyObject *self, PyObject *args)
+{
+ PyObject *name;
+ int fd, err;
+
+ 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;
+}
+
+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;
+}
+
+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;
+
+ 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;
+ }
+ 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;
+}
+
+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;
+ res = listxattr_common(PyBytes_AS_STRING(path), listxattr);
+ Py_DECREF(path);
+ return res;
+}
+
+PyDoc_STRVAR(posix_llistxattr__doc__,
+"llistxattr(path)\n\n\
+Like listxattr but don't follow symlinks..");
+
+static PyObject *
+posix_llistxattr(PyObject *self, PyObject *args)
+{
+ PyObject *path, *res;
+
+ if (!PyArg_ParseTuple(args, "O&:llistxattr", PyUnicode_FSConverter, &path))
+ return NULL;
+ res = listxattr_common(PyBytes_AS_STRING(path), llistxattr);
+ Py_DECREF(path);
+ return res;
+}
+
+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 *
+posix_flistxattr(PyObject *self, PyObject *args)
+{
+ long fd;
+
+ if (!PyArg_ParseTuple(args, "i:flistxattr", &fd))
+ return NULL;
+ return listxattr_common((const char *)(Py_uintptr_t)fd, wrap_flistxattr);
+}
+
+#endif /* HAVE_ATTR_XATTR_H */
+
static PyMethodDef posix_methods[] = {
{"access", posix_access, METH_VARARGS, posix_access__doc__},
#ifdef HAVE_TTYNAME
@@ -10399,6 +10781,20 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_MKFIFOAT
{"mkfifoat", posix_mkfifoat, METH_VARARGS, posix_mkfifoat__doc__},
#endif
+#ifdef HAVE_ATTR_XATTR_H
+ {"setxattr", posix_setxattr, METH_VARARGS, posix_setxattr__doc__},
+ {"lsetxattr", posix_lsetxattr, METH_VARARGS, posix_lsetxattr__doc__},
+ {"fsetxattr", posix_fsetxattr, METH_VARARGS, posix_fsetxattr__doc__},
+ {"getxattr", posix_getxattr, METH_VARARGS, posix_getxattr__doc__},
+ {"lgetxattr", posix_lgetxattr, METH_VARARGS, posix_lgetxattr__doc__},
+ {"fgetxattr", posix_fgetxattr, METH_VARARGS, posix_fgetxattr__doc__},
+ {"removexattr", posix_removexattr, METH_VARARGS, posix_removexattr__doc__},
+ {"lremovexattr", posix_lremovexattr, METH_VARARGS, posix_lremovexattr__doc__},
+ {"fremovexattr", posix_fremovexattr, METH_VARARGS, posix_fremovexattr__doc__},
+ {"listxattr", posix_listxattr, METH_VARARGS, posix_listxattr__doc__},
+ {"llistxattr", posix_llistxattr, METH_VARARGS, posix_llistxattr__doc__},
+ {"flistxattr", posix_flistxattr, METH_VARARGS, posix_flistxattr__doc__},
+#endif
{NULL, NULL} /* Sentinel */
};
@@ -10848,6 +11244,12 @@ all_ins(PyObject *d)
#endif
#endif
+#ifdef HAVE_ATTR_XATTR_H
+ if (ins(d, "XATTR_CREATE", (long)XATTR_CREATE)) return -1;
+ if (ins(d, "XATTR_REPLACE", (long)XATTR_REPLACE)) return -1;
+ if (ins(d, "XATTR_SIZE_MAX", (long)XATTR_SIZE_MAX)) return -1;
+#endif
+
#if defined(PYOS_OS2)
if (insertvalues(d)) return -1;
#endif
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 93daefd..a786bae 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -846,16 +846,13 @@ PyDictProxy_New(PyObject *dict)
/* This has no reason to be in this file except that adding new files is a
bit of a pain */
-/* forward */
-static PyTypeObject wrappertype;
-
typedef struct {
PyObject_HEAD
PyWrapperDescrObject *descr;
PyObject *self;
} wrapperobject;
-#define Wrapper_Check(v) (Py_TYPE(v) == &wrappertype)
+#define Wrapper_Check(v) (Py_TYPE(v) == &_PyMethodWrapper_Type)
static void
wrapper_dealloc(wrapperobject *wp)
@@ -1021,7 +1018,7 @@ wrapper_traverse(PyObject *self, visitproc visit, void *arg)
return 0;
}
-static PyTypeObject wrappertype = {
+PyTypeObject _PyMethodWrapper_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"method-wrapper", /* tp_name */
sizeof(wrapperobject), /* tp_basicsize */
@@ -1070,7 +1067,7 @@ PyWrapper_New(PyObject *d, PyObject *self)
assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
(PyObject *)PyDescr_TYPE(descr)));
- wp = PyObject_GC_New(wrapperobject, &wrappertype);
+ wp = PyObject_GC_New(wrapperobject, &_PyMethodWrapper_Type);
if (wp != NULL) {
Py_INCREF(descr);
wp->descr = descr;
diff --git a/Objects/object.c b/Objects/object.c
index cf49e1b..52acf12 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1558,6 +1558,9 @@ _Py_ReadyTypes(void)
if (PyType_Ready(&PyWrapperDescr_Type) < 0)
Py_FatalError("Can't initialize wrapper type");
+ if (PyType_Ready(&_PyMethodWrapper_Type) < 0)
+ Py_FatalError("Can't initialize method wrapper type");
+
if (PyType_Ready(&PyEllipsis_Type) < 0)
Py_FatalError("Can't initialize ellipsis type");
diff --git a/PC/errmap.h b/PC/errmap.h
index d225aa4..8dde31c 100644
--- a/PC/errmap.h
+++ b/PC/errmap.h
@@ -72,6 +72,7 @@ int winerror_to_errno(int winerror)
case 202: return 8;
case 206: return 2;
case 215: return 11;
+ case 267: return 20;
case 1816: return 12;
default: return EINVAL;
}
diff --git a/PC/generrmap.c b/PC/generrmap.c
index bf1081b..0323cd4 100644
--- a/PC/generrmap.c
+++ b/PC/generrmap.c
@@ -1,3 +1,6 @@
+#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
#include <stdio.h>
#include <errno.h>
@@ -6,15 +9,21 @@
int main()
{
int i;
+ _setmode(fileno(stdout), O_BINARY);
printf("/* Generated file. Do not edit. */\n");
printf("int winerror_to_errno(int winerror)\n");
- printf("{\n\tswitch(winerror) {\n");
+ printf("{\n switch(winerror) {\n");
for(i=1; i < 65000; i++) {
_dosmaperr(i);
- if (errno == EINVAL)
- continue;
- printf("\t\tcase %d: return %d;\n", i, errno);
+ if (errno == EINVAL) {
+ /* Issue #12802 */
+ if (i == ERROR_DIRECTORY)
+ errno = ENOTDIR;
+ else
+ continue;
+ }
+ printf(" case %d: return %d;\n", i, errno);
}
- printf("\t\tdefault: return EINVAL;\n");
- printf("\t}\n}\n");
+ printf(" default: return EINVAL;\n");
+ printf(" }\n}\n");
}
diff --git a/Python/import.c b/Python/import.c
index 19e975a..1411248 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -2653,7 +2653,9 @@ PyObject *
PyImport_ImportModuleNoBlock(const char *name)
{
PyObject *nameobj, *modules, *result;
+#ifdef WITH_THREAD
long me;
+#endif
/* Try to get the module from sys.modules[name] */
modules = PyImport_GetModuleDict();
diff --git a/configure b/configure
index ed13d88..4200d88 100755
--- a/configure
+++ b/configure
@@ -6090,7 +6090,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h
fi
-for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
+for ac_header in asm/types.h attr/xattr.h conio.h curses.h direct.h dlfcn.h errno.h \
fcntl.h grp.h \
ieeefp.h io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
diff --git a/configure.in b/configure.in
index c10f67a..43745fb 100644
--- a/configure.in
+++ b/configure.in
@@ -1299,7 +1299,7 @@ dnl AC_MSG_RESULT($cpp_type)
# checks for header files
AC_HEADER_STDC
-AC_CHECK_HEADERS(asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
+AC_CHECK_HEADERS(asm/types.h attr/xattr.h conio.h curses.h direct.h dlfcn.h errno.h \
fcntl.h grp.h \
ieeefp.h io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
diff --git a/pyconfig.h.in b/pyconfig.h.in
index eed1ff7..bf9e7fe 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -64,6 +64,9 @@
/* Define if GCC supports __attribute__((format(PyArg_ParseTuple, 2, 3))) */
#undef HAVE_ATTRIBUTE_FORMAT_PARSETUPLE
+/* Define to 1 if you have the <attr/xattr.h> header file. */
+#undef HAVE_ATTR_XATTR_H
+
/* Define to 1 if you have the `bind_textdomain_codeset' function. */
#undef HAVE_BIND_TEXTDOMAIN_CODESET