btrfs-progs: tests: update README, images, coding style
[platform/upstream/btrfs-progs.git] / libbtrfsutil / python / error.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 typedef struct {
23         PyOSErrorObject os_error;
24         PyObject *btrfsutilerror;
25 } BtrfsUtilError;
26
27 void SetFromBtrfsUtilError(enum btrfs_util_error err)
28 {
29         SetFromBtrfsUtilErrorWithPaths(err, NULL, NULL);
30 }
31
32 void SetFromBtrfsUtilErrorWithPath(enum btrfs_util_error err,
33                                    struct path_arg *path1)
34 {
35         SetFromBtrfsUtilErrorWithPaths(err, path1, NULL);
36 }
37
38 void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err,
39                                     struct path_arg *path1,
40                                     struct path_arg *path2)
41 {
42         PyObject *strobj, *args, *exc;
43         int i = errno;
44         const char *str1 = btrfs_util_strerror(err), *str2 = strerror(i);
45
46         if (str1 && str2 && strcmp(str1, str2) != 0) {
47                 strobj = PyUnicode_FromFormat("%s: %s", str1, str2);
48         } else if (str1) {
49                 strobj = PyUnicode_FromString(str1);
50         } else if (str2) {
51                 strobj = PyUnicode_FromString(str2);
52         } else {
53                 Py_INCREF(Py_None);
54                 strobj = Py_None;
55         }
56         if (strobj == NULL)
57                 return;
58
59         args = Py_BuildValue("iOOOOi", i, strobj,
60                              path1 ? path1->object : Py_None, Py_None,
61                              path2 ? path2->object : Py_None, (int)err);
62         Py_DECREF(strobj);
63         if (args == NULL)
64                 return;
65
66         exc = PyObject_CallObject((PyObject *)&BtrfsUtilError_type, args);
67         Py_DECREF(args);
68         if (exc == NULL)
69                 return;
70
71         PyErr_SetObject((PyObject *)&BtrfsUtilError_type, exc);
72         Py_DECREF(exc);
73 }
74
75 static int BtrfsUtilError_clear(BtrfsUtilError *self)
76 {
77         Py_CLEAR(self->btrfsutilerror);
78         return Py_TYPE(self)->tp_base->tp_clear((PyObject *)self);
79 }
80
81 static void BtrfsUtilError_dealloc(BtrfsUtilError *self)
82 {
83         PyObject_GC_UnTrack(self);
84         BtrfsUtilError_clear(self);
85         Py_TYPE(self)->tp_free((PyObject *)self);
86 }
87
88 static int BtrfsUtilError_traverse(BtrfsUtilError *self, visitproc visit,
89                                    void *arg)
90 {
91         Py_VISIT(self->btrfsutilerror);
92         return Py_TYPE(self)->tp_base->tp_traverse((PyObject *)self, visit, arg);
93 }
94
95 static PyObject *BtrfsUtilError_new(PyTypeObject *type, PyObject *args,
96                                     PyObject *kwds)
97 {
98         BtrfsUtilError *self;
99         PyObject *oserror_args = args;
100
101         if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 6) {
102                 oserror_args = PyTuple_GetSlice(args, 0, 5);
103                 if (oserror_args == NULL)
104                         return NULL;
105         }
106
107         self = (BtrfsUtilError *)type->tp_base->tp_new(type, oserror_args,
108                                                        kwds);
109         if (oserror_args != args)
110                 Py_DECREF(oserror_args);
111         if (self == NULL)
112                 return NULL;
113
114         if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 6) {
115                 self->btrfsutilerror = PyTuple_GET_ITEM(args, 5);
116                 Py_INCREF(self->btrfsutilerror);
117         }
118
119         return (PyObject *)self;
120 }
121
122 static PyObject *BtrfsUtilError_str(BtrfsUtilError *self)
123 {
124 #define OR_NONE(x) ((x) ? (x) : Py_None)
125         if (self->btrfsutilerror) {
126                 if (self->os_error.filename) {
127                         if (self->os_error.filename2) {
128                                 return PyUnicode_FromFormat("[BtrfsUtilError %S Errno %S] %S: %R -> %R",
129                                                             OR_NONE(self->btrfsutilerror),
130                                                             OR_NONE(self->os_error.myerrno),
131                                                             OR_NONE(self->os_error.strerror),
132                                                             self->os_error.filename,
133                                                             self->os_error.filename2);
134                         } else {
135                                 return PyUnicode_FromFormat("[BtrfsUtilError %S Errno %S] %S: %R",
136                                                             OR_NONE(self->btrfsutilerror),
137                                                             OR_NONE(self->os_error.myerrno),
138                                                             OR_NONE(self->os_error.strerror),
139                                                             self->os_error.filename);
140                         }
141                 }
142                 if (self->os_error.myerrno && self->os_error.strerror) {
143                         return PyUnicode_FromFormat("[BtrfsUtilError %S Errno %S] %S",
144                                                     self->btrfsutilerror,
145                                                     self->os_error.myerrno,
146                                                     self->os_error.strerror);
147                 }
148         }
149         return Py_TYPE(self)->tp_base->tp_str((PyObject *)self);
150 #undef OR_NONE
151 }
152
153 static PyMemberDef BtrfsUtilError_members[] = {
154         {"btrfsutilerror", T_OBJECT,
155          offsetof(BtrfsUtilError, btrfsutilerror), 0,
156          "btrfsutil error code"},
157         {},
158 };
159
160 #define BtrfsUtilError_DOC      \
161         "Btrfs operation error."
162
163 PyTypeObject BtrfsUtilError_type = {
164         PyVarObject_HEAD_INIT(NULL, 0)
165         "btrfsutil.BtrfsUtilError",                     /* tp_name */
166         sizeof(BtrfsUtilError),                         /* tp_basicsize */
167         0,                                              /* tp_itemsize */
168         (destructor)BtrfsUtilError_dealloc,             /* tp_dealloc */
169         NULL,                                           /* tp_print */
170         NULL,                                           /* tp_getattr */
171         NULL,                                           /* tp_setattr */
172         NULL,                                           /* tp_as_async */
173         NULL,                                           /* tp_repr */
174         NULL,                                           /* tp_as_number */
175         NULL,                                           /* tp_as_sequence */
176         NULL,                                           /* tp_as_mapping */
177         NULL,                                           /* tp_hash  */
178         NULL,                                           /* tp_call */
179         (reprfunc)BtrfsUtilError_str,                   /* tp_str */
180         NULL,                                           /* tp_getattro */
181         NULL,                                           /* tp_setattro */
182         NULL,                                           /* tp_as_buffer */
183         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /* tp_flags */
184         BtrfsUtilError_DOC,                             /* tp_doc */
185         (traverseproc)BtrfsUtilError_traverse,          /* tp_traverse */
186         (inquiry)BtrfsUtilError_clear,                  /* tp_clear */
187         NULL,                                           /* tp_richcompare */
188         0,                                              /* tp_weaklistoffset */
189         NULL,                                           /* tp_iter */
190         NULL,                                           /* tp_iternext */
191         NULL,                                           /* tp_methods */
192         BtrfsUtilError_members,                         /* tp_members */
193         NULL,                                           /* tp_getset */
194         NULL,                                           /* tp_base */
195         NULL,                                           /* tp_dict */
196         NULL,                                           /* tp_descr_get */
197         NULL,                                           /* tp_descr_set */
198         offsetof(BtrfsUtilError, os_error.dict),        /* tp_dictoffset */
199         NULL,                                           /* tp_init */
200         NULL,                                           /* tp_alloc */
201         BtrfsUtilError_new,                             /* tp_new */
202 };