Coverage Report

Created: 2023-06-07 06:53

/src/libfsxfs/libfsxfs/libfsxfs_inode_btree.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Inode B+ tree functions
3
 *
4
 * Copyright (C) 2020-2023, 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_btree_header.h"
29
#include "libfsxfs_definitions.h"
30
#include "libfsxfs_inode_btree.h"
31
#include "libfsxfs_inode_btree_record.h"
32
#include "libfsxfs_inode_information.h"
33
#include "libfsxfs_libbfio.h"
34
#include "libfsxfs_libcdata.h"
35
#include "libfsxfs_libcerror.h"
36
#include "libfsxfs_libcnotify.h"
37
38
/* Creates an inode B+ tree
39
 * Make sure the value inode_btree is referencing, is set to NULL
40
 * Returns 1 if successful or -1 on error
41
 */
42
int libfsxfs_inode_btree_initialize(
43
     libfsxfs_inode_btree_t **inode_btree,
44
     libcerror_error_t **error )
45
4.18k
{
46
4.18k
  static char *function = "libfsxfs_inode_btree_initialize";
47
48
4.18k
  if( inode_btree == NULL )
49
0
  {
50
0
    libcerror_error_set(
51
0
     error,
52
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54
0
     "%s: invalid inode B+ tree.",
55
0
     function );
56
57
0
    return( -1 );
58
0
  }
59
4.18k
  if( *inode_btree != NULL )
60
0
  {
61
0
    libcerror_error_set(
62
0
     error,
63
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
64
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65
0
     "%s: invalid inode B+ tree value already set.",
66
0
     function );
67
68
0
    return( -1 );
69
0
  }
70
4.18k
  *inode_btree = memory_allocate_structure(
71
4.18k
                  libfsxfs_inode_btree_t );
72
73
4.18k
  if( *inode_btree == NULL )
74
0
  {
75
0
    libcerror_error_set(
76
0
     error,
77
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
78
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
79
0
     "%s: unable to create inode B+ tree.",
80
0
     function );
81
82
0
    goto on_error;
83
0
  }
84
4.18k
  if( memory_set(
85
4.18k
       *inode_btree,
86
4.18k
       0,
87
4.18k
       sizeof( libfsxfs_inode_btree_t ) ) == NULL )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
92
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
93
0
     "%s: unable to clear inode B+ tree.",
94
0
     function );
95
96
0
    memory_free(
97
0
     *inode_btree );
98
99
0
    *inode_btree = NULL;
100
101
0
    return( -1 );
102
0
  }
103
4.18k
  if( libcdata_array_initialize(
104
4.18k
       &( ( *inode_btree )->inode_information_array ),
105
4.18k
       0,
106
4.18k
       error ) != 1 )
107
0
  {
108
0
    libcerror_error_set(
109
0
     error,
110
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
111
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
112
0
     "%s: unable to create inode information array.",
113
0
     function );
114
115
0
    goto on_error;
116
0
  }
117
4.18k
  return( 1 );
118
119
0
on_error:
120
0
  if( *inode_btree != NULL )
121
0
  {
122
0
    memory_free(
123
0
     *inode_btree );
124
125
0
    *inode_btree = NULL;
126
0
  }
127
0
  return( -1 );
128
4.18k
}
129
130
/* Frees an inode B+ tree
131
 * Returns 1 if successful or -1 on error
132
 */
133
int libfsxfs_inode_btree_free(
134
     libfsxfs_inode_btree_t **inode_btree,
135
     libcerror_error_t **error )
136
4.18k
{
137
4.18k
  static char *function = "libfsxfs_inode_btree_free";
138
4.18k
  int result            = 1;
139
140
4.18k
  if( inode_btree == NULL )
141
0
  {
142
0
    libcerror_error_set(
143
0
     error,
144
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
145
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
146
0
     "%s: invalid inode B+ tree.",
147
0
     function );
148
149
0
    return( -1 );
150
0
  }
151
4.18k
  if( *inode_btree != NULL )
152
4.18k
  {
153
4.18k
    if( libcdata_array_free(
154
4.18k
         &( ( *inode_btree )->inode_information_array ),
155
4.18k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_inode_information_free,
156
4.18k
         error ) != 1 )
157
0
    {
158
0
      libcerror_error_set(
159
0
       error,
160
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
161
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
162
0
       "%s: unable to free inode information array.",
163
0
       function );
164
165
0
      result = -1;
166
0
    }
167
4.18k
    memory_free(
168
4.18k
     *inode_btree );
169
170
4.18k
    *inode_btree = NULL;
171
4.18k
  }
172
4.18k
  return( result );
173
4.18k
}
174
175
/* Reads the inode information
176
 * Returns 1 if successful or -1 on error
177
 */
