Coverage Report

Created: 2024-02-25 07:20

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