Coverage Report

Created: 2026-04-04 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsapfs/libfsapfs/libfsapfs_object_map_btree.c
Line
Count
Source
1
/*
2
 * The object map B-tree functions
3
 *
4
 * Copyright (C) 2018-2025, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsapfs_btree_entry.h"
28
#include "libfsapfs_btree_node.h"
29
#include "libfsapfs_data_block.h"
30
#include "libfsapfs_definitions.h"
31
#include "libfsapfs_io_handle.h"
32
#include "libfsapfs_libbfio.h"
33
#include "libfsapfs_libcerror.h"
34
#include "libfsapfs_libcnotify.h"
35
#include "libfsapfs_libfcache.h"
36
#include "libfsapfs_libfdata.h"
37
#include "libfsapfs_object_map_btree.h"
38
#include "libfsapfs_object_map_descriptor.h"
39
40
#include "fsapfs_object.h"
41
#include "fsapfs_object_map.h"
42
43
/* Creates a object map B-tree
44
 * Make sure the value object_map_btree is referencing, is set to NULL
45
 * Returns 1 if successful or -1 on error
46
 */
47
int libfsapfs_object_map_btree_initialize(
48
     libfsapfs_object_map_btree_t **object_map_btree,
49
     libfsapfs_io_handle_t *io_handle,
50
     libfdata_vector_t *data_block_vector,
51
     uint64_t root_node_block_number,
52
     libcerror_error_t **error )
53
13.0k
{
54
13.0k
  static char *function = "libfsapfs_object_map_btree_initialize";
55
56
13.0k
  if( object_map_btree == NULL )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
61
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
62
0
     "%s: invalid object map B-tree.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
13.0k
  if( *object_map_btree != NULL )
68
0
  {
69
0
    libcerror_error_set(
70
0
     error,
71
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
72
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
73
0
     "%s: invalid object map B-tree value already set.",
74
0
     function );
75
76
0
    return( -1 );
77
0
  }
78
13.0k
  *object_map_btree = memory_allocate_structure(
79
13.0k
                       libfsapfs_object_map_btree_t );
80
81
13.0k
  if( *object_map_btree == NULL )
82
0
  {
83
0
    libcerror_error_set(
84
0
     error,
85
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
86
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
87
0
     "%s: unable to create object map B-tree.",
88
0
     function );
89
90
0
    goto on_error;
91
0
  }
92
13.0k
  if( memory_set(
93
13.0k
       *object_map_btree,
94
13.0k
       0,
95
13.0k
       sizeof( libfsapfs_object_map_btree_t ) ) == NULL )
96
0
  {
97
0
    libcerror_error_set(
98
0
     error,
99
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
100
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
101
0
     "%s: unable to clear object map B-tree.",
102
0
     function );
103
104
0
    memory_free(
105
0
     *object_map_btree );
106
107
0
    *object_map_btree = NULL;
108
109
0
    return( -1 );
110
0
  }
111
13.0k
  if( libfcache_cache_initialize(
112
13.0k
       &( ( *object_map_btree )->data_block_cache ),
113
13.0k
       LIBFSAPFS_MAXIMUM_CACHE_ENTRIES_DATA_BLOCKS,
114
13.0k
       error ) != 1 )
115
0
  {
116
0
    libcerror_error_set(
117
0
     error,
118
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
119
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
120
0
     "%s: unable to create data block cache.",
121
0
     function );
122
123
0
    goto on_error;
124
0
  }
125
13.0k
  if( libfcache_cache_initialize(
126
13.0k
       &( ( *object_map_btree )->node_cache ),
127
13.0k
       LIBFSAPFS_MAXIMUM_CACHE_ENTRIES_BTREE_NODES,
128
13.0k
       error ) != 1 )
129
0
  {
130
0
    libcerror_error_set(
131
0
     error,
132
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
133
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
134
0
     "%s: unable to create node cache.",
135
0
     function );
136
137
0
    goto on_error;
138
0
  }
139
13.0k
  ( *object_map_btree )->io_handle              = io_handle;
140
13.0k
  ( *object_map_btree )->data_block_vector      = data_block_vector;
141
13.0k
  ( *object_map_btree )->root_node_block_number = root_node_block_number;
142
143
13.0k
  return( 1 );
144
145
0
on_error:
146
0
  if( *object_map_btree != NULL )
147
0
  {
148
0
    memory_free(
149
0
     *object_map_btree );
150
151
0
    *object_map_btree = NULL;
152
0
  }
153
0
  return( -1 );
154
13.0k
}
155
156
/* Frees a object map B-tree
157
 * Returns 1 if successful or -1 on error
158
 */
159
int libfsapfs_object_map_btree_free(
160
     libfsapfs_object_map_btree_t **object_map_btree,
161
     libcerror_error_t **error )
