1 /*
2  * Attribute list attribute ($ATTRIBUTE_LIST) 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 <memory.h>
24 #include <types.h>
25 
26 #include "libfsntfs_cluster_block.h"
27 #include "libfsntfs_cluster_block_stream.h"
28 #include "libfsntfs_definitions.h"
29 #include "libfsntfs_io_handle.h"
30 #include "libfsntfs_libbfio.h"
31 #include "libfsntfs_libcdata.h"
32 #include "libfsntfs_libcerror.h"
33 #include "libfsntfs_libcnotify.h"
34 #include "libfsntfs_libfcache.h"
35 #include "libfsntfs_libfdata.h"
36 #include "libfsntfs_mft_attribute.h"
37 #include "libfsntfs_mft_attribute_list.h"
38 #include "libfsntfs_mft_attribute_list_entry.h"
39 
40 #include "fsntfs_mft_attribute_list.h"
41 
42 /* Creates attribute list
43  * Make sure the value attribute_list is referencing, is set to NULL
44  * Returns 1 if successful or -1 on error
45  */
libfsntfs_mft_attribute_list_initialize(libfsntfs_mft_attribute_list_t ** attribute_list,uint64_t base_record_file_reference,libcerror_error_t ** error)46 int libfsntfs_mft_attribute_list_initialize(
47      libfsntfs_mft_attribute_list_t **attribute_list,
48      uint64_t base_record_file_reference,
49      libcerror_error_t **error )
50 {
51 	static char *function = "libfsntfs_mft_attribute_list_initialize";
52 
53 	if( attribute_list == NULL )
54 	{
55 		libcerror_error_set(
56 		 error,
57 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59 		 "%s: invalid attribute list.",
60 		 function );
61 
62 		return( -1 );
63 	}
64 	if( *attribute_list != NULL )
65 	{
66 		libcerror_error_set(
67 		 error,
68 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
69 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70 		 "%s: invalid attribute list value already set.",
71 		 function );
72 
73 		return( -1 );
74 	}
75 	*attribute_list = memory_allocate_structure(
76 	                   libfsntfs_mft_attribute_list_t );
77 
78 	if( *attribute_list == NULL )
79 	{
80 		libcerror_error_set(
81 		 error,
82 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
83 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84 		 "%s: unable to create attribute list.",
85 		 function );
86 
87 		goto on_error;
88 	}
89 	if( memory_set(
90 	     *attribute_list,
91 	     0,
92 	     sizeof( libfsntfs_mft_attribute_list_t ) ) == NULL )
93 	{
94 		libcerror_error_set(
95 		 error,
96 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
97 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
98 		 "%s: unable to clear attribute list.",
99 		 function );
100 
101 		memory_free(
102 		 *attribute_list );
103 
104 		*attribute_list = NULL;
105 
106 		return( -1 );
107 	}
108 	if( libcdata_array_initialize(
109 	     &( ( *attribute_list )->entries_array ),
110 	     0,
111 	     error ) != 1 )
112 	{
113 		libcerror_error_set(
114 		 error,
115 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
116 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
117 		 "%s: unable to create entries array.",
118 		 function );
119 
120 		goto on_error;
121 	}
122 	if( libcdata_array_initialize(
123 	     &( ( *attribute_list )->file_references_array ),
124 	     0,
125 	     error ) != 1 )
126 	{
127 		libcerror_error_set(
128 		 error,
129 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
130 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
131 		 "%s: unable to create file references array.",
132 		 function );
133 
134 		goto on_error;
135 	}
136 	( *attribute_list )->base_record_file_reference = base_record_file_reference;
137 
138 	return( 1 );
139 
140 on_error:
141 	if( *attribute_list != NULL )
142 	{
143 		if( ( *attribute_list )->entries_array != NULL )
144 		{
145 			libcdata_array_free(
146 			 &( ( *attribute_list )->entries_array ),
147 			 NULL,
148 			 NULL );
149 		}
150 		memory_free(
151 		 *attribute_list );
152 
153 		*attribute_list = NULL;
154 	}
155 	return( -1 );
156 }
157 
158 /* Frees attribute list
159  * Returns 1 if successful or -1 on error
160  */
libfsntfs_mft_attribute_list_free(libfsntfs_mft_attribute_list_t ** attribute_list,libcerror_error_t ** error)161 int libfsntfs_mft_attribute_list_free(
162      libfsntfs_mft_attribute_list_t **attribute_list,
163      libcerror_error_t **error )
164 {
165 	static char *function = "libfsntfs_mft_attribute_list_free";
166 	int result            = 1;
167 
168 	if( attribute_list == NULL )
169 	{
170 		libcerror_error_set(
171 		 error,
172 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
173 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
174 		 "%s: invalid attribute list.",
175 		 function );
176 
177 		return( -1 );
178 	}
179 	if( *attribute_list != NULL )
180 	{
181 		if( libcdata_array_free(
182 		     &( ( *attribute_list )->entries_array ),
183 		     (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_list_entry_free,
184 		     error ) != 1 )
185 		{
186 			libcerror_error_set(
187 			 error,
188 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
189 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
190 			 "%s: unable to free entries array.",
191 			 function );
192 
193 			result = -1;
194 		}
195 		if( libcdata_array_free(
196 		     &( ( *attribute_list )->file_references_array ),
197 		     (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_list_file_reference_free,
198 		     error ) != 1 )
199 		{
200 			libcerror_error_set(
201 			 error,
202 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
204 			 "%s: unable to free file references array.",
205 			 function );
206 
207 			result = -1;
208 		}
209 		memory_free(
210 		 *attribute_list );
211 
212 		*attribute_list = NULL;
213 	}
214 	return( result );
215 }
216 
217 /* Frees attribute list file reference
218  * Returns 1 if successful or -1 on error
219  */
libfsntfs_mft_attribute_list_file_reference_free(uint64_t ** file_reference,libcerror_error_t ** error)220 int libfsntfs_mft_attribute_list_file_reference_free(
221      uint64_t **file_reference,
222      libcerror_error_t **error )
223 {
224 	static char *function = "libfsntfs_mft_attribute_list_file_reference_free";
225 
226 	if( file_reference == NULL )
227 	{
228 		libcerror_error_set(
229 		 error,
230 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
231 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
232 		 "%s: invalid file reference.",
233 		 function );
234 
235 		return( -1 );
236 	}
237 	if( *file_reference != NULL )
238 	{
239 		memory_free(
240 		 *file_reference );
241 
242 		*file_reference = NULL;
243 	}
244 	return( 1 );
245 }
246 
247 /* Reads the attribute list
248  * Returns 1 if successful or -1 on error
249  */
libfsntfs_mft_attribute_list_read_data(libfsntfs_mft_attribute_list_t * attribute_list,const uint8_t * data,size_t data_size,libcerror_error_t ** error)250 int libfsntfs_mft_attribute_list_read_data(
251      libfsntfs_mft_attribute_list_t *attribute_list,
252      const uint8_t *data,
253      size_t data_size,
254      libcerror_error_t **error )
255 {
256 	libfsntfs_mft_attribute_list_entry_t *mft_attribute_list_entry = NULL;
257 	static char *function                                          = "libfsntfs_mft_attribute_list_read_data";
258 	size_t data_offset                                             = 0;
259 	int attribute_index                                            = 0;
260 	int entry_index                                                = 0;
261 
262 	if( attribute_list == NULL )
263 	{
264 		libcerror_error_set(
265 		 error,
266 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
267 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
268 		 "%s: invalid attribute list.",
269 		 function );
270 
271 		return( -1 );
272 	}
273 	if( data == NULL )
274 	{
275 		libcerror_error_set(
276 		 error,
277 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
278 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
279 		 "%s: invalid data.",
280 		 function );
281 
282 		return( -1 );
283 	}
284 	if( data_size > (size_t) SSIZE_MAX )
285 	{
286 		libcerror_error_set(
287 		 error,
288 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
289 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
290 		 "%s: invalid data size value out of bounds.",
291 		 function );
292 
293 		return( -1 );
294 	}
295 #if defined( HAVE_DEBUG_OUTPUT )
296 	if( libcnotify_verbose != 0 )
297 	{
298 		libcnotify_printf(
299 		 "%s: attribute list data:\n",
300 		 function );
301 		libcnotify_print_data(
302 		 data,
303 		 data_size,
304 		 0 );
305 	}
306 #endif
307 	while( data_offset < data_size )
308 	{
309 		if( libfsntfs_mft_attribute_list_entry_initialize(
310 		     &mft_attribute_list_entry,
311 		     error ) != 1 )
312 		{
313 			libcerror_error_set(
314 			 error,
315 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
316 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
317 			 "%s: unable to create MFT attribute list entry.",
318 			 function );
319 
320 			goto on_error;
321 		}
322 		if( libfsntfs_mft_attribute_list_entry_read_data(
323 		     mft_attribute_list_entry,
324 		     &( data[ data_offset ] ),
325 		     data_size,
326 		     error ) != 1 )
327 		{
328 			libcerror_error_set(
329 			 error,
330 			 LIBCERROR_ERROR_DOMAIN_IO,
331 			 LIBCERROR_IO_ERROR_READ_FAILED,
332 			 "%s: unable to read MFT attribute list entry: %d.",
333 			 function,
334 			 attribute_index );
335 
336 			goto on_error;
337 		}
338 		data_offset += mft_attribute_list_entry->size;
339 
340 		if( libcdata_array_append_entry(
341 		     attribute_list->entries_array,
342 		     &entry_index,
343 		     (intptr_t *) mft_attribute_list_entry,
344 		     error ) != 1 )
345 		{
346 			libcerror_error_set(
347 			 error,
348 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
349 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
350 			 "%s: unable to append MFT attribute list entry: %d to array.",
351 			 function,
352 			 attribute_index );
353 
354 			goto on_error;
355 		}
356 		mft_attribute_list_entry = NULL;
357 
358 		attribute_index++;
359 	}
360 #if defined( HAVE_DEBUG_OUTPUT )
361 	if( libcnotify_verbose != 0 )
362 	{
363 		if( data_offset < data_size )
364 		{
365 			libcnotify_printf(
366 			 "%s: alignment padding:\n",
367 			 function );
368 			libcnotify_print_data(
369 			 &( data[ data_offset ] ),
370 			 data_size - data_offset,
371 			 0 );
372 		}
373 	}
374 #endif
375 	return( 1 );
376 
377 on_error:
378 	if( mft_attribute_list_entry != NULL )
379 	{
380 		libfsntfs_mft_attribute_list_entry_free(
381 		 &mft_attribute_list_entry,
382 		 NULL );
383 	}
384 	return( -1 );
385 }
386 
387 /* Reads the attribute list
388  * Returns 1 if successful or -1 on error
389  */
libfsntfs_mft_attribute_list_read_from_attribute(libfsntfs_mft_attribute_list_t * attribute_list,libfsntfs_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfsntfs_mft_attribute_t * list_attribute,libcerror_error_t ** error)390 int libfsntfs_mft_attribute_list_read_from_attribute(
391      libfsntfs_mft_attribute_list_t *attribute_list,
392      libfsntfs_io_handle_t *io_handle,
393      libbfio_handle_t *file_io_handle,
394      libfsntfs_mft_attribute_t *list_attribute,
395      libcerror_error_t **error )
396 {
397 	uint8_t data[ sizeof( fsntfs_mft_attribute_list_entry_header_t ) + 256 ];
398 
399 	libfdata_stream_t *cluster_block_stream                        = NULL;
400 	libfsntfs_mft_attribute_list_entry_t *mft_attribute_list_entry = NULL;
401 	static char *function                                          = "libfsntfs_mft_attribute_list_read_from_attribute";
402 	size64_t data_size                                             = 0;
403 	ssize_t read_count                                             = 0;
404 	off64_t data_offset                                            = 0;
405 	int attribute_index                                            = 0;
406 	int entry_index                                                = 0;
407 
408 	if( attribute_list == NULL )
409 	{
410 		libcerror_error_set(
411 		 error,
412 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
413 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
414 		 "%s: invalid attribute list.",
415 		 function );
416 
417 		return( -1 );
418 	}
419 	if( libfsntfs_cluster_block_stream_initialize(
420 	     &cluster_block_stream,
421 	     io_handle,
422 	     list_attribute,
423 	     NULL,
424 	     0,
425 	     error ) != 1 )
426 	{
427 		libcerror_error_set(
428 		 error,
429 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
430 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
431 		 "%s: unable to create cluster block stream.",
432 		 function );
433 
434 		goto on_error;
435 	}
436 	if( libfdata_stream_get_size(
437 	     cluster_block_stream,
438 	     &data_size,
439 	     error ) != 1 )
440 	{
441 		libcerror_error_set(
442 		 error,
443 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
444 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
445 		 "%s: unable to retrieve size from cluster block stream.",
446 		 function );
447 
448 		goto on_error;
449 	}
450 	while( (size64_t) data_offset < data_size )
451 	{
452 		if( memory_set(
453 		     data,
454 		     0,
455 		     sizeof( fsntfs_mft_attribute_list_entry_header_t ) + 256 ) == NULL )
456 		{
457 			libcerror_error_set(
458 			 error,
459 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
460 			 LIBCERROR_MEMORY_ERROR_SET_FAILED,
461 			 "%s: unable to clear data.",
462 			 function );
463 
464 			goto on_error;
465 		}
466 		read_count = libfdata_stream_read_buffer_at_offset(
467 		              cluster_block_stream,
468 		              (intptr_t *) file_io_handle,
469 		              data,
470 		              sizeof( fsntfs_mft_attribute_list_entry_header_t ) + 256,
471 		              data_offset,
472 		              0,
473 		              error );
474 
475 		if( read_count < 0 )
476 		{
477 			libcerror_error_set(
478 			 error,
479 			 LIBCERROR_ERROR_DOMAIN_IO,
480 			 LIBCERROR_IO_ERROR_READ_FAILED,
481 			 "%s: unable to read attribute list entry: %d from cluster block stream at offset: %" PRIi64 " (0x%08" PRIx64 ").",
482 			 function,
483 			 attribute_index,
484 			 data_offset,
485 			 data_offset );
486 
487 			goto on_error;
488 		}
489 		if( libfsntfs_mft_attribute_list_entry_initialize(
490 		     &mft_attribute_list_entry,
491 		     error ) != 1 )
492 		{
493 			libcerror_error_set(
494 			 error,
495 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
496 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
497 			 "%s: unable to create attribute list entry: %d.",
498 			 function,
499 			 attribute_index );
500 
501 			goto on_error;
502 		}
503 		if( libfsntfs_mft_attribute_list_entry_read_data(
504 		     mft_attribute_list_entry,
505 		     data,
506 		     sizeof( fsntfs_mft_attribute_list_entry_header_t ) + 256,
507 		     error ) != 1 )
508 		{
509 			libcerror_error_set(
510 			 error,
511 			 LIBCERROR_ERROR_DOMAIN_IO,
512 			 LIBCERROR_IO_ERROR_READ_FAILED,
513 			 "%s: unable to read attribute list entry: %d.",
514 			 function,
515 			 attribute_index );
516 
517 			goto on_error;
518 		}
519 		data_offset += mft_attribute_list_entry->size;
520 
521 		if( libcdata_array_append_entry(
522 		     attribute_list->entries_array,
523 		     &entry_index,
524 		     (intptr_t *) mft_attribute_list_entry,
525 		     error ) != 1 )
526 		{
527 			libcerror_error_set(
528 			 error,
529 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
530 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
531 			 "%s: unable to append attribute list entry: %d to array.",
532 			 function,
533 			 attribute_index );
534 
535 			goto on_error;
536 		}
537 		mft_attribute_list_entry = NULL;
538 
539 		attribute_index++;
540 	}
541 	if( libfdata_stream_free(
542 	     &cluster_block_stream,
543 	     error ) != 1 )
544 	{
545 		libcerror_error_set(
546 		 error,
547 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
548 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
549 		 "%s: unable to free cluster block stream.",
550 		 function );
551 
552 		goto on_error;
553 	}
554 	return( 1 );
555 
556 on_error:
557 	if( mft_attribute_list_entry != NULL )
558 	{
559 		libfsntfs_mft_attribute_list_entry_free(
560 		 &mft_attribute_list_entry,
561 		 NULL );
562 	}
563 	if( cluster_block_stream != NULL )
564 	{
565 		libfdata_stream_free(
566 		 &cluster_block_stream,
567 		 NULL );
568 	}
569 	return( -1 );
570 }
571 
572 /* Retrieves the number of attribute list entries
573  * Returns 1 if successful or -1 on error
574  */
libfsntfs_mft_attribute_list_get_number_of_entries(libfsntfs_mft_attribute_list_t * attribute_list,int * number_of_entries,libcerror_error_t ** error)575 int libfsntfs_mft_attribute_list_get_number_of_entries(
576      libfsntfs_mft_attribute_list_t *attribute_list,
577      int *number_of_entries,
578      libcerror_error_t **error )
579 {
580 	static char *function = "libfsntfs_mft_attribute_list_get_number_of_entries";
581 
582 	if( attribute_list == NULL )
583 	{
584 		libcerror_error_set(
585 		 error,
586 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
587 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
588 		 "%s: invalid attribute list.",
589 		 function );
590 
591 		return( -1 );
592 	}
593 	if( libcdata_array_get_number_of_entries(
594 	     attribute_list->entries_array,
595 	     number_of_entries,
596 	     error ) != 1 )
597 	{
598 		libcerror_error_set(
599 		 error,
600 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
601 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
602 		 "%s: unable to retrieve number of entries from array.",
603 		 function );
604 
605 		return( -1 );
606 	}
607 	return( 1 );
608 }
609 
610 /* Retrieves a specific attribute list entry
611  * Returns 1 if successful or -1 on error
612  */
libfsntfs_mft_attribute_list_get_entry_by_index(libfsntfs_mft_attribute_list_t * attribute_list,int entry_index,libfsntfs_mft_attribute_list_entry_t ** mft_attribute_list_entry,libcerror_error_t ** error)613 int libfsntfs_mft_attribute_list_get_entry_by_index(
614      libfsntfs_mft_attribute_list_t *attribute_list,
615      int entry_index,
616      libfsntfs_mft_attribute_list_entry_t **mft_attribute_list_entry,
617      libcerror_error_t **error )
618 {
619 	static char *function = "libfsntfs_mft_entry_get_attribute_by_index";
620 
621 	if( attribute_list == NULL )
622 	{
623 		libcerror_error_set(
624 		 error,
625 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
626 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
627 		 "%s: invalid attribute list.",
628 		 function );
629 
630 		return( -1 );
631 	}
632 	if( libcdata_array_get_entry_by_index(
633 	     attribute_list->entries_array,
634 	     entry_index,
635 	     (intptr_t **) mft_attribute_list_entry,
636 	     error ) != 1 )
637 	{
638 		libcerror_error_set(
639 		 error,
640 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
641 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
642 		 "%s: unable to retrieve entry: %d from array.",
643 		 function,
644 		 entry_index );
645 
646 		return( -1 );
647 	}
648 	return( 1 );
649 }
650 
651 /* Compares attribute lists by their base record file reference
652  * Returns LIBCDATA_COMPARE_LESS, LIBCDATA_COMPARE_EQUAL, LIBCDATA_COMPARE_GREATER if successful or -1 on error
653  */
libfsntfs_mft_attribute_list_compare_by_base_record_file_reference(libfsntfs_mft_attribute_list_t * first_attribute_list,libfsntfs_mft_attribute_list_t * second_attribute_list,libcerror_error_t ** error)654 int libfsntfs_mft_attribute_list_compare_by_base_record_file_reference(
655      libfsntfs_mft_attribute_list_t *first_attribute_list,
656      libfsntfs_mft_attribute_list_t *second_attribute_list,
657      libcerror_error_t **error )
658 {
659 	static char *function           = "libfsntfs_mft_attribute_list_compare_by_base_record_file_reference";
660 	uint64_t first_mft_entry_index  = 0;
661 	uint64_t second_mft_entry_index = 0;
662 
663 	if( first_attribute_list == NULL )
664 	{
665 		libcerror_error_set(
666 		 error,
667 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
668 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
669 		 "%s: invalid first attribute list.",
670 		 function );
671 
672 		return( -1 );
673 	}
674 	if( second_attribute_list == NULL )
675 	{
676 		libcerror_error_set(
677 		 error,
678 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
679 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
680 		 "%s: invalid second attribute list.",
681 		 function );
682 
683 		return( -1 );
684 	}
685 	first_mft_entry_index  = first_attribute_list->base_record_file_reference & 0xffffffffffffUL;
686 	second_mft_entry_index = second_attribute_list->base_record_file_reference & 0xffffffffffffUL;
687 
688 	if( first_mft_entry_index < second_mft_entry_index )
689 	{
690 		return( LIBCDATA_COMPARE_LESS );
691 	}
692 	else if( first_mft_entry_index > second_mft_entry_index )
693 	{
694 		return( LIBCDATA_COMPARE_GREATER );
695 	}
696 	return( LIBCDATA_COMPARE_EQUAL );
697 }
698 
699 /* Retrieves the number of attribute list data file references
700  * Returns 1 if successful or -1 on error
701  */
libfsntfs_mft_attribute_list_get_number_of_file_references(libfsntfs_mft_attribute_list_t * attribute_list,int * number_of_file_references,libcerror_error_t ** error)702 int libfsntfs_mft_attribute_list_get_number_of_file_references(
703      libfsntfs_mft_attribute_list_t *attribute_list,
704      int *number_of_file_references,
705      libcerror_error_t **error )
706 {
707 	static char *function = "libfsntfs_mft_attribute_list_get_number_of_file_references";
708 
709 	if( attribute_list == NULL )
710 	{
711 		libcerror_error_set(
712 		 error,
713 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
714 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
715 		 "%s: invalid attribute list.",
716 		 function );
717 
718 		return( -1 );
719 	}
720 	if( libcdata_array_get_number_of_entries(
721 	     attribute_list->file_references_array,
722 	     number_of_file_references,
723 	     error ) != 1 )
724 	{
725 		libcerror_error_set(
726 		 error,
727 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
728 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
729 		 "%s: unable to retrieve number of entries from array.",
730 		 function );
731 
732 		return( -1 );
733 	}
734 	return( 1 );
735 }
736 
737 /* Retrieves a specific attribute list data file reference
738  * Returns 1 if successful or -1 on error
739  */
libfsntfs_mft_attribute_list_get_file_reference_by_index(libfsntfs_mft_attribute_list_t * attribute_list,int file_reference_index,uint64_t * file_reference,libcerror_error_t ** error)740 int libfsntfs_mft_attribute_list_get_file_reference_by_index(
741      libfsntfs_mft_attribute_list_t *attribute_list,
742      int file_reference_index,
743      uint64_t *file_reference,
744      libcerror_error_t **error )
745 {
746 	uint64_t *safe_file_reference = NULL;
747 	static char *function         = "libfsntfs_mft_attribute_list_get_file_reference_by_index";
748 
749 	if( attribute_list == NULL )
750 	{
751 		libcerror_error_set(
752 		 error,
753 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
754 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
755 		 "%s: invalid attribute list.",
756 		 function );
757 
758 		return( -1 );
759 	}
760 	if( file_reference == NULL )
761 	{
762 		libcerror_error_set(
763 		 error,
764 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
765 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
766 		 "%s: invalid file reference.",
767 		 function );
768 
769 		return( -1 );
770 	}
771 	if( libcdata_array_get_entry_by_index(
772 	     attribute_list->file_references_array,
773 	     file_reference_index,
774 	     (intptr_t **) &safe_file_reference,
775 	     error ) != 1 )
776 	{
777 		libcerror_error_set(
778 		 error,
779 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
780 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
781 		 "%s: unable to retrieve entry: %d from array.",
782 		 function,
783 		 file_reference_index );
784 
785 		return( -1 );
786 	}
787 	*file_reference = *safe_file_reference;
788 
789 	return( 1 );
790 }
791 
792 /* Compares attribute list data file references
793  * Returns LIBCDATA_COMPARE_LESS, LIBCDATA_COMPARE_EQUAL, LIBCDATA_COMPARE_GREATER if successful or -1 on error
794  */
libfsntfs_mft_attribute_list_compare_file_reference(uint64_t * first_file_reference,uint64_t * second_file_reference,libcerror_error_t ** error)795 int libfsntfs_mft_attribute_list_compare_file_reference(
796      uint64_t *first_file_reference,
797      uint64_t *second_file_reference,
798      libcerror_error_t **error )
799 {
800 	static char *function           = "libfsntfs_mft_attribute_list_compare_file_reference";
801 	uint64_t first_mft_entry_index  = 0;
802 	uint64_t second_mft_entry_index = 0;
803 
804 	if( first_file_reference == NULL )
805 	{
806 		libcerror_error_set(
807 		 error,
808 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
809 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
810 		 "%s: invalid first file reference.",
811 		 function );
812 
813 		return( -1 );
814 	}
815 	if( second_file_reference == NULL )
816 	{
817 		libcerror_error_set(
818 		 error,
819 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
820 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
821 		 "%s: invalid second file reference.",
822 		 function );
823 
824 		return( -1 );
825 	}
826 	first_mft_entry_index  = *first_file_reference & 0xffffffffffffUL;
827 	second_mft_entry_index = *second_file_reference & 0xffffffffffffUL;
828 
829 	if( first_mft_entry_index < second_mft_entry_index )
830 	{
831 		return( LIBCDATA_COMPARE_LESS );
832 	}
833 	else if( first_mft_entry_index > second_mft_entry_index )
834 	{
835 		return( LIBCDATA_COMPARE_GREATER );
836 	}
837 	return( LIBCDATA_COMPARE_EQUAL );
838 }
839 
840 /* Insert an attribute list data file reference
841  * Returns 1 if successful or -1 on error
842  */
libfsntfs_mft_attribute_list_insert_file_reference(libfsntfs_mft_attribute_list_t * attribute_list,uint64_t file_reference,libcerror_error_t ** error)843 int libfsntfs_mft_attribute_list_insert_file_reference(
844      libfsntfs_mft_attribute_list_t *attribute_list,
845      uint64_t file_reference,
846      libcerror_error_t **error )
847 {
848 	uint64_t *safe_file_reference = NULL;
849 	static char *function         = "libfsntfs_mft_attribute_list_insert_file_reference";
850 	int entry_index               = 0;
851 	int result                    = 0;
852 
853 	if( attribute_list == NULL )
854 	{
855 		libcerror_error_set(
856 		 error,
857 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
858 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
859 		 "%s: invalid attribute list.",
860 		 function );
861 
862 		return( -1 );
863 	}
864 	safe_file_reference = (uint64_t *) memory_allocate(
865 	                                    sizeof( uint64_t ) );
866 
867 	if( safe_file_reference == NULL )
868 	{
869 		libcerror_error_set(
870 		 error,
871 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
872 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
873 		 "%s: unable to create file reference.",
874 		 function );
875 
876 		goto on_error;
877 	}
878 	*safe_file_reference = file_reference;
879 
880 	result = libcdata_array_insert_entry(
881 	          attribute_list->file_references_array,
882 	          &entry_index,
883 	          (intptr_t *) safe_file_reference,
884 	          (int (*)(intptr_t *, intptr_t *, libcerror_error_t **)) &libfsntfs_mft_attribute_list_compare_file_reference,
885 	          LIBCDATA_INSERT_FLAG_UNIQUE_ENTRIES,
886 	          error );
887 
888 	if( result == -1 )
889 	{
890 		libcerror_error_set(
891 		 error,
892 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
893 		 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
894 		 "%s: unable to insert file reference in array.",
895 		 function );
896 
897 		goto on_error;
898 	}
899 	else if( result == 0 )
900 	{
901 		memory_free(
902 		 safe_file_reference );
903 	}
904 	return( 1 );
905 
906 on_error:
907 	if( safe_file_reference != NULL )
908 	{
909 		memory_free(
910 		 safe_file_reference );
911 	}
912 	return( -1 );
913 }
914 
915