2 * Copyright (C) 2018 Facebook
4 * This file is part of libbtrfsutil.
6 * libbtrfsutil is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * libbtrfsutil is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with libbtrfsutil. If not, see <http://www.gnu.org/licenses/>.
20 #include "btrfsutilpy.h"
22 static int fd_converter(PyObject *o, void *p)
28 tmp = PyLong_AsLongAndOverflow(o, &overflow);
29 if (tmp == -1 && PyErr_Occurred())
31 if (overflow > 0 || tmp > INT_MAX) {
32 PyErr_SetString(PyExc_OverflowError,
33 "fd is greater than maximum");
36 if (overflow < 0 || tmp < 0) {
37 PyErr_SetString(PyExc_ValueError, "fd is negative");
44 int path_converter(PyObject *o, void *p)
46 struct path_arg *path = p;
47 int is_index, is_bytes, is_unicode;
48 PyObject *bytes = NULL;
49 Py_ssize_t length = 0;
57 path->object = path->cleanup = NULL;
62 is_index = path->allow_fd && PyIndex_Check(o);
63 is_bytes = PyBytes_Check(o);
64 is_unicode = PyUnicode_Check(o);
66 if (!is_index && !is_bytes && !is_unicode) {
67 _Py_IDENTIFIER(__fspath__);
70 func = _PyObject_LookupSpecial(o, &PyId___fspath__);
74 o = PyObject_CallFunctionObjArgs(func, NULL);
78 is_bytes = PyBytes_Check(o);
79 is_unicode = PyUnicode_Check(o);
83 if (!PyUnicode_FSConverter(o, &bytes))
85 } else if (is_bytes) {
88 } else if (is_index) {
89 if (!fd_converter(o, &path->fd))
95 PyErr_Format(PyExc_TypeError, "expected %s, not %s",
96 path->allow_fd ? "string, bytes, os.PathLike, or integer" :
97 "string, bytes, or os.PathLike",
102 length = PyBytes_GET_SIZE(bytes);
103 tmp = PyBytes_AS_STRING(bytes);
104 if ((size_t)length != strlen(tmp)) {
105 PyErr_SetString(PyExc_TypeError,
106 "path has embedded nul character");
114 path->cleanup = bytes;
118 path->length = length;
120 return Py_CLEANUP_SUPPORTED;
128 PyObject *list_from_uint64_array(const uint64_t *arr, size_t n)
137 for (i = 0; i < n; i++) {
140 tmp = PyLong_FromUnsignedLongLong(arr[i]);
145 PyList_SET_ITEM(ret, i, tmp);
151 void path_cleanup(struct path_arg *path)
153 Py_CLEAR(path->object);
154 Py_CLEAR(path->cleanup);
157 static PyMethodDef btrfsutil_methods[] = {
158 {"sync", (PyCFunction)filesystem_sync,
159 METH_VARARGS | METH_KEYWORDS,
161 "Sync a specific Btrfs filesystem.\n\n"
163 "path -- string, bytes, path-like object, or open file descriptor"},
164 {"start_sync", (PyCFunction)start_sync,
165 METH_VARARGS | METH_KEYWORDS,
166 "start_sync(path) -> int\n\n"
167 "Start a sync on a specific Btrfs filesystem and return the\n"
168 "transaction ID.\n\n"
170 "path -- string, bytes, path-like object, or open file descriptor"},
171 {"wait_sync", (PyCFunction)wait_sync,
172 METH_VARARGS | METH_KEYWORDS,
173 "wait_sync(path, transid=0)\n\n"
174 "Wait for a transaction to sync.\n"
176 "path -- string, bytes, path-like object, or open file descriptor\n"
177 "transid -- int transaction ID to wait for, or zero for the current\n"
179 {"is_subvolume", (PyCFunction)is_subvolume,
180 METH_VARARGS | METH_KEYWORDS,
181 "is_subvolume(path) -> bool\n\n"
182 "Get whether a file is a subvolume.\n\n"
184 "path -- string, bytes, path-like object, or open file descriptor"},
185 {"subvolume_id", (PyCFunction)subvolume_id,
186 METH_VARARGS | METH_KEYWORDS,
187 "subvolume_id(path) -> int\n\n"
188 "Get the ID of the subvolume containing a file.\n\n"
190 "path -- string, bytes, path-like object, or open file descriptor"},
191 {"subvolume_path", (PyCFunction)subvolume_path,
192 METH_VARARGS | METH_KEYWORDS,
193 "subvolume_path(path, id=0) -> int\n\n"
194 "Get the path of a subvolume relative to the filesystem root.\n\n"
196 "path -- string, bytes, path-like object, or open file descriptor\n"
197 "id -- if not zero, instead of returning the subvolume path of the\n"
198 "given path, return the path of the subvolume with this ID"},
199 {"subvolume_info", (PyCFunction)subvolume_info,
200 METH_VARARGS | METH_KEYWORDS,
201 "subvolume_info(path, id=0) -> SubvolumeInfo\n\n"
202 "Get information about a subvolume.\n\n"
204 "path -- string, bytes, path-like object, or open file descriptor\n"
205 "id -- if not zero, instead of returning information about the\n"
206 "given path, return information about the subvolume with this ID"},
207 {"get_subvolume_read_only", (PyCFunction)get_subvolume_read_only,
208 METH_VARARGS | METH_KEYWORDS,
209 "get_subvolume_read_only(path) -> bool\n\n"
210 "Get whether a subvolume is read-only.\n\n"
212 "path -- string, bytes, path-like object, or open file descriptor"},
213 {"set_subvolume_read_only", (PyCFunction)set_subvolume_read_only,
214 METH_VARARGS | METH_KEYWORDS,
215 "set_subvolume_read_only(path, read_only=True)\n\n"
216 "Set whether a subvolume is read-only.\n\n"
218 "path -- string, bytes, path-like object, or open file descriptor\n"
219 "read_only -- bool flag value"},
220 {"get_default_subvolume", (PyCFunction)get_default_subvolume,
221 METH_VARARGS | METH_KEYWORDS,
222 "get_default_subvolume(path) -> int\n\n"
223 "Get the ID of the default subvolume of a filesystem.\n\n"
225 "path -- string, bytes, path-like object, or open file descriptor"},
226 {"set_default_subvolume", (PyCFunction)set_default_subvolume,
227 METH_VARARGS | METH_KEYWORDS,
228 "set_default_subvolume(path, id=0)\n\n"
229 "Set the default subvolume of a filesystem.\n\n"
231 "path -- string, bytes, path-like object, or open file descriptor\n"
232 "id -- if not zero, set the default subvolume to the subvolume with\n"
233 "this ID instead of the given path"},
234 {"create_subvolume", (PyCFunction)create_subvolume,
235 METH_VARARGS | METH_KEYWORDS,
236 "create_subvolume(path, async=False)\n\n"
237 "Create a new subvolume.\n\n"
239 "path -- string, bytes, or path-like object\n"
240 "async -- create the subvolume without waiting for it to commit to\n"
241 "disk and return the transaction ID"},
242 {"create_snapshot", (PyCFunction)create_snapshot,
243 METH_VARARGS | METH_KEYWORDS,
244 "create_snapshot(source, path, recursive=False, read_only=False, async=False)\n\n"
245 "Create a new snapshot.\n\n"
247 "source -- string, bytes, path-like object, or open file descriptor\n"
248 "path -- string, bytes, or path-like object\n"
249 "recursive -- also snapshot child subvolumes\n"
250 "read_only -- create a read-only snapshot\n"
251 "async -- create the subvolume without waiting for it to commit to\n"
252 "disk and return the transaction ID"},
253 {"delete_subvolume", (PyCFunction)delete_subvolume,
254 METH_VARARGS | METH_KEYWORDS,
255 "delete_subvolume(path, recursive=False)\n\n"
256 "Delete a subvolume or snapshot.\n\n"
258 "path -- string, bytes, or path-like object\n"
259 "recursive -- if the given subvolume has child subvolumes, delete\n"
260 "them instead of failing"},
261 {"deleted_subvolumes", (PyCFunction)deleted_subvolumes,
262 METH_VARARGS | METH_KEYWORDS,
263 "deleted_subvolumes(path)\n\n"
264 "Get the list of subvolume IDs which have been deleted but not yet\n"
267 "path -- string, bytes, path-like object, or open file descriptor"},
271 static struct PyModuleDef btrfsutilmodule = {
272 PyModuleDef_HEAD_INIT,
274 "Library for managing Btrfs filesystems",
280 PyInit_btrfsutil(void)
284 BtrfsUtilError_type.tp_base = (PyTypeObject *)PyExc_OSError;
285 if (PyType_Ready(&BtrfsUtilError_type) < 0)
288 if (PyStructSequence_InitType2(&SubvolumeInfo_type, &SubvolumeInfo_desc) < 0)
291 SubvolumeIterator_type.tp_new = PyType_GenericNew;
292 if (PyType_Ready(&SubvolumeIterator_type) < 0)
295 QgroupInherit_type.tp_new = PyType_GenericNew;
296 if (PyType_Ready(&QgroupInherit_type) < 0)
299 m = PyModule_Create(&btrfsutilmodule);
303 Py_INCREF(&BtrfsUtilError_type);
304 PyModule_AddObject(m, "BtrfsUtilError",
305 (PyObject *)&BtrfsUtilError_type);
307 Py_INCREF(&SubvolumeInfo_type);
308 PyModule_AddObject(m, "SubvolumeInfo", (PyObject *)&SubvolumeInfo_type);
310 Py_INCREF(&SubvolumeIterator_type);
311 PyModule_AddObject(m, "SubvolumeIterator",
312 (PyObject *)&SubvolumeIterator_type);
314 Py_INCREF(&QgroupInherit_type);
315 PyModule_AddObject(m, "QgroupInherit",
316 (PyObject *)&QgroupInherit_type);
318 add_module_constants(m);