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