Commits

Ross Lagerwall  committed 525320d

Issue #10812: Add some extra posix functions to the os module.

  • Participants
  • Parent commits bbab0db

Comments (0)

Files changed (7)

File Doc/library/os.rst

    .. versionadded:: 3.3
 
 
+.. function:: fexecve(fd, args, env)
+
+   Execute the program specified by a file descriptor *fd* with arguments given
+   by *args* and environment given by *env*, replacing the current process.
+   *args* and *env* are given as in :func:`execve`.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. function:: fpathconf(fd, name)
 
    Return system configuration information relevant to an open file. *name*
    .. versionadded:: 3.3
 
 
+.. function:: futimens(fd, (atime_sec, atime_nsec), (mtime_sec, mtime_nsec))
+              futimens(fd, None, None)
+
+   Updates the timestamps of a file specified by the file descriptor *fd*, 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.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. data:: UTIME_NOW
+          UTIME_OMIT
+
+   Flags used with :func:`futimens` to specify that the timestamp must be
+   updated either to the current time or not updated at all.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. function:: futimes(fd, (atime, mtime))
+              futimes(fd, None)
+
+   Set the access and modified time of the file specified by the file
+   descriptor *fd* to the given values. If the second form is used, set the
+   access and modified times to the current time.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. function:: isatty(fd)
 
    Return ``True`` if the file descriptor *fd* is open and connected to a
    .. versionadded:: 3.3
 
 
+.. function:: lockf(fd, cmd, len)
+
+   Apply, test or remove a POSIX lock on an open file descriptor.
+   *fd* is an open file descriptor.
+   *cmd* specifies the command to use - one of :data:`F_LOCK`, :data:`F_TLOCK`,
+   :data:`F_ULOCK` or :data:`F_TEST`.
+   *len* specifies the section of the file to lock.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. data:: F_LOCK
+          F_TLOCK
+          F_ULOCK
+          F_TEST
+
+   Flags that specify what action :func:`lockf` will take.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
 .. function:: lseek(fd, pos, how)
 
    Set the current position of file descriptor *fd* to position *pos*, modified
    Availability: Unix, Windows.
 
 
+.. function:: posix_fallocate(fd, offset, len)
+
+   Ensures that enough disk space is allocated for the file specified by *fd*
+   starting from *offset* and continuing for *len* bytes.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. function:: posix_fadvise(fd, offset, len, advice)
+
+   Announces an intention to access data in a specific pattern thus allowing
+   the kernel to make optimizations.
+   The advice applies to the region of the file specified by *fd* starting at
+   *offset* and continuing for *len* bytes.
+   *advice* is one of :data:`POSIX_FADV_NORMAL`, :data:`POSIX_FADV_SEQUENTIAL`,
+   :data:`POSIX_FADV_RANDOM`, :data:`POSIX_FADV_NOREUSE`,
+   :data:`POSIX_FADV_WILLNEED` or :data:`POSIX_FADV_DONTNEED`.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. data:: POSIX_FADV_NORMAL
+          POSIX_FADV_SEQUENTIAL
+          POSIX_FADV_RANDOM
+          POSIX_FADV_NOREUSE
+          POSIX_FADV_WILLNEED
+          POSIX_FADV_DONTNEED
+
+   Flags that can be used in *advice* in :func:`posix_fadvise` that specify
+   the access pattern that is likely to be used.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. function:: pread(fd, buffersize, offset)
+
+   Read from a file descriptor, *fd*, at a position of *offset*. It will read up
+   to *buffersize* number of bytes. The file offset remains unchanged.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. function:: pwrite(fd, string, offset)
+
+   Write *string* to a file descriptor, *fd*, from *offset*, leaving the file
+   offset unchanged.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. function:: read(fd, n)
 
    Read at most *n* bytes from file descriptor *fd*. Return a bytestring containing the
    .. versionadded:: 3.3
 
 
