1 /*
2 * MFT 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_definitions.h"
27 #include "libfsntfs_io_handle.h"
28 #include "libfsntfs_libbfio.h"
29 #include "libfsntfs_libcerror.h"
30 #include "libfsntfs_libfcache.h"
31 #include "libfsntfs_libfdata.h"
32 #include "libfsntfs_mft.h"
33 #include "libfsntfs_mft_attribute_list.h"
34 #include "libfsntfs_mft_entry.h"
35 #include "libfsntfs_types.h"
36
37 /* Creates a MFT
38 * Make sure the value mft is referencing, is set to NULL
39 * Returns 1 if successful or -1 on error
40 */
libfsntfs_mft_initialize(libfsntfs_mft_t ** mft,libfsntfs_io_handle_t * io_handle,size64_t mft_entry_size,uint8_t flags,libcerror_error_t ** error)41 int libfsntfs_mft_initialize(
42 libfsntfs_mft_t **mft,
43 libfsntfs_io_handle_t *io_handle,
44 size64_t mft_entry_size,
45 uint8_t flags,
46 libcerror_error_t **error )
47 {
48 static char *function = "libfsntfs_mft_initialize";
49
50 if( mft == NULL )
51 {
52 libcerror_error_set(
53 error,
54 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56 "%s: invalid MFT.",
57 function );
58
59 return( -1 );
60 }
61 if( *mft != NULL )
62 {
63 libcerror_error_set(
64 error,
65 LIBCERROR_ERROR_DOMAIN_RUNTIME,
66 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67 "%s: invalid MFT value already set.",
68 function );
69
70 return( -1 );
71 }
72 if( io_handle == NULL )
73 {
74 libcerror_error_set(
75 error,
76 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
77 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
78 "%s: invalid IO handle.",
79 function );
80
81 return( -1 );
82 }
83 *mft = memory_allocate_structure(
84 libfsntfs_mft_t );
85
86 if( *mft == NULL )
87 {
88 libcerror_error_set(
89 error,
90 LIBCERROR_ERROR_DOMAIN_MEMORY,
91 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
92 "%s: unable to create MFT.",
93 function );
94
95 goto on_error;
96 }
97 if( memory_set(
98 *mft,
99 0,
100 sizeof( libfsntfs_mft_t ) ) == NULL )
101 {
102 libcerror_error_set(
103 error,
104 LIBCERROR_ERROR_DOMAIN_MEMORY,
105 LIBCERROR_MEMORY_ERROR_SET_FAILED,
106 "%s: unable to clear MFT.",
107 function );
108
109 memory_free(
110 *mft );
111
112 *mft = NULL;
113
114 return( -1 );
115 }
116 if( libfdata_vector_initialize(
117 &( ( *mft )->mft_entry_vector ),
118 mft_entry_size,
119 (intptr_t *) io_handle,
120 NULL,
121 NULL,
122 (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_mft_entry_read_element_data,
123 NULL,
124 LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
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 MFT entry vector.",
132 function );
133
134 goto on_error;
135 }
136 if( libfcache_cache_initialize(
137 &( ( *mft )->mft_entry_cache ),
138 LIBFSNTFS_MAXIMUM_CACHE_ENTRIES_MFT_ENTRIES,
139 error ) != 1 )
140 {
141 libcerror_error_set(
142 error,
143 LIBCERROR_ERROR_DOMAIN_RUNTIME,
144 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
145 "%s: unable to create MFT entry cache.",
146 function );
147
148 goto on_error;
149 }
150 if( libfcache_cache_initialize(
151 &( ( *mft )->single_mft_entry_cache ),
152 1,
153 error ) != 1 )
154 {
155 libcerror_error_set(
156 error,
157 LIBCERROR_ERROR_DOMAIN_RUNTIME,
158 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
159 "%s: unable to create signle MFT entry cache.",
160 function );
161
162 goto on_error;
163 }
164 ( *mft )->io_handle = io_handle;
165 ( *mft )->flags = flags;
166
167 return( 1 );
168
169 on_error:
170 if( *mft != NULL )
171 {
172 if( ( *mft )->mft_entry_cache != NULL )
173 {
174 libfcache_cache_free(
175 &( ( *mft )->mft_entry_cache ),
176 NULL );
177 }
178 if( ( *mft )->mft_entry_vector != NULL )
179 {
180 libfdata_vector_free(
181 &( ( *mft )->mft_entry_vector ),
182 NULL );
183 }
184 memory_free(
185 *mft );
186
187 *mft = NULL;
188 }
189 return( -1 );
190 }
191
192 /* Frees a MFT
193 * Returns 1 if successful or -1 on error
194 */
libfsntfs_mft_free(libfsntfs_mft_t ** mft,libcerror_error_t ** error)195 int libfsntfs_mft_free(
196 libfsntfs_mft_t **mft,
197 libcerror_error_t **error )
198 {
199 static char *function = "libfsntfs_mft_free";
200 int result = 1;
201
202 if( mft == NULL )
203 {
204 libcerror_error_set(
205 error,
206 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
207 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
208 "%s: invalid MFT.",
209 function );
210
211 return( -1 );
212 }
213 if( *mft != NULL )
214 {
215 if( libfdata_vector_free(
216 &( ( *mft )->mft_entry_vector ),
217 error ) != 1 )
218 {
219 libcerror_error_set(
220 error,
221 LIBCERROR_ERROR_DOMAIN_RUNTIME,
222 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
223 "%s: unable to free MFT entry vector.",
224 function );
225
226 result = -1;
227 }
228 if( libfcache_cache_free(
229 &( ( *mft )->mft_entry_cache ),
230 error ) != 1 )
231 {
232 libcerror_error_set(
233 error,
234 LIBCERROR_ERROR_DOMAIN_RUNTIME,
235 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
236 "%s: unable to free MFT entry cache.",
237 function );
238
239 result = -1;
240 }
241 if( libfcache_cache_free(
242 &( ( *mft )->single_mft_entry_cache ),
243 error ) != 1 )
244 {
245 libcerror_error_set(
246 error,
247 LIBCERROR_ERROR_DOMAIN_RUNTIME,
248 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
249 "%s: unable to free single MFT entry cache.",
250 function );
251
252 result = -1;
253 }
254 if( ( *mft )->attribute_list_tree != NULL )
255 {
256 if( libcdata_btree_free(
257 &( ( *mft )->attribute_list_tree ),
258 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_list_free,
259 error ) != 1 )
260 {
261 libcerror_error_set(
262 error,
263 LIBCERROR_ERROR_DOMAIN_RUNTIME,
264 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
265 "%s: unable to free attribute list tree.",
266 function );
267
268 result = -1;
269 }
270 }
271 memory_free(
272 *mft );
273
274 *mft = NULL;
275 }
276 return( result );
277 }
278
279 /* Reads the attribute list data MFT entries
280 * Returns 1 if successful or -1 on error
281 */
libfsntfs_mft_read_list_data_mft_entries(libfsntfs_mft_t * mft,libbfio_handle_t * file_io_handle,libcerror_error_t ** error)282 int libfsntfs_mft_read_list_data_mft_entries(
283 libfsntfs_mft_t *mft,
284 libbfio_handle_t *file_io_handle,
285 libcerror_error_t **error )
286 {
287 libcdata_tree_node_t *upper_node = NULL;
288 libfsntfs_mft_attribute_list_t *attribute_list = NULL;
289 libfsntfs_mft_attribute_list_t *existing_attribute_list = NULL;
290 libfsntfs_mft_entry_t *mft_entry = NULL;
291 static char *function = "libfsntfs_mft_read_list_data_mft_entries";
292 uint64_t base_record_file_reference = 0;
293 uint64_t file_reference = 0;
294 uint64_t mft_entry_index = 0;
295 int result = 0;
296 int value_index = 0;
297
298 if( mft == NULL )
299 {
300 libcerror_error_set(
301 error,
302 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
303 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
304 "%s: invalid MFT.",
305 function );
306
307 return( -1 );
308 }
309 if( mft->attribute_list_tree != NULL )
310 {
311 libcerror_error_set(
312 error,
313 LIBCERROR_ERROR_DOMAIN_RUNTIME,
314 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
315 "%s: invalid MFT - attribute list tree value already set.",
316 function );
317
318 return( -1 );
319 }
320 if( libcdata_btree_initialize(
321 &( mft->attribute_list_tree ),
322 LIBFSNTFS_INDEX_TREE_MAXIMUM_NUMBER_OF_SUB_NODES,
323 error ) != 1 )
324 {
325 libcerror_error_set(
326 error,
327 LIBCERROR_ERROR_DOMAIN_RUNTIME,
328 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
329 "%s: unable to create attribute list B-tree.",
330 function );
331
332 goto on_error;
333 }
334 for( mft_entry_index = 0;
335 mft_entry_index < mft->number_of_mft_entries;
336 mft_entry_index++ )
337 {
338 if( libfdata_vector_get_element_value_by_index(
339 mft->mft_entry_vector,
340 (intptr_t *) file_io_handle,
341 (libfdata_cache_t *) mft->mft_entry_cache,
342 (int) mft_entry_index,
343 (intptr_t **) &mft_entry,
344 0,
345 error ) != 1 )
346 {
347 libcerror_error_set(
348 error,
349 LIBCERROR_ERROR_DOMAIN_RUNTIME,
350 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
351 "%s: unable to retrieve MFT entry: %" PRIu64 ".",
352 function,
353 mft_entry_index );
354
355 goto on_error;
356 }
357 result = libfsntfs_mft_entry_get_base_record_file_reference(
358 mft_entry,
359 &base_record_file_reference,
360 error );
361
362 if( result == -1 )
363 {
364 libcerror_error_set(
365 error,
366 LIBCERROR_ERROR_DOMAIN_RUNTIME,
367 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
368 "%s: unable to retrieve base record file reference from MFT entry: %" PRIu64 ".",
369 function,
370 mft_entry_index );
371
372 goto on_error;
373 }
374 if( ( result == 0 )
375 || ( base_record_file_reference == 0 ) )
376 {
377 continue;
378 }
379 if( libfsntfs_mft_attribute_list_initialize(
380 &attribute_list,
381 base_record_file_reference,
382 error ) != 1 )
383 {
384 libcerror_error_set(
385 error,
386 LIBCERROR_ERROR_DOMAIN_RUNTIME,
387 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
388 "%s: unable to create attribute list.",
389 function );
390
391 goto on_error;
392 }
393 result = libcdata_btree_insert_value(
394 mft->attribute_list_tree,
395 &value_index,
396 (intptr_t *) attribute_list,
397 (int (*)(intptr_t *, intptr_t *, libcerror_error_t **)) &libfsntfs_mft_attribute_list_compare_by_base_record_file_reference,
398 &upper_node,
399 (intptr_t **) &existing_attribute_list,
400 error );
401
402 if( result == -1 )
403 {
404 libcerror_error_set(
405 error,
406 LIBCERROR_ERROR_DOMAIN_RUNTIME,
407 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
408 "%s: unable to insert attribute list into tree.",
409 function );
410
411 goto on_error;
412 }
413 else if( result == 0 )
414 {
415 if( libfsntfs_mft_attribute_list_free(
416 &attribute_list,
417 error ) != 1 )
418 {
419 libcerror_error_set(
420 error,
421 LIBCERROR_ERROR_DOMAIN_RUNTIME,
422 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
423 "%s: unable to free attribute list.",
424 function );
425
426 goto on_error;
427 }
428 }
429 else
430 {
431 existing_attribute_list = attribute_list;
432
433 attribute_list = NULL;
434 }
435 if( libfsntfs_mft_entry_get_file_reference(
436 mft_entry,
437 &file_reference,
438 error ) != 1 )
439 {
440 libcerror_error_set(
441 error,
442 LIBCERROR_ERROR_DOMAIN_RUNTIME,
443 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
444 "%s: unable to retrieve file reference from MFT entry: %" PRIu64 ".",
445 function,
446 mft_entry_index );
447
448 goto on_error;
449 }
450 if( libfsntfs_mft_attribute_list_insert_file_reference(
451 existing_attribute_list,
452 file_reference,
453 error ) == -1 )
454 {
455 libcerror_error_set(
456 error,
457 LIBCERROR_ERROR_DOMAIN_RUNTIME,
458 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
459 "%s: unable to insert attribute list data file reference in attribute list.",
460 function );
461
462 goto on_error;
463 }
464 }
465 return( 1 );
466
467 on_error:
468 if( attribute_list != NULL )
469 {
470 libfsntfs_mft_attribute_list_free(
471 &attribute_list,
472 NULL );
473 }
474 if( mft->attribute_list_tree != NULL )
475 {
476 libcdata_btree_free(
477 &( mft->attribute_list_tree ),
478 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_mft_attribute_list_free,
479 NULL );
480 }
481 return( -1 );
482 }
483
484 /* Retrieves the number of MFT entries
485 * Returns 1 if successful or -1 on error
486 */
libfsntfs_mft_get_number_of_entries(libfsntfs_mft_t * mft,uint64_t * number_of_entries,libcerror_error_t ** error)487 int libfsntfs_mft_get_number_of_entries(
488 libfsntfs_mft_t *mft,
489 uint64_t *number_of_entries,
490 libcerror_error_t **error )
491 {
492 static char *function = "libfsntfs_mft_get_number_of_entries";
493
494 if( mft == NULL )
495 {
496 libcerror_error_set(
497 error,
498 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
499 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
500 "%s: invalid MFT.",
501 function );
502
503 return( -1 );
504 }
505 if( number_of_entries == NULL )
506 {
507 libcerror_error_set(
508 error,
509 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
510 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
511 "%s: invalid number of entries.",
512 function );
513
514 return( -1 );
515 }
516 *number_of_entries = mft->number_of_mft_entries;
517
518 return( 1 );
519 }
520
521 /* Retrieves the MFT entry for a specific index
522 * Returns 1 if successful or -1 on error
523 */
libfsntfs_mft_get_mft_entry_by_index(libfsntfs_mft_t * mft,libbfio_handle_t * file_io_handle,uint64_t mft_entry_index,libfsntfs_mft_entry_t ** mft_entry,libcerror_error_t ** error)524 int libfsntfs_mft_get_mft_entry_by_index(
525 libfsntfs_mft_t *mft,
526 libbfio_handle_t *file_io_handle,
527 uint64_t mft_entry_index,
528 libfsntfs_mft_entry_t **mft_entry,
529 libcerror_error_t **error )
530 {
531 libfsntfs_mft_entry_t *safe_mft_entry = NULL;
532 static char *function = "libfsntfs_mft_get_mft_entry_by_index";
533
534 if( mft == NULL )
535 {
536 libcerror_error_set(
537 error,
538 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
539 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
540 "%s: invalid MFT.",
541 function );
542
543 return( -1 );
544 }
545 if( mft_entry_index > mft->number_of_mft_entries )
546 {
547 libcerror_error_set(
548 error,
549 LIBCERROR_ERROR_DOMAIN_RUNTIME,
550 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
551 "%s: invalid MFT entry index value out of bounds.",
552 function );
553
554 return( -1 );
555 }
556 if( mft_entry == NULL )
557 {
558 libcerror_error_set(
559 error,
560 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
561 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
562 "%s: invalid MFT entry.",
563 function );
564
565 return( -1 );
566 }
567 if( libfdata_vector_get_element_value_by_index(
568 mft->mft_entry_vector,
569 (intptr_t *) file_io_handle,
570 (libfdata_cache_t *) mft->mft_entry_cache,
571 (int) mft_entry_index,
572 (intptr_t **) &safe_mft_entry,
573 0,
574 error ) != 1 )
575 {
576 libcerror_error_set(
577 error,
578 LIBCERROR_ERROR_DOMAIN_RUNTIME,
579 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
580 "%s: unable to retrieve MFT entry: %" PRIu64 ".",
581 function,
582 mft_entry_index );
583
584 return( -1 );
585 }
586 if( libfsntfs_mft_entry_read_attributes(
587 safe_mft_entry,
588 mft->io_handle,
589 file_io_handle,
590 mft->mft_entry_vector,
591 mft->attribute_list_tree,
592 mft->flags,
593 error ) != 1 )
594 {
595 libcerror_error_set(
596 error,
597 LIBCERROR_ERROR_DOMAIN_IO,
598 LIBCERROR_IO_ERROR_READ_FAILED,
599 "%s: unable to read MFT entry: %d attributes.",
600 function,
601 mft_entry_index );
602
603 return( -1 );
604 }
605 *mft_entry = safe_mft_entry;
606
607 return( 1 );
608 }
609
610 /* Retrieves the MFT entry for a specific index
611 * Returns 1 if successful or -1 on error
612 */
libfsntfs_mft_get_mft_entry_by_index_no_cache(libfsntfs_mft_t * mft,libbfio_handle_t * file_io_handle,uint64_t mft_entry_index,libfsntfs_mft_entry_t ** mft_entry,libcerror_error_t ** error)613 int libfsntfs_mft_get_mft_entry_by_index_no_cache(
614 libfsntfs_mft_t *mft,
615 libbfio_handle_t *file_io_handle,
616 uint64_t mft_entry_index,
617 libfsntfs_mft_entry_t **mft_entry,
618 libcerror_error_t **error )
619 {
620 libfsntfs_mft_entry_t *safe_mft_entry = NULL;
621 static char *function = "libfsntfs_mft_get_mft_entry_by_index_no_cache";
622
623 if( mft == NULL )
624 {
625 libcerror_error_set(
626 error,
627 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
628 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
629 "%s: invalid MFT.",
630 function );
631
632 return( -1 );
633 }
634 if( mft_entry_index > mft->number_of_mft_entries )
635 {
636 libcerror_error_set(
637 error,
638 LIBCERROR_ERROR_DOMAIN_RUNTIME,
639 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
640 "%s: invalid MFT entry index value out of bounds.",
641 function );
642
643 return( -1 );
644 }
645 if( mft_entry == NULL )
646 {
647 libcerror_error_set(
648 error,
649 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
650 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
651 "%s: invalid MFT entry.",
652 function );
653
654 return( -1 );
655 }
656 if( libfdata_vector_get_element_value_by_index(
657 mft->mft_entry_vector,
658 (intptr_t *) file_io_handle,
659 (libfdata_cache_t *) mft->single_mft_entry_cache,
660 (int) mft_entry_index,
661 (intptr_t **) &safe_mft_entry,
662 LIBFDATA_READ_FLAG_IGNORE_CACHE,
663 error ) != 1 )
664 {
665 libcerror_error_set(
666 error,
667 LIBCERROR_ERROR_DOMAIN_RUNTIME,
668 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
669 "%s: unable to retrieve MFT entry: %" PRIu64 ".",
670 function,
671 mft_entry_index );
672
673 return( -1 );
674 }
675 if( libfsntfs_mft_entry_read_attributes(
676 safe_mft_entry,
677 mft->io_handle,
678 file_io_handle,
679 mft->mft_entry_vector,
680 mft->attribute_list_tree,
681 mft->flags,
682 error ) != 1 )
683 {
684 libcerror_error_set(
685 error,
686 LIBCERROR_ERROR_DOMAIN_IO,
687 LIBCERROR_IO_ERROR_READ_FAILED,
688 "%s: unable to read MFT entry: %d attributes.",
689 function,
690 mft_entry_index );
691
692 return( -1 );
693 }
694 if( libfcache_cache_clear_value_by_index(
695 mft->single_mft_entry_cache,
696 0,
697 error ) != 1 )
698 {
699 libcerror_error_set(
700 error,
701 LIBCERROR_ERROR_DOMAIN_RUNTIME,
702 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
703 "%s: unable to clear single MFT entry cache entry: 0.",
704 function );
705
706 return( -1 );
707 }
708 *mft_entry = safe_mft_entry;
709
710 return( 1 );
711 }
712
713