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