+.. function:: readv(fd, buffers)
+
+   Read from a file descriptor into a number of writable buffers. *buffers* is
+   an arbitrary sequence of writable buffers. Returns the total number of bytes
+   read.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. function:: tcgetpgrp(fd)
 
    Return the process group associated with the terminal given by *fd* (an open
       :meth:`~file.write` method.
 
 
+.. function:: writev(fd, buffers)
+
+   Write the the contents of *buffers* to file descriptor *fd*, where *buffers*
+   is an arbitrary sequence of buffers.
+   Returns the total number of bytes written.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. _open-constants:
 
 ``open()`` flag constants
       Added support for Windows 6.0 (Vista) symbolic links.
 
 
+.. function:: lutimes(path, (atime, mtime))
+              lutimes(path, None)
+
+   Like :func:`utime`, but if *path* is a symbolic link, it is not
+   dereferenced.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. function:: mkfifo(path[, mode])
 
    Create a FIFO (a named pipe) named *path* with numeric mode *mode*.  The
       Added support for Windows 6.0 (Vista) symbolic links.
 
 
+.. function:: sync()
+
+   Force write of everything to disk.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. function:: truncate(path, length)
+
+   Truncate the file corresponding to *path*, so that it is at most
+   *length* bytes in size.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. function:: unlink(path)
 
    Remove (delete) the file *path*.  This is the same function as
 
    Availability: Unix.
 
+.. function:: waitid(idtype, id, options)
+
+   Wait for the completion of one or more child processes.
+   *idtype* can be :data:`P_PID`, :data:`P_PGID` or :data:`P_ALL`.
+   *id* specifies the pid to wait on.
+   *options* is constructed from the ORing of one or more of :data:`WEXITED`,
+   :data:`WSTOPPED` or :data:`WCONTINUED` and additionally may be ORed with
+   :data:`WNOHANG` or :data:`WNOWAIT`. The return value is an object
+   representing the data contained in the :c:type:`siginfo_t` structure, namely:
+   :attr:`si_pid`, :attr:`si_uid`, :attr:`si_signo`, :attr:`si_status`,
+   :attr:`si_code` or ``None`` if :data:`WNOHANG` is specified and there are no
+   children in a waitable state.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+.. data:: P_PID
+          P_PGID
+          P_ALL
+
+   These are the possible values for *idtype* in :func:`waitid`. They affect
+   how *id* is interpreted.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+.. data:: WEXITED
+          WSTOPPED
+          WNOWAIT
+
+   Flags that can be used in *options* in :func:`waitid` that specify what
+   child signal to wait for.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
+.. data:: CLD_EXITED
+          CLD_DUMPED
+          CLD_TRAPPED
+          CLD_CONTINUED
+
+   These are the possible values for :attr:`si_code` in the result returned by
+   :func:`waitid`.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
 
 .. function:: waitpid(pid, options)
 

File Lib/test/test_posix.py

         NO_ARG_FUNCTIONS = [ "ctermid", "getcwd", "getcwdb", "uname",
                              "times", "getloadavg",
                              "getegid", "geteuid", "getgid", "getgroups",
-                             "getpid", "getpgrp", "getppid", "getuid",
+                             "getpid", "getpgrp", "getppid", "getuid", "sync",
                            ]
 
         for name in NO_ARG_FUNCTIONS:
             finally:
                 fp.close()
 
+    @unittest.skipUnless(hasattr(posix, 'truncate'), "test needs posix.truncate()")
+    def test_truncate(self):
+        with open(support.TESTFN, 'w') as fp:
+            fp.write('test')
+            fp.flush()
+        posix.truncate(support.TESTFN, 0)
+
+    @unittest.skipUnless(hasattr(posix, 'fexecve'), "test needs posix.fexecve()")
+    @unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
+    @unittest.skipUnless(hasattr(os, 'wait'), "test needs os.wait()")
+    def test_fexecve(self):
+        fp = os.open(sys.executable, os.O_RDONLY)
+        try:
+            pid = os.fork()
+            if pid == 0:
+                os.chdir(os.path.split(sys.executable)[0])
+                posix.fexecve(fp, [sys.executable, '-c', 'pass'], os.environ)
+            else:
+                self.assertEqual(os.wait(), (pid, 0))
+        finally:
+            os.close(fp)
+
+    @unittest.skipUnless(hasattr(posix, 'waitid'), "test needs posix.waitid()")
+    @unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
+    def test_waitid(self):
+        pid = os.fork()
+        if pid == 0:
+            os.chdir(os.path.split(sys.executable)[0])
+            posix.execve(sys.executable, [sys.executable, '-c', 'pass'], os.environ)
+        else:
+            res = posix.waitid(posix.P_PID, pid, posix.WEXITED)
+            self.assertEqual(pid, res.si_pid)
+
+    @unittest.skipUnless(hasattr(posix, 'lockf'), "test needs posix.lockf()")
+    def test_lockf(self):
+        fd = os.open(support.TESTFN, os.O_WRONLY | os.O_CREAT)
+        try:
+            os.write(fd, b'test')
+            os.lseek(fd, 0, os.SEEK_SET)
+            posix.lockf(fd, posix.F_LOCK, 4)
+            # section is locked
+            posix.lockf(fd, posix.F_ULOCK, 4)
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'pread'), "test needs posix.pread()")
+    def test_pread(self):
+        fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
+        try:
+            os.write(fd, b'test')
+            os.lseek(fd, 0, os.SEEK_SET)
+            self.assertEqual(b'es', posix.pread(fd, 2, 1))
+            # the first pread() shoudn't disturb the file offset
+            self.assertEqual(b'te', posix.read(fd, 2))
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'pwrite'), "test needs posix.pwrite()")
+    def test_pwrite(self):
+        fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
+        try:
+            os.write(fd, b'test')
+            os.lseek(fd, 0, os.SEEK_SET)
+            posix.pwrite(fd, b'xx', 1)
+            self.assertEqual(b'txxt', posix.read(fd, 4))
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'posix_fallocate'),
+        "test needs posix.posix_fallocate()")
+    def test_posix_fallocate(self):
+        fd = os.open(support.TESTFN, os.O_WRONLY | os.O_CREAT)
+        try:
+            posix.posix_fallocate(fd, 0, 10)
+        except OSError as inst:
+            # issue10812, ZFS doesn't appear to support posix_fallocate,
+            # so skip Solaris-based since they are likely to have ZFS.
+            if inst.errno != errno.EINVAL or not sys.platform.startswith("sunos"):
+                raise
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'posix_fadvise'),
+        "test needs posix.posix_fadvise()")
+    def test_posix_fadvise(self):
+        fd = os.open(support.TESTFN, os.O_RDONLY)
+        try:
+            posix.posix_fadvise(fd, 0, 0, posix.POSIX_FADV_WILLNEED)
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'futimes'), "test needs posix.futimes()")
+    def test_futimes(self):
+        now = time.time()
+        fd = os.open(support.TESTFN, os.O_RDONLY)
+        try:
+            posix.futimes(fd, None)
+            self.assertRaises(TypeError, posix.futimes, fd, (None, None))
+            self.assertRaises(TypeError, posix.futimes, fd, (now, None))
+            self.assertRaises(TypeError, posix.futimes, fd, (None, now))
+            posix.futimes(fd, (int(now), int(now)))
+            posix.futimes(fd, (now, now))
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'lutimes'), "test needs posix.lutimes()")
+    def test_lutimes(self):
+        now = time.time()
+        posix.lutimes(support.TESTFN, None)
+        self.assertRaises(TypeError, posix.lutimes, support.TESTFN, (None, None))
+        self.assertRaises(TypeError, posix.lutimes, support.TESTFN, (now, None))
+        self.assertRaises(TypeError, posix.lutimes, support.TESTFN, (None, now))
+        posix.lutimes(support.TESTFN, (int(now), int(now)))
+        posix.lutimes(support.TESTFN, (now, now))
+
+    @unittest.skipUnless(hasattr(posix, 'futimens'), "test needs posix.futimens()")
+    def test_futimens(self):
+        now = time.time()
+        fd = os.open(support.TESTFN, os.O_RDONLY)
+        try:
+            self.assertRaises(TypeError, posix.futimens, fd, (None, None), (None, None))
+            self.assertRaises(TypeError, posix.futimens, fd, (now, 0), None)
+            self.assertRaises(TypeError, posix.futimens, fd, None, (now, 0))
+            posix.futimens(fd, (int(now), int((now - int(now)) * 1e9)),
+                    (int(now), int((now - int(now)) * 1e9)))
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'writev'), "test needs posix.writev()")
+    def test_writev(self):
+        fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
+        try:
+            os.writev(fd, (b'test1', b'tt2', b't3'))
+            os.lseek(fd, 0, os.SEEK_SET)
+            self.assertEqual(b'test1tt2t3', posix.read(fd, 10))
+        finally:
+            os.close(fd)
+
+    @unittest.skipUnless(hasattr(posix, 'readv'), "test needs posix.readv()")
+    def test_readv(self):
+        fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
+        try:
+            os.write(fd, b'test1tt2t3')
+            os.lseek(fd, 0, os.SEEK_SET)
+            buf = [bytearray(i) for i in [5, 3, 2]]
+            self.assertEqual(posix.readv(fd, buf), 10)
+            self.assertEqual([b'test1', b'tt2', b't3'], [bytes(i) for i in buf])
+        finally:
+            os.close(fd)
+
     def test_dup(self):
         if hasattr(posix, 'dup'):
             fp = open(support.TESTFN)
 Library
 -------
 
+- Issue #10812: Add some extra posix functions to the os module.
 
 - Issue #10979: unittest stdout buffering now works with class and module
   setup and teardown.

File Modules/posixmodule.c

     10
 };
 
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+PyDoc_STRVAR(waitid_result__doc__,
+"waitid_result: Result from waitid.\n\n\
+This object may be accessed either as a tuple of\n\
+  (si_pid, si_uid, si_signo, si_status, si_code),\n\
+or via the attributes si_pid, si_uid, and so on.\n\
+\n\
+See os.waitid for more information.");
+
+static PyStructSequence_Field waitid_result_fields[] = {
+    {"si_pid",  },
+    {"si_uid", },
+    {"si_signo", },
+    {"si_status",  },
+    {"si_code", },
+    {0}
+};
+
+static PyStructSequence_Desc waitid_result_desc = {
+    "waitid_result", /* name */
+    waitid_result__doc__, /* doc */
+    waitid_result_fields,
+    5
+};
+static PyTypeObject WaitidResultType;
+#endif
+
 static int initialized;
 static PyTypeObject StatResultType;
 static PyTypeObject StatVFSResultType;
 }
 #endif /* HAVE_FSYNC */
 