162
13.0k
{
163
13.0k
  static char *function = "libfsapfs_object_map_btree_free";
164
13.0k
  int result            = 1;
165
166
13.0k
  if( object_map_btree == NULL )
167
0
  {
168
0
    libcerror_error_set(
169
0
     error,
170
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
171
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
172
0
     "%s: invalid object map B-tree.",
173
0
     function );
174
175
0
    return( -1 );
176
0
  }
177
13.0k
  if( *object_map_btree != NULL )
178
13.0k
  {
179
    /* The data_block_vector is referenced and freed elsewhere
180
     */
181
13.0k
    if( libfcache_cache_free(
182
13.0k
         &( ( *object_map_btree )->node_cache ),
183
13.0k
         error ) != 1 )
184
0
    {
185
0
      libcerror_error_set(
186
0
       error,
187
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
188
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
189
0
       "%s: unable to free node cache.",
190
0
       function );
191
192
0
      result = -1;
193
0
    }
194
13.0k
    if( libfcache_cache_free(
195
13.0k
         &( ( *object_map_btree )->data_block_cache ),
196
13.0k
         error ) != 1 )
197
0
    {
198
0
      libcerror_error_set(
199
0
       error,
200
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
201
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
202
0
       "%s: unable to free data block cache.",
203
0
       function );
204
205
0
      result = -1;
206
0
    }
207
13.0k
    memory_free(
208
13.0k
     *object_map_btree );
209
210
13.0k
    *object_map_btree = NULL;
211
13.0k
  }
212
13.0k
  return( result );
213
13.0k
}
214
215
/* Retrieves the object map B-tree root node
216
 * Returns 1 if successful or -1 on error
217
 */
218
int libfsapfs_object_map_btree_get_root_node(
219
     libfsapfs_object_map_btree_t *object_map_btree,
220
     libbfio_handle_t *file_io_handle,
221
     uint64_t root_node_block_number,
222
     libfsapfs_btree_node_t **root_node,
223
     libcerror_error_t **error )
