Coverage Report

Created: 2025-10-14 07:00

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-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.2k
{
47
10.2k
  static char *function = "libfsapfs_btree_node_initialize";
48
49
10.2k
  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.2k
  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.2k
  *btree_node = memory_allocate_structure(
72
10.2k
                 libfsapfs_btree_node_t );
73
74
10.2k
  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.2k
  if( memory_set(
86
10.2k
       *btree_node,
87
10.2k
       0,
88
10.2k
       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.2k
  if( libcdata_array_initialize(
105
10.2k
       &( ( *btree_node )->entries_array ),
106
10.2k
       0,
107
10.2k
       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.2k
  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.2k
}
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.2k
{
138
10.2k
  static char *function = "libfsapfs_btree_node_free";
139
10.2k
  int result            = 1;
140
141
10.2k
  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.2k
  if( *btree_node != NULL )
153
10.2k
  {
154
10.2k
    if( ( *btree_node )->node_header != NULL )
155
9.75k
    {
156
9.75k
      if( libfsapfs_btree_node_header_free(
157
9.75k
           &( ( *btree_node )->node_header ),
158
9.75k
           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
9.75k
    }
170
10.2k
    if( ( *btree_node )->footer != NULL )
171
9.43k
    {
172
9.43k
      if( libfsapfs_btree_footer_free(
173
9.43k
           &( ( *btree_node )->footer ),
174
9.43k
           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
9.43k
    }
186
10.2k
    if( libcdata_array_free(
187
10.2k
         &( ( *btree_node )->entries_array ),
188
10.2k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_entry_free,
189
10.2k
         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.2k
    memory_free(
201
10.2k
     *btree_node );
202
203
10.2k
    *btree_node = NULL;
204
10.2k
  }
205
10.2k
  return( result );
206
10.2k
}
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.2k
{
217
10.2k
  libfsapfs_btree_entry_t *btree_entry = NULL;
218
10.2k
  const uint8_t *btree_node_entry      = NULL;
219
10.2k
  static char *function                = "libfsapfs_btree_node_read_data";
220
10.2k
  size_t btree_entry_data_size         = 0;
221
10.2k
  size_t data_offset                   = 0;
222
10.2k
  size_t minimum_data_size             = 0;
223
10.2k
  size_t remaining_data_size           = 0;
224
10.2k
  uint16_t entries_data_offset         = 0;
225
10.2k
  uint16_t footer_offset               = 0;
226
10.2k
  uint16_t key_data_offset             = 0;
227
10.2k
  uint16_t key_data_size               = 0;
228
10.2k
  uint16_t map_entry_index             = 0;
229
10.2k
  uint16_t value_data_offset           = 0;
230
10.2k
  uint16_t value_data_size             = 0;
231
10.2k
  int entry_index                      = 0;
232
233
10.2k
  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.2k
  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.2k
  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.2k
  minimum_data_size = sizeof( fsapfs_object_t ) + sizeof( fsapfs_btree_node_header_t ) + sizeof( fsapfs_btree_footer_t );
267
268
10.2k
  if( ( data_size < minimum_data_size )
269
10.2k
   || ( 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.2k
  if( libfsapfs_btree_node_read_object_data(
293
10.2k
       btree_node,
294
10.2k
       data,
295
10.2k
       data_size,
296
10.2k
       error ) != 1 )
297
159
  {
298
159
    libcerror_error_set(
299
159
     error,
300
159
     LIBCERROR_ERROR_DOMAIN_IO,
301
159
     LIBCERROR_IO_ERROR_READ_FAILED,
302
159
     "%s: unable to read B-tree node object data.",
303
159
     function );
304
305
159
    goto on_error;
306
159
  }
307
10.0k
  data_offset = sizeof( fsapfs_object_t );
308
309
10.0k
  if( libfsapfs_btree_node_header_initialize(
310
10.0k
       &( btree_node->node_header ),
311
10.0k
       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.0k
  if( libfsapfs_btree_node_header_read_data(
323
10.0k
       btree_node->node_header,
324
10.0k
       &( data[ data_offset ] ),
325
10.0k
       sizeof( fsapfs_btree_node_header_t ),
326
10.0k
       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.0k
  data_offset += sizeof( fsapfs_btree_node_header_t );
338
339
10.0k
  remaining_data_size = data_size - minimum_data_size;
340
341
10.0k
  if( btree_node->node_header->entries_data_offset >= remaining_data_size )
342
3
  {
343
3
    libcerror_error_set(
344
3
     error,
345
3
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
346
3
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
347
3
     "%s: invalid entries offset size value out of bounds.",
348
3
     function );
349
350
3
    goto on_error;
351
3
  }
352
10.0k
  remaining_data_size -= btree_node->node_header->entries_data_offset;
353
354
10.0k
  if( btree_node->node_header->entries_data_size > remaining_data_size )
355
12
  {
356
12
    libcerror_error_set(
357
12
     error,
358
12
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
359
12
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
360
12
     "%s: invalid entries data size value out of bounds.",
361
12
     function );
362
363
12
    goto on_error;
364
12
  }
365
10.0k
  remaining_data_size -= btree_node->node_header->entries_data_size;
366
367
10.0k
  if( btree_node->node_header->unused_data_offset >= remaining_data_size )
368
16
  {
369
16
    libcerror_error_set(
370
16
     error,
371
16
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
372
16
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
373
16
     "%s: invalid unused offset size value out of bounds.",
374
16
     function );
375
376
16
    goto on_error;
377
16
  }
378
10.0k
  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.0k
  footer_offset = (uint16_t) data_size;
396
397
10.0k
  if( ( btree_node->node_header->flags & 0x0001 ) != 0 )
398
9.58k
  {
399
9.58k
    if( libfsapfs_btree_footer_initialize(
400
9.58k
         &( btree_node->footer ),
401
9.58k
         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
9.58k
    if( libfsapfs_btree_footer_read_data(
413
9.58k
         btree_node->footer,
414
9.58k
         &( data[ data_size - sizeof( fsapfs_btree_footer_t ) ] ),
415
9.58k
         sizeof( fsapfs_btree_footer_t ),
416
9.58k
         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
9.58k
    footer_offset -= (uint16_t) sizeof( fsapfs_btree_footer_t );
428
9.58k
  }
429
10.0k
  if( ( btree_node->node_header->flags & 0x0004 ) == 0 )
430
3.74k
  {
431
3.74k
    btree_entry_data_size = sizeof( fsapfs_btree_variable_size_entry_t );
432
3.74k
  }
433
6.29k
  else
434
6.29k
  {
435
6.29k
    btree_entry_data_size = sizeof( fsapfs_btree_fixed_size_entry_t );
436
6.29k
  }
437
10.0k
  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
9.99k
  data_offset += btree_node->node_header->entries_data_offset;
449
450
9.99k
  entries_data_offset = btree_node->node_header->entries_data_offset + (uint16_t) ( sizeof( fsapfs_object_t ) + sizeof( fsapfs_btree_node_header_t ) );
451
452
9.99k
  for( map_entry_index = 0;
453
74.9k
       map_entry_index < btree_node->node_header->number_of_keys;
454
64.9k
       map_entry_index++ )
455
65.1k
  {
456
65.1k
    btree_node_entry = &( data[ data_offset ] );
457
458
65.1k
    if( ( btree_node->node_header->flags & 0x0004 ) == 0 )
459
38.3k
    {
460
38.3k
      byte_stream_copy_to_uint16_little_endian(
461
38.3k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->key_data_offset,
462
38.3k
       key_data_offset );
463
464
38.3k
      byte_stream_copy_to_uint16_little_endian(
465
38.3k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->key_data_size,
466
38.3k
       key_data_size );
467
468
38.3k
      byte_stream_copy_to_uint16_little_endian(
469
38.3k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->value_data_offset,
470
38.3k
       value_data_offset );
471
472
38.3k
      byte_stream_copy_to_uint16_little_endian(
473
38.3k
       ( (fsapfs_btree_variable_size_entry_t *) btree_node_entry )->value_data_size,
474
38.3k
       value_data_size );
475
38.3k
    }
476
26.7k
    else
477
26.7k
    {
478
26.7k
      byte_stream_copy_to_uint16_little_endian(
479
26.7k
       ( (fsapfs_btree_fixed_size_entry_t *) btree_node_entry )->key_data_offset,
480
26.7k
       key_data_offset );
481
482
26.7k
      byte_stream_copy_to_uint16_little_endian(
483
26.7k
       ( (fsapfs_btree_fixed_size_entry_t *) btree_node_entry )->value_data_offset,
484
26.7k
       value_data_offset );
485
486
26.7k
      switch( btree_node->object_subtype )
487
26.7k
      {
488
26.6k
        case 0x0000000bUL:
489
26.6k
          key_data_size   = (uint16_t) sizeof( fsapfs_object_map_btree_key_t );
490
26.6k
          value_data_size = (uint16_t) sizeof( fsapfs_object_map_btree_value_t );
491
26.6k
          break;
492
493
103
        default:
494
103
          libcerror_error_set(
495
103
           error,
496
103
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
497
103
           LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
498
103
           "%s: invalid object subtype: 0x%08" PRIx32 ".",
499
103
           function,
500
103
           btree_node->object_subtype );
501
502
103
          goto on_error;
503
26.7k
      }
504
26.6k
      if( ( btree_node->node_header->flags & 0x0002 ) == 0 )
505
11.3k
      {
506
11.3k
        value_data_size = 8;
507
11.3k
      }
508
26.6k
    }
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
65.0k
    data_offset += btree_entry_data_size;
544
545
65.0k
    key_data_offset += entries_data_offset + btree_node->node_header->entries_data_size;
546
547
65.0k
    if( ( (size_t) key_data_offset > data_size )
548
65.0k
     || ( (size_t) key_data_size > ( data_size - key_data_offset ) ) )
549
70
    {
550
70
      libcerror_error_set(
551
70
       error,
552
70
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
553
70
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
554
70
       "%s: invalid key data offset value out of bounds.",
555
70
       function );
556
557
70
      goto on_error;
558
70
    }
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
64.9k
    value_data_offset = footer_offset - value_data_offset;
573
574
64.9k
    if( ( (size_t) value_data_offset > data_size )
575
64.9k
     || ( (size_t) value_data_size > ( data_size - value_data_offset ) ) )
576
70
    {
577
70
      libcerror_error_set(
578
70
       error,
579
70
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
580
70
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
581
70
       "%s: invalid value data offset value out of bounds.",
582
70
       function );
583
584
70
      goto on_error;
585
70
    }
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
64.9k
    if( libfsapfs_btree_entry_initialize(
600
64.9k
         &btree_entry,
601
64.9k
         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
64.9k
    if( libfsapfs_btree_entry_set_key_data(
613
64.9k
         btree_entry,
614
64.9k
         &( data[ key_data_offset ] ),
615
64.9k
         (size_t) key_data_size,
616
64.9k
         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
64.9k
    if( libfsapfs_btree_entry_set_value_data(
628
64.9k
         btree_entry,
629
64.9k
         &( data[ value_data_offset ] ),
630
64.9k
         (size_t) value_data_size,
631
64.9k
         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
64.9k
    if( libcdata_array_append_entry(
643
64.9k
         btree_node->entries_array,
644
64.9k
         &entry_index,
645
64.9k
         (intptr_t *) btree_entry,
646
64.9k
         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
64.9k
    btree_entry = NULL;
659
64.9k
  }
660
9.75k
  return( 1 );
661
662
472
on_error:
663
472
  if( btree_entry != NULL )
664
0
  {
665
0
    libfsapfs_btree_entry_free(
666
0
     &btree_entry,
667
0
     NULL );
668
0
  }
669
472
  if( btree_node->footer != NULL )
670
150
  {
671
150
    libfsapfs_btree_footer_free(
672
150
     &( btree_node->footer ),
673
150
     NULL );
674
150
  }
675
472
  if( btree_node->node_header != NULL )
676
313
  {
677
313
    libfsapfs_btree_node_header_free(
678
313
     &( btree_node->node_header ),
679
313
     NULL );
680
313
  }
681
472
  return( -1 );
682
9.99k
}
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.2k
{
693
10.2k
  static char *function = "libfsapfs_btree_node_read_object_data";
694
10.2k
  uint32_t object_type  = 0;
695
696
#if defined( HAVE_DEBUG_OUTPUT )
697
  uint64_t value_64bit  = 0;
698
#endif
699
700
10.2k
  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.2k
  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.2k
  if( ( data_size < sizeof( fsapfs_object_t ) )
723
10.2k
   || ( 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.2k
  byte_stream_copy_to_uint32_little_endian(
747
10.2k
   ( (fsapfs_object_t *) data )->type,
748
10.2k
   btree_node->object_type );
749
750
10.2k
  object_type = btree_node->object_type & 0x0ffffffUL;
751
752
10.2k
  if( ( object_type != 0x00000000UL )
753
9.93k
   && ( object_type != 0x00000002UL )
754
321
   && ( object_type != 0x00000003UL ) )
755
159
  {
756
159
    libcerror_error_set(
757
159
     error,
758
159
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
759
159
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
760
159
     "%s: invalid object type: 0x%08" PRIx32 ".",
761
159
     function,
762
159
     btree_node->object_type );
763
764
159
    return( -1 );
765
159
  }
766
10.0k
  byte_stream_copy_to_uint32_little_endian(
767
10.0k
   ( (fsapfs_object_t *) data )->subtype,
768
10.0k
   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.0k
  return( 1 );
813
10.2k
}
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
30.0k
{
822
30.0k
  static char *function = "libfsapfs_btree_node_is_leaf_node";
823
824
30.0k
  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
30.0k
  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
30.0k
  return( btree_node->node_header->flags & 0x0002 );
847
30.0k
}
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
15.0k
{
857
15.0k
  static char *function = "libfsapfs_btree_node_get_number_of_entries";
858
859
15.0k
  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
15.0k
  if( libcdata_array_get_number_of_entries(
871
15.0k
       btree_node->entries_array,
872
15.0k
       number_of_entries,
873
15.0k
       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
15.0k
  return( 1 );
885
15.0k
}
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
73.4k
{
896
73.4k
  static char *function = "libfsapfs_btree_node_get_entry_by_index";
897
898
73.4k
  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
73.4k
  if( libcdata_array_get_entry_by_index(
910
73.4k
       btree_node->entries_array,
911
73.4k
       entry_index,
912
73.4k
       (intptr_t **) btree_entry,
913
73.4k
       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
73.4k
  return( 1 );
926
73.4k
}
927