Coverage Report

Created: 2025-06-24 07:14

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