224
13.0k
{
225
13.0k
  libfcache_cache_value_t *cache_value = NULL;
226
13.0k
  libfsapfs_btree_node_t *node         = NULL;
227
13.0k
  libfsapfs_data_block_t *data_block   = NULL;
228
13.0k
  static char *function                = "libfsapfs_object_map_btree_get_root_node";
229
13.0k
  int result                           = 0;
230
231
#if defined( HAVE_PROFILER )
232
  int64_t profiler_start_timestamp     = 0;
233
#endif
234
235
13.0k
  if( object_map_btree == NULL )
236
0
  {
237
0
    libcerror_error_set(
238
0
     error,
239
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
240
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
241
0
     "%s: invalid object map B-tree.",
242
0
     function );
243
244
0
    return( -1 );
245
0
  }
246
13.0k
  if( root_node_block_number > (uint64_t) INT_MAX )
247
204
  {
248
204
    libcerror_error_set(
249
204
     error,
250
204
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
251
204
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
252
204
     "%s: invalid root node block number value out of bounds.",
253
204
     function );
254
255
204
    return( -1 );
256
204
  }
257
12.8k
  if( root_node == NULL )
258
0
  {
259
0
    libcerror_error_set(
260
0
     error,
261
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
262
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
263
0
     "%s: invalid root node.",
264
0
     function );
265
266
0
    return( -1 );
267
0
  }
268
#if defined( HAVE_PROFILER )
269
  if( object_map_btree->io_handle->profiler != NULL )
270
  {
271
    if( libfsapfs_profiler_start_timing(
272
         object_map_btree->io_handle->profiler,
273
         &profiler_start_timestamp,
274
         error ) != 1 )
275
    {
276
      libcerror_error_set(
277
       error,
278
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
279
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
280
       "%s: unable to start timing.",
281
       function );
282
283
      goto on_error;
284
    }
285
  }
286
#endif /* defined( HAVE_PROFILER ) */
287
288
12.8k
  result = libfcache_cache_get_value_by_identifier(
289
12.8k
            object_map_btree->node_cache,
290
12.8k
            0,
291
12.8k
            (off64_t) root_node_block_number,
292
12.8k
            0,
293
12.8k
            &cache_value,
294
12.8k
            error );
295
296
12.8k
  if( result == -1 )
297
0
  {
298
0
    libcerror_error_set(
299
0
     error,
300
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
301
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
302
0
     "%s: unable to retrieve value from cache.",
303
0
     function );
304
305
0
    goto on_error;
306
0
  }
307
12.8k
  else if( result == 0 )
308
11.3k
  {
309
11.3k
    if( libfdata_vector_get_element_value_by_index(
310
11.3k
         object_map_btree->data_block_vector,
311
11.3k
         (intptr_t *) file_io_handle,
312
11.3k
         (libfdata_cache_t *) object_map_btree->data_block_cache,
313
11.3k
         (int) root_node_block_number,
314
11.3k
         (intptr_t **) &data_block,
315
11.3k
         0,
316
11.3k
         error ) != 1 )
317
383
    {
318
383
      libcerror_error_set(
319
383
       error,
320
383
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
321
383
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
322
383
       "%s: unable to retrieve data block: %" PRIu64 ".",
323
383
       function,
324
383
       root_node_block_number );
325
326
383
      goto on_error;
327
383
    }
328
10.9k
    if( data_block == NULL )
329
0
    {
330
0
      libcerror_error_set(
331
0
       error,
332
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
333
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
334
0
       "%s: invalid data block: %" PRIu64 ".",
335
0
       function,
336
0
       root_node_block_number );
337
338
0
      goto on_error;
339
0
    }
340
10.9k
    if( libfsapfs_btree_node_initialize(
341
10.9k
         &node,
342
10.9k
         error ) != 1 )
343
0
    {
344
0
      libcerror_error_set(
345
0
       error,
346
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
347
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
348
0
       "%s: unable to create B-tree node.",
349
0
       function );
350
351
0
      goto on_error;
352
0
    }
353
10.9k
    if( libfsapfs_btree_node_read_data(
354
10.9k
         node,
355
10.9k
         data_block->data,
356
10.9k
         data_block->data_size,
357
10.9k
         error ) != 1 )
358
651
    {
359
651
      libcerror_error_set(
360
651
       error,
361
651
       LIBCERROR_ERROR_DOMAIN_IO,
362
651
       LIBCERROR_IO_ERROR_READ_FAILED,
363
651
       "%s: unable to read B-tree node.",
364
651
       function );
365
366
651
      goto on_error;
367
651
    }
368
10.2k
    if( node->object_type != 0x40000002UL )
369
111
    {
370
111
      libcerror_error_set(
371
111
       error,
372
111
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
373
111
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
374
111
       "%s: invalid object type: 0x%08" PRIx32 ".",
375
111
       function,
376
111
       node->object_type );
377
378
111
      goto on_error;
379
111
    }
380
10.1k
    if( node->object_subtype != 0x0000000bUL )
381
164
    {
382
164
      libcerror_error_set(
383
164
       error,
384
164
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
385
164
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
386
164
       "%s: invalid object subtype: 0x%08" PRIx32 ".",
387
164
       function,
388
164
       node->object_subtype );
389
390
164
      goto on_error;
391
164
    }
392
10.0k
    if( ( ( node->node_header->flags & 0x0001 ) == 0 )
393
10.0k
     || ( ( node->node_header->flags & 0x0004 ) == 0 ) )
394
7
    {
395
7
      libcerror_error_set(
396
7
       error,
397
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
398
7
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
399
7
       "%s: unsupported flags: 0x%04" PRIx16 ".",
400
7
       function,
401
7
       node->node_header->flags );
402
403
7
      goto on_error;
404
7
    }
405
9.99k
    if( node->footer->node_size != 4096 )
406
108
    {
407
108
      libcerror_error_set(
408
108
       error,
409
108
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
410
108
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
411
108
       "%s: invalid node size value out of bounds.",
412
108
       function );
413
414
108
      goto on_error;
415
108
    }
416
9.89k
    if( node->footer->key_size != sizeof( fsapfs_object_map_btree_key_t ) )
417
127
    {
418
127
      libcerror_error_set(
419
127
       error,
420
127
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
421
127
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
422
127
       "%s: invalid key size value out of bounds.",
423
127
       function );
424
425
127
      goto on_error;
426
127
    }
427
9.76k
    if( node->footer->value_size != sizeof( fsapfs_object_map_btree_value_t ) )
428
154
    {
429
154
      libcerror_error_set(
430
154
       error,
431
154
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
432
154
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
433
154
       "%s: invalid value size value out of bounds.",
434
154
       function );
435
436
154
      goto on_error;
437
154
    }
438
9.61k
    if( libfcache_cache_set_value_by_identifier(
439
9.61k
         object_map_btree->node_cache,
440
9.61k
         0,
441
9.61k
         (off64_t) root_node_block_number,
442
9.61k
         0,
443
9.61k
         (intptr_t *) node,
444
9.61k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_node_free,
445
9.61k
         LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
446
9.61k
         error ) != 1 )
447
0
    {
448
0
      libcerror_error_set(
449
0
       error,
450
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
451
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
452
0
       "%s: unable to set value in cache.",
453
0
       function );
454
455
0
      goto on_error;
456
0
    }
457
9.61k
    node = NULL;
458
459
9.61k
    if( libfcache_cache_get_value_by_identifier(
460
9.61k
         object_map_btree->node_cache,
461
9.61k
         0,
462
9.61k
         (off64_t) root_node_block_number,
463
9.61k
         0,
464
9.61k
         &cache_value,
465
9.61k
         error ) != 1 )
466
0
    {
467
0
      libcerror_error_set(
468
0
       error,
469
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
470
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
471
0
       "%s: unable to retrieve value from cache.",
472
0
       function );
473
474
0
      goto on_error;
475
0
    }
476
9.61k
  }
477
#if defined( HAVE_PROFILER )
478
  if( object_map_btree->io_handle->profiler != NULL )
479
  {
480
    if( libfsapfs_profiler_stop_timing(
481
         object_map_btree->io_handle->profiler,
482
         profiler_start_timestamp,
483
         function,
484
         root_node_block_number * object_map_btree->io_handle->block_size,
485
         object_map_btree->io_handle->block_size,
486
         error ) != 1 )
487
    {
488
      libcerror_error_set(
489
       error,
490
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
491
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
492
       "%s: unable to stop timing.",
493
       function );
494
495
      goto on_error;
496
    }
497
  }
498
#endif /* defined( HAVE_PROFILER ) */
499
500
11.0k
  if( libfcache_cache_value_get_value(
501
11.0k
       cache_value,
502
11.0k
       (intptr_t **) root_node,
503
11.0k
       error ) != 1 )
504
0
  {
505
0
    libcerror_error_set(
506
0
     error,
507
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
508
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
509
0
     "%s: unable to retrieve root node.",
510
0
     function );
511
512
0
    goto on_error;
513
0
  }
514
11.0k
  return( 1 );
515
516
1.70k
on_error:
517
1.70k
  if( node != NULL )
518
1.32k
  {
519
1.32k
    libfsapfs_btree_node_free(
520
1.32k
     &node,
521
1.32k
     NULL );
522
1.32k
  }
523
1.70k
  return( -1 );
524
11.0k
}
525
526
/* Retrieves a object map B-tree sub node
527
 * Returns 1 if successful or -1 on error
528
 */
