talloc: improve pytalloc error code paths if talloc* fails
[metze/samba/wip.git] / lib / talloc / pytalloc_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Python/Talloc glue
4    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU 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    This program 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 General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <Python.h>
21 #include "replace.h"
22 #include <talloc.h>
23 #include "pytalloc.h"
24 #include <assert.h>
25 #include "pytalloc_private.h"
26
27 _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
28 {
29         static PyTypeObject *type = NULL;
30         PyObject *mod;
31
32         if (type != NULL) {
33                 return type;
34         }
35
36         mod = PyImport_ImportModule("talloc");
37         if (mod == NULL) {
38                 return NULL;
39         }
40
41         type = (PyTypeObject *)PyObject_GetAttrString(mod, "Object");
42         Py_DECREF(mod);
43
44         return type;
45 }
46
47 _PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
48 {
49         static PyTypeObject *type = NULL;
50         PyObject *mod;
51
52         if (type != NULL) {
53                 return type;
54         }
55
56         mod = PyImport_ImportModule("talloc");
57         if (mod == NULL) {
58                 return NULL;
59         }
60
61         type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
62         Py_DECREF(mod);
63
64         return type;
65 }
66
67 static PyTypeObject *pytalloc_GetGenericObjectType(void)
68 {
69         static PyTypeObject *type = NULL;
70         PyObject *mod;
71
72         if (type != NULL) {
73                 return type;
74         }
75
76         mod = PyImport_ImportModule("talloc");
77         if (mod == NULL) {
78                 return NULL;
79         }
80
81         type = (PyTypeObject *)PyObject_GetAttrString(mod, "GenericObject");
82         Py_DECREF(mod);
83
84         return type;
85 }
86
87 /**
88  * Import an existing talloc pointer into a Python object.
89  */
90 _PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
91                                      void *ptr)
92 {
93         PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
94         PyTypeObject *ObjectType = pytalloc_GetObjectType();
95
96         if (mem_ctx == NULL) {
97                 return PyErr_NoMemory();
98         }
99
100         if (PyType_IsSubtype(py_type, BaseObjectType)) {
101                 pytalloc_BaseObject *ret
102                         = (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
103
104                 ret->talloc_ctx = talloc_new(NULL);
105                 if (ret->talloc_ctx == NULL) {
106                         Py_DECREF(ret);
107                         return PyErr_NoMemory();
108                 }
109
110                 /*
111                  * This allows us to keep multiple references to this object -
112                  * we only reference this context, which is per ptr, not the
113                  * talloc_ctx, which is per pytalloc_Object
114                  */
115                 if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
116                         Py_DECREF(ret);
117                         return PyErr_NoMemory();
118                 }
119                 ret->talloc_ptr_ctx = mem_ctx;
120                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
121                 ret->ptr = ptr;
122                 return (PyObject *)ret;
123
124         } else if (PyType_IsSubtype(py_type, ObjectType)) {
125                 pytalloc_Object *ret
126                         = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
127
128                 ret->talloc_ctx = talloc_new(NULL);
129                 if (ret->talloc_ctx == NULL) {
130                         Py_DECREF(ret);
131                         return PyErr_NoMemory();
132                 }
133
134                 if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
135                         Py_DECREF(ret);
136                         return PyErr_NoMemory();
137                 }
138                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
139                 ret->ptr = ptr;
140                 return (PyObject *)ret;
141         } else {
142                 PyErr_SetString(PyExc_RuntimeError,
143                                 "pytalloc_steal_ex() called for object type "
144                                 "not based on talloc");
145                 return NULL;
146         }
147 }
148
149 /**
150  * Import an existing talloc pointer into a Python object.
151  */
152 _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
153 {
154         return pytalloc_steal_ex(py_type, ptr, ptr);
155 }
156
157
158 /**
159  * Import an existing talloc pointer into a Python object, leaving the
160  * original parent, and creating a reference to the object in the python
161  * object.
162  *
163  * We remember the object we hold the reference to (a
164  * possibly-non-talloc pointer), the existing parent (typically the
165  * start of the array) and the new referenced parent.  That way we can
166  * cope with the fact that we will have multiple parents, one per time
167  * python sees the object.
168  */
169 _PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
170                                          TALLOC_CTX *mem_ctx, void *ptr)
171 {
172         PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
173         PyTypeObject *ObjectType = pytalloc_GetObjectType();
174
175         if (mem_ctx == NULL) {
176                 return PyErr_NoMemory();
177         }
178
179         if (PyType_IsSubtype(py_type, BaseObjectType)) {
180                 pytalloc_BaseObject *ret
181                         = (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
182                 ret->talloc_ctx = talloc_new(NULL);
183                 if (ret->talloc_ctx == NULL) {
184                         Py_DECREF(ret);
185                         return PyErr_NoMemory();
186                 }
187                 if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
188                         Py_DECREF(ret);
189                         return PyErr_NoMemory();
190                 }
191                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
192                 ret->talloc_ptr_ctx = mem_ctx;
193                 ret->ptr = ptr;
194                 return (PyObject *)ret;
195         } else if (PyType_IsSubtype(py_type, ObjectType)) {
196                 pytalloc_Object *ret
197                         = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
198                 ret->talloc_ctx = talloc_new(NULL);
199                 if (ret->talloc_ctx == NULL) {
200                         Py_DECREF(ret);
201                         return PyErr_NoMemory();
202                 }
203                 if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
204                         Py_DECREF(ret);
205                         return PyErr_NoMemory();
206                 }
207                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
208                 ret->ptr = ptr;
209                 return (PyObject *)ret;
210         } else {
211                 PyErr_SetString(PyExc_RuntimeError,
212                                 "pytalloc_reference_ex() called for object type "
213                                 "not based on talloc");
214                 return NULL;
215         }
216 }
217
218 #if PY_MAJOR_VERSION < 3
219
220 static void py_cobject_talloc_free(void *ptr)
221 {
222         talloc_free(ptr);
223 }
224
225 _PUBLIC_ PyObject *pytalloc_CObject_FromTallocPtr(void *ptr)
226 {
227         if (ptr == NULL) {
228                 Py_RETURN_NONE;
229         }
230         return PyCObject_FromVoidPtr(ptr, py_cobject_talloc_free);
231 }
232
233 #endif
234
235 /*
236  * Wrap a generic talloc pointer into a talloc.GenericObject,
237  * this is a subclass of talloc.BaseObject.
238  */
239 _PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr)
240 {
241         PyTypeObject *tp = pytalloc_GetGenericObjectType();
242         return pytalloc_steal_ex(tp, mem_ctx, ptr);
243 }
244
245 /*
246  * Wrap a generic talloc pointer into a talloc.GenericObject,
247  * this is a subclass of talloc.BaseObject.
248  */
249 _PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr)
250 {
251         PyTypeObject *tp = pytalloc_GetGenericObjectType();
252         return pytalloc_reference_ex(tp, mem_ctx, ptr);
253 }
254
255 _PUBLIC_ int pytalloc_Check(PyObject *obj)
256 {
257         PyTypeObject *tp = pytalloc_GetObjectType();
258
259         return PyObject_TypeCheck(obj, tp);
260 }
261
262 _PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
263 {
264         PyTypeObject *tp = pytalloc_GetBaseObjectType();
265
266         return PyObject_TypeCheck(obj, tp);
267 }
268
269 _PUBLIC_ size_t pytalloc_BaseObject_size(void)
270 {
271         return sizeof(pytalloc_BaseObject);
272 }
273
274 static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name,
275                                         bool check_only, const char *function)
276 {
277         TALLOC_CTX *mem_ctx;
278         void *ptr = NULL;
279         void *type_obj = talloc_check_name(ptr, type_name);
280
281         mem_ctx = _pytalloc_get_mem_ctx(py_obj);
282         ptr = _pytalloc_get_ptr(py_obj);
283
284         if (mem_ctx != ptr) {
285                 if (check_only) {
286                         return NULL;
287                 }
288
289                 PyErr_Format(PyExc_TypeError, "%s: expected %s, "
290                              "but the pointer is no talloc pointer, "
291                              "pytalloc_get_ptr() would get the raw pointer.",
292                              function, type_name);
293                 return NULL;
294         }
295
296         type_obj = talloc_check_name(ptr, type_name);
297         if (type_obj == NULL) {
298                 const char *name = NULL;
299
300                 if (check_only) {
301                         return NULL;
302                 }
303
304                 name = talloc_get_name(ptr);
305                 PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s",
306                              function, type_name, name);
307                 return NULL;
308         }
309
310         return ptr;
311 }
312
313 _PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name)
314 {
315         void *ptr = NULL;
316
317         ptr = _pytalloc_get_checked_type(py_obj, type_name,
318                                          true, /* check_only */
319                                          "pytalloc_check_type");
320         if (ptr == NULL) {
321                 return 0;
322         }
323
324         return 1;
325 }
326
327 _PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
328 {
329         return _pytalloc_get_checked_type(py_obj, type_name,
330                                           false, /* not check_only */
331                                           "pytalloc_get_type");
332 }
333
334 _PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
335 {
336         if (pytalloc_BaseObject_check(py_obj)) {
337                 return ((pytalloc_BaseObject *)py_obj)->ptr;
338         }
339         if (pytalloc_Check(py_obj)) {
340                 return ((pytalloc_Object *)py_obj)->ptr;
341         }
342         return NULL;
343 }
344
345 _PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
346 {
347         if (pytalloc_BaseObject_check(py_obj)) {
348                 return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
349         }
350         if (pytalloc_Check(py_obj)) {
351                 return ((pytalloc_Object *)py_obj)->talloc_ctx;
352         }
353         return NULL;
354 }
355
356 _PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type)
357 {
358         PyTypeObject *talloc_type = pytalloc_GetBaseObjectType();
359         if (talloc_type == NULL) {
360                 PyErr_Format(PyExc_TypeError, "pytalloc: unable to get talloc.BaseObject type");
361                 return -1;
362         }
363
364         type->tp_base = talloc_type;
365         type->tp_basicsize = pytalloc_BaseObject_size();
366
367         return PyType_Ready(type);
368 }