+#ifdef HAVE_SYNC
+PyDoc_STRVAR(posix_sync__doc__,
+"sync()\n\n\
+Force write of everything to disk.");
+
+static PyObject *
+posix_sync(PyObject *self, PyObject *noargs)
+{
+    Py_BEGIN_ALLOW_THREADS
+    sync();
+    Py_END_ALLOW_THREADS
+    Py_RETURN_NONE;
+}
+#endif
+
 #ifdef HAVE_FDATASYNC
 
 #ifdef __hpux
 #endif /* MS_WINDOWS */
 }
 
+#ifdef HAVE_FUTIMES
+PyDoc_STRVAR(posix_futimes__doc__,
+"futimes(fd, (atime, mtime))\n\
+futimes(fd, None)\n\n\
+Set the access and modified time of the file specified by the file\n\
+descriptor fd to the given values. If the second form is used, set the\n\
+access and modified times to the current time.");
+
+static PyObject *
+posix_futimes(PyObject *self, PyObject *args)
+{
+    int res, fd;
+    PyObject* arg;
+    struct timeval buf[2];
+    long ausec, musec;
+
+    if (!PyArg_ParseTuple(args, "iO:futimes", &fd, &arg))
+        return NULL;
+
+    if (arg == Py_None) {
+        /* optional time values not given */
+        Py_BEGIN_ALLOW_THREADS
+        res = futimes(fd, NULL);
+        Py_END_ALLOW_THREADS
+    }
+    else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
+        PyErr_SetString(PyExc_TypeError,
+                "futimes() arg 2 must be a tuple (atime, mtime)");
+        return NULL;
+    }
+    else {
+        if (extract_time(PyTuple_GET_ITEM(arg, 0),
+                &(buf[0].tv_sec), &ausec) == -1) {
+            return NULL;
+        }
+        if (extract_time(PyTuple_GET_ITEM(arg, 1),
+                &(buf[1].tv_sec), &musec) == -1) {
+            return NULL;
+        }
+        buf[0].tv_usec = ausec;
+        buf[1].tv_usec = musec;
+        Py_BEGIN_ALLOW_THREADS
+        res = futimes(fd, buf);
+        Py_END_ALLOW_THREADS
+    }
+    if (res < 0)
+        return posix_error();
+    Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_LUTIMES
+PyDoc_STRVAR(posix_lutimes__doc__,
+"lutimes(path, (atime, mtime))\n\
+lutimes(path, None)\n\n\
+Like utime(), but if path is a symbolic link, it is not dereferenced.");
+
+static PyObject *
+posix_lutimes(PyObject *self, PyObject *args)
+{
+    PyObject *opath, *arg;
+    const char *path;
+    int res;
+    struct timeval buf[2];
+    long ausec, musec;
+
+    if (!PyArg_ParseTuple(args, "O&O:lutimes",
+            PyUnicode_FSConverter, &opath, &arg))
+        return NULL;
+    path = PyBytes_AsString(opath);
+    if (arg == Py_None) {
+        /* optional time values not given */
+        Py_BEGIN_ALLOW_THREADS
+        res = lutimes(path, NULL);
+        Py_END_ALLOW_THREADS
+    }
+    else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
+        PyErr_SetString(PyExc_TypeError,
+            "lutimes() arg 2 must be a tuple (atime, mtime)");
+        Py_DECREF(opath);
+        return NULL;
+    }
+    else {
+        if (extract_time(PyTuple_GET_ITEM(arg, 0),
+                &(buf[0].tv_sec), &ausec) == -1) {
+            Py_DECREF(opath);
+            return NULL;
+        }
+        if (extract_time(PyTuple_GET_ITEM(arg, 1),
+                &(buf[1].tv_sec), &musec) == -1) {
+            Py_DECREF(opath);
+            return NULL;
+        }
+        buf[0].tv_usec = ausec;
+        buf[1].tv_usec = musec;
+        Py_BEGIN_ALLOW_THREADS
+        res = lutimes(path, buf);
+        Py_END_ALLOW_THREADS
+    }
+    Py_DECREF(opath);
+    if (res < 0)
+        return posix_error();
+    Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_FUTIMENS
+PyDoc_STRVAR(posix_futimens__doc__,
+"futimens(fd, (atime_sec, atime_nsec), (mtime_sec, mtime_nsec))\n\
+futimens(fd, None, None)\n\n\
+Updates the timestamps of a file specified by the file descriptor fd, with\n\
+nanosecond precision.\n\
+The second form sets atime and mtime to the current time.\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_futimens(PyObject *self, PyObject *args)
+{
+    int res, fd;
+    PyObject *atime, *mtime;
+    struct timespec buf[2];
+
+    if (!PyArg_ParseTuple(args, "iOO:futimens",
+            &fd, &atime, &mtime))
+        return NULL;
+    if (atime == Py_None && mtime == Py_None) {
+        /* optional time values not given */
+        Py_BEGIN_ALLOW_THREADS
+        res = futimens(fd, NULL);
+        Py_END_ALLOW_THREADS
+    }
+    else if (!PyTuple_Check(atime) || PyTuple_Size(atime) != 2) {
+        PyErr_SetString(PyExc_TypeError,
+            "futimens() arg 2 must be a tuple (atime_sec, atime_nsec)");
+        return NULL;
+    }
+    else if (!PyTuple_Check(mtime) || PyTuple_Size(mtime) != 2) {
+        PyErr_SetString(PyExc_TypeError,
+            "futimens() arg 3 must be a tuple (mtime_sec, mtime_nsec)");
+        return NULL;
+    }
+    else {
+        if (!PyArg_ParseTuple(atime, "ll:futimens",
+                &(buf[0].tv_sec), &(buf[0].tv_nsec))) {
+            return NULL;
+        }
+        if (!PyArg_ParseTuple(mtime, "ll:futimens",
+                &(buf[1].tv_sec), &(buf[1].tv_nsec))) {
+            return NULL;
+        }
+        Py_BEGIN_ALLOW_THREADS
+        res = futimens(fd, buf);
+        Py_END_ALLOW_THREADS
+    }
+    if (res < 0)
+        return posix_error();
+    Py_RETURN_NONE;
+}
+#endif
 
 /* Process operations */
 
 }
 #endif
 