529
int libfsapfs_object_map_btree_get_sub_node(
530
     libfsapfs_object_map_btree_t *object_map_btree,
531
     libbfio_handle_t *file_io_handle,
532
     uint64_t sub_node_block_number,
533
     libfsapfs_btree_node_t **sub_node,
534
     libcerror_error_t **error )
535
3.74k
{
536
3.74k
  libfcache_cache_value_t *cache_value = NULL;
537
3.74k
  libfsapfs_btree_node_t *node         = NULL;
538
3.74k
  libfsapfs_data_block_t *data_block   = NULL;
539
3.74k
  static char *function                = "libfsapfs_object_map_btree_get_sub_node";
540
3.74k
  int result                           = 0;
541
542
#if defined( HAVE_PROFILER )
543
  int64_t profiler_start_timestamp     = 0;
544
#endif
545
546
3.74k
  if( object_map_btree == NULL )
547
0
  {
548
0
    libcerror_error_set(
549
0
     error,
550
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
551
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
552
0
     "%s: invalid object map B-tree.",
553
0
     function );
554
555
0
    return( -1 );
556
0
  }
557
3.74k
  if( sub_node_block_number > (uint64_t) INT_MAX )
558
525
  {
559
525
    libcerror_error_set(
560
525
     error,
561
525
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
562
525
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
563
525
     "%s: invalid sub node block number value out of bounds.",
564
525
     function );
565
566
525
    return( -1 );
567
525
  }
568
3.21k
  if( sub_node == NULL )
569
0
  {
570
0
    libcerror_error_set(
571
0
     error,
572
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
573
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
574
0
     "%s: invalid sub node.",
575
0
     function );
576
577
0
    return( -1 );
578
0
  }
579
#if defined( HAVE_PROFILER )
580
  if( object_map_btree->io_handle->profiler != NULL )
581
  {
582
    if( libfsapfs_profiler_start_timing(
583
         object_map_btree->io_handle->profiler,
584
         &profiler_start_timestamp,
585
         error ) != 1 )
586
    {
587
      libcerror_error_set(
588
       error,
589
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
590
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
591
       "%s: unable to start timing.",
592
       function );
593
594
      goto on_error;
595
    }
596
  }
597
#endif /* defined( HAVE_PROFILER ) */
598
599
3.21k
  result = libfcache_cache_get_value_by_identifier(
600
3.21k
            object_map_btree->node_cache,
601
3.21k
            0,
602
3.21k
            (off64_t) sub_node_block_number,
603
3.21k
            0,
604
3.21k
            &cache_value,
605
3.21k
            error );
606
607
3.21k
  if( result == -1 )
608
0
  {
609
0
    libcerror_error_set(
610
0
     error,
611
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
612
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
613
0
     "%s: unable to retrieve value from cache.",
614
0
     function );
615
616
0
    goto on_error;
617
0
  }
618
3.21k
  else if( result == 0 )
619
392
  {
620
392
    if( libfdata_vector_get_element_value_by_index(
621
392
         object_map_btree->data_block_vector,
622
392
         (intptr_t *) file_io_handle,
623
392
         (libfdata_cache_t *) object_map_btree->data_block_cache,
624
392
         (int) sub_node_block_number,
625
392
         (intptr_t **) &data_block,
626
392
         0,
627
392
         error ) != 1 )
628
189
    {
629
189
      libcerror_error_set(
630
189
       error,
631
189
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
632
189
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
633
189
       "%s: unable to retrieve data block: %" PRIu64 ".",
634
189
       function,
635
189
       sub_node_block_number );
636
637
189
      goto on_error;
638
189
    }
639
203
    if( data_block == NULL )
640
0
    {
641
0
      libcerror_error_set(
642
0
       error,
643
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
644
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
645
0
       "%s: invalid data block: %" PRIu64 ".",
646
0
       function,
647
0
       sub_node_block_number );
648
649
0
      goto on_error;
650
0
    }
651
203
    if( libfsapfs_btree_node_initialize(
652
203
         &node,
653
203
         error ) != 1 )
654
0
    {
655
0
      libcerror_error_set(
656
0
       error,
657
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
658
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
659
0
       "%s: unable to create B-tree node.",
660
0
       function );
661
662
0
      goto on_error;
663
0
    }
664
203
    if( libfsapfs_btree_node_read_data(
665
203
         node,
666
203
         data_block->data,
667
203
         data_block->data_size,
668
203
         error ) != 1 )
669
57
    {
670
57
      libcerror_error_set(
671
57
       error,
672
57
       LIBCERROR_ERROR_DOMAIN_IO,
673
57
       LIBCERROR_IO_ERROR_READ_FAILED,
674
57
       "%s: unable to read B-tree node.",
675
57
       function );
676
677
57
      goto on_error;
678
57
    }
679
146
    if( node->object_type != 0x40000003UL )
680
49
    {
681
49
      libcerror_error_set(
682
49
       error,
683
49
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
684
49
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
685
49
       "%s: invalid object type: 0x%08" PRIx32 ".",
686
49
       function,
687
49
       node->object_type );
688
689
49
      goto on_error;
690
49
    }
691
97
    if( node->object_subtype != 0x0000000bUL )
692
87
    {
693
87
      libcerror_error_set(
694
87
       error,
695
87
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
696
87
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
697
87
       "%s: invalid object subtype: 0x%08" PRIx32 ".",
698
87
       function,
699
87
       node->object_subtype );
700
701
87
      goto on_error;
702
87
    }
703
10
    if( ( ( node->node_header->flags & 0x0001 ) != 0 )
704
7
     || ( ( node->node_header->flags & 0x0004 ) == 0 ) )
705
6
    {
706
6
      libcerror_error_set(
707
6
       error,
708
6
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
709
6
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
710
6
       "%s: unsupported flags: 0x%04" PRIx16 ".",
711
6
       function,
712
6
       node->node_header->flags );
713
714
6
      goto on_error;
715
6
    }
716
4
    if( libfcache_cache_set_value_by_identifier(
717
4
         object_map_btree->node_cache,
718
4
         0,
719
4
         (off64_t) sub_node_block_number,
720
4
         0,
721
4
         (intptr_t *) node,
722
4
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_node_free,
723
4
         LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
724
4
         error ) != 1 )
725
0
    {
726
0
      libcerror_error_set(
727
0
       error,
728
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
729
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
730
0
       "%s: unable to set value in cache.",
731
0
       function );
732
733
0
      goto on_error;
734
0
    }
735
4
    node = NULL;
736
737
4
    if( libfcache_cache_get_value_by_identifier(
738
4
         object_map_btree->node_cache,
739
4
         0,
740
4
         (off64_t) sub_node_block_number,
741
4
         0,
742
4
         &cache_value,
743
4
         error ) != 1 )
744
0
    {
745
0
      libcerror_error_set(
746
0
       error,
747
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
748
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
749
0
       "%s: unable to retrieve value from cache.",
750
0
       function );
751
752
0
      goto on_error;
753
0
    }
754
4
  }
755
#if defined( HAVE_PROFILER )
756
  if( object_map_btree->io_handle->profiler != NULL )
757
  {
758
    if( libfsapfs_profiler_stop_timing(
759
         object_map_btree->io_handle->profiler,
760
         profiler_start_timestamp,
761
         function,
762
         sub_node_block_number * object_map_btree->io_handle->block_size,
763
         object_map_btree->io_handle->block_size,
764
         error ) != 1 )
765
    {
766
      libcerror_error_set(
767
       error,
768
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
769
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
770
       "%s: unable to stop timing.",
771
       function );
772
773
      goto on_error;
774
    }
775
  }
776
#endif /* defined( HAVE_PROFILER ) */
777
778
2.83k
  if( libfcache_cache_value_get_value(
779
2.83k
       cache_value,
780
2.83k
       (intptr_t **) sub_node,
781
2.83k
       error ) != 1 )
782
0
  {
783
0
    libcerror_error_set(
784
0
     error,
785
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
786
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
787
0
     "%s: unable to retrieve sub node.",
788
0
     function );
789
790
0
    goto on_error;
791
0
  }
792
2.83k
  return( 1 );
793
794
388
on_error:
795
388
  if( node != NULL )
796
199
  {
797
199
    libfsapfs_btree_node_free(
798
199
     &node,
799
199
     NULL );
800
199
  }
801
388
  return( -1 );
802
2.83k
}
803
804
/* Retrieves an entry for a specific identifier from the object map B-tree node
805
 * Returns 1 if successful, 0 if not found or -1 on error
806
 */
