packaging: Enable LTO and set visibility to hidden
[platform/upstream/btrfs-progs.git] / libbtrfsutil / python / subvolume.c
1 /*
2  * Copyright (C) 2018 Facebook
3  *
4  * This file is part of libbtrfsutil.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "btrfsutilpy.h"
21
22 PyObject *is_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
23 {
24         static char *keywords[] = {"path", NULL};
25         struct path_arg path = {.allow_fd = true};
26         enum btrfs_util_error err;
27
28         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:is_subvolume",
29                                          keywords, &path_converter, &path))
30                 return NULL;
31
32         if (path.path)
33                 err = btrfs_util_is_subvolume(path.path);
34         else
35                 err = btrfs_util_is_subvolume_fd(path.fd);
36         if (err == BTRFS_UTIL_OK) {
37                 path_cleanup(&path);
38                 Py_RETURN_TRUE;
39         } else if (err == BTRFS_UTIL_ERROR_NOT_BTRFS ||
40                    err == BTRFS_UTIL_ERROR_NOT_SUBVOLUME) {
41                 path_cleanup(&path);
42                 Py_RETURN_FALSE;
43         } else {
44                 SetFromBtrfsUtilErrorWithPath(err, &path);
45                 path_cleanup(&path);
46                 return NULL;
47         }
48 }
49
50 PyObject *subvolume_id(PyObject *self, PyObject *args, PyObject *kwds)
51 {
52         static char *keywords[] = {"path", NULL};
53         struct path_arg path = {.allow_fd = true};
54         enum btrfs_util_error err;
55         uint64_t id;
56
57         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:subvolume_id",
58                                          keywords, &path_converter, &path))
59                 return NULL;
60
61         if (path.path)
62                 err = btrfs_util_subvolume_id(path.path, &id);
63         else
64                 err = btrfs_util_subvolume_id_fd(path.fd, &id);
65         if (err) {
66                 SetFromBtrfsUtilErrorWithPath(err, &path);
67                 path_cleanup(&path);
68                 return NULL;
69         }
70
71         path_cleanup(&path);
72         return PyLong_FromUnsignedLongLong(id);
73 }
74
75 PyObject *subvolume_path(PyObject *self, PyObject *args, PyObject *kwds)
76 {
77         static char *keywords[] = {"path", "id", NULL};
78         struct path_arg path = {.allow_fd = true};
79         enum btrfs_util_error err;
80         uint64_t id = 0;
81         char *subvol_path;
82         PyObject *ret;
83
84         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:subvolume_path",
85                                          keywords, &path_converter, &path, &id))
86                 return NULL;
87
88         if (path.path)
89                 err = btrfs_util_subvolume_path(path.path, id, &subvol_path);
90         else
91                 err = btrfs_util_subvolume_path_fd(path.fd, id, &subvol_path);
92         if (err) {
93                 SetFromBtrfsUtilErrorWithPath(err, &path);
94                 path_cleanup(&path);
95                 return NULL;
96         }
97
98         path_cleanup(&path);
99
100         ret = PyUnicode_DecodeFSDefault(subvol_path);
101         free(subvol_path);
102         return ret;
103 }
104
105 static PyObject *subvolume_info_to_object(const struct btrfs_util_subvolume_info *subvol)
106 {
107         PyObject *ret, *tmp;
108
109         ret = PyStructSequence_New(&SubvolumeInfo_type);
110         if (ret == NULL)
111                 return NULL;
112
113 #define SET_UINT64(i, field)                                    \
114         tmp = PyLong_FromUnsignedLongLong(subvol->field);       \
115         if (tmp == NULL) {                                      \
116                 Py_DECREF(ret);                                 \
117                 return ret;                                     \
118         }                                                       \
119         PyStructSequence_SET_ITEM(ret, i, tmp);
120
121 #define SET_UUID(i, field)                                              \
122         tmp = PyBytes_FromStringAndSize((char *)subvol->field, 16);     \
123         if (tmp == NULL) {                                              \
124                 Py_DECREF(ret);                                         \
125                 return ret;                                             \
126         }                                                               \
127         PyStructSequence_SET_ITEM(ret, i, tmp);
128
129 #define SET_TIME(i, field)                                              \
130         tmp = PyFloat_FromDouble(subvol->field.tv_sec +                 \
131                                  subvol->field.tv_nsec / 1000000000);   \
132         if (tmp == NULL) {                                              \
133                 Py_DECREF(ret);                                         \
134                 return ret;                                             \
135         }                                                               \
136         PyStructSequence_SET_ITEM(ret, i, tmp);
137
138         SET_UINT64(0, id);
139         SET_UINT64(1, parent_id);
140         SET_UINT64(2, dir_id);
141         SET_UINT64(3, flags);
142         SET_UUID(4, uuid);
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);
150         SET_TIME(12, ctime);
151         SET_TIME(13, otime);
152         SET_TIME(14, stime);
153         SET_TIME(15, rtime);
154
155 #undef SET_TIME
156 #undef SET_UUID
157 #undef SET_UINT64
158
159         return ret;
160 }
161
162 PyObject *subvolume_info(PyObject *self, PyObject *args, PyObject *kwds)
163 {
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;
168         uint64_t id = 0;
169
170         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:subvolume_info",
171                                          keywords, &path_converter, &path, &id))
172                 return NULL;
173
174         if (path.path)
175                 err = btrfs_util_subvolume_info(path.path, id, &subvol);
176         else
177                 err = btrfs_util_subvolume_info_fd(path.fd, id, &subvol);
178         if (err) {
179                 SetFromBtrfsUtilErrorWithPath(err, &path);
180                 path_cleanup(&path);
181                 return NULL;
182         }
183
184         path_cleanup(&path);
185
186         return subvolume_info_to_object(&subvol);
187 }
188
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"},
206         {},
207 };
208
209 PyStructSequence_Desc SubvolumeInfo_desc = {
210         "btrfsutil.SubvolumeInfo",
211         "Information about a Btrfs subvolume.",
212         SubvolumeInfo_fields,
213         14,
214 };
215
216 PyTypeObject SubvolumeInfo_type;
217
218 PyObject *get_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds)
219 {
220         static char *keywords[] = {"path", NULL};
221         struct path_arg path = {.allow_fd = true};
222         enum btrfs_util_error err;
223         bool read_only;
224
225         if (!PyArg_ParseTupleAndKeywords(args, kwds,
226                                          "O&:get_subvolume_read_only",
227                                          keywords, &path_converter, &path))
228                 return NULL;
229
230         if (path.path) {
231                 err = btrfs_util_get_subvolume_read_only(path.path, &read_only);
232         } else {
233                 err = btrfs_util_get_subvolume_read_only_fd(path.fd,
234                                                             &read_only);
235         }
236         if (err) {
237                 SetFromBtrfsUtilErrorWithPath(err, &path);
238                 path_cleanup(&path);
239                 return NULL;
240         }
241
242         path_cleanup(&path);
243         return PyBool_FromLong(read_only);
244 }
245
246 PyObject *set_subvolume_read_only(PyObject *self, PyObject *args, PyObject *kwds)
247 {
248         static char *keywords[] = {"path", "read_only", NULL};
249         struct path_arg path = {.allow_fd = true};
250         enum btrfs_util_error err;
251         int read_only = 1;
252
253         if (!PyArg_ParseTupleAndKeywords(args, kwds,
254                                          "O&|p:set_subvolume_read_only",
255                                          keywords, &path_converter, &path,
256                                          &read_only))
257                 return NULL;
258
259         if (path.path)
260                 err = btrfs_util_set_subvolume_read_only(path.path, read_only);
261         else
262                 err = btrfs_util_set_subvolume_read_only_fd(path.fd, read_only);
263         if (err) {
264                 SetFromBtrfsUtilErrorWithPath(err, &path);
265                 path_cleanup(&path);
266                 return NULL;
267         }
268
269         path_cleanup(&path);
270         Py_RETURN_NONE;
271 }
272
273 PyObject *get_default_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
274 {
275         static char *keywords[] = {"path", NULL};
276         struct path_arg path = {.allow_fd = true};
277         enum btrfs_util_error err;
278         uint64_t id;
279
280         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get_default_subvolume",
281                                          keywords, &path_converter, &path))
282                 return NULL;
283
284         if (path.path)
285                 err = btrfs_util_get_default_subvolume(path.path, &id);
286         else
287                 err = btrfs_util_get_default_subvolume_fd(path.fd, &id);
288         if (err) {
289                 SetFromBtrfsUtilErrorWithPath(err, &path);
290                 path_cleanup(&path);
291                 return NULL;
292         }
293
294         path_cleanup(&path);
295         return PyLong_FromUnsignedLongLong(id);
296 }
297
298 PyObject *set_default_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
299 {
300         static char *keywords[] = {"path", "id", NULL};
301         struct path_arg path = {.allow_fd = true};
302         enum btrfs_util_error err;
303         uint64_t id = 0;
304
305         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:set_default_subvolume",
306                                          keywords, &path_converter, &path, &id))
307                 return NULL;
308
309         if (path.path)
310                 err = btrfs_util_set_default_subvolume(path.path, id);
311         else
312                 err = btrfs_util_set_default_subvolume_fd(path.fd, id);
313         if (err) {
314                 SetFromBtrfsUtilErrorWithPath(err, &path);
315                 path_cleanup(&path);
316                 return NULL;
317         }
318
319         path_cleanup(&path);
320         Py_RETURN_NONE;
321 }
322
323 PyObject *create_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
324 {
325         static char *keywords[] = {"path", "async", "qgroup_inherit", NULL};
326         struct path_arg path = {.allow_fd = false};
327         enum btrfs_util_error err;
328         int async = 0;
329         QgroupInherit *inherit = NULL;
330         uint64_t transid;
331
332         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|pO!:create_subvolume",
333                                          keywords, &path_converter, &path,
334                                          &async, &QgroupInherit_type, &inherit))
335                 return NULL;
336
337         err = btrfs_util_create_subvolume(path.path, 0, async ? &transid : NULL,
338                                           inherit ? inherit->inherit : NULL);
339         if (err) {
340                 SetFromBtrfsUtilErrorWithPath(err, &path);
341                 path_cleanup(&path);
342                 return NULL;
343         }
344
345         path_cleanup(&path);
346         if (async)
347                 return PyLong_FromUnsignedLongLong(transid);
348         else
349                 Py_RETURN_NONE;
350 }
351
352 PyObject *create_snapshot(PyObject *self, PyObject *args, PyObject *kwds)
353 {
354         static char *keywords[] = {
355                 "source", "path", "recursive", "read_only", "async",
356                 "qgroup_inherit", NULL,
357         };
358         struct path_arg src = {.allow_fd = true}, dst = {.allow_fd = false};
359         enum btrfs_util_error err;
360         int recursive = 0, read_only = 0, async = 0;
361         int flags = 0;
362         QgroupInherit *inherit = NULL;
363         uint64_t transid;
364
365         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&|pppO!:create_snapshot",
366                                          keywords, &path_converter, &src,
367                                          &path_converter, &dst, &recursive,
368                                          &read_only, &async,
369                                          &QgroupInherit_type, &inherit))
370                 return NULL;
371
372         if (recursive)
373                 flags |= BTRFS_UTIL_CREATE_SNAPSHOT_RECURSIVE;
374         if (read_only)
375                 flags |= BTRFS_UTIL_CREATE_SNAPSHOT_READ_ONLY;
376
377         if (src.path) {
378                 err = btrfs_util_create_snapshot(src.path, dst.path, flags,
379                                                  async ? &transid : NULL,
380                                                  inherit ? inherit->inherit : NULL);
381         } else {
382                 err = btrfs_util_create_snapshot_fd(src.fd, dst.path, flags,
383                                                     async ? &transid : NULL,
384                                                     inherit ? inherit->inherit : NULL);
385         }
386         if (err) {
387                 SetFromBtrfsUtilErrorWithPaths(err, &src, &dst);
388                 path_cleanup(&src);
389                 path_cleanup(&dst);
390                 return NULL;
391         }
392
393         path_cleanup(&src);
394         path_cleanup(&dst);
395         if (async)
396                 return PyLong_FromUnsignedLongLong(transid);
397         else
398                 Py_RETURN_NONE;
399 }
400
401 PyObject *delete_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
402 {
403         static char *keywords[] = {"path", "recursive", NULL};
404         struct path_arg path = {.allow_fd = false};
405         enum btrfs_util_error err;
406         int recursive = 0;
407         int flags = 0;
408
409         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|p:delete_subvolume",
410                                          keywords, &path_converter, &path,
411                                          &recursive))
412                 return NULL;
413
414         if (recursive)
415                 flags |= BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE;
416
417         err = btrfs_util_delete_subvolume(path.path, flags);
418         if (err) {
419                 SetFromBtrfsUtilErrorWithPath(err, &path);
420                 path_cleanup(&path);
421                 return NULL;
422         }
423
424         path_cleanup(&path);
425         Py_RETURN_NONE;
426 }
427
428 PyObject *deleted_subvolumes(PyObject *self, PyObject *args, PyObject *kwds)
429 {
430         static char *keywords[] = {"path", NULL};
431         struct path_arg path = {.allow_fd = true};
432         PyObject *ret;
433         uint64_t *ids;
434         size_t n;
435         enum btrfs_util_error err;
436
437         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:deleted_subvolumes",
438                                          keywords, &path_converter, &path))
439                 return NULL;
440
441         if (path.path)
442                 err = btrfs_util_deleted_subvolumes(path.path, &ids, &n);
443         else
444                 err = btrfs_util_deleted_subvolumes_fd(path.fd, &ids, &n);
445         if (err) {
446                 SetFromBtrfsUtilErrorWithPath(err, &path);
447                 path_cleanup(&path);
448                 return NULL;
449         }
450
451         path_cleanup(&path);
452
453         ret = list_from_uint64_array(ids, n);
454         free(ids);
455         return ret;
456 }
457
458 typedef struct {
459         PyObject_HEAD
460         struct btrfs_util_subvolume_iterator *iter;
461         bool info;
462 } SubvolumeIterator;
463
464 static void SubvolumeIterator_dealloc(SubvolumeIterator *self)
465 {
466         btrfs_util_destroy_subvolume_iterator(self->iter);
467         Py_TYPE(self)->tp_free((PyObject *)self);
468 }
469
470 static PyObject *SubvolumeIterator_next(SubvolumeIterator *self)
471 {
472         enum btrfs_util_error err;
473         PyObject *ret, *tmp;
474         char *path;
475
476         if (!self->iter) {
477                 PyErr_SetString(PyExc_ValueError,
478                                 "operation on closed iterator");
479                 return NULL;
480         }
481
482         if (self->info) {
483                 struct btrfs_util_subvolume_info subvol;
484
485                 err = btrfs_util_subvolume_iterator_next_info(self->iter, &path,
486                                                               &subvol);
487                 if (err == BTRFS_UTIL_ERROR_STOP_ITERATION) {
488                         PyErr_SetNone(PyExc_StopIteration);
489                         return NULL;
490                 } else if (err) {
491                         SetFromBtrfsUtilError(err);
492                         return NULL;
493                 }
494
495                 tmp = subvolume_info_to_object(&subvol);
496         } else {
497                 uint64_t id;
498
499                 err = btrfs_util_subvolume_iterator_next(self->iter, &path, &id);
500                 if (err == BTRFS_UTIL_ERROR_STOP_ITERATION) {
501                         PyErr_SetNone(PyExc_StopIteration);
502                         return NULL;
503                 } else if (err) {
504                         SetFromBtrfsUtilError(err);
505                         return NULL;
506                 }
507
508                 tmp = PyLong_FromUnsignedLongLong(id);
509
510         }
511         if (tmp) {
512                 ret = Py_BuildValue("O&O", PyUnicode_DecodeFSDefault, path,
513                                     tmp);
514                 Py_DECREF(tmp);
515                 free(path);
516         } else {
517                 ret = NULL;
518         }
519         return ret;
520 }
521
522 static int SubvolumeIterator_init(SubvolumeIterator *self, PyObject *args,
523                                   PyObject *kwds)
524 {
525         static char *keywords[] = {"path", "top", "info", "post_order", NULL};
526         struct path_arg path = {.allow_fd = true};
527         enum btrfs_util_error err;
528         unsigned long long top = 5;
529         int info = 0;
530         int post_order = 0;
531         int flags = 0;
532
533         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|Kpp:SubvolumeIterator",
534                                          keywords, &path_converter, &path, &top,
535                                          &info, &post_order))
536                 return -1;
537
538         if (post_order)
539                 flags |= BTRFS_UTIL_SUBVOLUME_ITERATOR_POST_ORDER;
540
541         if (path.path) {
542                 err = btrfs_util_create_subvolume_iterator(path.path, top,
543                                                            flags, &self->iter);
544         } else {
545                 err = btrfs_util_create_subvolume_iterator_fd(path.fd, top,
546                                                               flags,
547                                                               &self->iter);
548         }
549         if (err) {
550                 SetFromBtrfsUtilErrorWithPath(err, &path);
551                 path_cleanup(&path);
552                 return -1;
553         }
554
555         self->info = info;
556
557         return 0;
558 }
559
560 static PyObject *SubvolumeIterator_close(SubvolumeIterator *self)
561 {
562         if (self->iter) {
563                 btrfs_util_destroy_subvolume_iterator(self->iter);
564                 self->iter = NULL;
565         }
566         Py_RETURN_NONE;
567 }
568
569 static PyObject *SubvolumeIterator_fileno(SubvolumeIterator *self)
570 {
571         if (!self->iter) {
572                 PyErr_SetString(PyExc_ValueError,
573                                 "operation on closed iterator");
574                 return NULL;
575         }
576         return PyLong_FromLong(btrfs_util_subvolume_iterator_fd(self->iter));
577 }
578
579 static PyObject *SubvolumeIterator_enter(SubvolumeIterator *self)
580 {
581         Py_INCREF((PyObject *)self);
582         return (PyObject *)self;
583 }
584
585 static PyObject *SubvolumeIterator_exit(SubvolumeIterator *self, PyObject *args,
586                                        PyObject *kwds)
587 {
588         static char *keywords[] = {"exc_type", "exc_value", "traceback", NULL};
589         PyObject *exc_type, *exc_value, *traceback;
590
591         if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO:__exit__", keywords,
592                                          &exc_type, &exc_value, &traceback))
593                 return NULL;
594
595         return SubvolumeIterator_close(self);
596 }
597
598 #define SubvolumeIterator_DOC   \
599          "SubvolumeIterator(path, top=0, info=False, post_order=False) -> new subvolume iterator\n\n"   \
600          "Create a new iterator that produces tuples of (path, ID) representing\n"      \
601          "subvolumes on a filesystem.\n\n"                                              \
602          "Arguments:\n"                                                                 \
603          "path -- string, bytes, path-like object, or open file descriptor in\n"        \
604          "filesystem to list\n"                                                         \
605          "top -- if not zero, instead of only listing subvolumes beneath the\n"         \
606          "given path, list subvolumes beneath the subvolume with this ID; passing\n"    \
607          "BTRFS_FS_TREE_OBJECTID (5) here lists all subvolumes. The subvolumes\n"       \
608          "are listed relative to the subvolume with this ID.\n"                         \
609          "info -- bool indicating the iterator should yield SubvolumeInfo instead of\n" \
610          "the subvolume ID\n"                                                           \
611          "post_order -- bool indicating whether to yield parent subvolumes before\n"    \
612          "child subvolumes (e.g., 'foo/bar' before 'foo')"
613
614 static PyMethodDef SubvolumeIterator_methods[] = {
615         {"close", (PyCFunction)SubvolumeIterator_close,
616          METH_NOARGS,
617          "close()\n\n"
618          "Close this iterator."},
619         {"fileno", (PyCFunction)SubvolumeIterator_fileno,
620          METH_NOARGS,
621          "fileno() -> int\n\n"
622          "Get the file descriptor associated with this iterator."},
623         {"__enter__", (PyCFunction)SubvolumeIterator_enter,
624          METH_NOARGS, ""},
625         {"__exit__", (PyCFunction)SubvolumeIterator_exit,
626          METH_VARARGS | METH_KEYWORDS, ""},
627         {},
628 };
629
630 PyTypeObject SubvolumeIterator_type = {
631         PyVarObject_HEAD_INIT(NULL, 0)
632         "btrfsutil.SubvolumeIterator",          /* tp_name */
633         sizeof(SubvolumeIterator),              /* tp_basicsize */
634         0,                                      /* tp_itemsize */
635         (destructor)SubvolumeIterator_dealloc,  /* tp_dealloc */
636         NULL,                                   /* tp_print */
637         NULL,                                   /* tp_getattr */
638         NULL,                                   /* tp_setattr */
639         NULL,                                   /* tp_as_async */
640         NULL,                                   /* tp_repr */
641         NULL,                                   /* tp_as_number */
642         NULL,                                   /* tp_as_sequence */
643         NULL,                                   /* tp_as_mapping */
644         NULL,                                   /* tp_hash  */
645         NULL,                                   /* tp_call */
646         NULL,                                   /* tp_str */
647         NULL,                                   /* tp_getattro */
648         NULL,                                   /* tp_setattro */
649         NULL,                                   /* tp_as_buffer */
650         Py_TPFLAGS_DEFAULT,                     /* tp_flags */
651         SubvolumeIterator_DOC,                  /* tp_doc */
652         NULL,                                   /* tp_traverse */
653         NULL,                                   /* tp_clear */
654         NULL,                                   /* tp_richcompare */
655         0,                                      /* tp_weaklistoffset */
656         PyObject_SelfIter,                      /* tp_iter */
657         (iternextfunc)SubvolumeIterator_next,   /* tp_iternext */
658         SubvolumeIterator_methods,              /* tp_methods */
659         NULL,                                   /* tp_members */
660         NULL,                                   /* tp_getset */
661         NULL,                                   /* tp_base */
662         NULL,                                   /* tp_dict */
663         NULL,                                   /* tp_descr_get */
664         NULL,                                   /* tp_descr_set */
665         0,                                      /* tp_dictoffset */
666         (initproc)SubvolumeIterator_init,       /* tp_init */
667 };