talloc: use the system pytalloc-util for python3 as well
[sfrench/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 _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                         return NULL;
107                 }
108
109                 /*
110                  * This allows us to keep multiple references to this object -
111                  * we only reference this context, which is per ptr, not the
112                  * talloc_ctx, which is per pytalloc_Object
113                  */
114                 if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
115                         return NULL;
116                 }
117                 ret->talloc_ptr_ctx = mem_ctx;
118                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
119                 ret->ptr = ptr;
120                 return (PyObject *)ret;
121
122         } else if (PyType_IsSubtype(py_type, ObjectType)) {
123                 pytalloc_Object *ret
124                         = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
125
126                 ret->talloc_ctx = talloc_new(NULL);
127                 if (ret->talloc_ctx == NULL) {
128                         return NULL;
129                 }
130
131                 if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
132                         return NULL;
133                 }
134                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
135                 ret->ptr = ptr;
136                 return (PyObject *)ret;
137         } else {
138                 PyErr_SetString(PyExc_RuntimeError,
139                                 "pytalloc_steal_ex() called for object type "
140                                 "not based on talloc");
141                 return NULL;
142         }
143 }
144
145 /**
146  * Import an existing talloc pointer into a Python object.
147  */
148 _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
149 {
150         return pytalloc_steal_ex(py_type, ptr, ptr);
151 }
152
153
154 /**
155  * Import an existing talloc pointer into a Python object, leaving the
156  * original parent, and creating a reference to the object in the python
157  * object.
158  *
159  * We remember the object we hold the reference to (a
160  * possibly-non-talloc pointer), the existing parent (typically the
161  * start of the array) and the new referenced parent.  That way we can
162  * cope with the fact that we will have multiple parents, one per time
163  * python sees the object.
164  */
165 _PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
166                                          TALLOC_CTX *mem_ctx, void *ptr)
167 {
168         PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
169         PyTypeObject *ObjectType = pytalloc_GetObjectType();
170
171         if (mem_ctx == NULL) {
172                 return PyErr_NoMemory();
173         }
174
175         if (PyType_IsSubtype(py_type, BaseObjectType)) {
176                 pytalloc_BaseObject *ret
177                         = (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
178                 ret->talloc_ctx = talloc_new(NULL);
179                 if (ret->talloc_ctx == NULL) {
180                         return NULL;
181                 }
182                 if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
183                         return NULL;
184                 }
185                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
186                 ret->talloc_ptr_ctx = mem_ctx;
187                 ret->ptr = ptr;
188                 return (PyObject *)ret;
189         } else if (PyType_IsSubtype(py_type, ObjectType)) {
190                 pytalloc_Object *ret
191                         = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
192                 ret->talloc_ctx = talloc_new(NULL);
193                 if (ret->talloc_ctx == NULL) {
194                         return NULL;
195                 }
196                 if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
197                         return NULL;
198                 }
199                 talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
200                 ret->ptr = ptr;
201                 return (PyObject *)ret;
202         } else {
203                 PyErr_SetString(PyExc_RuntimeError,
204                                 "pytalloc_reference_ex() called for object type "
205                                 "not based on talloc");
206                 return NULL;
207         }
208 }
209
210 #if PY_MAJOR_VERSION < 3
211
212 static void py_cobject_talloc_free(void *ptr)
213 {
214         talloc_free(ptr);
215 }
216
217 _PUBLIC_ PyObject *pytalloc_CObject_FromTallocPtr(void *ptr)
218 {
219         if (ptr == NULL) {
220                 Py_RETURN_NONE;
221         }
222         return PyCObject_FromVoidPtr(ptr, py_cobject_talloc_free);
223 }
224
225 #endif
226
227 /*
228  * Wrap a generic talloc pointer into a talloc.GenericObject,
229  * this is a subclass of talloc.BaseObject.
230  */
231 _PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr)
232 {
233         PyTypeObject *tp = pytalloc_GetGenericObjectType();
234         return pytalloc_steal_ex(tp, mem_ctx, ptr);
235 }
236
237 /*
238  * Wrap a generic talloc pointer into a talloc.GenericObject,
239  * this is a subclass of talloc.BaseObject.
240  */
241 _PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr)
242 {
243         PyTypeObject *tp = pytalloc_GetGenericObjectType();
244         return pytalloc_reference_ex(tp, mem_ctx, ptr);
245 }
246
247 _PUBLIC_ int pytalloc_Check(PyObject *obj)
248 {
249         PyTypeObject *tp = pytalloc_GetObjectType();
250
251         return PyObject_TypeCheck(obj, tp);
252 }
253
254 _PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
255 {
256         PyTypeObject *tp = pytalloc_GetBaseObjectType();
257
258         return PyObject_TypeCheck(obj, tp);
259 }
260
261 _PUBLIC_ size_t pytalloc_BaseObject_size(void)
262 {
263         return sizeof(pytalloc_BaseObject);
264 }
265
266 static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name,
267                                         bool check_only, const char *function)
268 {
269         TALLOC_CTX *mem_ctx;
270         void *ptr = NULL;
271         void *type_obj = talloc_check_name(ptr, type_name);
272
273         mem_ctx = _pytalloc_get_mem_ctx(py_obj);
274         ptr = _pytalloc_get_ptr(py_obj);
275
276         if (mem_ctx != ptr) {
277                 if (check_only) {
278                         return NULL;
279                 }
280
281                 PyErr_Format(PyExc_TypeError, "%s: expected %s, "
282                              "but the pointer is no talloc pointer, "
283                              "pytalloc_get_ptr() would get the raw pointer.",
284                              function, type_name);
285                 return NULL;
286         }
287
288         type_obj = talloc_check_name(ptr, type_name);
289         if (type_obj == NULL) {
290                 const char *name = NULL;
291
292                 if (check_only) {
293                         return NULL;
294                 }
295
296                 name = talloc_get_name(ptr);
297                 PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s",
298                              function, type_name, name);
299                 return NULL;
300         }
301
302         return ptr;
303 }
304
305 _PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name)
306 {
307         void *ptr = NULL;
308
309         ptr = _pytalloc_get_checked_type(py_obj, type_name,
310                                          true, /* check_only */
311                                          "pytalloc_check_type");
312         if (ptr == NULL) {
313                 return 0;
314         }
315
316         return 1;
317 }
318
319 _PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
320 {
321         return _pytalloc_get_checked_type(py_obj, type_name,
322                                           false, /* not check_only */
323                                           "pytalloc_get_type");
324 }
325
326 _PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
327 {
328         if (pytalloc_BaseObject_check(py_obj)) {
329                 return ((pytalloc_BaseObject *)py_obj)->ptr;
330         }
331         if (pytalloc_Check(py_obj)) {
332                 return ((pytalloc_Object *)py_obj)->ptr;
333         }
334         return NULL;
335 }
336
337 _PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
338 {
339         if (pytalloc_BaseObject_check(py_obj)) {
340                 return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
341         }
342         if (pytalloc_Check(py_obj)) {
343                 return ((pytalloc_Object *)py_obj)->talloc_ctx;
344         }
345         return NULL;
346 }
347
348 _PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type)
349 {
350         PyTypeObject *talloc_type = pytalloc_GetBaseObjectType();
351         if (talloc_type == NULL) {
352                 PyErr_Format(PyExc_TypeError, "pytalloc: unable to get talloc.BaseObject type");
353                 return -1;
354         }
355
356         type->tp_base = talloc_type;
357         type->tp_basicsize = pytalloc_BaseObject_size();
358
359         return PyType_Ready(type);
360 }