1 /*
2  * Python object definition of the sequence and iterator object of attributes
3  *
4  * Copyright (C) 2010-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <types.h>
24 
25 #if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
26 #include <stdlib.h>
27 #endif
28 
29 #include "pyfsntfs_attributes.h"
30 #include "pyfsntfs_libcerror.h"
31 #include "pyfsntfs_libfsntfs.h"
32 #include "pyfsntfs_python.h"
33 
34 PySequenceMethods pyfsntfs_attributes_sequence_methods = {
35 	/* sq_length */
36 	(lenfunc) pyfsntfs_attributes_len,
37 	/* sq_concat */
38 	0,
39 	/* sq_repeat */
40 	0,
41 	/* sq_item */
42 	(ssizeargfunc) pyfsntfs_attributes_getitem,
43 	/* sq_slice */
44 	0,
45 	/* sq_ass_item */
46 	0,
47 	/* sq_ass_slice */
48 	0,
49 	/* sq_contains */
50 	0,
51 	/* sq_inplace_concat */
52 	0,
53 	/* sq_inplace_repeat */
54 	0
55 };
56 
57 PyTypeObject pyfsntfs_attributes_type_object = {
58 	PyVarObject_HEAD_INIT( NULL, 0 )
59 
60 	/* tp_name */
61 	"pyfsntfs.attributes",
62 	/* tp_basicsize */
63 	sizeof( pyfsntfs_attributes_t ),
64 	/* tp_itemsize */
65 	0,
66 	/* tp_dealloc */
67 	(destructor) pyfsntfs_attributes_free,
68 	/* tp_print */
69 	0,
70 	/* tp_getattr */
71 	0,
72 	/* tp_setattr */
73 	0,
74 	/* tp_compare */
75 	0,
76 	/* tp_repr */
77 	0,
78 	/* tp_as_number */
79 	0,
80 	/* tp_as_sequence */
81 	&pyfsntfs_attributes_sequence_methods,
82 	/* tp_as_mapping */
83 	0,
84 	/* tp_hash */
85 	0,
86 	/* tp_call */
87 	0,
88 	/* tp_str */
89 	0,
90 	/* tp_getattro */
91 	0,
92 	/* tp_setattro */
93 	0,
94 	/* tp_as_buffer */
95 	0,
96 	/* tp_flags */
97 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,
98 	/* tp_doc */
99 	"pyfsntfs sequence and iterator object of attributes",
100 	/* tp_traverse */
101 	0,
102 	/* tp_clear */
103 	0,
104 	/* tp_richcompare */
105 	0,
106 	/* tp_weaklistoffset */
107 	0,
108 	/* tp_iter */
109 	(getiterfunc) pyfsntfs_attributes_iter,
110 	/* tp_iternext */
111 	(iternextfunc) pyfsntfs_attributes_iternext,
112 	/* tp_methods */
113 	0,
114 	/* tp_members */
115 	0,
116 	/* tp_getset */
117 	0,
118 	/* tp_base */
119 	0,
120 	/* tp_dict */
121 	0,
122 	/* tp_descr_get */
123 	0,
124 	/* tp_descr_set */
125 	0,
126 	/* tp_dictoffset */
127 	0,
128 	/* tp_init */
129 	(initproc) pyfsntfs_attributes_init,
130 	/* tp_alloc */
131 	0,
132 	/* tp_new */
133 	0,
134 	/* tp_free */
135 	0,
136 	/* tp_is_gc */
137 	0,
138 	/* tp_bases */
139 	NULL,
140 	/* tp_mro */
141 	NULL,
142 	/* tp_cache */
143 	NULL,
144 	/* tp_subclasses */
145 	NULL,
146 	/* tp_weaklist */
147 	NULL,
148 	/* tp_del */
149 	0
150 };
151 
152 /* Creates a new attributes sequence and iterator object
153  * Returns a Python object if successful or NULL on error
154  */
pyfsntfs_attributes_new(PyObject * parent_object,PyObject * (* get_item_by_index)(PyObject * parent_object,int index),int number_of_items)155 PyObject *pyfsntfs_attributes_new(
156            PyObject *parent_object,
157            PyObject* (*get_item_by_index)(
158                         PyObject *parent_object,
159                         int index ),
160            int number_of_items )
161 {
162 	pyfsntfs_attributes_t *sequence_object = NULL;
163 	static char *function                  = "pyfsntfs_attributes_new";
164 
165 	if( parent_object == NULL )
166 	{
167 		PyErr_Format(
168 		 PyExc_ValueError,
169 		 "%s: invalid parent object.",
170 		 function );
171 
172 		return( NULL );
173 	}
174 	if( get_item_by_index == NULL )
175 	{
176 		PyErr_Format(
177 		 PyExc_ValueError,
178 		 "%s: invalid get item by index function.",
179 		 function );
180 
181 		return( NULL );
182 	}
183 	/* Make sure the attributes values are initialized
184 	 */
185 	sequence_object = PyObject_New(
186 	                   struct pyfsntfs_attributes,
187 	                   &pyfsntfs_attributes_type_object );
188 
189 	if( sequence_object == NULL )
190 	{
191 		PyErr_Format(
192 		 PyExc_MemoryError,
193 		 "%s: unable to create sequence object.",
194 		 function );
195 
196 		goto on_error;
197 	}
198 	sequence_object->parent_object     = parent_object;
199 	sequence_object->get_item_by_index = get_item_by_index;
200 	sequence_object->current_index     = 0;
201 	sequence_object->number_of_items   = number_of_items;
202 
203 	Py_IncRef(
204 	 (PyObject *) sequence_object->parent_object );
205 
206 	return( (PyObject *) sequence_object );
207 
208 on_error:
209 	if( sequence_object != NULL )
210 	{
211 		Py_DecRef(
212 		 (PyObject *) sequence_object );
213 	}
214 	return( NULL );
215 }
216 
217 /* Initializes an attributes sequence and iterator object
218  * Returns 0 if successful or -1 on error
219  */
pyfsntfs_attributes_init(pyfsntfs_attributes_t * sequence_object)220 int pyfsntfs_attributes_init(
221      pyfsntfs_attributes_t *sequence_object )
222 {
223 	static char *function = "pyfsntfs_attributes_init";
224 
225 	if( sequence_object == NULL )
226 	{
227 		PyErr_Format(
228 		 PyExc_ValueError,
229 		 "%s: invalid sequence object.",
230 		 function );
231 
232 		return( -1 );
233 	}
234 	/* Make sure the attributes values are initialized
235 	 */
236 	sequence_object->parent_object     = NULL;
237 	sequence_object->get_item_by_index = NULL;
238 	sequence_object->current_index     = 0;
239 	sequence_object->number_of_items   = 0;
240 
241 	PyErr_Format(
242 	 PyExc_NotImplementedError,
243 	 "%s: initialize of attributes not supported.",
244 	 function );
245 
246 	return( -1 );
247 }
248 
249 /* Frees an attributes sequence object
250  */
pyfsntfs_attributes_free(pyfsntfs_attributes_t * sequence_object)251 void pyfsntfs_attributes_free(
252       pyfsntfs_attributes_t *sequence_object )
253 {
254 	struct _typeobject *ob_type = NULL;
255 	static char *function       = "pyfsntfs_attributes_free";
256 
257 	if( sequence_object == NULL )
258 	{
259 		PyErr_Format(
260 		 PyExc_ValueError,
261 		 "%s: invalid sequence object.",
262 		 function );
263 
264 		return;
265 	}
266 	ob_type = Py_TYPE(
267 	           sequence_object );
268 
269 	if( ob_type == NULL )
270 	{
271 		PyErr_Format(
272 		 PyExc_ValueError,
273 		 "%s: missing ob_type.",
274 		 function );
275 
276 		return;
277 	}
278 	if( ob_type->tp_free == NULL )
279 	{
280 		PyErr_Format(
281 		 PyExc_ValueError,
282 		 "%s: invalid ob_type - missing tp_free.",
283 		 function );
284 
285 		return;
286 	}
287 	if( sequence_object->parent_object != NULL )
288 	{
289 		Py_DecRef(
290 		 (PyObject *) sequence_object->parent_object );
291 	}
292 	ob_type->tp_free(
293 	 (PyObject*) sequence_object );
294 }
295 
296 /* The attributes len() function
297  */
pyfsntfs_attributes_len(pyfsntfs_attributes_t * sequence_object)298 Py_ssize_t pyfsntfs_attributes_len(
299             pyfsntfs_attributes_t *sequence_object )
300 {
301 	static char *function = "pyfsntfs_attributes_len";
302 
303 	if( sequence_object == NULL )
304 	{
305 		PyErr_Format(
306 		 PyExc_ValueError,
307 		 "%s: invalid sequence object.",
308 		 function );
309 
310 		return( -1 );
311 	}
312 	return( (Py_ssize_t) sequence_object->number_of_items );
313 }
314 
315 /* The attributes getitem() function
316  */
pyfsntfs_attributes_getitem(pyfsntfs_attributes_t * sequence_object,Py_ssize_t item_index)317 PyObject *pyfsntfs_attributes_getitem(
318            pyfsntfs_attributes_t *sequence_object,
319            Py_ssize_t item_index )
320 {
321 	PyObject *attribute_object = NULL;
322 	static char *function      = "pyfsntfs_attributes_getitem";
323 
324 	if( sequence_object == NULL )
325 	{
326 		PyErr_Format(
327 		 PyExc_ValueError,
328 		 "%s: invalid sequence object.",
329 		 function );
330 
331 		return( NULL );
332 	}
333 	if( sequence_object->get_item_by_index == NULL )
334 	{
335 		PyErr_Format(
336 		 PyExc_ValueError,
337 		 "%s: invalid sequence object - missing get item by index function.",
338 		 function );
339 
340 		return( NULL );
341 	}
342 	if( sequence_object->number_of_items < 0 )
343 	{
344 		PyErr_Format(
345 		 PyExc_ValueError,
346 		 "%s: invalid sequence object - invalid number of items.",
347 		 function );
348 
349 		return( NULL );
350 	}
351 	if( ( item_index < 0 )
352 	 || ( item_index >= (Py_ssize_t) sequence_object->number_of_items ) )
353 	{
354 		PyErr_Format(
355 		 PyExc_ValueError,
356 		 "%s: invalid invalid item index value out of bounds.",
357 		 function );
358 
359 		return( NULL );
360 	}
361 	attribute_object = sequence_object->get_item_by_index(
362 	                    sequence_object->parent_object,
363 	                    (int) item_index );
364 
365 	return( attribute_object );
366 }
367 
368 /* The attributes iter() function
369  */
pyfsntfs_attributes_iter(pyfsntfs_attributes_t * sequence_object)370 PyObject *pyfsntfs_attributes_iter(
371            pyfsntfs_attributes_t *sequence_object )
372 {
373 	static char *function = "pyfsntfs_attributes_iter";
374 
375 	if( sequence_object == NULL )
376 	{
377 		PyErr_Format(
378 		 PyExc_ValueError,
379 		 "%s: invalid sequence object.",
380 		 function );
381 
382 		return( NULL );
383 	}
384 	Py_IncRef(
385 	 (PyObject *) sequence_object );
386 
387 	return( (PyObject *) sequence_object );
388 }
389 
390 /* The attributes iternext() function
391  */
pyfsntfs_attributes_iternext(pyfsntfs_attributes_t * sequence_object)392 PyObject *pyfsntfs_attributes_iternext(
393            pyfsntfs_attributes_t *sequence_object )
394 {
395 	PyObject *attribute_object = NULL;
396 	static char *function      = "pyfsntfs_attributes_iternext";
397 
398 	if( sequence_object == NULL )
399 	{
400 		PyErr_Format(
401 		 PyExc_ValueError,
402 		 "%s: invalid sequence object.",
403 		 function );
404 
405 		return( NULL );
406 	}
407 	if( sequence_object->get_item_by_index == NULL )
408 	{
409 		PyErr_Format(
410 		 PyExc_ValueError,
411 		 "%s: invalid sequence object - missing get item by index function.",
412 		 function );
413 
414 		return( NULL );
415 	}
416 	if( sequence_object->current_index < 0 )
417 	{
418 		PyErr_Format(
419 		 PyExc_ValueError,
420 		 "%s: invalid sequence object - invalid current index.",
421 		 function );
422 
423 		return( NULL );
424 	}
425 	if( sequence_object->number_of_items < 0 )
426 	{
427 		PyErr_Format(
428 		 PyExc_ValueError,
429 		 "%s: invalid sequence object - invalid number of items.",
430 		 function );
431 
432 		return( NULL );
433 	}
434 	if( sequence_object->current_index >= sequence_object->number_of_items )
435 	{
436 		PyErr_SetNone(
437 		 PyExc_StopIteration );
438 
439 		return( NULL );
440 	}
441 	attribute_object = sequence_object->get_item_by_index(
442 	                    sequence_object->parent_object,
443 	                    sequence_object->current_index );
444 
445 	if( attribute_object != NULL )
446 	{
447 		sequence_object->current_index++;
448 	}
449 	return( attribute_object );
450 }
451 
452