talloc: pytalloc_get_checked_type: survive non-talloc objects
[garming/samba-autobuild/.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 static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type,
28                                          TALLOC_CTX *mem_ctx, void *ptr, bool steal);
29
30 _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
31 {
32         static PyTypeObject *type = NULL;
33         PyObject *mod;
34
35         if (type != NULL) {
36                 return type;
37         }
38
39         mod = PyImport_ImportModule("talloc");
40         if (mod == NULL) {
41                 return NULL;
42         }
43
44         type = (PyTypeObject *)PyObject_GetAttrString(mod, "Object");
45         Py_DECREF(mod);
46
47         return type;
48 }
49
50 _PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
51 {
52         static PyTypeObject *type = NULL;
53         PyObject *mod;
54
55         if (type != NULL) {
56                 return type;
57         }
58
59         mod = PyImport_ImportModule("talloc");
60         if (mod == NULL) {
61                 return NULL;
62         }
63
64         type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
65         Py_DECREF(mod);
66
67         return type;
68 }
69
70 static PyTypeObject *pytalloc_GetGenericObjectType(void)
71 {
72         static PyTypeObject *type = NULL;
73         PyObject *mod;
74
75         if (type != NULL) {
76                 return type;
77         }
78
79         mod = PyImport_ImportModule("talloc");
80         if (mod == NULL) {
81                 return NULL;
82         }
83
84         type = (PyTypeObject *)PyObject_GetAttrString(mod, "GenericObject");
85         Py_DECREF(mod);
86
87         return type;
88 }
89
90 /**
91  * Import an existing talloc pointer into a Python object.
92  */
93 _PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
94                                      void *ptr)
95 {
96         return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, true);
97 }
98
99 /**
100  * Import an existing talloc pointer into a Python object.
101  */
102 _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
103 {
104         return pytalloc_steal_or_reference(py_type, ptr, ptr, true);
105 }
106
107
108 /**
109  * Import an existing talloc pointer into a Python object, leaving the
110  * original parent, and creating a reference to the object in the python
111  * object.
112  *
113  * We remember the object we hold the reference to (a
114  * possibly-non-talloc pointer), the existing parent (typically the
115  * start of the array) and the new referenced parent.  That way we can
116  * cope with the fact that we will have multiple parents, one per time
117  * python sees the object.
118  */
119 _PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
120                                          TALLOC_CTX *mem_ctx, void *ptr)
121 {
122         return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, false);
123 }
124
125
126 /**
127  * Internal function that either steals or referecences the talloc
128  * pointer into a new talloc context.
129  */
130 static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type,
131                                          TALLOC_CTX *mem_ctx, void *ptr, bool steal)
132 {
133         bool ok = false;
134         TALLOC_CTX *talloc_ctx = NULL;
135         bool is_baseobject = false;
136         PyObject *obj = NULL;
137         PyTypeObject *BaseObjectType = NULL, *ObjectType = NULL;
138
139         BaseObjectType = pytalloc_GetBaseObjectType();
140         if (BaseObjectType == NULL) {
141                 goto err;
142         }
143         ObjectType = pytalloc_GetObjectType();
144         if (ObjectType == NULL) {
145                 goto err;
146         }
147
148         /* this should have been tested by caller */
149         if (mem_ctx == NULL) {
150                 return PyErr_NoMemory();
151         }
152
153         is_baseobject = PyType_IsSubtype(py_type, BaseObjectType);
154         if (!is_baseobject) {
155                 if (!PyType_IsSubtype(py_type, ObjectType)) {
156                         PyErr_SetString(PyExc_TypeError,
157                                 "Expected type based on talloc");
158                         return NULL;
159                 }
160         }
161
162         obj = py_type->tp_alloc(py_type, 0);
163         if (obj == NULL) {
164                 goto err;
165         }
166
167         talloc_ctx = talloc_new(NULL);
168         if (talloc_ctx == NULL) {
169                 PyErr_NoMemory();
170                 goto err;
171         }
172
173         if (steal) {
174                 ok = (talloc_steal(talloc_ctx, mem_ctx) != NULL);
175         } else {
176                 ok = (talloc_reference(talloc_ctx, mem_ctx) != NULL);
177         }
178         if (!ok) {
179                 goto err;
180         }
181         talloc_set_name_const(talloc_ctx, py_type->tp_name);
182
183         if (is_baseobject) {
184                 pytalloc_BaseObject *ret = (pytalloc_BaseObject*)obj;
185                 ret->talloc_ctx = talloc_ctx;
186                 ret->talloc_ptr_ctx = mem_ctx;
187                 ret->ptr = ptr;
188         } else {
189                 pytalloc_Object *ret = (pytalloc_Object*)obj;
190                 ret->talloc_ctx = talloc_ctx;
191                 ret->ptr = ptr;
192         }
193         return obj;
194
195 err:
196         TALLOC_FREE(talloc_ctx);
197         Py_XDECREF(obj);
198         return NULL;
199 }
200
201 /*
202  * Wrap a generic talloc pointer into a talloc.GenericObject,
203  * this is a subclass of talloc.BaseObject.
204  */
205 _PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr)
206 {
207         PyTypeObject *tp = pytalloc_GetGenericObjectType();
208         return pytalloc_steal_ex(tp, mem_ctx, ptr);
209 }
210
211 /*
212  * Wrap a generic talloc pointer into a talloc.GenericObject,
213  * this is a subclass of talloc.BaseObject.
214  */
215 _PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr)
216 {
217         PyTypeObject *tp = pytalloc_GetGenericObjectType();
218         return pytalloc_reference_ex(tp, mem_ctx, ptr);
219 }
220
221 _PUBLIC_ int pytalloc_Check(PyObject *obj)
222 {
223         PyTypeObject *tp = pytalloc_GetObjectType();
224
225         return PyObject_TypeCheck(obj, tp);
226 }
227
228 _PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
229 {
230         PyTypeObject *tp = pytalloc_GetBaseObjectType();
231
232         return PyObject_TypeCheck(obj, tp);
233 }
234
235 _PUBLIC_ size_t pytalloc_BaseObject_size(void)
236 {
237         return sizeof(pytalloc_BaseObject);
238 }
239
240 static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name,
241                                         bool check_only, const char *function)
242 {
243         TALLOC_CTX *mem_ctx;
244         void *ptr = NULL;
245         void *type_obj = talloc_check_name(ptr, type_name);
246
247         mem_ctx = _pytalloc_get_mem_ctx(py_obj);
248         ptr = _pytalloc_get_ptr(py_obj);
249
250         if (mem_ctx != ptr || ptr == NULL) {
251                 if (check_only) {
252                         return NULL;
253                 }
254
255                 PyErr_Format(PyExc_TypeError, "%s: expected %s, "
256                              "but the pointer is no talloc pointer, "
257                              "pytalloc_get_ptr() would get the raw pointer.",
258                              function, type_name);
259                 return NULL;
260         }
261
262         type_obj = talloc_check_name(ptr, type_name);
263         if (type_obj == NULL) {
264                 const char *name = NULL;
265
266                 if (check_only) {
267                         return NULL;
268                 }
269
270                 name = talloc_get_name(ptr);
271                 PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s",
272                              function, type_name, name);
273                 return NULL;
274         }
275
276         return ptr;
277 }
278
279 _PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name)
280 {
281         void *ptr = NULL;
282
283         ptr = _pytalloc_get_checked_type(py_obj, type_name,
284                                          true, /* check_only */
285                                          "pytalloc_check_type");
286         if (ptr == NULL) {
287                 return 0;
288         }
289
290         return 1;
291 }
292
293 _PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
294 {
295         return _pytalloc_get_checked_type(py_obj, type_name,
296                                           false, /* not check_only */
297                                           "pytalloc_get_type");
298 }
299
300 _PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
301 {
302         if (pytalloc_BaseObject_check(py_obj)) {
303                 return ((pytalloc_BaseObject *)py_obj)->ptr;
304         }
305         if (pytalloc_Check(py_obj)) {
306                 return ((pytalloc_Object *)py_obj)->ptr;
307         }
308         return NULL;
309 }
310
311 _PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
312 {
313         if (pytalloc_BaseObject_check(py_obj)) {
314                 return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
315         }
316         if (pytalloc_Check(py_obj)) {
317                 return ((pytalloc_Object *)py_obj)->talloc_ctx;
318         }
319         return NULL;
320 }
321
322 _PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type)
323 {
324         PyTypeObject *talloc_type = pytalloc_GetBaseObjectType();
325         if (talloc_type == NULL) {
326                 return -1;
327         }
328
329         type->tp_base = talloc_type;
330         type->tp_basicsize = pytalloc_BaseObject_size();
331
332         return PyType_Ready(type);
333 }
334
335 _PUBLIC_ const char *_pytalloc_get_name(PyObject *obj)
336 {
337         void *ptr = pytalloc_get_ptr(obj);
338         if (ptr == NULL) {
339                 return "non-talloc object";
340         }
341         return talloc_get_name(ptr);
342 }