libbtrfsutil: add qgroup inheritance helpers
[platform/upstream/btrfs-progs.git] / libbtrfsutil / python / module.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 static int fd_converter(PyObject *o, void *p)
23 {
24         int *fd = p;
25         long tmp;
26         int overflow;
27
28         tmp = PyLong_AsLongAndOverflow(o, &overflow);
29         if (tmp == -1 && PyErr_Occurred())
30                 return 0;
31         if (overflow > 0 || tmp > INT_MAX) {
32                 PyErr_SetString(PyExc_OverflowError,
33                                 "fd is greater than maximum");
34                 return 0;
35         }
36         if (overflow < 0 || tmp < 0) {
37                 PyErr_SetString(PyExc_ValueError, "fd is negative");
38                 return 0;
39         }
40         *fd = tmp;
41         return 1;
42 }
43
44 int path_converter(PyObject *o, void *p)
45 {
46         struct path_arg *path = p;
47         int is_index, is_bytes, is_unicode;
48         PyObject *bytes = NULL;
49         Py_ssize_t length = 0;
50         char *tmp;
51
52         if (o == NULL) {
53                 path_cleanup(p);
54                 return 1;
55         }
56
57         path->object = path->cleanup = NULL;
58         Py_INCREF(o);
59
60         path->fd = -1;
61
62         is_index = path->allow_fd && PyIndex_Check(o);
63         is_bytes = PyBytes_Check(o);
64         is_unicode = PyUnicode_Check(o);
65
66         if (!is_index && !is_bytes && !is_unicode) {
67                 _Py_IDENTIFIER(__fspath__);
68                 PyObject *func;
69
70                 func = _PyObject_LookupSpecial(o, &PyId___fspath__);
71                 if (func == NULL)
72                         goto err_format;
73                 Py_DECREF(o);
74                 o = PyObject_CallFunctionObjArgs(func, NULL);
75                 Py_DECREF(func);
76                 if (o == NULL)
77                         return 0;
78                 is_bytes = PyBytes_Check(o);
79                 is_unicode = PyUnicode_Check(o);
80         }
81
82         if (is_unicode) {
83                 if (!PyUnicode_FSConverter(o, &bytes))
84                         goto err;
85         } else if (is_bytes) {
86                 bytes = o;
87                 Py_INCREF(bytes);
88         } else if (is_index) {
89                 if (!fd_converter(o, &path->fd))
90                         goto err;
91                 path->path = NULL;
92                 goto out;
93         } else {
94 err_format:
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",
98                              Py_TYPE(o)->tp_name);
99                 goto err;
100         }
101
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");
107                 goto err;
108         }
109
110         path->path = tmp;
111         if (bytes == o)
112                 Py_DECREF(bytes);
113         else
114                 path->cleanup = bytes;
115         path->fd = -1;
116
117 out:
118         path->length = length;
119         path->object = o;
120         return Py_CLEANUP_SUPPORTED;
121
122 err:
123         Py_XDECREF(o);
124         Py_XDECREF(bytes);
125         return 0;
126 }
127
128 void path_cleanup(struct path_arg *path)
129 {
130         Py_CLEAR(path->object);
131         Py_CLEAR(path->cleanup);
132 }
133
134 static PyMethodDef btrfsutil_methods[] = {
135         {},
136 };
137
138 static struct PyModuleDef btrfsutilmodule = {
139         PyModuleDef_HEAD_INIT,
140         "btrfsutil",
141         "Library for managing Btrfs filesystems",
142         -1,
143         btrfsutil_methods,
144 };
145
146 PyMODINIT_FUNC
147 PyInit_btrfsutil(void)
148 {
149         PyObject *m;
150
151         BtrfsUtilError_type.tp_base = (PyTypeObject *)PyExc_OSError;
152         if (PyType_Ready(&BtrfsUtilError_type) < 0)
153                 return NULL;
154
155         QgroupInherit_type.tp_new = PyType_GenericNew;
156         if (PyType_Ready(&QgroupInherit_type) < 0)
157                 return NULL;
158
159         m = PyModule_Create(&btrfsutilmodule);
160         if (!m)
161                 return NULL;
162
163         Py_INCREF(&BtrfsUtilError_type);
164         PyModule_AddObject(m, "BtrfsUtilError",
165                            (PyObject *)&BtrfsUtilError_type);
166
167         Py_INCREF(&QgroupInherit_type);
168         PyModule_AddObject(m, "QgroupInherit",
169                            (PyObject *)&QgroupInherit_type);
170
171         add_module_constants(m);
172
173         return m;
174 }