1 /*
2 * Python object wrapper of libfwsi_item_list_t
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 <memory.h>
24 #include <narrow_string.h>
25 #include <types.h>
26
27 #if defined( HAVE_STDLIB_H )
28 #include <stdlib.h>
29 #endif
30
31 #include "pyfwsi_error.h"
32 #include "pyfwsi_file_entry.h"
33 #include "pyfwsi_item.h"
34 #include "pyfwsi_item_list.h"
35 #include "pyfwsi_items.h"
36 #include "pyfwsi_libcerror.h"
37 #include "pyfwsi_libclocale.h"
38 #include "pyfwsi_libfwsi.h"
39 #include "pyfwsi_network_location.h"
40 #include "pyfwsi_python.h"
41 #include "pyfwsi_root_folder.h"
42 #include "pyfwsi_unused.h"
43 #include "pyfwsi_volume.h"
44
45 PyMethodDef pyfwsi_item_list_object_methods[] = {
46
47 { "copy_from_byte_stream",
48 (PyCFunction) pyfwsi_item_list_copy_from_byte_stream,
49 METH_VARARGS | METH_KEYWORDS,
50 "copy_from_byte_stream(byte_stream, ascii_codepage=cp1252)\n"
51 "\n"
52 "Copies the the item list from the byte stream." },
53
54 /* Functions to access the items */
55
56 { "get_number_of_items",
57 (PyCFunction) pyfwsi_item_list_get_number_of_items,
58 METH_NOARGS,
59 "get_number_of_items() -> Integer\n"
60 "\n"
61 "Retrieves the number of items." },
62
63 { "get_item",
64 (PyCFunction) pyfwsi_item_list_get_item,
65 METH_VARARGS | METH_KEYWORDS,
66 "get_item(item_index) -> Object\n"
67 "\n"
68 "Retrieves a specific item." },
69
70 /* Sentinel */
71 { NULL, NULL, 0, NULL }
72 };
73
74 PyGetSetDef pyfwsi_item_list_object_get_set_definitions[] = {
75
76 { "number_of_items",
77 (getter) pyfwsi_item_list_get_number_of_items,
78 (setter) 0,
79 "The number of items.",
80 NULL },
81
82 { "items",
83 (getter) pyfwsi_item_list_get_items,
84 (setter) 0,
85 "The items",
86 NULL },
87
88 /* Sentinel */
89 { NULL, NULL, NULL, NULL, NULL }
90 };
91
92 PyTypeObject pyfwsi_item_list_type_object = {
93 PyVarObject_HEAD_INIT( NULL, 0 )
94
95 /* tp_name */
96 "pyfwsi.item_list",
97 /* tp_basicsize */
98 sizeof( pyfwsi_item_list_t ),
99 /* tp_itemsize */
100 0,
101 /* tp_dealloc */
102 (destructor) pyfwsi_item_list_free,
103 /* tp_print */
104 0,
105 /* tp_getattr */
106 0,
107 /* tp_setattr */
108 0,
109 /* tp_compare */
110 0,
111 /* tp_repr */
112 0,
113 /* tp_as_number */
114 0,
115 /* tp_as_sequence */
116 0,
117 /* tp_as_mapping */
118 0,
119 /* tp_hash */
120 0,
121 /* tp_call */
122 0,
123 /* tp_str */
124 0,
125 /* tp_getattro */
126 0,
127 /* tp_setattro */
128 0,
129 /* tp_as_buffer */
130 0,
131 /* tp_flags */
132 Py_TPFLAGS_DEFAULT,
133 /* tp_doc */
134 "pyfwsi item_list object (wraps libfwsi_item_list_t)",
135 /* tp_traverse */
136 0,
137 /* tp_clear */
138 0,
139 /* tp_richcompare */
140 0,
141 /* tp_weaklistoffset */
142 0,
143 /* tp_iter */
144 0,
145 /* tp_iternext */
146 0,
147 /* tp_methods */
148 pyfwsi_item_list_object_methods,
149 /* tp_members */
150 0,
151 /* tp_getset */
152 pyfwsi_item_list_object_get_set_definitions,
153 /* tp_base */
154 0,
155 /* tp_dict */
156 0,
157 /* tp_descr_get */
158 0,
159 /* tp_descr_set */
160 0,
161 /* tp_dictoffset */
162 0,
163 /* tp_init */
164 (initproc) pyfwsi_item_list_init,
165 /* tp_alloc */
166 0,
167 /* tp_new */
168 0,
169 /* tp_free */
170 0,
171 /* tp_is_gc */
172 0,
173 /* tp_bases */
174 NULL,
175 /* tp_mro */
176 NULL,
177 /* tp_cache */
178 NULL,
179 /* tp_subclasses */
180 NULL,
181 /* tp_weaklist */
182 NULL,
183 /* tp_del */
184 0
185 };
186
187 /* Creates a new pyfwsi item list object
188 * Returns a Python object if successful or NULL on error
189 */
pyfwsi_item_list_new(void)190 PyObject *pyfwsi_item_list_new(
191 void )
192 {
193 static char *function = "pyfwsi_item_list_new";
194 pyfwsi_item_list_t *pyfwsi_item_list = NULL;
195
196 pyfwsi_item_list = PyObject_New(
197 struct pyfwsi_item_list,
198 &pyfwsi_item_list_type_object );
199
200 if( pyfwsi_item_list == NULL )
201 {
202 PyErr_Format(
203 PyExc_MemoryError,
204 "%s: unable to initialize item list.",
205 function );
206
207 goto on_error;
208 }
209 if( pyfwsi_item_list_init(
210 pyfwsi_item_list ) != 0 )
211 {
212 PyErr_Format(
213 PyExc_MemoryError,
214 "%s: unable to initialize item list.",
215 function );
216
217 goto on_error;
218 }
219 return( (PyObject *) pyfwsi_item_list );
220
221 on_error:
222 if( pyfwsi_item_list != NULL )
223 {
224 Py_DecRef(
225 (PyObject *) pyfwsi_item_list );
226 }
227 return( NULL );
228 }
229
230 /* Initializes an item list object
231 * Returns 0 if successful or -1 on error
232 */
pyfwsi_item_list_init(pyfwsi_item_list_t * pyfwsi_item_list)233 int pyfwsi_item_list_init(
234 pyfwsi_item_list_t *pyfwsi_item_list )
235 {
236 static char *function = "pyfwsi_item_list_init";
237 libcerror_error_t *error = NULL;
238
239 if( pyfwsi_item_list == NULL )
240 {
241 PyErr_Format(
242 PyExc_TypeError,
243 "%s: invalid item list.",
244 function );
245
246 return( -1 );
247 }
248 pyfwsi_item_list->item_list = NULL;
249
250 if( libfwsi_item_list_initialize(
251 &( pyfwsi_item_list->item_list ),
252 &error ) != 1 )
253 {
254 pyfwsi_error_raise(
255 error,
256 PyExc_MemoryError,
257 "%s: unable to initialize item list.",
258 function );
259
260 libcerror_error_free(
261 &error );
262
263 return( -1 );
264 }
265 return( 0 );
266 }
267
268 /* Frees an item list object
269 */
pyfwsi_item_list_free(pyfwsi_item_list_t * pyfwsi_item_list)270 void pyfwsi_item_list_free(
271 pyfwsi_item_list_t *pyfwsi_item_list )
272 {
273 libcerror_error_t *error = NULL;
274 struct _typeobject *ob_type = NULL;
275 static char *function = "pyfwsi_item_list_free";
276 int result = 0;
277
278 if( pyfwsi_item_list == NULL )
279 {
280 PyErr_Format(
281 PyExc_TypeError,
282 "%s: invalid item list.",
283 function );
284
285 return;
286 }
287 if( pyfwsi_item_list->item_list == NULL )
288 {
289 PyErr_Format(
290 PyExc_TypeError,
291 "%s: invalid item list - missing libfwsi item list.",
292 function );
293
294 return;
295 }
296 ob_type = Py_TYPE(
297 pyfwsi_item_list );
298
299 if( ob_type == NULL )
300 {
301 PyErr_Format(
302 PyExc_ValueError,
303 "%s: missing ob_type.",
304 function );
305
306 return;
307 }
308 if( ob_type->tp_free == NULL )
309 {
310 PyErr_Format(
311 PyExc_ValueError,
312 "%s: invalid ob_type - missing tp_free.",
313 function );
314
315 return;
316 }
317 Py_BEGIN_ALLOW_THREADS
318
319 result = libfwsi_item_list_free(
320 &( pyfwsi_item_list->item_list ),
321 &error );
322
323 Py_END_ALLOW_THREADS
324
325 if( result != 1 )
326 {
327 pyfwsi_error_raise(
328 error,
329 PyExc_MemoryError,
330 "%s: unable to free item list.",
331 function );
332
333 libcerror_error_free(
334 &error );
335 }
336 ob_type->tp_free(
337 (PyObject*) pyfwsi_item_list );
338 }
339
340 /* Copies the item list from a byte stream
341 * Returns a Python object if successful or NULL on error
342 */
pyfwsi_item_list_copy_from_byte_stream(pyfwsi_item_list_t * pyfwsi_item_list,PyObject * arguments,PyObject * keywords)343 PyObject *pyfwsi_item_list_copy_from_byte_stream(
344 pyfwsi_item_list_t *pyfwsi_item_list,
345 PyObject *arguments,
346 PyObject *keywords )
347 {
348 PyObject *string_object = NULL;
349 libcerror_error_t *error = NULL;
350 static char *function = "pyfwsi_item_list_copy_from_byte_stream";
351 static char *keyword_list[] = { "byte_stream", "ascii_codepage", NULL };
352 const char *byte_stream = NULL;
353 char *codepage_string = NULL;
354 Py_ssize_t byte_stream_size = 0;
355 size_t codepage_string_length = 0;
356 uint32_t feature_flags = 0;
357 int ascii_codepage = LIBFWSI_CODEPAGE_WINDOWS_1252;
358 int result = 0;
359
360 if( pyfwsi_item_list == NULL )
361 {
362 PyErr_Format(
363 PyExc_TypeError,
364 "%s: invalid item list.",
365 function );
366
367 return( NULL );
368 }
369 if( PyArg_ParseTupleAndKeywords(
370 arguments,
371 keywords,
372 "O|s",
373 keyword_list,
374 &string_object,
375 &codepage_string ) == 0 )
376 {
377 return( NULL );
378 }
379 PyErr_Clear();
380
381 #if PY_MAJOR_VERSION >= 3
382 result = PyObject_IsInstance(
383 string_object,
384 (PyObject *) &PyBytes_Type );
385 #else
386 result = PyObject_IsInstance(
387 string_object,
388 (PyObject *) &PyString_Type );
389 #endif
390 if( result == -1 )
391 {
392 pyfwsi_error_fetch_and_raise(
393 PyExc_RuntimeError,
394 "%s: unable to determine if string object is of type string.",
395 function );
396
397 return( NULL );
398 }
399 else if( result == 0 )
400 {
401 PyErr_Format(
402 PyExc_TypeError,
403 "%s: unsupported string object type",
404 function );
405
406 return( NULL );
407 }
408 if( codepage_string != NULL )
409 {
410 codepage_string_length = narrow_string_length(
411 codepage_string );
412
413 feature_flags = LIBCLOCALE_CODEPAGE_FEATURE_FLAG_HAVE_WINDOWS;
414
415 if( libclocale_codepage_copy_from_string(
416 &ascii_codepage,
417 codepage_string,
418 codepage_string_length,
419 feature_flags,
420 &error ) != 1 )
421 {
422 pyfwsi_error_raise(
423 error,
424 PyExc_RuntimeError,
425 "%s: unable to determine ASCII codepage.",
426 function );
427
428 libcerror_error_free(
429 &error );
430
431 return( NULL );
432 }
433 }
434 PyErr_Clear();
435
436 #if PY_MAJOR_VERSION >= 3
437 byte_stream = PyBytes_AsString(
438 string_object );
439
440 byte_stream_size = PyBytes_Size(
441 string_object );
442 #else
443 byte_stream = PyString_AsString(
444 string_object );
445
446 byte_stream_size = PyString_Size(
447 string_object );
448 #endif
449 /* TODO size bounds check */
450
451 Py_BEGIN_ALLOW_THREADS
452
453 result = libfwsi_item_list_copy_from_byte_stream(
454 pyfwsi_item_list->item_list,
455 (uint8_t *) byte_stream,
456 (size_t) byte_stream_size,
457 ascii_codepage,
458 &error );
459
460 Py_END_ALLOW_THREADS
461
462 if( result != 1 )
463 {
464 pyfwsi_error_raise(
465 error,
466 PyExc_IOError,
467 "%s: unable to copy item list from byte stream.",
468 function );
469
470 libcerror_error_free(
471 &error );
472
473 return( NULL );
474 }
475 Py_IncRef(
476 Py_None );
477
478 return( Py_None );
479 }
480
481 /* Retrieves the number of items
482 * Returns a Python object if successful or NULL on error
483 */
pyfwsi_item_list_get_number_of_items(pyfwsi_item_list_t * pyfwsi_item_list,PyObject * arguments PYFWSI_ATTRIBUTE_UNUSED)484 PyObject *pyfwsi_item_list_get_number_of_items(
485 pyfwsi_item_list_t *pyfwsi_item_list,
486 PyObject *arguments PYFWSI_ATTRIBUTE_UNUSED )
487 {
488 libcerror_error_t *error = NULL;
489 PyObject *integer_object = NULL;
490 static char *function = "pyfwsi_item_list_get_number_of_items";
491 int number_of_items = 0;
492 int result = 0;
493
494 PYFWSI_UNREFERENCED_PARAMETER( arguments )
495
496 if( pyfwsi_item_list == NULL )
497 {
498 PyErr_Format(
499 PyExc_TypeError,
500 "%s: invalid item list.",
501 function );
502
503 return( NULL );
504 }
505 Py_BEGIN_ALLOW_THREADS
506
507 result = libfwsi_item_list_get_number_of_items(
508 pyfwsi_item_list->item_list,
509 &number_of_items,
510 &error );
511
512 Py_END_ALLOW_THREADS
513
514 if( result != 1 )
515 {
516 pyfwsi_error_raise(
517 error,
518 PyExc_IOError,
519 "%s: unable to retrieve number of items.",
520 function );
521
522 libcerror_error_free(
523 &error );
524
525 return( NULL );
526 }
527 #if PY_MAJOR_VERSION >= 3
528 integer_object = PyLong_FromLong(
529 (long) number_of_items );
530 #else
531 integer_object = PyInt_FromLong(
532 (long) number_of_items );
533 #endif
534 return( integer_object );
535 }
536
537 /* Retrieves a specific item by index
538 * Returns a Python object if successful or NULL on error
539 */
pyfwsi_item_list_get_item_by_index(PyObject * pyfwsi_item_list,int item_index)540 PyObject *pyfwsi_item_list_get_item_by_index(
541 PyObject *pyfwsi_item_list,
542 int item_index )
543 {
544 libcerror_error_t *error = NULL;
545 libfwsi_item_t *item = NULL;
546 PyObject *item_object = NULL;
547 PyTypeObject *type_object = NULL;
548 static char *function = "pyfwsi_item_list_get_item_by_index";
549 int item_type = 0;
550 int result = 0;
551
552 if( pyfwsi_item_list == NULL )
553 {
554 PyErr_Format(
555 PyExc_TypeError,
556 "%s: invalid item list.",
557 function );
558
559 return( NULL );
560 }
561 Py_BEGIN_ALLOW_THREADS
562
563 result = libfwsi_item_list_get_item(
564 ( (pyfwsi_item_list_t *) pyfwsi_item_list )->item_list,
565 item_index,
566 &item,
567 &error );
568
569 Py_END_ALLOW_THREADS
570
571 if( result != 1 )
572 {
573 pyfwsi_error_raise(
574 error,
575 PyExc_IOError,
576 "%s: unable to retrieve item: %d.",
577 function,
578 item_index );
579
580 libcerror_error_free(
581 &error );
582
583 goto on_error;
584 }
585 Py_BEGIN_ALLOW_THREADS
586
587 result = libfwsi_item_get_type(
588 item,
589 &item_type,
590 &error );
591
592 Py_END_ALLOW_THREADS
593
594 if( result != 1 )
595 {
596 pyfwsi_error_raise(
597 error,
598 PyExc_IOError,
599 "%s: unable to retrieve item: %d class type.",
600 function,
601 item_index );
602
603 libcerror_error_free(
604 &error );
605
606 goto on_error;
607 }
608 switch( item_type )
609 {
610 case LIBFWSI_ITEM_TYPE_FILE_ENTRY:
611 type_object = &pyfwsi_file_entry_type_object;
612 break;
613
614 case LIBFWSI_ITEM_TYPE_NETWORK_LOCATION:
615 type_object = &pyfwsi_network_location_type_object;
616 break;
617
618 case LIBFWSI_ITEM_TYPE_ROOT_FOLDER:
619 type_object = &pyfwsi_root_folder_type_object;
620 break;
621
622 case LIBFWSI_ITEM_TYPE_VOLUME:
623 type_object = &pyfwsi_volume_type_object;
624 break;
625
626 case LIBFWSI_ITEM_TYPE_UNKNOWN:
627 case LIBFWSI_ITEM_TYPE_CDBURN:
628 case LIBFWSI_ITEM_TYPE_CONTROL_PANEL:
629 case LIBFWSI_ITEM_TYPE_DELEGATE:
630 case LIBFWSI_ITEM_TYPE_GAME_FOLDER:
631 case LIBFWSI_ITEM_TYPE_URI:
632 case LIBFWSI_ITEM_TYPE_USERS_PROPERTY_VIEW:
633 default:
634 type_object = &pyfwsi_item_type_object;
635 break;
636 }
637 item_object = pyfwsi_item_new(
638 type_object,
639 item,
640 pyfwsi_item_list );
641
642 if( item_object == NULL )
643 {
644 PyErr_Format(
645 PyExc_MemoryError,
646 "%s: unable to create item object.",
647 function );
648
649 goto on_error;
650 }
651 return( item_object );
652
653 on_error:
654 if( item != NULL )
655 {
656 libfwsi_item_free(
657 &item,
658 NULL );
659 }
660 return( NULL );
661 }
662
663 /* Retrieves a specific item
664 * Returns a Python object if successful or NULL on error
665 */
pyfwsi_item_list_get_item(pyfwsi_item_list_t * pyfwsi_item_list,PyObject * arguments,PyObject * keywords)666 PyObject *pyfwsi_item_list_get_item(
667 pyfwsi_item_list_t *pyfwsi_item_list,
668 PyObject *arguments,
669 PyObject *keywords )
670 {
671 PyObject *item_object = NULL;
672 static char *keyword_list[] = { "item_index", NULL };
673 int item_index = 0;
674
675 if( PyArg_ParseTupleAndKeywords(
676 arguments,
677 keywords,
678 "i",
679 keyword_list,
680 &item_index ) == 0 )
681 {
682 return( NULL );
683 }
684 item_object = pyfwsi_item_list_get_item_by_index(
685 (PyObject *) pyfwsi_item_list,
686 item_index );
687
688 return( item_object );
689 }
690
691 /* Retrieves an items sequence and iterator object for the items
692 * Returns a Python object if successful or NULL on error
693 */
pyfwsi_item_list_get_items(pyfwsi_item_list_t * pyfwsi_item_list,PyObject * arguments PYFWSI_ATTRIBUTE_UNUSED)694 PyObject *pyfwsi_item_list_get_items(
695 pyfwsi_item_list_t *pyfwsi_item_list,
696 PyObject *arguments PYFWSI_ATTRIBUTE_UNUSED )
697 {
698 libcerror_error_t *error = NULL;
699 PyObject *items_object = NULL;
700 static char *function = "pyfwsi_item_list_get_items";
701 int number_of_items = 0;
702 int result = 0;
703
704 PYFWSI_UNREFERENCED_PARAMETER( arguments )
705
706 if( pyfwsi_item_list == NULL )
707 {
708 PyErr_Format(
709 PyExc_TypeError,
710 "%s: invalid item list.",
711 function );
712
713 return( NULL );
714 }
715 Py_BEGIN_ALLOW_THREADS
716
717 result = libfwsi_item_list_get_number_of_items(
718 pyfwsi_item_list->item_list,
719 &number_of_items,
720 &error );
721
722 Py_END_ALLOW_THREADS
723
724 if( result != 1 )
725 {
726 pyfwsi_error_raise(
727 error,
728 PyExc_IOError,
729 "%s: unable to retrieve number of items.",
730 function );
731
732 libcerror_error_free(
733 &error );
734
735 return( NULL );
736 }
737 items_object = pyfwsi_items_new(
738 (PyObject *) pyfwsi_item_list,
739 &pyfwsi_item_list_get_item_by_index,
740 number_of_items );
741
742 if( items_object == NULL )
743 {
744 PyErr_Format(
745 PyExc_MemoryError,
746 "%s: unable to create items object.",
747 function );
748
749 return( NULL );
750 }
751 return( items_object );
752 }
753
754