Coverage Report

Created: 2025-09-05 06:58

/src/libfsapfs/libfsapfs/libfsapfs_btree_node.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The B-tree node functions
3
 *
4
 * Copyright (C) 2018-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 "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
10.8k
{
47
10.8k
  static char *function = "libfsapfs_btree_node_initialize";
48
49
10.8k
  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
10.8k
  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
10.8k
  *btree_node = memory_allocate_structure(
72
10.8k
                 libfsapfs_btree_node_t );
73
74
10.8k
  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
10.8k
  if( memory_set(
86
10.8k
       *btree_node,
87
10.8k
       0,
88
10.8k
       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
10.8k
  if( libcdata_array_initialize(
105
10.8k
       &( ( *btree_node )->entries_array ),
106
10.8k
       0,
107
10.8k
       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
10.8k
  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
10.8k
}
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
10.8k
{
138
10.8k
  static char *function = "libfsapfs_btree_node_free";
139
10.8k
  int result            = 1;
140
141
10.8k
  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
10.8k
  if( *btree_node != NULL )
153
10.8k
  {
154
10.8k
    if( ( *btree_node )->node_header != NULL )
155
10.3k
    {
156
10.3k
      if( libfsapfs_btree_node_header_free(
157
10.3k
           &( ( *btree_node )->node_header ),
158
10.3k
           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
10.3k
    }
170
10.8k
    if( ( *btree_node )->footer != NULL )
171
10.0k
    {
172
10.0k
      if( libfsapfs_btree_footer_free(
173
10.0k
           &( ( *btree_node )->footer ),
174
10.0k
           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
10.0k
    }
186
10.8k
    if( libcdata_array_free(
187
10.8k
         &( ( *btree_node )->entries_array ),
188
10.8k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_entry_free,
189
10.8k
         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
10.8k
    memory_free(
201
10.8k
     *btree_node );
202
203
10.8k
    *btree_node = NULL;
204
10.8k
  }
205
10.8k
  return( result );
206
10.8k
}
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
10.8k
{
217
10.8k
  libfsapfs_btree_entry_t *btree_entry = NULL;
218
10.8k
  const uint8_t *btree_node_entry      = NULL;
219
10.8k
  static char *function                = "libfsapfs_btree_node_read_data";
220
10.8k
  size_t btree_entry_data_size         = 0;
221
10.8k
  size_t data_offset                   = 0;
222
10.8k
  size_t minimum_data_size             = 0;
223
10.8k
  size_t remaining_data_size           = 0;
224
10.8k
  uint16_t entries_data_offset         = 0;
225
10.8k
  uint16_t footer_offset               = 0;
226
10.8k
  uint16_t key_data_offset             = 0;
227
10.8k
  uint16_t key_data_size               = 0;
228
10.8k
  uint16_t map_entry_index             = 0;
229
10.8k
  uint16_t value_data_offset           = 0;
230
10.8k
  uint16_t value_data_size             = 0;
231
10.8k
  int entry_index                      = 0;
232
233
10.8k
  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
10.8k
  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
10.8k
  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
10.8k
  minimum_data_size = sizeof( fsapfs_object_t ) + sizeof( fsapfs_btree_node_header_t ) + sizeof( fsapfs_btree_footer_t );
267
268
10.8k
  if( ( data_size < minimum_data_size )
269
10.8k
   || ( 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
10.8k
  if( libfsapfs_btree_node_read_object_data(
293
10.8k
       btree_node,
294
10.8k
       data,
295
10.8k
       data_size,
296
10.8k
       error ) != 1 )
297
161
  {
298
161
    libcerror_error_set(
299
161
     error,
300
161
     LIBCERROR_ERROR_DOMAIN_IO,
301
161
     LIBCERROR_IO_ERROR_READ_FAILED,
302
161
     "%s: unable to read B-tree node object data.",
303
161
     function );
304
305
161
    goto on_error;
306
161
  }
307
10.7k
  data_offset = sizeof( fsapfs_object_t );
308
309
10.7k
  if( libfsapfs_btree_node_header_initialize(
310
10.7k
       &( btree_node->node_header ),
311
10.7k
       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
10.7k
  if( libfsapfs_btree_node_header_read_data(
323
10.7k
       btree_node->node_header,
324
10.7k
       &( data[ data_offset ] ),
325
10.7k
       sizeof( fsapfs_btree_node_header_t ),
326
10.7k
       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
10.7k
  data_offset += sizeof( fsapfs_btree_node_header_t );
338
339
10.7k
  remaining_data_size = data_size - minimum_data_size;
340
341
10.7k
  if( btree_node->node_header->entries_data_offset >= remaining_data_size )
342
14
  {
343
14
    libcerror_error_set(
344
14
     error,
345
14
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
346
14
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
347
14
     "%s: invalid entries offset size value out of bounds.",
348
14
     function );
349
350
14
    goto on_error;
351
14
  }
352
10.7k
  remaining_data_size -= btree_node->node_header->entries_data_offset;
353
354
10.7k
  if( btree_node->node_header->entries_data_size > remaining_data_size )
355
13
  {
356
13
    libcerror_error_set(
357
13
     error,
358
13
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
359
13
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
360
13
     "%s: invalid entries data size value out of bounds.",
361
13
     function );
362
363
13
    goto on_error;
364
13
  }
365
10.6k
  remaining_data_size -= btree_node->node_header->entries_data_size;
366
367
10.6k
  if( btree_node->node_header->unused_data_offset >= remaining_data_size )
368
23
  {
369
23
    libcerror_error_set(
370
23
     error,
371
23
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
372
23
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
373
23
     "%s: invalid unused offset size value out of bounds.",
374
23
     function );
375
376
23
    goto on_error;
377
23
  }
378
10.6k
  remaining_data_size -= btree_node->node_header->unused_data_offset;
379
380
/* TODO this check fails on some container
381
  if( btree_node->node_header->unused_data_size > remaining_data_size )
382
  {
383
    libcerror_error_set(
384
     error,
385
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
386
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
387
     "%s: invalid unused data size value out of bounds.",
388
     function );
389
390
    goto on_error;
391
  }
392
*/
393
/* TODO sanity check other data_offset and data_size values */
394
395
10.6k
  footer_offset = (uint16_t) data_size;
396
397
10.6k
  if( ( btree_node->node_header->flags & 0x0001 ) != 0 )
398
10.2k
  {
399
10.2k
    if( libfsapfs_btree_footer_initialize(
400
10.2k
         &( btree_node->footer ),
401
10.2k
         error ) != 1 )
402
0
    {
403
0
      libcerror_error_set(
404
0
       error,
405
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
406
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
407
0
       "%s: unable to create B-tree footer.",
408
0
       function );
409
410
0
      goto on_error;
411
0
    }
412
10.2k
    if( libfsapfs_btree_footer_read_data(
413
10.2k
         btree_node->footer,
414
10.2k
         &( data[ data_size - sizeof( fsapfs_btree_footer_t ) ] ),
415
10.2k
         sizeof( fsapfs_btree_footer_t ),
416
10.2k
         error ) != 1 )
417
0
    {
418
0
      libcerror_error_set(
419
0
       error,
420
0
       LIBCERROR_ERROR_DOMAIN_IO,
421
0
       LIBCERROR_IO_ERROR_READ_FAILED,
422
0
       "%s: unable to read B-tree footer.",
423
0
       function );
424
425
0
      goto on_error;
426
0
    }
427
10.2k
    footer_offset -= (uint16_t) sizeof( fsapfs_btree_footer_t );
428
10.2k
  }
429
10.6k
  if( ( btree_node->node_header->flags & 0x0004 ) == 0 )
430
3.92k
  {
431
3.92k
    btree_entry_data_size = sizeof( fsapfs_btree_variable_size_entry_t );
432
3.92k
  }
433
6.74k
  else
434
6.74k
  {
435
6.74k
    btree_entry_data_size = sizeof( fsapfs_btree_fixed_size_entry_t );
436
6.74k
  }
437
10.6k
  if( (size_t) btree_node->node_header->number_of_keys > (size_t) ( btree_node->node_header->entries_data_size / btree_entry_data_size ) )
438
39
  {
439
39
    libcerror_error_set(
440
39
     error,
441
39
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
442
39
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
443
39
     "%s: invalid number of keys value out of bounds.",
444
39
     function );
445
446
39
    goto on_error;
447
39
  }
448
10.6k
  data_offset += btree_node->node_header->entries_data_offset;
449
450
10.6k
  entries_data_offset = btree_node->node_header->entries_data_offset + (uint16_t) ( sizeof( fsapfs_object_t ) + sizeof( fsapfs_btree_node_header_t ) );
451
452
10.6k
  for( map_entry_index = 0;
453
81.1k
       map_entry_index < btree_node->node_header->number_of_keys;
454
70.4k
       map_entry_index++ )
455
70.7k
  {
456
70.7k
    btree_node_entry = &( data[ data_offset ] );
457
458
70.7k
    if( ( btree_node->node_header->flags & 0x0004 ) == 0 )
459
42.8k
    {
460
42.8k
      byte_stream_copy_to_uint16_little_endian(
461
42.8k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->key_data_offset,
462
42.8k
       key_data_offset );
463
464
42.8k
      byte_stream_copy_to_uint16_little_endian(
465
42.8k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->key_data_size,
466
42.8k
       key_data_size );
467
468
42.8k
      byte_stream_copy_to_uint16_little_endian(
469
42.8k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->value_data_offset,
470
42.8k
       value_data_offset );
471
472
42.8k
      byte_stream_copy_to_uint16_little_endian(
473
42.8k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->value_data_size,
474
42.8k
       value_data_size );
475
42.8k
    }
476
27.9k
    else
477
27.9k
    {
478
27.9k
      byte_stream_copy_to_uint16_little_endian(
479
27.9k
       ( (fsapfs_btree_fixed_size_entry_t *) btree_node_entry )->key_data_offset,
480
27.9k
       key_data_offset );
481
482
27.9k
      byte_stream_copy_to_uint16_little_endian(
483
27.9k
       ( (fsapfs_btree_fixed_size_entry_t *) btree_node_entry )->value_data_offset,
484
27.9k
       value_data_offset );
485
486
27.9k
      switch( btree_node->object_subtype )
487
27.9k
      {
488
27.8k
        case 0x0000000bUL:
489
27.8k
          key_data_size   = (uint16_t) sizeof( fsapfs_object_map_btree_key_t );
490
27.8k
          value_data_size = (uint16_t) sizeof( fsapfs_object_map_btree_value_t );
491
27.8k
          break;
492
493
105
        default:
494
105
          libcerror_error_set(
495
105
           error,
496
105
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
497
105
           LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
498
105
           "%s: invalid object subtype: 0x%08" PRIx32 ".",
499
105
           function,
500
105
           btree_node->object_subtype );
501
502
105
          goto on_error;
503
27.9k
      }
504
27.8k
      if( ( btree_node->node_header->flags & 0x0002 ) == 0 )
505
12.4k
      {
506
12.4k
        value_data_size = 8;
507
12.4k
      }
508
27.8k
    }
509
#if defined( HAVE_DEBUG_OUTPUT )
510
    if( libcnotify_verbose != 0 )
511
    {
512
      libcnotify_printf(
513
       "%s: entry: %03" PRIu16 " key data offset\t\t: 0x%04" PRIx16 " (block offset: 0x%04" PRIzx ")\n",
514
       function,
515
       map_entry_index,
516
       key_data_offset,
517
       (size_t) key_data_offset + (size_t) entries_data_offset + (size_t) btree_node->node_header->entries_data_size );
518
519
      libcnotify_printf(
520
       "%s: entry: %03" PRIu16 " key data size\t\t: %" PRIu16 "\n",
521
       function,
522
       map_entry_index,
523
       key_data_size );
524
525
      libcnotify_printf(
526
       "%s: entry: %03" PRIu16 " value data offset\t\t: 0x%04" PRIx16 " (block offset: 0x%04" PRIzx ")\n",
527
       function,
528
       map_entry_index,
529
       value_data_offset,
530
       (size_t) footer_offset - (size_t) value_data_offset);
531
532
      libcnotify_printf(
533
       "%s: entry: %03" PRIu16 " value data size\t\t: %" PRIu16 "\n",
534
       function,
535
       map_entry_index,
536
       value_data_size );
537
538
      libcnotify_printf(
539
       "\n" );
540
    }
541
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
542
543
70.6k
    data_offset += btree_entry_data_size;
544
545
70.6k
    key_data_offset += entries_data_offset + btree_node->node_header->entries_data_size;
546
547
70.6k
    if( ( (size_t) key_data_offset > data_size )
548
70.6k
     || ( (size_t) key_data_size > ( data_size - key_data_offset ) ) )
549
73
    {
550
73
      libcerror_error_set(
551
73
       error,
552
73
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
553
73
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
554
73
       "%s: invalid key data offset value out of bounds.",
555
73
       function );
556
557
73
      goto on_error;
558
73
    }
559
#if defined( HAVE_DEBUG_OUTPUT )
560
    if( libcnotify_verbose != 0 )
561
    {
562
      libcnotify_printf(
563
       "%s: entry: %03" PRIu16 " key data:\n",
564
       function,
565
       map_entry_index );
566
      libcnotify_print_data(
567
       &( data[ key_data_offset ] ),
568
       (size_t) key_data_size,
569
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
570
    }
571
#endif
572
70.5k
    value_data_offset = footer_offset - value_data_offset;
573
574
70.5k
    if( ( (size_t) value_data_offset > data_size )
575
70.5k
     || ( (size_t) value_data_size > ( data_size - value_data_offset ) ) )
576
94
    {
577
94
      libcerror_error_set(
578
94
       error,
579
94
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
580
94
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
581
94
       "%s: invalid value data offset value out of bounds.",
582
94
       function );
583
584
94
      goto on_error;
585
94
    }
586
#if defined( HAVE_DEBUG_OUTPUT )
587
    if( libcnotify_verbose != 0 )
588
    {
589
      libcnotify_printf(
590
       "%s: entry: %03" PRIu16 " value data:\n",
591
       function,
592
       map_entry_index );
593
      libcnotify_print_data(
594
       &( data[ value_data_offset ] ),
595
       (size_t) value_data_size,
596
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
597
    }
598
#endif
599
70.4k
    if( libfsapfs_btree_entry_initialize(
600
70.4k
         &btree_entry,
601
70.4k
         error ) != 1 )
602
0
    {
603
0
      libcerror_error_set(
604
0
       error,
605
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
606
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
607
0
       "%s: unable to create B-tree entry.",
608
0
       function );
609
610
0
      goto on_error;
611
0
    }
612
70.4k
    if( libfsapfs_btree_entry_set_key_data(
613
70.4k
         btree_entry,
614
70.4k
         &( data[ key_data_offset ] ),
615
70.4k
         (size_t) key_data_size,
616
70.4k
         error ) != 1 )
617
0
    {
618
0
      libcerror_error_set(
619
0
       error,
620
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
621
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
622
0
       "%s: unable to set key data in B-tree entry.",
623
0
       function );
624
625
0
      goto on_error;
626
0
    }
627
70.4k
    if( libfsapfs_btree_entry_set_value_data(
628
70.4k
         btree_entry,
629
70.4k
         &( data[ value_data_offset ] ),
630
70.4k
         (size_t) value_data_size,
631
70.4k
         error ) != 1 )
632
0
    {
633
0
      libcerror_error_set(
634
0
       error,
635
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
636
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
637
0
       "%s: unable to set value data in B-tree entry.",
638
0
       function );
639
640
0
      goto on_error;
641
0
    }
642
70.4k
    if( libcdata_array_append_entry(
643
70.4k
         btree_node->entries_array,
644
70.4k
         &entry_index,
645
70.4k
         (intptr_t *) btree_entry,
646
70.4k
         error ) != 1 )
647
0
    {
648
0
      libcerror_error_set(
649
0
       error,
650
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
651
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
652
0
       "%s: unable to append B-tree entry: %" PRIu32 " to array.",
653
0
       function,
654
0
       map_entry_index );
655
656
0
      goto on_error;
657
0
    }
658
70.4k
    btree_entry = NULL;
659
70.4k
  }
660
10.3k
  return( 1 );
661
662
522
on_error:
663
522
  if( btree_entry != NULL )
664
0
  {
665
0
    libfsapfs_btree_entry_free(
666
0
     &btree_entry,
667
0
     NULL );
668
0
  }
669
522
  if( btree_node->footer != NULL )
670
166
  {
671
166
    libfsapfs_btree_footer_free(
672
166
     &( btree_node->footer ),
673
166
     NULL );
674
166
  }
675
522
  if( btree_node->node_header != NULL )
676
361
  {
677
361
    libfsapfs_btree_node_header_free(
678
361
     &( btree_node->node_header ),
679
361
     NULL );
680
361
  }
681
522
  return( -1 );
682
10.6k
}
683
684
/* Reads the B-tree node object
685
 * Returns 1 if successful or -1 on error
686
 */
687
int libfsapfs_btree_node_read_object_data(
688
     libfsapfs_btree_node_t *btree_node,
689
     const uint8_t *data,
690
     size_t data_size,
691
     libcerror_error_t **error )
692
10.8k
{
693
10.8k
  static char *function = "libfsapfs_btree_node_read_object_data";
694
10.8k
  uint32_t object_type  = 0;
695
696
#if defined( HAVE_DEBUG_OUTPUT )
697
  uint64_t value_64bit  = 0;
698
#endif
699
700
10.8k
  if( btree_node == NULL )
701
0
  {
702
0
    libcerror_error_set(
703
0
     error,
704
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
705
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
706
0
     "%s: invalid B-tree node.",
707
0
     function );
708
709
0
    return( -1 );
710
0
  }
711
10.8k
  if( data == NULL )
712
0
  {
713
0
    libcerror_error_set(
714
0
     error,
715
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
716
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
717
0
     "%s: invalid data.",
718
0
     function );
719
720
0
    return( -1 );
721
0
  }
722
10.8k
  if( ( data_size < sizeof( fsapfs_object_t ) )
723
10.8k
   || ( data_size > (size_t) SSIZE_MAX ) )
724
0
  {
725
0
    libcerror_error_set(
726
0
     error,
727
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
728
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
729
0
     "%s: invalid data size value out of bounds.",
730
0
     function );
731
732
0
    return( -1 );
733
0
  }
734
#if defined( HAVE_DEBUG_OUTPUT )
735
  if( libcnotify_verbose != 0 )
736
  {
737
    libcnotify_printf(
738
     "%s: B-tree node object data:\n",
739
     function );
740
    libcnotify_print_data(
741
     data,
742
     sizeof( fsapfs_object_t ),
743
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
744
  }
745
#endif
746
10.8k
  byte_stream_copy_to_uint32_little_endian(
747
10.8k
   ( (fsapfs_object_t *) data )->type,
748
10.8k
   btree_node->object_type );
749
750
10.8k
  object_type = btree_node->object_type & 0x0ffffffUL;
751
752
10.8k
  if( ( object_type != 0x00000000UL )
753
10.8k
   && ( object_type != 0x00000002UL )
754
10.8k
   && ( object_type != 0x00000003UL ) )
755
161
  {
756
161
    libcerror_error_set(
757
161
     error,
758
161
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
759
161
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
760
161
     "%s: invalid object type: 0x%08" PRIx32 ".",
761
161
     function,
762
161
     btree_node->object_type );
763
764
161
    return( -1 );
765
161
  }
766
10.7k
  byte_stream_copy_to_uint32_little_endian(
767
10.7k
   ( (fsapfs_object_t *) data )->subtype,
768
10.7k
   btree_node->object_subtype );
769
770
#if defined( HAVE_DEBUG_OUTPUT )
771
  if( libcnotify_verbose != 0 )
772
  {
773
    byte_stream_copy_to_uint64_little_endian(
774
     ( (fsapfs_object_t *) data )->checksum,
775
     value_64bit );
776
    libcnotify_printf(
777
     "%s: object checksum\t\t\t: 0x%08" PRIx64 "\n",
778
     function,
779
     value_64bit );
780
781
    byte_stream_copy_to_uint64_little_endian(
782
     ( (fsapfs_object_t *) data )->identifier,
783
     value_64bit );
784
    libcnotify_printf(
785
     "%s: object identifier\t\t: %" PRIu64 "\n",
786
     function,
787
     value_64bit );
788
789
    byte_stream_copy_to_uint64_little_endian(
790
     ( (fsapfs_object_t *) data )->transaction_identifier,
791
     value_64bit );
792
    libcnotify_printf(
793
     "%s: object transaction identifier\t: %" PRIu64 "\n",
794
     function,
795
     value_64bit );
796
797
    libcnotify_printf(
798
     "%s: object type\t\t\t: 0x%08" PRIx32 "\n",
799
     function,
800
     btree_node->object_type );
801
802
    libcnotify_printf(
803
     "%s: object subtype\t\t\t: 0x%08" PRIx32 "\n",
804
     function,
805
     btree_node->object_subtype );
806
807
    libcnotify_printf(
808
     "\n" );
809
  }
810
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
811
812
10.7k
  return( 1 );
813
10.8k
}
814
815
/* Determines if the node is a leaf node
816
 * Returns 1 if the node is a leaf node, 0 if not or -1 on error
817
 */
818
int libfsapfs_btree_node_is_leaf_node(
819
     libfsapfs_btree_node_t *btree_node,
820
     libcerror_error_t **error )
821
34.5k
{
822
34.5k
  static char *function = "libfsapfs_btree_node_is_leaf_node";
823
824
34.5k
  if( btree_node == NULL )
825
0
  {
826
0
    libcerror_error_set(
827
0
     error,
828
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
829
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
830
0
     "%s: invalid B-tree node.",
831
0
     function );
832
833
0
    return( -1 );
834
0
  }
835
34.5k
  if( btree_node->node_header == NULL )
836
0
  {
837
0
    libcerror_error_set(
838
0
     error,
839
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
840
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
841
0
     "%s: invalid B-tree node - missing node header.",
842
0
     function );
843
844
0
    return( -1 );
845
0
  }
846
34.5k
  return( btree_node->node_header->flags & 0x0002 );
847
34.5k
}
848
849
/* Retrieves the number of B-tree entries
850
 * Returns 1 if successful or -1 on error
851
 */
852
int libfsapfs_btree_node_get_number_of_entries(
853
     libfsapfs_btree_node_t *btree_node,
854
     int *number_of_entries,
855
     libcerror_error_t **error )
856
17.2k
{
857
17.2k
  static char *function = "libfsapfs_btree_node_get_number_of_entries";
858
859
17.2k
  if( btree_node == NULL )
860
0
  {
861
0
    libcerror_error_set(
862
0
     error,
863
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
864
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
865
0
     "%s: invalid B-tree node.",
866
0
     function );
867
868
0
    return( -1 );
869
0
  }
870
17.2k
  if( libcdata_array_get_number_of_entries(
871
17.2k
       btree_node->entries_array,
872
17.2k
       number_of_entries,
873
17.2k
       error ) != 1 )
874
0
  {
875
0
    libcerror_error_set(
876
0
     error,
877
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
878
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
879
0
     "%s: unable to retrieve number of entries from array.",
880
0
     function );
881
882
0
    return( -1 );
883
0
  }
884
17.2k
  return( 1 );
885
17.2k
}
886
887
/* Retrieves a specific of B-tree entry
888
 * Returns 1 if successful or -1 on error
889
 */
890
int libfsapfs_btree_node_get_entry_by_index(
891
     libfsapfs_btree_node_t *btree_node,
892
     int entry_index,
893
     libfsapfs_btree_entry_t **btree_entry,
894
     libcerror_error_t **error )
895
79.8k
{
896
79.8k
  static char *function = "libfsapfs_btree_node_get_entry_by_index";
897
898
79.8k
  if( btree_node == NULL )
899
0
  {
900
0
    libcerror_error_set(
901
0
     error,
902
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
903
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
904
0
     "%s: invalid B-tree node.",
905
0
     function );
906
907
0
    return( -1 );
908
0
  }
909
79.8k
  if( libcdata_array_get_entry_by_index(
910
79.8k
       btree_node->entries_array,
911
79.8k
       entry_index,
912
79.8k
       (intptr_t **) btree_entry,
913
79.8k
       error ) != 1 )
914
0
  {
915
0
    libcerror_error_set(
916
0
     error,
917
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
918
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
919
0
     "%s: unable to retrieve entry: %d from array.",
920
0
     function,
921
0
     entry_index );
922
923
0
    return( -1 );
924
0
  }
925
79.8k
  return( 1 );
926
79.8k
}
927