diff -r 3072b4bf6e27 -r 06ac25ece230 Doc/library/os.rst --- a/Doc/library/os.rst Thu Jan 20 05:12:37 2011 +0100 +++ b/Doc/library/os.rst Thu Jan 20 13:23:50 2011 +0200 @@ -637,6 +637,17 @@ This function is not available on MacOS. +.. 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* @@ -690,6 +701,45 @@ Availability: Unix. +.. 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 @@ -698,6 +748,30 @@ Availability: Unix. +.. 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 @@ -758,6 +832,66 @@ 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 @@ -775,6 +909,17 @@ :meth:`~file.readline` methods. +.. 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 @@ -816,6 +961,17 @@ :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 @@ -1087,6 +1243,17 @@ 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 @@ -1411,6 +1578,25 @@ 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 @@ -1990,6 +2176,58 @@ 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) @@ -2167,6 +2405,15 @@ Availability: Unix. +.. function:: gethostid() + + Returns the host id, a unique 32-bit identifier for the current machine. + + Availability: Unix. + + .. versionadded:: 3.3 + + .. function:: getloadavg() Return the number of processes in the system run queue averaged over the last @@ -2176,6 +2423,16 @@ Availability: Unix. +.. function:: sethostid(hostid) + + Sets the machine's host id to *hostid*. *hostid* is expected to be an integer + identifier. + + Availability: Unix. + + .. versionadded:: 3.3 + + .. function:: sysconf(name) Return integer-valued system configuration values. If the configuration value diff -r 3072b4bf6e27 -r 06ac25ece230 Lib/test/test_posix.py --- a/Lib/test/test_posix.py Thu Jan 20 05:12:37 2011 +0100 +++ b/Lib/test/test_posix.py Thu Jan 20 13:23:50 2011 +0200 @@ -37,7 +37,7 @@ 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: @@ -132,6 +132,175 @@ 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, 'gethostid'), "test needs posix.gethostid()") + def test_gethostid(self): + self.assertTrue(isinstance(posix.gethostid(), int)) + + @unittest.skipUnless(hasattr(posix, 'sethostid'), "test needs posix.sethostid()") + def test_sethostid(self): + hid = os.gethostid() + try: + posix.sethostid(2464787) + except OSError as e: + if sys.platform.startswith("freebsd") or sys.platform == "darwin": + self.assertEqual(e.errno, errno.EPERM) + else: + self.assertEqual(e.errno, errno.EACCES) + else: + # running test as root! + self.assertEqual(os.gethostid(), 2464787) + posix.sethostid(hid) + + @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) diff -r 3072b4bf6e27 -r 06ac25ece230 Modules/posixmodule.c --- a/Modules/posixmodule.c Thu Jan 20 05:12:37 2011 +0100 +++ b/Modules/posixmodule.c Thu Jan 20 13:23:50 2011 +0200 @@ -59,6 +59,10 @@ #include "osdefs.h" #endif +#ifdef HAVE_SYS_UIO_H +#include +#endif + #ifdef HAVE_SYS_TYPES_H #include #endif /* HAVE_SYS_TYPES_H */ @@ -349,6 +353,20 @@ #endif #endif +int +PyParse_off_t(PyObject* arg, void* addr) +{ +#if !defined(HAVE_LARGEFILE_SUPPORT) + *((off_t*)addr) = PyLong_AsLong(arg); +#else + *((off_t*)addr) = PyLong_Check(arg) ? PyLong_AsLongLong(arg) + : PyLong_AsLong(arg); +#endif + if (PyErr_Occurred()) + return 0; + return 1; +} + #if defined _MSC_VER && _MSC_VER >= 1400 /* Microsoft CRT in VS2005 and higher will verify that a filehandle is * valid and throw an assertion if it isn't. @@ -1476,6 +1494,33 @@ 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; @@ -2075,6 +2120,21 @@ } #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 @@ -3345,6 +3405,167 @@ #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 */ @@ -3389,79 +3610,7 @@ } #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) { @@ -3543,6 +3692,84 @@ 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\ @@ -3559,9 +3786,7 @@ 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 @@ -3572,40 +3797,22 @@ &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) @@ -3621,13 +3828,69 @@ 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__, @@ -4194,6 +4457,51 @@ } #endif +#ifdef HAVE_GETHOSTID +PyDoc_STRVAR(posix_gethostid__doc__, +"gethostid() -> hostid\n\n\ +Gets the host id, a unique 32-bit identifier for the current machine."); + +static PyObject * +posix_gethostid(PyObject *self, PyObject *noargs) +{ + long res; + errno = 0; + + res = gethostid(); + if (errno != 0) + return posix_error(); + + return PyLong_FromLong(res); +} +#endif + +#ifdef HAVE_SETHOSTID +PyDoc_STRVAR(posix_sethostid__doc__, +"sethostid(hostid)\n\n\ +Sets the machine's host id to hostid. hostid is expected to be an integer\n\ +identifier."); + +static PyObject * +posix_sethostid(PyObject *self, PyObject *args) +{ + long hostid; + if (!PyArg_ParseTuple(args, "l:sethostid", &hostid)) + return NULL; +#if !(defined(__FreeBSD__) || defined(__APPLE__)) + if (sethostid(hostid) == -1) + return posix_error(); +#else + errno = 0; + sethostid(hostid); + if (errno != 0) + return posix_error(); +#endif + + Py_RETURN_NONE; +} +#endif + #ifdef HAVE_GETEGID PyDoc_STRVAR(posix_getegid__doc__, "getegid() -> egid\n\n\ @@ -4984,6 +5292,55 @@ } #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\ @@ -5599,6 +5956,35 @@ 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, PyParse_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\ @@ -5613,8 +5999,7 @@ #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, PyParse_off_t, &pos, &how)) return NULL; #ifdef SEEK_SET /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ @@ -5625,15 +6010,6 @@ } #endif /* SEEK_END */ -#if !defined(HAVE_LARGEFILE_SUPPORT) - pos = PyLong_AsLong(posobj); -#else - pos = PyLong_Check(posobj) ? - PyLong_AsLongLong(posobj) : PyLong_AsLong(posobj); -#endif - if (PyErr_Occurred()) - return NULL; - if (!_PyVerify_fd(fd)) return posix_error(); Py_BEGIN_ALLOW_THREADS @@ -5689,6 +6065,127 @@ return buffer; } +#if defined(HAVE_READV) || defined(HAVE_WRITEV) +static int +iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type) +{ + int i, j; + *iov = PyMem_New(struct iovec, cnt); + if (*iov == NULL) { + PyErr_NoMemory(); + return 0; + } + *buf = PyMem_New(Py_buffer, cnt); + if (*buf == NULL) { + PyMem_Del(*iov); + PyErr_NoMemory(); + return 0; + } + + for (i = 0; i < cnt; i++) { + if (PyObject_GetBuffer(PySequence_GetItem(seq, i), &(*buf)[i], + type) == -1) { + PyMem_Del(*iov); + for (j = 0; j < i; j++) { + PyBuffer_Release(&(*buf)[j]); + } + PyMem_Del(*buf); + return 0; + } + (*iov)[i].iov_base = (*buf)[i].buf; + (*iov)[i].iov_len = (*buf)[i].len; + } + return 1; +} + +static void +iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt) +{ + int i; + PyMem_Del(iov); + for (i = 0; i < cnt; i++) { + PyBuffer_Release(&buf[i]); + } + PyMem_Del(buf); +} +#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, PyParse_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\ @@ -5723,6 +6220,73 @@ return PyLong_FromSsize_t(size); } +#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, PyParse_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 PyDoc_STRVAR(posix_fstat__doc__, "fstat(fd) -> stat result\n\n\ @@ -5934,18 +6498,8 @@ 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, PyParse_off_t, &length)) return NULL; Py_BEGIN_ALLOW_THREADS @@ -5958,6 +6512,93 @@ } #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, PyParse_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, PyParse_off_t, &offset, PyParse_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, PyParse_off_t, &offset, PyParse_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\ @@ -7838,6 +8479,15 @@ {"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 */ @@ -7846,6 +8496,9 @@ {"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__}, @@ -7866,6 +8519,12 @@ #ifdef HAVE_FORKPTY {"forkpty", posix_forkpty, METH_NOARGS, posix_forkpty__doc__}, #endif /* HAVE_FORKPTY */ +#ifdef HAVE_GETHOSTID + {"gethostid", posix_gethostid, METH_NOARGS, posix_gethostid__doc__}, +#endif +#ifdef HAVE_SETHOSTID + {"sethostid", posix_sethostid, METH_VARARGS, posix_sethostid__doc__}, +#endif #ifdef HAVE_GETEGID {"getegid", posix_getegid, METH_NOARGS, posix_getegid__doc__}, #endif /* HAVE_GETEGID */ @@ -7944,6 +8603,9 @@ #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 */ @@ -7968,9 +8630,24 @@ {"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 {"fstat", posix_fstat, METH_VARARGS, posix_fstat__doc__}, {"isatty", posix_isatty, METH_VARARGS, posix_isatty__doc__}, #ifdef HAVE_PIPE @@ -7990,6 +8667,15 @@ #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 @@ -8003,6 +8689,9 @@ #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 @@ -8362,6 +9051,76 @@ if (ins(d, "ST_NOSUID", (long)ST_NOSUID)) return -1; #endif /* ST_NOSUID */ + /* 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; @@ -8461,6 +9220,11 @@ #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; @@ -8481,6 +9245,10 @@ # 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); diff -r 3072b4bf6e27 -r 06ac25ece230 configure.in --- a/configure.in Thu Jan 20 05:12:37 2011 +0100 +++ b/configure.in Thu Jan 20 13:23:50 2011 +0200 @@ -1293,7 +1293,7 @@ sys/lock.h sys/mkdev.h sys/modem.h \ sys/param.h sys/poll.h sys/select.h sys/socket.h sys/statvfs.h sys/stat.h \ sys/termio.h sys/time.h \ -sys/times.h sys/types.h sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \ +sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \ sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h) AC_HEADER_DIRENT @@ -2535,19 +2535,20 @@ # 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 \ - gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ + clock confstr ctermid execv fchmod fchown fexecve fork fpathconf ftime \ + ftruncate futimens futimes \ + gai_strerror getgroups gethostid 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 lockf lstat lutimes mbrtowc mkfifo mknod \ + mktime mremap nice pathconf pause plock poll posix_fallocate posix_fadvise pread \ + pthread_init putenv pwrite readlink readv realpath \ select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ - setgid \ + setgid sethostid \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setuid setvbuf \ - sigaction siginterrupt sigrelse snprintf strftime strlcpy \ + sigaction siginterrupt sigrelse snprintf strftime strlcpy sync \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ - truncate uname unsetenv utimes waitpid wait3 wait4 \ - wcscoll wcsftime wcsxfrm _getpty) + truncate uname unsetenv 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.