807
int libfsapfs_object_map_btree_get_entry_from_node_by_identifier(
808
     libfsapfs_object_map_btree_t *object_map_btree,
809
     libfsapfs_btree_node_t *node,
810
     uint64_t object_identifier,
811
     uint64_t transaction_identifier,
812
     libfsapfs_btree_entry_t **btree_entry,
813
     libcerror_error_t **error )
814
13.9k
{
815
13.9k
  libfsapfs_btree_entry_t *entry          = NULL;
816
13.9k
  libfsapfs_btree_entry_t *previous_entry = NULL;
817
13.9k
  static char *function                   = "libfsapfs_object_map_btree_get_entry_from_node_by_identifier";
818
13.9k
  uint64_t object_map_identifier          = 0;
819
13.9k
  uint64_t object_map_transaction         = 0;
820
13.9k
  uint64_t previous_object_map_identifier = 0;
821
13.9k
  int btree_entry_index                   = 0;
822
13.9k
  int is_leaf_node                        = 0;
823
13.9k
  int number_of_entries                   = 0;
824
825
13.9k
  if( object_map_btree == NULL )
826
0
  {
827
0
    libcerror_error_set(
828
0
     error,
829
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
830
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
831
0
     "%s: invalid object map B-tree.",
832
0
     function );
833
834
0
    return( -1 );
835
0
  }
836
13.9k
  if( btree_entry == 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 B-tree entry.",
843
0
     function );
844
845
0
    return( -1 );
846
0
  }
847
#if defined( HAVE_DEBUG_OUTPUT )
848
  if( libcnotify_verbose != 0 )
849
  {
850
    libcnotify_printf(
851
     "%s: retrieving B-tree entry identifier: %" PRIu64 " (transaction: %" PRIu64 ").\n",
852
     function,
853
     object_identifier,
854
     transaction_identifier );
855
  }
856
#endif
857
13.9k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
858
13.9k
                  node,
859
13.9k
                  error );
860
861
13.9k
  if( is_leaf_node == -1 )
862
0
  {
863
0
    libcerror_error_set(
864
0
     error,
865
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
866
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
867
0
     "%s: unable to determine if B-tree node is a leaf node.",
868
0
     function );
869
870
0
    return( -1 );
871
0
  }
