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