Issue #4761: Add the *at() family of functions (openat(), etc.) to the posix

module.  Patch by Ross Lagerwall.
This commit is contained in:
Antoine Pitrou 2011-02-25 23:25:17 +00:00
parent 68e5c044e8
commit f65132de3d
7 changed files with 1560 additions and 544 deletions

View File

@ -606,6 +606,21 @@ associated with a :term:`file object` when required. Note that using the file
descriptor directly will bypass the file object methods, ignoring aspects such
as internal buffering of data.
.. data:: AT_SYMLINK_NOFOLLOW
AT_EACCESS
AT_FDCWD
AT_REMOVEDIR
AT_SYMLINK_FOLLOW
UTIME_NOW
UTIME_OMIT
These parameters are used as flags to the \*at family of functions.
Availability: Unix.
.. versionadded:: 3.3
.. function:: close(fd)
Close file descriptor *fd*.
@ -654,6 +669,19 @@ as internal buffering of data.
Availability: Unix, Windows.
.. function:: faccessat(dirfd, path, mode, flags=0)
Like :func:`access` but if *path* is relative, it is taken as relative to *dirfd*.
*flags* is optional and can be constructed by ORing together zero or more
of these values: :data:`AT_SYMLINK_NOFOLLOW`, :data:`AT_EACCESS`.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: fchmod(fd, mode)
Change the mode of the file given by *fd* to the numeric *mode*. See the docs
@ -662,6 +690,18 @@ as internal buffering of data.
Availability: Unix.
.. function:: fchmodat(dirfd, path, mode, flags=0)
Like :func:`chmod` but if *path* is relative, it is taken as relative to *dirfd*.
*flags* is optional and may be 0 or :data:`AT_SYMLINK_NOFOLLOW`.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: fchown(fd, uid, gid)
Change the owner and group id of the file given by *fd* to the numeric *uid*
@ -670,6 +710,18 @@ as internal buffering of data.
Availability: Unix.
.. function:: fchownat(dirfd, path, uid, gid, flags=0)
Like :func:`chown` but if *path* is relative, it is taken as relative to *dirfd*.
*flags* is optional and may be 0 or :data:`AT_SYMLINK_NOFOLLOW`.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: fdatasync(fd)
Force write of file with filedescriptor *fd* to disk. Does not force update of
@ -705,6 +757,17 @@ as internal buffering of data.
Availability: Unix, Windows.
.. function:: fstatat(dirfd, path, flags=0)
Like :func:`stat` but if *path* is relative, it is taken as relative to *dirfd*.
*flags* is optional and may be 0 or :data:`AT_SYMLINK_NOFOLLOW`.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: fstatvfs(fd)
@ -734,6 +797,18 @@ as internal buffering of data.
Availability: Unix.
.. function:: futimesat(dirfd, path, (atime, mtime))
futimesat(dirfd, path, None)
Like :func:`utime` but if *path* is relative, it is taken as relative to *dirfd*.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: isatty(fd)
Return ``True`` if the file descriptor *fd* is open and connected to a
@ -742,6 +817,20 @@ as internal buffering of data.
Availability: Unix.
.. function:: linkat(srcfd, srcpath, dstfd, dstpath, flags=0)
Like :func:`link` but if *srcpath* is relative, it is taken as relative to *srcfd*
and if *dstpath* is relative, it is taken as relative to *dstfd*.
*flags* is optional and may be 0 or :data:`AT_SYMLINK_FOLLOW`.
If *srcpath* is relative and *srcfd* is the special value :data:`AT_FDCWD`, then
*srcpath* is interpreted relative to the current working directory. This
also applies for *dstpath*.
Availability: Unix.
.. versionadded:: 3.3
.. function:: lseek(fd, pos, how)
Set the current position of file descriptor *fd* to position *pos*, modified
@ -761,6 +850,39 @@ as internal buffering of data.
respectively. Availability: Windows, Unix.
.. function:: mkdirat(dirfd, path, mode=0o777)
Like :func:`mkdir` but if *path* is relative, it is taken as relative to *dirfd*.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: mkfifoat(dirfd, path, mode=0o666)
Like :func:`mkfifo` but if *path* is relative, it is taken as relative to *dirfd*.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: mknodat(dirfd, path, mode=0o600, device=0)
Like :func:`mknod` but if *path* is relative, it is taken as relative to *dirfd*.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: open(file, flags[, mode])
Open the file *file* and set various flags according to *flags* and possibly
@ -783,6 +905,17 @@ as internal buffering of data.
wrap a file descriptor in a file object, use :func:`fdopen`.
.. function:: openat(dirfd, path, flags, mode=0o777)
Like :func:`open` but if *path* is relative, it is taken as relative to *dirfd*.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: openpty()
.. index:: module: pty
@ -860,6 +993,41 @@ as internal buffering of data.
.. versionadded:: 3.3
.. function:: readlinkat(dirfd, path)
Like :func:`readlink` but if *path* is relative, it is taken as relative to *dirfd*.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: renameat(olddirfd, oldpath, newdirfd, newpath)
Like :func:`rename` but if *oldpath* is relative, it is taken as relative to
*olddirfd* and if *newpath* is relative, it is taken as relative to *newdirfd*.
If *oldpath* is relative and *olddirfd* is the special value :data:`AT_FDCWD`, then
*oldpath* is interpreted relative to the current working directory. This
also applies for *newpath*.
Availability: Unix.
.. versionadded:: 3.3
.. function:: symlinkat(src, dstfd, dst)
Like :func:`symlink` but if *dst* is relative, it is taken as relative to *dstfd*.
If *dst* is relative and *dstfd* is the special value :data:`AT_FDCWD`, then *dst*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: tcgetpgrp(fd)
Return the process group associated with the terminal given by *fd* (an open
@ -885,6 +1053,38 @@ as internal buffering of data.
Availability: Unix.
.. function:: unlinkat(dirfd, path, flags=0)
Like :func:`unlink` but if *path* is relative, it is taken as relative to *dirfd*.
*flags* is optional and may be 0 or :data:`AT_REMOVEDIR`. If :data:`AT_REMOVEDIR` is
specified, :func:`unlinkat` behaves like :func:`rmdir`.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: utimensat(dirfd, path, (atime_sec, atime_nsec), (mtime_sec, mtime_nsec), flags)
utimensat(dirfd, path, None, None, flags)
Updates the timestamps of a file with nanosecond precision.
The second form sets *atime* and *mtime* to the current time.
If *atime_nsec* or *mtime_nsec* is specified as :data:`UTIME_NOW`, the corresponding
timestamp is updated to the current time.
If *atime_nsec* or *mtime_nsec* is specified as :data:`UTIME_OMIT`, the corresponding
timestamp is not updated.
If *path* is relative, it is taken as relative to *dirfd*.
*flags* is optional and may be 0 or :data:`AT_SYMLINK_NOFOLLOW`.
If *path* is relative and *dirfd* is the special value :data:`AT_FDCWD`, then *path*
is interpreted relative to the current working directory.
Availability: Unix.
.. versionadded:: 3.3
.. function:: write(fd, str)
Write the bytestring in *str* to file descriptor *fd*. Return the number of

View File

@ -389,6 +389,198 @@ class PosixTester(unittest.TestCase):
set([int(x) for x in groups.split()]),
set(posix.getgroups() + [posix.getegid()]))
# tests for the posix *at functions follow
@unittest.skipUnless(hasattr(posix, 'faccessat'), "test needs posix.faccessat()")
def test_faccessat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
self.assertTrue(posix.faccessat(f, support.TESTFN, os.R_OK))
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'fchmodat'), "test needs posix.fchmodat()")
def test_fchmodat(self):
os.chmod(support.TESTFN, stat.S_IRUSR)
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.fchmodat(f, support.TESTFN, stat.S_IRUSR | stat.S_IWUSR)
s = posix.stat(support.TESTFN)
self.assertEqual(s[0] & stat.S_IRWXU, stat.S_IRUSR | stat.S_IWUSR)
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'fchownat'), "test needs posix.fchownat()")
def test_fchownat(self):
support.unlink(support.TESTFN)
open(support.TESTFN, 'w').close()
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.fchownat(f, support.TESTFN, os.getuid(), os.getgid())
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'fstatat'), "test needs posix.fstatat()")
def test_fstatat(self):
support.unlink(support.TESTFN)
with open(support.TESTFN, 'w') as outfile:
outfile.write("testline\n")
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
s1 = posix.stat(support.TESTFN)
s2 = posix.fstatat(f, support.TESTFN)
self.assertEqual(s1, s2)
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'futimesat'), "test needs posix.futimesat()")
def test_futimesat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
now = time.time()
posix.futimesat(f, support.TESTFN, None)
self.assertRaises(TypeError, posix.futimesat, f, support.TESTFN, (None, None))
self.assertRaises(TypeError, posix.futimesat, f, support.TESTFN, (now, None))
self.assertRaises(TypeError, posix.futimesat, f, support.TESTFN, (None, now))
posix.futimesat(f, support.TESTFN, (int(now), int(now)))
posix.futimesat(f, support.TESTFN, (now, now))
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'linkat'), "test needs posix.linkat()")
def test_linkat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.linkat(f, support.TESTFN, f, support.TESTFN + 'link')
# should have same inodes
self.assertEqual(posix.stat(support.TESTFN)[1],
posix.stat(support.TESTFN + 'link')[1])
finally:
posix.close(f)
support.unlink(support.TESTFN + 'link')
@unittest.skipUnless(hasattr(posix, 'mkdirat'), "test needs posix.mkdirat()")
def test_mkdirat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.mkdirat(f, support.TESTFN + 'dir')
posix.stat(support.TESTFN + 'dir') # should not raise exception
finally:
posix.close(f)
support.rmtree(support.TESTFN + 'dir')
@unittest.skipUnless(hasattr(posix, 'mknodat') and hasattr(stat, 'S_IFIFO'),
"don't have mknodat()/S_IFIFO")
def test_mknodat(self):
# Test using mknodat() to create a FIFO (the only use specified
# by POSIX).
support.unlink(support.TESTFN)
mode = stat.S_IFIFO | stat.S_IRUSR | stat.S_IWUSR
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.mknodat(f, support.TESTFN, mode, 0)
except OSError as e:
# Some old systems don't allow unprivileged users to use
# mknod(), or only support creating device nodes.
self.assertIn(e.errno, (errno.EPERM, errno.EINVAL))
else:
self.assertTrue(stat.S_ISFIFO(posix.stat(support.TESTFN).st_mode))
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'openat'), "test needs posix.openat()")
def test_openat(self):
support.unlink(support.TESTFN)
with open(support.TESTFN, 'w') as outfile:
outfile.write("testline\n")
a = posix.open(posix.getcwd(), posix.O_RDONLY)
b = posix.openat(a, support.TESTFN, posix.O_RDONLY)
try:
res = posix.read(b, 9).decode(encoding="utf-8")
self.assertEqual("testline\n", res)
finally:
posix.close(a)
posix.close(b)
@unittest.skipUnless(hasattr(posix, 'readlinkat'), "test needs posix.readlinkat()")
def test_readlinkat(self):
os.symlink(support.TESTFN, support.TESTFN + 'link')
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
self.assertEqual(posix.readlink(support.TESTFN + 'link'),
posix.readlinkat(f, support.TESTFN + 'link'))
finally:
support.unlink(support.TESTFN + 'link')
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'renameat'), "test needs posix.renameat()")
def test_renameat(self):
support.unlink(support.TESTFN)
open(support.TESTFN + 'ren', 'w').close()
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.renameat(f, support.TESTFN + 'ren', f, support.TESTFN)
except:
posix.rename(support.TESTFN + 'ren', support.TESTFN)
raise
else:
posix.stat(support.TESTFN) # should not throw exception
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'symlinkat'), "test needs posix.symlinkat()")
def test_symlinkat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.symlinkat(support.TESTFN, f, support.TESTFN + 'link')
self.assertEqual(posix.readlink(support.TESTFN + 'link'), support.TESTFN)
finally:
posix.close(f)
support.unlink(support.TESTFN + 'link')
@unittest.skipUnless(hasattr(posix, 'unlinkat'), "test needs posix.unlinkat()")
def test_unlinkat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
open(support.TESTFN + 'del', 'w').close()
posix.stat(support.TESTFN + 'del') # should not throw exception
try:
posix.unlinkat(f, support.TESTFN + 'del')
except:
support.unlink(support.TESTFN + 'del')
raise
else:
self.assertRaises(OSError, posix.stat, support.TESTFN + 'link')
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'utimensat'), "test needs posix.utimensat()")
def test_utimensat(self):
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
now = time.time()
posix.utimensat(f, support.TESTFN, None, None)
self.assertRaises(TypeError, posix.utimensat, f, support.TESTFN, (None, None), (None, None))
self.assertRaises(TypeError, posix.utimensat, f, support.TESTFN, (now, 0), None)
self.assertRaises(TypeError, posix.utimensat, f, support.TESTFN, None, (now, 0))
posix.utimensat(f, support.TESTFN, (int(now), int((now - int(now)) * 1e9)),
(int(now), int((now - int(now)) * 1e9)))
finally:
posix.close(f)
@unittest.skipUnless(hasattr(posix, 'mkfifoat'), "don't have mkfifoat()")
def test_mkfifoat(self):
support.unlink(support.TESTFN)
f = posix.open(posix.getcwd(), posix.O_RDONLY)
try:
posix.mkfifoat(f, support.TESTFN, stat.S_IRUSR | stat.S_IWUSR)
self.assertTrue(stat.S_ISFIFO(posix.stat(support.TESTFN).st_mode))
finally:
posix.close(f)
class PosixGroupsTester(unittest.TestCase):
def setUp(self):

