1 /*
2  * The catalog B-tree file functions
3  *
4  * Copyright (C) 2009-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <byte_stream.h>
24 #include <types.h>
25 
26 #include "libfshfs_btree_node.h"
27 #include "libfshfs_btree_node_record.h"
28 #include "libfshfs_catalog_btree_file.h"
29 #include "libfshfs_catalog_btree_key.h"
30 #include "libfshfs_definitions.h"
31 #include "libfshfs_directory_entry.h"
32 #include "libfshfs_directory_record.h"
33 #include "libfshfs_file_record.h"
34 #include "libfshfs_libbfio.h"
35 #include "libfshfs_libcdata.h"
36 #include "libfshfs_libcerror.h"
37 #include "libfshfs_libcnotify.h"
38 #include "libfshfs_libuna.h"
39 #include "libfshfs_thread_record.h"
40 
41 #include "fshfs_catalog_file.h"
42 
43 /* Retrieves the catalog B-tree key from a specific B-tree node record
44  * Returns 1 if successful or -1 on error
45  */
libfshfs_catalog_btree_file_get_key_from_node_by_index(libfshfs_btree_node_t * node,uint16_t record_index,libfshfs_catalog_btree_key_t ** node_key,libcerror_error_t ** error)46 int libfshfs_catalog_btree_file_get_key_from_node_by_index(
47      libfshfs_btree_node_t *node,
48      uint16_t record_index,
49      libfshfs_catalog_btree_key_t **node_key,
50      libcerror_error_t **error )
51 {
52 	libfshfs_btree_node_record_t *node_record   = NULL;
53 	libfshfs_catalog_btree_key_t *safe_node_key = NULL;
54 	static char *function                       = "libfshfs_catalog_btree_file_get_key_from_node_by_index";
55 
56 	if( node_key == NULL )
57 	{
58 		libcerror_error_set(
59 		 error,
60 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
61 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
62 		 "%s: invalid catalog B-tree key.",
63 		 function );
64 
65 		return( -1 );
66 	}
67 	if( libfshfs_btree_node_get_record_by_index(
68 	     node,
69 	     record_index,
70 	     &node_record,
71 	     error ) == -1 )
72 	{
73 		libcerror_error_set(
74 		 error,
75 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
76 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
77 		 "%s: unable to retrieve node record: %" PRIu16 ".",
78 		 function,
79 		 record_index );
80 
81 		goto on_error;
82 	}
83 	if( node_record == NULL )
84 	{
85 		libcerror_error_set(
86 		 error,
87 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
88 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
89 		 "%s: missing B-tree node record: %" PRIu16 ".",
90 		 function,
91 		 record_index );
92 
93 		goto on_error;
94 	}
95 	if( node_record->key_value == NULL )
96 	{
97 		if( libfshfs_catalog_btree_key_initialize(
98 		     &safe_node_key,
99 		     error ) != 1 )
100 		{
101 			libcerror_error_set(
102 			 error,
103 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
104 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
105 			 "%s: unable to create catalog B-tree key.",
106 			 function );
107 
108 			goto on_error;
109 		}
110 		if( libfshfs_catalog_btree_key_read_data(
111 		     safe_node_key,
112 		     node_record->data,
113 		     node_record->data_size,
114 		     error ) != 1 )
115 		{
116 			libcerror_error_set(
117 			 error,
118 			 LIBCERROR_ERROR_DOMAIN_IO,
119 			 LIBCERROR_IO_ERROR_READ_FAILED,
120 			 "%s: unable to read catalog B-tree key.",
121 			 function );
122 
123 			goto on_error;
124 		}
125 		node_record->key_value               = (intptr_t *) safe_node_key;
126 		node_record->key_value_free_function = (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_catalog_btree_key_free;
127 	}
128 	*node_key = (libfshfs_catalog_btree_key_t *) node_record->key_value;
129 
130 	return( 1 );
131 
132 on_error:
133 	if( safe_node_key != NULL )
134 	{
135 		libfshfs_catalog_btree_key_free(
136 		 &safe_node_key,
137 		 NULL );
138 	}
139 	return( -1 );
140 }
141 
142 /* Retrieves a sub node number for from the catalog B-tree key
143  * Returns 1 if successful or -1 on error
144  */
libfshfs_catalog_btree_file_get_sub_node_number_from_key(libfshfs_catalog_btree_key_t * node_key,uint32_t * sub_node_number,libcerror_error_t ** error)145 int libfshfs_catalog_btree_file_get_sub_node_number_from_key(
146      libfshfs_catalog_btree_key_t *node_key,
147      uint32_t *sub_node_number,
148      libcerror_error_t **error )
149 {
150 	static char *function = "libfshfs_catalog_btree_file_get_sub_node_number_from_key";
151 
152 	if( node_key == NULL )
153 	{
154 		libcerror_error_set(
155 		 error,
156 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
157 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
158 		 "%s: invalid catalog B-tree key.",
159 		 function );
160 
161 		return( -1 );
162 	}
163 	if( node_key->record_data == NULL )
164 	{
165 		libcerror_error_set(
166 		 error,
167 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
168 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
169 		 "%s: invalid catalog B-tree key - missing record data.",
170 		 function );
171 
172 		return( -1 );
173 	}
174 	if( node_key->record_data_size < 4 )
175 	{
176 		libcerror_error_set(
177 		 error,
178 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
179 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
180 		 "%s: invalid catalog B-tree key - record data size value out of bounds.",
181 		 function );
182 
183 		return( -1 );
184 	}
185 	if( sub_node_number == NULL )
186 	{
187 		libcerror_error_set(
188 		 error,
189 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
190 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
191 		 "%s: invalid sub node number.",
192 		 function );
193 
194 		return( -1 );
195 	}
196 	byte_stream_copy_to_uint32_big_endian(
197 	 node_key->record_data,
198 	 *sub_node_number );
199 
200 	return( 1 );
201 }
202 
203 /* Retrieves a thread record for from the catalog B-tree key
204  * Returns 1 if successful, 0 if not found or -1 on error
205  */
libfshfs_catalog_btree_file_get_thread_record_from_key(libfshfs_catalog_btree_key_t * node_key,libfshfs_thread_record_t ** thread_record,libcerror_error_t ** error)206 int libfshfs_catalog_btree_file_get_thread_record_from_key(
207      libfshfs_catalog_btree_key_t *node_key,
208      libfshfs_thread_record_t **thread_record,
209      libcerror_error_t **error )
210 {
211 	libfshfs_thread_record_t *safe_thread_record = NULL;
212 	static char *function                        = "libfshfs_catalog_btree_file_get_thread_record_from_key";
213 	uint16_t record_type                         = 0;
214 	int result                                   = 0;
215 
216 	if( node_key == NULL )
217 	{
218 		libcerror_error_set(
219 		 error,
220 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
221 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
222 		 "%s: invalid catalog B-tree key.",
223 		 function );
224 
225 		return( -1 );
226 	}
227 	if( node_key->record_data == NULL )
228 	{
229 		libcerror_error_set(
230 		 error,
231 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
232 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
233 		 "%s: invalid catalog B-tree key - missing record data.",
234 		 function );
235 
236 		return( -1 );
237 	}
238 	if( node_key->record_data_size < 2 )
239 	{
240 		libcerror_error_set(
241 		 error,
242 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
243 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
244 		 "%s: invalid catalog B-tree key - record data size value out of bounds.",
245 		 function );
246 
247 		goto on_error;
248 	}
249 	if( thread_record == NULL )
250 	{
251 		libcerror_error_set(
252 		 error,
253 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
254 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
255 		 "%s: invalid thread record.",
256 		 function );
257 
258 		return( -1 );
259 	}
260 	if( *thread_record != NULL )
261 	{
262 		libcerror_error_set(
263 		 error,
264 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
265 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
266 		 "%s: invalid thread record value already set.",
267 		 function );
268 
269 		return( -1 );
270 	}
271 	byte_stream_copy_to_uint16_big_endian(
272 	 node_key->record_data,
273 	 record_type );
274 
275 	switch( record_type )
276 	{
277 		case LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_THREAD_RECORD:
278 		case LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_THREAD_RECORD:
279 		case LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_THREAD_RECORD:
280 		case LIBFSHFS_RECORD_TYPE_HFS_FILE_THREAD_RECORD:
281 			if( libfshfs_thread_record_initialize(
282 			     &safe_thread_record,
283 			     node_key->parent_identifier,
284 			     error ) != 1 )
285 			{
286 				libcerror_error_set(
287 				 error,
288 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
289 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
290 				 "%s: unable to create thread record.",
291 				 function );
292 
293 				goto on_error;
294 			}
295 			if( libfshfs_thread_record_read_data(
296 			     safe_thread_record,
297 			     node_key->record_data,
298 			     node_key->record_data_size,
299 			     error ) != 1 )
300 			{
301 				libcerror_error_set(
302 				 error,
303 				 LIBCERROR_ERROR_DOMAIN_IO,
304 				 LIBCERROR_IO_ERROR_READ_FAILED,
305 				 "%s: unable to read thread record.",
306 				 function );
307 
308 				goto on_error;
309 			}
310 			*thread_record = safe_thread_record;
311 
312 			result = 1;
313 
314 			break;
315 
316 		default:
317 			break;
318 	}
319 	return( result );
320 
321 on_error:
322 	if( safe_thread_record != NULL )
323 	{
324 		libfshfs_thread_record_free(
325 		 &safe_thread_record,
326 		 NULL );
327 	}
328 	return( -1 );
329 }
330 
331 /* Retrieves a thread record for a specific identifier from the catalog B-tree leaf node
332  * Returns 1 if successful, 0 if not found or -1 on error
333  */
libfshfs_catalog_btree_file_get_thread_record_from_leaf_node(libfshfs_btree_file_t * btree_file,libfshfs_btree_node_t * node,uint32_t identifier,libfshfs_thread_record_t ** thread_record,libcerror_error_t ** error)334 int libfshfs_catalog_btree_file_get_thread_record_from_leaf_node(
335      libfshfs_btree_file_t *btree_file,
336      libfshfs_btree_node_t *node,
337      uint32_t identifier,
338      libfshfs_thread_record_t **thread_record,
339      libcerror_error_t **error )
340 {
341 	libfshfs_catalog_btree_key_t *node_key = NULL;
342 	static char *function                  = "libfshfs_catalog_btree_file_get_thread_record_from_leaf_node";
343 	uint16_t record_index                  = 0;
344 	int is_leaf_node                       = 0;
345 	int result                             = 0;
346 
347 	if( btree_file == NULL )
348 	{
349 		libcerror_error_set(
350 		 error,
351 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
352 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
353 		 "%s: invalid B-tree file.",
354 		 function );
355 
356 		return( -1 );
357 	}
358 	if( node == NULL )
359 	{
360 		libcerror_error_set(
361 		 error,
362 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
363 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
364 		 "%s: invalid B-tree node.",
365 		 function );
366 
367 		return( -1 );
368 	}
369 	if( node->descriptor == NULL )
370 	{
371 		libcerror_error_set(
372 		 error,
373 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
374 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
375 		 "%s: invalid B-tree node - missing descriptor.",
376 		 function );
377 
378 		return( -1 );
379 	}
380 	if( thread_record == NULL )
381 	{
382 		libcerror_error_set(
383 		 error,
384 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
385 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
386 		 "%s: invalid thread record.",
387 		 function );
388 
389 		return( -1 );
390 	}
391 	is_leaf_node = libfshfs_btree_node_is_leaf_node(
392 	                node,
393 	                error );
394 
395 	if( is_leaf_node == -1 )
396 	{
397 		libcerror_error_set(
398 		 error,
399 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
400 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
401 		 "%s: unable to determine if B-tree node is a leaf node.",
402 		 function );
403 
404 		goto on_error;
405 	}
406 	else if( is_leaf_node == 0 )
407 	{
408 		libcerror_error_set(
409 		 error,
410 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
411 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
412 		 "%s: invalid node - not a leaf node.",
413 		 function );
414 
415 		goto on_error;
416 	}
417 	for( record_index = 0;
418 	     record_index < node->descriptor->number_of_records;
419 	     record_index++ )
420 	{
421 		if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
422 		     node,
423 		     record_index,
424 		     &node_key,
425 		     error ) == -1 )
426 		{
427 			libcerror_error_set(
428 			 error,
429 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
430 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
431 			 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
432 			 function,
433 			 record_index );
434 
435 			goto on_error;
436 		}
437 		if( node_key == NULL )
438 		{
439 			libcerror_error_set(
440 			 error,
441 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
442 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
443 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
444 			 function,
445 			 record_index );
446 
447 			goto on_error;
448 		}
449 		if( ( node_key->parent_identifier == identifier )
450 		 && ( node_key->name_size == 0 ) )
451 		{
452 			result = libfshfs_catalog_btree_file_get_thread_record_from_key(
453 			          node_key,
454 			          thread_record,
455 			          error );
456 
457 			if( result == -1 )
458 			{
459 				libcerror_error_set(
460 				 error,
461 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
462 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
463 				 "%s: unable to retrieve thread record from catalog B-Tree key.",
464 				 function );
465 
466 				goto on_error;
467 			}
468 		}
469 		if( ( result == 1 )
470 		 || ( node_key->parent_identifier > identifier ) )
471 		{
472 			break;
473 		}
474 	}
475 	return( result );
476 
477 on_error:
478 	if( *thread_record != NULL )
479 	{
480 		libfshfs_thread_record_free(
481 		 thread_record,
482 		 NULL );
483 	}
484 	return( -1 );
485 }
486 
487 /* Retrieves a thread record for a specific identifier from the catalog B-tree branch node
488  * Returns 1 if successful, 0 if not found or -1 on error
489  */
libfshfs_catalog_btree_file_get_thread_record_from_branch_node(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,libfshfs_btree_node_t * node,uint32_t identifier,libfshfs_thread_record_t ** thread_record,int recursion_depth,libcerror_error_t ** error)490 int libfshfs_catalog_btree_file_get_thread_record_from_branch_node(
491      libfshfs_btree_file_t *btree_file,
492      libbfio_handle_t *file_io_handle,
493      libfshfs_btree_node_t *node,
494      uint32_t identifier,
495      libfshfs_thread_record_t **thread_record,
496      int recursion_depth,
497      libcerror_error_t **error )
498 {
499 	libfshfs_btree_node_t *sub_node             = NULL;
500 	libfshfs_catalog_btree_key_t *last_node_key = NULL;
501 	libfshfs_catalog_btree_key_t *node_key      = NULL;
502 	static char *function                       = "libfshfs_catalog_btree_file_get_thread_record_from_branch_node";
503 	uint32_t sub_node_number                    = 0;
504 	uint16_t record_index                       = 0;
505 	uint8_t node_type                           = 0;
506 	int is_branch_node                          = 0;
507 	int result                                  = 0;
508 
509 	if( btree_file == NULL )
510 	{
511 		libcerror_error_set(
512 		 error,
513 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
514 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
515 		 "%s: invalid B-tree file.",
516 		 function );
517 
518 		return( -1 );
519 	}
520 	if( node == NULL )
521 	{
522 		libcerror_error_set(
523 		 error,
524 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
525 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
526 		 "%s: invalid B-tree node.",
527 		 function );
528 
529 		return( -1 );
530 	}
531 	if( node->descriptor == NULL )
532 	{
533 		libcerror_error_set(
534 		 error,
535 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
536 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
537 		 "%s: invalid B-tree node - missing descriptor.",
538 		 function );
539 
540 		return( -1 );
541 	}
542 	if( thread_record == NULL )
543 	{
544 		libcerror_error_set(
545 		 error,
546 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
547 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
548 		 "%s: invalid thread record.",
549 		 function );
550 
551 		return( -1 );
552 	}
553 	if( ( recursion_depth < 0 )
554 	 || ( recursion_depth > LIBFSHFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
555 	{
556 		libcerror_error_set(
557 		 error,
558 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
559 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
560 		 "%s: invalid recursion depth value out of bounds.",
561 		 function );
562 
563 		return( -1 );
564 	}
565 	is_branch_node = libfshfs_btree_node_is_branch_node(
566 	                  node,
567 	                  error );
568 
569 	if( is_branch_node == -1 )
570 	{
571 		libcerror_error_set(
572 		 error,
573 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
574 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
575 		 "%s: unable to determine if B-tree node is a branch node.",
576 		 function );
577 
578 		goto on_error;
579 	}
580 	else if( is_branch_node == 0 )
581 	{
582 		libcerror_error_set(
583 		 error,
584 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
585 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
586 		 "%s: invalid node - not a branch node.",
587 		 function );
588 
589 		goto on_error;
590 	}
591 	if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
592 	     node,
593 	     0,
594 	     &last_node_key,
595 	     error ) == -1 )
596 	{
597 		libcerror_error_set(
598 		 error,
599 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
600 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
601 		 "%s: unable to retrieve catalog B-tree key: 0.",
602 		 function );
603 
604 		goto on_error;
605 	}
606 	node_key = last_node_key;
607 
608 	for( record_index = 1;
609 	     record_index <= node->descriptor->number_of_records;
610 	     record_index++ )
611 	{
612 		if( record_index < node->descriptor->number_of_records )
613 		{
614 			if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
615 			     node,
616 			     record_index,
617 			     &node_key,
618 			     error ) == -1 )
619 			{
620 				libcerror_error_set(
621 				 error,
622 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
623 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
624 				 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
625 				 function,
626 				 record_index );
627 
628 				goto on_error;
629 			}
630 		}
631 		if( node_key == NULL )
632 		{
633 			libcerror_error_set(
634 			 error,
635 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
636 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
637 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
638 			 function,
639 			 record_index );
640 
641 			goto on_error;
642 		}
643 		if( ( record_index == node->descriptor->number_of_records )
644 		 || ( node_key->parent_identifier >= identifier ) )
645 		{
646 			if( libfshfs_catalog_btree_file_get_sub_node_number_from_key(
647 			     last_node_key,
648 			     &sub_node_number,
649 			     error ) != 1 )
650 			{
651 				libcerror_error_set(
652 				 error,
653 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
654 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
655 				 "%s: unable to retrieve sub node number from catalog B-Tree key.",
656 				 function );
657 
658 				goto on_error;
659 			}
660 #if defined( HAVE_DEBUG_OUTPUT )
661 			if( libcnotify_verbose != 0 )
662 			{
663 				libcnotify_printf(
664 				 "%s: B-tree sub node number\t: %" PRIu32 "\n",
665 				 function,
666 				 sub_node_number );
667 
668 				libcnotify_printf(
669 				 "\n" );
670 			}
671 #endif
672 			if( libfshfs_btree_file_get_node_by_number(
673 			     btree_file,
674 			     file_io_handle,
675 			     sub_node_number,
676 			     &sub_node,
677 			     recursion_depth,
678 			     error ) == -1 )
679 			{
680 				libcerror_error_set(
681 				 error,
682 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
683 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
684 				 "%s: unable to retrieve B-tree sub node: %" PRIu32 ".",
685 				 function,
686 				 sub_node_number );
687 
688 				goto on_error;
689 			}
690 			if( libfshfs_btree_node_get_node_type(
691 			     sub_node,
692 			     &node_type,
693 			     error ) != 1 )
694 			{
695 				libcerror_error_set(
696 				 error,
697 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
698 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
699 				 "%s: unable to determine if B-tree sub node: %" PRIu32 " type.",
700 				 function,
701 				 sub_node_number );
702 
703 				goto on_error;
704 			}
705 			if( node_type == 0x00 )
706 			{
707 				result = libfshfs_catalog_btree_file_get_thread_record_from_branch_node(
708 					  btree_file,
709 					  file_io_handle,
710 					  sub_node,
711 					  identifier,
712 					  thread_record,
713 					  recursion_depth + 1,
714 					  error );
715 			}
716 			else if( node_type == 0xff )
717 			{
718 				result = libfshfs_catalog_btree_file_get_thread_record_from_leaf_node(
719 				          btree_file,
720 				          sub_node,
721 				          identifier,
722 				          thread_record,
723 				          error );
724 			}
725 			if( result == -1 )
726 			{
727 				libcerror_error_set(
728 				 error,
729 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
730 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
731 				 "%s: unable to retrieve thread record from catalog B-tree node: %" PRIu32 ".",
732 				 function,
733 				 sub_node_number );
734 
735 				goto on_error;
736 			}
737 			if( ( result == 1 )
738 			 || ( node_key->parent_identifier > identifier ) )
739 			{
740 				break;
741 			}
742 		}
743 		last_node_key = node_key;
744 	}
745 	return( result );
746 
747 on_error:
748 	if( *thread_record != NULL )
749 	{
750 		libfshfs_thread_record_free(
751 		 thread_record,
752 		 NULL );
753 	}
754 	return( -1 );
755 }
756 
757 /* Retrieves a thread record for a specific identifier from the catalog B-tree file
758  * Returns 1 if successful, 0 if not found or -1 on error
759  */
libfshfs_catalog_btree_file_get_thread_record(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,uint32_t identifier,libfshfs_thread_record_t ** thread_record,libcerror_error_t ** error)760 int libfshfs_catalog_btree_file_get_thread_record(
761      libfshfs_btree_file_t *btree_file,
762      libbfio_handle_t *file_io_handle,
763      uint32_t identifier,
764      libfshfs_thread_record_t **thread_record,
765      libcerror_error_t **error )
766 {
767 	libfshfs_btree_node_t *root_node = NULL;
768 	static char *function            = "libfshfs_catalog_btree_file_get_thread_record";
769 	uint8_t node_type                = 0;
770 	int result                       = 0;
771 
772 	if( libfshfs_btree_file_get_root_node(
773 	     btree_file,
774 	     file_io_handle,
775 	     &root_node,
776 	     0,
777 	     error ) == -1 )
778 	{
779 		libcerror_error_set(
780 		 error,
781 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
782 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
783 		 "%s: unable to retrieve B-tree root node.",
784 		 function );
785 
786 		return( -1 );
787 	}
788 	if( libfshfs_btree_node_get_node_type(
789 	     root_node,
790 	     &node_type,
791 	     error ) != 1 )
792 	{
793 		libcerror_error_set(
794 		 error,
795 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
796 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
797 		 "%s: unable to determine if B-tree root node is a branch node.",
798 		 function );
799 
800 		return( -1 );
801 	}
802 	if( node_type == 0x00 )
803 	{
804 		result = libfshfs_catalog_btree_file_get_thread_record_from_branch_node(
805 		          btree_file,
806 		          file_io_handle,
807 		          root_node,
808 		          identifier,
809 		          thread_record,
810 		          1,
811 		          error );
812 	}
813 	else if( node_type == 0xff )
814 	{
815 		result = libfshfs_catalog_btree_file_get_thread_record_from_leaf_node(
816 		          btree_file,
817 		          root_node,
818 		          identifier,
819 		          thread_record,
820 		          error );
821 	}
822 	if( result == -1 )
823 	{
824 		libcerror_error_set(
825 		 error,
826 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
827 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
828 		 "%s: unable to retrieve thread record: %" PRIu32 " from catalog B-tree root node.",
829 		 function,
830 		 identifier );
831 
832 		return( -1 );
833 	}
834 	return( result );
835 }
836 
837 /* Retrieves a directory entry for from the catalog B-tree key
838  * Returns 1 if successful, 0 if not found or -1 on error
839  */
libfshfs_catalog_btree_file_get_directory_entry_from_key(libfshfs_catalog_btree_key_t * node_key,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)840 int libfshfs_catalog_btree_file_get_directory_entry_from_key(
841      libfshfs_catalog_btree_key_t *node_key,
842      libfshfs_directory_entry_t **directory_entry,
843      libcerror_error_t **error )
844 {
845 	libfshfs_directory_entry_t *safe_directory_entry = NULL;
846 	libfshfs_directory_record_t *directory_record    = NULL;
847 	libfshfs_file_record_t *file_record              = NULL;
848 	intptr_t *catalog_record                         = NULL;
849 	static char *function                            = "libfshfs_catalog_btree_file_get_directory_entry_from_key";
850 	uint16_t record_type                             = 0;
851 	int result                                       = 0;
852 
853 	if( node_key == NULL )
854 	{
855 		libcerror_error_set(
856 		 error,
857 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
858 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
859 		 "%s: invalid catalog B-tree key.",
860 		 function );
861 
862 		return( -1 );
863 	}
864 	if( node_key->record_data == NULL )
865 	{
866 		libcerror_error_set(
867 		 error,
868 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
869 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
870 		 "%s: invalid catalog B-tree key - missing record data.",
871 		 function );
872 
873 		return( -1 );
874 	}
875 	if( node_key->record_data_size < 2 )
876 	{
877 		libcerror_error_set(
878 		 error,
879 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
880 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
881 		 "%s: invalid catalog B-tree key - record data size value out of bounds.",
882 		 function );
883 
884 		goto on_error;
885 	}
886 	if( directory_entry == NULL )
887 	{
888 		libcerror_error_set(
889 		 error,
890 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
891 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
892 		 "%s: invalid directory entry.",
893 		 function );
894 
895 		return( -1 );
896 	}
897 	if( *directory_entry != NULL )
898 	{
899 		libcerror_error_set(
900 		 error,
901 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
902 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
903 		 "%s: invalid directory entry value already set.",
904 		 function );
905 
906 		return( -1 );
907 	}
908 	byte_stream_copy_to_uint16_big_endian(
909 	 node_key->record_data,
910 	 record_type );
911 
912 	switch( record_type )
913 	{
914 		case LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_RECORD:
915 		case LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_RECORD:
916 			if( libfshfs_directory_record_initialize(
917 			     &directory_record,
918 			     error ) != 1 )
919 			{
920 				libcerror_error_set(
921 				 error,
922 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
923 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
924 				 "%s: unable to create directory record.",
925 				 function );
926 
927 				goto on_error;
928 			}
929 			if( libfshfs_directory_record_read_data(
930 			     directory_record,
931 			     node_key->record_data,
932 			     node_key->record_data_size,
933 			     error ) != 1 )
934 			{
935 				libcerror_error_set(
936 				 error,
937 				 LIBCERROR_ERROR_DOMAIN_IO,
938 				 LIBCERROR_IO_ERROR_READ_FAILED,
939 				 "%s: unable to read directory record.",
940 				 function );
941 
942 				goto on_error;
943 			}
944 			catalog_record = (intptr_t *) directory_record;
945 
946 			break;
947 
948 		case LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_RECORD:
949 		case LIBFSHFS_RECORD_TYPE_HFS_FILE_RECORD:
950 			if( libfshfs_file_record_initialize(
951 			     &file_record,
952 			     error ) != 1 )
953 			{
954 				libcerror_error_set(
955 				 error,
956 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
957 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
958 				 "%s: unable to create file record.",
959 				 function );
960 
961 				goto on_error;
962 			}
963 			if( libfshfs_file_record_read_data(
964 			     file_record,
965 			     node_key->record_data,
966 			     node_key->record_data_size,
967 			     error ) != 1 )
968 			{
969 				libcerror_error_set(
970 				 error,
971 				 LIBCERROR_ERROR_DOMAIN_IO,
972 				 LIBCERROR_IO_ERROR_READ_FAILED,
973 				 "%s: unable to read file record.",
974 				 function );
975 
976 				goto on_error;
977 			}
978 			catalog_record = (intptr_t *) file_record;
979 
980 			break;
981 
982 		default:
983 			break;
984 	}
985 	if( catalog_record != NULL )
986 	{
987 		if( libfshfs_directory_entry_initialize(
988 		     &safe_directory_entry,
989 		     error ) != 1 )
990 		{
991 			libcerror_error_set(
992 			 error,
993 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
994 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
995 			 "%s: unable to create directory entry.",
996 			 function );
997 
998 			goto on_error;
999 		}
1000 		if( libfshfs_directory_entry_set_name(
1001 		     safe_directory_entry,
1002 		     node_key->name_data,
1003 		     node_key->name_size,
1004 		     error ) != 1 )
1005 		{
1006 			libcerror_error_set(
1007 			 error,
1008 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1009 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1010 			 "%s: unable to set name of directory entry.",
1011 			 function );
1012 
1013 			goto on_error;
1014 		}
1015 		safe_directory_entry->parent_identifier = node_key->parent_identifier;
1016 
1017 		if( libfshfs_directory_entry_set_catalog_record(
1018 		     safe_directory_entry,
1019 		     record_type,
1020 		     catalog_record,
1021 		     error ) != 1 )
1022 		{
1023 			libcerror_error_set(
1024 			 error,
1025 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1026 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1027 			 "%s: unable to set catalog record of directory entry.",
1028 			 function );
1029 
1030 			goto on_error;
1031 		}
1032 		directory_record = NULL;
1033 		file_record      = NULL;
1034 
1035 		*directory_entry = safe_directory_entry;
1036 
1037 		result = 1;
1038 	}
1039 	return( result );
1040 
1041 on_error:
1042 	if( file_record != NULL )
1043 	{
1044 		libfshfs_file_record_free(
1045 		 &file_record,
1046 		 NULL );
1047 	}
1048 	if( directory_record != NULL )
1049 	{
1050 		libfshfs_directory_record_free(
1051 		 &directory_record,
1052 		 NULL );
1053 	}
1054 	if( safe_directory_entry != NULL )
1055 	{
1056 		libfshfs_directory_entry_free(
1057 		 &safe_directory_entry,
1058 		 NULL );
1059 	}
1060 	return( -1 );
1061 }
1062 
1063 /* Retrieves a directory entry for a specific thread record from the catalog B-tree leaf node
1064  * Returns 1 if successful, 0 if not found or -1 on error
1065  */
libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_thread_record(libfshfs_btree_file_t * btree_file,libfshfs_btree_node_t * node,libfshfs_thread_record_t * thread_record,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)1066 int libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_thread_record(
1067      libfshfs_btree_file_t *btree_file,
1068      libfshfs_btree_node_t *node,
1069      libfshfs_thread_record_t *thread_record,
1070      libfshfs_directory_entry_t **directory_entry,
1071      libcerror_error_t **error )
1072 {
1073 	libfshfs_catalog_btree_key_t *node_key = NULL;
1074 	static char *function                  = "libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_thread_record";
1075 	uint16_t record_index                  = 0;
1076 	uint16_t record_type                   = 0;
1077 	int compare_result                     = 0;
1078 	int is_leaf_node                       = 0;
1079 	int result                             = 0;
1080 
1081 	if( btree_file == NULL )
1082 	{
1083 		libcerror_error_set(
1084 		 error,
1085 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1086 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1087 		 "%s: invalid B-tree file.",
1088 		 function );
1089 
1090 		return( -1 );
1091 	}
1092 	if( node == NULL )
1093 	{
1094 		libcerror_error_set(
1095 		 error,
1096 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1097 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1098 		 "%s: invalid B-tree node.",
1099 		 function );
1100 
1101 		return( -1 );
1102 	}
1103 	if( node->descriptor == NULL )
1104 	{
1105 		libcerror_error_set(
1106 		 error,
1107 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1108 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1109 		 "%s: invalid B-tree node - missing descriptor.",
1110 		 function );
1111 
1112 		return( -1 );
1113 	}
1114 	if( thread_record == NULL )
1115 	{
1116 		libcerror_error_set(
1117 		 error,
1118 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1119 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1120 		 "%s: invalid thread record.",
1121 		 function );
1122 
1123 		return( -1 );
1124 	}
1125 	if( directory_entry == NULL )
1126 	{
1127 		libcerror_error_set(
1128 		 error,
1129 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1130 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1131 		 "%s: invalid directory entry.",
1132 		 function );
1133 
1134 		return( -1 );
1135 	}
1136 	is_leaf_node = libfshfs_btree_node_is_leaf_node(
1137 	                node,
1138 	                error );
1139 
1140 	if( is_leaf_node == -1 )
1141 	{
1142 		libcerror_error_set(
1143 		 error,
1144 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1145 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1146 		 "%s: unable to determine if B-tree node is a leaf node.",
1147 		 function );
1148 
1149 		goto on_error;
1150 	}
1151 	else if( is_leaf_node == 0 )
1152 	{
1153 		libcerror_error_set(
1154 		 error,
1155 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1156 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1157 		 "%s: invalid node - not a leaf node.",
1158 		 function );
1159 
1160 		goto on_error;
1161 	}
1162 	for( record_index = 0;
1163 	     record_index < node->descriptor->number_of_records;
1164 	     record_index++ )
1165 	{
1166 		if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
1167 		     node,
1168 		     record_index,
1169 		     &node_key,
1170 		     error ) == -1 )
1171 		{
1172 			libcerror_error_set(
1173 			 error,
1174 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1175 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1176 			 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
1177 			 function,
1178 			 record_index );
1179 
1180 			goto on_error;
1181 		}
1182 		if( node_key == NULL )
1183 		{
1184 			libcerror_error_set(
1185 			 error,
1186 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1187 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1188 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
1189 			 function,
1190 			 record_index );
1191 
1192 			goto on_error;
1193 		}
1194 		if( node_key->parent_identifier == thread_record->parent_identifier )
1195 		{
1196 			if( node_key->record_data_size < 2 )
1197 			{
1198 				libcerror_error_set(
1199 				 error,
1200 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1201 				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1202 				 "%s: invalid catalog B-tree key: %" PRIu16 " - record data size value out of bounds.",
1203 				 function,
1204 				 record_index );
1205 
1206 				goto on_error;
1207 			}
1208 			byte_stream_copy_to_uint16_big_endian(
1209 			 node_key->record_data,
1210 			 record_type );
1211 
1212 			switch( record_type )
1213 			{
1214 				case LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_RECORD:
1215 				case LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_RECORD:
1216 				case LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_RECORD:
1217 				case LIBFSHFS_RECORD_TYPE_HFS_FILE_RECORD:
1218 					compare_result = libfshfs_catalog_btree_key_compare_name(
1219 					                  node_key,
1220 					                  thread_record->name,
1221 					                  thread_record->name_size,
1222 					                  error );
1223 
1224 					if( compare_result == -1 )
1225 					{
1226 						libcerror_error_set(
1227 						 error,
1228 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1229 						 LIBCERROR_RUNTIME_ERROR_GENERIC,
1230 						 "%s: unable to compare thread record name with catalog B-tree key name.",
1231 						 function );
1232 
1233 						goto on_error;
1234 					}
1235 					break;
1236 
1237 				default:
1238 					compare_result = LIBUNA_COMPARE_LESS;
1239 					break;
1240 			}
1241 			if( compare_result != 0 )
1242 			{
1243 				result = libfshfs_catalog_btree_file_get_directory_entry_from_key(
1244 				          node_key,
1245 				          directory_entry,
1246 				          error );
1247 
1248 				if( result == -1 )
1249 				{
1250 					libcerror_error_set(
1251 					 error,
1252 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1253 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1254 					 "%s: unable to retrieve directory entry from record data.",
1255 					 function );
1256 
1257 					goto on_error;
1258 				}
1259 			}
1260 		}
1261 		if( ( result == 1 )
1262 		 || ( node_key->parent_identifier > thread_record->parent_identifier ) )
1263 		{
1264 			break;
1265 		}
1266 	}
1267 	return( result );
1268 
1269 on_error:
1270 	if( *directory_entry != NULL )
1271 	{
1272 		libfshfs_directory_entry_free(
1273 		 directory_entry,
1274 		 NULL );
1275 	}
1276 	return( -1 );
1277 }
1278 
1279 /* Retrieves a directory entry for a specific thread record from the catalog B-tree branch node
1280  * Returns 1 if successful, 0 if not found or -1 on error
1281  */
libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_thread_record(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,libfshfs_btree_node_t * node,libfshfs_thread_record_t * thread_record,libfshfs_directory_entry_t ** directory_entry,int recursion_depth,libcerror_error_t ** error)1282 int libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_thread_record(
1283      libfshfs_btree_file_t *btree_file,
1284      libbfio_handle_t *file_io_handle,
1285      libfshfs_btree_node_t *node,
1286      libfshfs_thread_record_t *thread_record,
1287      libfshfs_directory_entry_t **directory_entry,
1288      int recursion_depth,
1289      libcerror_error_t **error )
1290 {
1291 	libfshfs_btree_node_t *sub_node             = NULL;
1292 	libfshfs_catalog_btree_key_t *last_node_key = NULL;
1293 	libfshfs_catalog_btree_key_t *node_key      = NULL;
1294 	static char *function                       = "libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_thread_record";
1295 	uint32_t sub_node_number                    = 0;
1296 	uint16_t record_index                       = 0;
1297 	uint8_t node_type                           = 0;
1298 	int is_branch_node                          = 0;
1299 	int result                                  = 0;
1300 
1301 	if( btree_file == NULL )
1302 	{
1303 		libcerror_error_set(
1304 		 error,
1305 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1306 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1307 		 "%s: invalid B-tree file.",
1308 		 function );
1309 
1310 		return( -1 );
1311 	}
1312 	if( node == NULL )
1313 	{
1314 		libcerror_error_set(
1315 		 error,
1316 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1317 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1318 		 "%s: invalid B-tree node.",
1319 		 function );
1320 
1321 		return( -1 );
1322 	}
1323 	if( node->descriptor == NULL )
1324 	{
1325 		libcerror_error_set(
1326 		 error,
1327 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1328 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1329 		 "%s: invalid B-tree node - missing descriptor.",
1330 		 function );
1331 
1332 		return( -1 );
1333 	}
1334 	if( thread_record == NULL )
1335 	{
1336 		libcerror_error_set(
1337 		 error,
1338 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1339 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1340 		 "%s: invalid thread record.",
1341 		 function );
1342 
1343 		return( -1 );
1344 	}
1345 	if( directory_entry == NULL )
1346 	{
1347 		libcerror_error_set(
1348 		 error,
1349 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1350 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1351 		 "%s: invalid directory entry.",
1352 		 function );
1353 
1354 		return( -1 );
1355 	}
1356 	if( ( recursion_depth < 0 )
1357 	 || ( recursion_depth > LIBFSHFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1358 	{
1359 		libcerror_error_set(
1360 		 error,
1361 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1362 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1363 		 "%s: invalid recursion depth value out of bounds.",
1364 		 function );
1365 
1366 		return( -1 );
1367 	}
1368 	is_branch_node = libfshfs_btree_node_is_branch_node(
1369 	                  node,
1370 	                  error );
1371 
1372 	if( is_branch_node == -1 )
1373 	{
1374 		libcerror_error_set(
1375 		 error,
1376 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1377 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1378 		 "%s: unable to determine if B-tree node is a branch node.",
1379 		 function );
1380 
1381 		goto on_error;
1382 	}
1383 	else if( is_branch_node == 0 )
1384 	{
1385 		libcerror_error_set(
1386 		 error,
1387 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1388 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1389 		 "%s: invalid node - not a branch node.",
1390 		 function );
1391 
1392 		goto on_error;
1393 	}
1394 	if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
1395 	     node,
1396 	     0,
1397 	     &last_node_key,
1398 	     error ) == -1 )
1399 	{
1400 		libcerror_error_set(
1401 		 error,
1402 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1403 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1404 		 "%s: unable to retrieve catalog B-tree key: 0.",
1405 		 function );
1406 
1407 		goto on_error;
1408 	}
1409 	node_key = last_node_key;
1410 
1411 	for( record_index = 1;
1412 	     record_index <= node->descriptor->number_of_records;
1413 	     record_index++ )
1414 	{
1415 		if( record_index < node->descriptor->number_of_records )
1416 		{
1417 			if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
1418 			     node,
1419 			     record_index,
1420 			     &node_key,
1421 			     error ) == -1 )
1422 			{
1423 				libcerror_error_set(
1424 				 error,
1425 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1426 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1427 				 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
1428 				 function,
1429 				 record_index );
1430 
1431 				goto on_error;
1432 			}
1433 		}
1434 		if( node_key == NULL )
1435 		{
1436 			libcerror_error_set(
1437 			 error,
1438 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1439 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1440 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
1441 			 function,
1442 			 record_index );
1443 
1444 			goto on_error;
1445 		}
1446 		if( ( record_index == node->descriptor->number_of_records )
1447 		 || ( node_key->parent_identifier >= thread_record->parent_identifier ) )
1448 		{
1449 			if( libfshfs_catalog_btree_file_get_sub_node_number_from_key(
1450 			     last_node_key,
1451 			     &sub_node_number,
1452 			     error ) != 1 )
1453 			{
1454 				libcerror_error_set(
1455 				 error,
1456 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1457 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1458 				 "%s: unable to retrieve sub node number from catalog B-Tree key.",
1459 				 function );
1460 
1461 				goto on_error;
1462 			}
1463 #if defined( HAVE_DEBUG_OUTPUT )
1464 			if( libcnotify_verbose != 0 )
1465 			{
1466 				libcnotify_printf(
1467 				 "%s: B-tree sub node number\t: %" PRIu32 "\n",
1468 				 function,
1469 				 sub_node_number );
1470 
1471 				libcnotify_printf(
1472 				 "\n" );
1473 			}
1474 #endif
1475 			if( libfshfs_btree_file_get_node_by_number(
1476 			     btree_file,
1477 			     file_io_handle,
1478 			     sub_node_number,
1479 			     &sub_node,
1480 			     recursion_depth,
1481 			     error ) == -1 )
1482 			{
1483 				libcerror_error_set(
1484 				 error,
1485 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1486 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1487 				 "%s: unable to retrieve B-tree sub node: %" PRIu32 ".",
1488 				 function,
1489 				 sub_node_number );
1490 
1491 				goto on_error;
1492 			}
1493 			if( libfshfs_btree_node_get_node_type(
1494 			     sub_node,
1495 			     &node_type,
1496 			     error ) != 1 )
1497 			{
1498 				libcerror_error_set(
1499 				 error,
1500 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1501 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1502 				 "%s: unable to determine if B-tree sub node: %" PRIu32 " type.",
1503 				 function,
1504 				 sub_node_number );
1505 
1506 				goto on_error;
1507 			}
1508 			if( node_type == 0x00 )
1509 			{
1510 				result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_thread_record(
1511 				          btree_file,
1512 				          file_io_handle,
1513 				          sub_node,
1514 				          thread_record,
1515 				          directory_entry,
1516 				          recursion_depth + 1,
1517 				          error );
1518 			}
1519 			else if( node_type == 0xff )
1520 			{
1521 				result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_thread_record(
1522 				          btree_file,
1523 				          sub_node,
1524 				          thread_record,
1525 				          directory_entry,
1526 				          error );
1527 			}
1528 			if( result == -1 )
1529 			{
1530 				libcerror_error_set(
1531 				 error,
1532 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1533 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1534 				 "%s: unable to retrieve directory entry from catalog B-tree node: %" PRIu32 ".",
1535 				 function,
1536 				 sub_node_number );
1537 
1538 				goto on_error;
1539 			}
1540 			if( ( result == 1 )
1541 			 || ( node_key->parent_identifier > thread_record->parent_identifier ) )
1542 			{
1543 				break;
1544 			}
1545 		}
1546 		last_node_key = node_key;
1547 	}
1548 	return( result );
1549 
1550 on_error:
1551 	if( *directory_entry != NULL )
1552 	{
1553 		libfshfs_directory_entry_free(
1554 		 directory_entry,
1555 		 NULL );
1556 	}
1557 	return( -1 );
1558 }
1559 
1560 /* Retrieves a directory entry for a specific identifier from the catalog B-tree file
1561  * Returns 1 if successful, 0 if not found or -1 on error
1562  */
libfshfs_catalog_btree_file_get_directory_entry_by_identifier(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,uint32_t identifier,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)1563 int libfshfs_catalog_btree_file_get_directory_entry_by_identifier(
1564      libfshfs_btree_file_t *btree_file,
1565      libbfio_handle_t *file_io_handle,
1566      uint32_t identifier,
1567      libfshfs_directory_entry_t **directory_entry,
1568      libcerror_error_t **error )
1569 {
1570 	libfshfs_btree_node_t *root_node        = NULL;
1571 	libfshfs_thread_record_t *thread_record = NULL;
1572 	static char *function                   = "libfshfs_catalog_btree_file_get_directory_entry_by_identifier";
1573 	uint8_t node_type                       = 0;
1574 	int result                              = 0;
1575 
1576 	result = libfshfs_catalog_btree_file_get_thread_record(
1577 	          btree_file,
1578 	          file_io_handle,
1579 	          identifier,
1580 	          &thread_record,
1581 	          error );
1582 
1583 	if( result == -1 )
1584 	{
1585 		libcerror_error_set(
1586 		 error,
1587 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1588 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1589 		 "%s: unable to retrieve thread record: %" PRIu32 " from catalog B-tree root node.",
1590 		 function,
1591 		 identifier );
1592 
1593 		goto on_error;
1594 	}
1595 	else if( result != 0 )
1596 	{
1597 		if( libfshfs_btree_file_get_root_node(
1598 		     btree_file,
1599 		     file_io_handle,
1600 		     &root_node,
1601 		     0,
1602 		     error ) == -1 )
1603 		{
1604 			libcerror_error_set(
1605 			 error,
1606 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1607 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1608 			 "%s: unable to retrieve B-tree root node.",
1609 			 function );
1610 
1611 			goto on_error;
1612 		}
1613 		if( libfshfs_btree_node_get_node_type(
1614 		     root_node,
1615 		     &node_type,
1616 		     error ) != 1 )
1617 		{
1618 			libcerror_error_set(
1619 			 error,
1620 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1621 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1622 			 "%s: unable to determine if B-tree root node type.",
1623 			 function );
1624 
1625 			goto on_error;
1626 		}
1627 		if( node_type == 0x00 )
1628 		{
1629 			result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_thread_record(
1630 			          btree_file,
1631 			          file_io_handle,
1632 			          root_node,
1633 			          thread_record,
1634 			          directory_entry,
1635 			          1,
1636 			          error );
1637 		}
1638 		else if( node_type == 0xff )
1639 		{
1640 			result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_thread_record(
1641 			          btree_file,
1642 			          root_node,
1643 			          thread_record,
1644 			          directory_entry,
1645 			          error );
1646 		}
1647 		if( result == -1 )
1648 		{
1649 			libcerror_error_set(
1650 			 error,
1651 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1652 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1653 			 "%s: unable to retrieve directory entry: %" PRIu32 " from catalog B-tree root node.",
1654 			 function,
1655 			 identifier );
1656 
1657 			goto on_error;
1658 		}
1659 		if( libfshfs_thread_record_free(
1660 		     &thread_record,
1661 		     error ) != 1 )
1662 		{
1663 			libcerror_error_set(
1664 			 error,
1665 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1666 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1667 			 "%s: unable to free thread record.",
1668 			 function );
1669 
1670 			goto on_error;
1671 		}
1672 	}
1673 	return( result );
1674 
1675 on_error:
1676 	if( thread_record != NULL )
1677 	{
1678 		libfshfs_thread_record_free(
1679 		 &thread_record,
1680 		 NULL );
1681 	}
1682 	return( -1 );
1683 }
1684 
1685 /* Retrieves a directory entry for an UTF-8 encoded name from the catalog B-tree leaf node
1686  * Returns 1 if successful, 0 if not found or -1 on error
1687  */
libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf8_name(libfshfs_btree_file_t * btree_file,libfshfs_btree_node_t * node,uint32_t parent_identifier,const uint8_t * utf8_string,size_t utf8_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)1688 int libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf8_name(
1689      libfshfs_btree_file_t *btree_file,
1690      libfshfs_btree_node_t *node,
1691      uint32_t parent_identifier,
1692      const uint8_t *utf8_string,
1693      size_t utf8_string_length,
1694      uint8_t use_case_folding,
1695      libfshfs_directory_entry_t **directory_entry,
1696      libcerror_error_t **error )
1697 {
1698 	libfshfs_catalog_btree_key_t *node_key = NULL;
1699 	static char *function                  = "libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf8_name";
1700 	uint16_t record_index                  = 0;
1701 	uint16_t record_type                   = 0;
1702 	int compare_result                     = 0;
1703 	int is_leaf_node                       = 0;
1704 	int result                             = 0;
1705 
1706 	if( btree_file == NULL )
1707 	{
1708 		libcerror_error_set(
1709 		 error,
1710 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1711 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1712 		 "%s: invalid B-tree file.",
1713 		 function );
1714 
1715 		return( -1 );
1716 	}
1717 	if( node == NULL )
1718 	{
1719 		libcerror_error_set(
1720 		 error,
1721 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1722 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1723 		 "%s: invalid B-tree node.",
1724 		 function );
1725 
1726 		return( -1 );
1727 	}
1728 	if( node->descriptor == NULL )
1729 	{
1730 		libcerror_error_set(
1731 		 error,
1732 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1733 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1734 		 "%s: invalid B-tree node - missing descriptor.",
1735 		 function );
1736 
1737 		return( -1 );
1738 	}
1739 	if( directory_entry == NULL )
1740 	{
1741 		libcerror_error_set(
1742 		 error,
1743 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1744 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1745 		 "%s: invalid directory entry.",
1746 		 function );
1747 
1748 		return( -1 );
1749 	}
1750 	is_leaf_node = libfshfs_btree_node_is_leaf_node(
1751 	                node,
1752 	                error );
1753 
1754 	if( is_leaf_node == -1 )
1755 	{
1756 		libcerror_error_set(
1757 		 error,
1758 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1759 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1760 		 "%s: unable to determine if B-tree node is a leaf node.",
1761 		 function );
1762 
1763 		goto on_error;
1764 	}
1765 	else if( is_leaf_node == 0 )
1766 	{
1767 		libcerror_error_set(
1768 		 error,
1769 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1770 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1771 		 "%s: invalid node - not a leaf node.",
1772 		 function );
1773 
1774 		goto on_error;
1775 	}
1776 	for( record_index = 0;
1777 	     record_index < node->descriptor->number_of_records;
1778 	     record_index++ )
1779 	{
1780 		if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
1781 		     node,
1782 		     record_index,
1783 		     &node_key,
1784 		     error ) == -1 )
1785 		{
1786 			libcerror_error_set(
1787 			 error,
1788 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1789 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1790 			 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
1791 			 function,
1792 			 record_index );
1793 
1794 			goto on_error;
1795 		}
1796 		if( node_key == NULL )
1797 		{
1798 			libcerror_error_set(
1799 			 error,
1800 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1801 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1802 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
1803 			 function,
1804 			 record_index );
1805 
1806 			goto on_error;
1807 		}
1808 		if( node_key->parent_identifier == parent_identifier )
1809 		{
1810 			if( node_key->record_data_size < 2 )
1811 			{
1812 				libcerror_error_set(
1813 				 error,
1814 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1815 				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1816 				 "%s: invalid catalog B-tree key: %" PRIu16 " - record data size value out of bounds.",
1817 				 function,
1818 				 record_index );
1819 
1820 				goto on_error;
1821 			}
1822 			byte_stream_copy_to_uint16_big_endian(
1823 			 node_key->record_data,
1824 			 record_type );
1825 
1826 			switch( record_type )
1827 			{
1828 				case LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_RECORD:
1829 				case LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_RECORD:
1830 				case LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_RECORD:
1831 				case LIBFSHFS_RECORD_TYPE_HFS_FILE_RECORD:
1832 					compare_result = libfshfs_catalog_btree_key_compare_name_with_utf8_string(
1833 					                  node_key,
1834 					                  utf8_string,
1835 					                  utf8_string_length,
1836 					                  use_case_folding,
1837 					                  error );
1838 
1839 					if( compare_result == -1 )
1840 					{
1841 						libcerror_error_set(
1842 						 error,
1843 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1844 						 LIBCERROR_RUNTIME_ERROR_GENERIC,
1845 						 "%s: unable to compare UTF-8 string with catalog B-tree key name.",
1846 						 function );
1847 
1848 						goto on_error;
1849 					}
1850 					break;
1851 
1852 				default:
1853 					compare_result = LIBUNA_COMPARE_LESS;
1854 					break;
1855 			}
1856 			if( compare_result == LIBUNA_COMPARE_EQUAL )
1857 			{
1858 				result = libfshfs_catalog_btree_file_get_directory_entry_from_key(
1859 				          node_key,
1860 				          directory_entry,
1861 				          error );
1862 
1863 				if( result == -1 )
1864 				{
1865 					libcerror_error_set(
1866 					 error,
1867 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1868 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1869 					 "%s: unable to retrieve directory entry from record data.",
1870 					 function );
1871 
1872 					goto on_error;
1873 				}
1874 			}
1875 		}
1876 		if( ( result == 1 )
1877 		 || ( node_key->parent_identifier > parent_identifier ) )
1878 		{
1879 			break;
1880 		}
1881 	}
1882 	return( result );
1883 
1884 on_error:
1885 	if( *directory_entry != NULL )
1886 	{
1887 		libfshfs_directory_entry_free(
1888 		 directory_entry,
1889 		 NULL );
1890 	}
1891 	return( -1 );
1892 }
1893 
1894 /* Retrieves a directory entry for an UTF-8 encoded name from the catalog B-tree branch node
1895  * Returns 1 if successful, 0 if not found or -1 on error
1896  */
libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf8_name(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,libfshfs_btree_node_t * node,uint32_t parent_identifier,const uint8_t * utf8_string,size_t utf8_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,int recursion_depth,libcerror_error_t ** error)1897 int libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf8_name(
1898      libfshfs_btree_file_t *btree_file,
1899      libbfio_handle_t *file_io_handle,
1900      libfshfs_btree_node_t *node,
1901      uint32_t parent_identifier,
1902      const uint8_t *utf8_string,
1903      size_t utf8_string_length,
1904      uint8_t use_case_folding,
1905      libfshfs_directory_entry_t **directory_entry,
1906      int recursion_depth,
1907      libcerror_error_t **error )
1908 {
1909 	libfshfs_btree_node_t *sub_node             = NULL;
1910 	libfshfs_catalog_btree_key_t *last_node_key = NULL;
1911 	libfshfs_catalog_btree_key_t *node_key      = NULL;
1912 	static char *function                       = "libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf8_name";
1913 	uint32_t sub_node_number                    = 0;
1914 	uint16_t record_index                       = 0;
1915 	uint8_t node_type                           = 0;
1916 	int is_branch_node                          = 0;
1917 	int result                                  = 0;
1918 
1919 	if( btree_file == NULL )
1920 	{
1921 		libcerror_error_set(
1922 		 error,
1923 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1924 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1925 		 "%s: invalid B-tree file.",
1926 		 function );
1927 
1928 		return( -1 );
1929 	}
1930 	if( node == NULL )
1931 	{
1932 		libcerror_error_set(
1933 		 error,
1934 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1935 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1936 		 "%s: invalid B-tree node.",
1937 		 function );
1938 
1939 		return( -1 );
1940 	}
1941 	if( node->descriptor == NULL )
1942 	{
1943 		libcerror_error_set(
1944 		 error,
1945 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1946 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1947 		 "%s: invalid B-tree node - missing descriptor.",
1948 		 function );
1949 
1950 		return( -1 );
1951 	}
1952 	if( directory_entry == NULL )
1953 	{
1954 		libcerror_error_set(
1955 		 error,
1956 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1957 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1958 		 "%s: invalid directory entry.",
1959 		 function );
1960 
1961 		return( -1 );
1962 	}
1963 	if( ( recursion_depth < 0 )
1964 	 || ( recursion_depth > LIBFSHFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1965 	{
1966 		libcerror_error_set(
1967 		 error,
1968 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1969 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1970 		 "%s: invalid recursion depth value out of bounds.",
1971 		 function );
1972 
1973 		return( -1 );
1974 	}
1975 	is_branch_node = libfshfs_btree_node_is_branch_node(
1976 	                  node,
1977 	                  error );
1978 
1979 	if( is_branch_node == -1 )
1980 	{
1981 		libcerror_error_set(
1982 		 error,
1983 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1984 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1985 		 "%s: unable to determine if B-tree node is a branch node.",
1986 		 function );
1987 
1988 		goto on_error;
1989 	}
1990 	else if( is_branch_node == 0 )
1991 	{
1992 		libcerror_error_set(
1993 		 error,
1994 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1995 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1996 		 "%s: invalid node - not a branch node.",
1997 		 function );
1998 
1999 		goto on_error;
2000 	}
2001 	if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
2002 	     node,
2003 	     0,
2004 	     &last_node_key,
2005 	     error ) == -1 )
2006 	{
2007 		libcerror_error_set(
2008 		 error,
2009 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2010 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2011 		 "%s: unable to retrieve catalog B-tree key: 0.",
2012 		 function );
2013 
2014 		goto on_error;
2015 	}
2016 	node_key = last_node_key;
2017 
2018 	for( record_index = 1;
2019 	     record_index <= node->descriptor->number_of_records;
2020 	     record_index++ )
2021 	{
2022 		if( record_index < node->descriptor->number_of_records )
2023 		{
2024 			if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
2025 			     node,
2026 			     record_index,
2027 			     &node_key,
2028 			     error ) == -1 )
2029 			{
2030 				libcerror_error_set(
2031 				 error,
2032 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2033 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2034 				 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
2035 				 function,
2036 				 record_index );
2037 
2038 				goto on_error;
2039 			}
2040 		}
2041 		if( node_key == NULL )
2042 		{
2043 			libcerror_error_set(
2044 			 error,
2045 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2046 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2047 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
2048 			 function,
2049 			 record_index );
2050 
2051 			goto on_error;
2052 		}
2053 		if( ( record_index == node->descriptor->number_of_records )
2054 		 || ( node_key->parent_identifier >= parent_identifier ) )
2055 		{
2056 			if( libfshfs_catalog_btree_file_get_sub_node_number_from_key(
2057 			     last_node_key,
2058 			     &sub_node_number,
2059 			     error ) != 1 )
2060 			{
2061 				libcerror_error_set(
2062 				 error,
2063 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2064 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2065 				 "%s: unable to retrieve sub node number from catalog B-Tree key.",
2066 				 function );
2067 
2068 				goto on_error;
2069 			}
2070 #if defined( HAVE_DEBUG_OUTPUT )
2071 			if( libcnotify_verbose != 0 )
2072 			{
2073 				libcnotify_printf(
2074 				 "%s: B-tree sub node number\t: %" PRIu32 "\n",
2075 				 function,
2076 				 sub_node_number );
2077 
2078 				libcnotify_printf(
2079 				 "\n" );
2080 			}
2081 #endif
2082 			if( libfshfs_btree_file_get_node_by_number(
2083 			     btree_file,
2084 			     file_io_handle,
2085 			     sub_node_number,
2086 			     &sub_node,
2087 			     recursion_depth,
2088 			     error ) == -1 )
2089 			{
2090 				libcerror_error_set(
2091 				 error,
2092 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2093 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2094 				 "%s: unable to retrieve B-tree sub node: %" PRIu32 ".",
2095 				 function,
2096 				 sub_node_number );
2097 
2098 				goto on_error;
2099 			}
2100 			if( libfshfs_btree_node_get_node_type(
2101 			     sub_node,
2102 			     &node_type,
2103 			     error ) != 1 )
2104 			{
2105 				libcerror_error_set(
2106 				 error,
2107 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2108 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2109 				 "%s: unable to determine if B-tree sub node: %" PRIu32 " type.",
2110 				 function,
2111 				 sub_node_number );
2112 
2113 				goto on_error;
2114 			}
2115 			if( node_type == 0x00 )
2116 			{
2117 				result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf8_name(
2118 				          btree_file,
2119 				          file_io_handle,
2120 				          sub_node,
2121 				          parent_identifier,
2122 				          utf8_string,
2123 				          utf8_string_length,
2124 				          use_case_folding,
2125 				          directory_entry,
2126 				          recursion_depth + 1,
2127 				          error );
2128 			}
2129 			else if( node_type == 0xff )
2130 			{
2131 				result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf8_name(
2132 				          btree_file,
2133 				          sub_node,
2134 				          parent_identifier,
2135 				          utf8_string,
2136 				          utf8_string_length,
2137 				          use_case_folding,
2138 				          directory_entry,
2139 				          error );
2140 			}
2141 			if( result == -1 )
2142 			{
2143 				libcerror_error_set(
2144 				 error,
2145 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2146 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2147 				 "%s: unable to retrieve directory entry from catalog B-tree node: %" PRIu32 ".",
2148 				 function,
2149 				 sub_node_number );
2150 
2151 				goto on_error;
2152 			}
2153 			if( ( result == 1 )
2154 			 || ( node_key->parent_identifier > parent_identifier ) )
2155 			{
2156 				break;
2157 			}
2158 		}
2159 		last_node_key = node_key;
2160 	}
2161 	return( result );
2162 
2163 on_error:
2164 	if( *directory_entry != NULL )
2165 	{
2166 		libfshfs_directory_entry_free(
2167 		 directory_entry,
2168 		 NULL );
2169 	}
2170 	return( -1 );
2171 }
2172 
2173 /* Retrieves a directory entry for an UTF-8 encoded name from the catalog B-tree file
2174  * Returns 1 if successful, 0 if not found or -1 on error
2175  */
libfshfs_catalog_btree_file_get_directory_entry_by_utf8_name(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,uint32_t parent_identifier,const uint8_t * utf8_string,size_t utf8_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)2176 int libfshfs_catalog_btree_file_get_directory_entry_by_utf8_name(
2177      libfshfs_btree_file_t *btree_file,
2178      libbfio_handle_t *file_io_handle,
2179      uint32_t parent_identifier,
2180      const uint8_t *utf8_string,
2181      size_t utf8_string_length,
2182      uint8_t use_case_folding,
2183      libfshfs_directory_entry_t **directory_entry,
2184      libcerror_error_t **error )
2185 {
2186 	libfshfs_btree_node_t *root_node = NULL;
2187 	static char *function            = "libfshfs_catalog_btree_file_get_directory_entry_by_utf8_name";
2188 	uint8_t node_type                = 0;
2189 	int result                       = 0;
2190 
2191 	if( libfshfs_btree_file_get_root_node(
2192 	     btree_file,
2193 	     file_io_handle,
2194 	     &root_node,
2195 	     0,
2196 	     error ) == -1 )
2197 	{
2198 		libcerror_error_set(
2199 		 error,
2200 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2201 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2202 		 "%s: unable to retrieve B-tree root node.",
2203 		 function );
2204 
2205 		return( -1 );
2206 	}
2207 	if( libfshfs_btree_node_get_node_type(
2208 	     root_node,
2209 	     &node_type,
2210 	     error ) != 1 )
2211 	{
2212 		libcerror_error_set(
2213 		 error,
2214 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2215 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2216 		 "%s: unable to determine if B-tree root node type.",
2217 		 function );
2218 
2219 		return( -1 );
2220 	}
2221 	if( node_type == 0x00 )
2222 	{
2223 		result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf8_name(
2224 		          btree_file,
2225 		          file_io_handle,
2226 		          root_node,
2227 		          parent_identifier,
2228 		          utf8_string,
2229 		          utf8_string_length,
2230 		          use_case_folding,
2231 		          directory_entry,
2232 		          1,
2233 		          error );
2234 	}
2235 	else if( node_type == 0xff )
2236 	{
2237 		result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf8_name(
2238 		          btree_file,
2239 		          root_node,
2240 		          parent_identifier,
2241 		          utf8_string,
2242 		          utf8_string_length,
2243 		          use_case_folding,
2244 		          directory_entry,
2245 		          error );
2246 	}
2247 	if( result == -1 )
2248 	{
2249 		libcerror_error_set(
2250 		 error,
2251 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2252 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2253 		 "%s: unable to retrieve directory entry from catalog B-tree root node.",
2254 		 function );
2255 
2256 		return( -1 );
2257 	}
2258 	return( result );
2259 }
2260 
2261 /* Retrieves a directory entry for an UTF-8 encoded path from the catalog B-tree file
2262  * Returns 1 if successful, 0 if not found or -1 on error
2263  */
libfshfs_catalog_btree_file_get_directory_entry_by_utf8_path(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,const uint8_t * utf8_string,size_t utf8_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)2264 int libfshfs_catalog_btree_file_get_directory_entry_by_utf8_path(
2265      libfshfs_btree_file_t *btree_file,
2266      libbfio_handle_t *file_io_handle,
2267      const uint8_t *utf8_string,
2268      size_t utf8_string_length,
2269      uint8_t use_case_folding,
2270      libfshfs_directory_entry_t **directory_entry,
2271      libcerror_error_t **error )
2272 {
2273 	libfshfs_btree_node_t *root_node                 = NULL;
2274 	libfshfs_directory_entry_t *safe_directory_entry = NULL;
2275 	const uint8_t *utf8_string_segment               = NULL;
2276 	static char *function                            = "libfshfs_catalog_btree_file_get_directory_entry_by_utf8_path";
2277 	libuna_unicode_character_t unicode_character     = 0;
2278 	size_t utf8_string_index                         = 0;
2279 	size_t utf8_string_segment_length                = 0;
2280 	uint32_t lookup_identifier                       = 0;
2281 	uint8_t node_type                                = 0;
2282 	int result                                       = 0;
2283 
2284 	if( btree_file == NULL )
2285 	{
2286 		libcerror_error_set(
2287 		 error,
2288 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2289 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2290 		 "%s: invalid B-tree file.",
2291 		 function );
2292 
2293 		return( -1 );
2294 	}
2295 	if( utf8_string == NULL )
2296 	{
2297 		libcerror_error_set(
2298 		 error,
2299 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2300 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2301 		 "%s: invalid UTF-8 string.",
2302 		 function );
2303 
2304 		return( -1 );
2305 	}
2306 	if( utf8_string_length > (size_t) SSIZE_MAX )
2307 	{
2308 		libcerror_error_set(
2309 		 error,
2310 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2311 		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
2312 		 "%s: invalid UTF-8 string length value exceeds maximum.",
2313 		 function );
2314 
2315 		return( -1 );
2316 	}
2317 	if( directory_entry == NULL )
2318 	{
2319 		libcerror_error_set(
2320 		 error,
2321 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2322 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2323 		 "%s: invalid directory entry.",
2324 		 function );
2325 
2326 		return( -1 );
2327 	}
2328 	if( libfshfs_btree_file_get_root_node(
2329 	     btree_file,
2330 	     file_io_handle,
2331 	     &root_node,
2332 	     0,
2333 	     error ) == -1 )
2334 	{
2335 		libcerror_error_set(
2336 		 error,
2337 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2338 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2339 		 "%s: unable to retrieve B-tree root node.",
2340 		 function );
2341 
2342 		goto on_error;
2343 	}
2344 	if( libfshfs_btree_node_get_node_type(
2345 	     root_node,
2346 	     &node_type,
2347 	     error ) != 1 )
2348 	{
2349 		libcerror_error_set(
2350 		 error,
2351 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2352 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2353 		 "%s: unable to determine if B-tree root node type.",
2354 		 function );
2355 
2356 		goto on_error;
2357 	}
2358 	lookup_identifier = LIBFSHFS_ROOT_DIRECTORY_IDENTIFIER;
2359 
2360 	if( utf8_string_length > 0 )
2361 	{
2362 		/* Ignore a leading separator
2363 		 */
2364 		if( utf8_string[ utf8_string_index ] == (uint8_t) LIBFSHFS_SEPARATOR )
2365 		{
2366 			utf8_string_index++;
2367 		}
2368 	}
2369 	if( ( utf8_string_length == 0 )
2370 	 || ( utf8_string_length == 1 ) )
2371 	{
2372 /* TODO optimize this */
2373 		result = libfshfs_catalog_btree_file_get_directory_entry_by_identifier(
2374 		          btree_file,
2375 		          file_io_handle,
2376 		          LIBFSHFS_ROOT_DIRECTORY_IDENTIFIER,
2377 		          &safe_directory_entry,
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 root directory entry from catalog B-tree file.",
2387 			 function );
2388 
2389 			goto on_error;
2390 		}
2391 	}
2392 	else while( utf8_string_index < utf8_string_length )
2393 	{
2394 		utf8_string_segment        = &( utf8_string[ utf8_string_index ] );
2395 		utf8_string_segment_length = utf8_string_index;
2396 
2397 		while( utf8_string_index < utf8_string_length )
2398 		{
2399 			if( libuna_unicode_character_copy_from_utf8(
2400 			     &unicode_character,
2401 			     utf8_string,
2402 			     utf8_string_length,
2403 			     &utf8_string_index,
2404 			     error ) != 1 )
2405 			{
2406 				libcerror_error_set(
2407 				 error,
2408 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2409 				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
2410 				 "%s: unable to copy UTF-8 string to Unicode character.",
2411 				 function );
2412 
2413 				goto on_error;
2414 			}
2415 			if( ( unicode_character == (libuna_unicode_character_t) LIBFSHFS_SEPARATOR )
2416 			 || ( unicode_character == 0 ) )
2417 			{
2418 				utf8_string_segment_length += 1;
2419 
2420 				break;
2421 			}
2422 		}
2423 		utf8_string_segment_length = utf8_string_index - utf8_string_segment_length;
2424 
2425 		if( utf8_string_segment_length == 0 )
2426 		{
2427 			result = 0;
2428 		}
2429 		else
2430 		{
2431 			if( safe_directory_entry != NULL )
2432 			{
2433 				if( libfshfs_directory_entry_free(
2434 				     &safe_directory_entry,
2435 				     error ) != 1 )
2436 				{
2437 					libcerror_error_set(
2438 					 error,
2439 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2440 					 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
2441 					 "%s: unable to free directory entry.",
2442 					 function );
2443 
2444 					goto on_error;
2445 				}
2446 			}
2447 			if( node_type == 0x00 )
2448 			{
2449 				result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf8_name(
2450 					  btree_file,
2451 					  file_io_handle,
2452 					  root_node,
2453 					  lookup_identifier,
2454 					  utf8_string_segment,
2455 					  utf8_string_segment_length,
2456 					  use_case_folding,
2457 					  &safe_directory_entry,
2458 					  1,
2459 					  error );
2460 			}
2461 			else if( node_type == 0xff )
2462 			{
2463 				result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf8_name(
2464 					  btree_file,
2465 					  root_node,
2466 					  lookup_identifier,
2467 					  utf8_string_segment,
2468 					  utf8_string_segment_length,
2469 					  use_case_folding,
2470 					  &safe_directory_entry,
2471 					  error );
2472 			}
2473 		}
2474 		if( result == -1 )
2475 		{
2476 			libcerror_error_set(
2477 			 error,
2478 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2479 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2480 			 "%s: unable to retrieve directory entry by name.",
2481 			 function );
2482 
2483 			goto on_error;
2484 		}
2485 		else if( result == 0 )
2486 		{
2487 			break;
2488 		}
2489 		if( libfshfs_directory_entry_get_identifier(
2490 		     safe_directory_entry,
2491 		     &lookup_identifier,
2492 		     error ) != 1 )
2493 		{
2494 			libcerror_error_set(
2495 			 error,
2496 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2497 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2498 			 "%s: unable to retrieve directory entry identifier.",
2499 			 function );
2500 
2501 			goto on_error;
2502 		}
2503 	}
2504 	if( result != 0 )
2505 	{
2506 		*directory_entry = safe_directory_entry;
2507 	}
2508 	return( result );
2509 
2510 on_error:
2511 	if( *directory_entry != NULL )
2512 	{
2513 		libfshfs_directory_entry_free(
2514 		 directory_entry,
2515 		 NULL );
2516 	}
2517 	return( -1 );
2518 }
2519 
2520 /* Retrieves a directory entry for an UTF-16 encoded name from the catalog B-tree leaf node
2521  * Returns 1 if successful, 0 if not found or -1 on error
2522  */
libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf16_name(libfshfs_btree_file_t * btree_file,libfshfs_btree_node_t * node,uint32_t parent_identifier,const uint16_t * utf16_string,size_t utf16_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)2523 int libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf16_name(
2524      libfshfs_btree_file_t *btree_file,
2525      libfshfs_btree_node_t *node,
2526      uint32_t parent_identifier,
2527      const uint16_t *utf16_string,
2528      size_t utf16_string_length,
2529      uint8_t use_case_folding,
2530      libfshfs_directory_entry_t **directory_entry,
2531      libcerror_error_t **error )
2532 {
2533 	libfshfs_catalog_btree_key_t *node_key = NULL;
2534 	static char *function                  = "libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf16_name";
2535 	uint16_t record_index                  = 0;
2536 	uint16_t record_type                   = 0;
2537 	int compare_result                     = 0;
2538 	int is_leaf_node                       = 0;
2539 	int result                             = 0;
2540 
2541 	if( btree_file == NULL )
2542 	{
2543 		libcerror_error_set(
2544 		 error,
2545 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2546 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2547 		 "%s: invalid B-tree file.",
2548 		 function );
2549 
2550 		return( -1 );
2551 	}
2552 	if( node == NULL )
2553 	{
2554 		libcerror_error_set(
2555 		 error,
2556 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2557 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2558 		 "%s: invalid B-tree node.",
2559 		 function );
2560 
2561 		return( -1 );
2562 	}
2563 	if( node->descriptor == NULL )
2564 	{
2565 		libcerror_error_set(
2566 		 error,
2567 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2568 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2569 		 "%s: invalid B-tree node - missing descriptor.",
2570 		 function );
2571 
2572 		return( -1 );
2573 	}
2574 	if( directory_entry == NULL )
2575 	{
2576 		libcerror_error_set(
2577 		 error,
2578 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2579 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2580 		 "%s: invalid directory entry.",
2581 		 function );
2582 
2583 		return( -1 );
2584 	}
2585 	is_leaf_node = libfshfs_btree_node_is_leaf_node(
2586 	                node,
2587 	                error );
2588 
2589 	if( is_leaf_node == -1 )
2590 	{
2591 		libcerror_error_set(
2592 		 error,
2593 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2594 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2595 		 "%s: unable to determine if B-tree node is a leaf node.",
2596 		 function );
2597 
2598 		goto on_error;
2599 	}
2600 	else if( is_leaf_node == 0 )
2601 	{
2602 		libcerror_error_set(
2603 		 error,
2604 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2605 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
2606 		 "%s: invalid node - not a leaf node.",
2607 		 function );
2608 
2609 		goto on_error;
2610 	}
2611 	for( record_index = 0;
2612 	     record_index < node->descriptor->number_of_records;
2613 	     record_index++ )
2614 	{
2615 		if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
2616 		     node,
2617 		     record_index,
2618 		     &node_key,
2619 		     error ) == -1 )
2620 		{
2621 			libcerror_error_set(
2622 			 error,
2623 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2624 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2625 			 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
2626 			 function,
2627 			 record_index );
2628 
2629 			goto on_error;
2630 		}
2631 		if( node_key == NULL )
2632 		{
2633 			libcerror_error_set(
2634 			 error,
2635 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2636 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2637 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
2638 			 function,
2639 			 record_index );
2640 
2641 			goto on_error;
2642 		}
2643 		if( node_key->parent_identifier == parent_identifier )
2644 		{
2645 			if( node_key->record_data_size < 2 )
2646 			{
2647 				libcerror_error_set(
2648 				 error,
2649 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2650 				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2651 				 "%s: invalid catalog B-tree key: %" PRIu16 " - record data size value out of bounds.",
2652 				 function,
2653 				 record_index );
2654 
2655 				goto on_error;
2656 			}
2657 			byte_stream_copy_to_uint16_big_endian(
2658 			 node_key->record_data,
2659 			 record_type );
2660 
2661 			switch( record_type )
2662 			{
2663 				case LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_RECORD:
2664 				case LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_RECORD:
2665 				case LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_RECORD:
2666 				case LIBFSHFS_RECORD_TYPE_HFS_FILE_RECORD:
2667 					compare_result = libfshfs_catalog_btree_key_compare_name_with_utf16_string(
2668 					                  node_key,
2669 					                  utf16_string,
2670 					                  utf16_string_length,
2671 					                  use_case_folding,
2672 					                  error );
2673 
2674 					if( compare_result == -1 )
2675 					{
2676 						libcerror_error_set(
2677 						 error,
2678 						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2679 						 LIBCERROR_RUNTIME_ERROR_GENERIC,
2680 						 "%s: unable to compare UTF-16 string with catalog B-tree key name.",
2681 						 function );
2682 
2683 						goto on_error;
2684 					}
2685 					break;
2686 
2687 				default:
2688 					compare_result = LIBUNA_COMPARE_LESS;
2689 					break;
2690 			}
2691 			if( compare_result == LIBUNA_COMPARE_EQUAL )
2692 			{
2693 				result = libfshfs_catalog_btree_file_get_directory_entry_from_key(
2694 				          node_key,
2695 				          directory_entry,
2696 				          error );
2697 
2698 				if( result == -1 )
2699 				{
2700 					libcerror_error_set(
2701 					 error,
2702 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2703 					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2704 					 "%s: unable to retrieve directory entry from record data.",
2705 					 function );
2706 
2707 					goto on_error;
2708 				}
2709 			}
2710 		}
2711 		if( ( result == 1 )
2712 		 || ( node_key->parent_identifier > parent_identifier ) )
2713 		{
2714 			break;
2715 		}
2716 	}
2717 	return( result );
2718 
2719 on_error:
2720 	if( *directory_entry != NULL )
2721 	{
2722 		libfshfs_directory_entry_free(
2723 		 directory_entry,
2724 		 NULL );
2725 	}
2726 	return( -1 );
2727 }
2728 
2729 /* Retrieves a directory entry for an UTF-16 encoded name from the catalog B-tree branch node
2730  * Returns 1 if successful, 0 if not found or -1 on error
2731  */
libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf16_name(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,libfshfs_btree_node_t * node,uint32_t parent_identifier,const uint16_t * utf16_string,size_t utf16_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,int recursion_depth,libcerror_error_t ** error)2732 int libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf16_name(
2733      libfshfs_btree_file_t *btree_file,
2734      libbfio_handle_t *file_io_handle,
2735      libfshfs_btree_node_t *node,
2736      uint32_t parent_identifier,
2737      const uint16_t *utf16_string,
2738      size_t utf16_string_length,
2739      uint8_t use_case_folding,
2740      libfshfs_directory_entry_t **directory_entry,
2741      int recursion_depth,
2742      libcerror_error_t **error )
2743 {
2744 	libfshfs_btree_node_t *sub_node             = NULL;
2745 	libfshfs_catalog_btree_key_t *last_node_key = NULL;
2746 	libfshfs_catalog_btree_key_t *node_key      = NULL;
2747 	static char *function                       = "libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf16_name";
2748 	uint32_t sub_node_number                    = 0;
2749 	uint16_t record_index                       = 0;
2750 	uint8_t node_type                           = 0;
2751 	int is_branch_node                          = 0;
2752 	int result                                  = 0;
2753 
2754 	if( btree_file == NULL )
2755 	{
2756 		libcerror_error_set(
2757 		 error,
2758 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2759 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2760 		 "%s: invalid B-tree file.",
2761 		 function );
2762 
2763 		return( -1 );
2764 	}
2765 	if( node == NULL )
2766 	{
2767 		libcerror_error_set(
2768 		 error,
2769 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2770 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2771 		 "%s: invalid B-tree node.",
2772 		 function );
2773 
2774 		return( -1 );
2775 	}
2776 	if( node->descriptor == NULL )
2777 	{
2778 		libcerror_error_set(
2779 		 error,
2780 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2781 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2782 		 "%s: invalid B-tree node - missing descriptor.",
2783 		 function );
2784 
2785 		return( -1 );
2786 	}
2787 	if( directory_entry == NULL )
2788 	{
2789 		libcerror_error_set(
2790 		 error,
2791 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2792 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2793 		 "%s: invalid directory entry.",
2794 		 function );
2795 
2796 		return( -1 );
2797 	}
2798 	if( ( recursion_depth < 0 )
2799 	 || ( recursion_depth > LIBFSHFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
2800 	{
2801 		libcerror_error_set(
2802 		 error,
2803 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2804 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2805 		 "%s: invalid recursion depth value out of bounds.",
2806 		 function );
2807 
2808 		return( -1 );
2809 	}
2810 	is_branch_node = libfshfs_btree_node_is_branch_node(
2811 	                  node,
2812 	                  error );
2813 
2814 	if( is_branch_node == -1 )
2815 	{
2816 		libcerror_error_set(
2817 		 error,
2818 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2819 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2820 		 "%s: unable to determine if B-tree node is a branch node.",
2821 		 function );
2822 
2823 		goto on_error;
2824 	}
2825 	else if( is_branch_node == 0 )
2826 	{
2827 		libcerror_error_set(
2828 		 error,
2829 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2830 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
2831 		 "%s: invalid node - not a branch node.",
2832 		 function );
2833 
2834 		goto on_error;
2835 	}
2836 	if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
2837 	     node,
2838 	     0,
2839 	     &last_node_key,
2840 	     error ) == -1 )
2841 	{
2842 		libcerror_error_set(
2843 		 error,
2844 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2845 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2846 		 "%s: unable to retrieve catalog B-tree key: 0.",
2847 		 function );
2848 
2849 		goto on_error;
2850 	}
2851 	node_key = last_node_key;
2852 
2853 	for( record_index = 1;
2854 	     record_index <= node->descriptor->number_of_records;
2855 	     record_index++ )
2856 	{
2857 		if( record_index < node->descriptor->number_of_records )
2858 		{
2859 			if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
2860 			     node,
2861 			     record_index,
2862 			     &node_key,
2863 			     error ) == -1 )
2864 			{
2865 				libcerror_error_set(
2866 				 error,
2867 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2868 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2869 				 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
2870 				 function,
2871 				 record_index );
2872 
2873 				goto on_error;
2874 			}
2875 		}
2876 		if( node_key == NULL )
2877 		{
2878 			libcerror_error_set(
2879 			 error,
2880 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2881 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2882 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
2883 			 function,
2884 			 record_index );
2885 
2886 			goto on_error;
2887 		}
2888 		if( ( record_index == node->descriptor->number_of_records )
2889 		 || ( node_key->parent_identifier >= parent_identifier ) )
2890 		{
2891 			if( libfshfs_catalog_btree_file_get_sub_node_number_from_key(
2892 			     last_node_key,
2893 			     &sub_node_number,
2894 			     error ) != 1 )
2895 			{
2896 				libcerror_error_set(
2897 				 error,
2898 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2899 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2900 				 "%s: unable to retrieve sub node number from catalog B-Tree key.",
2901 				 function );
2902 
2903 				goto on_error;
2904 			}
2905 #if defined( HAVE_DEBUG_OUTPUT )
2906 			if( libcnotify_verbose != 0 )
2907 			{
2908 				libcnotify_printf(
2909 				 "%s: B-tree sub node number\t: %" PRIu32 "\n",
2910 				 function,
2911 				 sub_node_number );
2912 
2913 				libcnotify_printf(
2914 				 "\n" );
2915 			}
2916 #endif
2917 			if( libfshfs_btree_file_get_node_by_number(
2918 			     btree_file,
2919 			     file_io_handle,
2920 			     sub_node_number,
2921 			     &sub_node,
2922 			     recursion_depth,
2923 			     error ) == -1 )
2924 			{
2925 				libcerror_error_set(
2926 				 error,
2927 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2928 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2929 				 "%s: unable to retrieve B-tree sub node: %" PRIu32 ".",
2930 				 function,
2931 				 sub_node_number );
2932 
2933 				goto on_error;
2934 			}
2935 			if( libfshfs_btree_node_get_node_type(
2936 			     sub_node,
2937 			     &node_type,
2938 			     error ) != 1 )
2939 			{
2940 				libcerror_error_set(
2941 				 error,
2942 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2943 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2944 				 "%s: unable to determine if B-tree sub node: %" PRIu32 " type.",
2945 				 function,
2946 				 sub_node_number );
2947 
2948 				goto on_error;
2949 			}
2950 			if( node_type == 0x00 )
2951 			{
2952 				result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf16_name(
2953 				          btree_file,
2954 				          file_io_handle,
2955 				          sub_node,
2956 				          parent_identifier,
2957 				          utf16_string,
2958 				          utf16_string_length,
2959 				          use_case_folding,
2960 				          directory_entry,
2961 				          recursion_depth + 1,
2962 				          error );
2963 			}
2964 			else if( node_type == 0xff )
2965 			{
2966 				result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf16_name(
2967 				          btree_file,
2968 				          sub_node,
2969 				          parent_identifier,
2970 				          utf16_string,
2971 				          utf16_string_length,
2972 				          use_case_folding,
2973 				          directory_entry,
2974 				          error );
2975 			}
2976 			if( result == -1 )
2977 			{
2978 				libcerror_error_set(
2979 				 error,
2980 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2981 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2982 				 "%s: unable to retrieve directory entry from catalog B-tree node: %" PRIu32 ".",
2983 				 function,
2984 				 sub_node_number );
2985 
2986 				goto on_error;
2987 			}
2988 			if( ( result == 1 )
2989 			 || ( node_key->parent_identifier > parent_identifier ) )
2990 			{
2991 				break;
2992 			}
2993 		}
2994 		last_node_key = node_key;
2995 	}
2996 	return( result );
2997 
2998 on_error:
2999 	if( *directory_entry != NULL )
3000 	{
3001 		libfshfs_directory_entry_free(
3002 		 directory_entry,
3003 		 NULL );
3004 	}
3005 	return( -1 );
3006 }
3007 
3008 /* Retrieves a directory entry for an UTF-16 encoded name from the catalog B-tree file
3009  * Returns 1 if successful, 0 if not found or -1 on error
3010  */
libfshfs_catalog_btree_file_get_directory_entry_by_utf16_name(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,uint32_t parent_identifier,const uint16_t * utf16_string,size_t utf16_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)3011 int libfshfs_catalog_btree_file_get_directory_entry_by_utf16_name(
3012      libfshfs_btree_file_t *btree_file,
3013      libbfio_handle_t *file_io_handle,
3014      uint32_t parent_identifier,
3015      const uint16_t *utf16_string,
3016      size_t utf16_string_length,
3017      uint8_t use_case_folding,
3018      libfshfs_directory_entry_t **directory_entry,
3019      libcerror_error_t **error )
3020 {
3021 	libfshfs_btree_node_t *root_node = NULL;
3022 	static char *function            = "libfshfs_catalog_btree_file_get_directory_entry_by_utf16_name";
3023 	uint8_t node_type                = 0;
3024 	int result                       = 0;
3025 
3026 	if( libfshfs_btree_file_get_root_node(
3027 	     btree_file,
3028 	     file_io_handle,
3029 	     &root_node,
3030 	     0,
3031 	     error ) == -1 )
3032 	{
3033 		libcerror_error_set(
3034 		 error,
3035 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3036 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3037 		 "%s: unable to retrieve B-tree root node.",
3038 		 function );
3039 
3040 		return( -1 );
3041 	}
3042 	if( libfshfs_btree_node_get_node_type(
3043 	     root_node,
3044 	     &node_type,
3045 	     error ) != 1 )
3046 	{
3047 		libcerror_error_set(
3048 		 error,
3049 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3050 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3051 		 "%s: unable to determine if B-tree root node type.",
3052 		 function );
3053 
3054 		return( -1 );
3055 	}
3056 	if( node_type == 0x00 )
3057 	{
3058 		result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf16_name(
3059 		          btree_file,
3060 		          file_io_handle,
3061 		          root_node,
3062 		          parent_identifier,
3063 		          utf16_string,
3064 		          utf16_string_length,
3065 		          use_case_folding,
3066 		          directory_entry,
3067 		          1,
3068 		          error );
3069 	}
3070 	else if( node_type == 0xff )
3071 	{
3072 		result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf16_name(
3073 		          btree_file,
3074 		          root_node,
3075 		          parent_identifier,
3076 		          utf16_string,
3077 		          utf16_string_length,
3078 		          use_case_folding,
3079 		          directory_entry,
3080 		          error );
3081 	}
3082 	if( result == -1 )
3083 	{
3084 		libcerror_error_set(
3085 		 error,
3086 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3087 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3088 		 "%s: unable to retrieve directory entry from catalog B-tree root node.",
3089 		 function );
3090 
3091 		return( -1 );
3092 	}
3093 	return( result );
3094 }
3095 
3096 /* Retrieves a directory entry for an UTF-16 encoded path from the catalog B-tree file
3097  * Returns 1 if successful, 0 if not found or -1 on error
3098  */
libfshfs_catalog_btree_file_get_directory_entry_by_utf16_path(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,const uint16_t * utf16_string,size_t utf16_string_length,uint8_t use_case_folding,libfshfs_directory_entry_t ** directory_entry,libcerror_error_t ** error)3099 int libfshfs_catalog_btree_file_get_directory_entry_by_utf16_path(
3100      libfshfs_btree_file_t *btree_file,
3101      libbfio_handle_t *file_io_handle,
3102      const uint16_t *utf16_string,
3103      size_t utf16_string_length,
3104      uint8_t use_case_folding,
3105      libfshfs_directory_entry_t **directory_entry,
3106      libcerror_error_t **error )
3107 {
3108 	libfshfs_btree_node_t *root_node                 = NULL;
3109 	libfshfs_directory_entry_t *safe_directory_entry = NULL;
3110 	const uint16_t *utf16_string_segment             = NULL;
3111 	static char *function                            = "libfshfs_catalog_btree_file_get_directory_entry_by_utf16_path";
3112 	libuna_unicode_character_t unicode_character     = 0;
3113 	size_t utf16_string_index                        = 0;
3114 	size_t utf16_string_segment_length               = 0;
3115 	uint32_t lookup_identifier                       = 0;
3116 	uint8_t node_type                                = 0;
3117 	int result                                       = 0;
3118 
3119 	if( btree_file == NULL )
3120 	{
3121 		libcerror_error_set(
3122 		 error,
3123 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3124 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3125 		 "%s: invalid B-tree file.",
3126 		 function );
3127 
3128 		return( -1 );
3129 	}
3130 	if( utf16_string == NULL )
3131 	{
3132 		libcerror_error_set(
3133 		 error,
3134 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3135 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3136 		 "%s: invalid UTF-16 string.",
3137 		 function );
3138 
3139 		return( -1 );
3140 	}
3141 	if( utf16_string_length > (size_t) SSIZE_MAX )
3142 	{
3143 		libcerror_error_set(
3144 		 error,
3145 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3146 		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
3147 		 "%s: invalid UTF-16 string length value exceeds maximum.",
3148 		 function );
3149 
3150 		return( -1 );
3151 	}
3152 	if( directory_entry == NULL )
3153 	{
3154 		libcerror_error_set(
3155 		 error,
3156 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3157 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3158 		 "%s: invalid directory entry.",
3159 		 function );
3160 
3161 		return( -1 );
3162 	}
3163 	if( libfshfs_btree_file_get_root_node(
3164 	     btree_file,
3165 	     file_io_handle,
3166 	     &root_node,
3167 	     0,
3168 	     error ) == -1 )
3169 	{
3170 		libcerror_error_set(
3171 		 error,
3172 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3173 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3174 		 "%s: unable to retrieve B-tree root node.",
3175 		 function );
3176 
3177 		goto on_error;
3178 	}
3179 	if( libfshfs_btree_node_get_node_type(
3180 	     root_node,
3181 	     &node_type,
3182 	     error ) != 1 )
3183 	{
3184 		libcerror_error_set(
3185 		 error,
3186 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3187 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3188 		 "%s: unable to determine if B-tree root node type.",
3189 		 function );
3190 
3191 		goto on_error;
3192 	}
3193 	lookup_identifier = LIBFSHFS_ROOT_DIRECTORY_IDENTIFIER;
3194 
3195 	if( utf16_string_length > 0 )
3196 	{
3197 		/* Ignore a leading separator
3198 		 */
3199 		if( utf16_string[ utf16_string_index ] == (uint16_t) LIBFSHFS_SEPARATOR )
3200 		{
3201 			utf16_string_index++;
3202 		}
3203 	}
3204 	if( ( utf16_string_length == 0 )
3205 	 || ( utf16_string_length == 1 ) )
3206 	{
3207 /* TODO optimize this */
3208 		result = libfshfs_catalog_btree_file_get_directory_entry_by_identifier(
3209 		          btree_file,
3210 		          file_io_handle,
3211 		          LIBFSHFS_ROOT_DIRECTORY_IDENTIFIER,
3212 		          &safe_directory_entry,
3213 		          error );
3214 
3215 		if( result == -1 )
3216 		{
3217 			libcerror_error_set(
3218 			 error,
3219 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3220 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3221 			 "%s: unable to retrieve root directory entry from catalog B-tree file.",
3222 			 function );
3223 
3224 			goto on_error;
3225 		}
3226 	}
3227 	else while( utf16_string_index < utf16_string_length )
3228 	{
3229 		utf16_string_segment        = &( utf16_string[ utf16_string_index ] );
3230 		utf16_string_segment_length = utf16_string_index;
3231 
3232 		while( utf16_string_index < utf16_string_length )
3233 		{
3234 			if( libuna_unicode_character_copy_from_utf16(
3235 			     &unicode_character,
3236 			     utf16_string,
3237 			     utf16_string_length,
3238 			     &utf16_string_index,
3239 			     error ) != 1 )
3240 			{
3241 				libcerror_error_set(
3242 				 error,
3243 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3244 				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
3245 				 "%s: unable to copy UTF-16 string to Unicode character.",
3246 				 function );
3247 
3248 				goto on_error;
3249 			}
3250 			if( ( unicode_character == (libuna_unicode_character_t) LIBFSHFS_SEPARATOR )
3251 			 || ( unicode_character == 0 ) )
3252 			{
3253 				utf16_string_segment_length += 1;
3254 
3255 				break;
3256 			}
3257 		}
3258 		utf16_string_segment_length = utf16_string_index - utf16_string_segment_length;
3259 
3260 		if( utf16_string_segment_length == 0 )
3261 		{
3262 			result = 0;
3263 		}
3264 		else
3265 		{
3266 			if( safe_directory_entry != NULL )
3267 			{
3268 				if( libfshfs_directory_entry_free(
3269 				     &safe_directory_entry,
3270 				     error ) != 1 )
3271 				{
3272 					libcerror_error_set(
3273 					 error,
3274 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3275 					 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
3276 					 "%s: unable to free directory entry.",
3277 					 function );
3278 
3279 					goto on_error;
3280 				}
3281 			}
3282 			if( node_type == 0x00 )
3283 			{
3284 				result = libfshfs_catalog_btree_file_get_directory_entry_from_branch_node_by_utf16_name(
3285 					  btree_file,
3286 					  file_io_handle,
3287 					  root_node,
3288 					  lookup_identifier,
3289 					  utf16_string_segment,
3290 					  utf16_string_segment_length,
3291 					  use_case_folding,
3292 					  &safe_directory_entry,
3293 					  1,
3294 					  error );
3295 			}
3296 			else if( node_type == 0xff )
3297 			{
3298 				result = libfshfs_catalog_btree_file_get_directory_entry_from_leaf_node_by_utf16_name(
3299 					  btree_file,
3300 					  root_node,
3301 					  lookup_identifier,
3302 					  utf16_string_segment,
3303 					  utf16_string_segment_length,
3304 					  use_case_folding,
3305 					  &safe_directory_entry,
3306 					  error );
3307 			}
3308 		}
3309 		if( result == -1 )
3310 		{
3311 			libcerror_error_set(
3312 			 error,
3313 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3314 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3315 			 "%s: unable to retrieve directory entry by name.",
3316 			 function );
3317 
3318 			goto on_error;
3319 		}
3320 		else if( result == 0 )
3321 		{
3322 			break;
3323 		}
3324 		if( libfshfs_directory_entry_get_identifier(
3325 		     safe_directory_entry,
3326 		     &lookup_identifier,
3327 		     error ) != 1 )
3328 		{
3329 			libcerror_error_set(
3330 			 error,
3331 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3332 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3333 			 "%s: unable to retrieve directory entry identifier.",
3334 			 function );
3335 
3336 			goto on_error;
3337 		}
3338 	}
3339 	if( result != 0 )
3340 	{
3341 		*directory_entry = safe_directory_entry;
3342 	}
3343 	return( result );
3344 
3345 on_error:
3346 	if( *directory_entry != NULL )
3347 	{
3348 		libfshfs_directory_entry_free(
3349 		 directory_entry,
3350 		 NULL );
3351 	}
3352 	return( -1 );
3353 }
3354 
3355 /* Retrieves directory entries for a specific parent identifier from the catalog B-tree leaf node
3356  * Returns 1 if successful or -1 on error
3357  */
libfshfs_catalog_btree_file_get_directory_entries_from_leaf_node(libfshfs_btree_file_t * btree_file,libfshfs_btree_node_t * node,uint32_t parent_identifier,libcdata_array_t * directory_entries,libcerror_error_t ** error)3358 int libfshfs_catalog_btree_file_get_directory_entries_from_leaf_node(
3359      libfshfs_btree_file_t *btree_file,
3360      libfshfs_btree_node_t *node,
3361      uint32_t parent_identifier,
3362      libcdata_array_t *directory_entries,
3363      libcerror_error_t **error )
3364 {
3365 	libfshfs_catalog_btree_key_t *node_key      = NULL;
3366 	libfshfs_directory_entry_t *directory_entry = NULL;
3367 	static char *function                       = "libfshfs_catalog_btree_file_get_directory_entries_from_leaf_node";
3368 	uint16_t record_index                       = 0;
3369 	int entry_index                             = 0;
3370 	int is_leaf_node                            = 0;
3371 	int result                                  = 0;
3372 
3373 	if( btree_file == NULL )
3374 	{
3375 		libcerror_error_set(
3376 		 error,
3377 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3378 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3379 		 "%s: invalid B-tree file.",
3380 		 function );
3381 
3382 		return( -1 );
3383 	}
3384 	if( node == NULL )
3385 	{
3386 		libcerror_error_set(
3387 		 error,
3388 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3389 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3390 		 "%s: invalid B-tree node.",
3391 		 function );
3392 
3393 		return( -1 );
3394 	}
3395 	if( node->descriptor == NULL )
3396 	{
3397 		libcerror_error_set(
3398 		 error,
3399 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3400 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3401 		 "%s: invalid B-tree node - missing descriptor.",
3402 		 function );
3403 
3404 		return( -1 );
3405 	}
3406 	is_leaf_node = libfshfs_btree_node_is_leaf_node(
3407 	                node,
3408 	                error );
3409 
3410 	if( is_leaf_node == -1 )
3411 	{
3412 		libcerror_error_set(
3413 		 error,
3414 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3415 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3416 		 "%s: unable to determine if B-tree node is a leaf node.",
3417 		 function );
3418 
3419 		goto on_error;
3420 	}
3421 	else if( is_leaf_node == 0 )
3422 	{
3423 		libcerror_error_set(
3424 		 error,
3425 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3426 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
3427 		 "%s: invalid node - not a leaf node.",
3428 		 function );
3429 
3430 		goto on_error;
3431 	}
3432 	for( record_index = 0;
3433 	     record_index < node->descriptor->number_of_records;
3434 	     record_index++ )
3435 	{
3436 		if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
3437 		     node,
3438 		     record_index,
3439 		     &node_key,
3440 		     error ) == -1 )
3441 		{
3442 			libcerror_error_set(
3443 			 error,
3444 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3445 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3446 			 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
3447 			 function,
3448 			 record_index );
3449 
3450 			goto on_error;
3451 		}
3452 		if( node_key == NULL )
3453 		{
3454 			libcerror_error_set(
3455 			 error,
3456 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3457 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3458 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
3459 			 function,
3460 			 record_index );
3461 
3462 			goto on_error;
3463 		}
3464 		if( node_key->parent_identifier == parent_identifier )
3465 		{
3466 			result = libfshfs_catalog_btree_file_get_directory_entry_from_key(
3467 			          node_key,
3468 			          &directory_entry,
3469 			          error );
3470 
3471 			if( result == -1 )
3472 			{
3473 				libcerror_error_set(
3474 				 error,
3475 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3476 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3477 				 "%s: unable to retrieve directory entry from record data.",
3478 				 function );
3479 
3480 				goto on_error;
3481 			}
3482 			else if( result != 0 )
3483 			{
3484 				if( libcdata_array_append_entry(
3485 				     directory_entries,
3486 				     &entry_index,
3487 				     (intptr_t *) directory_entry,
3488 				     error ) != 1 )
3489 				{
3490 					libcerror_error_set(
3491 					 error,
3492 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3493 					 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
3494 					 "%s: unable to append directory entry to array.",
3495 					 function );
3496 
3497 					goto on_error;
3498 				}
3499 				directory_entry = NULL;
3500 			}
3501 		}
3502 		if( node_key->parent_identifier > parent_identifier )
3503 		{
3504 			break;
3505 		}
3506 	}
3507 	return( 1 );
3508 
3509 on_error:
3510 	if( directory_entry != NULL )
3511 	{
3512 		libfshfs_directory_entry_free(
3513 		 &directory_entry,
3514 		 NULL );
3515 	}
3516 	libcdata_array_empty(
3517 	 directory_entries,
3518 	 (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_directory_entry_free,
3519 	 NULL );
3520 
3521 	return( -1 );
3522 }
3523 
3524 /* Retrieves directory entries for a specific parent identifier from the catalog B-tree branch node
3525  * Returns 1 if successful or -1 on error
3526  */
libfshfs_catalog_btree_file_get_directory_entries_from_branch_node(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,libfshfs_btree_node_t * node,uint32_t parent_identifier,libcdata_array_t * directory_entries,int recursion_depth,libcerror_error_t ** error)3527 int libfshfs_catalog_btree_file_get_directory_entries_from_branch_node(
3528      libfshfs_btree_file_t *btree_file,
3529      libbfio_handle_t *file_io_handle,
3530      libfshfs_btree_node_t *node,
3531      uint32_t parent_identifier,
3532      libcdata_array_t *directory_entries,
3533      int recursion_depth,
3534      libcerror_error_t **error )
3535 {
3536 	libfshfs_btree_node_t *sub_node             = NULL;
3537 	libfshfs_catalog_btree_key_t *last_node_key = NULL;
3538 	libfshfs_catalog_btree_key_t *node_key      = NULL;
3539 	static char *function                       = "libfshfs_catalog_btree_file_get_directory_entries_from_branch_node";
3540 	uint32_t sub_node_number                    = 0;
3541 	uint16_t record_index                       = 0;
3542 	uint8_t node_type                           = 0;
3543 	int is_branch_node                          = 0;
3544 	int result                                  = 0;
3545 
3546 	if( btree_file == NULL )
3547 	{
3548 		libcerror_error_set(
3549 		 error,
3550 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3551 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3552 		 "%s: invalid B-tree file.",
3553 		 function );
3554 
3555 		return( -1 );
3556 	}
3557 	if( node == NULL )
3558 	{
3559 		libcerror_error_set(
3560 		 error,
3561 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3562 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3563 		 "%s: invalid B-tree node.",
3564 		 function );
3565 
3566 		return( -1 );
3567 	}
3568 	if( node->descriptor == NULL )
3569 	{
3570 		libcerror_error_set(
3571 		 error,
3572 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3573 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3574 		 "%s: invalid B-tree node - missing descriptor.",
3575 		 function );
3576 
3577 		return( -1 );
3578 	}
3579 	if( ( recursion_depth < 0 )
3580 	 || ( recursion_depth > LIBFSHFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
3581 	{
3582 		libcerror_error_set(
3583 		 error,
3584 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3585 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
3586 		 "%s: invalid recursion depth value out of bounds.",
3587 		 function );
3588 
3589 		return( -1 );
3590 	}
3591 	is_branch_node = libfshfs_btree_node_is_branch_node(
3592 	                  node,
3593 	                  error );
3594 
3595 	if( is_branch_node == -1 )
3596 	{
3597 		libcerror_error_set(
3598 		 error,
3599 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3600 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3601 		 "%s: unable to determine if B-tree node is a branch node.",
3602 		 function );
3603 
3604 		goto on_error;
3605 	}
3606 	else if( is_branch_node == 0 )
3607 	{
3608 		libcerror_error_set(
3609 		 error,
3610 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3611 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
3612 		 "%s: invalid node - not a branch node.",
3613 		 function );
3614 
3615 		goto on_error;
3616 	}
3617 	if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
3618 	     node,
3619 	     0,
3620 	     &last_node_key,
3621 	     error ) == -1 )
3622 	{
3623 		libcerror_error_set(
3624 		 error,
3625 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3626 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3627 		 "%s: unable to retrieve catalog B-tree key: 0.",
3628 		 function );
3629 
3630 		goto on_error;
3631 	}
3632 	node_key = last_node_key;
3633 
3634 	for( record_index = 1;
3635 	     record_index <= node->descriptor->number_of_records;
3636 	     record_index++ )
3637 	{
3638 		if( record_index < node->descriptor->number_of_records )
3639 		{
3640 			if( libfshfs_catalog_btree_file_get_key_from_node_by_index(
3641 			     node,
3642 			     record_index,
3643 			     &node_key,
3644 			     error ) == -1 )
3645 			{
3646 				libcerror_error_set(
3647 				 error,
3648 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3649 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3650 				 "%s: unable to retrieve catalog B-tree key: %" PRIu16 ".",
3651 				 function,
3652 				 record_index );
3653 
3654 				goto on_error;
3655 			}
3656 		}
3657 		if( node_key == NULL )
3658 		{
3659 			libcerror_error_set(
3660 			 error,
3661 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3662 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3663 			 "%s: missing catalog B-tree key: %" PRIu16 ".",
3664 			 function,
3665 			 record_index );
3666 
3667 			goto on_error;
3668 		}
3669 		if( ( record_index == node->descriptor->number_of_records )
3670 		 || ( node_key->parent_identifier >= parent_identifier ) )
3671 		{
3672 			if( libfshfs_catalog_btree_file_get_sub_node_number_from_key(
3673 			     last_node_key,
3674 			     &sub_node_number,
3675 			     error ) != 1 )
3676 			{
3677 				libcerror_error_set(
3678 				 error,
3679 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3680 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3681 				 "%s: unable to retrieve sub node number from catalog B-Tree key.",
3682 				 function );
3683 
3684 				goto on_error;
3685 			}
3686 #if defined( HAVE_DEBUG_OUTPUT )
3687 			if( libcnotify_verbose != 0 )
3688 			{
3689 				libcnotify_printf(
3690 				 "%s: B-tree sub node number\t: %" PRIu32 "\n",
3691 				 function,
3692 				 sub_node_number );
3693 
3694 				libcnotify_printf(
3695 				 "\n" );
3696 			}
3697 #endif
3698 			if( libfshfs_btree_file_get_node_by_number(
3699 			     btree_file,
3700 			     file_io_handle,
3701 			     sub_node_number,
3702 			     &sub_node,
3703 			     recursion_depth,
3704 			     error ) == -1 )
3705 			{
3706 				libcerror_error_set(
3707 				 error,
3708 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3709 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3710 				 "%s: unable to retrieve B-tree sub node: %" PRIu32 ".",
3711 				 function,
3712 				 sub_node_number );
3713 
3714 				goto on_error;
3715 			}
3716 			if( libfshfs_btree_node_get_node_type(
3717 			     sub_node,
3718 			     &node_type,
3719 			     error ) != 1 )
3720 			{
3721 				libcerror_error_set(
3722 				 error,
3723 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3724 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3725 				 "%s: unable to determine if B-tree sub node: %" PRIu32 " type.",
3726 				 function,
3727 				 sub_node_number );
3728 
3729 				goto on_error;
3730 			}
3731 			if( node_type == 0x00 )
3732 			{
3733 				result = libfshfs_catalog_btree_file_get_directory_entries_from_branch_node(
3734 				          btree_file,
3735 				          file_io_handle,
3736 				          sub_node,
3737 				          parent_identifier,
3738 				          directory_entries,
3739 				          recursion_depth + 1,
3740 				          error );
3741 			}
3742 			else if( node_type == 0xff )
3743 			{
3744 				result = libfshfs_catalog_btree_file_get_directory_entries_from_leaf_node(
3745 				          btree_file,
3746 				          sub_node,
3747 				          parent_identifier,
3748 				          directory_entries,
3749 				          error );
3750 			}
3751 			if( result != 1 )
3752 			{
3753 				libcerror_error_set(
3754 				 error,
3755 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3756 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3757 				 "%s: unable to retrieve directory entries from catalog B-tree node: %" PRIu32 ".",
3758 				 function,
3759 				 sub_node_number );
3760 
3761 				goto on_error;
3762 			}
3763 			if( node_key->parent_identifier > parent_identifier )
3764 			{
3765 				break;
3766 			}
3767 		}
3768 		last_node_key = node_key;
3769 	}
3770 	return( 1 );
3771 
3772 on_error:
3773 	libcdata_array_empty(
3774 	 directory_entries,
3775 	 (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_directory_entry_free,
3776 	 NULL );
3777 
3778 	return( -1 );
3779 }
3780 
3781 /* Retrieves directory entries for a specific parent identifier from the catalog B-tree file
3782  * Returns 1 if successful or -1 on error
3783  */
libfshfs_catalog_btree_file_get_directory_entries(libfshfs_btree_file_t * btree_file,libbfio_handle_t * file_io_handle,uint32_t parent_identifier,libcdata_array_t * directory_entries,libcerror_error_t ** error)3784 int libfshfs_catalog_btree_file_get_directory_entries(
3785      libfshfs_btree_file_t *btree_file,
3786      libbfio_handle_t *file_io_handle,
3787      uint32_t parent_identifier,
3788      libcdata_array_t *directory_entries,
3789      libcerror_error_t **error )
3790 {
3791 	libfshfs_btree_node_t *root_node = NULL;
3792 	static char *function            = "libfshfs_catalog_btree_file_get_directory_entries";
3793 	uint8_t node_type                = 0;
3794 	int result                       = 1;
3795 
3796 	if( libfshfs_btree_file_get_root_node(
3797 	     btree_file,
3798 	     file_io_handle,
3799 	     &root_node,
3800 	     0,
3801 	     error ) == -1 )
3802 	{
3803 		libcerror_error_set(
3804 		 error,
3805 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3806 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3807 		 "%s: unable to retrieve B-tree root node.",
3808 		 function );
3809 
3810 		goto on_error;
3811 	}
3812 	if( libfshfs_btree_node_get_node_type(
3813 	     root_node,
3814 	     &node_type,
3815 	     error ) != 1 )
3816 	{
3817 		libcerror_error_set(
3818 		 error,
3819 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3820 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3821 		 "%s: unable to determine if B-tree root node is a branch node.",
3822 		 function );
3823 
3824 		goto on_error;
3825 	}
3826 	if( node_type == 0x00 )
3827 	{
3828 		result = libfshfs_catalog_btree_file_get_directory_entries_from_branch_node(
3829 		          btree_file,
3830 		          file_io_handle,
3831 		          root_node,
3832 		          parent_identifier,
3833 		          directory_entries,
3834 		          1,
3835 		          error );
3836 	}
3837 	else if( node_type == 0xff )
3838 	{
3839 		result = libfshfs_catalog_btree_file_get_directory_entries_from_leaf_node(
3840 		          btree_file,
3841 		          root_node,
3842 		          parent_identifier,
3843 		          directory_entries,
3844 		          error );
3845 	}
3846 	if( result != 1 )
3847 	{
3848 		libcerror_error_set(
3849 		 error,
3850 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3851 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3852 		 "%s: unable to retrieve directory entries from catalog B-tree root node.",
3853 		 function );
3854 
3855 		goto on_error;
3856 	}
3857 	return( 1 );
3858 
3859 on_error:
3860 	libcdata_array_empty(
3861 	 directory_entries,
3862 	 (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_directory_entry_free,
3863 	 NULL );
3864 
3865 	return( -1 );
3866 }
3867 
3868