1 /*
2  * Python object wrapper of libfsapfs_container_t
3  *
4  * Copyright (C) 2018-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 "pyfsapfs_container.h"
30 #include "pyfsapfs_error.h"
31 #include "pyfsapfs_file_object_io_handle.h"
32 #include "pyfsapfs_guid.h"
33 #include "pyfsapfs_integer.h"
34 #include "pyfsapfs_libbfio.h"
35 #include "pyfsapfs_libcerror.h"
36 #include "pyfsapfs_libfsapfs.h"
37 #include "pyfsapfs_python.h"
38 #include "pyfsapfs_unused.h"
39 #include "pyfsapfs_volume.h"
40 #include "pyfsapfs_volumes.h"
41 
42 #if !defined( LIBFSAPFS_HAVE_BFIO )
43 
44 LIBFSAPFS_EXTERN \
45 int libfsapfs_container_open_file_io_handle(
46      libfsapfs_container_t *container,
47      libbfio_handle_t *file_io_handle,
48      int access_flags,
49      libfsapfs_error_t **error );
50 
51 #endif /* !defined( LIBFSAPFS_HAVE_BFIO ) */
52 
53 PyMethodDef pyfsapfs_container_object_methods[] = {
54 
55 	{ "signal_abort",
56 	  (PyCFunction) pyfsapfs_container_signal_abort,
57 	  METH_NOARGS,
58 	  "signal_abort() -> None\n"
59 	  "\n"
60 	  "Signals the container to abort the current activity." },
61 
62 	{ "open",
63 	  (PyCFunction) pyfsapfs_container_open,
64 	  METH_VARARGS | METH_KEYWORDS,
65 	  "open(filename, mode='r') -> None\n"
66 	  "\n"
67 	  "Opens a container." },
68 
69 	{ "open_file_object",
70 	  (PyCFunction) pyfsapfs_container_open_file_object,
71 	  METH_VARARGS | METH_KEYWORDS,
72 	  "open_file_object(file_object, mode='r') -> None\n"
73 	  "\n"
74 	  "Opens a container using a file-like object." },
75 
76 	{ "close",
77 	  (PyCFunction) pyfsapfs_container_close,
78 	  METH_NOARGS,
79 	  "close() -> None\n"
80 	  "\n"
81 	  "Closes a container." },
82 
83 	{ "is_locked",
84 	  (PyCFunction) pyfsapfs_container_is_locked,
85 	  METH_NOARGS,
86 	  "is_locked() -> Boolean or None\n"
87 	  "\n"
88 	  "Determines if the container is locked." },
89 
90 	{ "get_size",
91 	  (PyCFunction) pyfsapfs_container_get_size,
92 	  METH_NOARGS,
93 	  "get_size() -> Integer\n"
94 	  "\n"
95 	  "Retrieves the size." },
96 
97 	{ "get_identifier",
98 	  (PyCFunction) pyfsapfs_container_get_identifier,
99 	  METH_NOARGS,
100 	  "get_identifier() -> Unicode string\n"
101 	  "\n"
102 	  "Retrieves the identifier." },
103 
104 	{ "get_number_of_volumes",
105 	  (PyCFunction) pyfsapfs_container_get_number_of_volumes,
106 	  METH_NOARGS,
107 	  "get_number_of_volumes() -> Integer\n"
108 	  "\n"
109 	  "Retrieves the number of volumes." },
110 
111 	{ "get_volume",
112 	  (PyCFunction) pyfsapfs_container_get_volume,
113 	  METH_VARARGS | METH_KEYWORDS,
114 	  "get_volume(volume_index) -> Object\n"
115 	  "\n"
116 	  "Retrieves the of volume specified by the index." },
117 
118 	/* Sentinel */
119 	{ NULL, NULL, 0, NULL }
120 };
121 
122 PyGetSetDef pyfsapfs_container_object_get_set_definitions[] = {
123 
124 	{ "size",
125 	  (getter) pyfsapfs_container_get_size,
126 	  (setter) 0,
127 	  "The size.",
128 	  NULL },
129 
130 	{ "identifier",
131 	  (getter) pyfsapfs_container_get_identifier,
132 	  (setter) 0,
133 	  "The identifier.",
134 	  NULL },
135 
136 	{ "number_of_volumes",
137 	  (getter) pyfsapfs_container_get_number_of_volumes,
138 	  (setter) 0,
139 	  "The number of volumes.",
140 	  NULL },
141 
142 	{ "volumes",
143 	  (getter) pyfsapfs_container_get_volumes,
144 	  (setter) 0,
145 	  "The of volumes.",
146 	  NULL },
147 
148 	/* Sentinel */
149 	{ NULL, NULL, NULL, NULL, NULL }
150 };
151 
152 PyTypeObject pyfsapfs_container_type_object = {
153 	PyVarObject_HEAD_INIT( NULL, 0 )
154 
155 	/* tp_name */
156 	"pyfsapfs.container",
157 	/* tp_basicsize */
158 	sizeof( pyfsapfs_container_t ),
159 	/* tp_itemsize */
160 	0,
161 	/* tp_dealloc */
162 	(destructor) pyfsapfs_container_free,
163 	/* tp_print */
164 	0,
165 	/* tp_getattr */
166 	0,
167 	/* tp_setattr */
168 	0,
169 	/* tp_compare */
170 	0,
171 	/* tp_repr */
172 	0,
173 	/* tp_as_number */
174 	0,
175 	/* tp_as_sequence */
176 	0,
177 	/* tp_as_mapping */
178 	0,
179 	/* tp_hash */
180 	0,
181 	/* tp_call */
182 	0,
183 	/* tp_str */
184 	0,
185 	/* tp_getattro */
186 	0,
187 	/* tp_setattro */
188 	0,
189 	/* tp_as_buffer */
190 	0,
191 	/* tp_flags */
192 	Py_TPFLAGS_DEFAULT,
193 	/* tp_doc */
194 	"pyfsapfs container object (wraps libfsapfs_container_t)",
195 	/* tp_traverse */
196 	0,
197 	/* tp_clear */
198 	0,
199 	/* tp_richcompare */
200 	0,
201 	/* tp_weaklistoffset */
202 	0,
203 	/* tp_iter */
204 	0,
205 	/* tp_iternext */
206 	0,
207 	/* tp_methods */
208 	pyfsapfs_container_object_methods,
209 	/* tp_members */
210 	0,
211 	/* tp_getset */
212 	pyfsapfs_container_object_get_set_definitions,
213 	/* tp_base */
214 	0,
215 	/* tp_dict */
216 	0,
217 	/* tp_descr_get */
218 	0,
219 	/* tp_descr_set */
220 	0,
221 	/* tp_dictoffset */
222 	0,
223 	/* tp_init */
224 	(initproc) pyfsapfs_container_init,
225 	/* tp_alloc */
226 	0,
227 	/* tp_new */
228 	0,
229 	/* tp_free */
230 	0,
231 	/* tp_is_gc */
232 	0,
233 	/* tp_bases */
234 	NULL,
235 	/* tp_mro */
236 	NULL,
237 	/* tp_cache */
238 	NULL,
239 	/* tp_subclasses */
240 	NULL,
241 	/* tp_weaklist */
242 	NULL,
243 	/* tp_del */
244 	0
245 };
246 
247 /* Initializes a container object
248  * Returns 0 if successful or -1 on error
249  */
pyfsapfs_container_init(pyfsapfs_container_t * pyfsapfs_container)250 int pyfsapfs_container_init(
251      pyfsapfs_container_t *pyfsapfs_container )
252 {
253 	libcerror_error_t *error = NULL;
254 	static char *function    = "pyfsapfs_container_init";
255 
256 	if( pyfsapfs_container == NULL )
257 	{
258 		PyErr_Format(
259 		 PyExc_ValueError,
260 		 "%s: invalid container.",
261 		 function );
262 
263 		return( -1 );
264 	}
265 	/* Make sure libfsapfs container is set to NULL
266 	 */
267 	pyfsapfs_container->container      = NULL;
268 	pyfsapfs_container->file_io_handle = NULL;
269 
270 	if( libfsapfs_container_initialize(
271 	     &( pyfsapfs_container->container ),
272 	     &error ) != 1 )
273 	{
274 		pyfsapfs_error_raise(
275 		 error,
276 		 PyExc_MemoryError,
277 		 "%s: unable to initialize container.",
278 		 function );
279 
280 		libcerror_error_free(
281 		 &error );
282 
283 		return( -1 );
284 	}
285 	return( 0 );
286 }
287 
288 /* Frees a container object
289  */
pyfsapfs_container_free(pyfsapfs_container_t * pyfsapfs_container)290 void pyfsapfs_container_free(
291       pyfsapfs_container_t *pyfsapfs_container )
292 {
293 	struct _typeobject *ob_type = NULL;
294 	libcerror_error_t *error    = NULL;
295 	static char *function       = "pyfsapfs_container_free";
296 	int result                  = 0;
297 
298 	if( pyfsapfs_container == NULL )
299 	{
300 		PyErr_Format(
301 		 PyExc_ValueError,
302 		 "%s: invalid container.",
303 		 function );
304 
305 		return;
306 	}
307 	ob_type = Py_TYPE(
308 	           pyfsapfs_container );
309 
310 	if( ob_type == NULL )
311 	{
312 		PyErr_Format(
313 		 PyExc_ValueError,
314 		 "%s: missing ob_type.",
315 		 function );
316 
317 		return;
318 	}
319 	if( ob_type->tp_free == NULL )
320 	{
321 		PyErr_Format(
322 		 PyExc_ValueError,
323 		 "%s: invalid ob_type - missing tp_free.",
324 		 function );
325 
326 		return;
327 	}
328 	if( pyfsapfs_container->container != NULL )
329 	{
330 		Py_BEGIN_ALLOW_THREADS
331 
332 		result = libfsapfs_container_free(
333 		          &( pyfsapfs_container->container ),
334 		          &error );
335 
336 		Py_END_ALLOW_THREADS
337 
338 		if( result != 1 )
339 		{
340 			pyfsapfs_error_raise(
341 			 error,
342 			 PyExc_MemoryError,
343 			 "%s: unable to free libfsapfs container.",
344 			 function );
345 
346 			libcerror_error_free(
347 			 &error );
348 		}
349 	}
350 	ob_type->tp_free(
351 	 (PyObject*) pyfsapfs_container );
352 }
353 
354 /* Signals the container to abort the current activity
355  * Returns a Python object if successful or NULL on error
356  */
pyfsapfs_container_signal_abort(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)357 PyObject *pyfsapfs_container_signal_abort(
358            pyfsapfs_container_t *pyfsapfs_container,
359            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
360 {
361 	libcerror_error_t *error = NULL;
362 	static char *function    = "pyfsapfs_container_signal_abort";
363 	int result               = 0;
364 
365 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
366 
367 	if( pyfsapfs_container == NULL )
368 	{
369 		PyErr_Format(
370 		 PyExc_ValueError,
371 		 "%s: invalid container.",
372 		 function );
373 
374 		return( NULL );
375 	}
376 	Py_BEGIN_ALLOW_THREADS
377 
378 	result = libfsapfs_container_signal_abort(
379 	          pyfsapfs_container->container,
380 	          &error );
381 
382 	Py_END_ALLOW_THREADS
383 
384 	if( result != 1 )
385 	{
386 		pyfsapfs_error_raise(
387 		 error,
388 		 PyExc_IOError,
389 		 "%s: unable to signal abort.",
390 		 function );
391 
392 		libcerror_error_free(
393 		 &error );
394 
395 		return( NULL );
396 	}
397 	Py_IncRef(
398 	 Py_None );
399 
400 	return( Py_None );
401 }
402 
403 /* Opens a container
404  * Returns a Python object if successful or NULL on error
405  */
pyfsapfs_container_open(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments,PyObject * keywords)406 PyObject *pyfsapfs_container_open(
407            pyfsapfs_container_t *pyfsapfs_container,
408            PyObject *arguments,
409            PyObject *keywords )
410 {
411 	PyObject *string_object      = NULL;
412 	libcerror_error_t *error     = NULL;
413 	const char *filename_narrow  = NULL;
414 	static char *function        = "pyfsapfs_container_open";
415 	static char *keyword_list[]  = { "filename", "mode", NULL };
416 	char *mode                   = NULL;
417 	int result                   = 0;
418 
419 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
420 	const wchar_t *filename_wide = NULL;
421 #else
422 	PyObject *utf8_string_object = NULL;
423 #endif
424 
425 	if( pyfsapfs_container == NULL )
426 	{
427 		PyErr_Format(
428 		 PyExc_ValueError,
429 		 "%s: invalid container.",
430 		 function );
431 
432 		return( NULL );
433 	}
434 	/* Note that PyArg_ParseTupleAndKeywords with "s" will force Unicode strings to be converted to narrow character string.
435 	 * On Windows the narrow character strings contains an extended ASCII string with a codepage. Hence we get a conversion
436 	 * exception. This will also fail if the default encoding is not set correctly. We cannot use "u" here either since that
437 	 * does not allow us to pass non Unicode string objects and Python (at least 2.7) does not seems to automatically upcast them.
438 	 */
439 	if( PyArg_ParseTupleAndKeywords(
440 	     arguments,
441 	     keywords,
442 	     "O|s",
443 	     keyword_list,
444 	     &string_object,
445 	     &mode ) == 0 )
446 	{
447 		return( NULL );
448 	}
449 	if( ( mode != NULL )
450 	 && ( mode[ 0 ] != 'r' ) )
451 	{
452 		PyErr_Format(
453 		 PyExc_ValueError,
454 		 "%s: unsupported mode: %s.",
455 		 function,
456 		 mode );
457 
458 		return( NULL );
459 	}
460 	PyErr_Clear();
461 
462 	result = PyObject_IsInstance(
463 	          string_object,
464 	          (PyObject *) &PyUnicode_Type );
465 
466 	if( result == -1 )
467 	{
468 		pyfsapfs_error_fetch_and_raise(
469 		 PyExc_RuntimeError,
470 		 "%s: unable to determine if string object is of type Unicode.",
471 		 function );
472 
473 		return( NULL );
474 	}
475 	else if( result != 0 )
476 	{
477 		PyErr_Clear();
478 
479 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
480 		filename_wide = (wchar_t *) PyUnicode_AsUnicode(
481 		                             string_object );
482 		Py_BEGIN_ALLOW_THREADS
483 
484 		result = libfsapfs_container_open_wide(
485 		          pyfsapfs_container->container,
486 		          filename_wide,
487 		          LIBFSAPFS_OPEN_READ,
488 		          &error );
489 
490 		Py_END_ALLOW_THREADS
491 #else
492 		utf8_string_object = PyUnicode_AsUTF8String(
493 		                      string_object );
494 
495 		if( utf8_string_object == NULL )
496 		{
497 			pyfsapfs_error_fetch_and_raise(
498 			 PyExc_RuntimeError,
499 			 "%s: unable to convert Unicode string to UTF-8.",
500 			 function );
501 
502 			return( NULL );
503 		}
504 #if PY_MAJOR_VERSION >= 3
505 		filename_narrow = PyBytes_AsString(
506 		                   utf8_string_object );
507 #else
508 		filename_narrow = PyString_AsString(
509 		                   utf8_string_object );
510 #endif
511 		Py_BEGIN_ALLOW_THREADS
512 
513 		result = libfsapfs_container_open(
514 		          pyfsapfs_container->container,
515 		          filename_narrow,
516 		          LIBFSAPFS_OPEN_READ,
517 		          &error );
518 
519 		Py_END_ALLOW_THREADS
520 
521 		Py_DecRef(
522 		 utf8_string_object );
523 #endif
524 		if( result != 1 )
525 		{
526 			pyfsapfs_error_raise(
527 			 error,
528 			 PyExc_IOError,
529 			 "%s: unable to open container.",
530 			 function );
531 
532 			libcerror_error_free(
533 			 &error );
534 
535 			return( NULL );
536 		}
537 		Py_IncRef(
538 		 Py_None );
539 
540 		return( Py_None );
541 	}
542 	PyErr_Clear();
543 
544 #if PY_MAJOR_VERSION >= 3
545 	result = PyObject_IsInstance(
546 	          string_object,
547 	          (PyObject *) &PyBytes_Type );
548 #else
549 	result = PyObject_IsInstance(
550 	          string_object,
551 	          (PyObject *) &PyString_Type );
552 #endif
553 	if( result == -1 )
554 	{
555 		pyfsapfs_error_fetch_and_raise(
556 		 PyExc_RuntimeError,
557 		 "%s: unable to determine if string object is of type string.",
558 		 function );
559 
560 		return( NULL );
561 	}
562 	else if( result != 0 )
563 	{
564 		PyErr_Clear();
565 
566 #if PY_MAJOR_VERSION >= 3
567 		filename_narrow = PyBytes_AsString(
568 		                   string_object );
569 #else
570 		filename_narrow = PyString_AsString(
571 		                   string_object );
572 #endif
573 		Py_BEGIN_ALLOW_THREADS
574 
575 		result = libfsapfs_container_open(
576 		          pyfsapfs_container->container,
577 		          filename_narrow,
578 		          LIBFSAPFS_OPEN_READ,
579 		          &error );
580 
581 		Py_END_ALLOW_THREADS
582 
583 		if( result != 1 )
584 		{
585 			pyfsapfs_error_raise(
586 			 error,
587 			 PyExc_IOError,
588 			 "%s: unable to open container.",
589 			 function );
590 
591 			libcerror_error_free(
592 			 &error );
593 
594 			return( NULL );
595 		}
596 		Py_IncRef(
597 		 Py_None );
598 
599 		return( Py_None );
600 	}
601 	PyErr_Format(
602 	 PyExc_TypeError,
603 	 "%s: unsupported string object type.",
604 	 function );
605 
606 	return( NULL );
607 }
608 
609 /* Opens a container using a file-like object
610  * Returns a Python object if successful or NULL on error
611  */
pyfsapfs_container_open_file_object(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments,PyObject * keywords)612 PyObject *pyfsapfs_container_open_file_object(
613            pyfsapfs_container_t *pyfsapfs_container,
614            PyObject *arguments,
615            PyObject *keywords )
616 {
617 	PyObject *file_object       = NULL;
618 	libcerror_error_t *error    = NULL;
619 	static char *function       = "pyfsapfs_container_open_file_object";
620 	static char *keyword_list[] = { "file_object", "mode", NULL };
621 	char *mode                  = NULL;
622 	int result                  = 0;
623 
624 	if( pyfsapfs_container == NULL )
625 	{
626 		PyErr_Format(
627 		 PyExc_ValueError,
628 		 "%s: invalid container.",
629 		 function );
630 
631 		return( NULL );
632 	}
633 	if( PyArg_ParseTupleAndKeywords(
634 	     arguments,
635 	     keywords,
636 	     "O|s",
637 	     keyword_list,
638 	     &file_object,
639 	     &mode ) == 0 )
640 	{
641 		return( NULL );
642 	}
643 	if( ( mode != NULL )
644 	 && ( mode[ 0 ] != 'r' ) )
645 	{
646 		PyErr_Format(
647 		 PyExc_ValueError,
648 		 "%s: unsupported mode: %s.",
649 		 function,
650 		 mode );
651 
652 		return( NULL );
653 	}
654 	PyErr_Clear();
655 
656 	result = PyObject_HasAttrString(
657 	          file_object,
658 	          "read" );
659 
660 	if( result != 1 )
661 	{
662 		PyErr_Format(
663 		 PyExc_TypeError,
664 		 "%s: unsupported file object - missing read attribute.",
665 		 function );
666 
667 		return( NULL );
668 	}
669 	PyErr_Clear();
670 
671 	result = PyObject_HasAttrString(
672 	          file_object,
673 	          "seek" );
674 
675 	if( result != 1 )
676 	{
677 		PyErr_Format(
678 		 PyExc_TypeError,
679 		 "%s: unsupported file object - missing seek attribute.",
680 		 function );
681 
682 		return( NULL );
683 	}
684 	if( pyfsapfs_container->file_io_handle != NULL )
685 	{
686 		pyfsapfs_error_raise(
687 		 error,
688 		 PyExc_IOError,
689 		 "%s: invalid container - file IO handle already set.",
690 		 function );
691 
692 		goto on_error;
693 	}
694 	if( pyfsapfs_file_object_initialize(
695 	     &( pyfsapfs_container->file_io_handle ),
696 	     file_object,
697 	     &error ) != 1 )
698 	{
699 		pyfsapfs_error_raise(
700 		 error,
701 		 PyExc_MemoryError,
702 		 "%s: unable to initialize file IO handle.",
703 		 function );
704 
705 		libcerror_error_free(
706 		 &error );
707 
708 		goto on_error;
709 	}
710 	Py_BEGIN_ALLOW_THREADS
711 
712 	result = libfsapfs_container_open_file_io_handle(
713 	          pyfsapfs_container->container,
714 	          pyfsapfs_container->file_io_handle,
715 	          LIBFSAPFS_OPEN_READ,
716 	          &error );
717 
718 	Py_END_ALLOW_THREADS
719 
720 	if( result != 1 )
721 	{
722 		pyfsapfs_error_raise(
723 		 error,
724 		 PyExc_IOError,
725 		 "%s: unable to open container.",
726 		 function );
727 
728 		libcerror_error_free(
729 		 &error );
730 
731 		goto on_error;
732 	}
733 	Py_IncRef(
734 	 Py_None );
735 
736 	return( Py_None );
737 
738 on_error:
739 	if( pyfsapfs_container->file_io_handle != NULL )
740 	{
741 		libbfio_handle_free(
742 		 &( pyfsapfs_container->file_io_handle ),
743 		 NULL );
744 	}
745 	return( NULL );
746 }
747 
748 /* Closes a container
749  * Returns a Python object if successful or NULL on error
750  */
pyfsapfs_container_close(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)751 PyObject *pyfsapfs_container_close(
752            pyfsapfs_container_t *pyfsapfs_container,
753            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
754 {
755 	libcerror_error_t *error = NULL;
756 	static char *function    = "pyfsapfs_container_close";
757 	int result               = 0;
758 
759 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
760 
761 	if( pyfsapfs_container == NULL )
762 	{
763 		PyErr_Format(
764 		 PyExc_ValueError,
765 		 "%s: invalid container.",
766 		 function );
767 
768 		return( NULL );
769 	}
770 	Py_BEGIN_ALLOW_THREADS
771 
772 	result = libfsapfs_container_close(
773 	          pyfsapfs_container->container,
774 	          &error );
775 
776 	Py_END_ALLOW_THREADS
777 
778 	if( result != 0 )
779 	{
780 		pyfsapfs_error_raise(
781 		 error,
782 		 PyExc_IOError,
783 		 "%s: unable to close container.",
784 		 function );
785 
786 		libcerror_error_free(
787 		 &error );
788 
789 		return( NULL );
790 	}
791 	if( pyfsapfs_container->file_io_handle != NULL )
792 	{
793 		Py_BEGIN_ALLOW_THREADS
794 
795 		result = libbfio_handle_free(
796 		          &( pyfsapfs_container->file_io_handle ),
797 		          &error );
798 
799 		Py_END_ALLOW_THREADS
800 
801 		if( result != 1 )
802 		{
803 			pyfsapfs_error_raise(
804 			 error,
805 			 PyExc_MemoryError,
806 			 "%s: unable to free libbfio file IO handle.",
807 			 function );
808 
809 			libcerror_error_free(
810 			 &error );
811 
812 			return( NULL );
813 		}
814 	}
815 	Py_IncRef(
816 	 Py_None );
817 
818 	return( Py_None );
819 }
820 
821 /* Determines if the container is locked
822  * Returns a Python object if successful or NULL on error
823  */
pyfsapfs_container_is_locked(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)824 PyObject *pyfsapfs_container_is_locked(
825            pyfsapfs_container_t *pyfsapfs_container,
826            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
827 {
828 	libcerror_error_t *error = NULL;
829 	static char *function    = "pyfsapfs_container_is_locked";
830 	int result               = 0;
831 
832 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
833 
834 	if( pyfsapfs_container == NULL )
835 	{
836 		PyErr_Format(
837 		 PyExc_ValueError,
838 		 "%s: invalid container.",
839 		 function );
840 
841 		return( NULL );
842 	}
843 	Py_BEGIN_ALLOW_THREADS
844 
845 	result = libfsapfs_container_is_locked(
846 	          pyfsapfs_container->container,
847 	          &error );
848 
849 	Py_END_ALLOW_THREADS
850 
851 	if( result == -1 )
852 	{
853 		pyfsapfs_error_raise(
854 		 error,
855 		 PyExc_IOError,
856 		 "%s: unable to determine if container is locked.",
857 		 function );
858 
859 		libcerror_error_free(
860 		 &error );
861 
862 		return( NULL );
863 	}
864 	if( result != 0 )
865 	{
866 		Py_IncRef(
867 		 (PyObject *) Py_True );
868 
869 		return( Py_True );
870 	}
871 	Py_IncRef(
872 	 (PyObject *) Py_False );
873 
874 	return( Py_False );
875 }
876 
877 /* Retrieves the size
878  * Returns a Python object if successful or NULL on error
879  */
pyfsapfs_container_get_size(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)880 PyObject *pyfsapfs_container_get_size(
881            pyfsapfs_container_t *pyfsapfs_container,
882            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
883 {
884 	PyObject *integer_object = NULL;
885 	libcerror_error_t *error = NULL;
886 	static char *function    = "pyfsapfs_container_get_size";
887 	size64_t size            = 0;
888 	int result               = 0;
889 
890 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
891 
892 	if( pyfsapfs_container == NULL )
893 	{
894 		PyErr_Format(
895 		 PyExc_ValueError,
896 		 "%s: invalid container.",
897 		 function );
898 
899 		return( NULL );
900 	}
901 	Py_BEGIN_ALLOW_THREADS
902 
903 	result = libfsapfs_container_get_size(
904 	          pyfsapfs_container->container,
905 	          &size,
906 	          &error );
907 
908 	Py_END_ALLOW_THREADS
909 
910 	if( result != 1 )
911 	{
912 		pyfsapfs_error_raise(
913 		 error,
914 		 PyExc_IOError,
915 		 "%s: failed to retrieve size.",
916 		 function );
917 
918 		libcerror_error_free(
919 		 &error );
920 
921 		return( NULL );
922 	}
923 	integer_object = pyfsapfs_integer_unsigned_new_from_64bit(
924 	                  (uint64_t) size );
925 
926 	return( integer_object );
927 }
928 
929 /* Retrieves the identifier
930  * Returns a Python object if successful or NULL on error
931  */
pyfsapfs_container_get_identifier(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)932 PyObject *pyfsapfs_container_get_identifier(
933            pyfsapfs_container_t *pyfsapfs_container,
934            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
935 {
936 	uint8_t uuid_data[ 16 ];
937 
938 	PyObject *string_object  = NULL;
939 	libcerror_error_t *error = NULL;
940 	static char *function    = "pyfsapfs_container_get_identifier";
941 	int result               = 0;
942 
943 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
944 
945 	if( pyfsapfs_container == NULL )
946 	{
947 		PyErr_Format(
948 		 PyExc_ValueError,
949 		 "%s: invalid container.",
950 		 function );
951 
952 		return( NULL );
953 	}
954 	Py_BEGIN_ALLOW_THREADS
955 
956 	result = libfsapfs_container_get_identifier(
957 	          pyfsapfs_container->container,
958 	          uuid_data,
959 	          16,
960 	          &error );
961 
962 	Py_END_ALLOW_THREADS
963 
964 	if( result != 1 )
965 	{
966 		pyfsapfs_error_raise(
967 		 error,
968 		 PyExc_IOError,
969 		 "%s: unable to retrieve identifier.",
970 		 function );
971 
972 		libcerror_error_free(
973 		 &error );
974 
975 		return( NULL );
976 	}
977 	string_object = pyfsapfs_string_new_from_guid(
978 	                 uuid_data,
979 	                 16 );
980 
981 	if( string_object == NULL )
982 	{
983 		PyErr_Format(
984 		 PyExc_IOError,
985 		 "%s: unable to convert UUID into Unicode object.",
986 		 function );
987 
988 		return( NULL );
989 	}
990 	return( string_object );
991 }
992 
993 /* Retrieves the number of volumes
994  * Returns a Python object if successful or NULL on error
995  */
pyfsapfs_container_get_number_of_volumes(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)996 PyObject *pyfsapfs_container_get_number_of_volumes(
997            pyfsapfs_container_t *pyfsapfs_container,
998            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
999 {
1000 	PyObject *integer_object = NULL;
1001 	libcerror_error_t *error = NULL;
1002 	static char *function    = "pyfsapfs_container_get_number_of_volumes";
1003 	int number_of_volumes    = 0;
1004 	int result               = 0;
1005 
1006 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
1007 
1008 	if( pyfsapfs_container == NULL )
1009 	{
1010 		PyErr_Format(
1011 		 PyExc_ValueError,
1012 		 "%s: invalid container.",
1013 		 function );
1014 
1015 		return( NULL );
1016 	}
1017 	Py_BEGIN_ALLOW_THREADS
1018 
1019 	result = libfsapfs_container_get_number_of_volumes(
1020 	          pyfsapfs_container->container,
1021 	          &number_of_volumes,
1022 	          &error );
1023 
1024 	Py_END_ALLOW_THREADS
1025 
1026 	if( result != 1 )
1027 	{
1028 		pyfsapfs_error_raise(
1029 		 error,
1030 		 PyExc_IOError,
1031 		 "%s: unable to retrieve number of volumes.",
1032 		 function );
1033 
1034 		libcerror_error_free(
1035 		 &error );
1036 
1037 		return( NULL );
1038 	}
1039 #if PY_MAJOR_VERSION >= 3
1040 	integer_object = PyLong_FromLong(
1041 	                  (long) number_of_volumes );
1042 #else
1043 	integer_object = PyInt_FromLong(
1044 	                  (long) number_of_volumes );
1045 #endif
1046 	return( integer_object );
1047 }
1048 
1049 /* Retrieves a specific of volume by index
1050  * Returns a Python object if successful or NULL on error
1051  */
pyfsapfs_container_get_volume_by_index(PyObject * pyfsapfs_container,int volume_index)1052 PyObject *pyfsapfs_container_get_volume_by_index(
1053            PyObject *pyfsapfs_container,
1054            int volume_index )
1055 {
1056 	PyObject *volume_object    = NULL;
1057 	libcerror_error_t *error   = NULL;
1058 	libfsapfs_volume_t *volume = NULL;
1059 	static char *function      = "pyfsapfs_container_get_volume_by_index";
1060 	int result                 = 0;
1061 
1062 	if( pyfsapfs_container == NULL )
1063 	{
1064 		PyErr_Format(
1065 		 PyExc_ValueError,
1066 		 "%s: invalid container.",
1067 		 function );
1068 
1069 		return( NULL );
1070 	}
1071 	Py_BEGIN_ALLOW_THREADS
1072 
1073 	result = libfsapfs_container_get_volume_by_index(
1074 	          ( (pyfsapfs_container_t *) pyfsapfs_container )->container,
1075 	          volume_index,
1076 	          &volume,
1077 	          &error );
1078 
1079 	Py_END_ALLOW_THREADS
1080 
1081 	if( result != 1 )
1082 	{
1083 		pyfsapfs_error_raise(
1084 		 error,
1085 		 PyExc_IOError,
1086 		 "%s: unable to retrieve of volume: %d.",
1087 		 function,
1088 		 volume_index );
1089 
1090 		libcerror_error_free(
1091 		 &error );
1092 
1093 		goto on_error;
1094 	}
1095 	volume_object = pyfsapfs_volume_new(
1096 	                 volume,
1097 	                 pyfsapfs_container );
1098 
1099 	if( volume_object == NULL )
1100 	{
1101 		PyErr_Format(
1102 		 PyExc_MemoryError,
1103 		 "%s: unable to create volume object.",
1104 		 function );
1105 
1106 		goto on_error;
1107 	}
1108 	return( volume_object );
1109 
1110 on_error:
1111 	if( volume != NULL )
1112 	{
1113 		libfsapfs_volume_free(
1114 		 &volume,
1115 		 NULL );
1116 	}
1117 	return( NULL );
1118 }
1119 
1120 /* Retrieves a specific of volume
1121  * Returns a Python object if successful or NULL on error
1122  */
pyfsapfs_container_get_volume(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments,PyObject * keywords)1123 PyObject *pyfsapfs_container_get_volume(
1124            pyfsapfs_container_t *pyfsapfs_container,
1125            PyObject *arguments,
1126            PyObject *keywords )
1127 {
1128 	PyObject *volume_object     = NULL;
1129 	static char *keyword_list[] = { "volume_index", NULL };
1130 	int volume_index            = 0;
1131 
1132 	if( PyArg_ParseTupleAndKeywords(
1133 	     arguments,
1134 	     keywords,
1135 	     "i",
1136 	     keyword_list,
1137 	     &volume_index ) == 0 )
1138 	{
1139 		return( NULL );
1140 	}
1141 	volume_object = pyfsapfs_container_get_volume_by_index(
1142 	                 (PyObject *) pyfsapfs_container,
1143 	                 volume_index );
1144 
1145 	return( volume_object );
1146 }
1147 
1148 /* Retrieves a sequence and iterator object for the volumes
1149  * Returns a Python object if successful or NULL on error
1150  */
pyfsapfs_container_get_volumes(pyfsapfs_container_t * pyfsapfs_container,PyObject * arguments PYFSAPFS_ATTRIBUTE_UNUSED)1151 PyObject *pyfsapfs_container_get_volumes(
1152            pyfsapfs_container_t *pyfsapfs_container,
1153            PyObject *arguments PYFSAPFS_ATTRIBUTE_UNUSED )
1154 {
1155 	PyObject *sequence_object = NULL;
1156 	libcerror_error_t *error  = NULL;
1157 	static char *function     = "pyfsapfs_container_get_volumes";
1158 	int number_of_volumes     = 0;
1159 	int result                = 0;
1160 
1161 	PYFSAPFS_UNREFERENCED_PARAMETER( arguments )
1162 
1163 	if( pyfsapfs_container == NULL )
1164 	{
1165 		PyErr_Format(
1166 		 PyExc_ValueError,
1167 		 "%s: invalid container.",
1168 		 function );
1169 
1170 		return( NULL );
1171 	}
1172 	Py_BEGIN_ALLOW_THREADS
1173 
1174 	result = libfsapfs_container_get_number_of_volumes(
1175 	          pyfsapfs_container->container,
1176 	          &number_of_volumes,
1177 	          &error );
1178 
1179 	Py_END_ALLOW_THREADS
1180 
1181 	if( result != 1 )
1182 	{
1183 		pyfsapfs_error_raise(
1184 		 error,
1185 		 PyExc_IOError,
1186 		 "%s: unable to retrieve number of volumes.",
1187 		 function );
1188 
1189 		libcerror_error_free(
1190 		 &error );
1191 
1192 		return( NULL );
1193 	}
1194 	sequence_object = pyfsapfs_volumes_new(
1195 	                   (PyObject *) pyfsapfs_container,
1196 	                   &pyfsapfs_container_get_volume_by_index,
1197 	                   number_of_volumes );
1198 
1199 	if( sequence_object == NULL )
1200 	{
1201 		pyfsapfs_error_raise(
1202 		 error,
1203 		 PyExc_MemoryError,
1204 		 "%s: unable to create sequence object.",
1205 		 function );
1206 
1207 		return( NULL );
1208 	}
1209 	return( sequence_object );
1210 }
1211 
1212