872
13.9k
  if( libfsapfs_btree_node_get_number_of_entries(
873
13.9k
       node,
874
13.9k
       &number_of_entries,
875
13.9k
       error ) != 1 )
876
0
  {
877
0
    libcerror_error_set(
878
0
     error,
879
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
880
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
881
0
     "%s: unable to retrieve number of entries from B-tree node.",
882
0
     function );
883
884
0
    return( -1 );
885
0
  }
886
13.9k
  for( btree_entry_index = 0;
887
50.3k
       btree_entry_index < number_of_entries;
888
36.4k
       btree_entry_index++ )
889
39.2k
  {
890
39.2k
    if( libfsapfs_btree_node_get_entry_by_index(
891
39.2k
         node,
892
39.2k
         btree_entry_index,
893
39.2k
         &entry,
894
39.2k
         error ) != 1 )
895
0
    {
896
0
      libcerror_error_set(
897
0
       error,
898
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
899
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
900
0
       "%s: unable to retrieve number of entries from B-tree node.",
901
0
       function );
902
903
0
      return( -1 );
904
0
    }
905
39.2k
    if( entry == NULL )
906
0
    {
907
0
      libcerror_error_set(
908
0
       error,
909
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
910
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
911
0
       "%s: invalid B-tree entry: %d.",
912
0
       function,
913
0
       btree_entry_index );
914
915
0
      return( -1 );
916
0
    }
917
39.2k
    if( entry->key_data == NULL )
918
0
    {
919
0
      libcerror_error_set(
920
0
       error,
921
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
922
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
923
0
       "%s: invalid B-tree entry: %d - missing key data.",
924
0
       function,
925
0
       btree_entry_index );
926
927
0
      return( -1 );
928
0
    }
929
39.2k
    if( entry->key_data_size < 16 )
930
0
    {
931
0
      libcerror_error_set(
932
0
       error,
933
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
934
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
935
0
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
936
0
       function,
937
0
       btree_entry_index );
938
939
0
      return( -1 );
940
0
    }
941
39.2k
    byte_stream_copy_to_uint64_little_endian(
942
39.2k
     &( entry->key_data[ 0 ] ),
943
39.2k
     object_map_identifier );
944
945
39.2k
    byte_stream_copy_to_uint64_little_endian(
946
39.2k
     &( entry->key_data[ 8 ] ),
947
39.2k
     object_map_transaction );
948
949
#if defined( HAVE_DEBUG_OUTPUT )
950
    if( libcnotify_verbose != 0 )
951
    {
952
      libcnotify_printf(
953
       "%s: B-tree entry: %d, identifier: %" PRIu64 " (transaction: %" PRIu64 ")\n",
954
       function,
955
       btree_entry_index,
956
       object_map_identifier,
957
       object_map_transaction );
958
    }
959
#endif
960
39.2k
    if( object_map_identifier > object_identifier )
961
2.11k
    {
962
2.11k
      break;
963
2.11k
    }
964
37.1k
    else if( ( object_map_identifier == object_identifier )
965
21.3k
          && ( object_map_transaction > transaction_identifier ) )
966
707
    {
967
707
      break;
968
707
    }
969
36.4k
    previous_entry                 = entry;
970
36.4k
    previous_object_map_identifier = object_map_identifier;
971
36.4k
  }
972
13.9k
  if( is_leaf_node != 0 )
973
10.1k
  {
974
10.1k
    if( previous_object_map_identifier == object_identifier )
975
9.76k
    {
976
9.76k
      *btree_entry = previous_entry;
977
978
9.76k
      return( 1 );
979
9.76k
    }
980
10.1k
  }
981
3.75k
  else
982
3.75k
  {
983
3.75k
    if( ( previous_entry == NULL )
984
3.66k
     || ( ( object_map_identifier == object_identifier )
985
970
      &&  ( object_map_transaction <= transaction_identifier ) ) )
986
413
    {
987
413
      previous_entry = entry;
988
413
    }
989
3.75k
    *btree_entry = previous_entry;
990
991
3.75k
    return( 1 );
992
3.75k
  }
993
401
  return( 0 );
994
13.9k
}
995
996
/* Retrieves an entry for a specific identifier from the object map B-tree
997
 * Returns 1 if successful, 0 if not found or -1 on error
998
 */
999
int libfsapfs_object_map_btree_get_entry_by_identifier(
1000
     libfsapfs_object_map_btree_t *object_map_btree,
1001
     libbfio_handle_t *file_io_handle,
1002
     uint64_t object_identifier,
1003
     uint64_t transaction_identifier,
1004
     libfsapfs_btree_node_t **btree_node,
1005
     libfsapfs_btree_entry_t **btree_entry,
1006
     libcerror_error_t **error )
