Coverage Report

Created: 2026-08-31 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/libfsxfs/libfsxfs_extent_btree.c
Line
Count
Source
1
/*
2
 * Extent B+ tree functions
3
 *
4
 * Copyright (C) 2020-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 "libfsxfs_btree_block.h"
28
#include "libfsxfs_definitions.h"
29
#include "libfsxfs_extent.h"
30
#include "libfsxfs_extent_btree.h"
31
#include "libfsxfs_extents.h"
32
#include "libfsxfs_libbfio.h"
33
#include "libfsxfs_libcerror.h"
34
#include "libfsxfs_libcnotify.h"
35
36
/* Creates an extent B+ tree
37
 * Make sure the value extent_btree is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsxfs_extent_btree_initialize(
41
     libfsxfs_extent_btree_t **extent_btree,
42
     libcerror_error_t **error )
43
972
{
44
972
  static char *function = "libfsxfs_extent_btree_initialize";
45
46
972
  if( extent_btree == NULL )
47
0
  {
48
0
    libcerror_error_set(
49
0
     error,
50
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
51
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
52
0
     "%s: invalid extent B+ tree.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
972
  if( *extent_btree != NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
62
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
63
0
     "%s: invalid extent B+ tree value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
972
  *extent_btree = memory_allocate_structure(
69
972
                   libfsxfs_extent_btree_t );
70
71
972
  if( *extent_btree == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
76
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
77
0
     "%s: unable to create extent B+ tree.",
78
0
     function );
79
80
0
    goto on_error;
81
0
  }
82
972
  if( memory_set(
83
972
       *extent_btree,
84
972
       0,
85
972
       sizeof( libfsxfs_extent_btree_t ) ) == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
91
0
     "%s: unable to clear extent B+ tree.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
972
  return( 1 );
97
98
0
on_error:
99
0
  if( *extent_btree != NULL )
100
0
  {
101
0
    memory_free(
102
0
     *extent_btree );
103
104
0
    *extent_btree = NULL;
105
0
  }
106
0
  return( -1 );
107
972
}
108
109
/* Frees an extent B+ tree
110
 * Returns 1 if successful or -1 on error
111
 */
112
int libfsxfs_extent_btree_free(
113
     libfsxfs_extent_btree_t **extent_btree,
114
     libcerror_error_t **error )
115
972
{
116
972
  static char *function = "libfsxfs_extent_btree_free";
117
118
972
  if( extent_btree == NULL )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
123
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
124
0
     "%s: invalid extent B+ tree.",
125
0
     function );
126
127
0
    return( -1 );
128
0
  }
129
972
  if( *extent_btree != NULL )
130
972
  {
131
972
    memory_free(
132
972
     *extent_btree );
133
134
972
    *extent_btree = NULL;
135
972
  }
136
972
  return( 1 );
137
972
}
138
139
/* Retrieves the extents from the extent B+ tree root node
140
 * Returns 1 if successful or -1 on error
141
 */
142
int libfsxfs_extent_btree_get_extents_from_root_node(
143
     libfsxfs_extent_btree_t *extent_btree,
144
     libfsxfs_io_handle_t *io_handle,
145
     libbfio_handle_t *file_io_handle,
146
     uint64_t number_of_blocks,
147
     const uint8_t *data,
148
     size_t data_size,
149
     libcdata_array_t *extents_array,
150
     uint8_t add_sparse_extents,
151
     libcerror_error_t **error )