-
-#ifdef HAVE_EXECV
-PyDoc_STRVAR(posix_execv__doc__,
-"execv(path, args)\n\n\
-Execute an executable path with arguments, replacing current process.\n\
-\n\
-    path: path of executable file\n\
-    args: tuple or list of strings");
-
-static PyObject *
-posix_execv(PyObject *self, PyObject *args)
-{
-    PyObject *opath;
-    char *path;
-    PyObject *argv;
-    char **argvlist;
-    Py_ssize_t i, argc;
-    PyObject *(*getitem)(PyObject *, Py_ssize_t);
-
-    /* execv has two arguments: (path, argv), where
-       argv is a list or tuple of strings. */
-
-    if (!PyArg_ParseTuple(args, "O&O:execv",
-                          PyUnicode_FSConverter,
-                          &opath, &argv))
-        return NULL;
-    path = PyBytes_AsString(opath);
-    if (PyList_Check(argv)) {
-        argc = PyList_Size(argv);
-        getitem = PyList_GetItem;
-    }
-    else if (PyTuple_Check(argv)) {
-        argc = PyTuple_Size(argv);
-        getitem = PyTuple_GetItem;
-    }
-    else {
-        PyErr_SetString(PyExc_TypeError, "execv() arg 2 must be a tuple or list");
-        Py_DECREF(opath);
-        return NULL;
-    }
-    if (argc < 1) {
-        PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
-        Py_DECREF(opath);
-        return NULL;
-    }
-
-    argvlist = PyMem_NEW(char *, argc+1);
-    if (argvlist == NULL) {
-        Py_DECREF(opath);
-        return PyErr_NoMemory();
-    }
-    for (i = 0; i < argc; i++) {
-        if (!fsconvert_strdup((*getitem)(argv, i),
-                              &argvlist[i])) {
-            free_string_array(argvlist, i);
-            PyErr_SetString(PyExc_TypeError,
-                            "execv() arg 2 must contain only strings");
-            Py_DECREF(opath);
-            return NULL;
-
-        }
-    }
-    argvlist[argc] = NULL;
-
-    execv(path, argvlist);
-
-    /* If we get here it's definitely an error */
-
-    free_string_array(argvlist, argc);
-    Py_DECREF(opath);
-    return posix_error();
-}
-
+#if defined(HAVE_EXECV) || defined (HAVE_FEXECVE)
 static char**
 parse_envlist(PyObject* env, Py_ssize_t *envc_ptr)
 {
     return NULL;
 }
 
+static char**
+parse_arglist(PyObject* argv, Py_ssize_t *argc)
+{
+    int i;
+    char **argvlist = PyMem_NEW(char *, *argc+1);
+    if (argvlist == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    for (i = 0; i < *argc; i++) {
+        if (!fsconvert_strdup(PySequence_ITEM(argv, i),
+                              &argvlist[i]))
+        {
+            *argc = i;
+            goto fail;
+        }
+    }
+    argvlist[*argc] = NULL;
+    return argvlist;
+fail:
+    free_string_array(argvlist, *argc);
+    return NULL;
+}
+#endif
+
+#ifdef HAVE_EXECV
+PyDoc_STRVAR(posix_execv__doc__,
+"execv(path, args)\n\n\
+Execute an executable path with arguments, replacing current process.\n\
+\n\
+    path: path of executable file\n\
+    args: tuple or list of strings");
+
+static PyObject *
+posix_execv(PyObject *self, PyObject *args)
+{
+    PyObject *opath;
+    char *path;
+    PyObject *argv;
+    char **argvlist;
+    Py_ssize_t argc;
+
+    /* execv has two arguments: (path, argv), where
+       argv is a list or tuple of strings. */
+
+    if (!PyArg_ParseTuple(args, "O&O:execv",
+                          PyUnicode_FSConverter,
+                          &opath, &argv))
+        return NULL;
+    path = PyBytes_AsString(opath);
+    if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "execv() arg 2 must be a tuple or list");
+        Py_DECREF(opath);
+        return NULL;
+    }
+    argc = PySequence_Size(argv);
+    if (argc < 1) {
+        PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
+        Py_DECREF(opath);
+        return NULL;
+    }
+
+    argvlist = parse_arglist(argv, &argc);
+    if (argvlist == NULL) {
+        Py_DECREF(opath);
+        return NULL;
+    }
+
+    execv(path, argvlist);
+
+    /* If we get here it's definitely an error */
+
+    free_string_array(argvlist, argc);
+    Py_DECREF(opath);
+    return posix_error();
+}
+
 PyDoc_STRVAR(posix_execve__doc__,
 "execve(path, args, env)\n\n\
 Execute a path with arguments and environment, replacing current process.\n\
     PyObject *argv, *env;
     char **argvlist;
     char **envlist;
-    Py_ssize_t i, argc, envc;
-    PyObject *(*getitem)(PyObject *, Py_ssize_t);
-    Py_ssize_t lastarg = 0;
+    Py_ssize_t argc, envc;
 
     /* execve has three arguments: (path, argv, env), where
        argv is a list or tuple of strings and env is a dictionary
                           &opath, &argv, &env))
         return NULL;
     path = PyBytes_AsString(opath);
-    if (PyList_Check(argv)) {
-        argc = PyList_Size(argv);
-        getitem = PyList_GetItem;
-    }
-    else if (PyTuple_Check(argv)) {
-        argc = PyTuple_Size(argv);
-        getitem = PyTuple_GetItem;
-    }
-    else {
+    if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
         PyErr_SetString(PyExc_TypeError,
                         "execve() arg 2 must be a tuple or list");
         goto fail_0;
     }
+    argc = PySequence_Size(argv);
     if (!PyMapping_Check(env)) {
         PyErr_SetString(PyExc_TypeError,
                         "execve() arg 3 must be a mapping object");
         goto fail_0;
     }
 
-    argvlist = PyMem_NEW(char *, argc+1);
+    argvlist = parse_arglist(argv, &argc);
     if (argvlist == NULL) {
-        PyErr_NoMemory();
         goto fail_0;
     }
-    for (i = 0; i < argc; i++) {
-        if (!fsconvert_strdup((*getitem)(argv, i),
-                              &argvlist[i]))
-        {
-            lastarg = i;
-            goto fail_1;
-        }
-    }
-    lastarg = argc;
-    argvlist[argc] = NULL;
 
     envlist = parse_envlist(env, &envc);
     if (envlist == NULL)
         PyMem_DEL(envlist[envc]);
     PyMem_DEL(envlist);
   fail_1:
-    free_string_array(argvlist, lastarg);
+    free_string_array(argvlist, argc);
   fail_0:
     Py_DECREF(opath);
     return NULL;
 }
 #endif /* HAVE_EXECV */
 
+#ifdef HAVE_FEXECVE
+PyDoc_STRVAR(posix_fexecve__doc__,
+"fexecve(fd, args, env)\n\n\
+Execute the program specified by a file descriptor with arguments and\n\
+environment, replacing the current process.\n\
+\n\
+    fd: file descriptor of executable\n\
+    args: tuple or list of arguments\n\
+    env: dictionary of strings mapping to strings");
+
+static PyObject *
+posix_fexecve(PyObject *self, PyObject *args)
+{
+    int fd;
+    PyObject *argv, *env;
+    char **argvlist;
+    char **envlist;
+    Py_ssize_t argc, envc;
+
+    if (!PyArg_ParseTuple(args, "iOO:fexecve",
+                          &fd, &argv, &env))
+        return NULL;
+    if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "fexecve() arg 2 must be a tuple or list");
+        return NULL;
+    }
+    argc = PySequence_Size(argv);
+    if (!PyMapping_Check(env)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "fexecve() arg 3 must be a mapping object");
+        return NULL;
+    }
+
+    argvlist = parse_arglist(argv, &argc);
+    if (argvlist == NULL)
+        return NULL;
+
+    envlist = parse_envlist(env, &envc);
+    if (envlist == NULL)
+        goto fail;
+
+    fexecve(fd, argvlist, envlist);
+
+    /* If we get here it's definitely an error */
+
+    (void) posix_error();
+
+    while (--envc >= 0)
+        PyMem_DEL(envlist[envc]);
+    PyMem_DEL(envlist);
+  fail:
+    free_string_array(argvlist, argc);
+    return NULL;
+}
+#endif /* HAVE_FEXECVE */
 
 #ifdef HAVE_SPAWNV
 PyDoc_STRVAR(posix_spawnv__doc__,
 }
 #endif
 