1007
13.0k
{
1008
13.0k
  libfsapfs_btree_entry_t *entry = NULL;
1009
13.0k
  libfsapfs_btree_node_t *node   = NULL;
1010
13.0k
  static char *function          = "libfsapfs_object_map_btree_get_entry_by_identifier";
1011
13.0k
  uint64_t sub_node_block_number = 0;
1012
13.0k
  int is_leaf_node               = 0;
1013
13.0k
  int recursion_depth            = 0;
1014
13.0k
  int result                     = 0;
1015
1016
13.0k
  if( object_map_btree == NULL )
1017
0
  {
1018
0
    libcerror_error_set(
1019
0
     error,
1020
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1021
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1022
0
     "%s: invalid object map B-tree.",
1023
0
     function );
1024
1025
0
    return( -1 );
1026
0
  }
1027
13.0k
  if( btree_node == NULL )
1028
0
  {
1029
0
    libcerror_error_set(
1030
0
     error,
1031
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1032
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1033
0
     "%s: invalid B-tree node.",
1034
0
     function );
1035
1036
0
    return( -1 );
1037
0
  }
1038
13.0k
  if( btree_entry == NULL )
1039
0
  {
1040
0
    libcerror_error_set(
1041
0
     error,
1042
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1043
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1044
0
     "%s: invalid B-tree entry.",
1045
0
     function );
1046
1047
0
    return( -1 );
1048
0
  }
1049
13.0k
  if( libfsapfs_object_map_btree_get_root_node(
1050
13.0k
       object_map_btree,
1051
13.0k
       file_io_handle,
1052
13.0k
       object_map_btree->root_node_block_number,
1053
13.0k
       &node,
1054
13.0k
       error ) != 1 )
1055
1.90k
  {
1056
1.90k
    libcerror_error_set(
1057
1.90k
     error,
1058
1.90k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1059
1.90k
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1060
1.90k
     "%s: unable to retrieve B-tree root node.",
1061
1.90k
     function );
1062
1063
1.90k
    return( -1 );
1064
1.90k
  }
1065
11.0k
  do
1066
13.9k
  {
1067
13.9k
    if( ( recursion_depth < 0 )
1068
13.9k
     || ( recursion_depth > LIBFSAPFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1069
11
    {
1070
11
      libcerror_error_set(
1071
11
       error,
1072
11
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1073
11
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1074
11
       "%s: invalid recursion depth value out of bounds.",
1075
11
       function );
1076
1077
11
      return( -1 );
1078
11
    }
1079
13.9k
    is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1080
13.9k
                    node,
1081
13.9k
                    error );
1082
1083
13.9k
    if( is_leaf_node == -1 )
1084
0
    {
1085
0
      libcerror_error_set(
1086
0
       error,
1087
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1088
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1089
0
       "%s: unable to determine if B-tree node is a leaf node.",
1090
0
       function );
1091
1092
0
      return( -1 );
1093
0
    }
1094
13.9k
    result = libfsapfs_object_map_btree_get_entry_from_node_by_identifier(
1095
13.9k
              object_map_btree,
1096
13.9k
              node,
1097
13.9k
              object_identifier,
1098
13.9k
              transaction_identifier,
1099
13.9k
              &entry,
1100
13.9k
              error );
1101
1102
13.9k
    if( result == -1 )
1103
0
    {
1104
0
      libcerror_error_set(
1105
0
       error,
1106
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1107
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1108
0
       "%s: unable to retrieve entry from B-tree node.",
1109
0
       function );
1110
1111
0
      return( -1 );
1112
0
    }
1113
13.9k
    else if( result == 0 )
1114
401
    {
1115
401
      break;
1116
401
    }
1117
13.5k
    if( is_leaf_node != 0 )
1118
9.76k
    {
1119
9.76k
      *btree_node  = node;
1120
9.76k
      *btree_entry = entry;
1121
1122
9.76k
      return( 1 );
1123
9.76k
    }
1124
3.75k
    if( entry == NULL )
1125
7
    {
1126
7
      libcerror_error_set(
1127
7
       error,
1128
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1129
7
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1130
7
       "%s: invalid B-tree entry.",
1131
7
       function );
1132
1133
7
      return( -1 );
1134
7
    }
1135
3.74k
    if( entry->value_data == NULL )
1136
0
    {
1137
0
      libcerror_error_set(
1138
0
       error,
1139
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1140
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1141
0
       "%s: invalid B-tree entry - missing value data.",
1142
0
       function );
1143
1144
0
      return( -1 );
1145
0
    }
1146
3.74k
    if( entry->value_data_size != 8 )
1147
0
    {
1148
0
      libcerror_error_set(
1149
0
       error,
1150
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1151
0
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1152
0
       "%s: invalid B-tree entry - unsupported value data size.",
1153
0
       function );
1154
1155
0
      return( -1 );
1156
0
    }
1157
3.74k
    byte_stream_copy_to_uint64_little_endian(
1158
3.74k
     entry->value_data,
1159
3.74k
     sub_node_block_number );
1160
1161
#if defined( HAVE_DEBUG_OUTPUT )
1162
    if( libcnotify_verbose != 0 )
1163
    {
1164
      libcnotify_printf(
1165
       "%s: B-tree sub node block number: %" PRIu64 "\n",
1166
       function,
1167
       sub_node_block_number );
1168
    }
1169
#endif
1170
3.74k
    node = NULL;
1171
1172
3.74k
    if( libfsapfs_object_map_btree_get_sub_node(
1173
3.74k
         object_map_btree,
1174
3.74k
         file_io_handle,
1175
3.74k
         sub_node_block_number,
1176
3.74k
         &node,
1177
3.74k
         error ) != 1 )
1178
913
    {
1179
913
      libcerror_error_set(
1180
913
       error,
1181
913
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1182
913
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1183
913
       "%s: unable to retrieve B-tree sub node from block: %" PRIu64 ".",
1184
913
       function,
1185
913
       sub_node_block_number );
1186
1187
913
      return( -1 );
1188
913
    }
1189
2.83k
    recursion_depth++;
1190
2.83k
  }
1191
11.0k
  while( is_leaf_node == 0 );
1192
1193
401
  return( 0 );
1194
11.0k
}
1195
1196
/* Retrieves the object map descriptor of a specific object identifier
1197
 * Returns 1 if successful, 0 if no such value or -1 on error
1198
 */
1199
int libfsapfs_object_map_btree_get_descriptor_by_object_identifier(
1200
     libfsapfs_object_map_btree_t *object_map_btree,
1201
     libbfio_handle_t *file_io_handle,
1202
     uint64_t object_identifier,
1203
     uint64_t transaction_identifier,
1204
     libfsapfs_object_map_descriptor_t **descriptor,
1205
     libcerror_error_t **error )
1206
13.0k
{
1207
13.0k
  libfsapfs_btree_entry_t *entry                     = NULL;
1208
13.0k
  libfsapfs_btree_node_t *node                       = NULL;
1209
13.0k
  libfsapfs_object_map_descriptor_t *safe_descriptor = NULL;
1210
13.0k
  static char *function                              = "libfsapfs_object_map_btree_get_descriptor_by_object_identifier";
1211
13.0k
  int result                                         = 0;
1212
1213
13.0k
  if( object_map_btree == NULL )
1214
0
  {
1215
0
    libcerror_error_set(
1216
0
     error,
1217
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1218
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1219
0
     "%s: invalid object map B-tree.",
1220
0
     function );
1221
1222
0
    return( -1 );
1223
0
  }
1224
13.0k
  if( descriptor == NULL )
1225
0
  {
1226
0
    libcerror_error_set(
1227
0
     error,
1228
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1229
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1230
0
     "%s: invalid descriptor.",
1231
0
     function );
1232
1233
0
    return( -1 );
1234
0
  }
1235
13.0k
  if( *descriptor != NULL )
1236
0
  {
1237
0
    libcerror_error_set(
1238
0
     error,
1239
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1240
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1241
0
     "%s: invalid descriptor value already set.",
1242
0
     function );
1243
1244
0
    return( -1 );
1245
0
  }
1246
13.0k
  result = libfsapfs_object_map_btree_get_entry_by_identifier(
1247
13.0k
            object_map_btree,
1248
13.0k
            file_io_handle,
1249
13.0k
            object_identifier,
1250
13.0k
            transaction_identifier,
1251
13.0k
            &node,
1252
13.0k
            &entry,
1253
13.0k
            error );
1254
1255
13.0k
  if( result == -1 )
1256
2.84k
  {
1257
2.84k
    libcerror_error_set(
1258
2.84k
     error,
1259
2.84k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1260
2.84k
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1261
2.84k
     "%s: unable to retrieve entry from B-tree.",
1262
2.84k
     function );
1263
1264
2.84k
    goto on_error;
1265
2.84k
  }
1266
10.1k
  else if( result != 0 )
1267
9.76k
  {
1268
9.76k
    if( node == NULL )
1269
0
    {
1270
0
      libcerror_error_set(
1271
0
       error,
1272
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1273
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1274
0
       "%s: invalid B-tree node.",
1275
0
       function );
1276
1277
0
      goto on_error;
1278
0
    }
1279
9.76k
    if( entry == NULL )
1280
12
    {
1281
12
      libcerror_error_set(
1282
12
       error,
1283
12
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1284
12
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1285
12
       "%s: invalid B-tree entry.",
1286
12
       function );
1287
1288
12
      goto on_error;
1289
12
    }
1290
9.75k
    if( libfsapfs_object_map_descriptor_initialize(
1291
9.75k
         &safe_descriptor,
1292
9.75k
         error ) != 1 )
1293
0
    {
1294
0
      libcerror_error_set(
1295
0
       error,
1296
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1297
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1298
0
       "%s: unable to create object map descriptor.",
1299
0
       function );
1300
1301
0
      goto on_error;
1302
0
    }
1303
9.75k
    if( libfsapfs_object_map_descriptor_read_key_data(
1304
9.75k
         safe_descriptor,
1305
9.75k
         entry->key_data,
1306
9.75k
         (size_t) entry->key_data_size,
1307
9.75k
         error ) != 1 )
1308
0
    {
1309
0
      libcerror_error_set(
1310
0
       error,
1311
0
       LIBCERROR_ERROR_DOMAIN_IO,
1312
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1313
0
       "%s: unable to read object map descriptor key data.",
1314
0
       function );
1315
1316
0
      goto on_error;
1317
0
    }
1318
9.75k
    if( libfsapfs_object_map_descriptor_read_value_data(
1319
9.75k
         safe_descriptor,
1320
9.75k
         entry->value_data,
1321
9.75k
         (size_t) entry->value_data_size,
1322
9.75k
         error ) != 1 )
1323
0
    {
1324
0
      libcerror_error_set(
1325
0
       error,
1326
0
       LIBCERROR_ERROR_DOMAIN_IO,
1327
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1328
0
       "%s: unable to read object map descriptor value data.",
1329
0
       function );
1330
1331
0
      goto on_error;
1332
0
    }
1333
9.75k
    node = NULL;
1334
9.75k
  }
1335
10.1k
  *descriptor = safe_descriptor;
1336
1337
10.1k
  return( result );
1338
1339
2.85k
on_error:
1340
2.85k
  if( safe_descriptor != NULL )
1341
0
  {
1342
0
    libfsapfs_object_map_descriptor_free(
1343
0
     &safe_descriptor,
1344
     NULL );
1345
0
  }
1346
2.85k
  return( -1 );
1347
13.0k
}
1348