178
int libfsxfs_inode_btree_read_inode_information(
179
     libfsxfs_inode_btree_t *inode_btree,
180
     libfsxfs_io_handle_t *io_handle,
181
     libbfio_handle_t *file_io_handle,
182
     off64_t file_offset,
183
     libcerror_error_t **error )
184
16.5k
{
185
16.5k
  libfsxfs_inode_information_t *inode_information = NULL;
186
16.5k
  static char *function                           = "libfsxfs_file_system_read_inode_information";
187
16.5k
  int entry_index                                 = 0;
188
189
16.5k
  if( inode_btree == NULL )
190
0
  {
191
0
    libcerror_error_set(
192
0
     error,
193
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195
0
     "%s: invalid inode B+ tree.",
196
0
     function );
197
198
0
    return( -1 );
199
0
  }
200
16.5k
  if( libfsxfs_inode_information_initialize(
201
16.5k
       &inode_information,
202
16.5k
       error ) != 1 )
203
0
  {
204
0
    libcerror_error_set(
205
0
     error,
206
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
207
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
208
0
     "%s: unable to create inode information.",
209
0
     function );
210
211
0
    goto on_error;
212
0
  }
213
16.5k
  if( libfsxfs_inode_information_read_file_io_handle(
214
16.5k
       inode_information,
215
16.5k
       io_handle,
216
16.5k
       file_io_handle,
217
16.5k
       file_offset,
218
16.5k
       error ) != 1 )
219
9.48k
  {
220
9.48k
    libcerror_error_set(
221
9.48k
     error,
222
9.48k
     LIBCERROR_ERROR_DOMAIN_IO,
223
9.48k
     LIBCERROR_IO_ERROR_READ_FAILED,
224
9.48k
     "%s: unable to read inode information at offset: %" PRIi64 " (0x%08" PRIx64 ").",
225
9.48k
     function,
226
9.48k
     file_offset,
227
9.48k
     file_offset );
228
229
9.48k
    goto on_error;
230
9.48k
  }
231
7.02k
  if( libcdata_array_append_entry(
232
7.02k
       inode_btree->inode_information_array,
233
7.02k
       &entry_index,
234
7.02k
       (intptr_t *) inode_information,
235
7.02k
       error ) != 1 )
236
0
  {
237
0
    libcerror_error_set(
238
0
     error,
239
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
240
0
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
241
0
     "%s: unable to append inode information to array.",
242
0
     function );
243
244
0
    goto on_error;
245
0
  }
246
7.02k
  return( 1 );
247
248
9.48k
on_error:
249
9.48k
  if( inode_information != NULL )
250
9.48k
  {
251
9.48k
    libfsxfs_inode_information_free(
252
9.48k
     &inode_information,
253
9.48k
     NULL );
254
9.48k
  }
255
9.48k
  return( -1 );
256
7.02k
}
257
258
/* Retrieves the inode from the inode B+ tree branch node
259
 * Returns 1 if successful or -1 on error
260
 */
261
int libfsxfs_inode_btree_get_inode_from_branch_node(
262
     libfsxfs_inode_btree_t *inode_btree,
263
     libfsxfs_io_handle_t *io_handle,
264
     libbfio_handle_t *file_io_handle,
265
     uint64_t allocation_group_block_number,
266
     uint16_t number_of_records,
267
     const uint8_t *records_data,
268
     size_t records_data_size,
269
     uint64_t relative_inode_number,
270
     int recursion_depth,
271
     libcerror_error_t **error )
