1 /*
2  * Python object definition of the libfsntfs MFT metadata file
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_error.h"
30 #include "pyfsntfs_file_entry.h"
31 #include "pyfsntfs_file_object_io_handle.h"
32 #include "pyfsntfs_integer.h"
33 #include "pyfsntfs_libbfio.h"
34 #include "pyfsntfs_libcerror.h"
35 #include "pyfsntfs_libfsntfs.h"
36 #include "pyfsntfs_mft_metadata_file.h"
37 #include "pyfsntfs_mft_metadata_file_entries.h"
38 #include "pyfsntfs_python.h"
39 #include "pyfsntfs_unused.h"
40 
41 #if !defined( LIBFSNTFS_HAVE_BFIO )
42 
43 LIBFSNTFS_EXTERN \
44 int libfsntfs_mft_metadata_file_open_file_io_handle(
45      libfsntfs_mft_metadata_file_t *mft_metadata_file,
46      libbfio_handle_t *file_io_handle,
47      int access_flags,
48      libfsntfs_error_t **error );
49 
50 #endif /* !defined( LIBFSNTFS_HAVE_BFIO ) */
51 
52 PyMethodDef pyfsntfs_mft_metadata_file_object_methods[] = {
53 
54 	/* Functions to access the MFT metadata file */
55 
56 	{ "open",
57 	  (PyCFunction) pyfsntfs_mft_metadata_file_open,
58 	  METH_VARARGS | METH_KEYWORDS,
59 	  "open(filename, mode='r') -> None\n"
60 	  "\n"
61 	  "Opens a MFT metadata file." },
62 
63 	{ "open_file_object",
64 	  (PyCFunction) pyfsntfs_mft_metadata_file_open_file_object,
65 	  METH_VARARGS | METH_KEYWORDS,
66 	  "open_file_object(file_object, mode='r') -> None\n"
67 	  "\n"
68 	  "Opens a MFT metadata file using a file-like object." },
69 
70 	{ "close",
71 	  (PyCFunction) pyfsntfs_mft_metadata_file_close,
72 	  METH_NOARGS,
73 	  "close() -> None\n"
74 	  "\n"
75 	  "Closes a MFT metadata file." },
76 
77 	/* Functions to access the MFT metadata file values */
78 
79 	{ "get_volume_name",
80 	  (PyCFunction) pyfsntfs_mft_metadata_file_get_volume_name,
81 	  METH_NOARGS,
82 	  "get_volume_name() -> Unicode string or None\n"
83 	  "\n"
84 	  "Retrieves the volume name." },
85 
86 	/* Functions to access the file entries */
87 
88 	{ "get_number_of_file_entries",
89 	  (PyCFunction) pyfsntfs_mft_metadata_file_get_number_of_file_entries,
90 	  METH_NOARGS,
91 	  "get_number_of_file_entries() -> Integer\n"
92 	  "\n"
93 	  "Retrieves the number of file entries." },
94 
95 	{ "get_file_entry",
96 	  (PyCFunction) pyfsntfs_mft_metadata_file_get_file_entry,
97 	  METH_VARARGS | METH_KEYWORDS,
98 	  "get_file_entry(file_entry_index) -> Object\n"
99 	  "\n"
100 	  "Retrieves a specific file entry." },
101 
102 	/* Sentinel */
103 	{ NULL, NULL, 0, NULL }
104 };
105 
106 PyGetSetDef pyfsntfs_mft_metadata_file_object_get_set_definitions[] = {
107 
108 	{ "volume_name",
109 	  (getter) pyfsntfs_mft_metadata_file_get_volume_name,
110 	  (setter) 0,
111 	  "The volume name.",
112 	  NULL },
113 
114 	{ "number_of_file_entries",
115 	  (getter) pyfsntfs_mft_metadata_file_get_number_of_file_entries,
116 	  (setter) 0,
117 	  "The number of file entries.",
118 	  NULL },
119 
120 	{ "file_entries",
121 	  (getter) pyfsntfs_mft_metadata_file_get_file_entries,
122 	  (setter) 0,
123 	  "The file entries",
124 	  NULL },
125 
126 	/* Sentinel */
127 	{ NULL, NULL, NULL, NULL, NULL }
128 };
129 
130 PyTypeObject pyfsntfs_mft_metadata_file_type_object = {
131 	PyVarObject_HEAD_INIT( NULL, 0 )
132 
133 	/* tp_name */
134 	"pyfsntfs.mft_metadata_file",
135 	/* tp_basicsize */
136 	sizeof( pyfsntfs_mft_metadata_file_t ),
137 	/* tp_itemsize */
138 	0,
139 	/* tp_dealloc */
140 	(destructor) pyfsntfs_mft_metadata_file_free,
141 	/* tp_print */
142 	0,
143 	/* tp_getattr */
144 	0,
145 	/* tp_setattr */
146 	0,
147 	/* tp_compare */
148 	0,
149 	/* tp_repr */
150 	0,
151 	/* tp_as_number */
152 	0,
153 	/* tp_as_sequence */
154 	0,
155 	/* tp_as_mapping */
156 	0,
157 	/* tp_hash */
158 	0,
159 	/* tp_call */
160 	0,
161 	/* tp_str */
162 	0,
163 	/* tp_getattro */
164 	0,
165 	/* tp_setattro */
166 	0,
167 	/* tp_as_buffer */
168 	0,
169 	/* tp_flags */
170 	Py_TPFLAGS_DEFAULT,
171 	/* tp_doc */
172 	"pyfsntfs MFT metadata file object (wraps libfsntfs_mft_metadata_file_t)",
173 	/* tp_traverse */
174 	0,
175 	/* tp_clear */
176 	0,
177 	/* tp_richcompare */
178 	0,
179 	/* tp_weaklistoffset */
180 	0,
181 	/* tp_iter */
182 	0,
183 	/* tp_iternext */
184 	0,
185 	/* tp_methods */
186 	pyfsntfs_mft_metadata_file_object_methods,
187 	/* tp_members */
188 	0,
189 	/* tp_getset */
190 	pyfsntfs_mft_metadata_file_object_get_set_definitions,
191 	/* tp_base */
192 	0,
193 	/* tp_dict */
194 	0,
195 	/* tp_descr_get */
196 	0,
197 	/* tp_descr_set */
198 	0,
199 	/* tp_dictoffset */
200 	0,
201 	/* tp_init */
202 	(initproc) pyfsntfs_mft_metadata_file_init,
203 	/* tp_alloc */
204 	0,
205 	/* tp_new */
206 	0,
207 	/* tp_free */
208 	0,
209 	/* tp_is_gc */
210 	0,
211 	/* tp_bases */
212 	NULL,
213 	/* tp_mro */
214 	NULL,
215 	/* tp_cache */
216 	NULL,
217 	/* tp_subclasses */
218 	NULL,
219 	/* tp_weaklist */
220 	NULL,
221 	/* tp_del */
222 	0
223 };
224 
225 /* Initializes a MFT metadata file object
226  * Returns 0 if successful or -1 on error
227  */
pyfsntfs_mft_metadata_file_init(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file)228 int pyfsntfs_mft_metadata_file_init(
229      pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file )
230 {
231 	libcerror_error_t *error = NULL;
232 	static char *function    = "pyfsntfs_mft_metadata_file_init";
233 
234 	if( pyfsntfs_mft_metadata_file == NULL )
235 	{
236 		PyErr_Format(
237 		 PyExc_ValueError,
238 		 "%s: invalid MFT metadata file.",
239 		 function );
240 
241 		return( -1 );
242 	}
243 	/* Make sure libfsntfs MFT metadata file is set to NULL
244 	 */
245 	pyfsntfs_mft_metadata_file->mft_metadata_file = NULL;
246 	pyfsntfs_mft_metadata_file->file_io_handle    = NULL;
247 
248 	if( libfsntfs_mft_metadata_file_initialize(
249 	     &( pyfsntfs_mft_metadata_file->mft_metadata_file ),
250 	     &error ) != 1 )
251 	{
252 		pyfsntfs_error_raise(
253 		 error,
254 		 PyExc_MemoryError,
255 		 "%s: unable to initialize MFT metadata file.",
256 		 function );
257 
258 		libcerror_error_free(
259 		 &error );
260 
261 		return( -1 );
262 	}
263 	return( 0 );
264 }
265 
266 /* Frees a MFT metadata file object
267  */
pyfsntfs_mft_metadata_file_free(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file)268 void pyfsntfs_mft_metadata_file_free(
269       pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file )
270 {
271 	struct _typeobject *ob_type = NULL;
272 	libcerror_error_t *error    = NULL;
273 	static char *function       = "pyfsntfs_mft_metadata_file_free";
274 	int result                  = 0;
275 
276 	if( pyfsntfs_mft_metadata_file == NULL )
277 	{
278 		PyErr_Format(
279 		 PyExc_ValueError,
280 		 "%s: invalid MFT metadata file.",
281 		 function );
282 
283 		return;
284 	}
285 	ob_type = Py_TYPE(
286 	           pyfsntfs_mft_metadata_file );
287 
288 	if( ob_type == NULL )
289 	{
290 		PyErr_Format(
291 		 PyExc_ValueError,
292 		 "%s: missing ob_type.",
293 		 function );
294 
295 		return;
296 	}
297 	if( ob_type->tp_free == NULL )
298 	{
299 		PyErr_Format(
300 		 PyExc_ValueError,
301 		 "%s: invalid ob_type - missing tp_free.",
302 		 function );
303 
304 		return;
305 	}
306 	if( pyfsntfs_mft_metadata_file->mft_metadata_file != NULL )
307 	{
308 		Py_BEGIN_ALLOW_THREADS
309 
310 		result = libfsntfs_mft_metadata_file_free(
311 		          &( pyfsntfs_mft_metadata_file->mft_metadata_file ),
312 		          &error );
313 
314 		Py_END_ALLOW_THREADS
315 
316 		if( result != 1 )
317 		{
318 			pyfsntfs_error_raise(
319 			 error,
320 			 PyExc_MemoryError,
321 			 "%s: unable to free libfsntfs MFT metadata file.",
322 			 function );
323 
324 			libcerror_error_free(
325 			 &error );
326 		}
327 	}
328 	ob_type->tp_free(
329 	 (PyObject*) pyfsntfs_mft_metadata_file );
330 }
331 
332 /* Opens a MFT metadata file
333  * Returns a Python object if successful or NULL on error
334  */
pyfsntfs_mft_metadata_file_open(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments,PyObject * keywords)335 PyObject *pyfsntfs_mft_metadata_file_open(
336            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
337            PyObject *arguments,
338            PyObject *keywords )
339 {
340 	PyObject *string_object      = NULL;
341 	libcerror_error_t *error     = NULL;
342 	static char *function        = "pyfsntfs_mft_metadata_file_open";
343 	static char *keyword_list[]  = { "filename", "mode", NULL };
344 	const char *filename_narrow  = NULL;
345 	char *mode                   = NULL;
346 	int result                   = 0;
347 
348 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
349 	const wchar_t *filename_wide = NULL;
350 #else
351 	PyObject *utf8_string_object = NULL;
352 #endif
353 
354 	if( pyfsntfs_mft_metadata_file == NULL )
355 	{
356 		PyErr_Format(
357 		 PyExc_ValueError,
358 		 "%s: invalid MFT metadata file.",
359 		 function );
360 
361 		return( NULL );
362 	}
363 	/* Note that PyArg_ParseTupleAndKeywords with "s" will force Unicode strings to be converted to narrow character string.
364 	 * On Windows the narrow character strings contains an extended ASCII string with a codepage. Hence we get a conversion
365 	 * exception. This will also fail if the default encoding is not set correctly. We cannot use "u" here either since that
366 	 * does not allow us to pass non Unicode string objects and Python (at least 2.7) does not seems to automatically upcast them.
367 	 */
368 	if( PyArg_ParseTupleAndKeywords(
369 	     arguments,
370 	     keywords,
371 	     "O|s",
372 	     keyword_list,
373 	     &string_object,
374 	     &mode ) == 0 )
375 	{
376 		return( NULL );
377 	}
378 	if( ( mode != NULL )
379 	 && ( mode[ 0 ] != 'r' ) )
380 	{
381 		PyErr_Format(
382 		 PyExc_ValueError,
383 		 "%s: unsupported mode: %s.",
384 		 function,
385 		 mode );
386 
387 		return( NULL );
388 	}
389 	PyErr_Clear();
390 
391 	result = PyObject_IsInstance(
392 	          string_object,
393 	          (PyObject *) &PyUnicode_Type );
394 
395 	if( result == -1 )
396 	{
397 		pyfsntfs_error_fetch_and_raise(
398 	         PyExc_RuntimeError,
399 		 "%s: unable to determine if string object is of type unicode.",
400 		 function );
401 
402 		return( NULL );
403 	}
404 	else if( result != 0 )
405 	{
406 		PyErr_Clear();
407 
408 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
409 		filename_wide = (wchar_t *) PyUnicode_AsUnicode(
410 		                             string_object );
411 		Py_BEGIN_ALLOW_THREADS
412 
413 		result = libfsntfs_mft_metadata_file_open_wide(
414 		          pyfsntfs_mft_metadata_file->mft_metadata_file,
415 	                  filename_wide,
416 		          LIBFSNTFS_OPEN_READ,
417 		          &error );
418 
419 		Py_END_ALLOW_THREADS
420 #else
421 		utf8_string_object = PyUnicode_AsUTF8String(
422 		                      string_object );
423 
424 		if( utf8_string_object == NULL )
425 		{
426 			pyfsntfs_error_fetch_and_raise(
427 			 PyExc_RuntimeError,
428 			 "%s: unable to convert unicode string to UTF-8.",
429 			 function );
430 
431 			return( NULL );
432 		}
433 #if PY_MAJOR_VERSION >= 3
434 		filename_narrow = PyBytes_AsString(
435 				   utf8_string_object );
436 #else
437 		filename_narrow = PyString_AsString(
438 				   utf8_string_object );
439 #endif
440 		Py_BEGIN_ALLOW_THREADS
441 
442 		result = libfsntfs_mft_metadata_file_open(
443 		          pyfsntfs_mft_metadata_file->mft_metadata_file,
444 	                  filename_narrow,
445 		          LIBFSNTFS_OPEN_READ,
446 		          &error );
447 
448 		Py_END_ALLOW_THREADS
449 
450 		Py_DecRef(
451 		 utf8_string_object );
452 #endif
453 		if( result != 1 )
454 		{
455 			pyfsntfs_error_raise(
456 			 error,
457 			 PyExc_IOError,
458 			 "%s: unable to open MFT metadata file.",
459 			 function );
460 
461 			libcerror_error_free(
462 			 &error );
463 
464 			return( NULL );
465 		}
466 		Py_IncRef(
467 		 Py_None );
468 
469 		return( Py_None );
470 	}
471 	PyErr_Clear();
472 
473 #if PY_MAJOR_VERSION >= 3
474 	result = PyObject_IsInstance(
475 		  string_object,
476 		  (PyObject *) &PyBytes_Type );
477 #else
478 	result = PyObject_IsInstance(
479 		  string_object,
480 		  (PyObject *) &PyString_Type );
481 #endif
482 	if( result == -1 )
483 	{
484 		pyfsntfs_error_fetch_and_raise(
485 	         PyExc_RuntimeError,
486 		 "%s: unable to determine if string object is of type string.",
487 		 function );
488 
489 		return( NULL );
490 	}
491 	else if( result != 0 )
492 	{
493 		PyErr_Clear();
494 
495 #if PY_MAJOR_VERSION >= 3
496 		filename_narrow = PyBytes_AsString(
497 				   string_object );
498 #else
499 		filename_narrow = PyString_AsString(
500 				   string_object );
501 #endif
502 		Py_BEGIN_ALLOW_THREADS
503 
504 		result = libfsntfs_mft_metadata_file_open(
505 		          pyfsntfs_mft_metadata_file->mft_metadata_file,
506 	                  filename_narrow,
507 		          LIBFSNTFS_OPEN_READ,
508 		          &error );
509 
510 		Py_END_ALLOW_THREADS
511 
512 		if( result != 1 )
513 		{
514 			pyfsntfs_error_raise(
515 			 error,
516 			 PyExc_IOError,
517 			 "%s: unable to open MFT metadata file.",
518 			 function );
519 
520 			libcerror_error_free(
521 			 &error );
522 
523 			return( NULL );
524 		}
525 		Py_IncRef(
526 		 Py_None );
527 
528 		return( Py_None );
529 	}
530 	PyErr_Format(
531 	 PyExc_TypeError,
532 	 "%s: unsupported string object type.",
533 	 function );
534 
535 	return( NULL );
536 }
537 
538 /* Opens a MFT metadata file using a file-like object
539  * Returns a Python object if successful or NULL on error
540  */
pyfsntfs_mft_metadata_file_open_file_object(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments,PyObject * keywords)541 PyObject *pyfsntfs_mft_metadata_file_open_file_object(
542            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
543            PyObject *arguments,
544            PyObject *keywords )
545 {
546 	PyObject *file_object       = NULL;
547 	libcerror_error_t *error    = NULL;
548 	char *mode                  = NULL;
549 	static char *keyword_list[] = { "file_object", "mode", NULL };
550 	static char *function       = "pyfsntfs_mft_metadata_file_open_file_object";
551 	int result                  = 0;
552 
553 	if( pyfsntfs_mft_metadata_file == NULL )
554 	{
555 		PyErr_Format(
556 		 PyExc_ValueError,
557 		 "%s: invalid MFT metadata file.",
558 		 function );
559 
560 		return( NULL );
561 	}
562 	if( PyArg_ParseTupleAndKeywords(
563 	     arguments,
564 	     keywords,
565 	     "O|s",
566 	     keyword_list,
567 	     &file_object,
568 	     &mode ) == 0 )
569 	{
570 		return( NULL );
571 	}
572 	if( ( mode != NULL )
573 	 && ( mode[ 0 ] != 'r' ) )
574 	{
575 		PyErr_Format(
576 		 PyExc_ValueError,
577 		 "%s: unsupported mode: %s.",
578 		 function,
579 		 mode );
580 
581 		return( NULL );
582 	}
583 	if( pyfsntfs_file_object_initialize(
584 	     &( pyfsntfs_mft_metadata_file->file_io_handle ),
585 	     file_object,
586 	     &error ) != 1 )
587 	{
588 		pyfsntfs_error_raise(
589 		 error,
590 		 PyExc_MemoryError,
591 		 "%s: unable to initialize file IO handle.",
592 		 function );
593 
594 		libcerror_error_free(
595 		 &error );
596 
597 		goto on_error;
598 	}
599 	Py_BEGIN_ALLOW_THREADS
600 
601 	result = libfsntfs_mft_metadata_file_open_file_io_handle(
602 	          pyfsntfs_mft_metadata_file->mft_metadata_file,
603 	          pyfsntfs_mft_metadata_file->file_io_handle,
604 	          LIBFSNTFS_OPEN_READ,
605 	          &error );
606 
607 	Py_END_ALLOW_THREADS
608 
609 	if( result != 1 )
610 	{
611 		pyfsntfs_error_raise(
612 		 error,
613 		 PyExc_IOError,
614 		 "%s: unable to open MFT metadata file.",
615 		 function );
616 
617 		libcerror_error_free(
618 		 &error );
619 
620 		goto on_error;
621 	}
622 	Py_IncRef(
623 	 Py_None );
624 
625 	return( Py_None );
626 
627 on_error:
628 	if( pyfsntfs_mft_metadata_file->file_io_handle != NULL )
629 	{
630 		libbfio_handle_free(
631 		 &( pyfsntfs_mft_metadata_file->file_io_handle ),
632 		 NULL );
633 	}
634 	return( NULL );
635 }
636 
637 /* Closes a MFT metadata file
638  * Returns a Python object if successful or NULL on error
639  */
pyfsntfs_mft_metadata_file_close(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments PYFSNTFS_ATTRIBUTE_UNUSED)640 PyObject *pyfsntfs_mft_metadata_file_close(
641            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
642            PyObject *arguments PYFSNTFS_ATTRIBUTE_UNUSED )
643 {
644 	libcerror_error_t *error = NULL;
645 	static char *function    = "pyfsntfs_mft_metadata_file_close";
646 	int result               = 0;
647 
648 	PYFSNTFS_UNREFERENCED_PARAMETER( arguments )
649 
650 	if( pyfsntfs_mft_metadata_file == NULL )
651 	{
652 		PyErr_Format(
653 		 PyExc_ValueError,
654 		 "%s: invalid MFT metadata file.",
655 		 function );
656 
657 		return( NULL );
658 	}
659 	Py_BEGIN_ALLOW_THREADS
660 
661 	result = libfsntfs_mft_metadata_file_close(
662 	          pyfsntfs_mft_metadata_file->mft_metadata_file,
663 	          &error );
664 
665 	Py_END_ALLOW_THREADS
666 
667 	if( result != 0 )
668 	{
669 		pyfsntfs_error_raise(
670 		 error,
671 		 PyExc_IOError,
672 		 "%s: unable to close MFT metadata file.",
673 		 function );
674 
675 		libcerror_error_free(
676 		 &error );
677 
678 		return( NULL );
679 	}
680 	if( pyfsntfs_mft_metadata_file->file_io_handle != NULL )
681 	{
682 		Py_BEGIN_ALLOW_THREADS
683 
684 		result = libbfio_handle_free(
685 		          &( pyfsntfs_mft_metadata_file->file_io_handle ),
686 		          &error );
687 
688 		Py_END_ALLOW_THREADS
689 
690 		if( result != 1 )
691 		{
692 			pyfsntfs_error_raise(
693 			 error,
694 			 PyExc_IOError,
695 			 "%s: unable to free libbfio file IO handle.",
696 			 function );
697 
698 			libcerror_error_free(
699 			 &error );
700 
701 			return( NULL );
702 		}
703 	}
704 	Py_IncRef(
705 	 Py_None );
706 
707 	return( Py_None );
708 }
709 
710 /* Retrieves the volume name
711  * Returns a Python object if successful or NULL on error
712  */
pyfsntfs_mft_metadata_file_get_volume_name(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments PYFSNTFS_ATTRIBUTE_UNUSED)713 PyObject *pyfsntfs_mft_metadata_file_get_volume_name(
714            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
715            PyObject *arguments PYFSNTFS_ATTRIBUTE_UNUSED )
716 {
717 	libcerror_error_t *error = NULL;
718 	PyObject *string_object  = NULL;
719 	const char *errors       = NULL;
720 	uint8_t *volume_name     = NULL;
721 	static char *function    = "pyfsntfs_mft_metadata_file_get_volume_name";
722 	size_t volume_name_size  = 0;
723 	int result               = 0;
724 
725 	PYFSNTFS_UNREFERENCED_PARAMETER( arguments )
726 
727 	if( pyfsntfs_mft_metadata_file == NULL )
728 	{
729 		PyErr_Format(
730 		 PyExc_TypeError,
731 		 "%s: invalid MFT metadata file.",
732 		 function );
733 
734 		return( NULL );
735 	}
736 	Py_BEGIN_ALLOW_THREADS
737 
738 	result = libfsntfs_mft_metadata_file_get_utf8_volume_name_size(
739 	          pyfsntfs_mft_metadata_file->mft_metadata_file,
740 	          &volume_name_size,
741 	          &error );
742 
743 	Py_END_ALLOW_THREADS
744 
745 	if( result == -1 )
746 	{
747 		pyfsntfs_error_raise(
748 		 error,
749 		 PyExc_IOError,
750 		 "%s: unable to retrieve volume name size.",
751 		 function );
752 
753 		libcerror_error_free(
754 		 &error );
755 
756 		goto on_error;
757 	}
758 	else if( ( result == 0 )
759 	      || ( volume_name_size == 0 ) )
760 	{
761 		Py_IncRef(
762 		 Py_None );
763 
764 		return( Py_None );
765 	}
766 	volume_name = (uint8_t *) PyMem_Malloc(
767 	                           sizeof( uint8_t ) * volume_name_size );
768 
769 	if( volume_name == NULL )
770 	{
771 		PyErr_Format(
772 		 PyExc_IOError,
773 		 "%s: unable to create volume name.",
774 		 function );
775 
776 		goto on_error;
777 	}
778 	Py_BEGIN_ALLOW_THREADS
779 
780 	result = libfsntfs_mft_metadata_file_get_utf8_volume_name(
781 		  pyfsntfs_mft_metadata_file->mft_metadata_file,
782 		  volume_name,
783 		  volume_name_size,
784 		  &error );
785 
786 	Py_END_ALLOW_THREADS
787 
788 	if( result != 1 )
789 	{
790 		pyfsntfs_error_raise(
791 		 error,
792 		 PyExc_IOError,
793 		 "%s: unable to retrieve volume name.",
794 		 function );
795 
796 		libcerror_error_free(
797 		 &error );
798 
799 		goto on_error;
800 	}
801 	/* Pass the string length to PyUnicode_DecodeUTF8
802 	 * otherwise it makes the end of string character is part
803 	 * of the string
804 	 */
805 	string_object = PyUnicode_DecodeUTF8(
806 			 (char *) volume_name,
807 			 (Py_ssize_t) volume_name_size - 1,
808 			 errors );
809 
810 	PyMem_Free(
811 	 volume_name );
812 
813 	return( string_object );
814 
815 on_error:
816 	if( volume_name != NULL )
817 	{
818 		PyMem_Free(
819 		 volume_name );
820 	}
821 	return( NULL );
822 }
823 
824 /* Retrieves the number of file entries
825  * Returns a Python object if successful or NULL on error
826  */
pyfsntfs_mft_metadata_file_get_number_of_file_entries(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments PYFSNTFS_ATTRIBUTE_UNUSED)827 PyObject *pyfsntfs_mft_metadata_file_get_number_of_file_entries(
828            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
829            PyObject *arguments PYFSNTFS_ATTRIBUTE_UNUSED )
830 {
831 	libcerror_error_t *error        = NULL;
832 	PyObject *integer_object        = NULL;
833 	static char *function           = "pyfsntfs_mft_metadata_file_get_number_of_file_entries";
834 	uint64_t number_of_file_entries = 0;
835 	int result                      = 0;
836 
837 	PYFSNTFS_UNREFERENCED_PARAMETER( arguments )
838 
839 	if( pyfsntfs_mft_metadata_file == NULL )
840 	{
841 		PyErr_Format(
842 		 PyExc_TypeError,
843 		 "%s: invalid MFT metadata file.",
844 		 function );
845 
846 		return( NULL );
847 	}
848 	Py_BEGIN_ALLOW_THREADS
849 
850 	result = libfsntfs_mft_metadata_file_get_number_of_file_entries(
851 	          pyfsntfs_mft_metadata_file->mft_metadata_file,
852 	          &number_of_file_entries,
853 	          &error );
854 
855 	Py_END_ALLOW_THREADS
856 
857 	if( result != 1 )
858 	{
859 		pyfsntfs_error_raise(
860 		 error,
861 		 PyExc_IOError,
862 		 "%s: unable to retrieve number of file entries.",
863 		 function );
864 
865 		libcerror_error_free(
866 		 &error );
867 
868 		return( NULL );
869 	}
870 	integer_object = pyfsntfs_integer_unsigned_new_from_64bit(
871 	                  number_of_file_entries );
872 
873 	return( integer_object );
874 }
875 
876 /* Retrieves a specific file entry by index
877  * Returns a Python object if successful or NULL on error
878  */
pyfsntfs_mft_metadata_file_get_file_entry_by_index(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,uint64_t file_entry_index)879 PyObject *pyfsntfs_mft_metadata_file_get_file_entry_by_index(
880            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
881            uint64_t file_entry_index )
882 {
883 	libcerror_error_t *error           = NULL;
884 	libfsntfs_file_entry_t *file_entry = NULL;
885 	PyObject *file_entry_object        = NULL;
886 	static char *function              = "pyfsntfs_mft_metadata_file_get_file_entry_by_index";
887 	int result                         = 0;
888 
889 	if( pyfsntfs_mft_metadata_file == NULL )
890 	{
891 		PyErr_Format(
892 		 PyExc_TypeError,
893 		 "%s: invalid MFT metadata file.",
894 		 function );
895 
896 		return( NULL );
897 	}
898 	Py_BEGIN_ALLOW_THREADS
899 
900 	result = libfsntfs_mft_metadata_file_get_file_entry_by_index(
901 	          pyfsntfs_mft_metadata_file->mft_metadata_file,
902 	          file_entry_index,
903 	          &file_entry,
904 	          &error );
905 
906 	Py_END_ALLOW_THREADS
907 
908 	if( result != 1 )
909 	{
910 		pyfsntfs_error_raise(
911 		 error,
912 		 PyExc_IOError,
913 		 "%s: unable to retrieve file entry: %" PRIu64 ".",
914 		 function,
915 		 file_entry_index );
916 
917 		libcerror_error_free(
918 		 &error );
919 
920 		goto on_error;
921 	}
922 	file_entry_object = pyfsntfs_file_entry_new(
923 	                     file_entry,
924 	                     (PyObject *) pyfsntfs_mft_metadata_file );
925 
926 	if( file_entry_object == NULL )
927 	{
928 		PyErr_Format(
929 		 PyExc_MemoryError,
930 		 "%s: unable to create file entry object.",
931 		 function );
932 
933 		goto on_error;
934 	}
935 	return( file_entry_object );
936 
937 on_error:
938 	if( file_entry != NULL )
939 	{
940 		libfsntfs_file_entry_free(
941 		 &file_entry,
942 		 NULL );
943 	}
944 	return( NULL );
945 }
946 
947 /* Retrieves a specific file entry
948  * Returns a Python object if successful or NULL on error
949  */
pyfsntfs_mft_metadata_file_get_file_entry(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments,PyObject * keywords)950 PyObject *pyfsntfs_mft_metadata_file_get_file_entry(
951            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
952            PyObject *arguments,
953            PyObject *keywords )
954 {
955 	PyObject *file_entry_object = NULL;
956 	static char *keyword_list[] = { "file_entry_index", NULL };
957 	int file_entry_index        = 0;
958 
959 	if( PyArg_ParseTupleAndKeywords(
960 	     arguments,
961 	     keywords,
962 	     "i",
963 	     keyword_list,
964 	     &file_entry_index ) == 0 )
965 	{
966 		return( NULL );
967 	}
968 	file_entry_object = pyfsntfs_mft_metadata_file_get_file_entry_by_index(
969 	                     pyfsntfs_mft_metadata_file,
970 	                     file_entry_index );
971 
972 	return( file_entry_object );
973 }
974 
975 /* Retrieves a file entries sequence and iterator object for the MFT metadata file entries
976  * Returns a Python object if successful or NULL on error
977  */
pyfsntfs_mft_metadata_file_get_file_entries(pyfsntfs_mft_metadata_file_t * pyfsntfs_mft_metadata_file,PyObject * arguments PYFSNTFS_ATTRIBUTE_UNUSED)978 PyObject *pyfsntfs_mft_metadata_file_get_file_entries(
979            pyfsntfs_mft_metadata_file_t *pyfsntfs_mft_metadata_file,
980            PyObject *arguments PYFSNTFS_ATTRIBUTE_UNUSED )
981 {
982 	libcerror_error_t *error                   = NULL;
983 	PyObject *mft_metadata_file_entries_object = NULL;
984 	static char *function                      = "pyfsntfs_mft_metadata_file_get_file_entries";
985 	uint64_t number_of_file_entries            = 0;
986 	int result                                 = 0;
987 
988 	PYFSNTFS_UNREFERENCED_PARAMETER( arguments )
989 
990 	if( pyfsntfs_mft_metadata_file == NULL )
991 	{
992 		PyErr_Format(
993 		 PyExc_TypeError,
994 		 "%s: invalid MFT metadata file.",
995 		 function );
996 
997 		return( NULL );
998 	}
999 	Py_BEGIN_ALLOW_THREADS
1000 
1001 	result = libfsntfs_mft_metadata_file_get_number_of_file_entries(
1002 	          pyfsntfs_mft_metadata_file->mft_metadata_file,
1003 	          &number_of_file_entries,
1004 	          &error );
1005 
1006 	Py_END_ALLOW_THREADS
1007 
1008 	if( result != 1 )
1009 	{
1010 		pyfsntfs_error_raise(
1011 		 error,
1012 		 PyExc_IOError,
1013 		 "%s: unable to retrieve number of file entries.",
1014 		 function );
1015 
1016 		libcerror_error_free(
1017 		 &error );
1018 
1019 		return( NULL );
1020 	}
1021 	mft_metadata_file_entries_object = pyfsntfs_mft_metadata_file_entries_new(
1022 	                                    pyfsntfs_mft_metadata_file,
1023 	                                    &pyfsntfs_mft_metadata_file_get_file_entry_by_index,
1024 	                                    number_of_file_entries );
1025 
1026 	if( mft_metadata_file_entries_object == NULL )
1027 	{
1028 		PyErr_Format(
1029 		 PyExc_MemoryError,
1030 		 "%s: unable to create MFT metadata file entries object.",
1031 		 function );
1032 
1033 		return( NULL );
1034 	}
1035 	return( mft_metadata_file_entries_object );
1036 }
1037 
1038