View File

@ -35,6 +35,9 @@ Core and Builtins
Library
-------
- Issue #4761: Add the *at() family of functions (openat(), etc.) to the posix
module. Patch by Ross Lagerwall.
- Issue #7322: Trying to read from a socket's file-like object after a timeout
occurred now raises an error instead of silently losing data.

View File

@ -8009,6 +8009,552 @@ posix_getresgid (PyObject *self, PyObject *noargs)
}
#endif
/* 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 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 HAVE_FUTIMESAT
PyDoc_STRVAR(posix_futimesat__doc__,
"futimesat(dirfd, path, (atime, mtime))\n\
futimesat(dirfd, path, None)\n\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;
struct timeval buf[2];
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),
&(buf[0].tv_sec), &(buf[0].tv_usec)) == -1) {
Py_DECREF(opath);
return NULL;
}
if (extract_time(PyTuple_GET_ITEM(arg, 1),
&(buf[1].tv_sec), &(buf[1].tv_usec)) == -1) {
Py_DECREF(opath);
return NULL;
}
Py_BEGIN_ALLOW_THREADS
res = futimesat(dirfd, path, buf);
Py_END_ALLOW_THREADS
}
Py_DECREF(opath);
if (res < 0) {
return posix_error();
}
Py_RETURN_NONE;
}
#endif
#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
#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 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 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
#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 HAVE_UTIMENSAT
PyDoc_STRVAR(posix_utimensat__doc__,
"utimensat(dirfd, path, (atime_sec, atime_nsec),\n\
(mtime_sec, mtime_nsec), flags)\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\
The second form sets atime and 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 *opath;
char *path;
int res, dirfd, flags = 0;
PyObject *atime, *mtime;
struct timespec buf[2];
if (!PyArg_ParseTuple(args, "iO&OO|i:utimensat",
&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 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
static PyMethodDef posix_methods[] = {
{"access", posix_access, METH_VARARGS, posix_access__doc__},
#ifdef HAVE_TTYNAME
@ -8335,6 +8881,52 @@ static PyMethodDef posix_methods[] = {
{"getresgid", posix_getresgid, METH_NOARGS, posix_getresgid__doc__},
#endif
/* posix *at family of functions */
#ifdef HAVE_FACCESSAT
{"faccessat", posix_faccessat, METH_VARARGS, posix_faccessat__doc__},
#endif
#ifdef HAVE_FCHMODAT
{"fchmodat", posix_fchmodat, METH_VARARGS, posix_fchmodat__doc__},
#endif /* HAVE_FCHMODAT */
#ifdef HAVE_FCHOWNAT
{"fchownat", posix_fchownat, METH_VARARGS, posix_fchownat__doc__},
#endif /* HAVE_FCHOWNAT */
#ifdef HAVE_FSTATAT
{"fstatat", posix_fstatat, METH_VARARGS, posix_fstatat__doc__},
#endif
#ifdef HAVE_FUTIMESAT
{"futimesat", posix_futimesat, METH_VARARGS, posix_futimesat__doc__},
#endif
#ifdef HAVE_LINKAT
{"linkat", posix_linkat, METH_VARARGS, posix_linkat__doc__},
#endif /* HAVE_LINKAT */
#ifdef HAVE_MKDIRAT
{"mkdirat", posix_mkdirat, METH_VARARGS, posix_mkdirat__doc__},
#endif
#if defined(HAVE_MKNODAT) && defined(HAVE_MAKEDEV)
{"mknodat", posix_mknodat, METH_VARARGS, posix_mknodat__doc__},
#endif
#ifdef HAVE_OPENAT
{"openat", posix_openat, METH_VARARGS, posix_openat__doc__},
#endif
#ifdef HAVE_READLINKAT
{"readlinkat", posix_readlinkat, METH_VARARGS, posix_readlinkat__doc__},
#endif /* HAVE_READLINKAT */
#ifdef HAVE_RENAMEAT
{"renameat", posix_renameat, METH_VARARGS, posix_renameat__doc__},
#endif
#if HAVE_SYMLINKAT
{"symlinkat", posix_symlinkat, METH_VARARGS, posix_symlinkat__doc__},
#endif /* HAVE_SYMLINKAT */
#ifdef HAVE_UNLINKAT
{"unlinkat", posix_unlinkat, METH_VARARGS, posix_unlinkat__doc__},
#endif
#ifdef HAVE_UTIMENSAT
{"utimensat", posix_utimensat, METH_VARARGS, posix_utimensat__doc__},
#endif
#ifdef HAVE_MKFIFOAT
{"mkfifoat", posix_mkfifoat, METH_VARARGS, posix_mkfifoat__doc__},
#endif
{NULL, NULL} /* Sentinel */
};
@ -8520,6 +9112,28 @@ all_ins(PyObject *d)
#ifdef PRIO_USER
if (ins(d, "PRIO_USER", (long)PRIO_USER)) return -1;
#endif
/* posix - constants for *at functions */
#ifdef AT_SYMLINK_NOFOLLOW
if (ins(d, "AT_SYMLINK_NOFOLLOW", (long)AT_SYMLINK_NOFOLLOW)) return -1;
#endif
#ifdef AT_EACCESS
if (ins(d, "AT_EACCESS", (long)AT_EACCESS)) return -1;
#endif
#ifdef AT_FDCWD
if (ins(d, "AT_FDCWD", (long)AT_FDCWD)) return -1;
#endif
#ifdef AT_REMOVEDIR
if (ins(d, "AT_REMOVEDIR", (long)AT_REMOVEDIR)) return -1;
#endif
#ifdef AT_SYMLINK_FOLLOW
if (ins(d, "AT_SYMLINK_FOLLOW", (long)AT_SYMLINK_FOLLOW)) return -1;
#endif
#ifdef UTIME_NOW
if (ins(d, "UTIME_NOW", (long)UTIME_NOW)) return -1;
#endif
#ifdef UTIME_OMIT
if (ins(d, "UTIME_OMIT", (long)UTIME_OMIT)) return -1;
#endif
/* MS Windows */

