Coverage Report

Created: 2026-08-31 07:43

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