Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsapfs/libfsapfs/libfsapfs_btree_node.c
Line
Count
Source
1
/*
2
 * The B-tree node functions
3
 *
4
 * Copyright (C) 2018-2026, 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 "libfsapfs_btree_entry.h"
28
#include "libfsapfs_btree_footer.h"
29
#include "libfsapfs_btree_node_header.h"
30
#include "libfsapfs_btree_node.h"
31
#include "libfsapfs_libcdata.h"
32
#include "libfsapfs_libcerror.h"
33
#include "libfsapfs_libcnotify.h"
34
35
#include "fsapfs_btree.h"
36
#include "fsapfs_object.h"
37
#include "fsapfs_object_map.h"
38
39
/* Creates a B-tree node
40
 * Make sure the value btree_node is referencing, is set to NULL
41
 * Returns 1 if successful or -1 on error
42
 */
43
int libfsapfs_btree_node_initialize(
44
     libfsapfs_btree_node_t **btree_node,
45
     libcerror_error_t **error )
46
2.64k
{
47
2.64k
  static char *function = "libfsapfs_btree_node_initialize";
48
49
2.64k
  if( btree_node == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid B-tree node.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
2.64k
  if( *btree_node != NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
65
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66
0
     "%s: invalid B-tree node value already set.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
2.64k
  *btree_node = memory_allocate_structure(
72
2.64k
                 libfsapfs_btree_node_t );
73
74
2.64k
  if( *btree_node == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
79
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
80
0
     "%s: unable to create B-tree node.",
81
0
     function );
82
83
0
    goto on_error;
84
0
  }
85
2.64k
  if( memory_set(
86
2.64k
       *btree_node,
87
2.64k
       0,
88
2.64k
       sizeof( libfsapfs_btree_node_t ) ) == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
93
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
94
0
     "%s: unable to clear B-tree node.",
95
0
     function );
96
97
0
    memory_free(
98
0
     *btree_node );
99
100
0
    *btree_node = NULL;
101
102
0
    return( -1 );
103
0
  }
104
2.64k
  if( libcdata_array_initialize(
105
2.64k
       &( ( *btree_node )->entries_array ),
106
2.64k
       0,
107
2.64k
       error ) != 1 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
113
0
     "%s: unable to create entries array.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
2.64k
  return( 1 );
119
120
0
on_error:
121
0
  if( *btree_node != NULL )
122
0
  {
123
0
    memory_free(
124
0
     *btree_node );
125
126
0
    *btree_node = NULL;
127
0
  }
128
0
  return( -1 );
129
2.64k
}
130
131
/* Frees a B-tree node
132
 * Returns 1 if successful or -1 on error
133
 */
134
int libfsapfs_btree_node_free(
135
     libfsapfs_btree_node_t **btree_node,
136
     libcerror_error_t **error )
137
2.64k
{
138
2.64k
  static char *function = "libfsapfs_btree_node_free";
139
2.64k
  int result            = 1;
140
141
2.64k
  if( btree_node == NULL )
142
0
  {
143
0
    libcerror_error_set(
144
0
     error,
145
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
146
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
147
0
     "%s: invalid B-tree node.",
148
0
     function );
149
150
0
    return( -1 );
151
0
  }
152
2.64k
  if( *btree_node != NULL )
153
2.64k
  {
154
2.64k
    if( ( *btree_node )->node_header != NULL )
155
2.39k
    {
156
2.39k
      if( libfsapfs_btree_node_header_free(
157
2.39k
           &( ( *btree_node )->node_header ),
158
2.39k
           error ) != 1 )
159
0
      {
160
0
        libcerror_error_set(
161
0
         error,
162
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
163
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
164
0
         "%s: unable to free B-tree node header.",
165
0
         function );
166
167
0
        result = -1;
168
0
      }
169
2.39k
    }
170
2.64k
    if( ( *btree_node )->footer != NULL )
171
2.23k
    {
172
2.23k
      if( libfsapfs_btree_footer_free(
173
2.23k
           &( ( *btree_node )->footer ),
174
2.23k
           error ) != 1 )
175
0
      {
176
0
        libcerror_error_set(
177
0
         error,
178
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
179
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
180
0
         "%s: unable to free B-tree footer.",
181
0
         function );
182
183
0
        result = -1;
184
0
      }
185
2.23k
    }
186
2.64k
    if( libcdata_array_free(
187
2.64k
         &( ( *btree_node )->entries_array ),
188
2.64k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_entry_free,
189
2.64k
         error ) != 1 )
190
0
    {
191
0
      libcerror_error_set(
192
0
       error,
193
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
194
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
195
0
       "%s: unable to free entries array.",
196
0
       function );
197
198
0
      result = -1;
199
0
    }
200
2.64k
    memory_free(
201
2.64k
     *btree_node );
202
203
2.64k
    *btree_node = NULL;
204
2.64k
  }
205
2.64k
  return( result );
206
2.64k
}
207
208
/* Reads the B-tree node
209
 * Returns 1 if successful or -1 on error
210
 */
211
int libfsapfs_btree_node_read_data(
212
     libfsapfs_btree_node_t *btree_node,
213
     const uint8_t *data,
214
     size_t data_size,
215
     libcerror_error_t **error )
216
2.64k
{
217
2.64k
  libfsapfs_btree_entry_t *btree_entry = NULL;
218
2.64k
  const uint8_t *btree_node_entry      = NULL;
219
2.64k
  static char *function                = "libfsapfs_btree_node_read_data";
220
2.64k
  size_t btree_entry_data_size         = 0;
221
2.64k
  size_t data_offset                   = 0;
222
2.64k
  size_t minimum_data_size             = 0;
223
2.64k
  size_t remaining_data_size           = 0;
224
2.64k
  uint16_t entries_data_offset         = 0;
225
2.64k
  uint16_t footer_offset               = 0;
226
2.64k
  uint16_t key_data_offset             = 0;
227
2.64k
  uint16_t key_data_size               = 0;
228
2.64k
  uint16_t map_entry_index             = 0;
229
2.64k
  uint16_t value_data_offset           = 0;
230
2.64k
  uint16_t value_data_size             = 0;
231
2.64k
  int entry_index                      = 0;
232
233
2.64k
  if( btree_node == NULL )
234
0
  {
235
0
    libcerror_error_set(
236
0
     error,
237
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
238
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
239
0
     "%s: invalid B-tree node.",
240
0
     function );
241
242
0
    return( -1 );
243
0
  }
244
2.64k
  if( btree_node->node_header != NULL )
245
0
  {
246
0
    libcerror_error_set(
247
0
     error,
248
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
249
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
250
0
     "%s: invalid B-tree node - node header value already set.",
251
0
     function );
252
253
0
    return( -1 );
254
0
  }
255
2.64k
  if( data == NULL )
256
0
  {
257
0
    libcerror_error_set(
258
0
     error,
259
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
260
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
261
0
     "%s: invalid data.",
262
0
     function );
263
264
0
    return( -1 );
265
0
  }
266
2.64k
  minimum_data_size = sizeof( fsapfs_object_t ) + sizeof( fsapfs_btree_node_header_t ) + sizeof( fsapfs_btree_footer_t );
267
268
2.64k
  if( ( data_size < minimum_data_size )
269
2.64k
   || ( data_size > (size_t) SSIZE_MAX ) )
270
0
  {
271
0
    libcerror_error_set(
272
0
     error,
273
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
274
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
275
0
     "%s: invalid data size value out of bounds.",
276
0
     function );
277
278
0
    return( -1 );
279
0
  }
280
#if defined( HAVE_DEBUG_OUTPUT )
281
  if( libcnotify_verbose != 0 )
282
  {
283
    libcnotify_printf(
284
     "%s: B-tree node data:\n",
285
     function );
286
    libcnotify_print_data(
287
     data,
288
     data_size,
289
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
290
  }
291
#endif
292
2.64k
  if( libfsapfs_btree_node_read_object_data(
293
2.64k
       btree_node,
294
2.64k
       data,
295
2.64k
       data_size,
296
2.64k
       error ) != 1 )
297
110
  {
298
110
    libcerror_error_set(
299
110
     error,
300
110
     LIBCERROR_ERROR_DOMAIN_IO,
301
110
     LIBCERROR_IO_ERROR_READ_FAILED,
302
110
     "%s: unable to read B-tree node object data.",
303
110
     function );
304
305
110
    goto on_error;
306
110
  }
307
2.53k
  data_offset = sizeof( fsapfs_object_t );
308
309
2.53k
  if( libfsapfs_btree_node_header_initialize(
310
2.53k
       &( btree_node->node_header ),
311
2.53k
       error ) != 1 )
312
0
  {
313
0
    libcerror_error_set(
314
0
     error,
315
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
316
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
317
0
     "%s: unable to create B-tree node header.",
318
0
     function );
319
320
0
    goto on_error;
321
0
  }
322
2.53k
  if( libfsapfs_btree_node_header_read_data(
323
2.53k
       btree_node->node_header,
324
2.53k
       &( data[ data_offset ] ),
325
2.53k
       sizeof( fsapfs_btree_node_header_t ),
326
2.53k
       error ) != 1 )
327
0
  {
328
0
    libcerror_error_set(
329
0
     error,
330
0
     LIBCERROR_ERROR_DOMAIN_IO,
331
0
     LIBCERROR_IO_ERROR_READ_FAILED,
332
0
     "%s: unable to read B-tree node header.",
333
0
     function );
334
335
0
    goto on_error;
336
0
  }
337
2.53k
  data_offset += sizeof( fsapfs_btree_node_header_t );
338
339
2.53k
  remaining_data_size = data_size - minimum_data_size;
340
341
2.53k
  if( btree_node->node_header->entries_data_offset >= remaining_data_size )
342
5
  {
343
5
    libcerror_error_set(
344
5
     error,
345
5
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
346
5
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
347
5
     "%s: invalid entries offset size value out of bounds.",
348
5
     function );
349
350
5
    goto on_error;
351
5
  }
352
2.52k
  remaining_data_size -= btree_node->node_header->entries_data_offset;
353
354
2.52k
  if( btree_node->node_header->entries_data_size > remaining_data_size )
355
8
  {
356
8
    libcerror_error_set(
357
8
     error,
358
8
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
359
8
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
360
8
     "%s: invalid entries data size value out of bounds.",
361
8
     function );
362
363
8
    goto on_error;
364
8
  }
365
2.52k
  remaining_data_size -= btree_node->node_header->entries_data_size;
366
367
2.52k
  if( btree_node->node_header->unused_data_offset >= remaining_data_size )
368
10
  {
369
10
    libcerror_error_set(
370
10
     error,
371
10
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
372
10
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
373
10
     "%s: invalid unused offset size value out of bounds.",
374
10
     function );
375
376
10
    goto on_error;
377
10
  }
378
379
/* TODO this check fails on some container
380
  remaining_data_size -= btree_node->node_header->unused_data_offset;
381
382
  if( btree_node->node_header->unused_data_size > remaining_data_size )
383
  {
384
    libcerror_error_set(
385
     error,
386
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
387
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
388
     "%s: invalid unused data size value out of bounds.",
389
     function );
390
391
    goto on_error;
392
  }
393
*/
394
/* TODO sanity check other data_offset and data_size values */
395
396
2.51k
  footer_offset = (uint16_t) data_size;
397
398
2.51k
  if( ( btree_node->node_header->flags & 0x0001 ) != 0 )
399
2.28k
  {
400
2.28k
    if( libfsapfs_btree_footer_initialize(
401
2.28k
         &( btree_node->footer ),
402
2.28k
         error ) != 1 )
403
0
    {
404
0
      libcerror_error_set(
405
0
       error,
406
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
407
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
408
0
       "%s: unable to create B-tree footer.",
409
0
       function );
410
411
0
      goto on_error;
412
0
    }
413
2.28k
    if( libfsapfs_btree_footer_read_data(
414
2.28k
         btree_node->footer,
415
2.28k
         &( data[ data_size - sizeof( fsapfs_btree_footer_t ) ] ),
416
2.28k
         sizeof( fsapfs_btree_footer_t ),
417
2.28k
         error ) != 1 )
418
0
    {
419
0
      libcerror_error_set(
420
0
       error,
421
0
       LIBCERROR_ERROR_DOMAIN_IO,
422
0
       LIBCERROR_IO_ERROR_READ_FAILED,
423
0
       "%s: unable to read B-tree footer.",
424
0
       function );
425
426
0
      goto on_error;
427
0
    }
428
2.28k
    footer_offset -= (uint16_t) sizeof( fsapfs_btree_footer_t );
429
2.28k
  }
430
2.51k
  if( ( btree_node->node_header->flags & 0x0004 ) == 0 )
431
742
  {
432
742
    btree_entry_data_size = sizeof( fsapfs_btree_variable_size_entry_t );
433
742
  }
434
1.76k
  else
435
1.76k
  {
436
1.76k
    btree_entry_data_size = sizeof( fsapfs_btree_fixed_size_entry_t );
437
1.76k
  }
438
2.51k
  if( (size_t) btree_node->node_header->number_of_keys > (size_t) ( btree_node->node_header->entries_data_size / btree_entry_data_size ) )
439
26
  {
440
26
    libcerror_error_set(
441
26
     error,
442
26
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
443
26
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
444
26
     "%s: invalid number of keys value out of bounds.",
445
26
     function );
446
447
26
    goto on_error;
448
26
  }
449
2.48k
  data_offset += btree_node->node_header->entries_data_offset;
450
451
2.48k
  entries_data_offset = btree_node->node_header->entries_data_offset + (uint16_t) ( sizeof( fsapfs_object_t ) + sizeof( fsapfs_btree_node_header_t ) );
452
453
2.48k
  for( map_entry_index = 0;
454
24.7k
       map_entry_index < btree_node->node_header->number_of_keys;
455
22.2k
       map_entry_index++ )
456
22.3k
  {
457
22.3k
    btree_node_entry = &( data[ data_offset ] );
458
459
22.3k
    if( ( btree_node->node_header->flags & 0x0004 ) == 0 )
460
9.10k
    {
461
9.10k
      byte_stream_copy_to_uint16_little_endian(
462
9.10k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->key_data_offset,
463
9.10k
       key_data_offset );
464
465
9.10k
      byte_stream_copy_to_uint16_little_endian(
466
9.10k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->key_data_size,
467
9.10k
       key_data_size );
468
469
9.10k
      byte_stream_copy_to_uint16_little_endian(
470
9.10k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->value_data_offset,
471
9.10k
       value_data_offset );
472
473
9.10k
      byte_stream_copy_to_uint16_little_endian(
474
9.10k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->value_data_size,
475
9.10k
       value_data_size );
476
9.10k
    }
477
13.2k
    else
478
13.2k
    {
479
13.2k
      byte_stream_copy_to_uint16_little_endian(
480
13.2k
       ( (fsapfs_btree_fixed_size_entry_t *) btree_node_entry )->key_data_offset,
481
13.2k
       key_data_offset );
482
483
13.2k
      byte_stream_copy_to_uint16_little_endian(
484
13.2k
       ( (fsapfs_btree_fixed_size_entry_t *) btree_node_entry )->value_data_offset,
485
13.2k
       value_data_offset );
486
487
13.2k
      switch( btree_node->object_subtype )
488
13.2k
      {
489
13.2k
        case 0x0000000bUL:
490
13.2k
          key_data_size   = (uint16_t) sizeof( fsapfs_object_map_btree_key_t );
491
13.2k
          value_data_size = (uint16_t) sizeof( fsapfs_object_map_btree_value_t );
492
13.2k
          break;
493
494
7
        default:
495
7
          libcerror_error_set(
496
7
           error,
497
7
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
498
7
           LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
499
7
           "%s: invalid object subtype: 0x%08" PRIx32 ".",
500
7
           function,
501
7
           btree_node->object_subtype );
502
503
7
          goto on_error;
504
13.2k
      }
505
13.2k
      if( ( btree_node->node_header->flags & 0x0002 ) == 0 )
506
5.50k
      {
507
5.50k
        value_data_size = 8;
508
5.50k
      }
509
13.2k
    }
510
#if defined( HAVE_DEBUG_OUTPUT )
511
    if( libcnotify_verbose != 0 )
512
    {
513
      libcnotify_printf(
514
       "%s: entry: %03" PRIu16 " key data offset\t\t: 0x%04" PRIx16 " (block offset: 0x%04" PRIzx ")\n",
515
       function,
516
       map_entry_index,
517
       key_data_offset,
518
       (size_t) key_data_offset + (size_t) entries_data_offset + (size_t) btree_node->node_header->entries_data_size );
519
520
      libcnotify_printf(
521
       "%s: entry: %03" PRIu16 " key data size\t\t: %" PRIu16 "\n",
522
       function,
523
       map_entry_index,
524
       key_data_size );
525
526
      libcnotify_printf(
527
       "%s: entry: %03" PRIu16 " value data offset\t\t: 0x%04" PRIx16 " (block offset: 0x%04" PRIzx ")\n",
528
       function,
529
       map_entry_index,
530
       value_data_offset,
531
       (size_t) footer_offset - (size_t) value_data_offset);
532
533
      libcnotify_printf(
534
       "%s: entry: %03" PRIu16 " value data size\t\t: %" PRIu16 "\n",
535
       function,
536
       map_entry_index,
537
       value_data_size );
538
539
      libcnotify_printf(
540
       "\n" );
541
    }
542
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
543
544
22.3k
    data_offset += btree_entry_data_size;
545
546
22.3k
    key_data_offset += entries_data_offset + btree_node->node_header->entries_data_size;
547
548
22.3k
    if( ( (size_t) key_data_offset > data_size )
549
22.3k
     || ( (size_t) key_data_size > ( data_size - key_data_offset ) ) )
550
37
    {
551
37
      libcerror_error_set(
552
37
       error,
553
37
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
554
37
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
555
37
       "%s: invalid key data offset value out of bounds.",
556
37
       function );
557
558
37
      goto on_error;
559
37
    }
560
#if defined( HAVE_DEBUG_OUTPUT )
561
    if( libcnotify_verbose != 0 )
562
    {
563
      libcnotify_printf(
564
       "%s: entry: %03" PRIu16 " key data:\n",
565
       function,
566
       map_entry_index );
567
      libcnotify_print_data(
568
       &( data[ key_data_offset ] ),
569
       (size_t) key_data_size,
570
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
571
    }
572
#endif
573
22.3k
    value_data_offset = footer_offset - value_data_offset;
574
575
22.3k
    if( ( (size_t) value_data_offset > data_size )
576
22.3k
     || ( (size_t) value_data_size > ( data_size - value_data_offset ) ) )
577
42
    {
578
42
      libcerror_error_set(
579
42
       error,
580
42
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
581
42
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
582
42
       "%s: invalid value data offset value out of bounds.",
583
42
       function );
584
585
42
      goto on_error;
586
42
    }
587
#if defined( HAVE_DEBUG_OUTPUT )
588
    if( libcnotify_verbose != 0 )
589
    {
590
      libcnotify_printf(
591
       "%s: entry: %03" PRIu16 " value data:\n",
592
       function,
593
       map_entry_index );
594
      libcnotify_print_data(
595
       &( data[ value_data_offset ] ),
596
       (size_t) value_data_size,
597
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
598
    }
599
#endif
600
22.2k
    if( libfsapfs_btree_entry_initialize(
601
22.2k
         &btree_entry,
602
22.2k
         error ) != 1 )
603
0
    {
604
0
      libcerror_error_set(
605
0
       error,
606
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
607
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
608
0
       "%s: unable to create B-tree entry.",
609
0
       function );
610
611
0
      goto on_error;
612
0
    }
613
22.2k
    if( libfsapfs_btree_entry_set_key_data(
614
22.2k
         btree_entry,
615
22.2k
         &( data[ key_data_offset ] ),
616
22.2k
         (size_t) key_data_size,
617
22.2k
         error ) != 1 )
618
0
    {
619
0
      libcerror_error_set(
620
0
       error,
621
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
622
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
623
0
       "%s: unable to set key data in B-tree entry.",
624
0
       function );
625
626
0
      goto on_error;
627
0
    }
628
22.2k
    if( libfsapfs_btree_entry_set_value_data(
629
22.2k
         btree_entry,
630
22.2k
         &( data[ value_data_offset ] ),
631
22.2k
         (size_t) value_data_size,
632
22.2k
         error ) != 1 )
633
0
    {
634
0
      libcerror_error_set(
635
0
       error,
636
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
637
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
638
0
       "%s: unable to set value data in B-tree entry.",
639
0
       function );
640
641
0
      goto on_error;
642
0
    }
643
22.2k
    if( libcdata_array_append_entry(
644
22.2k
         btree_node->entries_array,
645
22.2k
         &entry_index,
646
22.2k
         (intptr_t *) btree_entry,
647
22.2k
         error ) != 1 )
648
0
    {
649
0
      libcerror_error_set(
650
0
       error,
651
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
652
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
653
0
       "%s: unable to append B-tree entry: %" PRIu32 " to array.",
654
0
       function,
655
0
       map_entry_index );
656
657
0
      goto on_error;
658
0
    }
659
22.2k
    btree_entry = NULL;
660
22.2k
  }
661
2.39k
  return( 1 );
662
663
245
on_error:
664
245
  if( btree_entry != NULL )
665
0
  {
666
0
    libfsapfs_btree_entry_free(
667
0
     &btree_entry,
668
0
     NULL );
669
0
  }
670
245
  if( btree_node->footer != NULL )
671
57
  {
672
57
    libfsapfs_btree_footer_free(
673
57
     &( btree_node->footer ),
674
57
     NULL );
675
57
  }
676
245
  if( btree_node->node_header != NULL )
677
135
  {
678
135
    libfsapfs_btree_node_header_free(
679
135
     &( btree_node->node_header ),
680
135
     NULL );
681
135
  }
682
245
  return( -1 );
683
2.48k
}
684
685
/* Reads the B-tree node object
686
 * Returns 1 if successful or -1 on error
687
 */
688
int libfsapfs_btree_node_read_object_data(
689
     libfsapfs_btree_node_t *btree_node,
690
     const uint8_t *data,
691
     size_t data_size,
692
     libcerror_error_t **error )
693
2.64k
{
694
2.64k
  static char *function = "libfsapfs_btree_node_read_object_data";
695
2.64k
  uint32_t object_type  = 0;
696
697
#if defined( HAVE_DEBUG_OUTPUT )
698
  uint64_t value_64bit  = 0;
699
#endif
700
701
2.64k
  if( btree_node == NULL )
702
0
  {
703
0
    libcerror_error_set(
704
0
     error,
705
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
706
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
707
0
     "%s: invalid B-tree node.",
708
0
     function );
709
710
0
    return( -1 );
711
0
  }
712
2.64k
  if( data == NULL )
713
0
  {
714
0
    libcerror_error_set(
715
0
     error,
716
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
717
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
718
0
     "%s: invalid data.",
719
0
     function );
720
721
0
    return( -1 );
722
0
  }
723
2.64k
  if( ( data_size < sizeof( fsapfs_object_t ) )
724
2.64k
   || ( data_size > (size_t) SSIZE_MAX ) )
725
0
  {
726
0
    libcerror_error_set(
727
0
     error,
728
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
729
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
730
0
     "%s: invalid data size value out of bounds.",
731
0
     function );
732
733
0
    return( -1 );
734
0
  }
735
#if defined( HAVE_DEBUG_OUTPUT )
736
  if( libcnotify_verbose != 0 )
737
  {
738
    libcnotify_printf(
739
     "%s: B-tree node object data:\n",
740
     function );
741
    libcnotify_print_data(
742
     data,
743
     sizeof( fsapfs_object_t ),
744
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
745
  }
746
#endif
747
2.64k
  byte_stream_copy_to_uint32_little_endian(
748
2.64k
   ( (fsapfs_object_t *) data )->type,
749
2.64k
   btree_node->object_type );
750
751
2.64k
  object_type = btree_node->object_type & 0x0ffffffUL;
752
753
2.64k
  if( ( object_type != 0x00000000UL )
754
2.48k
   && ( object_type != 0x00000002UL )
755
209
   && ( object_type != 0x00000003UL ) )
756
110
  {
757
110
    libcerror_error_set(
758
110
     error,
759
110
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
760
110
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
761
110
     "%s: invalid object type: 0x%08" PRIx32 ".",
762
110
     function,
763
110
     btree_node->object_type );
764
765
110
    return( -1 );
766
110
  }
767
2.53k
  byte_stream_copy_to_uint32_little_endian(
768
2.53k
   ( (fsapfs_object_t *) data )->subtype,
769
2.53k
   btree_node->object_subtype );
770
771
#if defined( HAVE_DEBUG_OUTPUT )
772
  if( libcnotify_verbose != 0 )
773
  {
774
    byte_stream_copy_to_uint64_little_endian(
775
     ( (fsapfs_object_t *) data )->checksum,
776
     value_64bit );
777
    libcnotify_printf(
778
     "%s: object checksum\t\t\t: 0x%08" PRIx64 "\n",
779
     function,
780
     value_64bit );
781
782
    byte_stream_copy_to_uint64_little_endian(
783
     ( (fsapfs_object_t *) data )->identifier,
784
     value_64bit );
785
    libcnotify_printf(
786
     "%s: object identifier\t\t: %" PRIu64 "\n",
787
     function,
788
     value_64bit );
789
790
    byte_stream_copy_to_uint64_little_endian(
791
     ( (fsapfs_object_t *) data )->transaction_identifier,
792
     value_64bit );
793
    libcnotify_printf(
794
     "%s: object transaction identifier\t: %" PRIu64 "\n",
795
     function,
796
     value_64bit );
797
798
    libcnotify_printf(
799
     "%s: object type\t\t\t: 0x%08" PRIx32 "\n",
800
     function,
801
     btree_node->object_type );
802
803
    libcnotify_printf(
804
     "%s: object subtype\t\t\t: 0x%08" PRIx32 "\n",
805
     function,
806
     btree_node->object_subtype );
807
808
    libcnotify_printf(
809
     "\n" );
810
  }
811
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
812
813
2.53k
  return( 1 );
814
2.64k
}
815
816
/* Determines if the node is a leaf node
817
 * Returns 1 if the node is a leaf node, 0 if not or -1 on error
818
 */
819
int libfsapfs_btree_node_is_leaf_node(
820
     libfsapfs_btree_node_t *btree_node,
821
     libcerror_error_t **error )
822
6.88k
{
823
6.88k
  static char *function = "libfsapfs_btree_node_is_leaf_node";
824
825
6.88k
  if( btree_node == NULL )
826
0
  {
827
0
    libcerror_error_set(
828
0
     error,
829
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
830
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
831
0
     "%s: invalid B-tree node.",
832
0
     function );
833
834
0
    return( -1 );
835
0
  }
836
6.88k
  if( btree_node->node_header == NULL )
837
0
  {
838
0
    libcerror_error_set(
839
0
     error,
840
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
841
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
842
0
     "%s: invalid B-tree node - missing node header.",
843
0
     function );
844
845
0
    return( -1 );
846
0
  }
847
6.88k
  return( btree_node->node_header->flags & 0x0002 );
848
6.88k
}
849
850
/* Retrieves the number of B-tree entries
851
 * Returns 1 if successful or -1 on error
852
 */
853
int libfsapfs_btree_node_get_number_of_entries(
854
     libfsapfs_btree_node_t *btree_node,
855
     int *number_of_entries,
856
     libcerror_error_t **error )
857
3.44k
{
858
3.44k
  static char *function = "libfsapfs_btree_node_get_number_of_entries";
859
860
3.44k
  if( btree_node == NULL )
861
0
  {
862
0
    libcerror_error_set(
863
0
     error,
864
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
865
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
866
0
     "%s: invalid B-tree node.",
867
0
     function );
868
869
0
    return( -1 );
870
0
  }
871
3.44k
  if( libcdata_array_get_number_of_entries(
872
3.44k
       btree_node->entries_array,
873
3.44k
       number_of_entries,
874
3.44k
       error ) != 1 )
875
0
  {
876
0
    libcerror_error_set(
877
0
     error,
878
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
879
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
880
0
     "%s: unable to retrieve number of entries from array.",
881
0
     function );
882
883
0
    return( -1 );
884
0
  }
885
3.44k
  return( 1 );
886
3.44k
}
887
888
/* Retrieves a specific of B-tree entry
889
 * Returns 1 if successful or -1 on error
890
 */
891
int libfsapfs_btree_node_get_entry_by_index(
892
     libfsapfs_btree_node_t *btree_node,
893
     int entry_index,
894
     libfsapfs_btree_entry_t **btree_entry,
895
     libcerror_error_t **error )
896
11.8k
{
897
11.8k
  static char *function = "libfsapfs_btree_node_get_entry_by_index";
898
899
11.8k
  if( btree_node == NULL )
900
0
  {
901
0
    libcerror_error_set(
902
0
     error,
903
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
904
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
905
0
     "%s: invalid B-tree node.",
906
0
     function );
907
908
0
    return( -1 );
909
0
  }
910
11.8k
  if( libcdata_array_get_entry_by_index(
911
11.8k
       btree_node->entries_array,
912
11.8k
       entry_index,
913
11.8k
       (intptr_t **) btree_entry,
914
11.8k
       error ) != 1 )
915
0
  {
916
0
    libcerror_error_set(
917
0
     error,
918
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
919
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
920
0
     "%s: unable to retrieve entry: %d from array.",
921
0
     function,
922
0
     entry_index );
923
924
0
    return( -1 );
925
0
  }
926
11.8k
  return( 1 );
927
11.8k
}
928