272
4.92k
{
273
4.92k
  static char *function              = "libfsxfs_inode_btree_get_inode_from_branch_node";
274
4.92k
  size_t number_of_key_value_pairs   = 0;
275
4.92k
  size_t records_data_offset         = 0;
276
4.92k
  uint32_t relative_key_inode_number = 0;
277
4.92k
  uint32_t relative_sub_block_number = 0;
278
4.92k
  uint16_t record_index              = 0;
279
4.92k
  int result                         = 0;
280
281
4.92k
  if( inode_btree == NULL )
282
0
  {
283
0
    libcerror_error_set(
284
0
     error,
285
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
286
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
287
0
     "%s: invalid inode B+ tree.",
288
0
     function );
289
290
0
    return( -1 );
291
0
  }
292
4.92k
  if( records_data == NULL )
293
0
  {
294
0
    libcerror_error_set(
295
0
     error,
296
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
297
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
298
0
     "%s: invalid records data.",
299
0
     function );
300
301
0
    return( -1 );
302
0
  }
303
4.92k
  if( ( records_data_size == 0 )
304
4.92k
   || ( records_data_size > (size_t) SSIZE_MAX ) )
305
0
  {
306
0
    libcerror_error_set(
307
0
     error,
308
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
309
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
310
0
     "%s: invalid records data size value out of bounds.",
311
0
     function );
312
313
0
    return( -1 );
314
0
  }
315
4.92k
  if( ( recursion_depth < 0 )
316
4.92k
   || ( recursion_depth > LIBFSXFS_MAXIMUM_RECURSION_DEPTH ) )
317
18
  {
318
18
    libcerror_error_set(
319
18
     error,
320
18
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
321
18
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
322
18
     "%s: invalid recursion depth value out of bounds.",
323
18
     function );
324
325
18
    return( -1 );
326
18
  }
327
4.90k
  number_of_key_value_pairs = records_data_size / 8;
328
329
4.90k
  if( (size_t) number_of_records > number_of_key_value_pairs )
330
26
  {
331
26
    libcerror_error_set(
332
26
     error,
333
26
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
334
26
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
335
26
     "%s: invalid number of records value out of bounds.",
336
26
     function );
337
338
26
    return( -1 );
339
26
  }
340
4.88k
  for( record_index = 0;
341
94.4k
       record_index < number_of_records;
342
89.5k
       record_index++ )
343
93.5k
  {
344
93.5k
    byte_stream_copy_to_uint32_big_endian(
345
93.5k
     &( records_data[ records_data_offset ] ),
346
93.5k
     relative_key_inode_number );
347
348
93.5k
    records_data_offset += 4;
349
350
#if defined( HAVE_DEBUG_OUTPUT )
351
    if( libcnotify_verbose != 0 )
352
    {
353
      libcnotify_printf(
354
       "%s: inode number\t\t: %" PRIu32 "\n",
355
       function,
356
       relative_key_inode_number );
357
    }
358
#endif
359
93.5k
    if( relative_inode_number < relative_key_inode_number )
360
4.00k
    {
361
4.00k
      break;
362
4.00k
    }
363
93.5k
  }
364
4.88k
  if( ( record_index > 0 )
365
4.88k
   && ( record_index <= number_of_records ) )
366
4.83k
  {
367
4.83k
    records_data_offset = ( number_of_key_value_pairs + record_index - 1 ) * 4;
368
369
4.83k
    byte_stream_copy_to_uint32_big_endian(
370
4.83k
     &( records_data[ records_data_offset ] ),
371
4.83k
     relative_sub_block_number );
372
373
#if defined( HAVE_DEBUG_OUTPUT )
374
    if( libcnotify_verbose != 0 )
375
    {
376
      libcnotify_printf(
377
       "%s: sub block number\t: %" PRIu32 "\n",
378
       function,
379
       relative_sub_block_number );
380
381
      libcnotify_printf(
382
       "\n" );
383
    }
384
#endif
385
4.83k
    result = libfsxfs_inode_btree_get_inode_from_node(
386
4.83k
              inode_btree,
387
4.83k
              io_handle,
388
4.83k
              file_io_handle,
389
4.83k
              allocation_group_block_number,
390
4.83k
              relative_sub_block_number,
391
4.83k
              relative_inode_number,
392
4.83k
              recursion_depth + 1,
393
4.83k
              error );
394
395
4.83k
    if( result == -1 )
396
4.77k
    {
397
4.77k
      libcerror_error_set(
398
4.77k
       error,
399
4.77k
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
400
4.77k
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
401
4.77k
       "%s: unable to retrieve inode from node.",
402
4.77k
       function );
403
404
4.77k
      return( -1 );
405
4.77k
    }
406
4.83k
  }
407
#if defined( HAVE_DEBUG_OUTPUT )
408
  else if( libcnotify_verbose != 0 )
409
  {
410
    libcnotify_printf(
411
     "\n" );
412
  }
413
#endif
414
102
  return( result );
415
4.88k
}
416
417
/* Retrieves the inode from the inode B+ tree leaf node
418
 * Returns 1 if successful or -1 on error
419
 */
