1 /*
2  * Recover functions
3  *
4  * Copyright (C) 2008-2018, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This software 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 software 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 software.  If not, see <http://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 "libpff_data_block.h"
28 #include "libpff_definitions.h"
29 #include "libpff_descriptors_index.h"
30 #include "libpff_index.h"
31 #include "libpff_index_node.h"
32 #include "libpff_index_tree.h"
33 #include "libpff_index_value.h"
34 #include "libpff_item_descriptor.h"
35 #include "libpff_item_tree.h"
36 #include "libpff_io_handle.h"
37 #include "libpff_libbfio.h"
38 #include "libpff_libcerror.h"
39 #include "libpff_libcnotify.h"
40 #include "libpff_libfmapi.h"
41 #include "libpff_local_descriptor_node.h"
42 #include "libpff_offsets_index.h"
43 #include "libpff_recover.h"
44 
45 #include "pff_block.h"
46 #include "pff_index_node.h"
47 
48 /* Scans for recoverable items
49  * By default only the unallocated space is checked for recoverable items
50  * Returns 1 if successful or -1 on error
51  */
libpff_recover_items(libpff_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libpff_descriptors_index_t * descriptors_index,libpff_offsets_index_t * offsets_index,libcdata_range_list_t * unallocated_data_block_list,libcdata_range_list_t * unallocated_page_block_list,libcdata_list_t * recovered_item_list,uint8_t recovery_flags,libcerror_error_t ** error)52 int libpff_recover_items(
53      libpff_io_handle_t *io_handle,
54      libbfio_handle_t *file_io_handle,
55      libpff_descriptors_index_t *descriptors_index,
56      libpff_offsets_index_t *offsets_index,
57      libcdata_range_list_t *unallocated_data_block_list,
58      libcdata_range_list_t *unallocated_page_block_list,
59      libcdata_list_t *recovered_item_list,
60      uint8_t recovery_flags,
61      libcerror_error_t **error )
62 {
63 	libfdata_tree_node_t *recovered_descriptor_index_leaf_node = NULL;
64 	libpff_data_block_t *recovered_data_block                  = NULL;
65 	libpff_index_t *recovered_descriptor_index                 = NULL;
66 	libpff_index_t *recovered_offset_index                     = NULL;
67 	libpff_index_value_t *descriptor_index_value               = NULL;
68 	libpff_index_value_t *offset_index_value                   = NULL;
69 	libpff_item_descriptor_t *item_descriptor                  = NULL;
70 	libcdata_tree_node_t *item_tree_node                       = NULL;
71 	static char *function                                      = "libpff_recover_items";
72 	int data_identifier_value_index                            = 0;
73 	int index_value_iterator                                   = 0;
74 	int local_descriptors_identifier_value_index               = 0;
75 	int number_of_index_values                                 = 0;
76 	int number_of_recovered_descriptor_index_values            = 0;
77 	int recovered_descriptor_index_value_iterator              = 0;
78 	int recoverable                                            = 0;
79 	int result                                                 = 0;
80 
81 	if( io_handle == NULL )
82 	{
83 		libcerror_error_set(
84 		 error,
85 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
86 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
87 		 "%s: invalid IO handle.",
88 		 function );
89 
90 		return( -1 );
91 	}
92 	if( ( io_handle->file_type != LIBPFF_FILE_TYPE_32BIT )
93 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT )
94 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
95 	{
96 		libcerror_error_set(
97 		 error,
98 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
99 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
100 		 "%s: unsupported file type.",
101 		 function );
102 
103 		return( -1 );
104 	}
105 	if( recovered_item_list == NULL )
106 	{
107 		libcerror_error_set(
108 		 error,
109 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
110 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
111 		 "%s: invalid recovered item list.",
112 		 function );
113 
114 		return( -1 );
115 	}
116 	if( libpff_descriptors_index_set_root_node(
117 	     descriptors_index,
118 	     0,
119 	     0,
120 	     1,
121 	     error ) != 1 )
122 	{
123 		libcerror_error_set(
124 		 error,
125 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
126 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
127 		 "%s: unable to set descriptors index root node.",
128 		 function );
129 
130 		goto on_error;
131 	}
132 	if( libpff_offsets_index_set_root_node(
133 	     offsets_index,
134 	     0,
135 	     0,
136 	     1,
137 	     error ) != 1 )
138 	{
139 		libcerror_error_set(
140 		 error,
141 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
142 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
143 		 "%s: unable to set offsets index root node.",
144 		 function );
145 
146 		goto on_error;
147 	}
148 #if defined( HAVE_DEBUG_OUTPUT )
149 	if( libbfio_handle_set_track_offsets_read(
150 	     file_io_handle,
151 	     0,
152 	     error ) != 1 )
153 	{
154                 libcerror_error_set(
155                  error,
156                  LIBCERROR_ERROR_DOMAIN_RUNTIME,
157                  LIBCERROR_RUNTIME_ERROR_SET_FAILED,
158                  "%s: unable to set track offsets read in file IO handle.",
159                  function );
160 
161 		goto on_error;
162 	}
163 #endif
164 	if( libpff_recover_index_nodes(
165 	     io_handle,
166 	     file_io_handle,
167 	     descriptors_index,
168 	     error ) != 1 )
169 	{
170 		libcerror_error_set(
171 		 error,
172 		 LIBCERROR_ERROR_DOMAIN_IO,
173 		 LIBCERROR_IO_ERROR_READ_FAILED,
174 		 "%s: unable to recover index nodes.",
175 		 function );
176 
177 		goto on_error;
178 	}
179 	if( libpff_recover_data_blocks(
180 	     io_handle,
181 	     file_io_handle,
182 	     descriptors_index,
183 	     offsets_index,
184 	     unallocated_data_block_list,
185 	     unallocated_page_block_list,
186 	     recovery_flags,
187 	     error ) != 1 )
188 	{
189 		libcerror_error_set(
190 		 error,
191 		 LIBCERROR_ERROR_DOMAIN_IO,
192 		 LIBCERROR_IO_ERROR_READ_FAILED,
193 		 "%s: unable to recover data blocks.",
194 		 function );
195 
196 		goto on_error;
197 	}
198 	/* For the recovered descriptor index nodes check
199 	 * if the local descriptor and data offset index value still exists
200 	 */
201 	if( libfdata_tree_get_number_of_leaf_nodes(
202 	     descriptors_index->recovered_index_tree,
203 	     (intptr_t *) file_io_handle,
204 	     descriptors_index->index_cache,
205 	     &number_of_recovered_descriptor_index_values,
206 	     0,
207 	     error ) != 1 )
208 	{
209 		libcerror_error_set(
210 		 error,
211 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
212 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
213 		 "%s: unable to retrieve number of recovered descriptor index values.",
214 		 function );
215 
216 		goto on_error;
217 	}
218 	for( recovered_descriptor_index_value_iterator = 0;
219 	     recovered_descriptor_index_value_iterator < number_of_recovered_descriptor_index_values;
220 	     recovered_descriptor_index_value_iterator++ )
221 	{
222 		if( io_handle->abort != 0 )
223 		{
224 			goto on_error;
225 		}
226 		if( libfdata_tree_get_leaf_node_by_index(
227 		     descriptors_index->recovered_index_tree,
228 		     (intptr_t *) file_io_handle,
229 		     descriptors_index->index_cache,
230 		     recovered_descriptor_index_value_iterator,
231 		     &recovered_descriptor_index_leaf_node,
232 		     0,
233 		     error ) != 1 )
234 		{
235 			libcerror_error_set(
236 			 error,
237 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
238 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
239 			 "%s: unable to retrieve recovered descriptor leaf node: %d.",
240 			 function,
241 			 recovered_descriptor_index_value_iterator );
242 
243 			goto on_error;
244 		}
245 		if( libfdata_tree_node_get_node_value(
246 		     recovered_descriptor_index_leaf_node,
247 		     (intptr_t *) file_io_handle,
248 		     descriptors_index->index_cache,
249 		     (intptr_t **) &descriptor_index_value,
250 		     0,
251 		     error ) != 1 )
252 		{
253 			libcerror_error_set(
254 			 error,
255 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
256 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
257 			 "%s: unable to retrieve recovered descriptor index value: %d.",
258 			 function,
259 			 recovered_descriptor_index_value_iterator );
260 
261 			goto on_error;
262 		}
263 		if( descriptor_index_value == NULL )
264 		{
265 			libcerror_error_set(
266 			 error,
267 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
268 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
269 			 "%s: missing descriptor index value: %d.",
270 			 function,
271 			 recovered_descriptor_index_value_iterator );
272 
273 			goto on_error;
274 		}
275 #if defined( HAVE_DEBUG_OUTPUT )
276 		if( libcnotify_verbose != 0 )
277 		{
278 			libcnotify_printf(
279 			 "%s: analyzing identifier: %" PRIu64 ", data: %" PRIu64 ", local descriptors: %" PRIu64 ", parent: %" PRIu32 "\n",
280 			 function,
281 			 descriptor_index_value->identifier,
282 			 descriptor_index_value->data_identifier,
283 			 descriptor_index_value->local_descriptors_identifier,
284 			 descriptor_index_value->parent_identifier );
285 		}
286 #endif
287 		recoverable = 1;
288 
289 		/* Check if the data identifier is recoverable
290 		 */
291 		if( recoverable != 0 )
292 		{
293 			if( libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
294 			     offsets_index->recovered_index_tree,
295 			     file_io_handle,
296 			     offsets_index->index_cache,
297 			     descriptor_index_value->data_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK,
298 			     &number_of_index_values,
299 			     error ) != 1 )
300 			{
301 				libcerror_error_set(
302 				 error,
303 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
304 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
305 				 "%s: unable to retrieve number of recovered offset index values for data identifier: %" PRIu64 ".",
306 				 function,
307 				 descriptor_index_value->data_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK );
308 
309 				goto on_error;
310 			}
311 /* TODO what if more than 1 identifier is recoverable ? now uses first come first serve */
312 			result = 0;
313 
314 			for( index_value_iterator = 0;
315 			     index_value_iterator < number_of_index_values;
316 			     index_value_iterator++ )
317 			{
318 				result = libpff_index_tree_get_value_by_identifier(
319 					  offsets_index->recovered_index_tree,
320 					  file_io_handle,
321 					  offsets_index->index_cache,
322 					  descriptor_index_value->data_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK,
323 					  index_value_iterator,
324 					  &offset_index_value,
325 					  error );
326 
327 				if( result == -1 )
328 				{
329 					libcerror_error_set(
330 					 error,
331 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
332 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
333 					 "%s: unable to retrieve recovered offset index value for data identifier: %" PRIu64 ".",
334 					 function,
335 					 descriptor_index_value->data_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK );
336 
337 					goto on_error;
338 				}
339 				else if( result != 0 )
340 				{
341 					/* Check if the data block is readable
342 					 */
343 #if defined( HAVE_DEBUG_OUTPUT )
344 					if( libcnotify_verbose != 0 )
345 					{
346 						libcnotify_printf(
347 						 "%s: reading data block at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
348 						 function,
349 						 offset_index_value->file_offset,
350 						 offset_index_value->file_offset );
351 					}
352 #endif
353 					if( libbfio_handle_seek_offset(
354 					     file_io_handle,
355 					     offset_index_value->file_offset,
356 					     SEEK_SET,
357 					     error ) == -1 )
358 					{
359 						libcerror_error_set(
360 						 error,
361 						 LIBCERROR_ERROR_DOMAIN_IO,
362 						 LIBCERROR_IO_ERROR_SEEK_FAILED,
363 						 "%s: unable to seek data block offset: %" PRIi64 ".",
364 						 function,
365 						 offset_index_value->file_offset );
366 
367 						goto on_error;
368 					}
369 					if( libpff_data_block_initialize(
370 					     &recovered_data_block,
371 					     io_handle,
372 					     (uint32_t) descriptor_index_value->identifier,
373 					     offset_index_value->identifier,
374 					     error ) != 1 )
375 					{
376 						libcerror_error_set(
377 						 error,
378 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
379 						 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
380 						 "%s: unable to create data block.",
381 						 function );
382 
383 						goto on_error;
384 					}
385 					result = libpff_data_block_read_file_io_handle(
386 					          recovered_data_block,
387 					          file_io_handle,
388 					          offset_index_value->file_offset,
389 					          offset_index_value->data_size,
390 					          io_handle->file_type,
391 					          error );
392 
393 					if( result != 1 )
394 					{
395 						libcerror_error_set(
396 						 error,
397 						 LIBCERROR_ERROR_DOMAIN_IO,
398 						 LIBCERROR_IO_ERROR_READ_FAILED,
399 						 "%s: unable to read data block.",
400 						 function );
401 #if defined( HAVE_DEBUG_OUTPUT )
402 						if( ( libcnotify_verbose != 0 )
403 						 && ( error != NULL )
404 						 && ( *error != NULL ) )
405 						{
406 							libcnotify_print_error_backtrace(
407 							 *error );
408 						}
409 #endif
410 						libcerror_error_free(
411 						 error );
412 
413 /* TODO delete unreadable offset identifier in offsets_index->recovered_index_tree */
414 					}
415 					if( libpff_data_block_free(
416 					     &recovered_data_block,
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 recovered data block.",
424 						 function );
425 
426 						goto on_error;
427 					}
428 /* TODO validate the block data ? */
429 					if( result == 1 )
430 					{
431 						break;
432 					}
433 				}
434 			}
435 			if( result == 0 )
436 			{
437 #if defined( HAVE_DEBUG_OUTPUT )
438 				if( libcnotify_verbose != 0 )
439 				{
440 					libcnotify_printf(
441 					 "%s: recovered offset index value for data identifier: %" PRIu64 " not available.\n",
442 					 function,
443 					 descriptor_index_value->data_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK );
444 				}
445 #endif
446 				recoverable = 0;
447 			}
448 			else
449 			{
450 				data_identifier_value_index = index_value_iterator;
451 			}
452 		}
453 		/* Check if the local descriptors are also recoverable
454 		 */
455 		if( recoverable != 0 )
456 		{
457 			/* Allow desciptors to have a zero local descriptors value
458 			 */
459 			if( descriptor_index_value->local_descriptors_identifier > 0 )
460 			{
461 				if( libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
462 				     offsets_index->recovered_index_tree,
463 				     file_io_handle,
464 				     offsets_index->index_cache,
465 				     descriptor_index_value->local_descriptors_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK,
466 				     &number_of_index_values,
467 				     error ) != 1 )
468 				{
469 					libcerror_error_set(
470 					 error,
471 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
472 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
473 					 "%s: unable to retrieve number of recovered offset index values for local descriptors identifier: %" PRIu64 ".",
474 					 function,
475 					 descriptor_index_value->local_descriptors_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK );
476 
477 					goto on_error;
478 				}
479 /* TODO what if more than 1 identifier is recoverable ? now uses first come first serve */
480 				result = 0;
481 
482 				for( index_value_iterator = 0;
483 				     index_value_iterator < number_of_index_values;
484 				     index_value_iterator++ )
485 				{
486 					result = libpff_index_tree_get_value_by_identifier(
487 						  offsets_index->recovered_index_tree,
488 						  file_io_handle,
489 						  offsets_index->index_cache,
490 						  descriptor_index_value->local_descriptors_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK,
491 						  index_value_iterator,
492 						  &offset_index_value,
493 						  error );
494 
495 					if( result == -1 )
496 					{
497 						libcerror_error_set(
498 						 error,
499 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
500 						 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
501 						 "%s: unable to retrieve recovered offset index value for local descriptors identifier: %" PRIu64 ".",
502 						 function,
503 						 descriptor_index_value->local_descriptors_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK );
504 
505 						goto on_error;
506 					}
507 					else if( result != 0 )
508 					{
509 						/* Check if local descriptors are readable
510 						 */
511 						result = libpff_recover_local_descriptors(
512 							  io_handle,
513 							  file_io_handle,
514 							  offsets_index,
515 							  descriptor_index_value->local_descriptors_identifier,
516 							  error );
517 
518 						if( result == -1 )
519 						{
520 							libcerror_error_set(
521 							 error,
522 							 LIBCERROR_ERROR_DOMAIN_IO,
523 							 LIBCERROR_IO_ERROR_READ_FAILED,
524 							 "%s: unable to read local descriptors with identifier: %" PRIu64 ".",
525 							 function,
526 							 descriptor_index_value->local_descriptors_identifier );
527 
528 							goto on_error;
529 						}
530 						else if( result != 0 )
531 						{
532 							break;
533 						}
534 					}
535 				}
536 				if( result == 0 )
537 				{
538 #if defined( HAVE_DEBUG_OUTPUT )
539 					if( libcnotify_verbose != 0 )
540 					{
541 						libcnotify_printf(
542 						 "%s: recovered offset index value for local descriptors identifier: %" PRIu64 " not available.\n",
543 						 function,
544 						 descriptor_index_value->local_descriptors_identifier & (uint64_t) LIBPFF_OFFSET_INDEX_IDENTIFIER_MASK );
545 					}
546 #endif
547 					recoverable = 0;
548 				}
549 				if( recoverable != 0 )
550 				{
551 					local_descriptors_identifier_value_index = index_value_iterator;
552 				}
553 			}
554 		}
555 		if( recoverable == 0 )
556 		{
557 			if( libfdata_tree_node_set_deleted(
558 			     recovered_descriptor_index_leaf_node,
559 			     error ) != 1 )
560 			{
561 				libcerror_error_set(
562 				 error,
563 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
564 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
565 				 "%s: unable to set deleted in recovered index tree leaf node: %d.",
566 				 function,
567 				 recovered_descriptor_index_value_iterator );
568 
569 				goto on_error;
570 			}
571 			number_of_recovered_descriptor_index_values--;
572 			recovered_descriptor_index_value_iterator--;
573 		}
574 		else
575 		{
576 #if defined( HAVE_DEBUG_OUTPUT )
577 			if( libcnotify_verbose != 0 )
578 			{
579 				libcnotify_printf(
580 				 "%s: item descriptor: %" PRIu64 " is recoverable.\n",
581 				 function,
582 				 descriptor_index_value->identifier );
583 			}
584 #endif
585 			/* Create a new item descriptor
586 			 */
587 			if( libpff_item_descriptor_initialize(
588 			     &item_descriptor,
589 			     (uint32_t) descriptor_index_value->identifier,
590 			     descriptor_index_value->data_identifier,
591 			     descriptor_index_value->local_descriptors_identifier,
592 			     1,
593 			     error ) != 1 )
594 			{
595 				libcerror_error_set(
596 				 error,
597 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
598 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
599 				 "%s: unable to create item descriptor.",
600 				 function );
601 
602 				goto on_error;
603 			}
604 			if( item_descriptor == NULL )
605 			{
606 				libcerror_error_set(
607 				 error,
608 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
609 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
610 				 "%s: missing item descriptor.",
611 				 function );
612 
613 				goto on_error;
614 			}
615 /* TODO add to initialize function or create a separate function for setting these value in the item descriptor */
616 			item_descriptor->recovered_data_identifier_value_index              = data_identifier_value_index;
617 			item_descriptor->recovered_local_descriptors_identifier_value_index = local_descriptors_identifier_value_index;
618 
619 			/* Create a new tree node with item tree values
620 			 */
621 			if( libcdata_tree_node_initialize(
622 			     &item_tree_node,
623 			     error ) != 1 )
624 			{
625 				libcerror_error_set(
626 				 error,
627 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
628 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
629 				 "%s: unable to create item tree node.",
630 				 function );
631 
632 				goto on_error;
633 			}
634 			if( libcdata_tree_node_set_value(
635 			     item_tree_node,
636 			     (intptr_t *) item_descriptor,
637 			     error ) != 1 )
638 			{
639 				libcerror_error_set(
640 				 error,
641 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
642 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
643 				 "%s: unable to set item descriptor in item tree node.",
644 				 function );
645 
646 				goto on_error;
647 			}
648 			item_descriptor = NULL;
649 
650 			if( libcdata_list_append_value(
651 			     recovered_item_list,
652 			     (intptr_t *) item_tree_node,
653 			     error ) != 1 )
654 			{
655 				libcerror_error_set(
656 				 error,
657 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
658 				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
659 				 "%s: unable to append tree node to recovered item list.",
660 				 function );
661 
662 				goto on_error;
663 			}
664 			item_tree_node = NULL;
665 		}
666 	}
667 #if defined( HAVE_DEBUG_OUTPUT )
668 	if( libbfio_handle_set_track_offsets_read(
669 	     file_io_handle,
670 	     0,
671 	     error ) != 1 )
672 	{
673                 libcerror_error_set(
674                  error,
675                  LIBCERROR_ERROR_DOMAIN_RUNTIME,
676                  LIBCERROR_RUNTIME_ERROR_SET_FAILED,
677                  "%s: unable to set track offsets read in file IO handle.",
678                  function );
679 
680                 goto on_error;
681 	}
682 #endif
683 	/* TODO
684 	 * link recovered descriptors to parent? and add to item hierarchy?
685 	 * handle scanning without index data
686 	 * what about 'encryption' ?
687 	 */
688 	return( 1 );
689 
690 on_error:
691 	if( recovered_data_block != NULL )
692 	{
693 		libpff_data_block_free(
694 		 &recovered_data_block,
695 		 NULL );
696 	}
697 	if( item_tree_node != NULL )
698 	{
699 		libcdata_tree_node_free(
700 		 &item_tree_node,
701 		 (int (*)(intptr_t **, libcerror_error_t **)) &libpff_item_descriptor_free,
702 		 NULL );
703 	}
704 	if( item_descriptor != NULL )
705 	{
706 		libpff_item_descriptor_free(
707 		 &item_descriptor,
708 		 NULL );
709 	}
710 	if( recovered_offset_index != NULL )
711 	{
712 		libpff_index_free(
713 		 &recovered_offset_index,
714 		 NULL );
715 	}
716 	if( recovered_descriptor_index != NULL )
717 	{
718 		libpff_index_free(
719 		 &recovered_descriptor_index,
720 		 NULL );
721 	}
722 	libcdata_list_empty(
723 	 recovered_item_list,
724 	 (int (*)(intptr_t **, libcerror_error_t **)) &libpff_item_tree_node_free_recovered,
725 	 NULL );
726 
727 	return( -1 );
728 }
729 
730 /* Scans for recoverable index nodes
731  * Returns 1 if successful or -1 on error
732  */
libpff_recover_index_nodes(libpff_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libpff_descriptors_index_t * descriptors_index,libcerror_error_t ** error)733 int libpff_recover_index_nodes(
734      libpff_io_handle_t *io_handle,
735      libbfio_handle_t *file_io_handle,
736      libpff_descriptors_index_t *descriptors_index,
737      libcerror_error_t **error )
738 {
739 	libfdata_tree_node_t *deleted_index_leaf_node = NULL;
740 	libpff_index_value_t *deleted_index_value     = NULL;
741 	libpff_index_value_t *index_value             = NULL;
742 	static char *function                         = "libpff_recover_index_nodes";
743 	off64_t node_data_offset                      = 0;
744 	size64_t node_data_size                       = 0;
745 	uint32_t node_data_flags                      = 0;
746 	int deleted_index_value_iterator              = 0;
747 	int index_value_iterator                      = 0;
748 	int node_data_file_index                      = 0;
749 	int number_of_index_values                    = 0;
750 	int number_of_deleted_index_values            = 0;
751 	int result                                    = 0;
752 
753 #ifdef TODO
754         uint32_t maximum_data_block_data_size         = 0;
755 #endif
756 
757 	if( io_handle == NULL )
758 	{
759 		libcerror_error_set(
760 		 error,
761 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
762 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
763 		 "%s: invalid IO handle.",
764 		 function );
765 
766 		return( -1 );
767 	}
768 #ifdef TODO
769 	if( ( io_handle->file_type != LIBPFF_FILE_TYPE_32BIT )
770 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT )
771 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
772 	{
773 		libcerror_error_set(
774 		 error,
775 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
776 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
777 		 "%s: unsupported file type.",
778 		 function );
779 
780 		return( -1 );
781 	}
782 	if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
783 	{
784 		maximum_data_block_data_size = 8192 - 12;
785 	}
786 	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
787 	{
788 		maximum_data_block_data_size = 8192 - 16;
789 	}
790 	else
791 	{
792 /* TODO: this value is currently assumed based on the 512 x 8 = 4k page */
793 		maximum_data_block_data_size = 65536 - 24;
794 	}
795 #endif
796 	/* Scan the existing descriptor index nodes for remnant values
797 	 */
798 	if( libfdata_tree_get_number_of_deleted_leaf_nodes(
799 	     descriptors_index->index_tree,
800 	     (intptr_t *) file_io_handle,
801 	     descriptors_index->index_cache,
802 	     &number_of_deleted_index_values,
803 	     0,
804 	     error ) != 1 )
805 	{
806 		libcerror_error_set(
807 		 error,
808 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
809 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
810 		 "%s: unable to retrieve number of deleted descriptor index values.",
811 		 function );
812 
813 		return( -1 );
814 	}
815 	for( deleted_index_value_iterator = 0;
816 	     deleted_index_value_iterator < number_of_deleted_index_values;
817 	     deleted_index_value_iterator++ )
818 	{
819 		if( io_handle->abort != 0 )
820 		{
821 			return( -1 );
822 		}
823 		if( libfdata_tree_get_deleted_leaf_node_by_index(
824 		     descriptors_index->index_tree,
825 		     (intptr_t *) file_io_handle,
826 		     descriptors_index->index_cache,
827 		     deleted_index_value_iterator,
828 		     &deleted_index_leaf_node,
829 		     0,
830 		     error ) != 1 )
831 		{
832 			libcerror_error_set(
833 			 error,
834 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
835 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
836 			 "%s: unable to retrieve deleted descriptor leaf node: %d.",
837 			 function,
838 			 deleted_index_value_iterator );
839 
840 			return( -1 );
841 		}
842 		if( libfdata_tree_node_get_node_value(
843 		     deleted_index_leaf_node,
844 		     (intptr_t *) file_io_handle,
845 		     descriptors_index->index_cache,
846 		     (intptr_t **) &deleted_index_value,
847 		     0,
848 		     error ) != 1 )
849 		{
850 			libcerror_error_set(
851 			 error,
852 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
853 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
854 			 "%s: unable to retrieve deleted descriptor index value: %d.",
855 			 function,
856 			 deleted_index_value_iterator );
857 
858 			return( -1 );
859 		}
860 		if( deleted_index_value == NULL )
861 		{
862 			libcerror_error_set(
863 			 error,
864 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
865 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
866 			 "%s: missing deleted descriptor index value: %d.",
867 			 function,
868 			 deleted_index_value_iterator );
869 
870 			return( -1 );
871 		}
872 #if defined( HAVE_DEBUG_OUTPUT )
873 		if( libcnotify_verbose != 0 )
874 		{
875 			libcnotify_printf(
876 			 "%s: analyzing identifier: %" PRIu64 ", data: %" PRIu64 ", local descriptors: %" PRIu64 ", parent: %" PRIu32 "\n",
877 			 function,
878 			 deleted_index_value->identifier,
879 			 deleted_index_value->data_identifier,
880 			 deleted_index_value->local_descriptors_identifier,
881 			 deleted_index_value->parent_identifier );
882 		}
883 #endif
884 		/* Check if the item value matches the existing item value
885 		 */
886 		result = libpff_index_tree_get_value_by_identifier(
887 			  descriptors_index->index_tree,
888 			  file_io_handle,
889 			  descriptors_index->index_cache,
890 			  deleted_index_value->identifier,
891 			  0,
892 			  &index_value,
893 			  error );
894 
895 		if( result == -1 )
896 		{
897 			libcerror_error_set(
898 			 error,
899 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
900 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
901 			 "%s: unable to retrieve descriptor index value for identifier: %" PRIu64 ".",
902 			 function,
903 			 deleted_index_value->identifier );
904 
905 			return( -1 );
906 		}
907 		else if( result != 0 )
908 		{
909 /* TODO what about parent changes ? */
910 			if( ( deleted_index_value->data_identifier == index_value->data_identifier )
911 			 && ( deleted_index_value->local_descriptors_identifier == index_value->local_descriptors_identifier ) )
912 			{
913 #if defined( HAVE_DEBUG_OUTPUT )
914 				if( libcnotify_verbose != 0 )
915 				{
916 					libcnotify_printf(
917 					 "%s: deleted descriptor index value: %" PRIu64 " matches existing item value.\n",
918 					 function,
919 					 deleted_index_value->identifier );
920 				}
921 #endif
922 				continue;
923 			}
924 		}
925 		/* Check for duplicates
926 		 */
927 		if( libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
928 		     descriptors_index->recovered_index_tree,
929 		     file_io_handle,
930 		     descriptors_index->index_cache,
931 		     deleted_index_value->identifier,
932 		     &number_of_index_values,
933 		     error ) != 1 )
934 		{
935 			libcerror_error_set(
936 			 error,
937 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
938 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
939 			 "%s: unable to retrieve number of recovered descriptor index values for identifier: %" PRIu64 ".",
940 			 function,
941 			 deleted_index_value->identifier );
942 
943 			return( -1 );
944 		}
945 		result = 0;
946 
947 		for( index_value_iterator = 0;
948 		     index_value_iterator < number_of_index_values;
949 		     index_value_iterator++ )
950 		{
951 			result = libpff_index_tree_get_value_by_identifier(
952 				  descriptors_index->recovered_index_tree,
953 				  file_io_handle,
954 				  descriptors_index->index_cache,
955 				  deleted_index_value->identifier,
956 				  index_value_iterator,
957 				  &index_value,
958 				  error );
959 
960 			if( result == -1 )
961 			{
962 				libcerror_error_set(
963 				 error,
964 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
965 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
966 				 "%s: unable to retrieve recovered descriptor index value for identifier: %" PRIu64 ".",
967 				 function,
968 				 deleted_index_value->identifier );
969 
970 				return( -1 );
971 			}
972 			else if( result != 0 )
973 			{
974 /* TODO what about parent changes ? */
975 				if( ( deleted_index_value->data_identifier == index_value->data_identifier )
976 				 && ( deleted_index_value->local_descriptors_identifier == index_value->local_descriptors_identifier ) )
977 				{
978 					break;
979 				}
980 				result = 0;
981 			}
982 		}
983 		if( result != 0 )
984 		{
985 #if defined( HAVE_DEBUG_OUTPUT )
986 			if( libcnotify_verbose != 0 )
987 			{
988 				libcnotify_printf(
989 				 "%s: deleted descriptor index value: %" PRIu64 " matches existing recovered item value.\n",
990 				 function,
991 				 deleted_index_value->identifier );
992 			}
993 #endif
994 			continue;
995 		}
996 		/* Add the recovered descriptor index values to the index tree
997 		 */
998 #if defined( HAVE_DEBUG_OUTPUT )
999 		if( libcnotify_verbose != 0 )
1000 		{
1001 			libcnotify_printf(
1002 			 "%s: decriptor index value: %d identifier: %" PRIu64 " is recoverable.\n",
1003 			 function,
1004 			 deleted_index_value_iterator,
1005 			 deleted_index_value->identifier );
1006 		}
1007 #endif
1008 		if( libfdata_tree_node_get_data_range(
1009 		     deleted_index_leaf_node,
1010 		     &node_data_file_index,
1011 		     &node_data_offset,
1012 		     &node_data_size,
1013 		     &node_data_flags,
1014 		     error ) != 1 )
1015 		{
1016 			libcerror_error_set(
1017 			 error,
1018 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1019 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1020 			 "%s: unable to retrieve deleted descriptor leaf node: %d range.",
1021 			 function,
1022 			 deleted_index_value_iterator );
1023 
1024 			return( -1 );
1025 		}
1026 		if( libpff_index_tree_insert_value(
1027 		     descriptors_index->recovered_index_tree,
1028 		     file_io_handle,
1029 		     descriptors_index->index_cache,
1030 		     deleted_index_value->identifier,
1031 		     node_data_offset,
1032 		     node_data_size,
1033 		     error ) != 1 )
1034 		{
1035 			libcerror_error_set(
1036 			 error,
1037 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1038 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1039 			 "%s: unable to insert descriptor index value: %" PRIu64 " to recovered index tree.",
1040 			 function,
1041 			 deleted_index_value->identifier );
1042 
1043 			return( -1 );
1044 		}
1045 	}
1046 #ifdef TODO
1047 	/* Scan the existing offset index nodes for remnant values
1048 	 */
1049 	if( libfdata_tree_get_number_of_deleted_leaf_nodes(
1050 	     offsets_index->index_tree,
1051 	     (intptr_t *) file_io_handle,
1052 	     offsets_index->index_cache,
1053 	     &number_of_deleted_index_values,
1054 	     0,
1055 	     error ) != 1 )
1056 	{
1057 		libcerror_error_set(
1058 		 error,
1059 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1060 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1061 		 "%s: unable to retrieve number of deleted offset index values.",
1062 		 function );
1063 
1064 		return( -1 );
1065 	}
1066 	for( deleted_index_value_iterator = 0;
1067 	     deleted_index_value_iterator < number_of_deleted_index_values;
1068 	     deleted_index_value_iterator++ )
1069 	{
1070 		if( io_handle->abort != 0 )
1071 		{
1072 			return( -1 );
1073 		}
1074 		if( libfdata_tree_get_deleted_leaf_node_by_index(
1075 		     offsets_index->index_tree,
1076 		     (intptr_t *) file_io_handle,
1077 		     offsets_index->index_cache,
1078 		     deleted_index_value_iterator,
1079 		     &deleted_index_leaf_node,
1080 		     0,
1081 		     error ) != 1 )
1082 		{
1083 			libcerror_error_set(
1084 			 error,
1085 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1086 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1087 			 "%s: unable to retrieve deleted offset leaf node: %d.",
1088 			 function,
1089 			 deleted_index_value_iterator );
1090 
1091 			return( -1 );
1092 		}
1093 		if( libfdata_tree_node_get_node_value(
1094 		     deleted_index_leaf_node,
1095 		     (intptr_t *) file_io_handle,
1096 		     offsets_index->index_cache,
1097 		     (intptr_t **) &deleted_index_value,
1098 		     0,
1099 		     error ) != 1 )
1100 		{
1101 			libcerror_error_set(
1102 			 error,
1103 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1104 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1105 			 "%s: unable to retrieve deleted offset index value: %d.",
1106 			 function,
1107 			 deleted_index_value_iterator );
1108 
1109 			return( -1 );
1110 		}
1111 		if( deleted_index_value == NULL )
1112 		{
1113 			libcerror_error_set(
1114 			 error,
1115 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1116 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1117 			 "%s: missing deleted offset index value: %d.",
1118 			 function,
1119 			 deleted_index_value_iterator );
1120 
1121 			return( -1 );
1122 		}
1123 #if defined( HAVE_DEBUG_OUTPUT )
1124 		if( libcnotify_verbose != 0 )
1125 		{
1126 			libcnotify_printf(
1127 			 "%s: analyzing identifier: %" PRIu64 " (%s) at offset: %" PRIi64 " of size: %" PRIu32 "\n",
1128 			 function,
1129 			 deleted_index_value->identifier,
1130 			 ( ( deleted_index_value->identifier & LIBPFF_OFFSET_INDEX_IDENTIFIER_FLAG_INTERNAL ) ? "internal" : "external" ),
1131 			 deleted_index_value->file_offset,
1132 			 deleted_index_value->data_size );
1133 		}
1134 #endif
1135 		/* Ignore index values without a valid file offset
1136 		 */
1137 		if( deleted_index_value->file_offset <= 0 )
1138 		{
1139 #if defined( HAVE_DEBUG_OUTPUT )
1140 			if( libcnotify_verbose != 0 )
1141 			{
1142 				libcnotify_printf(
1143 				 "%s: deleted offset index value: %" PRIu64 " has an invalid file offset: %" PRIi64 ".\n",
1144 				 function,
1145 				 deleted_index_value->identifier,
1146 				 deleted_index_value->file_offset );
1147 			}
1148 #endif
1149 			continue;
1150 		}
1151 		/* Ignore index values without a valid data size
1152 		 */
1153 		if( ( deleted_index_value->data_size == 0 )
1154 		 || ( (uint32_t) deleted_index_value->data_size > maximum_data_block_data_size ) )
1155 		{
1156 #if defined( HAVE_DEBUG_OUTPUT )
1157 			if( libcnotify_verbose != 0 )
1158 			{
1159 				libcnotify_printf(
1160 				 "%s: deleted offset index value: %" PRIu64 " has an invalid data size: %" PRIu32 ".\n",
1161 				 function,
1162 				 deleted_index_value->identifier,
1163 				 deleted_index_value->data_size );
1164 			}
1165 #endif
1166 			continue;
1167 		}
1168 		/* Check if the item value matches the existing item value
1169 		 */
1170 		result = libpff_index_tree_get_value_by_identifier(
1171 			  offsets_index->index_tree,
1172 			  file_io_handle,
1173 			  offsets_index->index_cache,
1174 			  deleted_index_value->identifier,
1175 			  0,
1176 			  &index_value,
1177 			  error );
1178 
1179 		if( result == -1 )
1180 		{
1181 			libcerror_error_set(
1182 			 error,
1183 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1184 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1185 			 "%s: unable to retrieve offset index value for identifier: %" PRIu64 ".",
1186 			 function,
1187 			 deleted_index_value->identifier );
1188 
1189 			return( -1 );
1190 		}
1191 		else if( result != 0 )
1192 		{
1193 			if( ( deleted_index_value->file_offset == index_value->file_offset )
1194 			 && ( deleted_index_value->data_size == index_value->data_size ) )
1195 			{
1196 #if defined( HAVE_DEBUG_OUTPUT )
1197 				if( libcnotify_verbose != 0 )
1198 				{
1199 					libcnotify_printf(
1200 					 "%s: deleted offset index value: %" PRIu64 " matches existing item value.\n",
1201 					 function,
1202 					 deleted_index_value->identifier );
1203 				}
1204 #endif
1205 				continue;
1206 			}
1207 		}
1208 		/* Check for duplicates
1209 		 */
1210 		if( libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
1211 		     offsets_index->recovered_index_tree,
1212 		     file_io_handle,
1213 		     offsets_index->index_cache,
1214 		     deleted_index_value->identifier,
1215 		     &number_of_index_values,
1216 		     error ) != 1 )
1217 		{
1218 			libcerror_error_set(
1219 			 error,
1220 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1221 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1222 			 "%s: unable to retrieve number of recovered offset index values for identifier: %" PRIu64 ".",
1223 			 function,
1224 			 deleted_index_value->identifier );
1225 
1226 			return( -1 );
1227 		}
1228 		result = 0;
1229 
1230 		for( index_value_iterator = 0;
1231 		     index_value_iterator < number_of_index_values;
1232 		     index_value_iterator++ )
1233 		{
1234 			result = libpff_index_tree_get_value_by_identifier(
1235 				  offsets_index->recovered_index_tree,
1236 				  file_io_handle,
1237 				  offsets_index->index_cache,
1238 				  deleted_index_value->identifier,
1239 				  index_value_iterator,
1240 				  &index_value,
1241 				  error );
1242 
1243 			if( result == -1 )
1244 			{
1245 				libcerror_error_set(
1246 				 error,
1247 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1248 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1249 				 "%s: unable to retrieve recovered offset index value for identifier: %" PRIu64 ".",
1250 				 function,
1251 				 deleted_index_value->identifier );
1252 
1253 				return( -1 );
1254 			}
1255 			else if( result != 0 )
1256 			{
1257 				if( ( deleted_index_value->file_offset == index_value->file_offset )
1258 				 && ( deleted_index_value->data_size == index_value->data_size ) )
1259 				{
1260 					break;
1261 				}
1262 				result = 0;
1263 			}
1264 		}
1265 		if( result != 0 )
1266 		{
1267 #if defined( HAVE_DEBUG_OUTPUT )
1268 			if( libcnotify_verbose != 0 )
1269 			{
1270 				libcnotify_printf(
1271 				 "%s: deleted offset index value: %" PRIu64 " matches existing recovered item value.\n",
1272 				 function,
1273 				 deleted_index_value->identifier );
1274 			}
1275 #endif
1276 			continue;
1277 		}
1278 		/* Add the recovered offset index values to the index tree
1279 		 */
1280 #if defined( HAVE_DEBUG_OUTPUT )
1281 		if( libcnotify_verbose != 0 )
1282 		{
1283 			libcnotify_printf(
1284 			 "%s: offset index value: %d identifier: %" PRIu64 " is recoverable.\n",
1285 			 function,
1286 			 deleted_index_value_iterator,
1287 			 deleted_index_value->identifier );
1288 		}
1289 #endif
1290 		if( libfdata_tree_node_get_data_range(
1291 		     deleted_index_leaf_node,
1292 		     &node_data_file_index,
1293 		     &node_data_offset,
1294 		     &node_data_size,
1295 		     &node_data_flags,
1296 		     error ) != 1 )
1297 		{
1298 			libcerror_error_set(
1299 			 error,
1300 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1301 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1302 			 "%s: unable to retrieve deleted offset leaf node: %d range.",
1303 			 function,
1304 			 deleted_index_value_iterator );
1305 
1306 			return( -1 );
1307 		}
1308 		if( libpff_index_tree_insert_value(
1309 		     offsets_index->recovered_index_tree,
1310 		     file_io_handle,
1311 		     offsets_index->index_cache,
1312 		     deleted_index_value->identifier,
1313 		     node_data_offset,
1314 		     node_data_size,
1315 		     error ) != 1 )
1316 		{
1317 			libcerror_error_set(
1318 			 error,
1319 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1320 			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1321 			 "%s: unable to insert offset index value: %" PRIu64 " to recovered index tree.",
1322 			 function,
1323 			 deleted_index_value->identifier );
1324 
1325 			return( -1 );
1326 		}
1327 	}
1328 #endif
1329 	return( 1 );
1330 }
1331 
1332 /* Scans for recoverable data blocks
1333  * Returns 1 if successful or -1 on error
1334  */
libpff_recover_data_blocks(libpff_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libpff_descriptors_index_t * descriptors_index,libpff_offsets_index_t * offsets_index,libcdata_range_list_t * unallocated_data_block_list,libcdata_range_list_t * unallocated_page_block_list,uint8_t recovery_flags,libcerror_error_t ** error)1335 int libpff_recover_data_blocks(
1336      libpff_io_handle_t *io_handle,
1337      libbfio_handle_t *file_io_handle,
1338      libpff_descriptors_index_t *descriptors_index,
1339      libpff_offsets_index_t *offsets_index,
1340      libcdata_range_list_t *unallocated_data_block_list,
1341      libcdata_range_list_t *unallocated_page_block_list,
1342      uint8_t recovery_flags,
1343      libcerror_error_t **error )
1344 {
1345 	libpff_index_value_t *index_value       = NULL;
1346 	uint8_t *block_buffer                   = NULL;
1347 	uint8_t *data_block_footer              = NULL;
1348 	intptr_t *value                         = NULL;
1349 	static char *function                   = "libpff_recover_data_blocks";
1350 	off64_t block_buffer_data_offset        = 0;
1351 	off64_t block_offset                    = 0;
1352 	off64_t data_block_offset               = 0;
1353 	off64_t page_block_offset               = 0;
1354 	size64_t block_size                     = 0;
1355 	size64_t data_block_size                = 0;
1356 	size64_t page_block_size                = 0;
1357 	size_t block_buffer_offset              = 0;
1358 	size_t block_buffer_size_available      = 0;
1359 	size_t data_block_data_offset           = 0;
1360 	size_t read_size                        = 0;
1361 	ssize_t read_count                      = 0;
1362 	uint64_t data_block_back_pointer        = 0;
1363 	uint32_t data_block_calculated_checksum = 0;
1364 	uint32_t data_block_stored_checksum     = 0;
1365 	uint32_t maximum_data_block_size        = 0;
1366 	uint16_t data_block_data_size           = 0;
1367 	uint16_t format_data_block_size         = 0;
1368 	uint16_t format_page_block_size         = 0;
1369 	uint16_t scan_block_size                = 0;
1370 	uint8_t supported_recovery_flags        = 0;
1371 	int index_value_iterator                = 0;
1372 	int number_of_index_values              = 0;
1373 	int number_of_unallocated_data_blocks   = 0;
1374 	int number_of_unallocated_page_blocks   = 0;
1375 	int result                              = 0;
1376 	int unallocated_data_block_index        = 0;
1377 	int unallocated_page_block_index        = 0;
1378 
1379 	if( io_handle == NULL )
1380 	{
1381 		libcerror_error_set(
1382 		 error,
1383 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1384 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1385 		 "%s: invalid IO handle.",
1386 		 function );
1387 
1388 		return( -1 );
1389 	}
1390 	if( ( io_handle->file_type != LIBPFF_FILE_TYPE_32BIT )
1391 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT )
1392 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
1393 	{
1394 		libcerror_error_set(
1395 		 error,
1396 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1397 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1398 		 "%s: unsupported file type.",
1399 		 function );
1400 
1401 		return( -1 );
1402 	}
1403 	if( ( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
1404 	 || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) )
1405 	{
1406 		format_data_block_size  = 64;
1407 		format_page_block_size  = 512;
1408 	}
1409 	else
1410 	{
1411 		format_data_block_size  = 512;
1412 		format_page_block_size  = 4096;
1413 	}
1414 	if( ( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
1415 	 || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) )
1416 	{
1417 		maximum_data_block_size = 8192;
1418 	}
1419 	else
1420 	{
1421 /* TODO: this value is currently assumed based on the 512 x 8 = 4k page */
1422 		maximum_data_block_size = 65536;
1423 	}
1424 	supported_recovery_flags = LIBPFF_RECOVERY_FLAG_IGNORE_ALLOCATION_DATA
1425 	                         | LIBPFF_RECOVERY_FLAG_SCAN_FOR_FRAGMENTS;
1426 
1427 	if( ( recovery_flags & ~( supported_recovery_flags ) ) != 0 )
1428 	{
1429 		libcerror_error_set(
1430 		 error,
1431 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1432 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1433 		 "%s: unsupported recovery flags.",
1434 		 function );
1435 
1436 		return( -1 );
1437 	}
1438 	/* Scan the unallocated page block list or all blocks for index nodes
1439 	 */
1440 	if( ( recovery_flags & LIBPFF_RECOVERY_FLAG_IGNORE_ALLOCATION_DATA ) == 0 )
1441 	{
1442 		if( libcdata_range_list_get_number_of_elements(
1443 		     unallocated_data_block_list,
1444 		     &number_of_unallocated_data_blocks,
1445 		     error ) != 1 )
1446 		{
1447 			libcerror_error_set(
1448 			 error,
1449 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1450 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1451 			 "%s: unable to retrieve number of unallocated data blocks.",
1452 			 function );
1453 
1454 			goto on_error;
1455 		}
1456 		if( ( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
1457 		 || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT ) )
1458 		{
1459 			if( libcdata_range_list_get_number_of_elements(
1460 			     unallocated_page_block_list,
1461 			     &number_of_unallocated_page_blocks,
1462 			     error ) != 1 )
1463 			{
1464 				libcerror_error_set(
1465 				 error,
1466 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1467 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1468 				 "%s: unable to retrieve number of unallocated page blocks.",
1469 				 function );
1470 
1471 				goto on_error;
1472 			}
1473 		}
1474 		else
1475 		{
1476 			number_of_unallocated_page_blocks = 0;
1477 		}
1478 	}
1479 	if( ( recovery_flags & LIBPFF_RECOVERY_FLAG_SCAN_FOR_FRAGMENTS ) == 0 )
1480 	{
1481 		scan_block_size = format_page_block_size;
1482 	}
1483 	else
1484 	{
1485 		scan_block_size = format_data_block_size;
1486 	}
1487 	block_buffer = (uint8_t *) memory_allocate(
1488 	                            sizeof( uint8_t ) * ( maximum_data_block_size * 2 ) );
1489 
1490 	if( block_buffer == NULL )
1491 	{
1492 		libcerror_error_set(
1493 		 error,
1494 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
1495 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1496 		 "%s: unable to create block buffer.",
1497 		 function );
1498 
1499 		goto on_error;
1500 	}
1501 	if( ( number_of_unallocated_data_blocks > 0 )
1502 	 || ( number_of_unallocated_page_blocks > 0 )
1503 	 || ( ( recovery_flags & LIBPFF_RECOVERY_FLAG_IGNORE_ALLOCATION_DATA ) != 0 ) )
1504 	{
1505 		block_offset      = 0;
1506 		data_block_offset = -1;
1507 		page_block_offset = -1;
1508 
1509 		while( block_offset < (off64_t) io_handle->file_size )
1510 		{
1511 			if( io_handle->abort != 0 )
1512 			{
1513 				goto on_error;
1514 			}
1515 			if( ( recovery_flags & LIBPFF_RECOVERY_FLAG_IGNORE_ALLOCATION_DATA ) == 0 )
1516 			{
1517 				if( data_block_offset < block_offset )
1518 				{
1519 					if( unallocated_data_block_index < number_of_unallocated_data_blocks )
1520 					{
1521 						if( libcdata_range_list_get_range_by_index(
1522 						     unallocated_data_block_list,
1523 						     unallocated_data_block_index,
1524 						     (uint64_t *) &data_block_offset,
1525 						     (uint64_t *) &data_block_size,
1526 						     &value,
1527 						     error ) != 1 )
1528 						{
1529 							libcerror_error_set(
1530 							 error,
1531 							 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1532 							 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1533 							 "%s: unable to retrieve unallocated data block: %d.",
1534 							 function,
1535 							 unallocated_data_block_index );
1536 
1537 							goto on_error;
1538 						}
1539 						unallocated_data_block_index++;
1540 					}
1541 					else
1542 					{
1543 						data_block_offset = (off64_t) io_handle->file_size;
1544 						data_block_size   = 0;
1545 					}
1546 				}
1547 				if( page_block_offset < block_offset )
1548 				{
1549 					if( unallocated_page_block_index < number_of_unallocated_page_blocks )
1550 					{
1551 						if( libcdata_range_list_get_range_by_index(
1552 						     unallocated_page_block_list,
1553 						     unallocated_page_block_index,
1554 						     (uint64_t *) &page_block_offset,
1555 						     (uint64_t *) &page_block_size,
1556 						     &value,
1557 						     error ) != 1 )
1558 						{
1559 							libcerror_error_set(
1560 							 error,
1561 							 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1562 							 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1563 							 "%s: unable to retrieve unallocated page block: %d.",
1564 							 function,
1565 							 unallocated_page_block_index );
1566 
1567 							goto on_error;
1568 						}
1569 						unallocated_page_block_index++;
1570 					}
1571 					else
1572 					{
1573 						page_block_offset = (off64_t) io_handle->file_size;
1574 						page_block_size   = 0;
1575 					}
1576 				}
1577 			}
1578 			if( ( recovery_flags & LIBPFF_RECOVERY_FLAG_IGNORE_ALLOCATION_DATA ) == 0 )
1579 			{
1580 				if( ( data_block_offset >= (off64_t) io_handle->file_size )
1581 				 && ( page_block_offset >= (off64_t) io_handle->file_size ) )
1582 				{
1583 					break;
1584 				}
1585 				/* Process the smallest offset
1586 				 */
1587 				else if( ( data_block_offset < page_block_offset )
1588 				      && ( data_block_size > scan_block_size ) )
1589 				{
1590 					block_offset = data_block_offset;
1591 					block_size   = data_block_size;
1592 				}
1593 				else if( ( page_block_offset < data_block_offset )
1594 				      && ( page_block_size > scan_block_size ) )
1595 				{
1596 					block_offset = page_block_offset;
1597 					block_size   = page_block_size;
1598 				}
1599 				/* Process the largest range
1600 				 */
1601 				else if( data_block_size > page_block_size )
1602 				{
1603 					block_offset = data_block_offset;
1604 					block_size   = data_block_size;
1605 				}
1606 				else
1607 				{
1608 					block_offset = page_block_offset;
1609 					block_size   = page_block_size;
1610 				}
1611 			}
1612 			else
1613 			{
1614 				block_size = scan_block_size;
1615 			}
1616 			if( ( block_offset % scan_block_size ) != 0 )
1617 			{
1618 				block_offset  = ( ( block_offset / scan_block_size ) + 1 ) * scan_block_size;
1619 				block_size   -= block_size % scan_block_size;
1620 			}
1621 			if( block_size < scan_block_size )
1622 			{
1623 				block_offset += block_size;
1624 
1625 				continue;
1626 			}
1627 			while( block_size >= scan_block_size )
1628 			{
1629 				/* The index nodes have a fixed block size and stored block size aligned
1630 				 */
1631 				if( ( block_size >= format_page_block_size )
1632 				 && ( ( block_offset % format_page_block_size ) == 0 ) )
1633 				{
1634 					/* Scan for index values in the index node
1635 					 */
1636 					result = libpff_recover_index_values(
1637 						  io_handle,
1638 						  file_io_handle,
1639 						  descriptors_index,
1640 						  offsets_index,
1641 						  unallocated_data_block_list,
1642 						  block_offset,
1643 						  recovery_flags,
1644 						  error );
1645 
1646 					if( result == -1 )
1647 					{
1648 						libcerror_error_set(
1649 						 error,
1650 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1651 						 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1652 						 "%s: unable to recover index node at offset: %" PRIi64 ".\n",
1653 						 function,
1654 						 block_offset );
1655 
1656 						goto on_error;
1657 					}
1658 					else if( result == 1 )
1659 					{
1660 						block_offset += format_page_block_size;
1661 						block_size   -= format_page_block_size;
1662 
1663 						continue;
1664 					}
1665 				}
1666 				if( ( recovery_flags & LIBPFF_RECOVERY_FLAG_SCAN_FOR_FRAGMENTS ) == 0 )
1667 				{
1668 					block_offset += scan_block_size;
1669 					block_size   -= scan_block_size;
1670 
1671 					continue;
1672 				}
1673 /* TODO optimize by minimizing amount of reads */
1674 				if( block_buffer_size_available == 0 )
1675 				{
1676 					block_buffer_data_offset = block_offset;
1677 
1678 					if( block_buffer_offset > 0 )
1679 					{
1680 /* TODO optimize by copying the needed data to the front of the buffer */
1681 						block_buffer_data_offset -= format_data_block_size;
1682 						block_buffer_offset       = maximum_data_block_size - format_data_block_size;
1683 					}
1684 					read_size = (size_t) block_size;
1685 
1686 					if( read_size > (size_t) maximum_data_block_size )
1687 					{
1688 						read_size = (size_t) maximum_data_block_size;
1689 					}
1690 #if defined( HAVE_DEBUG_OUTPUT )
1691 					if( libcnotify_verbose != 0 )
1692 					{
1693 						libcnotify_printf(
1694 						 "%s: reading data block at offset: %" PRIi64 " (0x%08" PRIx64 ") of size: %" PRIzd "\n",
1695 						 function,
1696 						 block_buffer_data_offset,
1697 						 block_buffer_data_offset,
1698 						 read_size );
1699 					}
1700 #endif
1701 					if( libbfio_handle_seek_offset(
1702 					     file_io_handle,
1703 					     block_buffer_data_offset,
1704 					     SEEK_SET,
1705 					     error ) == -1 )
1706 					{
1707 						libcerror_error_set(
1708 						 error,
1709 						 LIBCERROR_ERROR_DOMAIN_IO,
1710 						 LIBCERROR_IO_ERROR_SEEK_FAILED,
1711 						 "%s: unable to seek data block offset: %" PRIi64 ".",
1712 						 function,
1713 						 block_buffer_data_offset );
1714 
1715 						goto on_error;
1716 					}
1717 					read_count = libbfio_handle_read_buffer(
1718 						      file_io_handle,
1719 						      &( block_buffer[ block_buffer_offset ] ),
1720 						      read_size,
1721 						      error );
1722 
1723 					if( read_count != (ssize_t) read_size )
1724 					{
1725 						libcerror_error_set(
1726 						 error,
1727 						 LIBCERROR_ERROR_DOMAIN_IO,
1728 						 LIBCERROR_IO_ERROR_READ_FAILED,
1729 						 "%s: unable to read data block.",
1730 						 function );
1731 
1732 						goto on_error;
1733 					}
1734 					block_buffer_size_available = read_size;
1735 				}
1736 				if( block_buffer_size_available >= format_data_block_size )
1737 				{
1738 					/* Scan the block for a data block footer
1739 					 */
1740 					data_block_footer = &( block_buffer[ block_buffer_offset ] );
1741 
1742 					if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
1743 					{
1744 						data_block_footer += format_data_block_size - sizeof( pff_block_footer_32bit_t );
1745 
1746 						byte_stream_copy_to_uint16_little_endian(
1747 						 ( (pff_block_footer_32bit_t *) data_block_footer )->data_size,
1748 						 data_block_data_size );
1749 						byte_stream_copy_to_uint32_little_endian(
1750 						 ( (pff_block_footer_32bit_t *) data_block_footer )->back_pointer,
1751 						 data_block_back_pointer );
1752 						byte_stream_copy_to_uint32_little_endian(
1753 						 ( (pff_block_footer_32bit_t *) data_block_footer )->checksum,
1754 						 data_block_stored_checksum );
1755 					}
1756 					else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
1757 					{
1758 						data_block_footer += format_data_block_size - sizeof( pff_block_footer_64bit_t );
1759 
1760 						byte_stream_copy_to_uint16_little_endian(
1761 						 ( (pff_block_footer_64bit_t *) data_block_footer )->data_size,
1762 						 data_block_data_size );
1763 						byte_stream_copy_to_uint32_little_endian(
1764 						 ( (pff_block_footer_64bit_t *) data_block_footer )->checksum,
1765 						 data_block_stored_checksum );
1766 						byte_stream_copy_to_uint64_little_endian(
1767 						 ( (pff_block_footer_64bit_t *) data_block_footer )->back_pointer,
1768 						 data_block_back_pointer );
1769 					}
1770 					else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
1771 					{
1772 						data_block_footer += format_data_block_size - sizeof( pff_block_footer_64bit_4k_page_t );
1773 
1774 						byte_stream_copy_to_uint16_little_endian(
1775 						 ( (pff_block_footer_64bit_4k_page_t *) data_block_footer )->data_size,
1776 						 data_block_data_size );
1777 						byte_stream_copy_to_uint32_little_endian(
1778 						 ( (pff_block_footer_64bit_4k_page_t *) data_block_footer )->checksum,
1779 						 data_block_stored_checksum );
1780 						byte_stream_copy_to_uint64_little_endian(
1781 						 ( (pff_block_footer_64bit_4k_page_t *) data_block_footer )->back_pointer,
1782 						 data_block_back_pointer );
1783 					}
1784 					/* Check if back pointer itself is not empty but the upper 32-bit are
1785 					 */
1786 					if( ( data_block_back_pointer != 0 )
1787 					 && ( ( data_block_back_pointer >> 32 ) == 0 ) )
1788 					{
1789 						data_block_data_offset = block_buffer_offset - ( ( data_block_data_size / format_data_block_size ) * format_data_block_size );
1790 
1791 						if( (size_t) data_block_data_size < read_size )
1792 						{
1793 							/* Check for duplicates
1794 							 */
1795 							if( libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
1796 							     offsets_index->recovered_index_tree,
1797 							     file_io_handle,
1798 							     offsets_index->index_cache,
1799 							     data_block_back_pointer,
1800 							     &number_of_index_values,
1801 							     error ) != 1 )
1802 							{
1803 								libcerror_error_set(
1804 								 error,
1805 								 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1806 								 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1807 								 "%s: unable to retrieve number of recovered offset index values for identifier: %" PRIu64 ".",
1808 								 function,
1809 								 data_block_back_pointer );
1810 
1811 								goto on_error;
1812 							}
1813 							result = 0;
1814 
1815 							for( index_value_iterator = 0;
1816 							     index_value_iterator < number_of_index_values;
1817 							     index_value_iterator++ )
1818 							{
1819 								result = libpff_index_tree_get_value_by_identifier(
1820 									  offsets_index->recovered_index_tree,
1821 									  file_io_handle,
1822 									  offsets_index->index_cache,
1823 									  data_block_back_pointer,
1824 									  index_value_iterator,
1825 									  &index_value,
1826 									  error );
1827 
1828 								if( result == -1 )
1829 								{
1830 									libcerror_error_set(
1831 									 error,
1832 									 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1833 									 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1834 									 "%s: unable to retrieve recovered offset index value for identifier: %" PRIu64 ".",
1835 									 function,
1836 									 data_block_back_pointer );
1837 
1838 									goto on_error;
1839 								}
1840 								else if( result != 0 )
1841 								{
1842 									if( ( (off64_t) ( block_buffer_data_offset + data_block_data_offset ) == index_value->file_offset )
1843 									 && ( (size32_t) data_block_data_size == index_value->data_size ) )
1844 									{
1845 										break;
1846 									}
1847 									result = 0;
1848 								}
1849 							}
1850 							if( result != 0 )
1851 							{
1852 #if defined( HAVE_DEBUG_OUTPUT )
1853 								if( libcnotify_verbose != 0 )
1854 								{
1855 									libcnotify_printf(
1856 									 "%s: recovered data block with identifier: %" PRIu64 " matches existing recovered item value.\n",
1857 									 function,
1858 									 data_block_back_pointer );
1859 								}
1860 #endif
1861 								block_offset += format_data_block_size;
1862 								block_size   -= format_data_block_size;
1863 
1864 /* TODO reset block_buffer_offset and block_buffer_size_available ? */
1865 
1866 								continue;
1867 							}
1868 							if( data_block_stored_checksum != 0 )
1869 							{
1870 								if( libfmapi_checksum_calculate_weak_crc32(
1871 								     &data_block_calculated_checksum,
1872 								     &( block_buffer[ data_block_data_offset ] ),
1873 								     data_block_data_size,
1874 								     0,
1875 								     error ) != 1 )
1876 								{
1877 									libcerror_error_set(
1878 									 error,
1879 									 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1880 									 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1881 									 "%s: unable to calculate weak CRC-32.",
1882 									 function );
1883 
1884 									goto on_error;
1885 								}
1886 								if( data_block_stored_checksum != data_block_calculated_checksum )
1887 								{
1888 #if defined( HAVE_DEBUG_OUTPUT )
1889 									if( libcnotify_verbose != 0 )
1890 									{
1891 										libcnotify_printf(
1892 										 "%s: mismatch in data block: %" PRIu64 " checksum ( %" PRIu32 " != %" PRIu32 " ).\n",
1893 										 function,
1894 										 data_block_back_pointer,
1895 										 data_block_stored_checksum,
1896 										 data_block_calculated_checksum );
1897 									}
1898 #endif
1899 									block_offset += format_data_block_size;
1900 									block_size   -= format_data_block_size;
1901 
1902 									continue;
1903 								}
1904 							}
1905 /* TODO consider data block as fragment */
1906 
1907 							data_block_data_size = ( ( data_block_data_size / format_data_block_size ) + 1 ) * format_data_block_size;
1908 
1909 #if defined( HAVE_DEBUG_OUTPUT )
1910 							if( libcnotify_verbose != 0 )
1911 							{
1912 								libcnotify_printf(
1913 								 "%s: data block back pointer: 0x%08" PRIx64 "\n",
1914 								 function,
1915 								 data_block_back_pointer );
1916 
1917 								libcnotify_printf(
1918 								 "%s: data block data at offset: %" PRIi64 " (0x%08" PRIx64 ") of size: %" PRIzd "\n",
1919 								 function,
1920 								 block_buffer_data_offset + data_block_data_offset,
1921 								 block_buffer_data_offset + data_block_data_offset,
1922 								 data_block_data_size );
1923 								libcnotify_print_data(
1924 								 &( block_buffer[ data_block_data_offset ] ),
1925 								 data_block_data_size,
1926 								 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1927 							}
1928 #endif
1929 						}
1930 					}
1931 					block_buffer_offset         += format_data_block_size;
1932 					block_buffer_size_available -= format_data_block_size;
1933 				}
1934 				else
1935 				{
1936 					block_buffer_offset         = 0;
1937 					block_buffer_size_available = 0;
1938 				}
1939 				block_offset += scan_block_size;
1940 				block_size   -= scan_block_size;
1941 			}
1942 		}
1943 	}
1944 	memory_free(
1945 	 block_buffer );
1946 
1947 	return( 1 );
1948 
1949 on_error:
1950 	if( block_buffer != NULL )
1951 	{
1952 		memory_free(
1953 		 block_buffer );
1954 	}
1955 	return( -1 );
1956 }
1957 
1958 /* Scans for recoverable index values in an index node
1959  * Returns 1 if successful, returns 0 if no valid index node could be found or -1 on error
1960  */
libpff_recover_index_values(libpff_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libpff_descriptors_index_t * descriptors_index,libpff_offsets_index_t * offsets_index,libcdata_range_list_t * unallocated_data_block_list,size64_t node_offset,uint8_t recovery_flags,libcerror_error_t ** error)1961 int libpff_recover_index_values(
1962      libpff_io_handle_t *io_handle,
1963      libbfio_handle_t *file_io_handle,
1964      libpff_descriptors_index_t *descriptors_index,
1965      libpff_offsets_index_t *offsets_index,
1966      libcdata_range_list_t *unallocated_data_block_list,
1967      size64_t node_offset,
1968      uint8_t recovery_flags,
1969      libcerror_error_t **error )
1970 {
1971 	libpff_index_value_t *index_value                 = NULL;
1972 	libpff_index_node_t *index_node                   = NULL;
1973 	uint8_t *node_entry_data                          = NULL;
1974 	const char *index_string                          = NULL;
1975 	static char *function                             = "libpff_recover_index_values";
1976 	off64_t index_value_file_offset                   = 0;
1977 	uint64_t index_value_data_identifier              = 0;
1978 	uint64_t index_value_identifier                   = 0;
1979 	uint64_t index_value_local_descriptors_identifier = 0;
1980         uint32_t maximum_data_block_data_size             = 0;
1981 	uint16_t index_value_data_size                    = 0;
1982 	uint8_t entry_index                               = 0;
1983 	int index_value_iterator                          = 0;
1984 	int number_of_index_values                        = 0;
1985 	int result                                        = 0;
1986 
1987 	if( io_handle == NULL )
1988 	{
1989 		libcerror_error_set(
1990 		 error,
1991 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1992 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1993 		 "%s: invalid IO handle.",
1994 		 function );
1995 
1996 		return( -1 );
1997 	}
1998 	if( ( io_handle->file_type != LIBPFF_FILE_TYPE_32BIT )
1999 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT )
2000 	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2001 	{
2002 		libcerror_error_set(
2003 		 error,
2004 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2005 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
2006 		 "%s: unsupported file type.",
2007 		 function );
2008 
2009 		return( -1 );
2010 	}
2011 	if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2012 	{
2013 		maximum_data_block_data_size = 8192 - 12;
2014 	}
2015 	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2016 	{
2017 		maximum_data_block_data_size = 8192 - 16;
2018 	}
2019 	else
2020 	{
2021 /* TODO: this value is currently assumed based on the 512 x 8 = 4k page */
2022 		maximum_data_block_data_size = 65536 - 24;
2023 	}
2024 	if( libpff_index_node_initialize(
2025 	     &index_node,
2026 	     error ) != 1 )
2027 	{
2028 		libcerror_error_set(
2029 		 error,
2030 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2031 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2032 		 "%s: unable to create index node.",
2033 		 function );
2034 
2035 		goto on_error;
2036 	}
2037 	if( libpff_index_node_read_file_io_handle(
2038 	     index_node,
2039 	     file_io_handle,
2040 	     node_offset,
2041 	     io_handle->file_type,
2042 	     error ) != 1 )
2043 	{
2044 #if defined( HAVE_DEBUG_OUTPUT )
2045 		if( ( libcnotify_verbose != 0 )
2046 		 && ( error != NULL )
2047 		 && ( *error != NULL ) )
2048 		{
2049 			libcnotify_print_error_backtrace(
2050 			 *error );
2051 		}
2052 #endif
2053 		libcerror_error_free(
2054 		 error );
2055 
2056 		libpff_index_node_free(
2057 		 &index_node,
2058 		 NULL );
2059 
2060 		return( 0 );
2061 	}
2062 	if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2063 	{
2064 		index_string = "descriptor";
2065 	}
2066 	else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2067 	{
2068 		index_string = "offset";
2069 	}
2070 	if( ( index_node->type != LIBPFF_INDEX_TYPE_DESCRIPTOR )
2071 	 && ( index_node->type != LIBPFF_INDEX_TYPE_OFFSET ) )
2072 	{
2073 #if defined( HAVE_DEBUG_OUTPUT )
2074 		if( libcnotify_verbose != 0 )
2075 		{
2076 			libcnotify_printf(
2077 			 "%s: unsupported index type: 0x%02" PRIx8 ".\n",
2078 			 function,
2079 			 index_node->type );
2080 		}
2081 #endif
2082 	}
2083 	else if( index_node->level != LIBPFF_INDEX_NODE_LEVEL_LEAF )
2084 	{
2085 #if defined( HAVE_DEBUG_OUTPUT )
2086 		if( libcnotify_verbose != 0 )
2087 		{
2088 			libcnotify_printf(
2089 			 "%s: skipping %s index branch node at level: %" PRIu8 ".\n",
2090 			 function,
2091 			 index_string,
2092 			 index_node->level );
2093 		}
2094 #endif
2095 	}
2096 	else
2097 	{
2098 		/* Check if the index leaf entries are recoverable
2099 		 */
2100 		for( entry_index = 0;
2101 		     entry_index < index_node->maximum_number_of_entries;
2102 		     entry_index++ )
2103 		{
2104 			if( libpff_index_node_get_entry_data(
2105 			     index_node,
2106 			     entry_index,
2107 			     &node_entry_data,
2108 			     error ) != 1 )
2109 			{
2110 				libcerror_error_set(
2111 				 error,
2112 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2113 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2114 				 "%s: unable to retrieve node entry: %" PRIu8 " data.",
2115 				 function,
2116 				 entry_index );
2117 
2118 				goto on_error;
2119 			}
2120 			if( node_entry_data == NULL )
2121 			{
2122 				libcerror_error_set(
2123 				 error,
2124 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2125 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2126 				 "%s: missing node entry: %" PRIu8 " data.",
2127 				 function,
2128 				 entry_index );
2129 
2130 				goto on_error;
2131 			}
2132 			if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2133 			{
2134 				byte_stream_copy_to_uint32_little_endian(
2135 				 node_entry_data,
2136 				 index_value_identifier );
2137 			}
2138 			else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2139 			      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2140 			{
2141 				byte_stream_copy_to_uint64_little_endian(
2142 				 node_entry_data,
2143 				 index_value_identifier );
2144 			}
2145 			/* Ignore the upper 32-bit of descriptor identifiers
2146 			 */
2147 			if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2148 			{
2149 				index_value_identifier &= 0xffffffffUL;
2150 			}
2151 #if defined( HAVE_DEBUG_OUTPUT )
2152 			if( libcnotify_verbose != 0 )
2153 			{
2154 				libcnotify_printf(
2155 				 "%s: analyzing %s index entry: %" PRIu8 " identifier: %" PRIu64 ".\n",
2156 				 function,
2157 				 index_string,
2158 				 entry_index,
2159 				 index_value_identifier );
2160 			}
2161 #endif
2162 			/* Ignore index values without an identifier
2163 			 */
2164 			if( index_value_identifier == 0 )
2165 			{
2166 #if defined( HAVE_DEBUG_OUTPUT )
2167 				if( libcnotify_verbose != 0 )
2168 				{
2169 					libcnotify_printf(
2170 					 "%s: %s index entry: %" PRIu8 " indentifier: %" PRIu64 " has an empty identifier.\n",
2171 					 function,
2172 					 index_string,
2173 					 entry_index,
2174 					 index_value_identifier );
2175 				}
2176 #endif
2177 				continue;
2178 			}
2179 			if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2180 			{
2181 				if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2182 				{
2183 					byte_stream_copy_to_uint32_little_endian(
2184 					 ( (pff_index_node_descriptor_entry_32bit_t *) node_entry_data )->data_identifier,
2185 					 index_value_data_identifier );
2186 					byte_stream_copy_to_uint32_little_endian(
2187 					 ( (pff_index_node_descriptor_entry_32bit_t *) node_entry_data )->local_descriptors_identifier,
2188 					 index_value_local_descriptors_identifier );
2189 				}
2190 				else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2191 				      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2192 				{
2193 					byte_stream_copy_to_uint64_little_endian(
2194 					 ( (pff_index_node_descriptor_entry_64bit_t *) node_entry_data )->data_identifier,
2195 					 index_value_data_identifier );
2196 					byte_stream_copy_to_uint64_little_endian(
2197 					 ( (pff_index_node_descriptor_entry_64bit_t *) node_entry_data )->local_descriptors_identifier,
2198 					 index_value_local_descriptors_identifier );
2199 				}
2200 			}
2201 			else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2202 			{
2203 				if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2204 				{
2205 					byte_stream_copy_to_uint32_little_endian(
2206 					 ( (pff_index_node_offset_entry_32bit_t *) node_entry_data )->file_offset,
2207 					 index_value_file_offset );
2208 					byte_stream_copy_to_uint16_little_endian(
2209 					 ( (pff_index_node_offset_entry_32bit_t *) node_entry_data )->data_size,
2210 					 index_value_data_size );
2211 				}
2212 				else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2213 				      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2214 				{
2215 					byte_stream_copy_to_uint64_little_endian(
2216 					 ( (pff_index_node_offset_entry_64bit_t *) node_entry_data )->file_offset,
2217 					 index_value_file_offset );
2218 					byte_stream_copy_to_uint16_little_endian(
2219 					 ( (pff_index_node_offset_entry_64bit_t *) node_entry_data )->data_size,
2220 					 index_value_data_size );
2221 				}
2222 			}
2223 			if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2224 			{
2225 				/* Ignore descriptor index values without a data identifier
2226 				 */
2227 				if( index_value_data_identifier == 0 )
2228 				{
2229 #if defined( HAVE_DEBUG_OUTPUT )
2230 					if( libcnotify_verbose != 0 )
2231 					{
2232 						libcnotify_printf(
2233 						 "%s: %s index entry: %" PRIu8 " identifier: %" PRIu64 " has an empty data identifier.\n",
2234 						 function,
2235 						 index_string,
2236 						 entry_index,
2237 						 index_value_identifier );
2238 					}
2239 #endif
2240 					continue;
2241 				}
2242 			}
2243 			else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2244 			{
2245 				/* Ignore index values without a valid file offset
2246 				 */
2247 				if( index_value_file_offset <= 0 )
2248 				{
2249 #if defined( HAVE_DEBUG_OUTPUT )
2250 					if( libcnotify_verbose != 0 )
2251 					{
2252 						libcnotify_printf(
2253 						 "%s: %s index entry: %" PRIu8 " identifier: %" PRIu64 " has an invalid file offset: %" PRIi64 ".\n",
2254 						 function,
2255 						 index_string,
2256 						 entry_index,
2257 						 index_value_identifier,
2258 						 index_value_file_offset );
2259 					}
2260 #endif
2261 					continue;
2262 				}
2263 				/* Ignore index values without a valid data size
2264 				 */
2265 				if( ( index_value_data_size == 0 )
2266 				 || ( (uint32_t) index_value_data_size > maximum_data_block_data_size ) )
2267 				{
2268 #if defined( HAVE_DEBUG_OUTPUT )
2269 					if( libcnotify_verbose != 0 )
2270 					{
2271 						libcnotify_printf(
2272 						 "%s: %s index entry: %" PRIu8 " identifier: %" PRIu64 " has an invalid data size: %" PRIu16 ".\n",
2273 						 function,
2274 						 index_string,
2275 						 entry_index,
2276 						 index_value_identifier,
2277 						 index_value_data_size );
2278 					}
2279 #endif
2280 					continue;
2281 				}
2282 			}
2283 			/* Check if the recovered item value matches the existing item value
2284 			 */
2285 			if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2286 			{
2287 				result = libpff_index_tree_get_value_by_identifier(
2288 					  descriptors_index->index_tree,
2289 					  file_io_handle,
2290 					  descriptors_index->index_cache,
2291 					  index_value_identifier,
2292 					  0,
2293 					  &index_value,
2294 					  error );
2295 			}
2296 			else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2297 			{
2298 				result = libpff_index_tree_get_value_by_identifier(
2299 					  offsets_index->index_tree,
2300 					  file_io_handle,
2301 					  offsets_index->index_cache,
2302 					  index_value_identifier,
2303 					  0,
2304 					  &index_value,
2305 					  error );
2306 			}
2307 			if( result == -1 )
2308 			{
2309 				libcerror_error_set(
2310 				 error,
2311 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2312 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2313 				 "%s: unable to retrieve %s index value for identifier: %" PRIu64 ".",
2314 				 function,
2315 				 index_string,
2316 				 index_value_identifier );
2317 
2318 				goto on_error;
2319 			}
2320 			else if( result != 0 )
2321 			{
2322 				if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2323 				{
2324 /* TODO what about parent changes ? */
2325 					if( ( index_value_data_identifier == index_value->data_identifier )
2326 					 && ( index_value_local_descriptors_identifier == index_value->local_descriptors_identifier ) )
2327 					{
2328 #if defined( HAVE_DEBUG_OUTPUT )
2329 						if( libcnotify_verbose != 0 )
2330 						{
2331 							libcnotify_printf(
2332 							 "%s: recovered descriptor index value: %" PRIu64 " matches existing item value.\n",
2333 							 function,
2334 							 index_value_identifier );
2335 						}
2336 #endif
2337 						continue;
2338 					}
2339 				}
2340 				else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2341 				{
2342 					if( ( index_value_file_offset == index_value->file_offset )
2343 					 && ( (size32_t) index_value_data_size == index_value->data_size ) )
2344 					{
2345 #if defined( HAVE_DEBUG_OUTPUT )
2346 						if( libcnotify_verbose != 0 )
2347 						{
2348 							libcnotify_printf(
2349 							 "%s: recovered offset index value: %" PRIu64 " matches existing item value.\n",
2350 							 function,
2351 							 index_value_identifier );
2352 						}
2353 #endif
2354 						continue;
2355 					}
2356 				}
2357 			}
2358 			/* Check for duplicates
2359 			 */
2360 			if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2361 			{
2362 				result = libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
2363 					  descriptors_index->recovered_index_tree,
2364 					  file_io_handle,
2365 					  descriptors_index->index_cache,
2366 					  index_value_identifier,
2367 					  &number_of_index_values,
2368 					  error );
2369 			}
2370 			else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2371 			{
2372 				result = libpff_index_tree_get_number_of_leaf_nodes_by_identifier(
2373 					  offsets_index->recovered_index_tree,
2374 					  file_io_handle,
2375 					  offsets_index->index_cache,
2376 					  index_value_identifier,
2377 					  &number_of_index_values,
2378 					  error );
2379 			}
2380 			if( result != 1 )
2381 			{
2382 				libcerror_error_set(
2383 				 error,
2384 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2385 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2386 				 "%s: unable to retrieve number of recovered %s index values for identifier: %" PRIu64 ".",
2387 				 function,
2388 				 index_string,
2389 				 index_value_identifier );
2390 
2391 				goto on_error;
2392 			}
2393 			result = 0;
2394 
2395 			for( index_value_iterator = 0;
2396 			     index_value_iterator < number_of_index_values;
2397 			     index_value_iterator++ )
2398 			{
2399 				if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2400 				{
2401 					result = libpff_index_tree_get_value_by_identifier(
2402 						  descriptors_index->recovered_index_tree,
2403 						  file_io_handle,
2404 						  descriptors_index->index_cache,
2405 						  index_value_identifier,
2406 						  index_value_iterator,
2407 						  &index_value,
2408 						  error );
2409 				}
2410 				else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2411 				{
2412 					result = libpff_index_tree_get_value_by_identifier(
2413 						  offsets_index->recovered_index_tree,
2414 						  file_io_handle,
2415 						  offsets_index->index_cache,
2416 						  index_value_identifier,
2417 						  index_value_iterator,
2418 						  &index_value,
2419 						  error );
2420 				}
2421 				if( result == -1 )
2422 				{
2423 					libcerror_error_set(
2424 					 error,
2425 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2426 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2427 					 "%s: unable to retrieve recovered %s index value for identifier: %" PRIu64 ".",
2428 					 function,
2429 					 index_string,
2430 					 index_value_identifier );
2431 
2432 					goto on_error;
2433 				}
2434 				else if( result != 0 )
2435 				{
2436 					if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2437 					{
2438 /* TODO what about parent changes ? */
2439 						if( ( index_value_data_identifier == index_value->data_identifier )
2440 						 && ( index_value_local_descriptors_identifier == index_value->local_descriptors_identifier ) )
2441 						{
2442 							break;
2443 						}
2444 					}
2445 					else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2446 					{
2447 						if( ( index_value_file_offset == index_value->file_offset )
2448 						 && ( (size32_t) index_value_data_size == index_value->data_size ) )
2449 						{
2450 							break;
2451 						}
2452 					}
2453 					result = 0;
2454 				}
2455 			}
2456 			if( result != 0 )
2457 			{
2458 #if defined( HAVE_DEBUG_OUTPUT )
2459 				if( libcnotify_verbose != 0 )
2460 				{
2461 					libcnotify_printf(
2462 					 "%s: recovered %s index value: %" PRIu64 " matches existing item value.\n",
2463 					 function,
2464 					 index_string,
2465 					 index_value_identifier );
2466 				}
2467 #endif
2468 				continue;
2469 			}
2470 			/* Check if the offset index value is unallocated according to the
2471 			 * unallocated data block list
2472 			 */
2473 			if( ( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2474 			 && ( ( recovery_flags & LIBPFF_RECOVERY_FLAG_IGNORE_ALLOCATION_DATA ) == 0 ) )
2475 			{
2476 				result = libcdata_range_list_range_is_present(
2477 					  unallocated_data_block_list,
2478 					  (uint64_t) index_value_file_offset,
2479 					  (uint64_t) index_value_data_size,
2480 					  error );
2481 
2482 				if( result == -1 )
2483 				{
2484 					libcerror_error_set(
2485 					 error,
2486 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2487 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2488 					 "%s: error determining if offset range is unallocated.",
2489 					 function );
2490 
2491 					goto on_error;
2492 				}
2493 				else if( result == 0 )
2494 				{
2495 #if defined( HAVE_DEBUG_OUTPUT )
2496 					if( libcnotify_verbose != 0 )
2497 					{
2498 						libcnotify_printf(
2499 						 "%s: %s index entry: %" PRIu8 " identifier: %" PRIu64 " refers to allocated range: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ").\n",
2500 						 function,
2501 						 index_string,
2502 						 entry_index,
2503 						 index_value_identifier,
2504 						 index_value_file_offset,
2505 						 index_value_file_offset + index_value_data_size,
2506 						 index_value_data_size );
2507 					}
2508 #endif
2509 					continue;
2510 				}
2511 #if defined( HAVE_DEBUG_OUTPUT )
2512 				if( libcnotify_verbose != 0 )
2513 				{
2514 					libcnotify_printf(
2515 					 "%s: %s index entry: %" PRIu8 " identifier: %" PRIu64 " refers to unallocated range: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ").\n",
2516 					 function,
2517 					 index_string,
2518 					 entry_index,
2519 					 index_value_identifier,
2520 					 index_value_file_offset,
2521 					 index_value_file_offset + index_value_data_size,
2522 					 index_value_data_size );
2523 				}
2524 #endif
2525 			}
2526 			/* Move the recovered node to the index
2527 			 */
2528 #if defined( HAVE_DEBUG_OUTPUT )
2529 			if( libcnotify_verbose != 0 )
2530 			{
2531 				libcnotify_printf(
2532 				 "%s: %s index entry: %" PRIu8 " identifier: %" PRIu64 " is recoverable.\n",
2533 				 function,
2534 				 index_string,
2535 				 entry_index,
2536 				 index_value_identifier );
2537 			}
2538 #endif
2539 			if( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
2540 			{
2541 				result = libpff_index_tree_insert_value(
2542 					  descriptors_index->recovered_index_tree,
2543 					  file_io_handle,
2544 					  descriptors_index->index_cache,
2545 					  index_value_identifier,
2546 					  node_offset,
2547 				          (size64_t) entry_index,
2548 					  error );
2549 			}
2550 			else if( index_node->type == LIBPFF_INDEX_TYPE_OFFSET )
2551 			{
2552 				result = libpff_index_tree_insert_value(
2553 					  offsets_index->recovered_index_tree,
2554 					  file_io_handle,
2555 					  offsets_index->index_cache,
2556 					  index_value_identifier,
2557 					  node_offset,
2558 				          (size64_t) entry_index,
2559 					  error );
2560 			}
2561 			if( result != 1 )
2562 			{
2563 				libcerror_error_set(
2564 				 error,
2565 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2566 				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
2567 				 "%s: unable to insert %s index value: %" PRIu64 " to recovered index tree.",
2568 				 function,
2569 				 index_string,
2570 				 index_value_identifier );
2571 
2572 				goto on_error;
2573 			}
2574 			node_offset += index_node->entry_size;
2575 		}
2576 	}
2577 	if( libpff_index_node_free(
2578 	     &index_node,
2579 	     error ) != 1 )
2580 	{
2581 		libcerror_error_set(
2582 		 error,
2583 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2584 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2585 		 "%s: unable to free index node.",
2586 		 function );
2587 
2588 		goto on_error;
2589 	}
2590 #if defined( HAVE_DEBUG_OUTPUT )
2591 	if( libcnotify_verbose != 0 )
2592 	{
2593 		libcnotify_printf(
2594 		 "\n" );
2595 	}
2596 #endif
2597 	return( 1 );
2598 
2599 on_error:
2600 	if( index_node != NULL )
2601 	{
2602 		libpff_index_node_free(
2603 		 &index_node,
2604 		 NULL );
2605 	}
2606 	return( -1 );
2607 }
2608 
2609 /* Scans for recoverable local descriptors
2610  * Returns 1 if successful, returns 0 if no valid local descriptors node could be found or -1 on error
2611  */
libpff_recover_local_descriptors(libpff_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libpff_offsets_index_t * offsets_index,uint64_t local_descriptors_identifier,libcerror_error_t ** error)2612 int libpff_recover_local_descriptors(
2613      libpff_io_handle_t *io_handle,
2614      libbfio_handle_t *file_io_handle,
2615      libpff_offsets_index_t *offsets_index,
2616      uint64_t local_descriptors_identifier,
2617      libcerror_error_t **error )
2618 {
2619 	libpff_index_value_t *offset_index_value                     = NULL;
2620 	libpff_local_descriptor_node_t *local_descriptor_node        = NULL;
2621 	uint8_t *node_entry_data                                     = NULL;
2622 	static char *function                                        = "libpff_recover_local_descriptors";
2623 	uint64_t local_descriptor_value_identifier                   = 0;
2624 	uint64_t local_descriptor_value_data_identifier              = 0;
2625 	uint64_t local_descriptor_value_local_descriptors_identifier = 0;
2626 	uint64_t local_descriptor_value_sub_node_identifier          = 0;
2627 	uint16_t entry_index                                         = 0;
2628 	int result                                                   = 1;
2629 
2630 	if( io_handle == NULL )
2631 	{
2632 		libcerror_error_set(
2633 		 error,
2634 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2635 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2636 		 "%s: invalid IO handle.",
2637 		 function );
2638 
2639 		return( -1 );
2640 	}
2641 	if( libpff_offsets_index_get_index_value_by_identifier(
2642 	     offsets_index,
2643 	     file_io_handle,
2644 	     local_descriptors_identifier,
2645 	     1,
2646 	     0,
2647 	     &offset_index_value,
2648 	     error ) != 1 )
2649 	{
2650 #if defined( HAVE_DEBUG_OUTPUT )
2651 		if( ( libcnotify_verbose != 0 )
2652 		 && ( error != NULL )
2653 		 && ( *error != NULL ) )
2654 		{
2655 			libcnotify_print_error_backtrace(
2656 			 *error );
2657 		}
2658 #endif
2659 		libcerror_error_free(
2660 		 error );
2661 
2662 		return( 0 );
2663 	}
2664 	if( offset_index_value == NULL )
2665 	{
2666 		libcerror_error_set(
2667 		 error,
2668 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2669 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2670 		 "%s: missing offset index value.",
2671 		 function );
2672 
2673 		return( -1 );
2674 	}
2675 #if defined( HAVE_DEBUG_OUTPUT )
2676 	if( libcnotify_verbose != 0 )
2677 	{
2678 		libcnotify_printf(
2679 		 "%s: local descriptor node identifier: %" PRIu64 " (%s) at offset: %" PRIi64 " of size: %" PRIu32 "\n",
2680 		 function,
2681 		 offset_index_value->identifier,
2682 		 ( ( offset_index_value->identifier & LIBPFF_OFFSET_INDEX_IDENTIFIER_FLAG_INTERNAL ) ? "internal" : "external" ),
2683 		 offset_index_value->file_offset,
2684 		 offset_index_value->data_size );
2685 	}
2686 #endif
2687 	if( libpff_local_descriptor_node_initialize(
2688 	     &local_descriptor_node,
2689 	     error ) != 1 )
2690 	{
2691 		libcerror_error_set(
2692 		 error,
2693 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2694 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2695 		 "%s: unable to create local descriptor node.",
2696 		 function );
2697 
2698 		return( -1 );
2699 	}
2700 	if( libpff_local_descriptor_node_read(
2701 	     local_descriptor_node,
2702 	     io_handle,
2703 	     file_io_handle,
2704 	     0 /* TODO descriptor identifier */,
2705 	     offset_index_value->identifier,
2706 	     offset_index_value->file_offset,
2707 	     offset_index_value->data_size,
2708 	     error ) != 1 )
2709 	{
2710 #if defined( HAVE_DEBUG_OUTPUT )
2711 		if( ( libcnotify_verbose != 0 )
2712 		 && ( error != NULL )
2713 		 && ( *error != NULL ) )
2714 		{
2715 			libcnotify_print_error_backtrace(
2716 			 *error );
2717 		}
2718 #endif
2719 		libcerror_error_free(
2720 		 error );
2721 
2722 		libpff_local_descriptor_node_free(
2723 		 &local_descriptor_node,
2724 		 NULL );
2725 
2726 		return( 0 );
2727 	}
2728 	for( entry_index = 0;
2729 	     entry_index < local_descriptor_node->number_of_entries;
2730 	     entry_index++ )
2731 	{
2732 		if( libpff_local_descriptor_node_get_entry_data(
2733 		     local_descriptor_node,
2734 		     entry_index,
2735 		     &node_entry_data,
2736 		     error ) != 1 )
2737 		{
2738 			libcerror_error_set(
2739 			 error,
2740 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2741 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2742 			 "%s: unable to retrieve node entry: %" PRIu16 " data.",
2743 			 function,
2744 			 entry_index );
2745 
2746 			return( -1 );
2747 		}
2748 		if( node_entry_data == NULL )
2749 		{
2750 			libcerror_error_set(
2751 			 error,
2752 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2753 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2754 			 "%s: missing node entry: %" PRIu16 " data.",
2755 			 function,
2756 			 entry_index );
2757 
2758 			return( -1 );
2759 		}
2760 		if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2761 		{
2762 			byte_stream_copy_to_uint32_little_endian(
2763 			 node_entry_data,
2764 			 local_descriptor_value_identifier );
2765 
2766 			node_entry_data += 4;
2767 		}
2768 		else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2769 		      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2770 		{
2771 			byte_stream_copy_to_uint64_little_endian(
2772 			 node_entry_data,
2773 			 local_descriptor_value_identifier );
2774 
2775 			node_entry_data += 8;
2776 		}
2777 		/* Ignore the upper 32-bit of local descriptor identifiers
2778 		 */
2779 		local_descriptor_value_identifier &= 0xffffffffUL;
2780 
2781 		/* Ignore local descriptor values without a data identifier
2782 		 */
2783 		if( local_descriptor_value_identifier == 0 )
2784 		{
2785 #if defined( HAVE_DEBUG_OUTPUT )
2786 			if( libcnotify_verbose != 0 )
2787 			{
2788 				libcnotify_printf(
2789 				 "%s: local descriptor entry: %" PRIu8 " identifier: %" PRIu64 " has an empty identifier.\n",
2790 				 function,
2791 				 entry_index,
2792 				 local_descriptor_value_identifier );
2793 			}
2794 #endif
2795 			result = 0;
2796 
2797 			break;
2798 		}
2799 		if( local_descriptor_node->level == LIBPFF_LOCAL_DESCRIPTOR_NODE_LEVEL_LEAF )
2800 		{
2801 			if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2802 			{
2803 				byte_stream_copy_to_uint32_little_endian(
2804 				 node_entry_data,
2805 				 local_descriptor_value_data_identifier );
2806 
2807 				node_entry_data += 4;
2808 
2809 				byte_stream_copy_to_uint32_little_endian(
2810 				 node_entry_data,
2811 				 local_descriptor_value_local_descriptors_identifier );
2812 
2813 				node_entry_data += 4;
2814 			}
2815 			else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2816 			      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2817 			{
2818 				byte_stream_copy_to_uint64_little_endian(
2819 				 node_entry_data,
2820 				 local_descriptor_value_data_identifier );
2821 
2822 				node_entry_data += 8;
2823 
2824 				byte_stream_copy_to_uint64_little_endian(
2825 				 node_entry_data,
2826 				 local_descriptor_value_local_descriptors_identifier );
2827 
2828 				node_entry_data += 8;
2829 			}
2830 			/* Ignore local descriptor values without a data identifier
2831 			 */
2832 			if( local_descriptor_value_data_identifier == 0 )
2833 			{
2834 #if defined( HAVE_DEBUG_OUTPUT )
2835 				if( libcnotify_verbose != 0 )
2836 				{
2837 					libcnotify_printf(
2838 					 "%s: local descriptor entry: %" PRIu8 " identifier: %" PRIu64 " has an empty data identifier.\n",
2839 					 function,
2840 					 entry_index,
2841 					 local_descriptor_value_identifier );
2842 				}
2843 #endif
2844 				result = 0;
2845 
2846 				break;
2847 			}
2848 		}
2849 		else
2850 		{
2851 			if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
2852 			{
2853 				byte_stream_copy_to_uint32_little_endian(
2854 				 node_entry_data,
2855 				 local_descriptor_value_sub_node_identifier );
2856 
2857 				node_entry_data += 4;
2858 			}
2859 			else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
2860 			      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
2861 			{
2862 				byte_stream_copy_to_uint64_little_endian(
2863 				 node_entry_data,
2864 				 local_descriptor_value_sub_node_identifier );
2865 
2866 				node_entry_data += 8;
2867 			}
2868 			/* Ignore local descriptor values without a sub node identifier
2869 			 */
2870 			if( local_descriptor_value_sub_node_identifier == 0 )
2871 			{
2872 #if defined( HAVE_DEBUG_OUTPUT )
2873 				if( libcnotify_verbose != 0 )
2874 				{
2875 					libcnotify_printf(
2876 					 "%s: local descriptor entry: %" PRIu8 " identifier: %" PRIu64 " has an empty sub node identifier.\n",
2877 					 function,
2878 					 entry_index,
2879 					 local_descriptor_value_identifier );
2880 				}
2881 #endif
2882 				result = 0;
2883 
2884 				break;
2885 			}
2886 			result = libpff_recover_local_descriptors(
2887 				  io_handle,
2888 				  file_io_handle,
2889 				  offsets_index,
2890 				  local_descriptor_value_sub_node_identifier,
2891 				  error );
2892 
2893 			if( result == -1 )
2894 			{
2895 				libcerror_error_set(
2896 				 error,
2897 				 LIBCERROR_ERROR_DOMAIN_IO,
2898 				 LIBCERROR_IO_ERROR_READ_FAILED,
2899 				 "%s: unable to read local descriptors with identifier: %" PRIu64 ".",
2900 				 function,
2901 				 local_descriptor_value_sub_node_identifier );
2902 
2903 				libpff_local_descriptor_node_free(
2904 				 &local_descriptor_node,
2905 				 NULL );
2906 
2907 				return( -1 );
2908 			}
2909 			else if( result == 0 )
2910 			{
2911 				break;
2912 			}
2913 		}
2914 	}
2915 	if( libpff_local_descriptor_node_free(
2916 	     &local_descriptor_node,
2917 	     error ) != 1 )
2918 	{
2919 		libcerror_error_set(
2920 		 error,
2921 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2922 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2923 		 "%s: unable to free local descriptor node.",
2924 		 function );
2925 
2926 		return( -1 );
2927 	}
2928 #if defined( HAVE_DEBUG_OUTPUT )
2929 	if( libcnotify_verbose != 0 )
2930 	{
2931 		libcnotify_printf(
2932 		 "\n" );
2933 	}
2934 #endif
2935 	return( result );
2936 }
2937 
2938