+
 #ifdef HAVE_GETEGID
 PyDoc_STRVAR(posix_getegid__doc__,
 "getegid() -> egid\n\n\
 }
 #endif /* HAVE_WAIT4 */
 
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+PyDoc_STRVAR(posix_waitid__doc__,
+"waitid(idtype, id, options) -> waitid_result\n\n\
+Wait for the completion of one or more child processes.\n\n\
+idtype can be P_PID, P_PGID or P_ALL.\n\
+id specifies the pid to wait on.\n\
+options is constructed from the ORing of one or more of WEXITED, WSTOPPED\n\
+or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.\n\
+Returns either waitid_result or None if WNOHANG is specified and there are\n\
+no children in a waitable state.");
+
+static PyObject *
+posix_waitid(PyObject *self, PyObject *args)
+{
+    PyObject *result;
+    idtype_t idtype;
+    id_t id;
+    int options, res;
+    siginfo_t si;
+    si.si_pid = 0;
+    if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID "i:waitid", &idtype, &id, &options))
+        return NULL;
+    Py_BEGIN_ALLOW_THREADS
+    res = waitid(idtype, id, &si, options);
+    Py_END_ALLOW_THREADS
+    if (res == -1)
+        return posix_error();
+
+    if (si.si_pid == 0)
+        Py_RETURN_NONE;
+
+    result = PyStructSequence_New(&WaitidResultType);
+    if (!result)
+        return NULL;
+
+    PyStructSequence_SET_ITEM(result, 0, PyLong_FromPid(si.si_pid));
+    PyStructSequence_SET_ITEM(result, 1, PyLong_FromPid(si.si_uid));
+    PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong((long)(si.si_signo)));
+    PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong((long)(si.si_status)));
+    PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong((long)(si.si_code)));
+    if (PyErr_Occurred()) {
+        Py_DECREF(result);
+        return NULL;
+    }
+
+    return result;
+}
+#endif
+
 #ifdef HAVE_WAITPID
 PyDoc_STRVAR(posix_waitpid__doc__,
 "waitpid(pid, options) -> (pid, status)\n\n\
     return Py_None;
 }
 
+#ifdef HAVE_LOCKF
+PyDoc_STRVAR(posix_lockf__doc__,
+"lockf(fd, cmd, len)\n\n\
+Apply, test or remove a POSIX lock on an open file descriptor.\n\n\
+fd is an open file descriptor.\n\
+cmd specifies the command to use - one of F_LOCK, F_TLOCK, F_ULOCK or\n\
+F_TEST.\n\
+len specifies the section of the file to lock.");
+
+static PyObject *
+posix_lockf(PyObject *self, PyObject *args)
+{
+    int fd, cmd, res;
+    off_t len;
+    if (!PyArg_ParseTuple(args, "iiO&:lockf",
+            &fd, &cmd, _parse_off_t, &len))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    res = lockf(fd, cmd, len);
+    Py_END_ALLOW_THREADS
+
+    if (res < 0)
+        return posix_error();
+
+    Py_RETURN_NONE;
+}
+#endif
+
 
 PyDoc_STRVAR(posix_lseek__doc__,
 "lseek(fd, pos, how) -> newpos\n\n\
 #else
     off_t pos, res;
 #endif
-    PyObject *posobj;
-    if (!PyArg_ParseTuple(args, "iOi:lseek", &fd, &posobj, &how))
+    if (!PyArg_ParseTuple(args, "iO&i:lseek", &fd, _parse_off_t, &pos, &how))
         return NULL;
 #ifdef SEEK_SET
     /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
     }
 #endif /* SEEK_END */
 
-#if !defined(HAVE_LARGEFILE_SUPPORT)
-    pos = PyLong_AsLong(posobj);
-#else
-    pos = PyLong_AsLongLong(posobj);
-#endif
     if (PyErr_Occurred())
         return NULL;
 
     return buffer;
 }
 
-
-PyDoc_STRVAR(posix_write__doc__,
-"write(fd, string) -> byteswritten\n\n\
-Write a string to a file descriptor.");
-
-static PyObject *
-posix_write(PyObject *self, PyObject *args)
-{
-    Py_buffer pbuf;
-    int fd;
-    Py_ssize_t size, len;
-
-    if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf))
-        return NULL;
-    if (!_PyVerify_fd(fd)) {
-        PyBuffer_Release(&pbuf);
-        return posix_error();
-    }
-    len = pbuf.len;
-    Py_BEGIN_ALLOW_THREADS
-#if defined(MS_WIN64) || defined(MS_WINDOWS)
-    if (len > INT_MAX)
-        len = INT_MAX;
-    size = write(fd, pbuf.buf, (int)len);
-#else
-    size = write(fd, pbuf.buf, len);
-#endif
-    Py_END_ALLOW_THREADS
-    PyBuffer_Release(&pbuf);
-    if (size < 0)
-        return posix_error();
-    return PyLong_FromSsize_t(size);
-}
-
-#ifdef HAVE_SENDFILE
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
+#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
+    || defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
 static Py_ssize_t
 iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type)
 {
 }
 #endif
 
