1 /*
2  * Python object definition of the volume file entries sequence and iterator
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_file_entry.h"
30 #include "pyfsntfs_libcerror.h"
31 #include "pyfsntfs_libfsntfs.h"
32 #include "pyfsntfs_python.h"
33 #include "pyfsntfs_volume_file_entries.h"
34 
35 PySequenceMethods pyfsntfs_volume_file_entries_sequence_methods = {
36 	/* sq_length */
37 	(lenfunc) pyfsntfs_volume_file_entries_len,
38 	/* sq_concat */
39 	0,
40 	/* sq_repeat */
41 	0,
42 	/* sq_item */
43 	(ssizeargfunc) pyfsntfs_volume_file_entries_getitem,
44 	/* sq_slice */
45 	0,
46 	/* sq_ass_item */
47 	0,
48 	/* sq_ass_slice */
49 	0,
50 	/* sq_contains */
51 	0,
52 	/* sq_inplace_concat */
53 	0,
54 	/* sq_inplace_repeat */
55 	0
56 };
57 
58 PyTypeObject pyfsntfs_volume_file_entries_type_object = {
59 	PyVarObject_HEAD_INIT( NULL, 0 )
60 
61 	/* tp_name */
62 	"pyfsntfs._volume_file_entries",
63 	/* tp_basicsize */
64 	sizeof( pyfsntfs_volume_file_entries_t ),
65 	/* tp_itemsize */
66 	0,
67 	/* tp_dealloc */
68 	(destructor) pyfsntfs_volume_file_entries_free,
69 	/* tp_print */
70 	0,
71 	/* tp_getattr */
72 	0,
73 	/* tp_setattr */
74 	0,
75 	/* tp_compare */
76 	0,
77 	/* tp_repr */
78 	0,
79 	/* tp_as_number */
80 	0,
81 	/* tp_as_sequence */
82 	&pyfsntfs_volume_file_entries_sequence_methods,
83 	/* tp_as_mapping */
84 	0,
85 	/* tp_hash */
86 	0,
87 	/* tp_call */
88 	0,
89 	/* tp_str */
90 	0,
91 	/* tp_getattro */
92 	0,
93 	/* tp_setattro */
94 	0,
95 	/* tp_as_buffer */
96 	0,
97 	/* tp_flags */
98 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,
99 	/* tp_doc */
100 	"internal pyfsntfs volume file entries sequence and iterator object",
101 	/* tp_traverse */
102 	0,
103 	/* tp_clear */
104 	0,
105 	/* tp_richcompare */
106 	0,
107 	/* tp_weaklistoffset */
108 	0,
109 	/* tp_iter */
110 	(getiterfunc) pyfsntfs_volume_file_entries_iter,
111 	/* tp_iternext */
112 	(iternextfunc) pyfsntfs_volume_file_entries_iternext,
113 	/* tp_methods */
114 	0,
115 	/* tp_members */
116 	0,
117 	/* tp_getset */
118 	0,
119 	/* tp_base */
120 	0,
121 	/* tp_dict */
122 	0,
123 	/* tp_descr_get */
124 	0,
125 	/* tp_descr_set */
126 	0,
127 	/* tp_dictoffset */
128 	0,
129 	/* tp_init */
130 	(initproc) pyfsntfs_volume_file_entries_init,
131 	/* tp_alloc */
132 	0,
133 	/* tp_new */
134 	0,
135 	/* tp_free */
136 	0,
137 	/* tp_is_gc */
138 	0,
139 	/* tp_bases */
140 	NULL,
141 	/* tp_mro */
142 	NULL,
143 	/* tp_cache */
144 	NULL,
145 	/* tp_subclasses */
146 	NULL,
147 	/* tp_weaklist */
148 	NULL,
149 	/* tp_del */
150 	0
151 };
152 
153 /* Creates a new volume file entries object
154  * Returns a Python object if successful or NULL on error
155  */
pyfsntfs_volume_file_entries_new(pyfsntfs_volume_t * volume_object,PyObject * (* get_file_entry_by_index)(pyfsntfs_volume_t * volume_object,uint64_t file_entry_index),uint64_t number_of_file_entries)156 PyObject *pyfsntfs_volume_file_entries_new(
157            pyfsntfs_volume_t *volume_object,
158            PyObject* (*get_file_entry_by_index)(
159                         pyfsntfs_volume_t *volume_object,
160                         uint64_t file_entry_index ),
161            uint64_t number_of_file_entries )
162 {
163 	pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries = NULL;
164 	static char *function                                       = "pyfsntfs_volume_file_entries_new";
165 
166 	if( volume_object == NULL )
167 	{
168 		PyErr_Format(
169 		 PyExc_ValueError,
170 		 "%s: invalid volume object.",
171 		 function );
172 
173 		return( NULL );
174 	}
175 	if( get_file_entry_by_index == NULL )
176 	{
177 		PyErr_Format(
178 		 PyExc_ValueError,
179 		 "%s: invalid get file entry by index function.",
180 		 function );
181 
182 		return( NULL );
183 	}
184 	/* Make sure the volume file entries values are initialized
185 	 */
186 	pyfsntfs_volume_file_entries = PyObject_New(
187 	                                struct pyfsntfs_volume_file_entries,
188 	                                &pyfsntfs_volume_file_entries_type_object );
189 
190 	if( pyfsntfs_volume_file_entries == NULL )
191 	{
192 		PyErr_Format(
193 		 PyExc_MemoryError,
194 		 "%s: unable to initialize volume file entries.",
195 		 function );
196 
197 		goto on_error;
198 	}
199 	if( pyfsntfs_volume_file_entries_init(
200 	     pyfsntfs_volume_file_entries ) != 0 )
201 	{
202 		PyErr_Format(
203 		 PyExc_MemoryError,
204 		 "%s: unable to initialize volume file entries.",
205 		 function );
206 
207 		goto on_error;
208 	}
209 	pyfsntfs_volume_file_entries->volume_object            = volume_object;
210 	pyfsntfs_volume_file_entries->get_file_entry_by_index = get_file_entry_by_index;
211 	pyfsntfs_volume_file_entries->number_of_file_entries  = number_of_file_entries;
212 
213 	Py_IncRef(
214 	 (PyObject *) pyfsntfs_volume_file_entries->volume_object );
215 
216 	return( (PyObject *) pyfsntfs_volume_file_entries );
217 
218 on_error:
219 	if( pyfsntfs_volume_file_entries != NULL )
220 	{
221 		Py_DecRef(
222 		 (PyObject *) pyfsntfs_volume_file_entries );
223 	}
224 	return( NULL );
225 }
226 
227 /* Initializes a volume file entries object
228  * Returns 0 if successful or -1 on error
229  */
pyfsntfs_volume_file_entries_init(pyfsntfs_volume_file_entries_t * pyfsntfs_volume_file_entries)230 int pyfsntfs_volume_file_entries_init(
231      pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries )
232 {
233 	static char *function = "pyfsntfs_volume_file_entries_init";
234 
235 	if( pyfsntfs_volume_file_entries == NULL )
236 	{
237 		PyErr_Format(
238 		 PyExc_ValueError,
239 		 "%s: invalid volume file entries.",
240 		 function );
241 
242 		return( -1 );
243 	}
244 	/* Make sure the volume file entries values are initialized
245 	 */
246 	pyfsntfs_volume_file_entries->volume_object           = NULL;
247 	pyfsntfs_volume_file_entries->get_file_entry_by_index = NULL;
248 	pyfsntfs_volume_file_entries->file_entry_index        = 0;
249 	pyfsntfs_volume_file_entries->number_of_file_entries  = 0;
250 
251 	return( 0 );
252 }
253 
254 /* Frees a volume file entries object
255  */
pyfsntfs_volume_file_entries_free(pyfsntfs_volume_file_entries_t * pyfsntfs_volume_file_entries)256 void pyfsntfs_volume_file_entries_free(
257       pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries )
258 {
259 	struct _typeobject *ob_type = NULL;
260 	static char *function       = "pyfsntfs_volume_file_entries_free";
261 
262 	if( pyfsntfs_volume_file_entries == NULL )
263 	{
264 		PyErr_Format(
265 		 PyExc_ValueError,
266 		 "%s: invalid volume file entries.",
267 		 function );
268 
269 		return;
270 	}
271 	ob_type = Py_TYPE(
272 	           pyfsntfs_volume_file_entries );
273 
274 	if( ob_type == NULL )
275 	{
276 		PyErr_Format(
277 		 PyExc_ValueError,
278 		 "%s: missing ob_type.",
279 		 function );
280 
281 		return;
282 	}
283 	if( ob_type->tp_free == NULL )
284 	{
285 		PyErr_Format(
286 		 PyExc_ValueError,
287 		 "%s: invalid ob_type - missing tp_free.",
288 		 function );
289 
290 		return;
291 	}
292 	if( pyfsntfs_volume_file_entries->volume_object != NULL )
293 	{
294 		Py_DecRef(
295 		 (PyObject *) pyfsntfs_volume_file_entries->volume_object );
296 	}
297 	ob_type->tp_free(
298 	 (PyObject*) pyfsntfs_volume_file_entries );
299 }
300 
301 /* The volume file entries len() function
302  */
pyfsntfs_volume_file_entries_len(pyfsntfs_volume_file_entries_t * pyfsntfs_volume_file_entries)303 Py_ssize_t pyfsntfs_volume_file_entries_len(
304             pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries )
305 {
306 	static char *function = "pyfsntfs_volume_file_entries_len";
307 
308 	if( pyfsntfs_volume_file_entries == NULL )
309 	{
310 		PyErr_Format(
311 		 PyExc_ValueError,
312 		 "%s: invalid volume file entries.",
313 		 function );
314 
315 		return( -1 );
316 	}
317 	return( (Py_ssize_t) pyfsntfs_volume_file_entries->number_of_file_entries );
318 }
319 
320 /* The volume file entries getitem() function
321  */
pyfsntfs_volume_file_entries_getitem(pyfsntfs_volume_file_entries_t * pyfsntfs_volume_file_entries,Py_ssize_t item_index)322 PyObject *pyfsntfs_volume_file_entries_getitem(
323            pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries,
324            Py_ssize_t item_index )
325 {
326 	PyObject *file_entry_object = NULL;
327 	static char *function       = "pyfsntfs_volume_file_entries_getitem";
328 
329 	if( pyfsntfs_volume_file_entries == NULL )
330 	{
331 		PyErr_Format(
332 		 PyExc_ValueError,
333 		 "%s: invalid volume file entries.",
334 		 function );
335 
336 		return( NULL );
337 	}
338 	if( pyfsntfs_volume_file_entries->get_file_entry_by_index == NULL )
339 	{
340 		PyErr_Format(
341 		 PyExc_ValueError,
342 		 "%s: invalid volume file entries - missing get file entry by index function.",
343 		 function );
344 
345 		return( NULL );
346 	}
347 	if( pyfsntfs_volume_file_entries->number_of_file_entries < 0 )
348 	{
349 		PyErr_Format(
350 		 PyExc_ValueError,
351 		 "%s: invalid volume file entries - invalid number of file entries.",
352 		 function );
353 
354 		return( NULL );
355 	}
356 	if( ( item_index < 0 )
357 	 || ( item_index >= (Py_ssize_t) pyfsntfs_volume_file_entries->number_of_file_entries ) )
358 	{
359 		PyErr_Format(
360 		 PyExc_ValueError,
361 		 "%s: invalid invalid item index value out of bounds.",
362 		 function );
363 
364 		return( NULL );
365 	}
366 	file_entry_object = pyfsntfs_volume_file_entries->get_file_entry_by_index(
367 	                     pyfsntfs_volume_file_entries->volume_object,
368 	                     (uint64_t) item_index );
369 
370 	return( file_entry_object );
371 }
372 
373 /* The volume file entries iter() function
374  */
pyfsntfs_volume_file_entries_iter(pyfsntfs_volume_file_entries_t * pyfsntfs_volume_file_entries)375 PyObject *pyfsntfs_volume_file_entries_iter(
376            pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries )
377 {
378 	static char *function = "pyfsntfs_volume_file_entries_iter";
379 
380 	if( pyfsntfs_volume_file_entries == NULL )
381 	{
382 		PyErr_Format(
383 		 PyExc_ValueError,
384 		 "%s: invalid volume file entries.",
385 		 function );
386 
387 		return( NULL );
388 	}
389 	Py_IncRef(
390 	 (PyObject *) pyfsntfs_volume_file_entries );
391 
392 	return( (PyObject *) pyfsntfs_volume_file_entries );
393 }
394 
395 /* The volume file entries iternext() function
396  */
pyfsntfs_volume_file_entries_iternext(pyfsntfs_volume_file_entries_t * pyfsntfs_volume_file_entries)397 PyObject *pyfsntfs_volume_file_entries_iternext(
398            pyfsntfs_volume_file_entries_t *pyfsntfs_volume_file_entries )
399 {
400 	PyObject *file_entry_object = NULL;
401 	static char *function       = "pyfsntfs_volume_file_entries_iternext";
402 
403 	if( pyfsntfs_volume_file_entries == NULL )
404 	{
405 		PyErr_Format(
406 		 PyExc_ValueError,
407 		 "%s: invalid volume file entries.",
408 		 function );
409 
410 		return( NULL );
411 	}
412 	if( pyfsntfs_volume_file_entries->get_file_entry_by_index == NULL )
413 	{
414 		PyErr_Format(
415 		 PyExc_ValueError,
416 		 "%s: invalid volume file entries - missing get file entry by index function.",
417 		 function );
418 
419 		return( NULL );
420 	}
421 	if( pyfsntfs_volume_file_entries->file_entry_index < 0 )
422 	{
423 		PyErr_Format(
424 		 PyExc_ValueError,
425 		 "%s: invalid volume file entries - invalid file entry index.",
426 		 function );
427 
428 		return( NULL );
429 	}
430 	if( pyfsntfs_volume_file_entries->number_of_file_entries < 0 )
431 	{
432 		PyErr_Format(
433 		 PyExc_ValueError,
434 		 "%s: invalid volume file entries - invalid number of file entries.",
435 		 function );
436 
437 		return( NULL );
438 	}
439 	if( pyfsntfs_volume_file_entries->file_entry_index >= pyfsntfs_volume_file_entries->number_of_file_entries )
440 	{
441 		PyErr_SetNone(
442 		 PyExc_StopIteration );
443 
444 		return( NULL );
445 	}
446 	file_entry_object = pyfsntfs_volume_file_entries->get_file_entry_by_index(
447 	                     pyfsntfs_volume_file_entries->volume_object,
448 	                     pyfsntfs_volume_file_entries->file_entry_index );
449 
450 	if( file_entry_object != NULL )
451 	{
452 		pyfsntfs_volume_file_entries->file_entry_index++;
453 	}
454 	return( file_entry_object );
455 }
456 
457