420
int libfsxfs_inode_btree_get_inode_from_leaf_node(
421
     libfsxfs_inode_btree_t *inode_btree,
422
     uint16_t number_of_records,
423
     const uint8_t *records_data,
424
     size_t records_data_size,
425
     uint64_t inode_number,
426
     libcerror_error_t **error )
427
3.31k
{
428
3.31k
  libfsxfs_inode_btree_record_t *inode_btree_record = NULL;
429
3.31k
  static char *function                             = "libfsxfs_inode_btree_get_inode_from_leaf_node";
430
3.31k
  size_t records_data_offset                        = 0;
431
3.31k
  uint16_t record_index                             = 0;
432
3.31k
  int result                                        = 0;
433
434
3.31k
  if( inode_btree == NULL )
435
0
  {
436
0
    libcerror_error_set(
437
0
     error,
438
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
439
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
440
0
     "%s: invalid inode B+ tree.",
441
0
     function );
442
443
0
    return( -1 );
444
0
  }
445
3.31k
  if( records_data == NULL )
446
0
  {
447
0
    libcerror_error_set(
448
0
     error,
449
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
450
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
451
0
     "%s: invalid records data.",
452
0
     function );
453
454
0
    return( -1 );
455
0
  }
456
3.31k
  if( ( records_data_size == 0 )
457
3.31k
   || ( records_data_size > (size_t) SSIZE_MAX ) )
458
0
  {
459
0
    libcerror_error_set(
460
0
     error,
461
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
462
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
463
0
     "%s: invalid records data size value out of bounds.",
464
0
     function );
465
466
0
    return( -1 );
467
0
  }
468
3.31k
  if( (size_t) number_of_records > ( records_data_size / 16 ) )
469
21
  {
470
21
    libcerror_error_set(
471
21
     error,
472
21
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
473
21
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
474
21
     "%s: invalid number of records value out of bounds.",
475
21
     function );
476
477
21
    return( -1 );
478
21
  }
479
3.29k
  for( record_index = 0;
480
23.2k
       record_index < number_of_records;
481
19.9k
       record_index++ )
482
23.2k
  {
483
23.2k
    if( libfsxfs_inode_btree_record_initialize(
484
23.2k
         &inode_btree_record,
485
23.2k
         error ) != 1 )
486
0
    {
487
0
      libcerror_error_set(
488
0
       error,
489
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
490
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
491
0
       "%s: unable to create inode B+ tree record: %" PRIu16 ".",
492
0
       function,
493
0
       record_index );
494
495
0
      goto on_error;
496
0
    }
497
23.2k
    if( libfsxfs_inode_btree_record_read_data(
498
23.2k
         inode_btree_record,
499
23.2k
         &( records_data[ records_data_offset ] ),
500
23.2k
         16,
501
23.2k
         error ) != 1 )
502
0
    {
503
0
      libcerror_error_set(
504
0
       error,
505
0
       LIBCERROR_ERROR_DOMAIN_IO,
506
0
       LIBCERROR_IO_ERROR_READ_FAILED,
507
0
       "%s: unable to read inode B+ tree record: %" PRIu16 ".",
508
0
       function,
509
0
       record_index );
510
511
0
      goto on_error;
512
0
    }
513
23.2k
    records_data_offset += 16;
514
515
23.2k
    if( ( inode_number >= inode_btree_record->inode_number )
516
23.2k
     && ( inode_number < ( inode_btree_record->inode_number + 64 ) ) )
517
3.25k
    {
518
/* TODO check bitmap */
519
3.25k
      result = 1;
520
3.25k
    }
521
/* TODO cache records in block */
522
23.2k
    if( libfsxfs_inode_btree_record_free(
523
23.2k
         &inode_btree_record,
524
23.2k
         error ) != 1 )
525
0
    {
526
0
      libcerror_error_set(
527
0
       error,
528
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
529
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
530
0
       "%s: unable to free inode B+ tree record: %" PRIu16 ".",
531
0
       function,
532
0
       record_index );
533
534
0
      goto on_error;
535
0
    }
536
23.2k
    if( result != 0 )
537
3.25k
    {
538
3.25k
      break;
539
3.25k
    }
540
23.2k
  }
541
3.29k
  return( result );
542
543
0
on_error:
544
0
  if( inode_btree_record != NULL )
545
0
  {
546
0
    libfsxfs_inode_btree_record_free(
547
0
     &inode_btree_record,
548
0
     NULL );
549
0
  }
550
0
  return( -1 );
551
3.29k
}
552
553
/* Retrieves the inode from the inode B+ tree node
554
 * Returns 1 if successful or -1 on error
555
 */
