From 306336bcdaf886c10df9c1b46886d5f0cddcaa69 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 24 Jun 2012 12:55:33 +0200 Subject: [PATCH] Closes #15161: add support for giving path as a fd for truncate() and pathconf(). --- Doc/library/os.rst | 12 +++++-- Lib/os.py | 2 ++ Lib/test/test_os.py | 2 ++ Modules/posixmodule.c | 82 ++++++++++++++++++++++++++++++++----------- 4 files changed, 76 insertions(+), 22 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index a1e174dbc25..0729a94b380 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -724,6 +724,8 @@ as internal buffering of data. included in ``pathconf_names``, an :exc:`OSError` is raised with :const:`errno.EINVAL` for the error number. + From Python 3.3, this is equivalent to ``os.pathconf(fd, name)``. + Availability: Unix. @@ -758,8 +760,9 @@ as internal buffering of data. .. function:: ftruncate(fd, length) - Truncate the file corresponding to file descriptor *fd*, so that it is at most - *length* bytes in size. + Truncate the file corresponding to file descriptor *fd*, so that it is at + most *length* bytes in size. From Python 3.3, this is equivalent to + ``os.truncate(fd, length)``. Availability: Unix. @@ -1622,6 +1625,9 @@ features: included in ``pathconf_names``, an :exc:`OSError` is raised with :const:`errno.EINVAL` for the error number. + This function can support :ref:`specifying an open file descriptor + `. + Availability: Unix. @@ -2054,6 +2060,8 @@ features: Truncate the file corresponding to *path*, so that it is at most *length* bytes in size. + This function can support :ref:`specifying a file descriptor `. + Availability: Unix. .. versionadded:: 3.3 diff --git a/Lib/os.py b/Lib/os.py index 4a40cfed6b5..f9906272672 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -172,8 +172,10 @@ if _exists("_have_functions"): _add("HAVE_FDOPENDIR", "listdir") _add("HAVE_FEXECVE", "execve") _set.add(stat) # fstat always works + _add("HAVE_FTRUNCATE", "truncate") _add("HAVE_FUTIMENS", "utime") _add("HAVE_FUTIMES", "utime") + _add("HAVE_FPATHCONF", "pathconf") if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3 _add("HAVE_FSTATVFS", "statvfs") supports_fd = _set diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 654dd23a5cf..62a7dadd872 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1084,10 +1084,12 @@ class TestInvalidFD(unittest.TestCase): def test_fpathconf(self): if hasattr(os, "fpathconf"): + self.check(os.pathconf, "PC_NAME_MAX") self.check(os.fpathconf, "PC_NAME_MAX") def test_ftruncate(self): if hasattr(os, "ftruncate"): + self.check(os.truncate, 0) self.check(os.ftruncate, 0) def test_lseek(self): diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index bfe32b81544..6da030a371d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8482,28 +8482,44 @@ posix_ftruncate(PyObject *self, PyObject *args) #ifdef HAVE_TRUNCATE PyDoc_STRVAR(posix_truncate__doc__, "truncate(path, length)\n\n\ -Truncate the file given by path to length bytes."); +Truncate the file given by path to length bytes.\n\ +On some platforms, path may also be specified as an open file descriptor.\n\ + If this functionality is unavailable, using it raises an exception."); static PyObject * -posix_truncate(PyObject *self, PyObject *args) +posix_truncate(PyObject *self, PyObject *args, PyObject *kwargs) { - PyObject *opath; - const char *path; + path_t path; off_t length; int res; + PyObject *result = NULL; + static char *keywords[] = {"path", "length", NULL}; - if (!PyArg_ParseTuple(args, "O&O&:truncate", - PyUnicode_FSConverter, &opath, _parse_off_t, &length)) + memset(&path, 0, sizeof(path)); +#ifdef HAVE_FTRUNCATE + path.allow_fd = 1; +#endif + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:truncate", keywords, + path_converter, &path, + _parse_off_t, &length)) return NULL; - path = PyBytes_AsString(opath); Py_BEGIN_ALLOW_THREADS - res = truncate(path, length); +#ifdef HAVE_FTRUNCATE + if (path.fd != -1) + res = ftruncate(path.fd, length); + else +#endif + res = truncate(path.narrow, length); Py_END_ALLOW_THREADS - Py_DECREF(opath); if (res < 0) - return posix_error(); - Py_RETURN_NONE; + result = path_posix_error("truncate", &path); + else { + Py_INCREF(Py_None); + result = Py_None; + } + path_cleanup(&path); + return result; } #endif @@ -9219,31 +9235,45 @@ posix_fpathconf(PyObject *self, PyObject *args) PyDoc_STRVAR(posix_pathconf__doc__, "pathconf(path, name) -> integer\n\n\ Return the configuration limit name for the file or directory path.\n\ -If there is no limit, return -1."); +If there is no limit, return -1.\n\ +On some platforms, path may also be specified as an open file descriptor.\n\ + If this functionality is unavailable, using it raises an exception."); static PyObject * -posix_pathconf(PyObject *self, PyObject *args) +posix_pathconf(PyObject *self, PyObject *args, PyObject *kwargs) { + path_t path; PyObject *result = NULL; int name; - char *path; + static char *keywords[] = {"path", "name", NULL}; - if (PyArg_ParseTuple(args, "sO&:pathconf", &path, - conv_path_confname, &name)) { + memset(&path, 0, sizeof(path)); +#ifdef HAVE_FPATHCONF + path.allow_fd = 1; +#endif + if (PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:pathconf", keywords, + path_converter, &path, + conv_path_confname, &name)) { long limit; errno = 0; - limit = pathconf(path, name); +#ifdef HAVE_FPATHCONF + if (path.fd != -1) + limit = fpathconf(path.fd, name); + else +#endif + limit = pathconf(path.narrow, name); if (limit == -1 && errno != 0) { if (errno == EINVAL) /* could be a path or name problem */ posix_error(); else - posix_error_with_filename(path); + result = path_posix_error("pathconf", &path); } else result = PyLong_FromLong(limit); } + path_cleanup(&path); return result; } #endif @@ -11078,7 +11108,9 @@ static PyMethodDef posix_methods[] = { {"ftruncate", posix_ftruncate, METH_VARARGS, posix_ftruncate__doc__}, #endif #ifdef HAVE_TRUNCATE - {"truncate", posix_truncate, METH_VARARGS, posix_truncate__doc__}, + {"truncate", (PyCFunction)posix_truncate, + METH_VARARGS | METH_KEYWORDS, + posix_truncate__doc__}, #endif #ifdef HAVE_POSIX_FALLOCATE {"posix_fallocate", posix_posix_fallocate, METH_VARARGS, posix_posix_fallocate__doc__}, @@ -11149,7 +11181,9 @@ static PyMethodDef posix_methods[] = { {"fpathconf", posix_fpathconf, METH_VARARGS, posix_fpathconf__doc__}, #endif #ifdef HAVE_PATHCONF - {"pathconf", posix_pathconf, METH_VARARGS, posix_pathconf__doc__}, + {"pathconf", (PyCFunction)posix_pathconf, + METH_VARARGS | METH_KEYWORDS, + posix_pathconf__doc__}, #endif {"abort", posix_abort, METH_NOARGS, posix_abort__doc__}, #ifdef MS_WINDOWS @@ -11741,6 +11775,10 @@ static char *have_functions[] = { "HAVE_FDOPENDIR", #endif +#ifdef HAVE_FPATHCONF + "HAVE_FPATHCONF", +#endif + #ifdef HAVE_FSTATAT "HAVE_FSTATAT", #endif @@ -11749,6 +11787,10 @@ static char *have_functions[] = { "HAVE_FSTATVFS", #endif +#ifdef HAVE_FTRUNCATE + "HAVE_FTRUNCATE", +#endif + #ifdef HAVE_FUTIMENS "HAVE_FUTIMENS", #endif