]> granicus.if.org Git - python/commitdiff
Closes #15161: add support for giving path as a fd for truncate() and pathconf().
authorGeorg Brandl <georg@python.org>
Sun, 24 Jun 2012 10:55:33 +0000 (12:55 +0200)
committerGeorg Brandl <georg@python.org>
Sun, 24 Jun 2012 10:55:33 +0000 (12:55 +0200)
Doc/library/os.rst
Lib/os.py
Lib/test/test_os.py
Modules/posixmodule.c

index a1e174dbc259357b3834fa392f6559ee301c936b..0729a94b380775f4d290fd03a60eb2e125cc463f 100644 (file)
@@ -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
+   <path_fd>`.
+
    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 <path_fd>`.
+
    Availability: Unix.
 
    .. versionadded:: 3.3
index 4a40cfed6b502d27ea9ec2d7bdaf4c18aa7f65dc..f99062726722ea1eac9a2ef983442155e76cd542 100644 (file)
--- 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
index 654dd23a5cf8e604d2d0e570718d00872e2d22d7..62a7dadd872967af656cee0e4986ea07568eb4dc 100644 (file)
@@ -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):
index bfe32b81544699f50eff7dc52295318f9f7dcfb7..6da030a371da6cf890637d8c9919e3b8a7495abc 100644 (file)
@@ -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