+#ifdef HAVE_READV
+PyDoc_STRVAR(posix_readv__doc__,
+"readv(fd, buffers) -> bytesread\n\n\
+Read from a file descriptor into a number of writable buffers. buffers\n\
+is an arbitrary sequence of writable buffers.\n\
+Returns the total number of bytes read.");
+
+static PyObject *
+posix_readv(PyObject *self, PyObject *args)
+{
+    int fd, cnt;
+    Py_ssize_t n;
+    PyObject *seq;
+    struct iovec *iov;
+    Py_buffer *buf;
+
+    if (!PyArg_ParseTuple(args, "iO:readv", &fd, &seq))
+        return NULL;
+    if (!PySequence_Check(seq)) {
+        PyErr_SetString(PyExc_TypeError,
+            "readv() arg 2 must be a sequence");
+        return NULL;
+    }
+    cnt = PySequence_Size(seq);
+
+    if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    n = readv(fd, iov, cnt);
+    Py_END_ALLOW_THREADS
+
+    iov_cleanup(iov, buf, cnt);
+    return PyLong_FromSsize_t(n);
+}
+#endif
+
+#ifdef HAVE_PREAD
+PyDoc_STRVAR(posix_pread__doc__,
+"pread(fd, buffersize, offset) -> string\n\n\
+Read from a file descriptor, fd, at a position of offset. It will read up\n\
+to buffersize number of bytes. The file offset remains unchanged.");
+
+static PyObject *
+posix_pread(PyObject *self, PyObject *args)
+{
+    int fd, size;
+    off_t offset;
+    Py_ssize_t n;
+    PyObject *buffer;
+    if (!PyArg_ParseTuple(args, "iiO&:pread", &fd, &size, _parse_off_t, &offset))
+        return NULL;
+
+    if (size < 0) {
+        errno = EINVAL;
+        return posix_error();
+    }
+    buffer = PyBytes_FromStringAndSize((char *)NULL, size);
+    if (buffer == NULL)
+        return NULL;
+    if (!_PyVerify_fd(fd)) {
+        Py_DECREF(buffer);
+        return posix_error();
+    }
+    Py_BEGIN_ALLOW_THREADS
+    n = pread(fd, PyBytes_AS_STRING(buffer), size, offset);
+    Py_END_ALLOW_THREADS
+    if (n < 0) {
+        Py_DECREF(buffer);
+        return posix_error();
+    }
+    if (n != size)
+        _PyBytes_Resize(&buffer, n);
+    return buffer;
+}
+#endif
+
+PyDoc_STRVAR(posix_write__doc__,
+"write(fd, string) -> byteswritten\n\n\
+Write a string to a file descriptor.");
+
+static PyObject *
+posix_write(PyObject *self, PyObject *args)
+{
+    Py_buffer pbuf;
+    int fd;
+    Py_ssize_t size, len;
+
+    if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf))
+        return NULL;
+    if (!_PyVerify_fd(fd)) {
+        PyBuffer_Release(&pbuf);
+        return posix_error();
+    }
+    len = pbuf.len;
+    Py_BEGIN_ALLOW_THREADS
+#if defined(MS_WIN64) || defined(MS_WINDOWS)
+    if (len > INT_MAX)
+        len = INT_MAX;
+    size = write(fd, pbuf.buf, (int)len);
+#else
+    size = write(fd, pbuf.buf, len);
+#endif
+    Py_END_ALLOW_THREADS
+    PyBuffer_Release(&pbuf);
+    if (size < 0)
+        return posix_error();
+    return PyLong_FromSsize_t(size);
+}
+
+#ifdef HAVE_SENDFILE
 PyDoc_STRVAR(posix_sendfile__doc__,
 "sendfile(out, in, offset, nbytes) -> byteswritten\n\
 sendfile(out, in, offset, nbytes, headers=None, trailers=None, flags=0)\n\
 }
 #endif  /* HAVE_PIPE */
 
+#ifdef HAVE_WRITEV
+PyDoc_STRVAR(posix_writev__doc__,
+"writev(fd, buffers) -> byteswritten\n\n\
+Write the contents of buffers to a file descriptor, where buffers is an\n\
+arbitrary sequence of buffers.\n\
+Returns the total bytes written.");
+
+static PyObject *
+posix_writev(PyObject *self, PyObject *args)
+{
+    int fd, cnt;
+    Py_ssize_t res;
+    PyObject *seq;
+    struct iovec *iov;
+    Py_buffer *buf;
+    if (!PyArg_ParseTuple(args, "iO:writev", &fd, &seq))
+        return NULL;
+    if (!PySequence_Check(seq)) {
+        PyErr_SetString(PyExc_TypeError,
+            "writev() arg 2 must be a sequence");
+        return NULL;
+    }
+    cnt = PySequence_Size(seq);
+
+    if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE)) {
+        return NULL;
+    }
+
+    Py_BEGIN_ALLOW_THREADS
+    res = writev(fd, iov, cnt);
+    Py_END_ALLOW_THREADS
+
+    iov_cleanup(iov, buf, cnt);
+    return PyLong_FromSsize_t(res);
+}
+#endif
+
+#ifdef HAVE_PWRITE
+PyDoc_STRVAR(posix_pwrite__doc__,
+"pwrite(fd, string, offset) -> byteswritten\n\n\
+Write string to a file descriptor, fd, from offset, leaving the file\n\
+offset unchanged.");
+
+static PyObject *
+posix_pwrite(PyObject *self, PyObject *args)
+{
+    Py_buffer pbuf;
+    int fd;
+    off_t offset;
+    Py_ssize_t size;
+
+    if (!PyArg_ParseTuple(args, "iy*O&:pwrite", &fd, &pbuf, _parse_off_t, &offset))
+        return NULL;
+
+    if (!_PyVerify_fd(fd)) {
+        PyBuffer_Release(&pbuf);
+        return posix_error();
+    }
+    Py_BEGIN_ALLOW_THREADS
+    size = pwrite(fd, pbuf.buf, (size_t)pbuf.len, offset);
+    Py_END_ALLOW_THREADS
+    PyBuffer_Release(&pbuf);
+    if (size < 0)
+        return posix_error();
+    return PyLong_FromSsize_t(size);
+}
+#endif
 
 #ifdef HAVE_MKFIFO
 PyDoc_STRVAR(posix_mkfifo__doc__,
     int fd;
     off_t length;
     int res;
-    PyObject *lenobj;
-
-    if (!PyArg_ParseTuple(args, "iO:ftruncate", &fd, &lenobj))
-        return NULL;
-
-#if !defined(HAVE_LARGEFILE_SUPPORT)
-    length = PyLong_AsLong(lenobj);
-#else
-    length = PyLong_Check(lenobj) ?
-        PyLong_AsLongLong(lenobj) : PyLong_AsLong(lenobj);
-#endif
-    if (PyErr_Occurred())
+
+    if (!PyArg_ParseTuple(args, "iO&:ftruncate", &fd, _parse_off_t, &length))
         return NULL;
 
     Py_BEGIN_ALLOW_THREADS
 }
 #endif
 