556
int libfsxfs_inode_btree_get_inode_from_node(
557
     libfsxfs_inode_btree_t *inode_btree,
558
     libfsxfs_io_handle_t *io_handle,
559
     libbfio_handle_t *file_io_handle,
560
     uint64_t allocation_group_block_number,
561
     uint64_t relative_block_number,
562
     uint64_t relative_inode_number,
563
     int recursion_depth,
564
     libcerror_error_t **error )
565
8.49k
{
566
8.49k
  libfsxfs_btree_block_t *btree_block = NULL;
567
8.49k
  static char *function               = "libfsxfs_inode_btree_get_inode_from_node";
568
8.49k
  off64_t btree_block_offset          = 0;
569
8.49k
  int compare_result                  = 0;
570
8.49k
  int result                          = 0;
571
572
8.49k
  if( inode_btree == 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 inode B+ tree.",
579
0
     function );
580
581
0
    return( -1 );
582
0
  }
583
8.49k
  if( io_handle == NULL )
584
0
  {
585
0
    libcerror_error_set(
586
0
     error,
587
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
588
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
589
0
     "%s: invalid IO handle.",
590
0
     function );
591
592
0
    return( -1 );
593
0
  }
594
8.49k
  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
8.49k
  if( allocation_group_block_number > (uint64_t) ( INT64_MAX / io_handle->block_size ) )
606
0
  {
607
0
    libcerror_error_set(
608
0
     error,
609
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
610
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
611
0
     "%s: invalid allocation group block number value out of bounds.",
612
0
     function );
613
614
0
    return( -1 );
615
0
  }
616
8.49k
  if( relative_block_number > ( (uint64_t) ( INT64_MAX / io_handle->block_size ) - allocation_group_block_number ) )
617
0
  {
618
0
    libcerror_error_set(
619
0
     error,
620
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
621
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
622
0
     "%s: invalid relative block number value out of bounds.",
623
0
     function );
624
625
0
    return( -1 );
626
0
  }
627
8.49k
  btree_block_offset = ( allocation_group_block_number + relative_block_number ) * io_handle->block_size;
628
629
8.49k
  if( libfsxfs_btree_block_initialize(
630
8.49k
       &btree_block,
631
8.49k
       io_handle->block_size,
632
8.49k
       4,
633
8.49k
       error ) != 1 )
634
0
  {
635
0
    libcerror_error_set(
636
0
     error,
637
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
638
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
639
0
     "%s: unable to create B+ tree block.",
640
0
     function );
641
642
0
    goto on_error;
643
0
  }
644
8.49k
  if( libfsxfs_btree_block_read_file_io_handle(
645
8.49k
       btree_block,
646
8.49k
       io_handle,
647
8.49k
       file_io_handle,
648
8.49k
       btree_block_offset,
649
8.49k
       error ) != 1 )
650
184
  {
651
184
    libcerror_error_set(
652
184
     error,
653
184
     LIBCERROR_ERROR_DOMAIN_IO,
654
184
     LIBCERROR_IO_ERROR_READ_FAILED,
655
184
     "%s: unable to read inode B+ tree block: %" PRIu32 " at offset: %" PRIi64 " (0x%08" PRIx64 ").",
656
184
     function,
657
184
     relative_block_number,
658
184
     btree_block_offset,
659
184
     btree_block_offset );
660
661
184
    goto on_error;
662
184
  }
663
8.30k
  if( io_handle->format_version == 5 )
664
3.51k
  {
665
3.51k
    compare_result = memory_compare(
666
3.51k
                      btree_block->header->signature,
667
3.51k
                      "IAB3",
668
3.51k
                      4 );
669
3.51k
  }
