1 /*
2  * Master File Table (MFT) entry functions
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 <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26 
27 #include "libfsntfs_debug.h"
28 #include "libfsntfs_definitions.h"
29 #include "libfsntfs_directory_entry.h"
30 #include "libfsntfs_fixup_values.h"
31 #include "libfsntfs_io_handle.h"
32 #include "libfsntfs_libbfio.h"
33 #include "libfsntfs_libcdata.h"
34 #include "libfsntfs_libcerror.h"
35 #include "libfsntfs_libcnotify.h"
36 #include "libfsntfs_libfcache.h"
37 #include "libfsntfs_libfdata.h"
38 #include "libfsntfs_libuna.h"
39 #include "libfsntfs_mft_attribute.h"
40 #include "libfsntfs_mft_attribute_list.h"
41 #include "libfsntfs_mft_attribute_list_entry.h"
42 #include "libfsntfs_mft_entry.h"
43 #include "libfsntfs_mft_entry_header.h"
44 #include "libfsntfs_standard_information_values.h"
45 #include "libfsntfs_types.h"
46 #include "libfsntfs_unused.h"
47 
48 #include "fsntfs_mft_entry.h"
49 
50 const char fsntfs_mft_entry_signature[ 4 ] = { 'F', 'I', 'L', 'E' };
51 
52 /* Checks if a buffer containing the MFT entry is filled with 0-byte values (empty-block)
53  * Returns 1 if empty, 0 if not or -1 on error
54  */
libfsntfs_mft_entry_check_for_empty_block(const uint8_t * data,size_t data_size,libcerror_error_t ** error)55 int libfsntfs_mft_entry_check_for_empty_block(
56      const uint8_t *data,
57      size_t data_size,
58      libcerror_error_t **error )
59 {
60 	libfsntfs_aligned_t *aligned_data_index = NULL;
61 	libfsntfs_aligned_t *aligned_data_start = NULL;
62 	uint8_t *data_index                     = NULL;
63 	uint8_t *data_start                     = NULL;
64 	static char *function                   = "libfsntfs_mft_entry_check_for_empty_block";
65 
66 	if( data == NULL )
67 	{
68 		libcerror_error_set(
69 		 error,
70 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
71 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
72 		 "%s: invalid data.",
73 		 function );
74 
75 		return( -1 );
76 	}
77 	if( data_size > (size_t) SSIZE_MAX )
78 	{
79 		libcerror_error_set(
80 		 error,
81 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
82 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
83 		 "%s: invalid data size value exceeds maximum.",
84 		 function );
85 
86 		return( -1 );
87 	}
88 	data_start = (uint8_t *) data;
89 	data_index = (uint8_t *) data + 1;
90 	data_size -= 1;
91 
92 	/* Only optimize for data larger than the alignment
93 	 */
94 	if( data_size > ( 2 * sizeof( libfsntfs_aligned_t ) ) )
95 	{
96 		/* Align the data start
97 		 */
98 		while( ( (intptr_t) data_start % sizeof( libfsntfs_aligned_t ) ) != 0 )
99 		{
100 			if( *data_start != *data_index )
101 			{
102 				return( 0 );
103 			}
104 			data_start += 1;
105 			data_index += 1;
106 			data_size  -= 1;
107 		}
108 		/* Align the data index
109 		 */
110 		while( ( (intptr_t) data_index % sizeof( libfsntfs_aligned_t ) ) != 0 )
111 		{
112 			if( *data_start != *data_index )
113 			{
114 				return( 0 );
115 			}
116 			data_index += 1;
117 			data_size  -= 1;
118 		}
119 		aligned_data_start = (libfsntfs_aligned_t *) data_start;
120 		aligned_data_index = (libfsntfs_aligned_t *) data_index;
121 
122 		while( data_size > sizeof( libfsntfs_aligned_t ) )
123 		{
124 			if( *aligned_data_start != *aligned_data_index )
125 			{
126 				return( 0 );
127 			}
128 			aligned_data_index += 1;
129 			data_size          -= sizeof( libfsntfs_aligned_t );
130 		}
131 		data_index = (uint8_t *) aligned_data_index;
132 	}
133 	while( data_size != 0 )
134 	{
135 		if( *data_start != *data_index )
136 		{
137 			return( 0 );
138 		}
139 		data_index += 1;
140 		data_size  -= 1;
141 	}
142 	return( 1 );
143 }
144 
145 /* Creates a MFT entry
146  * Make sure the value mft_entry is referencing, is set to NULL
147  * Returns 1 if successful or -1 on error
148  */
libfsntfs_mft_entry_initialize(libfsntfs_mft_entry_t ** mft_entry,libcerror_error_t ** error)149 int libfsntfs_mft_entry_initialize(
150      libfsntfs_mft_entry_t **mft_entry,
151      libcerror_error_t **error )
152 {
153 	static char *function = "libfsntfs_mft_entry_initialize";
154 
155 	if( mft_entry == NULL )
156 	{
157 		libcerror_error_set(
158 		 error,
159 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
160 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
161 		 "%s: invalid MFT entry.",
162 		 function );
163 
164 		return( -1 );
165 	}
166 	if( *mft_entry != NULL )
167 	{
168 		libcerror_error_set(
169 		 error,
170 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
171 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
172 		 "%s: invalid MFT entry value already set.",
173 		 function );
174 
175 		return( -1 );
176 	}
177 	*mft_entry = memory_allocate_structure(
178 	              libfsntfs_mft_entry_t );
179 
180 	if( *mft_entry == NULL )
181 	{
182 		libcerror_error_set(
183 		 error,
184 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
185 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
186 		 "%s: unable to create MFT entry.",
187 		 function );
188 
189 		goto on_error;
190 	}
191 	if( memory_set(
192 	     *mft_entry,
193 	     0,
194 	     sizeof( libfsntfs_mft_entry_t ) ) == NULL )
195 	{
196 		libcerror_error_set(
197 		 error,
198 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
199 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
200 		 "%s: unable to clear MFT entry.",
201 		 function );
202 
203 		memory_free(
204 		 *mft_entry );
205 
206 		*mft_entry = NULL;
207 
208 		return( -1 );
209 	}
210 	if( libcdata_array_initialize(
211 	     &( ( *mft_entry )->attributes_array ),
212 	     0,
213 	     error ) != 1 )
214 	{
215 		libcerror_error_set(
216 		 error,
217 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
218 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
219 		 "%s: unable to create attributes array.",
220 		 function );
221 
222 		goto on_error;
223 	}
224 	if( libcdata_array_initialize(
225 	     &( ( *mft_entry )->alternate_data_attributes_array ),
226 	     0,
227 	     error ) != 1 )
228 	{
229 		libcerror_error_set(
230 		 error,
231 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
232 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
233 		 "%s: unable to create alternate data attributes array.",
234 		 function );
235 
236 		goto on_error;
237 	}
238 	( *mft_entry )->file_name_attribute_index            = -1;
239 	( *mft_entry )->reparse_point_attribute_index        = -1;
240 	( *mft_entry )->security_descriptor_attribute_index  = -1;
241 	( *mft_entry )->standard_information_attribute_index = -1;
242 	( *mft_entry )->volume_information_attribute_index   = -1;
243 	( *mft_entry )->volume_name_attribute_index          = -1;
244 
245 	return( 1 );
246 
247 on_error:
248 	if( *mft_entry != NULL )
249 	{
250 		if( ( *mft_entry )->alternate_data_attributes_array != NULL )
251 		{
252 			libcdata_array_free(
253 			 &( ( *mft_entry )->alternate_data_attributes_array ),
254 			 NULL,
255 			 NULL );
256 		}
257 		if( ( *mft_entry )->attributes_array != NULL )
258 		{
259 			libcdata_array_free(
260 			 &( ( *mft_entry )->attributes_array ),
261 			 NULL,
262 			 NULL );
263 		}
264 		memory_free(
265 		 *mft_entry );
266 
267 		*mft_entry = NULL;
268 	}
269 	return( -1 );
270 }
271 
272 /* Frees a MFT entry
273  * Returns 1 if successful or -1 on error
274  */
libfsntfs_mft_entry_free(libfsntfs_mft_entry_t ** mft_entry,libcerror_error_t ** error)275 int libfsntfs_mft_entry_free(
276      libfsntfs_mft_entry_t **mft_entry,
277      libcerror_error_t **error )
278 {
279 	static char *function = "libfsntfs_mft_entry_free";
280 	int result            = 1;
281 
282 	if( mft_entry == NULL )
283 	{
284 		libcerror_error_set(
285 		 error,
286 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
287 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
288 		 "%s: invalid MFT entry.",
289 		 function );
290 
291 		return( -1 );
292 	}
293 	if( *mft_entry != NULL )
294 	{
295 		if( ( *mft_entry )->header != NULL )
296 		{
297 			if( libfsntfs_mft_entry_header_free(
298 			     &( ( *mft_entry )->header ),
299 			     error ) != 1 )
300 			{
301 				libcerror_error_set(
302 				 error,
303 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
304 				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
305 				 "%s: unable to free MFT entry header.",
306 				 function );
307 
308 				result = -1;
309 			}
310 		}
311 		if( ( *mft_entry )->data != NULL )
312 		{
313 			memory_free(
314 			 ( *mft_entry )->data );
315 		}
316 		/* The specific attribute references point to attributes in the array
317 		 * and are freed by freeing the array and its values
318 		 */
319 		if( libcdata_array_free(
320 		     &( ( *mft_entry )->attributes_array ),
321 		     (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_free,
322 		     error ) != 1 )
323 		{
324 			libcerror_error_set(
325 			 error,
326 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
327 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
328 			 "%s: unable to free attributes array.",
329 			 function );
330 
331 			result = -1;
332 		}
333 		if( ( *mft_entry )->attribute_list != NULL )
334 		{
335 			if( libfsntfs_mft_attribute_list_free(
336 			     &( ( *mft_entry )->attribute_list ),
337 			     error ) != 1 )
338 			{
339 				libcerror_error_set(
340 				 error,
341 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
342 				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
343 				 "%s: unable to free attribute list.",
344 				 function );
345 
346 				result = -1;
347 			}
348 		}
349 		/* The alternate_data_attributes_array only contains references that are managed
350 		 * by the attributes_array
351 		 */
352 		if( libcdata_array_free(
353 		     &( ( *mft_entry )->alternate_data_attributes_array ),
354 		     NULL,
355 		     error ) != 1 )
356 		{
357 			libcerror_error_set(
358 			 error,
359 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
360 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
361 			 "%s: unable to free alternate data attributes array.",
362 			 function );
363 
364 			result = -1;
365 		}
366 		memory_free(
367 		 *mft_entry );
368 
369 		*mft_entry = NULL;
370 	}
371 	return( result );
372 }
373 
374 /* Reads the MFT entry
375  * Returns 1 if successful, 0 if empty or marked as bad, or -1 on error
376  */
libfsntfs_mft_entry_read_data(libfsntfs_mft_entry_t * mft_entry,uint8_t * data,size_t data_size,uint32_t mft_entry_index,libcerror_error_t ** error)377 int libfsntfs_mft_entry_read_data(
378      libfsntfs_mft_entry_t *mft_entry,
379      uint8_t *data,
380      size_t data_size,
381      uint32_t mft_entry_index,
382      libcerror_error_t **error )
383 {
384 	static char *function           = "libfsntfs_mft_entry_read_data";
385 	size_t data_offset              = 0;
386 	size_t unknown_data_size        = 0;
387 	uint16_t attributes_offset      = 0;
388 	uint16_t fixup_values_offset    = 0;
389 	uint16_t number_of_fixup_values = 0;
390 	int result                      = 0;
391 
392 #if defined( HAVE_DEBUG_OUTPUT )
393 	uint16_t total_entry_size       = 0;
394 #endif
395 
396 	if( mft_entry == NULL )
397 	{
398 		libcerror_error_set(
399 		 error,
400 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
401 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
402 		 "%s: invalid MFT entry.",
403 		 function );
404 
405 		return( -1 );
406 	}
407 	if( mft_entry->header != NULL )
408 	{
409 		libcerror_error_set(
410 		 error,
411 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
412 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
413 		 "%s: invalid MFT entry - header value already set.",
414 		 function );
415 
416 		return( -1 );
417 	}
418 	if( data == NULL )
419 	{
420 		libcerror_error_set(
421 		 error,
422 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
423 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
424 		 "%s: invalid data.",
425 		 function );
426 
427 		return( -1 );
428 	}
429 	if( data_size > (size_t) SSIZE_MAX )
430 	{
431 		libcerror_error_set(
432 		 error,
433 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
434 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
435 		 "%s: invalid data size value exceeds maximum.",
436 		 function );
437 
438 		return( -1 );
439 	}
440 	result = libfsntfs_mft_entry_check_for_empty_block(
441 	          data,
442 	          data_size,
443 	          error );
444 
445 	if( result == -1 )
446 	{
447 		libcerror_error_set(
448 		 error,
449 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
450 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
451 		 "%s: unable to determine if MFT entry is empty.",
452 		 function );
453 
454 		goto on_error;
455 	}
456 	else if( result != 0 )
457 	{
458 #if defined( HAVE_DEBUG_OUTPUT )
459 		if( libcnotify_verbose != 0 )
460 		{
461 			libcnotify_printf(
462 			 "%s: MFT entry: %" PRIu32 " is empty.\n",
463 			 function,
464 			 mft_entry_index );
465 		}
466 #endif
467 		mft_entry->is_empty = 1;
468 
469 		return( 0 );
470 	}
471 	if( libfsntfs_mft_entry_header_initialize(
472 	     &( mft_entry->header ),
473 	     error ) != 1 )
474 	{
475 		libcerror_error_set(
476 		 error,
477 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
478 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
479 		 "%s: unable to create MFT entry header.",
480 		 function );
481 
482 		goto on_error;
483 	}
484 	result = libfsntfs_mft_entry_header_read_data(
485 	          mft_entry->header,
486 	          data,
487 	          data_size,
488 	          error );
489 
490 	if( result == -1 )
491 	{
492 		libcerror_error_set(
493 		 error,
494 		 LIBCERROR_ERROR_DOMAIN_IO,
495 		 LIBCERROR_IO_ERROR_READ_FAILED,
496 		 "%s: unable to read MFT entry header.",
497 		 function );
498 
499 		goto on_error;
500 	}
501 	else if( result == 0 )
502 	{
503 		/* Note that an empty MFT data can contain arbitrary data
504 		 */
505 		mft_entry->is_empty = 1;
506 
507 		return( 0 );
508 	}
509 #if defined( HAVE_DEBUG_OUTPUT )
510 	if( libcnotify_verbose != 0 )
511 	{
512 		if( libfsntfs_mft_entry_header_get_total_entry_size(
513 		     mft_entry->header,
514 		     &total_entry_size,
515 		     error ) != 1 )
516 		{
517 			libcerror_error_set(
518 			 error,
519 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
520 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
521 			 "%s: unable to retrieve total entry size.",
522 			 function );
523 
524 			goto on_error;
525 		}
526 		if( data_size != (size_t) total_entry_size )
527 		{
528 			libcnotify_printf(
529 			 "%s: mismatch in total MFT entry size (calculated: %" PRIzd ", stored: %" PRIu16 ").\n",
530 			 function,
531 			 data_size,
532 			 total_entry_size );
533 		}
534 	}
535 #endif
536 	if( libfsntfs_mft_entry_header_get_attributes_offset(
537 	     mft_entry->header,
538 	     &attributes_offset,
539 	     error ) != 1 )
540 	{
541 		libcerror_error_set(
542 		 error,
543 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
544 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
545 		 "%s: unable to retrieve attributes offset.",
546 		 function );
547 
548 		goto on_error;
549 	}
550 	if( attributes_offset >= data_size )
551 	{
552 		libcerror_error_set(
553 		 error,
554 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
555 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
556 		 "%s: invalid attributes offset value out of bounds.",
557 		 function );
558 
559 		goto on_error;
560 	}
561 	if( libfsntfs_mft_entry_header_get_fixup_values_offset(
562 	     mft_entry->header,
563 	     &fixup_values_offset,
564 	     error ) != 1 )
565 	{
566 		libcerror_error_set(
567 		 error,
568 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
569 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
570 		 "%s: unable to retrieve fix-up values offset.",
571 		 function );
572 
573 		goto on_error;
574 	}
575 	if( fixup_values_offset > attributes_offset )
576 	{
577 		libcerror_error_set(
578 		 error,
579 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
580 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
581 		 "%s: fix-up values offset exceeds attributes offset.",
582 		 function );
583 
584 		goto on_error;
585 	}
586 	if( fixup_values_offset > 42 )
587 	{
588 		data_offset = sizeof( fsntfs_mft_entry_header_t );
589 	}
590 	else
591 	{
592 		/* In NTFS 1.2 the fix-up values offset can point to wfixupPattern
593 		 */
594 		data_offset = 42;
595 	}
596 	if( data_offset < fixup_values_offset )
597 	{
598 		unknown_data_size = (size_t) fixup_values_offset - data_offset;
599 
600 #if defined( HAVE_DEBUG_OUTPUT )
601 		if( libcnotify_verbose != 0 )
602 		{
603 			libcnotify_printf(
604 			 "%s: unknown data:\n",
605 			 function );
606 			libcnotify_print_data(
607 			 &( data[ data_offset ] ),
608 			 unknown_data_size,
609 			 0 );
610 		}
611 #endif
612 		data_offset += unknown_data_size;
613 	}
614 	if( libfsntfs_mft_entry_header_get_number_of_fixup_values(
615 	     mft_entry->header,
616 	     &number_of_fixup_values,
617 	     error ) != 1 )
618 	{
619 		libcerror_error_set(
620 		 error,
621 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
622 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
623 		 "%s: unable to retrieve number of fix-up values.",
624 		 function );
625 
626 		goto on_error;
627 	}
628 	if( number_of_fixup_values > 0 )
629 	{
630 		if( libfsntfs_fixup_values_apply(
631 		     data,
632 		     data_size,
633 		     fixup_values_offset,
634 		     number_of_fixup_values,
635 		     error ) != 1 )
636 		{
637 			libcerror_error_set(
638 			 error,
639 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
640 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
641 			 "%s: unable to apply fix-up values.",
642 			 function );
643 
644 			goto on_error;
645 		}
646 		data_offset += 2 + ( (size_t) number_of_fixup_values * 2 );
647 	}
648 #if defined( HAVE_DEBUG_OUTPUT )
649 	if( libcnotify_verbose != 0 )
650 	{
651 		if( data_offset < attributes_offset )
652 		{
653 			libcnotify_printf(
654 			 "%s: unknown data:\n",
655 			 function );
656 			libcnotify_print_data(
657 			 &( data[ data_offset ] ),
658 			 (size_t) attributes_offset - data_offset,
659 			 0 );
660 		}
661 	}
662 #endif
663 	mft_entry->is_empty = 0;
664 
665 	mft_entry->index = mft_entry->header->index;
666 
667 	if( mft_entry->index != mft_entry_index )
668 	{
669 		mft_entry->index = mft_entry_index;
670 	}
671 	mft_entry->file_reference = ( (uint64_t) mft_entry->header->sequence << 48 ) | mft_entry->index;
672 
673 	return( 1 );
674 
675 on_error:
676 	if( mft_entry->header != NULL )
677 	{
678 		libfsntfs_mft_entry_header_free(
679 		 &( mft_entry->header ),
680 		 NULL );
681 	}
682 	return( -1 );
683 }
684 
685 /* Reads the MFT entry
686  * Returns 1 if successful or -1 on error
687  */
libfsntfs_mft_entry_read_file_io_handle(libfsntfs_mft_entry_t * mft_entry,libbfio_handle_t * file_io_handle,off64_t file_offset,uint32_t mft_entry_size,uint32_t mft_entry_index,libcerror_error_t ** error)688 int libfsntfs_mft_entry_read_file_io_handle(
689      libfsntfs_mft_entry_t *mft_entry,
690      libbfio_handle_t *file_io_handle,
691      off64_t file_offset,
692      uint32_t mft_entry_size,
693      uint32_t mft_entry_index,
694      libcerror_error_t **error )
695 {
696 	static char *function = "libfsntfs_mft_entry_read_file_io_handle";
697 	ssize_t read_count    = 0;
698 	int result            = 0;
699 
700 	if( mft_entry == NULL )
701 	{
702 		libcerror_error_set(
703 		 error,
704 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
705 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
706 		 "%s: invalid MFT entry.",
707 		 function );
708 
709 		return( -1 );
710 	}
711 	if( mft_entry->data != NULL )
712 	{
713 		libcerror_error_set(
714 		 error,
715 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
716 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
717 		 "%s: invalid MFT entry - data value already set.",
718 		 function );
719 
720 		return( -1 );
721 	}
722 	if( ( (size_t) mft_entry_size <= 42 )
723 	 || ( (size_t) mft_entry_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
724 	{
725 		libcerror_error_set(
726 		 error,
727 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
728 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
729 		 "%s: invalid MFT entry size value out of bounds.",
730 		 function );
731 
732 		goto on_error;
733 	}
734 	mft_entry->data = (uint8_t *) memory_allocate(
735 	                               (size_t) mft_entry_size );
736 
737 	if( mft_entry->data == NULL )
738 	{
739 		libcerror_error_set(
740 		 error,
741 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
742 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
743 		 "%s: unable to create MFT entry data.",
744 		 function );
745 
746 		goto on_error;
747 	}
748 	mft_entry->data_size = (size_t) mft_entry_size;
749 
750 #if defined( HAVE_DEBUG_OUTPUT )
751 	if( libcnotify_verbose != 0 )
752 	{
753 		libcnotify_printf(
754 		 "%s: reading MFT entry at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
755 		 function,
756 		 file_offset,
757 		 file_offset );
758 	}
759 #endif
760 	read_count = libbfio_handle_read_buffer_at_offset(
761 	              file_io_handle,
762 	              mft_entry->data,
763 	              mft_entry->data_size,
764 	              file_offset,
765 	              error );
766 
767 	if( read_count != (ssize_t) mft_entry->data_size )
768 	{
769 		libcerror_error_set(
770 		 error,
771 		 LIBCERROR_ERROR_DOMAIN_IO,
772 		 LIBCERROR_IO_ERROR_READ_FAILED,
773 		 "%s: unable to read MFT entry data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
774 		 function,
775 		 file_offset,
776 		 file_offset );
777 
778 		goto on_error;
779 	}
780 	result = libfsntfs_mft_entry_read_data(
781 	          mft_entry,
782 	          mft_entry->data,
783 	          mft_entry->data_size,
784 	          mft_entry_index,
785 	          error );
786 
787 	if( result == -1 )
788 	{
789 		libcerror_error_set(
790 		 error,
791 		 LIBCERROR_ERROR_DOMAIN_IO,
792 		 LIBCERROR_IO_ERROR_READ_FAILED,
793 		 "%s: unable to read MFT entry data.",
794 		 function );
795 
796 		goto on_error;
797 	}
798 	else if( result == 0 )
799 	{
800 		memory_free(
801 		 mft_entry->data );
802 
803 		mft_entry->data      = NULL;
804 		mft_entry->data_size = 0;
805 	}
806 	return( 1 );
807 
808 on_error:
809 	if( mft_entry->header != NULL )
810 	{
811 		libfsntfs_mft_entry_header_free(
812 		 &( mft_entry->header ),
813 		 NULL );
814 	}
815 	if( mft_entry->data != NULL )
816 	{
817 		memory_free(
818 		 mft_entry->data );
819 
820 		mft_entry->data = NULL;
821 	}
822 	mft_entry->data_size = 0;
823 
824 	return( -1 );
825 }
826 
827 /* Reads the MFT attributes
828  * Returns 1 if successful or -1 on error
829  */
libfsntfs_mft_entry_read_attributes_data(libfsntfs_mft_entry_t * mft_entry,libfsntfs_io_handle_t * io_handle,const uint8_t * data,size_t data_size,libcerror_error_t ** error)830 int libfsntfs_mft_entry_read_attributes_data(
831      libfsntfs_mft_entry_t *mft_entry,
832      libfsntfs_io_handle_t *io_handle,
833      const uint8_t *data,
834      size_t data_size,
835      libcerror_error_t **error )
836 {
837 	libfsntfs_mft_attribute_t *mft_attribute = NULL;
838 	static char *function                    = "libfsntfs_mft_entry_read_attributes_data";
839 	size_t data_offset                       = 0;
840 	uint32_t attribute_type                  = 0;
841 	uint16_t attributes_offset               = 0;
842 	int attribute_index                      = 0;
843 	int entry_index                          = 0;
844 
845 #if defined( HAVE_DEBUG_OUTPUT )
846 	uint16_t used_entry_size                 = 0;
847 #endif
848 
849 	if( mft_entry == NULL )
850 	{
851 		libcerror_error_set(
852 		 error,
853 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
854 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
855 		 "%s: invalid MFT entry.",
856 		 function );
857 
858 		return( -1 );
859 	}
860 	if( data == NULL )
861 	{
862 		libcerror_error_set(
863 		 error,
864 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
865 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
866 		 "%s: invalid data.",
867 		 function );
868 
869 		return( -1 );
870 	}
871 	if( data_size > (size_t) SSIZE_MAX )
872 	{
873 		libcerror_error_set(
874 		 error,
875 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
876 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
877 		 "%s: invalid data size value exceeds maximum.",
878 		 function );
879 
880 		return( -1 );
881 	}
882 	if( data_size < 4 )
883 	{
884 		libcerror_error_set(
885 		 error,
886 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
887 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
888 		 "%s: unsupported data size value too small\n",
889 		 function );
890 
891 		return( -1 );
892 	}
893 	if( libfsntfs_mft_entry_header_get_attributes_offset(
894 	     mft_entry->header,
895 	     &attributes_offset,
896 	     error ) != 1 )
897 	{
898 		libcerror_error_set(
899 		 error,
900 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
901 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
902 		 "%s: unable to retrieve attributes offset.",
903 		 function );
904 
905 		goto on_error;
906 	}
907 	data_offset = (size_t) attributes_offset;
908 
909 	do
910 	{
911 		if( data_offset > ( data_size - 4 ) )
912 		{
913 			libcerror_error_set(
914 			 error,
915 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
916 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
917 			 "%s: invalid MFT entry - attribute offset: %d value out of bounds.",
918 			 function,
919 			 attribute_index );
920 
921 			goto on_error;
922 		}
923 		byte_stream_copy_to_uint32_little_endian(
924 		 &( data[ data_offset ] ),
925 		 attribute_type );
926 
927 		if( attribute_type == LIBFSNTFS_ATTRIBUTE_TYPE_END_OF_ATTRIBUTES )
928 		{
929 			break;
930 		}
931 		if( libfsntfs_mft_attribute_initialize(
932 		     &mft_attribute,
933 		     error ) != 1 )
934 		{
935 			libcerror_error_set(
936 			 error,
937 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
938 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
939 			 "%s: unable to create MFT attribute: %d.",
940 			 function,
941 			 attribute_index );
942 
943 			goto on_error;
944 		}
945 		if( libfsntfs_mft_attribute_read_data(
946 		     mft_attribute,
947 		     io_handle,
948 		     &( data[ data_offset ] ),
949 		     data_size - data_offset,
950 		     error ) != 1 )
951 		{
952 			libcerror_error_set(
953 			 error,
954 			 LIBCERROR_ERROR_DOMAIN_IO,
955 			 LIBCERROR_IO_ERROR_READ_FAILED,
956 			 "%s: unable to read MFT attribute: %d of type: 0x%08" PRIx32 ".",
957 			 function,
958 			 attribute_index,
959 			 attribute_type );
960 
961 			goto on_error;
962 		}
963 		data_offset += mft_attribute->size;
964 
965 		if( attribute_type == LIBFSNTFS_ATTRIBUTE_TYPE_ATTRIBUTE_LIST )
966 		{
967 			if( mft_entry->list_attribute != NULL )
968 			{
969 				libcerror_error_set(
970 				 error,
971 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
972 				 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
973 				 "%s: invalid MFT entry - list attribute value already set.",
974 				 function );
975 
976 				goto on_error;
977 			}
978 			mft_entry->list_attribute = mft_attribute;
979 		}
980 		/* mft_entry->attributes_array takes over management of mft_attribute
981 		 */
982 		if( libcdata_array_append_entry(
983 		     mft_entry->attributes_array,
984 		     &entry_index,
985 		     (intptr_t *) mft_attribute,
986 		     error ) != 1 )
987 		{
988 			libcerror_error_set(
989 			 error,
990 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
991 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
992 			 "%s: unable to append attribute to array.",
993 			 function );
994 
995 			goto on_error;
996 		}
997 		if( libfsntfs_mft_entry_set_attribute_helper_values(
998 		     mft_entry,
999 		     entry_index,
1000 		     mft_attribute,
1001 		     error ) != 1 )
1002 		{
1003 			libcerror_error_set(
1004 			 error,
1005 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1006 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1007 			 "%s: unable to set helper values for attribute: %d.",
1008 			 function,
1009 			 attribute_index );
1010 
1011 			mft_attribute = NULL;
1012 
1013 			goto on_error;
1014 		}
1015 		mft_attribute = NULL;
1016 
1017 		attribute_index++;
1018 	}
1019 	while( attribute_type != LIBFSNTFS_ATTRIBUTE_TYPE_END_OF_ATTRIBUTES );
1020 
1021 	data_offset += 4;
1022 
1023 #if defined( HAVE_DEBUG_OUTPUT )
1024 	if( libcnotify_verbose != 0 )
1025 	{
1026 		if( libfsntfs_mft_entry_header_get_used_entry_size(
1027 		     mft_entry->header,
1028 		     &used_entry_size,
1029 		     error ) != 1 )
1030 		{
1031 			libcerror_error_set(
1032 			 error,
1033 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1034 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1035 			 "%s: unable to retrieve used entry size.",
1036 			 function );
1037 
1038 			goto on_error;
1039 		}
1040 		if( data_offset != (size_t) used_entry_size )
1041 		{
1042 			libcnotify_printf(
1043 			 "%s: mismatch in used MFT entry size (calculated: %" PRIzd ", stored: %" PRIu16 ").\n",
1044 			 function,
1045 			 data_offset,
1046 			 used_entry_size );
1047 		}
1048 	}
1049 #endif
1050 	return( 1 );
1051 
1052 on_error:
1053 	if( mft_attribute != NULL )
1054 	{
1055 		libfsntfs_mft_attribute_free(
1056 		 &mft_attribute,
1057 		 NULL );
1058 	}
1059 	libcdata_array_empty(
1060 	 mft_entry->attributes_array,
1061 	 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_free,
1062 	 NULL );
1063 
1064 	mft_entry->file_name_attribute_index            = -1;
1065 	mft_entry->reparse_point_attribute_index        = -1;
1066 	mft_entry->security_descriptor_attribute_index  = -1;
1067 	mft_entry->standard_information_attribute_index = -1;
1068 	mft_entry->volume_information_attribute_index   = -1;
1069 	mft_entry->volume_name_attribute_index          = -1;
1070 	mft_entry->list_attribute                       = NULL;
1071 	mft_entry->data_attribute                       = NULL;
1072 	mft_entry->wof_compressed_data_attribute        = NULL;
1073 
1074 	return( -1 );
1075 }
1076 
1077 /* Reads the MFT attributes
1078  * Returns 1 if successful or -1 on error
1079  */
libfsntfs_mft_entry_read_attributes(libfsntfs_mft_entry_t * mft_entry,libfsntfs_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfdata_vector_t * mft_entry_vector,libcdata_btree_t * attribute_list_tree,uint8_t flags,libcerror_error_t ** error)1080 int libfsntfs_mft_entry_read_attributes(
1081      libfsntfs_mft_entry_t *mft_entry,
1082      libfsntfs_io_handle_t *io_handle,
1083      libbfio_handle_t *file_io_handle,
1084      libfdata_vector_t *mft_entry_vector,
1085      libcdata_btree_t *attribute_list_tree,
1086      uint8_t flags,
1087      libcerror_error_t **error )
1088 {
1089 	libcdata_tree_node_t *upper_node                      = NULL;
1090 	libfsntfs_mft_attribute_list_t *attribute_list        = NULL;
1091 	libfsntfs_mft_attribute_list_t *lookup_attribute_list = NULL;
1092 	static char *function                                 = "libfsntfs_mft_entry_read_attributes";
1093 	int result                                            = 0;
1094 
1095 	if( mft_entry == NULL )
1096 	{
1097 		libcerror_error_set(
1098 		 error,
1099 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1100 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1101 		 "%s: invalid MFT entry.",
1102 		 function );
1103 
1104 		return( -1 );
1105 	}
1106 	if( mft_entry->attributes_read != 0 )
1107 	{
1108 		return( 1 );
1109 	}
1110 	if( mft_entry->is_empty == 0 )
1111 	{
1112 		if( libfsntfs_mft_entry_read_attributes_data(
1113 		     mft_entry,
1114 		     io_handle,
1115 		     mft_entry->data,
1116 		     mft_entry->data_size,
1117 		     error ) != 1 )
1118 		{
1119 			libcerror_error_set(
1120 			 error,
1121 			 LIBCERROR_ERROR_DOMAIN_IO,
1122 			 LIBCERROR_IO_ERROR_READ_FAILED,
1123 			 "%s: unable to read attributes of MFT entry: %d.",
1124 			 function,
1125 			 mft_entry->index );
1126 
1127 			goto on_error;
1128 		}
1129 		if( mft_entry->list_attribute != NULL )
1130 		{
1131 			if( ( flags & LIBFSNTFS_FILE_ENTRY_FLAGS_MFT_ONLY ) != 0 )
1132 			{
1133 				if( libfsntfs_mft_attribute_list_initialize(
1134 				     &lookup_attribute_list,
1135 				     mft_entry->file_reference,
1136 				     error ) != 1 )
1137 				{
1138 					libcerror_error_set(
1139 					 error,
1140 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1141 					 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1142 					 "%s: unable to create lookup attribute list.",
1143 					 function );
1144 
1145 					goto on_error;
1146 				}
1147 				result = libcdata_btree_get_value_by_value(
1148 				          attribute_list_tree,
1149 				          (intptr_t *) lookup_attribute_list,
1150 				          (int (*)(intptr_t *, intptr_t *, libcerror_error_t **)) &libfsntfs_mft_attribute_list_compare_by_base_record_file_reference,
1151 				          &upper_node,
1152 				          (intptr_t **) &attribute_list,
1153 				          error );
1154 
1155 				if( result == -1 )
1156 				{
1157 					libcerror_error_set(
1158 					 error,
1159 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1160 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1161 					 "%s: unable to retrieve path hint from tree.",
1162 					 function );
1163 
1164 					goto on_error;
1165 				}
1166 				if( libfsntfs_mft_attribute_list_free(
1167 				     &lookup_attribute_list,
1168 				     error ) != 1 )
1169 				{
1170 					libcerror_error_set(
1171 					 error,
1172 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1173 					 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1174 					 "%s: unable to free lookup attribute list.",
1175 					 function );
1176 
1177 					goto on_error;
1178 				}
1179 			}
1180 			else
1181 			{
1182 				if( libfsntfs_mft_entry_read_attribute_list(
1183 				     mft_entry,
1184 				     io_handle,
1185 				     file_io_handle,
1186 				     error ) != 1 )
1187 				{
1188 					libcerror_error_set(
1189 					 error,
1190 					 LIBCERROR_ERROR_DOMAIN_IO,
1191 					 LIBCERROR_IO_ERROR_READ_FAILED,
1192 					 "%s: unable to read attribute list.",
1193 					 function );
1194 
1195 					goto on_error;
1196 				}
1197 				attribute_list = mft_entry->attribute_list;
1198 			}
1199 			if( attribute_list != NULL )
1200 			{
1201 				if( libfsntfs_mft_entry_read_attribute_list_data_mft_entries(
1202 				     mft_entry,
1203 				     attribute_list,
1204 				     io_handle,
1205 				     file_io_handle,
1206 				     mft_entry_vector,
1207 				     error ) != 1 )
1208 				{
1209 					libcerror_error_set(
1210 					 error,
1211 					 LIBCERROR_ERROR_DOMAIN_IO,
1212 					 LIBCERROR_IO_ERROR_READ_FAILED,
1213 					 "%s: unable to read attribute list data MFT entries.",
1214 					 function );
1215 
1216 					goto on_error;
1217 				}
1218 			}
1219 			else
1220 			{
1221 				mft_entry->is_corrupted = 1;
1222 			}
1223 		}
1224 	}
1225 	mft_entry->attributes_read = 1;
1226 
1227 	return( 1 );
1228 
1229 on_error:
1230 	if( lookup_attribute_list != NULL )
1231 	{
1232 		libfsntfs_mft_attribute_list_free(
1233 		 &lookup_attribute_list,
1234 		 NULL );
1235 	}
1236 	if( mft_entry->attribute_list != NULL )
1237 	{
1238 		libfsntfs_mft_attribute_list_free(
1239 		 &( mft_entry->attribute_list ),
1240 		 NULL );
1241 	}
1242 	libcdata_array_empty(
1243 	 mft_entry->alternate_data_attributes_array,
1244 	 NULL,
1245 	 NULL );
1246 
1247 	libcdata_array_empty(
1248 	 mft_entry->attributes_array,
1249 	 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_free,
1250 	 NULL );
1251 
1252 	return( -1 );
1253 }
1254 
1255 /* Reads the attribute list
1256  * Returns 1 if successful or -1 on error
1257  */
libfsntfs_mft_entry_read_attribute_list(libfsntfs_mft_entry_t * mft_entry,libfsntfs_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libcerror_error_t ** error)1258 int libfsntfs_mft_entry_read_attribute_list(
1259      libfsntfs_mft_entry_t *mft_entry,
1260      libfsntfs_io_handle_t *io_handle,
1261      libbfio_handle_t *file_io_handle,
1262      libcerror_error_t **error )
1263 {
1264 	libfsntfs_mft_attribute_list_entry_t *attribute_list_entry = NULL;
1265 	static char *function                                      = "libfsntfs_mft_entry_read_attribute_list";
1266 	uint64_t attribute_list_data_mft_entry_index               = 0;
1267 	uint64_t file_reference                                    = 0;
1268 	int attribute_list_entry_index                             = 0;
1269 	int number_of_attribute_list_entries                       = 0;
1270 
1271 	if( mft_entry == NULL )
1272 	{
1273 		libcerror_error_set(
1274 		 error,
1275 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1276 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1277 		 "%s: invalid MFT entry.",
1278 		 function );
1279 
1280 		return( -1 );
1281 	}
1282 	if( mft_entry->list_attribute == NULL )
1283 	{
1284 		libcerror_error_set(
1285 		 error,
1286 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1287 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1288 		 "%s: invalid MFT entry - missing list attribute.",
1289 		 function );
1290 
1291 		return( -1 );
1292 	}
1293 	if( mft_entry->attribute_list != NULL )
1294 	{
1295 		libcerror_error_set(
1296 		 error,
1297 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1298 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1299 		 "%s: invalid MFT entry - attribute list value already set.",
1300 		 function );
1301 
1302 		return( -1 );
1303 	}
1304 	if( libfsntfs_mft_attribute_list_initialize(
1305 	     &( mft_entry->attribute_list ),
1306 	     mft_entry->file_reference,
1307 	     error ) != 1 )
1308 	{
1309 		libcerror_error_set(
1310 		 error,
1311 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1312 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1313 		 "%s: unable to create attribute list.",
1314 		 function );
1315 
1316 		goto on_error;
1317 	}
1318 	if( libfsntfs_mft_attribute_list_read_from_attribute(
1319 	     mft_entry->attribute_list,
1320 	     io_handle,
1321 	     file_io_handle,
1322 	     mft_entry->list_attribute,
1323 	     error ) != 1 )
1324 	{
1325 		libcerror_error_set(
1326 		 error,
1327 		 LIBCERROR_ERROR_DOMAIN_IO,
1328 		 LIBCERROR_IO_ERROR_READ_FAILED,
1329 		 "%s: unable to read attribute list.",
1330 		 function );
1331 
1332 		goto on_error;
1333 	}
1334 	if( libfsntfs_mft_attribute_list_get_number_of_entries(
1335 	     mft_entry->attribute_list,
1336 	     &number_of_attribute_list_entries,
1337 	     error ) != 1 )
1338 	{
1339 		libcerror_error_set(
1340 		 error,
1341 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1342 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1343 		 "%s: unable to retrieve number of attribute list entries.",
1344 		 function );
1345 
1346 		goto on_error;
1347 	}
1348 	for( attribute_list_entry_index = 0;
1349 	     attribute_list_entry_index < number_of_attribute_list_entries;
1350 	     attribute_list_entry_index++ )
1351 	{
1352 		if( libfsntfs_mft_attribute_list_get_entry_by_index(
1353 		     mft_entry->attribute_list,
1354 		     attribute_list_entry_index,
1355 		     &attribute_list_entry,
1356 		     error ) != 1 )
1357 		{
1358 			libcerror_error_set(
1359 			 error,
1360 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1361 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1362 			 "%s: unable to retrieve attribute list entry: %d.",
1363 			 function,
1364 			 attribute_list_entry_index );
1365 
1366 			goto on_error;
1367 		}
1368 		if( libfsntfs_mft_attribute_list_entry_get_file_reference(
1369 		     attribute_list_entry,
1370 		     &file_reference,
1371 		     error ) != 1 )
1372 		{
1373 			libcerror_error_set(
1374 			 error,
1375 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1376 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1377 			 "%s: unable to retrieve attribute list entry: %d file reference.",
1378 			 function,
1379 			 attribute_list_entry_index );
1380 
1381 			goto on_error;
1382 		}
1383 		attribute_list_data_mft_entry_index = file_reference & 0xffffffffffffUL;
1384 
1385 		if( attribute_list_data_mft_entry_index > (uint64_t) INT_MAX )
1386 		{
1387 			libcerror_error_set(
1388 			 error,
1389 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1390 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1391 			 "%s: attribute list data MFT entry reference value out of bounds.",
1392 			 function );
1393 
1394 			goto on_error;
1395 		}
1396 		/* Ignore the current MFT entry
1397 		 */
1398 		if( attribute_list_data_mft_entry_index == (uint64_t) mft_entry->index )
1399 		{
1400 			continue;
1401 		}
1402 		if( libfsntfs_mft_attribute_list_insert_file_reference(
1403 		     mft_entry->attribute_list,
1404 		     file_reference,
1405 		     error ) == -1 )
1406 		{
1407 			libcerror_error_set(
1408 			 error,
1409 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1410 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1411 			 "%s: unable to insert attribute list data file reference in attribute list.",
1412 			 function );
1413 
1414 			goto on_error;
1415 		}
1416 	}
1417 	return( 1 );
1418 
1419 on_error:
1420 	if( mft_entry->attribute_list != NULL )
1421 	{
1422 		libfsntfs_mft_attribute_list_free(
1423 		 &( mft_entry->attribute_list ),
1424 		 NULL );
1425 	}
1426 	return( -1 );
1427 }
1428 
1429 /* Reads a specific attribute list data MFT entry
1430  * Returns 1 if successful, 0 if not available or -1 on error
1431  */
libfsntfs_mft_entry_read_attribute_list_data_mft_entry_by_index(libfsntfs_mft_entry_t * mft_entry,libfsntfs_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfdata_vector_t * mft_entry_vector,libfcache_cache_t * mft_entry_cache,uint64_t file_reference,libcerror_error_t ** error)1432 int libfsntfs_mft_entry_read_attribute_list_data_mft_entry_by_index(
1433      libfsntfs_mft_entry_t *mft_entry,
1434      libfsntfs_io_handle_t *io_handle,
1435      libbfio_handle_t *file_io_handle,
1436      libfdata_vector_t *mft_entry_vector,
1437      libfcache_cache_t *mft_entry_cache,
1438      uint64_t file_reference,
1439      libcerror_error_t **error )
1440 {
1441 	libfsntfs_mft_attribute_t *data_mft_attribute = NULL;
1442 	libfsntfs_mft_attribute_t *mft_attribute      = NULL;
1443 	libfsntfs_mft_entry_t *data_mft_entry         = NULL;
1444 	static char *function                         = "libfsntfs_mft_entry_read_attribute_list_data_mft_entry_by_index";
1445 	uint64_t attribute_list_data_mft_entry        = 0;
1446 	uint64_t base_record_file_reference           = 0;
1447 	int attribute_index                           = 0;
1448 	int entry_index                               = 0;
1449 	int number_of_attributes                      = 0;
1450 
1451 	if( mft_entry == NULL )
1452 	{
1453 		libcerror_error_set(
1454 		 error,
1455 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1456 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1457 		 "%s: invalid MFT entry.",
1458 		 function );
1459 
1460 		return( -1 );
1461 	}
1462 	attribute_list_data_mft_entry = file_reference & 0xffffffffffffUL;
1463 
1464 #if defined( HAVE_DEBUG_OUTPUT )
1465 	if( libcnotify_verbose != 0 )
1466 	{
1467 		libcnotify_printf(
1468 		 "%s: reading data file reference: %" PRIu64 "-%" PRIu16 "\n",
1469 		 function,
1470 		 attribute_list_data_mft_entry,
1471 		 (uint16_t) ( file_reference >> 48 ) );
1472 		libcnotify_printf(
1473 		 "\n" );
1474 	}
1475 #endif
1476 	if( libfdata_vector_get_element_value_by_index(
1477 	     mft_entry_vector,
1478 	     (intptr_t *) file_io_handle,
1479 	     (libfdata_cache_t *) mft_entry_cache,
1480 	     (int) attribute_list_data_mft_entry,
1481 	     (intptr_t **) &data_mft_entry,
1482 	     0,
1483 	     error ) != 1 )
1484 	{
1485 		libcerror_error_set(
1486 		 error,
1487 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1488 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1489 		 "%s: unable to retrieve MFT entry: %" PRIu64 ".",
1490 		 function,
1491 		 attribute_list_data_mft_entry );
1492 
1493 		return( -1 );
1494 	}
1495 	if( data_mft_entry->header == NULL )
1496 	{
1497 		return( 0 );
1498 	}
1499 	if( libfsntfs_mft_entry_header_get_base_record_file_reference(
1500 	     data_mft_entry->header,
1501 	     &base_record_file_reference,
1502 	     error ) != 1 )
1503 	{
1504 		libcerror_error_set(
1505 		 error,
1506 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1507 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1508 		 "%s: unable to retrieve base record file reference.",
1509 		 function );
1510 
1511 		return( -1 );
1512 	}
1513 	if( mft_entry->file_reference != base_record_file_reference )
1514 	{
1515 		return( 0 );
1516 	}
1517 	if( libfsntfs_mft_entry_read_attributes_data(
1518 	     data_mft_entry,
1519 	     io_handle,
1520 	     data_mft_entry->data,
1521 	     data_mft_entry->data_size,
1522 	     error ) != 1 )
1523 	{
1524 		libcerror_error_set(
1525 		 error,
1526 		 LIBCERROR_ERROR_DOMAIN_IO,
1527 		 LIBCERROR_IO_ERROR_READ_FAILED,
1528 		 "%s: unable to read attributes.",
1529 		 function );
1530 
1531 		return( -1 );
1532 	}
1533 	if( libcdata_array_get_number_of_entries(
1534 	     data_mft_entry->attributes_array,
1535 	     &number_of_attributes,
1536 	     error ) != 1 )
1537 	{
1538 		libcerror_error_set(
1539 		 error,
1540 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1541 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1542 		 "%s: unable to retrieve number of attributes.",
1543 		 function );
1544 
1545 		return( -1 );
1546 	}
1547 	for( attribute_index = 0;
1548 	     attribute_index < number_of_attributes;
1549 	     attribute_index++ )
1550 	{
1551 		if( libcdata_array_get_entry_by_index(
1552 		     data_mft_entry->attributes_array,
1553 		     attribute_index,
1554 		     (intptr_t **) &mft_attribute,
1555 		     error ) != 1 )
1556 		{
1557 			libcerror_error_set(
1558 			 error,
1559 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1560 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1561 			 "%s: unable to retrieve attribute: %d from list MFT entry.",
1562 			 function,
1563 			 attribute_index );
1564 
1565 			return( -1 );
1566 		}
1567 		if( libfsntfs_mft_attribute_clone(
1568 		     &data_mft_attribute,
1569 		     mft_attribute,
1570 		     error ) != 1 )
1571 		{
1572 			libcerror_error_set(
1573 			 error,
1574 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1575 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1576 			 "%s: unable to clone MFT attribute: %d.",
1577 			 function,
1578 			 attribute_index );
1579 
1580 			return( -1 );
1581 		}
1582 		/* mft_entry->attributes_array takes over management of data_mft_attribute
1583 		 */
1584 		if( libcdata_array_append_entry(
1585 		     mft_entry->attributes_array,
1586 		     &entry_index,
1587 		     (intptr_t *) data_mft_attribute,
1588 		     error ) != 1 )
1589 		{
1590 			libcerror_error_set(
1591 			 error,
1592 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1593 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1594 			 "%s: unable to append MFT attribute to array.",
1595 			 function );
1596 
1597 			libfsntfs_mft_attribute_free(
1598 			 &data_mft_attribute,
1599 			 NULL );
1600 
1601 			return( -1 );
1602 		}
1603 		if( libfsntfs_mft_entry_set_attribute_helper_values(
1604 		     mft_entry,
1605 		     entry_index,
1606 		     data_mft_attribute,
1607 		     error ) != 1 )
1608 		{
1609 			libcerror_error_set(
1610 			 error,
1611 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1612 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1613 			 "%s: unable to set helper values for attribute: %d.",
1614 			 function,
1615 			 entry_index );
1616 
1617 			return( -1 );
1618 		}
1619 		data_mft_attribute = NULL;
1620 	}
1621 	return( 1 );
1622 }
1623 
1624 /* Reads the attribute list data MFT entries
1625  * Returns 1 if successful or -1 on error
1626  */
libfsntfs_mft_entry_read_attribute_list_data_mft_entries(libfsntfs_mft_entry_t * mft_entry,libfsntfs_mft_attribute_list_t * attribute_list,libfsntfs_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfdata_vector_t * mft_entry_vector,libcerror_error_t ** error)1627 int libfsntfs_mft_entry_read_attribute_list_data_mft_entries(
1628      libfsntfs_mft_entry_t *mft_entry,
1629      libfsntfs_mft_attribute_list_t *attribute_list,
1630      libfsntfs_io_handle_t *io_handle,
1631      libbfio_handle_t *file_io_handle,
1632      libfdata_vector_t *mft_entry_vector,
1633      libcerror_error_t **error )
1634 {
1635 	libfcache_cache_t *mft_entry_cache = NULL;
1636 	static char *function              = "libfsntfs_mft_entry_read_attribute_list_data_mft_entries";
1637 	uint64_t file_reference            = 0;
1638 	int file_reference_index           = 0;
1639 	int number_of_file_entries         = 0;
1640 	int result                         = 0;
1641 
1642 	if( mft_entry == NULL )
1643 	{
1644 		libcerror_error_set(
1645 		 error,
1646 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1647 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1648 		 "%s: invalid MFT entry.",
1649 		 function );
1650 
1651 		return( -1 );
1652 	}
1653 	/* Read the list data MFT entries
1654 	 * Use a local cache to prevent cache outs
1655 	 */
1656 	if( libfcache_cache_initialize(
1657 	     &mft_entry_cache,
1658 	     1,
1659 	     error ) != 1 )
1660 	{
1661 		libcerror_error_set(
1662 		 error,
1663 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1664 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1665 		 "%s: unable to create MFT entry cache.",
1666 		 function );
1667 
1668 		goto on_error;
1669 	}
1670 	if( libfsntfs_mft_attribute_list_get_number_of_file_references(
1671 	     attribute_list,
1672 	     &number_of_file_entries,
1673 	     error ) != 1 )
1674 	{
1675 		libcerror_error_set(
1676 		 error,
1677 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1678 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1679 		 "%s: unable to retrieve number of attribute list data MFT entries.",
1680 		 function );
1681 
1682 		goto on_error;
1683 	}
1684 	for( file_reference_index = 0;
1685 	     file_reference_index < number_of_file_entries;
1686 	     file_reference_index++ )
1687 	{
1688 		if( libfsntfs_mft_attribute_list_get_file_reference_by_index(
1689 		     attribute_list,
1690 		     file_reference_index,
1691 		     &file_reference,
1692 		     error ) != 1 )
1693 		{
1694 			libcerror_error_set(
1695 			 error,
1696 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1697 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1698 			 "%s: unable to retrieve attribute list data MFT entry: %d.",
1699 			 function,
1700 			 file_reference_index );
1701 
1702 			goto on_error;
1703 		}
1704 		result = libfsntfs_mft_entry_read_attribute_list_data_mft_entry_by_index(
1705 		          mft_entry,
1706 		          io_handle,
1707 		          file_io_handle,
1708 		          mft_entry_vector,
1709 		          mft_entry_cache,
1710 		          file_reference,
1711 		          error );
1712 
1713 		if( result == -1 )
1714 		{
1715 			libcerror_error_set(
1716 			 error,
1717 			 LIBCERROR_ERROR_DOMAIN_IO,
1718 			 LIBCERROR_IO_ERROR_READ_FAILED,
1719 			 "%s: unable to read attribute list data MFT entry: %" PRIu64 "-%" PRIu64 ".",
1720 			 function,
1721 			 file_reference & 0xffffffffffffUL,
1722 			 file_reference >> 48 );
1723 
1724 			goto on_error;
1725 		}
1726 		else if( result == 0 )
1727 		{
1728 			mft_entry->is_corrupted = 1;
1729 		}
1730 	}
1731 	if( libfcache_cache_free(
1732 	     &mft_entry_cache,
1733 	     error ) != 1 )
1734 	{
1735 		libcerror_error_set(
1736 		 error,
1737 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1738 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1739 		 "%s: unable to free MFT entry cache.",
1740 		 function );
1741 
1742 		goto on_error;
1743 	}
1744 	return( 1 );
1745 
1746 on_error:
1747 	if( mft_entry_cache != NULL )
1748 	{
1749 		libfcache_cache_free(
1750 		 &mft_entry_cache,
1751 		 NULL );
1752 	}
1753 	return( -1 );
1754 }
1755 
1756 /* Determines if the MFT entry is empty
1757  * Returns 1 if empty, 0 if not or -1 on error
1758  */
libfsntfs_mft_entry_is_empty(libfsntfs_mft_entry_t * mft_entry,libcerror_error_t ** error)1759 int libfsntfs_mft_entry_is_empty(
1760      libfsntfs_mft_entry_t *mft_entry,
1761      libcerror_error_t **error )
1762 {
1763 	static char *function = "libfsntfs_mft_entry_is_empty";
1764 
1765 	if( mft_entry == NULL )
1766 	{
1767 		libcerror_error_set(
1768 		 error,
1769 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1770 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1771 		 "%s: invalid MFT entry.",
1772 		 function );
1773 
1774 		return( -1 );
1775 	}
1776 	return( (int) mft_entry->is_empty );
1777 }
1778 
1779 /* Determines if the MFT entry is allocated (in use)
1780  * Returns 1 if allocated, 0 if not or -1 on error
1781  */
libfsntfs_mft_entry_is_allocated(libfsntfs_mft_entry_t * mft_entry,libcerror_error_t ** error)1782 int libfsntfs_mft_entry_is_allocated(
1783      libfsntfs_mft_entry_t *mft_entry,
1784      libcerror_error_t **error )
1785 {
1786 	static char *function = "libfsntfs_mft_entry_is_allocated";
1787 
1788 	if( mft_entry == NULL )
1789 	{
1790 		libcerror_error_set(
1791 		 error,
1792 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1793 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1794 		 "%s: invalid MFT entry.",
1795 		 function );
1796 
1797 		return( -1 );
1798 	}
1799 	if( mft_entry->header == NULL )
1800 	{
1801 		libcerror_error_set(
1802 		 error,
1803 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1804 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1805 		 "%s: invalid MFT entry - missing header.",
1806 		 function );
1807 
1808 		return( -1 );
1809 	}
1810 	if( ( mft_entry->header->flags & LIBFSNTFS_MFT_ENTRY_FLAG_IN_USE ) != 0 )
1811 	{
1812 		return( 1 );
1813 	}
1814 	return( 0 );
1815 }
1816 
1817 /* Determines if the MFT entry is corrupted
1818  * Returns 1 if corrupted, 0 if not or -1 on error
1819  */
libfsntfs_mft_entry_is_corrupted(libfsntfs_mft_entry_t * mft_entry,libcerror_error_t ** error)1820 int libfsntfs_mft_entry_is_corrupted(
1821      libfsntfs_mft_entry_t *mft_entry,
1822      libcerror_error_t **error )
1823 {
1824 	static char *function = "libfsntfs_mft_entry_is_corrupted";
1825 
1826 	if( mft_entry == NULL )
1827 	{
1828 		libcerror_error_set(
1829 		 error,
1830 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1831 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1832 		 "%s: invalid MFT entry.",
1833 		 function );
1834 
1835 		return( -1 );
1836 	}
1837 	return( (int) mft_entry->is_corrupted );
1838 }
1839 
1840 /* Retrieves the file reference
1841  * Returns 1 if successful or -1 on error
1842  */
libfsntfs_mft_entry_get_file_reference(libfsntfs_mft_entry_t * mft_entry,uint64_t * file_reference,libcerror_error_t ** error)1843 int libfsntfs_mft_entry_get_file_reference(
1844      libfsntfs_mft_entry_t *mft_entry,
1845      uint64_t *file_reference,
1846      libcerror_error_t **error )
1847 {
1848 	static char *function = "libfsntfs_mft_entry_get_file_reference";
1849 
1850 	if( mft_entry == NULL )
1851 	{
1852 		libcerror_error_set(
1853 		 error,
1854 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1855 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1856 		 "%s: invalid MFT entry.",
1857 		 function );
1858 
1859 		return( -1 );
1860 	}
1861 	if( file_reference == NULL )
1862 	{
1863 		libcerror_error_set(
1864 		 error,
1865 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1866 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1867 		 "%s: invalid file reference.",
1868 		 function );
1869 
1870 		return( -1 );
1871 	}
1872 	*file_reference = mft_entry->file_reference;
1873 
1874 	return( 1 );
1875 }
1876 
1877 /* Retrieves the base record file reference
1878  * Returns 1 if successful, 0 if not available or -1 on error
1879  */
libfsntfs_mft_entry_get_base_record_file_reference(libfsntfs_mft_entry_t * mft_entry,uint64_t * file_reference,libcerror_error_t ** error)1880 int libfsntfs_mft_entry_get_base_record_file_reference(
1881      libfsntfs_mft_entry_t *mft_entry,
1882      uint64_t *file_reference,
1883      libcerror_error_t **error )
1884 {
1885 	static char *function = "libfsntfs_mft_entry_get_base_record_file_reference";
1886 
1887 	if( mft_entry == NULL )
1888 	{
1889 		libcerror_error_set(
1890 		 error,
1891 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1892 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1893 		 "%s: invalid MFT entry.",
1894 		 function );
1895 
1896 		return( -1 );
1897 	}
1898 	if( mft_entry->header == NULL )
1899 	{
1900 		return( 0 );
1901 	}
1902 	if( libfsntfs_mft_entry_header_get_base_record_file_reference(
1903 	     mft_entry->header,
1904 	     file_reference,
1905 	     error ) != 1 )
1906 	{
1907 		libcerror_error_set(
1908 		 error,
1909 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1910 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1911 		 "%s: unable to retrieve base record file reference.",
1912 		 function );
1913 
1914 		return( -1 );
1915 	}
1916 	return( 1 );
1917 }
1918 
1919 /* Retrieves the journal sequence number
1920  * Returns 1 if successful or -1 on error
1921  */
libfsntfs_mft_entry_get_journal_sequence_number(libfsntfs_mft_entry_t * mft_entry,uint64_t * journal_sequence_number,libcerror_error_t ** error)1922 int libfsntfs_mft_entry_get_journal_sequence_number(
1923      libfsntfs_mft_entry_t *mft_entry,
1924      uint64_t *journal_sequence_number,
1925      libcerror_error_t **error )
1926 {
1927 	static char *function = "libfsntfs_mft_entry_get_journal_sequence_number";
1928 
1929 	if( mft_entry == NULL )
1930 	{
1931 		libcerror_error_set(
1932 		 error,
1933 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1934 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1935 		 "%s: invalid MFT entry.",
1936 		 function );
1937 
1938 		return( -1 );
1939 	}
1940 	if( libfsntfs_mft_entry_header_get_journal_sequence_number(
1941 	     mft_entry->header,
1942 	     journal_sequence_number,
1943 	     error ) != 1 )
1944 	{
1945 		libcerror_error_set(
1946 		 error,
1947 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1948 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1949 		 "%s: unable to retrieve journal sequence number.",
1950 		 function );
1951 
1952 		return( -1 );
1953 	}
1954 	return( 1 );
1955 }
1956 
1957 /* Retrieves the number of attributes
1958  * Returns 1 if successful or -1 on error
1959  */
libfsntfs_mft_entry_get_number_of_attributes(libfsntfs_mft_entry_t * mft_entry,int * number_of_attributes,libcerror_error_t ** error)1960 int libfsntfs_mft_entry_get_number_of_attributes(
1961      libfsntfs_mft_entry_t *mft_entry,
1962      int *number_of_attributes,
1963      libcerror_error_t **error )
1964 {
1965 	static char *function = "libfsntfs_mft_entry_get_number_of_attributes";
1966 
1967 	if( mft_entry == NULL )
1968 	{
1969 		libcerror_error_set(
1970 		 error,
1971 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1972 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1973 		 "%s: invalid MFT entry.",
1974 		 function );
1975 
1976 		return( -1 );
1977 	}
1978 	if( libcdata_array_get_number_of_entries(
1979 	     mft_entry->attributes_array,
1980 	     number_of_attributes,
1981 	     error ) != 1 )
1982 	{
1983 		libcerror_error_set(
1984 		 error,
1985 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1986 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1987 		 "%s: unable to retrieve number of entries from attributes array.",
1988 		 function );
1989 
1990 		return( -1 );
1991 	}
1992 	return( 1 );
1993 }
1994 
1995 /* Retrieves a specific attribute
1996  * Returns 1 if successful or -1 on error
1997  */
libfsntfs_mft_entry_get_attribute_by_index(libfsntfs_mft_entry_t * mft_entry,int attribute_index,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)1998 int libfsntfs_mft_entry_get_attribute_by_index(
1999      libfsntfs_mft_entry_t *mft_entry,
2000      int attribute_index,
2001      libfsntfs_mft_attribute_t **attribute,
2002      libcerror_error_t **error )
2003 {
2004 	static char *function = "libfsntfs_mft_entry_get_attribute_by_index";
2005 
2006 	if( mft_entry == NULL )
2007 	{
2008 		libcerror_error_set(
2009 		 error,
2010 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2011 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2012 		 "%s: invalid MFT entry.",
2013 		 function );
2014 
2015 		return( -1 );
2016 	}
2017 	if( libcdata_array_get_entry_by_index(
2018 	     mft_entry->attributes_array,
2019 	     attribute_index,
2020 	     (intptr_t **) attribute,
2021 	     error ) != 1 )
2022 	{
2023 		libcerror_error_set(
2024 		 error,
2025 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2026 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2027 		 "%s: unable to retrieve entry: %d from attributes array.",
2028 		 function,
2029 		 attribute_index );
2030 
2031 		return( -1 );
2032 	}
2033 	return( 1 );
2034 }
2035 
2036 /* Retrieves the $STANDARD_INFORMATION attribute
2037  * Returns 1 if successful, 0 if not available or -1 on error
2038  */
libfsntfs_mft_entry_get_standard_information_attribute(libfsntfs_mft_entry_t * mft_entry,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2039 int libfsntfs_mft_entry_get_standard_information_attribute(
2040      libfsntfs_mft_entry_t *mft_entry,
2041      libfsntfs_mft_attribute_t **attribute,
2042      libcerror_error_t **error )
2043 {
2044 	static char *function = "libfsntfs_mft_entry_get_standard_information_attribute";
2045 
2046 	if( mft_entry == NULL )
2047 	{
2048 		libcerror_error_set(
2049 		 error,
2050 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2051 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2052 		 "%s: invalid MFT entry.",
2053 		 function );
2054 
2055 		return( -1 );
2056 	}
2057 	if( mft_entry->standard_information_attribute_index == -1 )
2058 	{
2059 		return( 0 );
2060 	}
2061 	if( libcdata_array_get_entry_by_index(
2062 	     mft_entry->attributes_array,
2063 	     mft_entry->standard_information_attribute_index,
2064 	     (intptr_t **) attribute,
2065 	     error ) != 1 )
2066 	{
2067 		libcerror_error_set(
2068 		 error,
2069 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2070 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2071 		 "%s: unable to retrieve entry: %d from attributes array.",
2072 		 function,
2073 		 mft_entry->standard_information_attribute_index );
2074 
2075 		return( -1 );
2076 	}
2077 	return( 1 );
2078 }
2079 
2080 /* Retrieves the $VOLUME_INFORMATION attribute
2081  * Returns 1 if successful, 0 if not available or -1 on error
2082  */
libfsntfs_mft_entry_get_volume_information_attribute(libfsntfs_mft_entry_t * mft_entry,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2083 int libfsntfs_mft_entry_get_volume_information_attribute(
2084      libfsntfs_mft_entry_t *mft_entry,
2085      libfsntfs_mft_attribute_t **attribute,
2086      libcerror_error_t **error )
2087 {
2088 	static char *function = "libfsntfs_mft_entry_get_volume_information_attribute";
2089 
2090 	if( mft_entry == NULL )
2091 	{
2092 		libcerror_error_set(
2093 		 error,
2094 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2095 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2096 		 "%s: invalid MFT entry.",
2097 		 function );
2098 
2099 		return( -1 );
2100 	}
2101 	if( mft_entry->volume_information_attribute_index == -1 )
2102 	{
2103 		return( 0 );
2104 	}
2105 	if( libcdata_array_get_entry_by_index(
2106 	     mft_entry->attributes_array,
2107 	     mft_entry->volume_information_attribute_index,
2108 	     (intptr_t **) attribute,
2109 	     error ) != 1 )
2110 	{
2111 		libcerror_error_set(
2112 		 error,
2113 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2114 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2115 		 "%s: unable to retrieve entry: %d from attributes array.",
2116 		 function,
2117 		 mft_entry->volume_information_attribute_index );
2118 
2119 		return( -1 );
2120 	}
2121 	return( 1 );
2122 }
2123 
2124 /* Retrieves the $VOLUME_NAME attribute
2125  * Returns 1 if successful, 0 if not available or -1 on error
2126  */
libfsntfs_mft_entry_get_volume_name_attribute(libfsntfs_mft_entry_t * mft_entry,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2127 int libfsntfs_mft_entry_get_volume_name_attribute(
2128      libfsntfs_mft_entry_t *mft_entry,
2129      libfsntfs_mft_attribute_t **attribute,
2130      libcerror_error_t **error )
2131 {
2132 	static char *function = "libfsntfs_mft_entry_get_volume_name_attribute";
2133 
2134 	if( mft_entry == NULL )
2135 	{
2136 		libcerror_error_set(
2137 		 error,
2138 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2139 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2140 		 "%s: invalid MFT entry.",
2141 		 function );
2142 
2143 		return( -1 );
2144 	}
2145 	if( mft_entry->volume_name_attribute_index == -1 )
2146 	{
2147 		return( 0 );
2148 	}
2149 	if( libcdata_array_get_entry_by_index(
2150 	     mft_entry->attributes_array,
2151 	     mft_entry->volume_name_attribute_index,
2152 	     (intptr_t **) attribute,
2153 	     error ) != 1 )
2154 	{
2155 		libcerror_error_set(
2156 		 error,
2157 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2158 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2159 		 "%s: unable to retrieve entry: %d from attributes array.",
2160 		 function,
2161 		 mft_entry->volume_name_attribute_index );
2162 
2163 		return( -1 );
2164 	}
2165 	return( 1 );
2166 }
2167 
2168 /* Retrieves the number of alternate data attributes
2169  * Returns 1 if successful or -1 on error
2170  */
libfsntfs_mft_entry_get_number_of_alternate_data_attributes(libfsntfs_mft_entry_t * mft_entry,int * number_of_attributes,libcerror_error_t ** error)2171 int libfsntfs_mft_entry_get_number_of_alternate_data_attributes(
2172      libfsntfs_mft_entry_t *mft_entry,
2173      int *number_of_attributes,
2174      libcerror_error_t **error )
2175 {
2176 	static char *function = "libfsntfs_mft_entry_get_number_of_alternate_data_attributes";
2177 
2178 	if( mft_entry == NULL )
2179 	{
2180 		libcerror_error_set(
2181 		 error,
2182 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2183 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2184 		 "%s: invalid MFT entry.",
2185 		 function );
2186 
2187 		return( -1 );
2188 	}
2189 	if( libcdata_array_get_number_of_entries(
2190 	     mft_entry->alternate_data_attributes_array,
2191 	     number_of_attributes,
2192 	     error ) != 1 )
2193 	{
2194 		libcerror_error_set(
2195 		 error,
2196 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2197 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2198 		 "%s: unable to retrieve number of entries from alternate data attributes array.",
2199 		 function );
2200 
2201 		return( -1 );
2202 	}
2203 	return( 1 );
2204 }
2205 
2206 /* Retrieves a specific alternate data attribute
2207  * Returns 1 if successful or -1 on error
2208  */
libfsntfs_mft_entry_get_alternate_data_attribute_by_index(libfsntfs_mft_entry_t * mft_entry,int attribute_index,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2209 int libfsntfs_mft_entry_get_alternate_data_attribute_by_index(
2210      libfsntfs_mft_entry_t *mft_entry,
2211      int attribute_index,
2212      libfsntfs_mft_attribute_t **attribute,
2213      libcerror_error_t **error )
2214 {
2215 	static char *function = "libfsntfs_mft_entry_get_alternate_data_attribute_by_index";
2216 
2217 	if( mft_entry == NULL )
2218 	{
2219 		libcerror_error_set(
2220 		 error,
2221 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2222 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2223 		 "%s: invalid MFT entry.",
2224 		 function );
2225 
2226 		return( -1 );
2227 	}
2228 	if( libcdata_array_get_entry_by_index(
2229 	     mft_entry->alternate_data_attributes_array,
2230 	     attribute_index,
2231 	     (intptr_t **) attribute,
2232 	     error ) != 1 )
2233 	{
2234 		libcerror_error_set(
2235 		 error,
2236 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2237 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2238 		 "%s: unable to retrieve entry: %d from alternate data attributes array.",
2239 		 function,
2240 		 attribute_index );
2241 
2242 		return( -1 );
2243 	}
2244 	return( 1 );
2245 }
2246 
2247 /* Retrieves a specific alternate data attribute for an UTF-8 encoded name
2248  * Returns 1 if successful, 0 if no such alternate data attribute or -1 on error
2249  */
libfsntfs_mft_entry_get_alternate_data_attribute_by_utf8_name(libfsntfs_mft_entry_t * mft_entry,const uint8_t * utf8_string,size_t utf8_string_length,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2250 int libfsntfs_mft_entry_get_alternate_data_attribute_by_utf8_name(
2251      libfsntfs_mft_entry_t *mft_entry,
2252      const uint8_t *utf8_string,
2253      size_t utf8_string_length,
2254      libfsntfs_mft_attribute_t **attribute,
2255      libcerror_error_t **error )
2256 {
2257 	static char *function    = "libfsntfs_mft_entry_get_alternate_data_attribute_by_utf8_name";
2258 	int attribute_index      = 0;
2259 	int number_of_attributes = 0;
2260 	int result               = 0;
2261 
2262 	if( mft_entry == NULL )
2263 	{
2264 		libcerror_error_set(
2265 		 error,
2266 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2267 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2268 		 "%s: invalid MFT entry.",
2269 		 function );
2270 
2271 		return( -1 );
2272 	}
2273 	if( attribute == NULL )
2274 	{
2275 		libcerror_error_set(
2276 		 error,
2277 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2278 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2279 		 "%s: invalid attribute.",
2280 		 function );
2281 
2282 		return( -1 );
2283 	}
2284 	if( libcdata_array_get_number_of_entries(
2285 	     mft_entry->alternate_data_attributes_array,
2286 	     &number_of_attributes,
2287 	     error ) != 1 )
2288 	{
2289 		libcerror_error_set(
2290 		 error,
2291 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2292 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2293 		 "%s: unable to retrieve number of entries from alternate data attributes array.",
2294 		 function );
2295 
2296 		return( -1 );
2297 	}
2298 	for( attribute_index = 0;
2299 	     attribute_index < number_of_attributes;
2300 	     attribute_index++ )
2301 	{
2302 		if( libcdata_array_get_entry_by_index(
2303 		     mft_entry->alternate_data_attributes_array,
2304 		     attribute_index,
2305 		     (intptr_t **) attribute,
2306 		     error ) != 1 )
2307 		{
2308 			libcerror_error_set(
2309 			 error,
2310 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2311 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2312 			 "%s: unable to retrieve entry: %d from alternative data attributes array.",
2313 			 function,
2314 			 attribute_index );
2315 
2316 			return( -1 );
2317 		}
2318 		result = libfsntfs_mft_attribute_compare_name_with_utf8_string(
2319 		          *attribute,
2320 		          utf8_string,
2321 		          utf8_string_length,
2322 		          error );
2323 
2324 		if( result == -1 )
2325 		{
2326 			libcerror_error_set(
2327 			 error,
2328 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2329 			 LIBCERROR_RUNTIME_ERROR_GENERIC,
2330 			 "%s: unable to compare UTF-8 string with alternative data attribute name.",
2331 			 function );
2332 
2333 			goto on_error;
2334 		}
2335 		else if( result == 1 )
2336 		{
2337 			return( 1 );
2338 		}
2339 	}
2340 	*attribute = NULL;
2341 
2342 	return( 0 );
2343 
2344 on_error:
2345 	*attribute = NULL;
2346 
2347 	return( -1 );
2348 }
2349 
2350 /* Retrieves a specific alternate data attribute for an UTF-16 encoded name
2351  * Returns 1 if successful, 0 if no such alternate data attribute or -1 on error
2352  */
libfsntfs_mft_entry_get_alternate_data_attribute_by_utf16_name(libfsntfs_mft_entry_t * mft_entry,const uint16_t * utf16_string,size_t utf16_string_length,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2353 int libfsntfs_mft_entry_get_alternate_data_attribute_by_utf16_name(
2354      libfsntfs_mft_entry_t *mft_entry,
2355      const uint16_t *utf16_string,
2356      size_t utf16_string_length,
2357      libfsntfs_mft_attribute_t **attribute,
2358      libcerror_error_t **error )
2359 {
2360 	static char *function    = "libfsntfs_mft_entry_get_alternate_data_attribute_by_utf16_name";
2361 	int attribute_index      = 0;
2362 	int number_of_attributes = 0;
2363 	int result               = 0;
2364 
2365 	if( mft_entry == NULL )
2366 	{
2367 		libcerror_error_set(
2368 		 error,
2369 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2370 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2371 		 "%s: invalid MFT entry.",
2372 		 function );
2373 
2374 		return( -1 );
2375 	}
2376 	if( attribute == NULL )
2377 	{
2378 		libcerror_error_set(
2379 		 error,
2380 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2381 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2382 		 "%s: invalid attribute.",
2383 		 function );
2384 
2385 		return( -1 );
2386 	}
2387 	if( libcdata_array_get_number_of_entries(
2388 	     mft_entry->alternate_data_attributes_array,
2389 	     &number_of_attributes,
2390 	     error ) != 1 )
2391 	{
2392 		libcerror_error_set(
2393 		 error,
2394 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2395 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2396 		 "%s: unable to retrieve number of entries from alternate data attributes array.",
2397 		 function );
2398 
2399 		return( -1 );
2400 	}
2401 	for( attribute_index = 0;
2402 	     attribute_index < number_of_attributes;
2403 	     attribute_index++ )
2404 	{
2405 		if( libcdata_array_get_entry_by_index(
2406 		     mft_entry->alternate_data_attributes_array,
2407 		     attribute_index,
2408 		     (intptr_t **) attribute,
2409 		     error ) != 1 )
2410 		{
2411 			libcerror_error_set(
2412 			 error,
2413 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2414 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2415 			 "%s: unable to retrieve entry: %d from alternative data attributes array.",
2416 			 function,
2417 			 attribute_index );
2418 
2419 			return( -1 );
2420 		}
2421 		result = libfsntfs_mft_attribute_compare_name_with_utf16_string(
2422 		          *attribute,
2423 		          utf16_string,
2424 		          utf16_string_length,
2425 		          error );
2426 
2427 		if( result == -1 )
2428 		{
2429 			libcerror_error_set(
2430 			 error,
2431 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2432 			 LIBCERROR_RUNTIME_ERROR_GENERIC,
2433 			 "%s: unable to compare UTF-16 string with alternative data attribute name.",
2434 			 function );
2435 
2436 			goto on_error;
2437 		}
2438 		else if( result == 1 )
2439 		{
2440 			return( 1 );
2441 		}
2442 	}
2443 	*attribute = NULL;
2444 
2445 	return( 0 );
2446 
2447 on_error:
2448 	*attribute = NULL;
2449 
2450 	return( -1 );
2451 }
2452 
2453 /* Sets the attribute helper values for an attribute
2454  * Returns 1 if successful or -1 on error
2455  */
libfsntfs_mft_entry_set_attribute_helper_values(libfsntfs_mft_entry_t * mft_entry,int attribute_index,libfsntfs_mft_attribute_t * attribute,libcerror_error_t ** error)2456 int libfsntfs_mft_entry_set_attribute_helper_values(
2457      libfsntfs_mft_entry_t *mft_entry,
2458      int attribute_index,
2459      libfsntfs_mft_attribute_t *attribute,
2460      libcerror_error_t **error )
2461 {
2462 	uint8_t utf8_attribute_name[ 64 ];
2463 
2464 	static char *function                                                = "libfsntfs_mft_entry_set_attribute_helper_values";
2465 	size_t utf8_attribute_name_size                                      = 0;
2466 	uint32_t attribute_type                                              = 0;
2467 	int result                                                           = 0;
2468 
2469 #if defined( HAVE_DEBUG_OUTPUT )
2470 	libfsntfs_standard_information_values_t *standard_information_values = NULL;
2471 #endif
2472 
2473 	if( mft_entry == NULL )
2474 	{
2475 		libcerror_error_set(
2476 		 error,
2477 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2478 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2479 		 "%s: invalid MFT entry.",
2480 		 function );
2481 
2482 		return( -1 );
2483 	}
2484 	if( libfsntfs_mft_attribute_get_utf8_name_size(
2485 	     attribute,
2486 	     &utf8_attribute_name_size,
2487 	     error ) != 1 )
2488 	{
2489 		libcerror_error_set(
2490 		 error,
2491 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2492 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2493 		 "%s: unable to retrieve UTF-8 attribute name size.",
2494 		 function );
2495 
2496 		return( -1 );
2497 	}
2498 	if( libfsntfs_mft_attribute_get_type(
2499 	     attribute,
2500 	     &attribute_type,
2501 	     error ) != 1 )
2502 	{
2503 		libcerror_error_set(
2504 		 error,
2505 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2506 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2507 		 "%s: unable to retrieve attribute type.",
2508 		 function );
2509 
2510 		return( -1 );
2511 	}
2512 	switch( attribute_type )
2513 	{
2514 		case LIBFSNTFS_ATTRIBUTE_TYPE_DATA:
2515 			if( libfsntfs_mft_entry_set_data_attribute_helper_values(
2516 			     mft_entry,
2517 			     attribute,
2518 			     error ) != 1 )
2519 			{
2520 				libcerror_error_set(
2521 				 error,
2522 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2523 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2524 				 "%s: unable to set data attribute helper values.",
2525 				 function );
2526 
2527 				return( -1 );
2528 			}
2529 			break;
2530 
2531 		case LIBFSNTFS_ATTRIBUTE_TYPE_FILE_NAME:
2532 			if( mft_entry->file_name_attribute_index == -1 )
2533 			{
2534 				mft_entry->file_name_attribute_index = attribute_index;
2535 			}
2536 			break;
2537 
2538 		case LIBFSNTFS_ATTRIBUTE_TYPE_INDEX_ROOT:
2539 			if( libfsntfs_mft_attribute_get_utf8_name(
2540 			     attribute,
2541 			     utf8_attribute_name,
2542 			     64,
2543 			     error ) != 1 )
2544 			{
2545 				libcerror_error_set(
2546 				 error,
2547 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2548 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2549 				 "%s: unable to retrieve UTF-8 attribute name.",
2550 				 function );
2551 
2552 				return( -1 );
2553 			}
2554 			result = libuna_utf8_string_compare_with_utf8_stream(
2555 			          utf8_attribute_name,
2556 			          utf8_attribute_name_size,
2557 			          (uint8_t *) "$I30",
2558 			          4,
2559 			          error );
2560 
2561 			if( result == -1 )
2562 			{
2563 				libcerror_error_set(
2564 				 error,
2565 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2566 				 LIBCERROR_RUNTIME_ERROR_GENERIC,
2567 				 "%s: unable to compare UTF-8 string with $I30.",
2568 				 function );
2569 
2570 				return( -1 );
2571 			}
2572 			else if( result == LIBUNA_COMPARE_EQUAL )
2573 			{
2574 				mft_entry->has_i30_index = 1;
2575 			}
2576 			break;
2577 
2578 		case LIBFSNTFS_ATTRIBUTE_TYPE_REPARSE_POINT:
2579 			/* Assume only one reparse point attribute per MFT entry is allowed
2580 			 */
2581 			if( mft_entry->reparse_point_attribute_index != -1 )
2582 			{
2583 				libcerror_error_set(
2584 				 error,
2585 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2586 				 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2587 				 "%s: invalid MFT entry - reparse point attribute index value already set.",
2588 				 function );
2589 
2590 				return( -1 );
2591 			}
2592 			mft_entry->reparse_point_attribute_index = attribute_index;
2593 
2594 			break;
2595 
2596 		case LIBFSNTFS_ATTRIBUTE_TYPE_SECURITY_DESCRIPTOR:
2597 			/* Assume only one security descriptor attribute per MFT entry is allowed
2598 			 */
2599 			if( mft_entry->security_descriptor_attribute_index != -1 )
2600 			{
2601 				libcerror_error_set(
2602 				 error,
2603 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2604 				 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2605 				 "%s: invalid MFT entry - security descriptor attribute index value already set.",
2606 				 function );
2607 
2608 				return( -1 );
2609 			}
2610 			mft_entry->security_descriptor_attribute_index = attribute_index;
2611 
2612 			break;
2613 
2614 		case LIBFSNTFS_ATTRIBUTE_TYPE_STANDARD_INFORMATION:
2615 #if defined( HAVE_DEBUG_OUTPUT )
2616 			if( libfsntfs_standard_information_values_initialize(
2617 			     &standard_information_values,
2618 			     error ) != 1 )
2619 			{
2620 				libcerror_error_set(
2621 				 error,
2622 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2623 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2624 				 "%s: unable to create standard information values.",
2625 				 function );
2626 
2627 				return( -1 );
2628 			}
2629 			if( libfsntfs_standard_information_values_read_from_mft_attribute(
2630 			     standard_information_values,
2631 			     attribute,
2632 			     error ) != 1 )
2633 			{
2634 				libcerror_error_set(
2635 				 error,
2636 				 LIBCERROR_ERROR_DOMAIN_IO,
2637 				 LIBCERROR_IO_ERROR_READ_FAILED,
2638 				 "%s: unable to read standard information values from MFT attribute.",
2639 				 function );
2640 
2641 				libfsntfs_standard_information_values_free(
2642 				 &standard_information_values,
2643 				 NULL );
2644 
2645 				return( -1 );
2646 			}
2647 			if( libfsntfs_standard_information_values_free(
2648 			     &standard_information_values,
2649 			     error ) != 1 )
2650 			{
2651 				libcerror_error_set(
2652 				 error,
2653 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2654 				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2655 				 "%s: unable to free standard information values.",
2656 				 function );
2657 
2658 				return( -1 );
2659 			}
2660 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
2661 
2662 			/* Assume only one standard information attribute per MFT entry is allowed
2663 			 */
2664 			if( mft_entry->standard_information_attribute_index != -1 )
2665 			{
2666 				libcerror_error_set(
2667 				 error,
2668 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2669 				 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2670 				 "%s: invalid MFT entry - standard information attribute index value already set.",
2671 				 function );
2672 
2673 				return( -1 );
2674 			}
2675 			mft_entry->standard_information_attribute_index = attribute_index;
2676 
2677 			break;
2678 
2679 		case LIBFSNTFS_ATTRIBUTE_TYPE_VOLUME_INFORMATION:
2680 			/* Assume only one volume information attribute per MFT entry is allowed
2681 			 */
2682 			if( mft_entry->volume_information_attribute_index != -1 )
2683 			{
2684 				libcerror_error_set(
2685 				 error,
2686 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2687 				 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2688 				 "%s: invalid MFT entry - volume information attribute index value already set.",
2689 				 function );
2690 
2691 				return( -1 );
2692 			}
2693 			mft_entry->volume_information_attribute_index = attribute_index;
2694 
2695 			break;
2696 
2697 		case LIBFSNTFS_ATTRIBUTE_TYPE_VOLUME_NAME:
2698 			/* Assume only one volume name attribute per MFT entry is allowed
2699 			 */
2700 			if( mft_entry->volume_name_attribute_index != -1 )
2701 			{
2702 				libcerror_error_set(
2703 				 error,
2704 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2705 				 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
2706 				 "%s: invalid MFT entry - volume name attribute index value already set.",
2707 				 function );
2708 
2709 				return( -1 );
2710 			}
2711 			mft_entry->volume_name_attribute_index = attribute_index;
2712 
2713 			break;
2714 
2715 		default:
2716 			break;
2717 	}
2718 	return( 1 );
2719 }
2720 
2721 /* Sets the attribute helper values for a $DATA attribute
2722  * Returns 1 if successful or -1 on error
2723  */
libfsntfs_mft_entry_set_data_attribute_helper_values(libfsntfs_mft_entry_t * mft_entry,libfsntfs_mft_attribute_t * data_attribute,libcerror_error_t ** error)2724 int libfsntfs_mft_entry_set_data_attribute_helper_values(
2725      libfsntfs_mft_entry_t *mft_entry,
2726      libfsntfs_mft_attribute_t *data_attribute,
2727      libcerror_error_t **error )
2728 {
2729 	uint8_t utf8_attribute_name[ 64 ];
2730 
2731 	libfsntfs_mft_attribute_t *existing_data_attribute = NULL;
2732 	static char *function                              = "libfsntfs_mft_entry_set_data_attribute_helper_values";
2733 	size_t utf8_attribute_name_size                    = 0;
2734 	int attribute_index                                = 0;
2735 	int entry_index                                    = 0;
2736 	int result                                         = 0;
2737 
2738 	if( mft_entry == NULL )
2739 	{
2740 		libcerror_error_set(
2741 		 error,
2742 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2743 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2744 		 "%s: invalid MFT entry.",
2745 		 function );
2746 
2747 		return( -1 );
2748 	}
2749 	if( libfsntfs_mft_attribute_get_utf8_name_size(
2750 	     data_attribute,
2751 	     &utf8_attribute_name_size,
2752 	     error ) != 1 )
2753 	{
2754 		libcerror_error_set(
2755 		 error,
2756 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2757 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2758 		 "%s: unable to retrieve UTF-8 attribute name size.",
2759 		 function );
2760 
2761 		return( -1 );
2762 	}
2763 	if( utf8_attribute_name_size <= 1 )
2764 	{
2765 		if( libfsntfs_mft_attribute_append_to_chain(
2766 		     &( mft_entry->data_attribute ),
2767 		     data_attribute,
2768 		     error ) != 1 )
2769 		{
2770 			libcerror_error_set(
2771 			 error,
2772 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2773 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
2774 			 "%s: unable to chain attribute.",
2775 			 function );
2776 
2777 			return( -1 );
2778 		}
2779 	}
2780 	else
2781 	{
2782 		if( libfsntfs_mft_attribute_get_utf8_name(
2783 		     data_attribute,
2784 		     utf8_attribute_name,
2785 		     64,
2786 		     error ) != 1 )
2787 		{
2788 			libcerror_error_set(
2789 			 error,
2790 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2791 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2792 			 "%s: unable to retrieve UTF-8 attribute name.",
2793 			 function );
2794 
2795 			return( -1 );
2796 		}
2797 		result = libfsntfs_mft_entry_get_data_attribute_by_utf8_name(
2798 		          mft_entry,
2799 		          utf8_attribute_name,
2800 		          utf8_attribute_name_size,
2801 		          &attribute_index,
2802 		          &existing_data_attribute,
2803 		          error );
2804 
2805 		if( result == -1 )
2806 		{
2807 			libcerror_error_set(
2808 			 error,
2809 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2810 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2811 			 "%s: unable to retrieve data attribute.",
2812 			 function );
2813 
2814 			return( -1 );
2815 		}
2816 		else if( result == 0 )
2817 		{
2818 			if( libcdata_array_append_entry(
2819 			     mft_entry->alternate_data_attributes_array,
2820 			     &entry_index,
2821 			     (intptr_t *) data_attribute,
2822 			     error ) != 1 )
2823 			{
2824 				libcerror_error_set(
2825 				 error,
2826 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2827 				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
2828 				 "%s: unable to append alternate data attribute to array.",
2829 				 function );
2830 
2831 				return( -1 );
2832 			}
2833 			existing_data_attribute = data_attribute;
2834 		}
2835 		else
2836 		{
2837 			if( libfsntfs_mft_attribute_append_to_chain(
2838 			     &existing_data_attribute,
2839 			     data_attribute,
2840 			     error ) != 1 )
2841 			{
2842 				libcerror_error_set(
2843 				 error,
2844 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2845 				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
2846 				 "%s: unable to chain alternate data attribute.",
2847 				 function );
2848 
2849 				return( -1 );
2850 			}
2851 			if( libcdata_array_set_entry_by_index(
2852 			     mft_entry->alternate_data_attributes_array,
2853 			     attribute_index,
2854 			     (intptr_t *) existing_data_attribute,
2855 			     error ) != 1 )
2856 			{
2857 				libcerror_error_set(
2858 				 error,
2859 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2860 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2861 				 "%s: unable to append set data attribute: %d in array.",
2862 				 function,
2863 				 attribute_index );
2864 
2865 				return( -1 );
2866 			}
2867 		}
2868 		result = libfsntfs_mft_attribute_compare_name_with_utf8_string(
2869 		          data_attribute,
2870 		          (uint8_t *) "WofCompressedData",
2871 		          17,
2872 		          error );
2873 
2874 		if( result == -1 )
2875 		{
2876 			libcerror_error_set(
2877 			 error,
2878 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2879 			 LIBCERROR_RUNTIME_ERROR_GENERIC,
2880 			 "%s: unable to compare UTF-8 string with alternative data attribute name.",
2881 			 function );
2882 
2883 			return( -1 );
2884 		}
2885 		else if( result == 1 )
2886 		{
2887 			mft_entry->wof_compressed_data_attribute = existing_data_attribute;
2888 		}
2889 	}
2890 	return( 1 );
2891 }
2892 
2893 /* Retrieves a data attribute with the specified name
2894  * Returns 1 if successful, 0 if no attribute was found or -1 on error
2895  */
libfsntfs_mft_entry_get_data_attribute_by_utf8_name(libfsntfs_mft_entry_t * mft_entry,const uint8_t * utf8_string,size_t utf8_string_length,int * attribute_index,libfsntfs_mft_attribute_t ** attribute,libcerror_error_t ** error)2896 int libfsntfs_mft_entry_get_data_attribute_by_utf8_name(
2897      libfsntfs_mft_entry_t *mft_entry,
2898      const uint8_t *utf8_string,
2899      size_t utf8_string_length,
2900      int *attribute_index,
2901      libfsntfs_mft_attribute_t **attribute,
2902      libcerror_error_t **error )
2903 {
2904 	libfsntfs_mft_attribute_t *safe_attribute = NULL;
2905 	static char *function                     = "libfsntfs_mft_entry_get_data_attribute_by_utf8_name";
2906 	int number_of_attributes                  = 0;
2907 	int result                                = 0;
2908 	int safe_attribute_index                  = 0;
2909 
2910 	if( mft_entry == NULL )
2911 	{
2912 		libcerror_error_set(
2913 		 error,
2914 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2915 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2916 		 "%s: invalid MFT entry.",
2917 		 function );
2918 
2919 		return( -1 );
2920 	}
2921 	if( utf8_string == NULL )
2922 	{
2923 		libcerror_error_set(
2924 		 error,
2925 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2926 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2927 		 "%s: invalid UTF-8 string.",
2928 		 function );
2929 
2930 		return( -1 );
2931 	}
2932 	if( utf8_string_length > (size_t) ( SSIZE_MAX - 1 ) )
2933 	{
2934 		libcerror_error_set(
2935 		 error,
2936 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2937 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2938 		 "%s: invalid UTF-8 string length value exceeds maximum.",
2939 		 function );
2940 
2941 		return( -1 );
2942 	}
2943 	if( attribute_index == NULL )
2944 	{
2945 		libcerror_error_set(
2946 		 error,
2947 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2948 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2949 		 "%s: invalid attribute index.",
2950 		 function );
2951 
2952 		return( -1 );
2953 	}
2954 	if( attribute == NULL )
2955 	{
2956 		libcerror_error_set(
2957 		 error,
2958 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2959 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2960 		 "%s: invalid attribute.",
2961 		 function );
2962 
2963 		return( -1 );
2964 	}
2965 	if( libcdata_array_get_number_of_entries(
2966 	     mft_entry->alternate_data_attributes_array,
2967 	     &number_of_attributes,
2968 	     error ) != 1 )
2969 	{
2970 		libcerror_error_set(
2971 		 error,
2972 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2973 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2974 		 "%s: unable to retrieve number of alternate data attributes.",
2975 		 function );
2976 
2977 		return( -1 );
2978 	}
2979 	for( safe_attribute_index = 0;
2980 	     safe_attribute_index < number_of_attributes;
2981 	     safe_attribute_index++ )
2982 	{
2983 		if( libcdata_array_get_entry_by_index(
2984 		     mft_entry->alternate_data_attributes_array,
2985 		     safe_attribute_index,
2986 		     (intptr_t **) &safe_attribute,
2987 		     error ) != 1 )
2988 		{
2989 			libcerror_error_set(
2990 			 error,
2991 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2992 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2993 			 "%s: unable to retrieve alternate data attribute: %d.",
2994 			 function,
2995 			 safe_attribute_index );
2996 
2997 			return( -1 );
2998 		}
2999 		result = libfsntfs_mft_attribute_compare_name_with_utf8_string(
3000 		          safe_attribute,
3001 		          utf8_string,
3002 		          utf8_string_length,
3003 		          error );
3004 
3005 		if( result == -1 )
3006 		{
3007 			libcerror_error_set(
3008 			 error,
3009 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3010 			 LIBCERROR_RUNTIME_ERROR_GENERIC,
3011 			 "%s: unable to compare UTF-8 string with alternative data attribute: %d name.",
3012 			 function,
3013 			 safe_attribute_index );
3014 
3015 			return( -1 );
3016 		}
3017 		else if( result != 0 )
3018 		{
3019 			break;
3020 		}
3021 	}
3022 	if( result != 0 )
3023 	{
3024 		*attribute_index = safe_attribute_index;
3025 		*attribute       = safe_attribute;
3026 	}
3027 	else
3028 	{
3029 		*attribute_index = 0;
3030 		*attribute       = NULL;
3031 	}
3032 	return( result );
3033 }
3034 
3035 /* Determines if the file entry has the directory entries ($I30) index
3036  * Returns 1 if the default data stream, 0 if not or -1 on error
3037  */
libfsntfs_mft_entry_has_directory_entries_index(libfsntfs_mft_entry_t * mft_entry,libcerror_error_t ** error)3038 int libfsntfs_mft_entry_has_directory_entries_index(
3039      libfsntfs_mft_entry_t *mft_entry,
3040      libcerror_error_t **error )
3041 {
3042 	static char *function = "libfsntfs_mft_entry_has_directory_entries_index";
3043 
3044 	if( mft_entry == NULL )
3045 	{
3046 		libcerror_error_set(
3047 		 error,
3048 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3049 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3050 		 "%s: invalid MFT entry.",
3051 		 function );
3052 
3053 		return( -1 );
3054 	}
3055 	return( (int) mft_entry->has_i30_index );
3056 }
3057 
3058 /* Reads the MFT entry
3059  * Callback function for the MFT entry vector
3060  * Returns 1 if successful or -1 on error
3061  */
libfsntfs_mft_entry_read_element_data(intptr_t * data_handle LIBFSNTFS_ATTRIBUTE_UNUSED,libbfio_handle_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index LIBFSNTFS_ATTRIBUTE_UNUSED,off64_t element_data_offset,size64_t element_data_size,uint32_t element_flags LIBFSNTFS_ATTRIBUTE_UNUSED,uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,libcerror_error_t ** error)3062 int libfsntfs_mft_entry_read_element_data(
3063      intptr_t *data_handle LIBFSNTFS_ATTRIBUTE_UNUSED,
3064      libbfio_handle_t *file_io_handle,
3065      libfdata_vector_t *vector,
3066      libfdata_cache_t *cache,
3067      int element_index,
3068      int element_data_file_index LIBFSNTFS_ATTRIBUTE_UNUSED,
3069      off64_t element_data_offset,
3070      size64_t element_data_size,
3071      uint32_t element_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
3072      uint8_t read_flags LIBFSNTFS_ATTRIBUTE_UNUSED,
3073      libcerror_error_t **error )
3074 {
3075 	libfsntfs_mft_entry_t *mft_entry = NULL;
3076 	static char *function            = "libfsntfs_mft_entry_read_element_data";
3077 
3078 	LIBFSNTFS_UNREFERENCED_PARAMETER( data_handle )
3079 	LIBFSNTFS_UNREFERENCED_PARAMETER( element_data_file_index )
3080 	LIBFSNTFS_UNREFERENCED_PARAMETER( element_flags )
3081 	LIBFSNTFS_UNREFERENCED_PARAMETER( read_flags )
3082 
3083 #if ( SIZEOF_INT <= 4 )
3084 	if( element_index < 0 )
3085 #else
3086 	if( ( element_index < 0 )
3087 	 || ( (int64_t) element_index > (int64_t) UINT32_MAX ) )
3088 #endif
3089 	{
3090 		libcerror_error_set(
3091 		 error,
3092 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3093 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3094 		 "%s: invalid element index value out of bounds.",
3095 		 function );
3096 
3097 		return( -1 );
3098 	}
3099 	if( element_data_size > (size64_t) UINT32_MAX )
3100 	{
3101 		libcerror_error_set(
3102 		 error,
3103 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3104 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3105 		 "%s: invalid element data size value out of bounds.",
3106 		 function );
3107 
3108 		return( -1 );
3109 	}
3110 	if( libfsntfs_mft_entry_initialize(
3111 	     &mft_entry,
3112 	     error ) != 1 )
3113 	{
3114 		libcerror_error_set(
3115 		 error,
3116 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3117 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
3118 		 "%s: unable to create MFT entry.",
3119 		 function );
3120 
3121 		goto on_error;
3122 	}
3123 	if( libfsntfs_mft_entry_read_file_io_handle(
3124 	     mft_entry,
3125 	     file_io_handle,
3126 	     element_data_offset,
3127 	     (uint32_t) element_data_size,
3128 	     (uint32_t) element_index,
3129 	     error ) != 1 )
3130 	{
3131 		libcerror_error_set(
3132 		 error,
3133 		 LIBCERROR_ERROR_DOMAIN_IO,
3134 		 LIBCERROR_IO_ERROR_READ_FAILED,
3135 		 "%s: unable to read MFT entry: %d.",
3136 		 function,
3137 		 element_index );
3138 
3139 		goto on_error;
3140 	}
3141 	if( libfdata_vector_set_element_value_by_index(
3142 	     vector,
3143 	     (intptr_t *) file_io_handle,
3144 	     cache,
3145 	     element_index,
3146 	     (intptr_t *) mft_entry,
3147 	     (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_entry_free,
3148 	     LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
3149 	     error ) != 1 )
3150 	{
3151 		libcerror_error_set(
3152 		 error,
3153 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3154 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3155 		 "%s: unable to set MFT entry as element value.",
3156 		 function );
3157 
3158 		goto on_error;
3159 	}
3160 	return( 1 );
3161 
3162 on_error:
3163 	if( mft_entry != NULL )
3164 	{
3165 		libfsntfs_mft_entry_free(
3166 		 &mft_entry,
3167 		 NULL );
3168 	}
3169 	return( -1 );
3170 }
3171 
3172