+#ifdef HAVE_TRUNCATE
+PyDoc_STRVAR(posix_truncate__doc__,
+"truncate(path, length)\n\n\
+Truncate the file given by path to length bytes.");
+
+static PyObject *
+posix_truncate(PyObject *self, PyObject *args)
+{
+    PyObject *opath;
+    const char *path;
+    off_t length;
+    int res;
+
+    if (!PyArg_ParseTuple(args, "O&O&:truncate",
+            PyUnicode_FSConverter, &opath, _parse_off_t, &length))
+        return NULL;
+    path = PyBytes_AsString(opath);
+
+    Py_BEGIN_ALLOW_THREADS
+    res = truncate(path, length);
+    Py_END_ALLOW_THREADS
+    Py_DECREF(opath);
+    if (res < 0)
+        return posix_error();
+    Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_POSIX_FALLOCATE
+PyDoc_STRVAR(posix_posix_fallocate__doc__,
+"posix_fallocate(fd, offset, len)\n\n\
+Ensures that enough disk space is allocated for the file specified by fd\n\
+starting from offset and continuing for len bytes.");
+
+static PyObject *
+posix_posix_fallocate(PyObject *self, PyObject *args)
+{
+    off_t len, offset;
+    int res, fd;
+
+    if (!PyArg_ParseTuple(args, "iO&O&:posix_fallocate",
+            &fd, _parse_off_t, &offset, _parse_off_t, &len))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    res = posix_fallocate(fd, offset, len);
+    Py_END_ALLOW_THREADS
+    if (res != 0) {
+        errno = res;
+        return posix_error();
+    }
+    Py_RETURN_NONE;
+}
+#endif
+
+#ifdef HAVE_POSIX_FADVISE
+PyDoc_STRVAR(posix_posix_fadvise__doc__,
+"posix_fadvise(fd, offset, len, advice)\n\n\
+Announces an intention to access data in a specific pattern thus allowing\n\
+the kernel to make optimizations.\n\
+The advice applies to the region of the file specified by fd starting at\n\
+offset and continuing for len bytes.\n\
+advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,\n\
+POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED or\n\
+POSIX_FADV_DONTNEED.");
+
+static PyObject *
+posix_posix_fadvise(PyObject *self, PyObject *args)
+{
+    off_t len, offset;
+    int res, fd, advice;
+
+    if (!PyArg_ParseTuple(args, "iO&O&i:posix_fadvise",
+            &fd, _parse_off_t, &offset, _parse_off_t, &len, &advice))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    res = posix_fadvise(fd, offset, len, advice);
+    Py_END_ALLOW_THREADS
+    if (res != 0) {
+        errno = res;
+        return posix_error();
+    }
+    Py_RETURN_NONE;
+}
+#endif
+
 #ifdef HAVE_PUTENV
 PyDoc_STRVAR(posix_putenv__doc__,
 "putenv(key, value)\n\n\
     {"unlink",          posix_unlink, METH_VARARGS, posix_unlink__doc__},
     {"remove",          posix_unlink, METH_VARARGS, posix_remove__doc__},
     {"utime",           posix_utime, METH_VARARGS, posix_utime__doc__},
+#ifdef HAVE_FUTIMES
+    {"futimes",         posix_futimes, METH_VARARGS, posix_futimes__doc__},
+#endif
+#ifdef HAVE_LUTIMES
+    {"lutimes",         posix_lutimes, METH_VARARGS, posix_lutimes__doc__},
+#endif
+#ifdef HAVE_FUTIMENS
+    {"futimens",        posix_futimens, METH_VARARGS, posix_futimens__doc__},
+#endif
 #ifdef HAVE_TIMES
     {"times",           posix_times, METH_NOARGS, posix_times__doc__},
 #endif /* HAVE_TIMES */
     {"execv",           posix_execv, METH_VARARGS, posix_execv__doc__},
     {"execve",          posix_execve, METH_VARARGS, posix_execve__doc__},
 #endif /* HAVE_EXECV */
+#ifdef HAVE_FEXECVE
+    {"fexecve",          posix_fexecve, METH_VARARGS, posix_fexecve__doc__},
+#endif
 #ifdef HAVE_SPAWNV
     {"spawnv",          posix_spawnv, METH_VARARGS, posix_spawnv__doc__},
     {"spawnve",         posix_spawnve, METH_VARARGS, posix_spawnve__doc__},
 #ifdef HAVE_WAIT4
     {"wait4",           posix_wait4, METH_VARARGS, posix_wait4__doc__},
 #endif /* HAVE_WAIT4 */
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+    {"waitid",          posix_waitid, METH_VARARGS, posix_waitid__doc__},
+#endif
 #if defined(HAVE_WAITPID) || defined(HAVE_CWAIT)
     {"waitpid",         posix_waitpid, METH_VARARGS, posix_waitpid__doc__},
 #endif /* HAVE_WAITPID */
     {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__},
     {"dup",             posix_dup, METH_VARARGS, posix_dup__doc__},
     {"dup2",            posix_dup2, METH_VARARGS, posix_dup2__doc__},
+#ifdef HAVE_LOCKF
+    {"lockf",           posix_lockf, METH_VARARGS, posix_lockf__doc__},
+#endif
     {"lseek",           posix_lseek, METH_VARARGS, posix_lseek__doc__},
     {"read",            posix_read, METH_VARARGS, posix_read__doc__},
+#ifdef HAVE_READV
+    {"readv",           posix_readv, METH_VARARGS, posix_readv__doc__},
+#endif
+#ifdef HAVE_PREAD
+    {"pread",           posix_pread, METH_VARARGS, posix_pread__doc__},
+#endif
     {"write",           posix_write, METH_VARARGS, posix_write__doc__},
+#ifdef HAVE_WRITEV
+    {"writev",          posix_writev, METH_VARARGS, posix_writev__doc__},
+#endif
+#ifdef HAVE_PWRITE
+    {"pwrite",          posix_pwrite, METH_VARARGS, posix_pwrite__doc__},
+#endif
 #ifdef HAVE_SENDFILE
     {"sendfile",        (PyCFunction)posix_sendfile, METH_VARARGS | METH_KEYWORDS,
                             posix_sendfile__doc__},
 #ifdef HAVE_FTRUNCATE
     {"ftruncate",       posix_ftruncate, METH_VARARGS, posix_ftruncate__doc__},
 #endif
+#ifdef HAVE_TRUNCATE
+    {"truncate",        posix_truncate, METH_VARARGS, posix_truncate__doc__},
+#endif
+#ifdef HAVE_POSIX_FALLOCATE
+    {"posix_fallocate", posix_posix_fallocate, METH_VARARGS, posix_posix_fallocate__doc__},
+#endif
+#ifdef HAVE_POSIX_FADVISE
+    {"posix_fadvise",   posix_posix_fadvise, METH_VARARGS, posix_posix_fadvise__doc__},
+#endif
 #ifdef HAVE_PUTENV
     {"putenv",          posix_putenv, METH_VARARGS, posix_putenv__doc__},
 #endif
 #ifdef HAVE_FSYNC
     {"fsync",       posix_fsync, METH_O, posix_fsync__doc__},
 #endif
+#ifdef HAVE_SYNC
+    {"sync",        posix_sync, METH_NOARGS, posix_sync__doc__},
+#endif
 #ifdef HAVE_FDATASYNC
     {"fdatasync",   posix_fdatasync,  METH_O, posix_fdatasync__doc__},
 #endif
     if (ins(d, "SF_SYNC", (long)SF_SYNC)) return -1;
 #endif
 
+    /* constants for posix_fadvise */
+#ifdef POSIX_FADV_NORMAL
+    if (ins(d, "POSIX_FADV_NORMAL", (long)POSIX_FADV_NORMAL)) return -1;
+#endif
+#ifdef POSIX_FADV_SEQUENTIAL
+    if (ins(d, "POSIX_FADV_SEQUENTIAL", (long)POSIX_FADV_SEQUENTIAL)) return -1;
+#endif
+#ifdef POSIX_FADV_RANDOM
+    if (ins(d, "POSIX_FADV_RANDOM", (long)POSIX_FADV_RANDOM)) return -1;
+#endif
+#ifdef POSIX_FADV_NOREUSE
+    if (ins(d, "POSIX_FADV_NOREUSE", (long)POSIX_FADV_NOREUSE)) return -1;
+#endif
+#ifdef POSIX_FADV_WILLNEED
+    if (ins(d, "POSIX_FADV_WILLNEED", (long)POSIX_FADV_WILLNEED)) return -1;
+#endif
+#ifdef POSIX_FADV_DONTNEED
+    if (ins(d, "POSIX_FADV_DONTNEED", (long)POSIX_FADV_DONTNEED)) return -1;
+#endif
+
+    /* constants for waitid */
+#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_WAITID)
+    if (ins(d, "P_PID", (long)P_PID)) return -1;
+    if (ins(d, "P_PGID", (long)P_PGID)) return -1;
+    if (ins(d, "P_ALL", (long)P_ALL)) return -1;
+#endif
+#ifdef WEXITED
+    if (ins(d, "WEXITED", (long)WEXITED)) return -1;
+#endif
+#ifdef WNOWAIT
+    if (ins(d, "WNOWAIT", (long)WNOWAIT)) return -1;
+#endif
+#ifdef WSTOPPED
+    if (ins(d, "WSTOPPED", (long)WSTOPPED)) return -1;
+#endif
+#ifdef CLD_EXITED
+    if (ins(d, "CLD_EXITED", (long)CLD_EXITED)) return -1;
+#endif
+#ifdef CLD_DUMPED
+    if (ins(d, "CLD_DUMPED", (long)CLD_DUMPED)) return -1;
+#endif
+#ifdef CLD_TRAPPED
+    if (ins(d, "CLD_TRAPPED", (long)CLD_TRAPPED)) return -1;
+#endif
+#ifdef CLD_CONTINUED
+    if (ins(d, "CLD_CONTINUED", (long)CLD_CONTINUED)) return -1;
+#endif
+
+    /* constants for lockf */
+#ifdef F_LOCK
+    if (ins(d, "F_LOCK", (long)F_LOCK)) return -1;
+#endif
+#ifdef F_TLOCK
+    if (ins(d, "F_TLOCK", (long)F_TLOCK)) return -1;
+#endif
+#ifdef F_ULOCK
+    if (ins(d, "F_ULOCK", (long)F_ULOCK)) return -1;
+#endif
+#ifdef F_TEST
+    if (ins(d, "F_TEST", (long)F_TEST)) return -1;
+#endif
+
+    /* constants for futimens */
+#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
+
 #ifdef HAVE_SPAWNV
 #if defined(PYOS_OS2) && defined(PYCC_GCC)
     if (ins(d, "P_WAIT", (long)P_WAIT)) return -1;
 #endif
 
     if (!initialized) {
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+        waitid_result_desc.name = MODNAME ".waitid_result";
+        PyStructSequence_InitType(&WaitidResultType, &waitid_result_desc);
+#endif
+
         stat_result_desc.name = MODNAME ".stat_result";
         stat_result_desc.fields[7].name = PyStructSequence_UnnamedField;
         stat_result_desc.fields[8].name = PyStructSequence_UnnamedField;
 #  endif
 #endif
     }
+#if defined(HAVE_WAITID) && !defined(__APPLE__)
+    Py_INCREF((PyObject*) &WaitidResultType);
+    PyModule_AddObject(m, "waitid_result", (PyObject*) &WaitidResultType);
+#endif
     Py_INCREF((PyObject*) &StatResultType);
     PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType);
     Py_INCREF((PyObject*) &StatVFSResultType);
 LDFLAGS
 LIBS
 CPPFLAGS
-CPP
-CPPFLAGS'
+CPP'
 
 
 # Initialize some variables set by options.
 # checks for library functions
 for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
  clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \
- fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
+ fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
+ futimens futimes \
  gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
  getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
- initgroups kill killpg lchmod lchown linkat lstat mbrtowc mkdirat mkfifo \
+ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \
  mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \
- pthread_init putenv readlink readlinkat realpath renameat \
+ posix_fallocate posix_fadvise pread \
+ pthread_init putenv pwrite readlink readlinkat readv realpath renameat \
  select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
  setgid sethostname \
  setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
- sigaction siginterrupt sigrelse snprintf strftime strlcpy symlinkat \
+ sigaction siginterrupt sigrelse snprintf strftime strlcpy symlinkat sync \
  sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
- truncate uname unlinkat unsetenv utimensat utimes waitpid wait3 wait4 \
- wcscoll wcsftime wcsxfrm _getpty
+ truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
+ wcscoll wcsftime wcsxfrm writev _getpty
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

File configure.in

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

File pyconfig.h.in

 /* Define to 1 if you have the `fdopendir' function. */
 #undef HAVE_FDOPENDIR
 
+/* Define to 1 if you have the `fexecve' function. */
+#undef HAVE_FEXECVE
+
 /* Define to 1 if you have the `finite' function. */
 #undef HAVE_FINITE
 
 /* Define to 1 if you have the `ftruncate' function. */
 #undef HAVE_FTRUNCATE
 
+/* Define to 1 if you have the `futimens' function. */
+#undef HAVE_FUTIMENS
+
+/* Define to 1 if you have the `futimes' function. */
+#undef HAVE_FUTIMES
+
 /* Define to 1 if you have the `futimesat' function. */
 #undef HAVE_FUTIMESAT
 
 /* Define to 1 if you have the <linux/tipc.h> header file. */
 #undef HAVE_LINUX_TIPC_H
 
+/* Define to 1 if you have the `lockf' function. */
+#undef HAVE_LOCKF
+
 /* Define to 1 if you have the `log1p' function. */
 #undef HAVE_LOG1P
 
 /* Define to 1 if you have the `lstat' function. */
 #undef HAVE_LSTAT
 
+/* Define to 1 if you have the `lutimes' function. */
+#undef HAVE_LUTIMES
+
 /* Define this if you have the makedev macro. */
 #undef HAVE_MAKEDEV
 
 /* Define to 1 if you have the <poll.h> header file. */
 #undef HAVE_POLL_H
 
+/* Define to 1 if you have the `posix_fadvise' function. */
+#undef HAVE_POSIX_FADVISE
+
+/* Define to 1 if you have the `posix_fallocate' function. */
+#undef HAVE_POSIX_FALLOCATE
+
+/* Define to 1 if you have the `pread' function. */
+#undef HAVE_PREAD
+
 /* Define to 1 if you have the <process.h> header file. */
 #undef HAVE_PROCESS_H
 
 /* Define to 1 if you have the `putenv' function. */
 #undef HAVE_PUTENV
 
+/* Define to 1 if you have the `pwrite' function. */
+#undef HAVE_PWRITE
+
 /* 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 `readv' function. */
+#undef HAVE_READV
+
 /* Define to 1 if you have the `realpath' function. */
 #undef HAVE_REALPATH
 
 /* Define to 1 if you have the `symlinkat' function. */
 #undef HAVE_SYMLINKAT
 
+/* Define to 1 if you have the `sync' function. */
+#undef HAVE_SYNC
+
 /* Define to 1 if you have the `sysconf' function. */
 #undef HAVE_SYSCONF
 
 /* Define to 1 if you have the `wait4' function. */
 #undef HAVE_WAIT4
 
+/* Define to 1 if you have the `waitid' function. */
+#undef HAVE_WAITID
+
 /* Define to 1 if you have the `waitpid' function. */
 #undef HAVE_WAITPID
 
    */
 #undef HAVE_WORKING_TZSET
 
+/* Define to 1 if you have the `writev' function. */
+#undef HAVE_WRITEV
+
 /* Define if the zlib library has inflateCopy */
 #undef HAVE_ZLIB_COPY