670
4.79k
  else
671
4.79k
  {
672
4.79k
    compare_result = memory_compare(
673
4.79k
                      btree_block->header->signature,
674
4.79k
                      "IABT",
675
4.79k
                      4 );
676
4.79k
  }
677
8.30k
  if( compare_result != 0 )
678
67
  {
679
67
    libcerror_error_set(
680
67
     error,
681
67
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
682
67
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
683
67
     "%s: unsupported block signature.",
684
67
     function );
685
686
67
    goto on_error;
687
67
  }
688
/* TODO
689
  if( btree_block->header->level > inode_btree->maximum_depth )
690
  {
691
    libcerror_error_set(
692
     error,
693
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
694
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
695
     "%s: unsupported B+ tree node level.",
696
     function );
697
698
    goto on_error;
699
  }
700
*/
701
8.24k
  if( btree_block->header->level == 0 )
702
3.31k
  {
703
3.31k
    result = libfsxfs_inode_btree_get_inode_from_leaf_node(
704
3.31k
              inode_btree,
705
3.31k
              btree_block->header->number_of_records,
706
3.31k
              btree_block->records_data,
707
3.31k
              btree_block->records_data_size,
708
3.31k
              relative_inode_number,
709
3.31k
              error );
710
711
3.31k
    if( result == -1 )
712
21
    {
713
21
      libcerror_error_set(
714
21
       error,
715
21
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
716
21
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
717
21
       "%s: unable to retrieve inode from leaf node.",
718
21
       function );
719
720
21
      goto on_error;
721
21
    }
722
3.31k
  }
723
4.92k
  else
724
4.92k
  {
725
4.92k
    result = libfsxfs_inode_btree_get_inode_from_branch_node(
726
4.92k
              inode_btree,
727
4.92k
              io_handle,
728
4.92k
              file_io_handle,
729
4.92k
              allocation_group_block_number,
730
4.92k
              btree_block->header->number_of_records,
731
4.92k
              btree_block->records_data,
732
4.92k
              btree_block->records_data_size,
733
4.92k
              relative_inode_number,
734
4.92k
              recursion_depth,
735
4.92k
              error );
736
737
4.92k
    if( result == -1 )
738
4.82k
    {
739
4.82k
      libcerror_error_set(
740
4.82k
       error,
741
4.82k
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
742
4.82k
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
743
4.82k
       "%s: unable to retrieve inode from branch node.",
744
4.82k
       function );
745
746
4.82k
      goto on_error;
747
4.82k
    }
748
4.92k
  }
749
3.39k
  if( libfsxfs_btree_block_free(
750
3.39k
       &btree_block,
751
3.39k
       error ) != 1 )
752
0
  {
753
0
    libcerror_error_set(
754
0
     error,
755
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
756
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
757
0
     "%s: unable to free B+ tree block.",
758
0
     function );
759
760
0
    goto on_error;
761
0
  }
762
3.39k
  return( result );
763
764
5.09k
on_error:
765
5.09k
  if( btree_block != NULL )
766
5.09k
  {
767
5.09k
    libfsxfs_btree_block_free(
768
5.09k
     &btree_block,
769
5.09k
     NULL );
770
5.09k
  }
771
5.09k
  return( -1 );
772
3.39k
}
773
774
/* Retrieves a specific inode from the inode B+ tree
775
 * Returns 1 if successful, 0 if no such value or -1 on error
776
 */
777
int libfsxfs_inode_btree_get_inode_by_number(
778
     libfsxfs_inode_btree_t *inode_btree,
779
     libfsxfs_io_handle_t *io_handle,
780
     libbfio_handle_t *file_io_handle,
781
     uint64_t absolute_inode_number,
782
     off64_t *file_offset,
783
     libcerror_error_t **error )