1034
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -2534,18 +2534,19 @@ AC_MSG_RESULT(MACHDEP_OBJS)
# checks for library functions
AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat fork \
fpathconf fstatat ftime ftruncate futimesat \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
initgroups kill killpg lchmod lchown lstat mbrtowc mkfifo mknod mktime \
mremap nice pathconf pause plock poll pthread_init \
putenv readlink realpath \
initgroups kill killpg lchmod lchown linkat lstat mbrtowc mkdirat mkfifo \
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \
pthread_init putenv readlink readlinkat realpath renameat \
select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
setgid \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sigaction siginterrupt sigrelse snprintf strftime strlcpy \
sigaction siginterrupt sigrelse snprintf strftime strlcpy symlinkat \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
truncate uname unsetenv utimes waitpid wait3 wait4 \
truncate uname unlinkat unsetenv utimensat utimes waitpid wait3 wait4 \
wcscoll wcsftime wcsxfrm _getpty)
# For some functions, having a definition is not sufficient, since

View File

@ -205,15 +205,24 @@
/* Define to 1 if you have the `expm1' function. */
#undef HAVE_EXPM1
/* Define to 1 if you have the `faccessat' function. */
#undef HAVE_FACCESSAT
/* Define if you have the 'fchdir' function. */
#undef HAVE_FCHDIR
/* Define to 1 if you have the `fchmod' function. */
#undef HAVE_FCHMOD
/* Define to 1 if you have the `fchmodat' function. */
#undef HAVE_FCHMODAT
/* Define to 1 if you have the `fchown' function. */
#undef HAVE_FCHOWN
/* Define to 1 if you have the `fchownat' function. */
#undef HAVE_FCHOWNAT
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
@ -241,6 +250,9 @@
/* Define to 1 if you have the `fseeko' function. */
#undef HAVE_FSEEKO
/* Define to 1 if you have the `fstatat' function. */
#undef HAVE_FSTATAT
/* Define to 1 if you have the `fstatvfs' function. */
#undef HAVE_FSTATVFS
@ -259,6 +271,9 @@
/* Define to 1 if you have the `ftruncate' function. */
#undef HAVE_FTRUNCATE
/* Define to 1 if you have the `futimesat' function. */
#undef HAVE_FUTIMESAT
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
@ -431,6 +446,9 @@
/* Define if you have the 'link' function. */
#undef HAVE_LINK
/* Define to 1 if you have the `linkat' function. */
#undef HAVE_LINKAT
/* Define to 1 if you have the <linux/netlink.h> header file. */
#undef HAVE_LINUX_NETLINK_H
@ -461,12 +479,21 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkdirat' function. */
#undef HAVE_MKDIRAT
/* Define to 1 if you have the `mkfifo' function. */
#undef HAVE_MKFIFO
/* Define to 1 if you have the `mkfifoat' function. */
#undef HAVE_MKFIFOAT
/* Define to 1 if you have the `mknod' function. */
#undef HAVE_MKNOD
/* Define to 1 if you have the `mknodat' function. */
#undef HAVE_MKNODAT
/* Define to 1 if you have the `mktime' function. */
#undef HAVE_MKTIME
@ -485,6 +512,9 @@
/* Define to 1 if you have the `nice' function. */
#undef HAVE_NICE
/* Define to 1 if you have the `openat' function. */
#undef HAVE_OPENAT
/* Define to 1 if you have the `openpty' function. */
#undef HAVE_OPENPTY
@ -500,6 +530,9 @@
/* Define if the OS supports pipe2() */
#undef HAVE_PIPE2
/* Define if the OS supports pipe2() */
#undef HAVE_PIPE2
/* Define to 1 if you have the `plock' function. */
#undef HAVE_PLOCK
@ -536,9 +569,15 @@
/* Define to 1 if you have the `readlink' function. */
#undef HAVE_READLINK
/* Define to 1 if you have the `readlinkat' function. */
#undef HAVE_READLINKAT
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
/* Define to 1 if you have the `renameat' function. */
#undef HAVE_RENAMEAT
/* Define if you have readline 2.1 */
#undef HAVE_RL_CALLBACK
@ -724,6 +763,9 @@
/* Define if you have the 'symlink' function. */
#undef HAVE_SYMLINK
/* Define to 1 if you have the `symlinkat' function. */
#undef HAVE_SYMLINKAT
/* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF
@ -866,6 +908,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `unlinkat' function. */
#undef HAVE_UNLINKAT
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
@ -877,6 +922,9 @@
/* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H
/* Define to 1 if you have the `utimensat' function. */
#undef HAVE_UTIMENSAT
/* Define to 1 if you have the `utimes' function. */
#undef HAVE_UTIMES