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 PyObject *is_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
24 static char *keywords[] = {"path", NULL};
25 struct path_arg path = {.allow_fd = true};
26 enum btrfs_util_error err;
28 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:is_subvolume",
29 keywords, &path_converter, &path))
33 err = btrfs_util_is_subvolume(path.path);
35 err = btrfs_util_is_subvolume_fd(path.fd);
36 if (err == BTRFS_UTIL_OK) {
39 } else if (err == BTRFS_UTIL_ERROR_NOT_BTRFS ||
40 err == BTRFS_UTIL_ERROR_NOT_SUBVOLUME) {
44 SetFromBtrfsUtilErrorWithPath(err, &path);
50 PyObject *subvolume_id(PyObject *self, PyObject *args, PyObject *kwds)
52 static char *keywords[] = {"path", NULL};
53 struct path_arg path = {.allow_fd = true};
54 enum btrfs_util_error err;
57 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:subvolume_id",
58 keywords, &path_converter, &path))
62 err = btrfs_util_subvolume_id(path.path, &id);
64 err = btrfs_util_subvolume_id_fd(path.fd, &id);
66 SetFromBtrfsUtilErrorWithPath(err, &path);
72 return PyLong_FromUnsignedLongLong(id);
75 PyObject *subvolume_path(PyObject *self, PyObject *args, PyObject *kwds)
77 static char *keywords[] = {"path", "id", NULL};
78 struct path_arg path = {.allow_fd = true};
79 enum btrfs_util_error err;
84 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:subvolume_path",
85 keywords, &path_converter, &path, &id))
89 err = btrfs_util_subvolume_path(path.path, id, &subvol_path);
91 err = btrfs_util_subvolume_path_fd(path.fd, id, &subvol_path);
93 SetFromBtrfsUtilErrorWithPath(err, &path);
100 ret = PyUnicode_DecodeFSDefault(subvol_path);
105 static PyObject *subvolume_info_to_object(const struct btrfs_util_subvolume_info *subvol)
109 ret = PyStructSequence_New(&SubvolumeInfo_type);
113 #define SET_UINT64(i, field) \
114 tmp = PyLong_FromUnsignedLongLong(subvol->field); \
119 PyStructSequence_SET_ITEM(ret, i, tmp);
121 #define SET_UUID(i, field) \
122 tmp = PyBytes_FromStringAndSize((char *)subvol->field, 16); \
127 PyStructSequence_SET_ITEM(ret, i, tmp);
129 #define SET_TIME(i, field) \
130 tmp = PyFloat_FromDouble(subvol->field.tv_sec + \
131 subvol->field.tv_nsec / 1000000000); \
136 PyStructSequence_SET_ITEM(ret, i, tmp);
139 SET_UINT64(1, parent_id);
140 SET_UINT64(2, dir_id);
141 SET_UINT64(3, flags);
143 SET_UUID(5, parent_uuid);
144 SET_UUID(6, received_uuid);
145 SET_UINT64(7, generation);
146 SET_UINT64(8, ctransid);
147 SET_UINT64(9, otransid);
148 SET_UINT64(10, stransid);
149 SET_UINT64(11, rtransid);
162 PyObject *subvolume_info(PyObject *self, PyObject *args, PyObject *kwds)
164 static char *keywords[] = {"path", "id", NULL};
165 struct path_arg path = {.allow_fd = true};
166 struct btrfs_util_subvolume_info subvol;
167 enum btrfs_util_error err;
170 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:subvolume_info",
171 keywords, &path_converter, &path, &id))
175 err = btrfs_util_subvolume_info(path.path, id, &subvol);
177 err = btrfs_util_subvolume_info_fd(path.fd, id, &subvol);
179 SetFromBtrfsUtilErrorWithPath(err, &path);
186 return subvolume_info_to_object(&subvol);
189 static PyStructSequence_Field SubvolumeInfo_fields[] = {
190 {"id", "int ID of this subvolume"},
191 {"parent_id", "int ID of the subvolume containing this subvolume"},
192 {"dir_id", "int inode number of the directory containing this subvolume"},
193 {"flags", "int root item flags"},
194 {"uuid", "bytes UUID of this subvolume"},
195 {"parent_uuid", "bytes UUID of the subvolume this is a snapshot of"},
196 {"received_uuid", "bytes UUID of the subvolume this was received from"},
197 {"generation", "int transaction ID of the subvolume root"},
198 {"ctransid", "int transaction ID when an inode was last changed"},
199 {"otransid", "int transaction ID when this subvolume was created"},
200 {"stransid", "int transaction ID of the sent subvolume this subvolume was received from"},
201 {"rtransid", "int transaction ID when this subvolume was received"},
202 {"ctime", "float time when an inode was last changed"},
203 {"otime", "float time when this subvolume was created"},
204 {"stime", "float time, usually zero"},
205 {"rtime", "float time when this subvolume was received"},
209 PyStructSequence_Desc SubvolumeInfo_desc = {
210 "btrfsutil.SubvolumeInfo",
211 "Information about a Btrfs subvolume.",
212 SubvolumeInfo_fields,
216 PyTypeObject SubvolumeInfo_type;
218 PyObject *get_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds)
220 static char *keywords[] = {"path", NULL};
221 struct path_arg path = {.allow_fd = true};
222 enum btrfs_util_error err;
225 if (!PyArg_ParseTupleAndKeywords(args, kwds,
226 "O&:get_subvolume_read_only",
227 keywords, &path_converter, &path))
231 err = btrfs_util_get_subvolume_read_only(path.path, &read_only);
233 err = btrfs_util_get_subvolume_read_only_fd(path.fd,
237 SetFromBtrfsUtilErrorWithPath(err, &path);
243 return PyBool_FromLong(read_only);
246 PyObject *set_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds)
248 static char *keywords[] = {"path", "read_only", NULL};
249 struct path_arg path = {.allow_fd = true};
250 enum btrfs_util_error err;
253 if (!PyArg_ParseTupleAndKeywords(args, kwds,
254 "O&|p:set_subvolume_read_only",
255 keywords, &path_converter, &path,
260 err = btrfs_util_set_subvolume_read_only(path.path, read_only);
262 err = btrfs_util_set_subvolume_read_only_fd(path.fd, read_only);
264 SetFromBtrfsUtilErrorWithPath(err, &path);
273 PyObject *get_default_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
275 static char *keywords[] = {"path", NULL};
276 struct path_arg path = {.allow_fd = true};
277 enum btrfs_util_error err;
280 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get_default_subvolume",
281 keywords, &path_converter, &path))
285 err = btrfs_util_get_default_subvolume(path.path, &id);
287 err = btrfs_util_get_default_subvolume_fd(path.fd, &id);
289 SetFromBtrfsUtilErrorWithPath(err, &path);
295 return PyLong_FromUnsignedLongLong(id);
298 PyObject *set_default_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
300 static char *keywords[] = {"path", "id", NULL};
301 struct path_arg path = {.allow_fd = true};
302 enum btrfs_util_error err;
305 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:set_default_subvolume",
306 keywords, &path_converter, &path, &id))
310 err = btrfs_util_set_default_subvolume(path.path, id);
312 err = btrfs_util_set_default_subvolume_fd(path.fd, id);
314 SetFromBtrfsUtilErrorWithPath(err, &path);
323 PyObject *create_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
325 static char *keywords[] = {"path", "async", "qgroup_inherit", NULL};
326 struct path_arg path = {.allow_fd = false};
327 enum btrfs_util_error err;
329 QgroupInherit *inherit = NULL;
332 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|pO!:create_subvolume",
333 keywords, &path_converter, &path,
334 &async, &QgroupInherit_type, &inherit))
337 err = btrfs_util_create_subvolume(path.path, 0, async ? &transid : NULL,
338 inherit ? inherit->inherit : NULL);
340 SetFromBtrfsUtilErrorWithPath(err, &path);
347 return PyLong_FromUnsignedLongLong(transid);
354 struct btrfs_util_subvolume_iterator *iter;
358 static void SubvolumeIterator_dealloc(SubvolumeIterator *self)
360 btrfs_util_destroy_subvolume_iterator(self->iter);
361 Py_TYPE(self)->tp_free((PyObject *)self);
364 static PyObject *SubvolumeIterator_next(SubvolumeIterator *self)
366 enum btrfs_util_error err;
371 PyErr_SetString(PyExc_ValueError,
372 "operation on closed iterator");
377 struct btrfs_util_subvolume_info subvol;
379 err = btrfs_util_subvolume_iterator_next_info(self->iter, &path,
381 if (err == BTRFS_UTIL_ERROR_STOP_ITERATION) {
382 PyErr_SetNone(PyExc_StopIteration);
385 SetFromBtrfsUtilError(err);
389 tmp = subvolume_info_to_object(&subvol);
393 err = btrfs_util_subvolume_iterator_next(self->iter, &path, &id);
394 if (err == BTRFS_UTIL_ERROR_STOP_ITERATION) {
395 PyErr_SetNone(PyExc_StopIteration);
398 SetFromBtrfsUtilError(err);
402 tmp = PyLong_FromUnsignedLongLong(id);
406 ret = Py_BuildValue("O&O", PyUnicode_DecodeFSDefault, path,
416 static int SubvolumeIterator_init(SubvolumeIterator *self, PyObject *args,
419 static char *keywords[] = {"path", "top", "info", "post_order", NULL};
420 struct path_arg path = {.allow_fd = true};
421 enum btrfs_util_error err;
422 unsigned long long top = 5;
427 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|Kpp:SubvolumeIterator",
428 keywords, &path_converter, &path, &top,
433 flags |= BTRFS_UTIL_SUBVOLUME_ITERATOR_POST_ORDER;
436 err = btrfs_util_create_subvolume_iterator(path.path, top,
439 err = btrfs_util_create_subvolume_iterator_fd(path.fd, top,
444 SetFromBtrfsUtilErrorWithPath(err, &path);
454 static PyObject *SubvolumeIterator_close(SubvolumeIterator *self)
457 btrfs_util_destroy_subvolume_iterator(self->iter);
463 static PyObject *SubvolumeIterator_fileno(SubvolumeIterator *self)
466 PyErr_SetString(PyExc_ValueError,
467 "operation on closed iterator");
470 return PyLong_FromLong(btrfs_util_subvolume_iterator_fd(self->iter));
473 static PyObject *SubvolumeIterator_enter(SubvolumeIterator *self)
475 Py_INCREF((PyObject *)self);
476 return (PyObject *)self;
479 static PyObject *SubvolumeIterator_exit(SubvolumeIterator *self, PyObject *args,
482 static char *keywords[] = {"exc_type", "exc_value", "traceback", NULL};
483 PyObject *exc_type, *exc_value, *traceback;
485 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO:__exit__", keywords,
486 &exc_type, &exc_value, &traceback))
489 return SubvolumeIterator_close(self);
492 #define SubvolumeIterator_DOC \
493 "SubvolumeIterator(path, top=0, info=False, post_order=False) -> new subvolume iterator\n\n" \
494 "Create a new iterator that produces tuples of (path, ID) representing\n" \
495 "subvolumes on a filesystem.\n\n" \
497 "path -- string, bytes, path-like object, or open file descriptor in\n" \
498 "filesystem to list\n" \
499 "top -- if not zero, instead of only listing subvolumes beneath the\n" \
500 "given path, list subvolumes beneath the subvolume with this ID; passing\n" \
501 "BTRFS_FS_TREE_OBJECTID (5) here lists all subvolumes. The subvolumes\n" \
502 "are listed relative to the subvolume with this ID.\n" \
503 "info -- bool indicating the iterator should yield SubvolumeInfo instead of\n" \
504 "the subvolume ID\n" \
505 "post_order -- bool indicating whether to yield parent subvolumes before\n" \
506 "child subvolumes (e.g., 'foo/bar' before 'foo')"
508 static PyMethodDef SubvolumeIterator_methods[] = {
509 {"close", (PyCFunction)SubvolumeIterator_close,
512 "Close this iterator."},
513 {"fileno", (PyCFunction)SubvolumeIterator_fileno,
515 "fileno() -> int\n\n"
516 "Get the file descriptor associated with this iterator."},
517 {"__enter__", (PyCFunction)SubvolumeIterator_enter,
519 {"__exit__", (PyCFunction)SubvolumeIterator_exit,
520 METH_VARARGS | METH_KEYWORDS, ""},
524 PyTypeObject SubvolumeIterator_type = {
525 PyVarObject_HEAD_INIT(NULL, 0)
526 "btrfsutil.SubvolumeIterator", /* tp_name */
527 sizeof(SubvolumeIterator), /* tp_basicsize */
529 (destructor)SubvolumeIterator_dealloc, /* tp_dealloc */
531 NULL, /* tp_getattr */
532 NULL, /* tp_setattr */
533 NULL, /* tp_as_async */
535 NULL, /* tp_as_number */
536 NULL, /* tp_as_sequence */
537 NULL, /* tp_as_mapping */
541 NULL, /* tp_getattro */
542 NULL, /* tp_setattro */
543 NULL, /* tp_as_buffer */
544 Py_TPFLAGS_DEFAULT, /* tp_flags */
545 SubvolumeIterator_DOC, /* tp_doc */
546 NULL, /* tp_traverse */
548 NULL, /* tp_richcompare */
549 0, /* tp_weaklistoffset */
550 PyObject_SelfIter, /* tp_iter */
551 (iternextfunc)SubvolumeIterator_next, /* tp_iternext */
552 SubvolumeIterator_methods, /* tp_methods */
553 NULL, /* tp_members */
554 NULL, /* tp_getset */
557 NULL, /* tp_descr_get */
558 NULL, /* tp_descr_set */
559 0, /* tp_dictoffset */
560 (initproc)SubvolumeIterator_init, /* tp_init */