packaging: Enable LTO and set visibility to hidden
[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 PyObject *list_from_uint64_array(const uint64_t *arr, size_t n)
129 {
130     PyObject *ret;
131     size_t i;
132
133     ret = PyList_New(n);
134     if (!ret)
135             return NULL;
136
137     for (i = 0; i < n; i++) {
138             PyObject *tmp;
139
140             tmp = PyLong_FromUnsignedLongLong(arr[i]);
141             if (!tmp) {
142                     Py_DECREF(ret);
143                     return NULL;
144             }
145             PyList_SET_ITEM(ret, i, tmp);
146     }
147
148     return ret;
149 }
150
151 void path_cleanup(struct path_arg *path)
152 {
153         Py_CLEAR(path->object);
154         Py_CLEAR(path->cleanup);
155 }
156
157 static PyMethodDef btrfsutil_methods[] = {
158         {"sync", (PyCFunction)filesystem_sync,
159          METH_VARARGS | METH_KEYWORDS,
160          "sync(path)\n\n"
161          "Sync a specific Btrfs filesystem.\n\n"
162          "Arguments:\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"
169          "Arguments:\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"
175          "Arguments:\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"
178          "transaction"},
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"
183          "Arguments:\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"
189          "Arguments:\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"
195          "Arguments:\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"
203          "Arguments:\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"
211          "Arguments:\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"
217          "Arguments:\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"
224          "Arguments:\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"
230          "Arguments:\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"
238          "Arguments:\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"
246          "Arguments:\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"
257          "Arguments:\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"
265          "cleaned up\n\n"
266          "Arguments:\n"
267          "path -- string, bytes, path-like object, or open file descriptor"},
268         {},
269 };
270
271 static struct PyModuleDef btrfsutilmodule = {
272         PyModuleDef_HEAD_INIT,
273         "btrfsutil",
274         "Library for managing Btrfs filesystems",
275         -1,
276         btrfsutil_methods,
277 };
278
279 PyMODINIT_FUNC
280 PyInit_btrfsutil(void)
281 {
282         PyObject *m;
283
284         BtrfsUtilError_type.tp_base = (PyTypeObject *)PyExc_OSError;
285         if (PyType_Ready(&BtrfsUtilError_type) < 0)
286                 return NULL;
287
288         if (PyStructSequence_InitType2(&SubvolumeInfo_type, &SubvolumeInfo_desc) < 0)
289                 return NULL;
290
291         SubvolumeIterator_type.tp_new = PyType_GenericNew;
292         if (PyType_Ready(&SubvolumeIterator_type) < 0)
293                 return NULL;
294
295         QgroupInherit_type.tp_new = PyType_GenericNew;
296         if (PyType_Ready(&QgroupInherit_type) < 0)
297                 return NULL;
298
299         m = PyModule_Create(&btrfsutilmodule);
300         if (!m)
301                 return NULL;
302
303         Py_INCREF(&BtrfsUtilError_type);
304         PyModule_AddObject(m, "BtrfsUtilError",
305                            (PyObject *)&BtrfsUtilError_type);
306
307         Py_INCREF(&SubvolumeInfo_type);
308         PyModule_AddObject(m, "SubvolumeInfo", (PyObject *)&SubvolumeInfo_type);
309
310         Py_INCREF(&SubvolumeIterator_type);
311         PyModule_AddObject(m, "SubvolumeIterator",
312                            (PyObject *)&SubvolumeIterator_type);
313
314         Py_INCREF(&QgroupInherit_type);
315         PyModule_AddObject(m, "QgroupInherit",
316                            (PyObject *)&QgroupInherit_type);
317
318         add_module_constants(m);
319
320         return m;
321 }