784
3.92k
{
785
3.92k
  libfsxfs_inode_information_t *inode_information = NULL;
786
3.92k
  static char *function                           = "libfsxfs_inode_btree_get_inode_by_number";
787
3.92k
  uint64_t allocation_group_block_number          = 0;
788
3.92k
  uint64_t relative_inode_number                  = 0;
789
3.92k
  int allocation_group_index                      = 0;
790
3.92k
  int result                                      = 0;
791
792
3.92k
  if( inode_btree == NULL )
793
0
  {
794
0
    libcerror_error_set(
795
0
     error,
796
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
797
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
798
0
     "%s: invalid inode B+ tree.",
799
0
     function );
800
801
0
    return( -1 );
802
0
  }
803
3.92k
  if( io_handle == NULL )
804
0
  {
805
0
    libcerror_error_set(
806
0
     error,
807
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
808
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
809
0
     "%s: invalid IO handle.",
810
0
     function );
811
812
0
    return( -1 );
813
0
  }
814
3.92k
  if( io_handle->allocation_group_size == 0 )
815
0
  {
816
0
    libcerror_error_set(
817
0
     error,
818
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
819
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
820
0
     "%s: invalid IO handle - allocation group size value out of bounds.",
821
0
     function );
822
823
0
    return( -1 );
824
0
  }
825
3.92k
  if( io_handle->block_size == 0 )
826
0
  {
827
0
    libcerror_error_set(
828
0
     error,
829
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
830
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
831
0
     "%s: invalid IO handle - block size value out of bounds.",
832
0
     function );
833
834
0
    return( -1 );
835
0
  }
836
3.92k
  if( file_offset == NULL )
837
0
  {
838
0
    libcerror_error_set(
839
0
     error,
840
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
841
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
842
0
     "%s: invalid file offset.",
843
0
     function );
844
845
0
    return( -1 );
846
0
  }
847
3.92k
  allocation_group_index = (int) ( absolute_inode_number >> io_handle->number_of_relative_inode_number_bits );
848
3.92k
  relative_inode_number  = absolute_inode_number & ( ( (uint64_t) 1 << io_handle->number_of_relative_inode_number_bits ) - 1 );
849
850
#if defined( HAVE_DEBUG_OUTPUT )
851
  if( libcnotify_verbose != 0 )
852
  {
853
    libcnotify_printf(
854
     "%s: allocation group index\t: %d\n",
855
     function,
856
     allocation_group_index );
857
858
    libcnotify_printf(
859
     "%s: relative inode number\t\t: %" PRIu64 "\n",
860
     function,
861
     relative_inode_number );
862
863
    libcnotify_printf(
864
     "\n" );
865
  }
866
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
867
868
3.92k
  if( libcdata_array_get_entry_by_index(
869
3.92k
       inode_btree->inode_information_array,
870
3.92k
       allocation_group_index,
871
3.92k
       (intptr_t **) &inode_information,
872
3.92k
       error ) != 1 )
873
268
  {
874
268
    libcerror_error_set(
875
268
     error,
876
268
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
877
268
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
878
268
     "%s: unable to retrieve inode information: %d.",
879
268
     function,
880
268
     allocation_group_index );
881
882
268
    return( -1 );
883
268
  }
884
3.66k
  allocation_group_block_number = (uint64_t) allocation_group_index * io_handle->allocation_group_size;
885
886
3.66k
  if( inode_information == NULL )
887
0
  {
888
0
    libcerror_error_set(
889
0
     error,
890
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
891
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
892
0
     "%s: missing inode information.",
893
0
     function );
894
895
0
    return( -1 );
896
0
  }
897
3.66k
  result = libfsxfs_inode_btree_get_inode_from_node(
898
3.66k
            inode_btree,
899
3.66k
            io_handle,
900
3.66k
            file_io_handle,
901
3.66k
            allocation_group_block_number,
902
3.66k
            inode_information->inode_btree_root_block_number,
903
3.66k
            relative_inode_number,
904
3.66k
            0,
905
3.66k
            error );
906
907
3.66k
  if( result == -1 )
908
316
  {
909
316
    libcerror_error_set(
910
316
     error,
911
316
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
912
316
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
913
316
     "%s: unable to retrieve inode: %" PRIu64 " from root node: %" PRIu32 ".",
914
316
     function,
915
316
     relative_inode_number,
916
316
     inode_information->inode_btree_root_block_number );
917
918
316
    return( -1 );
919
316
  }
920
3.34k
  else if( result != 0 )
921
3.25k
  {
922
3.25k
    *file_offset = ( (off64_t) allocation_group_block_number * io_handle->block_size ) + ( (off64_t) relative_inode_number * io_handle->inode_size );
923
3.25k
  }
924
3.34k
  return( result );
925
3.66k
}
926