152
972
{
153
972
  libfsxfs_extent_t *last_extent   = NULL;
154
972
  libfsxfs_extent_t *sparse_extent = NULL;
155
972
  static char *function            = "libfsxfs_extent_btree_get_extents_from_root_node";
156
972
  uint64_t logical_block_number    = 0;
157
972
  uint16_t level                   = 0;
158
972
  uint16_t number_of_records       = 0;
159
972
  int entry_index                  = 0;
160
161
972
  if( extent_btree == NULL )
162
0
  {
163
0
    libcerror_error_set(
164
0
     error,
165
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
166
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
167
0
     "%s: invalid extent B+ tree.",
168
0
     function );
169
170
0
    return( -1 );
171
0
  }
172
972
  if( data == NULL )
173
0
  {
174
0
    libcerror_error_set(
175
0
     error,
176
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
177
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
178
0
     "%s: invalid data.",
179
0
     function );
180
181
0
    return( -1 );
182
0
  }
183
972
  if( ( data_size < 4 )
184
972
   || ( data_size > (size_t) SSIZE_MAX ) )
185
0
  {
186
0
    libcerror_error_set(
187
0
     error,
188
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
189
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
190
0
     "%s: invalid data size value out of bounds.",
191
0
     function );
192
193
0
    return( -1 );
194
0
  }
195
#if defined( HAVE_DEBUG_OUTPUT )
196
  if( libcnotify_verbose != 0 )
197
  {
198
    libcnotify_printf(
199
     "%s: extents B+ tree root node data:\n",
200
     function );
201
    libcnotify_print_data(
202
     data,
203
     data_size,
204
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
205
  }
206
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
207
208
972
  byte_stream_copy_to_uint16_big_endian(
209
972
   &( data[ 0 ] ),
210
972
   level );
211
212
972
  byte_stream_copy_to_uint16_big_endian(
213
972
   &( data[ 2 ] ),
214
972
   number_of_records );
215
216
#if defined( HAVE_DEBUG_OUTPUT )
217
  if( libcnotify_verbose != 0 )
218
  {
219
    libcnotify_printf(
220
     "%s: node level\t\t: %" PRIu16 "\n",
221
     function,
222
     level );
223
224
    libcnotify_printf(
225
     "%s: number of records\t: %" PRIu16 "\n",
226
     function,
227
     number_of_records );
228
229
    libcnotify_printf(
230
     "\n" );
231
  }
232
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
233
234
972
  if( level == 0 )
235
8
  {
236
8
    libcerror_error_set(
237
8
     error,
238
8
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
239
8
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
240
8
     "%s: unsupported B+ tree root node level.",
241
8
     function );
242
243
8
    goto on_error;
244
8
  }
245
964
  if( libfsxfs_extent_btree_get_extents_from_branch_node(
246
964
       extent_btree,
247
964
       io_handle,
248
964
       file_io_handle,
249
964
       number_of_records,
250
964
       &( data[ 4 ] ),
251
964
       data_size - 4,
252
964
       extents_array,
253
964
       add_sparse_extents,
254
964
       0,
255
964
       error ) != 1 )
256
304
  {
257
304
    libcerror_error_set(
258
304
     error,
259
304
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
260
304
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
261
304
     "%s: unable to retrieve extents from root node.",
262
304
     function );
263
264
304
    goto on_error;
265
304
  }
266
660
  if( libfsxfs_extents_get_last_extent(
267
660
       extents_array,
268
660
       &last_extent,
269
660
       error ) != 1 )
270
0
  {
271
0
    libcerror_error_set(
272
0
     error,
273
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
274
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
275
0
     "%s: unable to retrieve last extent.",
276
0
     function );
277
278
0
    goto on_error;
279
0
  }
280
660
  if( last_extent != NULL )
281
354
  {
282
354
    logical_block_number = last_extent->logical_block_number + last_extent->number_of_blocks;
283
354
  }
284
660
  if( ( add_sparse_extents != 0 )
285
259
   && ( logical_block_number < number_of_blocks ) )
286
103
  {
287
103
    if( ( last_extent == NULL )
288
12
     || ( ( last_extent->range_flags & LIBFSXFS_EXTENT_FLAG_IS_SPARSE ) == 0 ) )
289
96
    {
290
96
      if( libfsxfs_extent_initialize(
291
96
           &sparse_extent,
292
96
           error ) != 1 )
293
0
      {
294
0
        libcerror_error_set(
295
0
         error,
296
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
297
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
298
0
         "%s: unable to create sparse extent.",
299
0
         function );
300
301
0
        goto on_error;
302
0
      }
303
96
      sparse_extent->logical_block_number = logical_block_number;
304
96
      sparse_extent->range_flags          = LIBFSXFS_EXTENT_FLAG_IS_SPARSE;
305
306
96
      if( libcdata_array_append_entry(
307
96
           extents_array,
308
96
           &entry_index,
309
96
           (intptr_t *) sparse_extent,
310
96
           error ) != 1 )
311
0
      {
312
0
        libcerror_error_set(
313
0
         error,
314
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
315
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
316
0
         "%s: unable to append sparse extent to array.",
317
0
         function );
318
319
0
        goto on_error;
320
0
      }
321
96
      last_extent   = sparse_extent;
322
96
      sparse_extent = NULL;
323
96
    }
324
103
    last_extent->number_of_blocks += number_of_blocks - logical_block_number;
325
326
#if defined( HAVE_DEBUG_OUTPUT )
327
    if( libcnotify_verbose != 0 )
328
    {
329
      libcnotify_printf(
330
       "%s: logical block number\t\t\t: %" PRIu64 "\n",
331
       function,
332
       last_extent->logical_block_number );
333
334
      libcnotify_printf(
335
       "%s: physical block number\t\t\t: %" PRIu64 "\n",
336
       function,
337
       last_extent->physical_block_number );
338
339
      libcnotify_printf(
340
       "%s: number of blocks\t\t\t: %" PRIu64 "\n",
341
       function,
342
       last_extent->number_of_blocks );
343
344
      libcnotify_printf(
345
       "\n" );
346
    }
347
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
348
103
  }
349
660
  return( 1 );
350
351
312
on_error:
352
312
  if( sparse_extent != NULL )
353
0
  {
354
0
    libfsxfs_extent_free(
355
0
     &sparse_extent,
356
0
     NULL );
357
0
  }
358
312
  libcdata_array_empty(
359
312
   extents_array,
360
312
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
361
312
   NULL );
362
363
312
  return( -1 );
364
660
}
365
366
/* Retrieves the extents from the extent B+ tree branch node
367
 * Returns 1 if successful or -1 on error
368
 */
369
int libfsxfs_extent_btree_get_extents_from_branch_node(
370
     libfsxfs_extent_btree_t *extent_btree,
371
     libfsxfs_io_handle_t *io_handle,
372
     libbfio_handle_t *file_io_handle,
373
     uint16_t number_of_records,
374
     const uint8_t *records_data,
375
     size_t records_data_size,
376
     libcdata_array_t *extents_array,
377
     uint8_t add_sparse_extents,
378
     int recursion_depth,
379
     libcerror_error_t **error )
380
964
{
381
964
  static char *function            = "libfsxfs_extent_btree_get_extents_from_branch_node";
382
964
  size_t number_of_key_value_pairs = 0;
383
964
  size_t records_data_offset       = 0;
384
964
  uint64_t sub_block_number        = 0;
385
964
  uint16_t record_index            = 0;
386
387
#if defined( HAVE_DEBUG_OUTPUT )
388
  uint64_t value_64bit             = 0;
389
#endif
390
391
964
  if( extent_btree == NULL )
392
0
  {
393
0
    libcerror_error_set(
394
0
     error,
395
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
396
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
397
0
     "%s: invalid extent B+ tree.",
398
0
     function );
399
400
0
    return( -1 );
401
0
  }
402
964
  if( records_data == NULL )
403
0
  {
404
0
    libcerror_error_set(
405
0
     error,
406
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
407
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
408
0
     "%s: invalid records data.",
409
0
     function );
410
411
0
    return( -1 );
412
0
  }
413
964
  if( ( records_data_size == 0 )
414
961
   || ( records_data_size > (size_t) SSIZE_MAX ) )
415
3
  {
416
3
    libcerror_error_set(
417
3
     error,
418
3
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
419
3
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
420
3
     "%s: invalid records data size value out of bounds.",
421
3
     function );
422
423
3
    return( -1 );
424
3
  }
425
961
  if( ( recursion_depth < 0 )
426
961
   || ( recursion_depth > LIBFSXFS_MAXIMUM_RECURSION_DEPTH ) )
427
0
  {
428
0
    libcerror_error_set(
429
0
     error,
430
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
431
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
432
0
     "%s: invalid recursion depth value out of bounds.",
433
0
     function );
434
435
0
    return( -1 );
436
0
  }
437
961
  number_of_key_value_pairs = records_data_size / 16;
438
439
961
  if( (size_t) number_of_records > number_of_key_value_pairs )
440
31
  {
441
31
    libcerror_error_set(
442
31
     error,
443
31
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
444
31
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
445
31
     "%s: invalid number of records value out of bounds.",
446
31
     function );
447
448
31
    return( -1 );
449
31
  }
450
930
  for( record_index = 0;
451
9.57k
       record_index < number_of_records;
452
8.64k
       record_index++ )
453
8.64k
  {
454
#if defined( HAVE_DEBUG_OUTPUT )
455
    if( libcnotify_verbose != 0 )
456
    {
457
      byte_stream_copy_to_uint64_big_endian(
458
       &( records_data[ records_data_offset ] ),
459
       value_64bit );
460
      libcnotify_printf(
461
       "%s: key: %" PRIu16 "\t\t: %" PRIu64 "\n",
462
       function,
463
       record_index,
464
       value_64bit );
465
    }
466
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
467
468
8.64k
    records_data_offset += 8;
469
8.64k
  }
470
#if defined( HAVE_DEBUG_OUTPUT )
471
  if( libcnotify_verbose != 0 )
472
  {
473
    libcnotify_printf(
474
     "\n" );
475
  }
476
#endif
477
930
  records_data_offset = number_of_key_value_pairs * 8;
478
479
930
  for( record_index = 0;
480
6.89k
       record_index < number_of_records;
481
5.96k
       record_index++ )
482
6.23k
  {
483
6.23k
    byte_stream_copy_to_uint64_big_endian(
484
6.23k
     &( records_data[ records_data_offset ] ),
485
6.23k
     sub_block_number );
486
487
#if defined( HAVE_DEBUG_OUTPUT )
488
    if( libcnotify_verbose != 0 )
489
    {
490
      libcnotify_printf(
491
       "%s: value: %" PRIu16 "\t\t: %" PRIu64 "\n",
492
       function,
493
       record_index,
494
       sub_block_number );
495
496
      libcnotify_printf(
497
       "\n" );
498
    }
499
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
500
501
6.23k
    records_data_offset += 8;
502
503
6.23k
    if( libfsxfs_extent_btree_get_extents_from_node(
504
6.23k
         extent_btree,
505
6.23k
         io_handle,
506
6.23k
         file_io_handle,
507
6.23k
         sub_block_number,
508
6.23k
         extents_array,
509
6.23k
         add_sparse_extents,
510
6.23k
         recursion_depth + 1,
511
6.23k
         error ) != 1 )
512
270
    {
513
270
      libcerror_error_set(
514
270
       error,
515
270
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
516
270
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
517
270
       "%s: unable to retrieve extents from branch node.",
518
270
       function );
519
520
270
      goto on_error;
521
270
    }
522
6.23k
  }
523
#if defined( HAVE_DEBUG_OUTPUT )
524
  if( libcnotify_verbose != 0 )
525
  {
526
    libcnotify_printf(
527
     "\n" );
528
  }
529
#endif
530
660
  return( 1 );
531
532
270
on_error:
533
270
  libcdata_array_empty(
534
270
   extents_array,
535
270
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
536
270
   NULL );
537
538
270
  return( -1 );
539
930
}
540
541
/* Retrieves the extents from the extent B+ tree node
542
 * Returns 1 if successful or -1 on error
543
 */
544
int libfsxfs_extent_btree_get_extents_from_node(
545
     libfsxfs_extent_btree_t *extent_btree,
546
     libfsxfs_io_handle_t *io_handle,
547
     libbfio_handle_t *file_io_handle,
548
     uint64_t block_number,
549
     libcdata_array_t *extents_array,
550
     uint8_t add_sparse_extents,
551
     int recursion_depth,
552
     libcerror_error_t **error )
553
6.23k
{
554
6.23k
  libfsxfs_btree_block_t *btree_block = NULL;
555
6.23k
  static char *function               = "libfsxfs_extent_btree_get_extents_from_node";
556
6.23k
  off64_t btree_block_offset          = 0;
557
6.23k
  uint64_t relative_block_number      = 0;
558
6.23k
  int allocation_group_index          = 0;
559
6.23k
  int compare_result                  = 0;
560
561
6.23k
  if( extent_btree == NULL )
562
0
  {
563
0
    libcerror_error_set(
564
0
     error,
565
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
566
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
567
0
     "%s: invalid extent B+ tree.",
568
0
     function );
569
570
0
    return( -1 );
571
0
  }
572
6.23k
  if( io_handle == NULL )
573
0
  {
574
0
    libcerror_error_set(
575
0
     error,
576
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
577
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
578
0
     "%s: invalid IO handle.",
579
0
     function );
580
581
0
    return( -1 );
582
0
  }
583
6.23k
  if( io_handle->allocation_group_size == 0 )
584
0
  {
585
0
    libcerror_error_set(
586
0
     error,
587
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
588
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
589
0
     "%s: invalid IO handle - allocation group size value out of bounds.",
590
0
     function );
591
592
0
    return( -1 );
593
0
  }
594
6.23k
  if( io_handle->block_size == 0 )
595
0
  {
596
0
    libcerror_error_set(
597
0
     error,
598
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
599
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
600
0
     "%s: invalid IO handle - block size value out of bounds.",
601
0
     function );
602
603
0
    return( -1 );
604
0
  }
605
6.23k
  allocation_group_index = (int) ( block_number >> io_handle->number_of_relative_block_number_bits );
606
6.23k
  relative_block_number  = block_number & ( ( 1 << io_handle->number_of_relative_block_number_bits ) - 1 );
607
608
#if defined( HAVE_DEBUG_OUTPUT )
609
  if( libcnotify_verbose != 0 )
610
  {
611
    libcnotify_printf(
612
     "%s: allocation group index\t: %d\n",
613
     function,
614
     allocation_group_index );
615
616
    libcnotify_printf(
617
     "%s: relative block number\t: %" PRIu64 "\n",
618
     function,
619
     relative_block_number );
620
621
    libcnotify_printf(
622
     "\n" );
623
  }
624
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
625
626
6.23k
  btree_block_offset = ( ( (off64_t) allocation_group_index * io_handle->allocation_group_size ) + relative_block_number ) * io_handle->block_size;
627
628
6.23k
  if( libfsxfs_btree_block_initialize(
629
6.23k
       &btree_block,
630
6.23k
       io_handle->block_size,
631
6.23k
       8,
632
6.23k
       error ) != 1 )
633
0
  {
634
0
    libcerror_error_set(
635
0
     error,
636
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
637
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
638
0
     "%s: unable to create B+ tree block.",
639
0
     function );
640
641
0
    goto on_error;
642
0
  }
643
6.23k
  if( libfsxfs_btree_block_read_file_io_handle(
644
6.23k
       btree_block,
645
6.23k
       io_handle,
646
6.23k
       file_io_handle,
647
6.23k
       btree_block_offset,
648
6.23k
       error ) != 1 )
649
223
  {
650
223
    libcerror_error_set(
651
223
     error,
652
223
     LIBCERROR_ERROR_DOMAIN_IO,
653
223
     LIBCERROR_IO_ERROR_READ_FAILED,
654
223
     "%s: unable to read extent B+ tree block: %" PRIu32 " at offset: %" PRIi64 " (0x%08" PRIx64 ").",
655
223
     function,
656
223
     block_number,
657
223
     btree_block_offset,
658
223
     btree_block_offset );
659
660
223
    goto on_error;
661
223
  }
662
6.01k
  if( io_handle->format_version == 5 )
663
44
  {
664
44
    compare_result = memory_compare(
665
44
                      btree_block->header->signature,
666
44
                      "BMA3",
667
44
                      4 );
668
44
  }
669
5.96k
  else
670
5.96k
  {
671
5.96k
    compare_result = memory_compare(
672
5.96k
                      btree_block->header->signature,
673
5.96k
                      "BMAP",
674
5.96k
                      4 );
675
5.96k
  }
676
6.01k
  if( compare_result != 0 )
677
28
  {
678
28
    libcerror_error_set(
679
28
     error,
680
28
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
681
28
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
682
28
     "%s: unsupported block signature.",
683
28
     function );
684
685
28
    goto on_error;
686
28
  }
687
5.98k
  if( btree_block->header->level > extent_btree->maximum_depth )
688
17
  {
689
17
    libcerror_error_set(
690
17
     error,
691
17
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
692
17
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
693
17
     "%s: unsupported B+ tree node level.",
694
17
     function );
695
696
17
    goto on_error;
697
17
  }
698
5.96k
  if( btree_block->header->level == 0 )
699
5.96k
  {
700
5.96k
    if( libfsxfs_extents_read_data(
701
5.96k
         extents_array,
702
5.96k
         (uint32_t) btree_block->header->number_of_records,
703
5.96k
         btree_block->records_data,
704
5.96k
         btree_block->records_data_size,
705
5.96k
         add_sparse_extents,
706
5.96k
         error ) != 1 )
707
2
    {
708
2
      libcerror_error_set(
709
2
       error,
710
2
       LIBCERROR_ERROR_DOMAIN_IO,
711
2
       LIBCERROR_IO_ERROR_READ_FAILED,
712
2
       "%s: unable to read data extents.",
713
2
       function );
714
715
2
      goto on_error;
716
2
    }
717
5.96k
  }
718
0
  else
719
0
  {
720
0
    if( libfsxfs_extent_btree_get_extents_from_branch_node(
721
0
         extent_btree,
722
0
         io_handle,
723
0
         file_io_handle,
724
0
         btree_block->header->number_of_records,
725
0
         btree_block->records_data,
726
0
         btree_block->records_data_size,
727
0
         extents_array,
728
0
         add_sparse_extents,
729
0
         recursion_depth,
730
0
         error ) != 1 )
731
0
    {
732
0
      libcerror_error_set(
733
0
       error,
734
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
735
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
736
0
       "%s: unable to retrieve extents from branch node.",
737
0
       function );
738
739
0
      goto on_error;
740
0
    }
741
0
  }
742
5.96k
  if( libfsxfs_btree_block_free(
743
5.96k
       &btree_block,
744
5.96k
       error ) != 1 )
745
0
  {
746
0
    libcerror_error_set(
747
0
     error,
748
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
749
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
750
0
     "%s: unable to free B+ tree block.",
751
0
     function );
752
753
0
    goto on_error;
754
0
  }
755
5.96k
  return( 1 );
756
757
270
on_error:
758
270
  if( btree_block != NULL )
759
270
  {
760
270
    libfsxfs_btree_block_free(
761
270
     &btree_block,
762
270
     NULL );
763
270
  }
764
270
  libcdata_array_empty(
765
270
   extents_array,
766
270
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
767
270
   NULL );
768
769
270
  return( -1 );
770
5.96k
}
771