summaryrefslogtreecommitdiff
path: root/libbtrfsutil/python/module.c
diff options
context:
space:
mode:
authorDimitri John Ledkov <xnox@ubuntu.com>2018-05-08 14:17:29 -0700
committerDimitri John Ledkov <xnox@ubuntu.com>2018-05-08 14:17:29 -0700
commitd00c9550da1801a0eaff5cedf4312e24691b31ea (patch)
tree3881ca1764ef792259e1b70f12c884a3ac0c0715 /libbtrfsutil/python/module.c
parentdab6d2181f1f194ec3a76d900cf2c6533379cbea (diff)
New upstream release.
Diffstat (limited to 'libbtrfsutil/python/module.c')
-rw-r--r--libbtrfsutil/python/module.c321
1 files changed, 321 insertions, 0 deletions
diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c
new file mode 100644
index 00000000..2dbdc7be
--- /dev/null
+++ b/libbtrfsutil/python/module.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2018 Facebook
+ *
+ * This file is part of libbtrfsutil.
+ *
+ * libbtrfsutil is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * libbtrfsutil is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libbtrfsutil. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "btrfsutilpy.h"
+
+static int fd_converter(PyObject *o, void *p)
+{
+ int *fd = p;
+ long tmp;
+ int overflow;
+
+ tmp = PyLong_AsLongAndOverflow(o, &overflow);
+ if (tmp == -1 && PyErr_Occurred())
+ return 0;
+ if (overflow > 0 || tmp > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "fd is greater than maximum");
+ return 0;
+ }
+ if (overflow < 0 || tmp < 0) {
+ PyErr_SetString(PyExc_ValueError, "fd is negative");
+ return 0;
+ }
+ *fd = tmp;
+ return 1;
+}
+
+int path_converter(PyObject *o, void *p)
+{
+ struct path_arg *path = p;
+ int is_index, is_bytes, is_unicode;
+ PyObject *bytes = NULL;
+ Py_ssize_t length = 0;
+ char *tmp;
+
+ if (o == NULL) {
+ path_cleanup(p);
+ return 1;
+ }
+
+ path->object = path->cleanup = NULL;
+ Py_INCREF(o);
+
+ path->fd = -1;
+
+ is_index = path->allow_fd && PyIndex_Check(o);
+ is_bytes = PyBytes_Check(o);
+ is_unicode = PyUnicode_Check(o);
+
+ if (!is_index && !is_bytes && !is_unicode) {
+ _Py_IDENTIFIER(__fspath__);
+ PyObject *func;
+
+ func = _PyObject_LookupSpecial(o, &PyId___fspath__);
+ if (func == NULL)
+ goto err_format;
+ Py_DECREF(o);
+ o = PyObject_CallFunctionObjArgs(func, NULL);
+ Py_DECREF(func);
+ if (o == NULL)
+ return 0;
+ is_bytes = PyBytes_Check(o);
+ is_unicode = PyUnicode_Check(o);
+ }
+
+ if (is_unicode) {
+ if (!PyUnicode_FSConverter(o, &bytes))
+ goto err;
+ } else if (is_bytes) {
+ bytes = o;
+ Py_INCREF(bytes);
+ } else if (is_index) {
+ if (!fd_converter(o, &path->fd))
+ goto err;
+ path->path = NULL;
+ goto out;
+ } else {
+err_format:
+ PyErr_Format(PyExc_TypeError, "expected %s, not %s",
+ path->allow_fd ? "string, bytes, os.PathLike, or integer" :
+ "string, bytes, or os.PathLike",
+ Py_TYPE(o)->tp_name);
+ goto err;
+ }
+
+ length = PyBytes_GET_SIZE(bytes);
+ tmp = PyBytes_AS_STRING(bytes);
+ if ((size_t)length != strlen(tmp)) {
+ PyErr_SetString(PyExc_TypeError,
+ "path has embedded nul character");
+ goto err;
+ }
+
+ path->path = tmp;
+ if (bytes == o)
+ Py_DECREF(bytes);
+ else
+ path->cleanup = bytes;
+ path->fd = -1;
+
+out:
+ path->length = length;
+ path->object = o;
+ return Py_CLEANUP_SUPPORTED;
+
+err:
+ Py_XDECREF(o);
+ Py_XDECREF(bytes);
+ return 0;
+}
+
+PyObject *list_from_uint64_array(const uint64_t *arr, size_t n)
+{
+ PyObject *ret;
+ size_t i;
+
+ ret = PyList_New(n);
+ if (!ret)
+ return NULL;
+
+ for (i = 0; i < n; i++) {
+ PyObject *tmp;
+
+ tmp = PyLong_FromUnsignedLongLong(arr[i]);
+ if (!tmp) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ PyList_SET_ITEM(ret, i, tmp);
+ }
+
+ return ret;
+}
+
+void path_cleanup(struct path_arg *path)
+{
+ Py_CLEAR(path->object);
+ Py_CLEAR(path->cleanup);
+}
+
+static PyMethodDef btrfsutil_methods[] = {
+ {"sync", (PyCFunction)filesystem_sync,
+ METH_VARARGS | METH_KEYWORDS,
+ "sync(path)\n\n"
+ "Sync a specific Btrfs filesystem.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"start_sync", (PyCFunction)start_sync,
+ METH_VARARGS | METH_KEYWORDS,
+ "start_sync(path) -> int\n\n"
+ "Start a sync on a specific Btrfs filesystem and return the\n"
+ "transaction ID.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"wait_sync", (PyCFunction)wait_sync,
+ METH_VARARGS | METH_KEYWORDS,
+ "wait_sync(path, transid=0)\n\n"
+ "Wait for a transaction to sync.\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor\n"
+ "transid -- int transaction ID to wait for, or zero for the current\n"
+ "transaction"},
+ {"is_subvolume", (PyCFunction)is_subvolume,
+ METH_VARARGS | METH_KEYWORDS,
+ "is_subvolume(path) -> bool\n\n"
+ "Get whether a file is a subvolume.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"subvolume_id", (PyCFunction)subvolume_id,
+ METH_VARARGS | METH_KEYWORDS,
+ "subvolume_id(path) -> int\n\n"
+ "Get the ID of the subvolume containing a file.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"subvolume_path", (PyCFunction)subvolume_path,
+ METH_VARARGS | METH_KEYWORDS,
+ "subvolume_path(path, id=0) -> int\n\n"
+ "Get the path of a subvolume relative to the filesystem root.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor\n"
+ "id -- if not zero, instead of returning the subvolume path of the\n"
+ "given path, return the path of the subvolume with this ID"},
+ {"subvolume_info", (PyCFunction)subvolume_info,
+ METH_VARARGS | METH_KEYWORDS,
+ "subvolume_info(path, id=0) -> SubvolumeInfo\n\n"
+ "Get information about a subvolume.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor\n"
+ "id -- if not zero, instead of returning information about the\n"
+ "given path, return information about the subvolume with this ID"},
+ {"get_subvolume_read_only", (PyCFunction)get_subvolume_read_only,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_subvolume_read_only(path) -> bool\n\n"
+ "Get whether a subvolume is read-only.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"set_subvolume_read_only", (PyCFunction)set_subvolume_read_only,
+ METH_VARARGS | METH_KEYWORDS,
+ "set_subvolume_read_only(path, read_only=True)\n\n"
+ "Set whether a subvolume is read-only.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor\n"
+ "read_only -- bool flag value"},
+ {"get_default_subvolume", (PyCFunction)get_default_subvolume,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_default_subvolume(path) -> int\n\n"
+ "Get the ID of the default subvolume of a filesystem.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"set_default_subvolume", (PyCFunction)set_default_subvolume,
+ METH_VARARGS | METH_KEYWORDS,
+ "set_default_subvolume(path, id=0)\n\n"
+ "Set the default subvolume of a filesystem.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor\n"
+ "id -- if not zero, set the default subvolume to the subvolume with\n"
+ "this ID instead of the given path"},
+ {"create_subvolume", (PyCFunction)create_subvolume,
+ METH_VARARGS | METH_KEYWORDS,
+ "create_subvolume(path, async=False)\n\n"
+ "Create a new subvolume.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, or path-like object\n"
+ "async -- create the subvolume without waiting for it to commit to\n"
+ "disk and return the transaction ID"},
+ {"create_snapshot", (PyCFunction)create_snapshot,
+ METH_VARARGS | METH_KEYWORDS,
+ "create_snapshot(source, path, recursive=False, read_only=False, async=False)\n\n"
+ "Create a new snapshot.\n\n"
+ "Arguments:\n"
+ "source -- string, bytes, path-like object, or open file descriptor\n"
+ "path -- string, bytes, or path-like object\n"
+ "recursive -- also snapshot child subvolumes\n"
+ "read_only -- create a read-only snapshot\n"
+ "async -- create the subvolume without waiting for it to commit to\n"
+ "disk and return the transaction ID"},
+ {"delete_subvolume", (PyCFunction)delete_subvolume,
+ METH_VARARGS | METH_KEYWORDS,
+ "delete_subvolume(path, recursive=False)\n\n"
+ "Delete a subvolume or snapshot.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, or path-like object\n"
+ "recursive -- if the given subvolume has child subvolumes, delete\n"
+ "them instead of failing"},
+ {"deleted_subvolumes", (PyCFunction)deleted_subvolumes,
+ METH_VARARGS | METH_KEYWORDS,
+ "deleted_subvolumes(path)\n\n"
+ "Get the list of subvolume IDs which have been deleted but not yet\n"
+ "cleaned up\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {},
+};
+
+static struct PyModuleDef btrfsutilmodule = {
+ PyModuleDef_HEAD_INIT,
+ "btrfsutil",
+ "Library for managing Btrfs filesystems",
+ -1,
+ btrfsutil_methods,
+};
+
+PyMODINIT_FUNC
+PyInit_btrfsutil(void)
+{
+ PyObject *m;
+
+ BtrfsUtilError_type.tp_base = (PyTypeObject *)PyExc_OSError;
+ if (PyType_Ready(&BtrfsUtilError_type) < 0)
+ return NULL;
+
+ if (PyStructSequence_InitType2(&SubvolumeInfo_type, &SubvolumeInfo_desc) < 0)
+ return NULL;
+
+ SubvolumeIterator_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&SubvolumeIterator_type) < 0)
+ return NULL;
+
+ QgroupInherit_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&QgroupInherit_type) < 0)
+ return NULL;
+
+ m = PyModule_Create(&btrfsutilmodule);
+ if (!m)
+ return NULL;
+
+ Py_INCREF(&BtrfsUtilError_type);
+ PyModule_AddObject(m, "BtrfsUtilError",
+ (PyObject *)&BtrfsUtilError_type);
+
+ Py_INCREF(&SubvolumeInfo_type);
+ PyModule_AddObject(m, "SubvolumeInfo", (PyObject *)&SubvolumeInfo_type);
+
+ Py_INCREF(&SubvolumeIterator_type);
+ PyModule_AddObject(m, "SubvolumeIterator",
+ (PyObject *)&SubvolumeIterator_type);
+
+ Py_INCREF(&QgroupInherit_type);
+ PyModule_AddObject(m, "QgroupInherit",
+ (PyObject *)&QgroupInherit_type);
+
+ add_module_constants(m);
+
+ return m;
+}