Coverage Report

Created: 2025-06-13 07:22

/src/libfsapfs/libfsapfs/libfsapfs_snapshot_metadata_tree.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The snapshot metadata tree functions
3
 *
4
 * Copyright (C) 2018-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 <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_debug.h"
31
#include "libfsapfs_definitions.h"
32
#include "libfsapfs_io_handle.h"
33
#include "libfsapfs_libbfio.h"
34
#include "libfsapfs_libcerror.h"
35
#include "libfsapfs_libcnotify.h"
36
#include "libfsapfs_libfcache.h"
37
#include "libfsapfs_libfdata.h"
38
#include "libfsapfs_object_map_btree.h"
39
#include "libfsapfs_object_map_descriptor.h"
40
#include "libfsapfs_snapshot_metadata.h"
41
#include "libfsapfs_snapshot_metadata_tree.h"
42
43
#include "fsapfs_object.h"
44
#include "fsapfs_snapshot_metadata.h"
45
46
/* Creates a snapshot metadata tree
47
 * Make sure the value snapshot_metadata_tree is referencing, is set to NULL
48
 * Returns 1 if successful or -1 on error
49
 */
50
int libfsapfs_snapshot_metadata_tree_initialize(
51
     libfsapfs_snapshot_metadata_tree_t **snapshot_metadata_tree,
52
     libfsapfs_io_handle_t *io_handle,
53
     libfdata_vector_t *data_block_vector,
54
     libfsapfs_object_map_btree_t *object_map_btree,
55
     uint64_t root_node_block_number,
56
     libcerror_error_t **error )
57
4.52k
{
58
4.52k
  static char *function = "libfsapfs_snapshot_metadata_tree_initialize";
59
60
4.52k
  if( snapshot_metadata_tree == NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
65
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
66
0
     "%s: invalid snapshot metadata tree.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
4.52k
  if( *snapshot_metadata_tree != NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
76
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
77
0
     "%s: invalid snapshot metadata tree value already set.",
78
0
     function );
79
80
0
    return( -1 );
81
0
  }
82
4.52k
  *snapshot_metadata_tree = memory_allocate_structure(
83
4.52k
                             libfsapfs_snapshot_metadata_tree_t );
84
85
4.52k
  if( *snapshot_metadata_tree == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91
0
     "%s: unable to create snapshot metadata tree.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
4.52k
  if( memory_set(
97
4.52k
       *snapshot_metadata_tree,
98
4.52k
       0,
99
4.52k
       sizeof( libfsapfs_snapshot_metadata_tree_t ) ) == NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
104
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
105
0
     "%s: unable to clear snapshot metadata tree.",
106
0
     function );
107
108
0
    memory_free(
109
0
     *snapshot_metadata_tree );
110
111
0
    *snapshot_metadata_tree = NULL;
112
113
0
    return( -1 );
114
0
  }
115
4.52k
  if( libfcache_cache_initialize(
116
4.52k
       &( ( *snapshot_metadata_tree )->data_block_cache ),
117
4.52k
       LIBFSAPFS_MAXIMUM_CACHE_ENTRIES_DATA_BLOCKS,
118
4.52k
       error ) != 1 )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
123
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
124
0
     "%s: unable to create data block cache.",
125
0
     function );
126
127
0
    goto on_error;
128
0
  }
129
4.52k
  if( libfcache_cache_initialize(
130
4.52k
       &( ( *snapshot_metadata_tree )->node_cache ),
131
4.52k
       LIBFSAPFS_MAXIMUM_CACHE_ENTRIES_BTREE_NODES,
132
4.52k
       error ) != 1 )
133
0
  {
134
0
    libcerror_error_set(
135
0
     error,
136
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
137
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
138
0
     "%s: unable to create node cache.",
139
0
     function );
140
141
0
    goto on_error;
142
0
  }
143
4.52k
  ( *snapshot_metadata_tree )->io_handle              = io_handle;
144
4.52k
  ( *snapshot_metadata_tree )->data_block_vector      = data_block_vector;
145
4.52k
  ( *snapshot_metadata_tree )->object_map_btree       = object_map_btree;
146
4.52k
  ( *snapshot_metadata_tree )->root_node_block_number = root_node_block_number;
147
148
4.52k
  return( 1 );
149
150
0
on_error:
151
0
  if( *snapshot_metadata_tree != NULL )
152
0
  {
153
0
    memory_free(
154
0
     *snapshot_metadata_tree );
155
156
0
    *snapshot_metadata_tree = NULL;
157
0
  }
158
0
  return( -1 );
159
4.52k
}
160
161
/* Frees a snapshot metadata tree
162
 * Returns 1 if successful or -1 on error
163
 */
164
int libfsapfs_snapshot_metadata_tree_free(
165
     libfsapfs_snapshot_metadata_tree_t **snapshot_metadata_tree,
166
     libcerror_error_t **error )
167
4.52k
{
168
4.52k
  static char *function = "libfsapfs_snapshot_metadata_tree_free";
169
4.52k
  int result            = 1;
170
171
4.52k
  if( snapshot_metadata_tree == NULL )
172
0
  {
173
0
    libcerror_error_set(
174
0
     error,
175
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
176
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
177
0
     "%s: invalid snapshot metadata tree.",
178
0
     function );
179
180
0
    return( -1 );
181
0
  }
182
4.52k
  if( *snapshot_metadata_tree != NULL )
183
4.52k
  {
184
    /* The data_block_vector is referenced and freed elsewhere
185
     */
186
4.52k
    if( libfcache_cache_free(
187
4.52k
         &( ( *snapshot_metadata_tree )->node_cache ),
188
4.52k
         error ) != 1 )
189
0
    {
190
0
      libcerror_error_set(
191
0
       error,
192
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
193
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
194
0
       "%s: unable to free node cache.",
195
0
       function );
196
197
0
      result = -1;
198
0
    }
199
4.52k
    if( libfcache_cache_free(
200
4.52k
         &( ( *snapshot_metadata_tree )->data_block_cache ),
201
4.52k
         error ) != 1 )
202
0
    {
203
0
      libcerror_error_set(
204
0
       error,
205
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
206
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
207
0
       "%s: unable to free data block cache.",
208
0
       function );
209
210
0
      result = -1;
211
0
    }
212
4.52k
    memory_free(
213
4.52k
     *snapshot_metadata_tree );
214
215
4.52k
    *snapshot_metadata_tree = NULL;
216
4.52k
  }
217
4.52k
  return( result );
218
4.52k
}
219
220
/* Retrieves the sub node block number from a B-tree entry
221
 * Returns 1 if successful, 0 if not found or -1 on error
222
 */
223
int libfsapfs_snapshot_metadata_tree_get_sub_node_block_number_from_entry(
224
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
225
     libbfio_handle_t *file_io_handle,
226
     libfsapfs_btree_entry_t *entry,
227
     uint64_t transaction_identifier,
228
     uint64_t *sub_node_block_number,
229
     libcerror_error_t **error )
230
1.63k
{
231
1.63k
  libfsapfs_object_map_descriptor_t *object_map_descriptor = NULL;
232
1.63k
  static char *function                                    = "libfsapfs_snapshot_metadata_tree_get_sub_node_block_number_from_entry";
233
1.63k
  uint64_t sub_node_object_identifier                      = 0;
234
1.63k
  int result                                               = 0;
235
236
1.63k
  if( snapshot_metadata_tree == NULL )
237
0
  {
238
0
    libcerror_error_set(
239
0
     error,
240
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
241
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
242
0
     "%s: invalid snapshot metadata tree.",
243
0
     function );
244
245
0
    return( -1 );
246
0
  }
247
1.63k
  if( entry == NULL )
248
0
  {
249
0
    libcerror_error_set(
250
0
     error,
251
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
252
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
253
0
     "%s: invalid B-tree entry.",
254
0
     function );
255
256
0
    return( -1 );
257
0
  }
258
1.63k
  if( entry->value_data == NULL )
259
10
  {
260
10
    libcerror_error_set(
261
10
     error,
262
10
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
263
10
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
264
10
     "%s: invalid B-tree entry - missing value data.",
265
10
     function );
266
267
10
    return( -1 );
268
10
  }
269
1.62k
  if( entry->value_data_size != 8 )
270
41
  {
271
41
    libcerror_error_set(
272
41
     error,
273
41
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
274
41
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
275
41
     "%s: invalid B-tree entry - unsupported value data size.",
276
41
     function );
277
278
41
    return( -1 );
279
41
  }
280
1.58k
  if( sub_node_block_number == NULL )
281
0
  {
282
0
    libcerror_error_set(
283
0
     error,
284
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
285
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
286
0
     "%s: invalid sub node block number.",
287
0
     function );
288
289
0
    return( -1 );
290
0
  }
291
1.58k
  byte_stream_copy_to_uint64_little_endian(
292
1.58k
   entry->value_data,
293
1.58k
   sub_node_object_identifier );
294
295
#if defined( HAVE_DEBUG_OUTPUT )
296
  if( libcnotify_verbose != 0 )
297
  {
298
    libcnotify_printf(
299
     "%s: sub node object identifier: %" PRIu64 " (transaction: %" PRIu64 ")\n",
300
     function,
301
     sub_node_object_identifier,
302
     transaction_identifier );
303
  }
304
#endif
305
1.58k
  result = libfsapfs_object_map_btree_get_descriptor_by_object_identifier(
306
1.58k
            snapshot_metadata_tree->object_map_btree,
307
1.58k
            file_io_handle,
308
1.58k
            sub_node_object_identifier,
309
1.58k
            transaction_identifier,
310
1.58k
            &object_map_descriptor,
311
1.58k
            error );
312
313
1.58k
  if( result == -1 )
314
163
  {
315
163
    libcerror_error_set(
316
163
     error,
317
163
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
318
163
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
319
163
     "%s: unable to retrieve object map descriptor for sub node object identifier: %" PRIu64 " (transaction: %" PRIu64 ").",
320
163
     function,
321
163
     sub_node_object_identifier,
322
163
     transaction_identifier );
323
324
163
    goto on_error;
325
163
  }
326
1.42k
  else if( result != 0 )
327
1.22k
  {
328
1.22k
    if( object_map_descriptor == 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 object map descriptor.",
335
0
       function );
336
337
0
      goto on_error;
338
0
    }
339
#if defined( HAVE_DEBUG_OUTPUT )
340
    if( libcnotify_verbose != 0 )
341
    {
342
      libcnotify_printf(
343
       "%s: sub node block number: %" PRIu64 "\n",
344
       function,
345
       object_map_descriptor->physical_address );
346
    }
347
#endif
348
1.22k
    *sub_node_block_number = object_map_descriptor->physical_address;
349
350
1.22k
    if( libfsapfs_object_map_descriptor_free(
351
1.22k
         &object_map_descriptor,
352
1.22k
         error ) != 1 )
353
0
    {
354
0
      libcerror_error_set(
355
0
       error,
356
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
357
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
358
0
       "%s: unable to free object map descriptor.",
359
0
       function );
360
361
0
      goto on_error;
362
0
    }
363
1.22k
  }
364
1.42k
  return( result );
365
366
163
on_error:
367
163
  if( object_map_descriptor != NULL )
368
0
  {
369
0
    libfsapfs_object_map_descriptor_free(
370
0
     &object_map_descriptor,
371
0
     NULL );
372
0
  }
373
163
  return( -1 );
374
1.58k
}
375
376
/* Retrieves the snapshot metadata tree root node
377
 * Returns 1 if successful or -1 on error
378
 */
379
int libfsapfs_snapshot_metadata_tree_get_root_node(
380
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
381
     libbfio_handle_t *file_io_handle,
382
     uint64_t root_node_block_number,
383
     libfsapfs_btree_node_t **root_node,
384
     libcerror_error_t **error )
385
4.52k
{
386
4.52k
  libfcache_cache_value_t *cache_value = NULL;
387
4.52k
  libfsapfs_btree_node_t *node         = NULL;
388
4.52k
  libfsapfs_data_block_t *data_block   = NULL;
389
4.52k
  static char *function                = "libfsapfs_snapshot_metadata_tree_get_root_node";
390
4.52k
  int result                           = 0;
391
392
#if defined( HAVE_PROFILER )
393
  int64_t profiler_start_timestamp     = 0;
394
#endif
395
396
4.52k
  if( snapshot_metadata_tree == NULL )
397
0
  {
398
0
    libcerror_error_set(
399
0
     error,
400
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
401
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
402
0
     "%s: invalid snapshot metadata tree.",
403
0
     function );
404
405
0
    return( -1 );
406
0
  }
407
4.52k
  if( root_node_block_number > (uint64_t) INT_MAX )
408
132
  {
409
132
    libcerror_error_set(
410
132
     error,
411
132
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
412
132
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
413
132
     "%s: invalid root node block number value out of bounds.",
414
132
     function );
415
416
132
    return( -1 );
417
132
  }
418
4.38k
  if( root_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 root node.",
425
0
     function );
426
427
0
    return( -1 );
428
0
  }
429
#if defined( HAVE_PROFILER )
430
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
431
  {
432
    if( libfsapfs_profiler_start_timing(
433
         snapshot_metadata_tree->io_handle->profiler,
434
         &profiler_start_timestamp,
435
         error ) != 1 )
436
    {
437
      libcerror_error_set(
438
       error,
439
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
440
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
441
       "%s: unable to start timing.",
442
       function );
443
444
      goto on_error;
445
    }
446
  }
447
#endif /* defined( HAVE_PROFILER ) */
448
449
4.38k
  result = libfcache_cache_get_value_by_identifier(
450
4.38k
            snapshot_metadata_tree->node_cache,
451
4.38k
            0,
452
4.38k
            (off64_t) root_node_block_number,
453
4.38k
            0,
454
4.38k
            &cache_value,
455
4.38k
            error );
456
457
4.38k
  if( result == -1 )
458
0
  {
459
0
    libcerror_error_set(
460
0
     error,
461
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
462
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
463
0
     "%s: unable to retrieve value from cache.",
464
0
     function );
465
466
0
    goto on_error;
467
0
  }
468
4.38k
  else if( result == 0 )
469
4.38k
  {
470
4.38k
    if( libfdata_vector_get_element_value_by_index(
471
4.38k
         snapshot_metadata_tree->data_block_vector,
472
4.38k
         (intptr_t *) file_io_handle,
473
4.38k
         (libfdata_cache_t *) snapshot_metadata_tree->data_block_cache,
474
4.38k
         (int) root_node_block_number,
475
4.38k
         (intptr_t **) &data_block,
476
4.38k
         0,
477
4.38k
         error ) != 1 )
478
34
    {
479
34
      libcerror_error_set(
480
34
       error,
481
34
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
482
34
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
483
34
       "%s: unable to retrieve data block: %" PRIu64 ".",
484
34
       function,
485
34
       root_node_block_number );
486
487
34
      goto on_error;
488
34
    }
489
4.35k
    if( data_block == NULL )
490
0
    {
491
0
      libcerror_error_set(
492
0
       error,
493
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
494
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
495
0
       "%s: invalid data block: %" PRIu64 ".",
496
0
       function,
497
0
       root_node_block_number );
498
499
0
      goto on_error;
500
0
    }
501
4.35k
    if( libfsapfs_btree_node_initialize(
502
4.35k
         &node,
503
4.35k
         error ) != 1 )
504
0
    {
505
0
      libcerror_error_set(
506
0
       error,
507
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
508
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
509
0
       "%s: unable to create B-tree node.",
510
0
       function );
511
512
0
      goto on_error;
513
0
    }
514
4.35k
    if( libfsapfs_btree_node_read_data(
515
4.35k
         node,
516
4.35k
         data_block->data,
517
4.35k
         data_block->data_size,
518
4.35k
         error ) != 1 )
519
27
    {
520
27
      libcerror_error_set(
521
27
       error,
522
27
       LIBCERROR_ERROR_DOMAIN_IO,
523
27
       LIBCERROR_IO_ERROR_READ_FAILED,
524
27
       "%s: unable to read B-tree node.",
525
27
       function );
526
527
27
      goto on_error;
528
27
    }
529
4.32k
    if( node->object_type != 0x40000002UL )
530
57
    {
531
57
      libcerror_error_set(
532
57
       error,
533
57
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
534
57
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
535
57
       "%s: invalid object type: 0x%08" PRIx32 ".",
536
57
       function,
537
57
       node->object_type );
538
539
57
      goto on_error;
540
57
    }
541
4.27k
    if( node->object_subtype != 0x00000010UL )
542
145
    {
543
145
      libcerror_error_set(
544
145
       error,
545
145
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
546
145
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
547
145
       "%s: invalid object subtype: 0x%08" PRIx32 ".",
548
145
       function,
549
145
       node->object_subtype );
550
551
145
      goto on_error;
552
145
    }
553
4.12k
    if( ( node->node_header->flags & 0x0001 ) == 0 )
554
6
    {
555
6
      libcerror_error_set(
556
6
       error,
557
6
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
558
6
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
559
6
       "%s: unsupported flags: 0x%04" PRIx16 ".",
560
6
       function,
561
6
       node->node_header->flags );
562
563
6
      goto on_error;
564
6
    }
565
4.12k
    if( node->footer->node_size != 4096 )
566
159
    {
567
159
      libcerror_error_set(
568
159
       error,
569
159
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
570
159
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
571
159
       "%s: invalid node size value out of bounds.",
572
159
       function );
573
574
159
      goto on_error;
575
159
    }
576
3.96k
    if( node->footer->key_size != 0 )
577
128
    {
578
128
      libcerror_error_set(
579
128
       error,
580
128
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
581
128
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
582
128
       "%s: invalid key size value out of bounds.",
583
128
       function );
584
585
128
      goto on_error;
586
128
    }
587
3.83k
    if( node->footer->value_size != 0 )
588
138
    {
589
138
      libcerror_error_set(
590
138
       error,
591
138
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
592
138
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
593
138
       "%s: invalid value size value out of bounds.",
594
138
       function );
595
596
138
      goto on_error;
597
138
    }
598
3.69k
    if( libfcache_cache_set_value_by_identifier(
599
3.69k
         snapshot_metadata_tree->node_cache,
600
3.69k
         0,
601
3.69k
         (off64_t) root_node_block_number,
602
3.69k
         0,
603
3.69k
         (intptr_t *) node,
604
3.69k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_node_free,
605
3.69k
         LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
606
3.69k
         error ) != 1 )
607
0
    {
608
0
      libcerror_error_set(
609
0
       error,
610
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
611
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
612
0
       "%s: unable to set value in cache.",
613
0
       function );
614
615
0
      goto on_error;
616
0
    }
617
3.69k
    node = NULL;
618
619
3.69k
    if( libfcache_cache_get_value_by_identifier(
620
3.69k
         snapshot_metadata_tree->node_cache,
621
3.69k
         0,
622
3.69k
         (off64_t) root_node_block_number,
623
3.69k
         0,
624
3.69k
         &cache_value,
625
3.69k
         error ) != 1 )
626
0
    {
627
0
      libcerror_error_set(
628
0
       error,
629
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
630
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
631
0
       "%s: unable to retrieve value from cache.",
632
0
       function );
633
634
0
      goto on_error;
635
0
    }
636
3.69k
  }
637
#if defined( HAVE_PROFILER )
638
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
639
  {
640
    if( libfsapfs_profiler_stop_timing(
641
         snapshot_metadata_tree->io_handle->profiler,
642
         profiler_start_timestamp,
643
         function,
644
         root_node_block_number * snapshot_metadata_tree->io_handle->block_size,
645
         snapshot_metadata_tree->io_handle->block_size,
646
         error ) != 1 )
647
    {
648
      libcerror_error_set(
649
       error,
650
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
651
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
652
       "%s: unable to stop timing.",
653
       function );
654
655
      goto on_error;
656
    }
657
  }
658
#endif /* defined( HAVE_PROFILER ) */
659
660
3.69k
  if( libfcache_cache_value_get_value(
661
3.69k
       cache_value,
662
3.69k
       (intptr_t **) root_node,
663
3.69k
       error ) != 1 )
664
0
  {
665
0
    libcerror_error_set(
666
0
     error,
667
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
668
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
669
0
     "%s: unable to retrieve root node.",
670
0
     function );
671
672
0
    goto on_error;
673
0
  }
674
3.69k
  return( 1 );
675
676
694
on_error:
677
694
  if( node != NULL )
678
660
  {
679
660
    libfsapfs_btree_node_free(
680
660
     &node,
681
660
     NULL );
682
660
  }
683
694
  return( -1 );
684
3.69k
}
685
686
/* Retrieves a snapshot metadata tree sub node
687
 * Returns 1 if successful or -1 on error
688
 */
689
int libfsapfs_snapshot_metadata_tree_get_sub_node(
690
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
691
     libbfio_handle_t *file_io_handle,
692
     uint64_t sub_node_block_number,
693
     libfsapfs_btree_node_t **sub_node,
694
     libcerror_error_t **error )
695
1.22k
{
696
1.22k
  libfcache_cache_value_t *cache_value = NULL;
697
1.22k
  libfsapfs_btree_node_t *node         = NULL;
698
1.22k
  libfsapfs_data_block_t *data_block   = NULL;
699
1.22k
  static char *function                = "libfsapfs_snapshot_metadata_tree_get_sub_node";
700
1.22k
  int result                           = 0;
701
702
#if defined( HAVE_PROFILER )
703
  int64_t profiler_start_timestamp     = 0;
704
#endif
705
706
1.22k
  if( snapshot_metadata_tree == NULL )
707
0
  {
708
0
    libcerror_error_set(
709
0
     error,
710
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
711
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
712
0
     "%s: invalid snapshot metadata tree.",
713
0
     function );
714
715
0
    return( -1 );
716
0
  }
717
1.22k
  if( sub_node_block_number > (uint64_t) INT_MAX )
718
132
  {
719
132
    libcerror_error_set(
720
132
     error,
721
132
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
722
132
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
723
132
     "%s: invalid sub node block number value out of bounds.",
724
132
     function );
725
726
132
    return( -1 );
727
132
  }
728
1.08k
  if( sub_node == NULL )
729
0
  {
730
0
    libcerror_error_set(
731
0
     error,
732
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
733
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
734
0
     "%s: invalid sub node.",
735
0
     function );
736
737
0
    return( -1 );
738
0
  }
739
#if defined( HAVE_PROFILER )
740
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
741
  {
742
    if( libfsapfs_profiler_start_timing(
743
         snapshot_metadata_tree->io_handle->profiler,
744
         &profiler_start_timestamp,
745
         error ) != 1 )
746
    {
747
      libcerror_error_set(
748
       error,
749
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
750
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
751
       "%s: unable to start timing.",
752
       function );
753
754
      goto on_error;
755
    }
756
  }
757
#endif /* defined( HAVE_PROFILER ) */
758
759
1.08k
  result = libfcache_cache_get_value_by_identifier(
760
1.08k
            snapshot_metadata_tree->node_cache,
761
1.08k
            0,
762
1.08k
            (off64_t) sub_node_block_number,
763
1.08k
            0,
764
1.08k
            &cache_value,
765
1.08k
            error );
766
767
1.08k
  if( result == -1 )
768
0
  {
769
0
    libcerror_error_set(
770
0
     error,
771
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
772
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
773
0
     "%s: unable to retrieve value from cache.",
774
0
     function );
775
776
0
    goto on_error;
777
0
  }
778
1.08k
  else if( result == 0 )
779
237
  {
780
237
    if( libfdata_vector_get_element_value_by_index(
781
237
         snapshot_metadata_tree->data_block_vector,
782
237
         (intptr_t *) file_io_handle,
783
237
         (libfdata_cache_t *) snapshot_metadata_tree->data_block_cache,
784
237
         (int) sub_node_block_number,
785
237
         (intptr_t **) &data_block,
786
237
         0,
787
237
         error ) != 1 )
788
57
    {
789
57
      libcerror_error_set(
790
57
       error,
791
57
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
792
57
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
793
57
       "%s: unable to retrieve data block: %" PRIu64 ".",
794
57
       function,
795
57
       sub_node_block_number );
796
797
57
      goto on_error;
798
57
    }
799
180
    if( data_block == NULL )
800
0
    {
801
0
      libcerror_error_set(
802
0
       error,
803
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
804
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
805
0
       "%s: invalid data block: %" PRIu64 ".",
806
0
       function,
807
0
       sub_node_block_number );
808
809
0
      goto on_error;
810
0
    }
811
180
    if( libfsapfs_btree_node_initialize(
812
180
         &node,
813
180
         error ) != 1 )
814
0
    {
815
0
      libcerror_error_set(
816
0
       error,
817
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
818
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
819
0
       "%s: unable to create B-tree node.",
820
0
       function );
821
822
0
      goto on_error;
823
0
    }
824
180
    if( libfsapfs_btree_node_read_data(
825
180
         node,
826
180
         data_block->data,
827
180
         data_block->data_size,
828
180
         error ) != 1 )
829
6
    {
830
6
      libcerror_error_set(
831
6
       error,
832
6
       LIBCERROR_ERROR_DOMAIN_IO,
833
6
       LIBCERROR_IO_ERROR_READ_FAILED,
834
6
       "%s: unable to read B-tree node.",
835
6
       function );
836
837
6
      goto on_error;
838
6
    }
839
174
    if( node->object_type != 0x40000003UL )
840
18
    {
841
18
      libcerror_error_set(
842
18
       error,
843
18
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
844
18
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
845
18
       "%s: invalid object type: 0x%08" PRIx32 ".",
846
18
       function,
847
18
       node->object_type );
848
849
18
      goto on_error;
850
18
    }
851
156
    if( node->object_subtype != 0x00000010UL )
852
106
    {
853
106
      libcerror_error_set(
854
106
       error,
855
106
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
856
106
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
857
106
       "%s: invalid object subtype: 0x%08" PRIx32 ".",
858
106
       function,
859
106
       node->object_subtype );
860
861
106
      goto on_error;
862
106
    }
863
50
    if( ( node->node_header->flags & 0x0001 ) != 0 )
864
3
    {
865
3
      libcerror_error_set(
866
3
       error,
867
3
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
868
3
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
869
3
       "%s: unsupported flags: 0x%04" PRIx16 ".",
870
3
       function,
871
3
       node->node_header->flags );
872
873
3
      goto on_error;
874
3
    }
875
47
    if( libfcache_cache_set_value_by_identifier(
876
47
         snapshot_metadata_tree->node_cache,
877
47
         0,
878
47
         (off64_t) sub_node_block_number,
879
47
         0,
880
47
         (intptr_t *) node,
881
47
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_node_free,
882
47
         LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
883
47
         error ) != 1 )
884
0
    {
885
0
      libcerror_error_set(
886
0
       error,
887
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
888
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
889
0
       "%s: unable to set value in cache.",
890
0
       function );
891
892
0
      goto on_error;
893
0
    }
894
47
    node = NULL;
895
896
47
    if( libfcache_cache_get_value_by_identifier(
897
47
         snapshot_metadata_tree->node_cache,
898
47
         0,
899
47
         (off64_t) sub_node_block_number,
900
47
         0,
901
47
         &cache_value,
902
47
         error ) != 1 )
903
0
    {
904
0
      libcerror_error_set(
905
0
       error,
906
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
907
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
908
0
       "%s: unable to retrieve value from cache.",
909
0
       function );
910
911
0
      goto on_error;
912
0
    }
913
47
  }
914
#if defined( HAVE_PROFILER )
915
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
916
  {
917
    if( libfsapfs_profiler_stop_timing(
918
         snapshot_metadata_tree->io_handle->profiler,
919
         profiler_start_timestamp,
920
         function,
921
         sub_node_block_number * snapshot_metadata_tree->io_handle->block_size,
922
         snapshot_metadata_tree->io_handle->block_size,
923
         error ) != 1 )
924
    {
925
      libcerror_error_set(
926
       error,
927
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
928
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
929
       "%s: unable to stop timing.",
930
       function );
931
932
      goto on_error;
933
    }
934
  }
935
#endif /* defined( HAVE_PROFILER ) */
936
937
899
  if( libfcache_cache_value_get_value(
938
899
       cache_value,
939
899
       (intptr_t **) sub_node,
940
899
       error ) != 1 )
941
0
  {
942
0
    libcerror_error_set(
943
0
     error,
944
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
945
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
946
0
     "%s: unable to retrieve sub node.",
947
0
     function );
948
949
0
    goto on_error;
950
0
  }
951
899
  return( 1 );
952
953
190
on_error:
954
190
  if( node != NULL )
955
133
  {
956
133
    libfsapfs_btree_node_free(
957
133
     &node,
958
133
     NULL );
959
133
  }
960
190
  return( -1 );
961
899
}
962
963
/* Retrieves an entry for a specific identifier from the snapshot metadata tree node
964
 * Returns 1 if successful, 0 if not found or -1 on error
965
 */
966
int libfsapfs_snapshot_metadata_tree_get_entry_from_node_by_identifier(
967
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
968
     libfsapfs_btree_node_t *node,
969
     uint64_t object_identifier,
970
     libfsapfs_btree_entry_t **btree_entry,
971
     libcerror_error_t **error )
972
0
{
973
0
  libfsapfs_btree_entry_t *entry          = NULL;
974
0
  libfsapfs_btree_entry_t *previous_entry = NULL;
975
0
  static char *function                   = "libfsapfs_snapshot_metadata_tree_get_entry_from_node_by_identifier";
976
0
  uint64_t snapshot_metadata_identifier   = 0;
977
0
  uint8_t snapshot_metadata_data_type     = 0;
978
0
  int btree_entry_index                   = 0;
979
0
  int is_leaf_node                        = 0;
980
0
  int number_of_entries                   = 0;
981
982
0
  if( snapshot_metadata_tree == NULL )
983
0
  {
984
0
    libcerror_error_set(
985
0
     error,
986
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
987
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
988
0
     "%s: invalid snapshot metadata tree.",
989
0
     function );
990
991
0
    return( -1 );
992
0
  }
993
0
  if( btree_entry == NULL )
994
0
  {
995
0
    libcerror_error_set(
996
0
     error,
997
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
998
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
999
0
     "%s: invalid B-tree entry.",
1000
0
     function );
1001
1002
0
    return( -1 );
1003
0
  }
1004
#if defined( HAVE_DEBUG_OUTPUT )
1005
  if( libcnotify_verbose != 0 )
1006
  {
1007
    libcnotify_printf(
1008
     "%s: retrieving B-tree entry identifier: %" PRIu64 ".\n",
1009
     function,
1010
     object_identifier );
1011
  }
1012
#endif
1013
0
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1014
0
                  node,
1015
0
                  error );
1016
1017
0
  if( is_leaf_node == -1 )
1018
0
  {
1019
0
    libcerror_error_set(
1020
0
     error,
1021
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1022
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1023
0
     "%s: unable to determine if B-tree node is a leaf node.",
1024
0
     function );
1025
1026
0
    return( -1 );
1027
0
  }
1028
0
  if( libfsapfs_btree_node_get_number_of_entries(
1029
0
       node,
1030
0
       &number_of_entries,
1031
0
       error ) != 1 )
1032
0
  {
1033
0
    libcerror_error_set(
1034
0
     error,
1035
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1036
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1037
0
     "%s: unable to retrieve number of entries from B-tree node.",
1038
0
     function );
1039
1040
0
    return( -1 );
1041
0
  }
1042
0
  for( btree_entry_index = 0;
1043
0
       btree_entry_index < number_of_entries;
1044
0
       btree_entry_index++ )
1045
0
  {
1046
0
    if( libfsapfs_btree_node_get_entry_by_index(
1047
0
         node,
1048
0
         btree_entry_index,
1049
0
         &entry,
1050
0
         error ) != 1 )
1051
0
    {
1052
0
      libcerror_error_set(
1053
0
       error,
1054
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1055
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1056
0
       "%s: unable to retrieve number of entries from B-tree node.",
1057
0
       function );
1058
1059
0
      return( -1 );
1060
0
    }
1061
0
    if( entry == NULL )
1062
0
    {
1063
0
      libcerror_error_set(
1064
0
       error,
1065
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1066
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1067
0
       "%s: invalid B-tree entry: %d.",
1068
0
       function,
1069
0
       btree_entry_index );
1070
1071
0
      return( -1 );
1072
0
    }
1073
0
    if( entry->key_data == NULL )
1074
0
    {
1075
0
      libcerror_error_set(
1076
0
       error,
1077
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1078
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1079
0
       "%s: invalid B-tree entry: %d - missing key data.",
1080
0
       function,
1081
0
       btree_entry_index );
1082
1083
0
      return( -1 );
1084
0
    }
1085
0
    if( entry->key_data_size < 8 )
1086
0
    {
1087
0
      libcerror_error_set(
1088
0
       error,
1089
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1090
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1091
0
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
1092
0
       function,
1093
0
       btree_entry_index );
1094
1095
0
      return( -1 );
1096
0
    }
1097
0
    byte_stream_copy_to_uint64_little_endian(
1098
0
     entry->key_data,
1099
0
     snapshot_metadata_identifier );
1100
1101
0
    snapshot_metadata_data_type = (uint8_t) ( snapshot_metadata_identifier >> 60 );
1102
1103
#if defined( HAVE_DEBUG_OUTPUT )
1104
    if( libcnotify_verbose != 0 )
1105
    {
1106
      libcnotify_printf(
1107
       "%s: B-tree entry: %d, identifier: %" PRIu64 ", data type: 0x%" PRIx8 " %s\n",
1108
       function,
1109
       btree_entry_index,
1110
       snapshot_metadata_identifier & 0x0fffffffffffffffUL,
1111
       snapshot_metadata_data_type,
1112
       libfsapfs_debug_print_file_system_data_type(
1113
        snapshot_metadata_data_type ) );
1114
    }
1115
#endif
1116
0
    snapshot_metadata_identifier &= 0x0fffffffffffffffUL;
1117
1118
0
    if( is_leaf_node != 0 )
1119
0
    {
1120
0
      if( snapshot_metadata_identifier == object_identifier )
1121
0
      {
1122
0
        *btree_entry = entry;
1123
1124
0
        return( 1 );
1125
0
      }
1126
0
    }
1127
0
    else
1128
0
    {
1129
0
      if( snapshot_metadata_identifier >= object_identifier )
1130
0
      {
1131
0
        if( ( previous_entry == NULL )
1132
0
         || ( snapshot_metadata_identifier == object_identifier ) )
1133
0
        {
1134
0
          previous_entry = entry;
1135
0
        }
1136
0
        *btree_entry = previous_entry;
1137
1138
0
        return( 1 );
1139
0
      }
1140
0
      previous_entry = entry;
1141
0
    }
1142
0
  }
1143
0
  if( is_leaf_node == 0 )
1144
0
  {
1145
0
    *btree_entry = previous_entry;
1146
1147
0
    return( 1 );
1148
0
  }
1149
0
  return( 0 );
1150
0
}
1151
1152
/* Retrieves an entry for a specific identifier from the snapshot metadata tree
1153
 * Returns 1 if successful, 0 if not found or -1 on error
1154
 */
1155
int libfsapfs_snapshot_metadata_tree_get_entry_by_identifier(
1156
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1157
     libbfio_handle_t *file_io_handle,
1158
     uint64_t object_identifier,
1159
     libfsapfs_btree_node_t **btree_node,
1160
     libfsapfs_btree_entry_t **btree_entry,
1161
     libcerror_error_t **error )
1162
0
{
1163
0
  libfsapfs_btree_entry_t *entry = NULL;
1164
0
  libfsapfs_btree_node_t *node   = NULL;
1165
0
  static char *function          = "libfsapfs_snapshot_metadata_tree_get_entry_by_identifier";
1166
0
  uint64_t sub_node_block_number = 0;
1167
0
  int is_leaf_node               = 0;
1168
0
  int recursion_depth            = 0;
1169
0
  int result                     = 0;
1170
1171
0
  if( snapshot_metadata_tree == NULL )
1172
0
  {
1173
0
    libcerror_error_set(
1174
0
     error,
1175
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1176
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1177
0
     "%s: invalid snapshot metadata tree.",
1178
0
     function );
1179
1180
0
    return( -1 );
1181
0
  }
1182
0
  if( btree_node == NULL )
1183
0
  {
1184
0
    libcerror_error_set(
1185
0
     error,
1186
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1187
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1188
0
     "%s: invalid B-tree node.",
1189
0
     function );
1190
1191
0
    return( -1 );
1192
0
  }
1193
0
  if( btree_entry == NULL )
1194
0
  {
1195
0
    libcerror_error_set(
1196
0
     error,
1197
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1198
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1199
0
     "%s: invalid B-tree entry.",
1200
0
     function );
1201
1202
0
    return( -1 );
1203
0
  }
1204
0
  if( libfsapfs_snapshot_metadata_tree_get_root_node(
1205
0
       snapshot_metadata_tree,
1206
0
       file_io_handle,
1207
0
       snapshot_metadata_tree->root_node_block_number,
1208
0
       &node,
1209
0
       error ) != 1 )
1210
0
  {
1211
0
    libcerror_error_set(
1212
0
     error,
1213
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1214
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1215
0
     "%s: unable to retrieve B-tree root node.",
1216
0
     function );
1217
1218
0
    return( -1 );
1219
0
  }
1220
0
  do
1221
0
  {
1222
0
    if( ( recursion_depth < 0 )
1223
0
     || ( recursion_depth > LIBFSAPFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1224
0
    {
1225
0
      libcerror_error_set(
1226
0
       error,
1227
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1228
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1229
0
       "%s: invalid recursion depth value out of bounds.",
1230
0
       function );
1231
1232
0
      return( -1 );
1233
0
    }
1234
0
    is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1235
0
                    node,
1236
0
                    error );
1237
1238
0
    if( is_leaf_node == -1 )
1239
0
    {
1240
0
      libcerror_error_set(
1241
0
       error,
1242
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1243
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1244
0
       "%s: unable to determine if B-tree node is a leaf node.",
1245
0
       function );
1246
1247
0
      return( -1 );
1248
0
    }
1249
0
    result = libfsapfs_snapshot_metadata_tree_get_entry_from_node_by_identifier(
1250
0
              snapshot_metadata_tree,
1251
0
              node,
1252
0
              object_identifier,
1253
0
              &entry,
1254
0
              error );
1255
1256
0
    if( result == -1 )
1257
0
    {
1258
0
      libcerror_error_set(
1259
0
       error,
1260
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1261
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1262
0
       "%s: unable to retrieve entry from B-tree node.",
1263
0
       function );
1264
1265
0
      return( -1 );
1266
0
    }
1267
0
    else if( result == 0 )
1268
0
    {
1269
0
      break;
1270
0
    }
1271
0
    if( is_leaf_node != 0 )
1272
0
    {
1273
0
      *btree_node  = node;
1274
0
      *btree_entry = entry;
1275
1276
0
      return( 1 );
1277
0
    }
1278
0
    if( entry == NULL )
1279
0
    {
1280
0
      libcerror_error_set(
1281
0
       error,
1282
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1283
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1284
0
       "%s: invalid B-tree entry.",
1285
0
       function );
1286
1287
0
      return( -1 );
1288
0
    }
1289
0
    if( entry->value_data == NULL )
1290
0
    {
1291
0
      libcerror_error_set(
1292
0
       error,
1293
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1294
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1295
0
       "%s: invalid B-tree entry - missing value data.",
1296
0
       function );
1297
1298
0
      return( -1 );
1299
0
    }
1300
0
    if( entry->value_data_size != 8 )
1301
0
    {
1302
0
      libcerror_error_set(
1303
0
       error,
1304
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1305
0
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1306
0
       "%s: invalid B-tree entry - unsupported value data size.",
1307
0
       function );
1308
1309
0
      return( -1 );
1310
0
    }
1311
0
    byte_stream_copy_to_uint64_little_endian(
1312
0
     entry->value_data,
1313
0
     sub_node_block_number );
1314
1315
#if defined( HAVE_DEBUG_OUTPUT )
1316
    if( libcnotify_verbose != 0 )
1317
    {
1318
      libcnotify_printf(
1319
       "%s: B-tree sub node block number: %" PRIu64 "\n",
1320
       function,
1321
       sub_node_block_number );
1322
    }
1323
#endif
1324
0
    node = NULL;
1325
1326
0
    if( libfsapfs_snapshot_metadata_tree_get_sub_node(
1327
0
         snapshot_metadata_tree,
1328
0
         file_io_handle,
1329
0
         sub_node_block_number,
1330
0
         &node,
1331
0
         error ) != 1 )
1332
0
    {
1333
0
      libcerror_error_set(
1334
0
       error,
1335
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1336
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1337
0
       "%s: unable to retrieve B-tree sub node from block: %" PRIu64 ".",
1338
0
       function,
1339
0
       sub_node_block_number );
1340
1341
0
      return( -1 );
1342
0
    }
1343
0
    recursion_depth++;
1344
0
  }
1345
0
  while( is_leaf_node == 0 );
1346
1347
0
  return( 0 );
1348
0
}
1349
1350
/* Retrieves the snapshot metadata of a specific object identifier
1351
 * Returns 1 if successful, 0 if no such value or -1 on error
1352
 */
1353
int libfsapfs_snapshot_metadata_tree_get_metadata_by_object_identifier(
1354
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1355
     libbfio_handle_t *file_io_handle,
1356
     uint64_t object_identifier,
1357
     libfsapfs_snapshot_metadata_t **metadata,
1358
     libcerror_error_t **error )
1359
0
{
1360
0
  libfsapfs_btree_entry_t *entry = NULL;
1361
0
  libfsapfs_btree_node_t *node   = NULL;
1362
0
  static char *function          = "libfsapfs_snapshot_metadata_tree_get_metadata_by_object_identifier";
1363
0
  int result                     = 0;
1364
1365
0
  if( snapshot_metadata_tree == NULL )
1366
0
  {
1367
0
    libcerror_error_set(
1368
0
     error,
1369
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1370
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1371
0
     "%s: invalid snapshot metadata tree.",
1372
0
     function );
1373
1374
0
    return( -1 );
1375
0
  }
1376
0
  if( metadata == NULL )
1377
0
  {
1378
0
    libcerror_error_set(
1379
0
     error,
1380
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1381
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1382
0
     "%s: invalid metadata.",
1383
0
     function );
1384
1385
0
    return( -1 );
1386
0
  }
1387
0
  if( *metadata != NULL )
1388
0
  {
1389
0
    libcerror_error_set(
1390
0
     error,
1391
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1392
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1393
0
     "%s: invalid metadata value already set.",
1394
0
     function );
1395
1396
0
    return( -1 );
1397
0
  }
1398
0
  result = libfsapfs_snapshot_metadata_tree_get_entry_by_identifier(
1399
0
            snapshot_metadata_tree,
1400
0
            file_io_handle,
1401
0
            object_identifier,
1402
0
            &node,
1403
0
            &entry,
1404
0
            error );
1405
1406
0
  if( result == -1 )
1407
0
  {
1408
0
    libcerror_error_set(
1409
0
     error,
1410
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1411
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1412
0
     "%s: unable to retrieve entry from B-tree.",
1413
0
     function );
1414
1415
0
    goto on_error;
1416
0
  }
1417
0
  else if( result != 0 )
1418
0
  {
1419
0
    if( node == NULL )
1420
0
    {
1421
0
      libcerror_error_set(
1422
0
       error,
1423
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1424
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1425
0
       "%s: invalid B-tree node.",
1426
0
       function );
1427
1428
0
      goto on_error;
1429
0
    }
1430
0
    if( entry == NULL )
1431
0
    {
1432
0
      libcerror_error_set(
1433
0
       error,
1434
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1435
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1436
0
       "%s: invalid B-tree entry.",
1437
0
       function );
1438
1439
0
      goto on_error;
1440
0
    }
1441
0
    if( libfsapfs_snapshot_metadata_initialize(
1442
0
         metadata,
1443
0
         error ) != 1 )
1444
0
    {
1445
0
      libcerror_error_set(
1446
0
       error,
1447
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1448
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1449
0
       "%s: unable to create snapshot metadata.",
1450
0
       function );
1451
1452
0
      goto on_error;
1453
0
    }
1454
0
    if( libfsapfs_snapshot_metadata_read_key_data(
1455
0
         *metadata,
1456
0
         entry->key_data,
1457
0
         (size_t) entry->key_data_size,
1458
0
         error ) != 1 )
1459
0
    {
1460
0
      libcerror_error_set(
1461
0
       error,
1462
0
       LIBCERROR_ERROR_DOMAIN_IO,
1463
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1464
0
       "%s: unable to read snapshot metadata key data.",
1465
0
       function );
1466
1467
0
      goto on_error;
1468
0
    }
1469
0
    if( libfsapfs_snapshot_metadata_read_value_data(
1470
0
         *metadata,
1471
0
         entry->value_data,
1472
0
         (size_t) entry->value_data_size,
1473
0
         error ) != 1 )
1474
0
    {
1475
0
      libcerror_error_set(
1476
0
       error,
1477
0
       LIBCERROR_ERROR_DOMAIN_IO,
1478
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1479
0
       "%s: unable to read snapshot metadata value data.",
1480
0
       function );
1481
1482
0
      goto on_error;
1483
0
    }
1484
0
    node = NULL;
1485
0
  }
1486
0
  return( result );
1487
1488
0
on_error:
1489
0
  if( *metadata != NULL )
1490
0
  {
1491
0
    libfsapfs_snapshot_metadata_free(
1492
0
     metadata,
1493
0
     NULL );
1494
0
  }
1495
0
  return( -1 );
1496
0
}
1497
1498
/* Retrieves snapshots for a specific parent identifier from the snapshot metadata tree leaf node
1499
 * Returns 1 if successful, 0 if not found or -1 on error
1500
 */
1501
int libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node(
1502
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1503
     libfsapfs_btree_node_t *node,
1504
     libcdata_array_t *snapshots,
1505
     libcerror_error_t **error )
1506
2.62k
{
1507
2.62k
  libfsapfs_btree_entry_t *entry                   = NULL;
1508
2.62k
  libfsapfs_snapshot_metadata_t *snapshot_metadata = NULL;
1509
2.62k
  static char *function                            = "libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node";
1510
2.62k
  uint64_t snapshot_metadata_identifier            = 0;
1511
2.62k
  uint8_t snapshot_metadata_data_type              = 0;
1512
2.62k
  int btree_entry_index                            = 0;
1513
2.62k
  int entry_index                                  = 0;
1514
2.62k
  int found_snapshot_metadata                      = 0;
1515
2.62k
  int is_leaf_node                                 = 0;
1516
2.62k
  int number_of_entries                            = 0;
1517
1518
2.62k
  if( snapshot_metadata_tree == NULL )
1519
0
  {
1520
0
    libcerror_error_set(
1521
0
     error,
1522
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1523
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1524
0
     "%s: invalid snapshot metadata tree.",
1525
0
     function );
1526
1527
0
    return( -1 );
1528
0
  }
1529
2.62k
  if( node == NULL )
1530
0
  {
1531
0
    libcerror_error_set(
1532
0
     error,
1533
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1534
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1535
0
     "%s: invalid node.",
1536
0
     function );
1537
1538
0
    return( -1 );
1539
0
  }
1540
2.62k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1541
2.62k
                  node,
1542
2.62k
                  error );
1543
1544
2.62k
  if( is_leaf_node == -1 )
1545
0
  {
1546
0
    libcerror_error_set(
1547
0
     error,
1548
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1549
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1550
0
     "%s: unable to determine if B-tree node is a leaf node.",
1551
0
     function );
1552
1553
0
    goto on_error;
1554
0
  }
1555
2.62k
  else if( is_leaf_node == 0 )
1556
0
  {
1557
0
    libcerror_error_set(
1558
0
     error,
1559
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1560
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1561
0
     "%s: invalid node - not a leaf node.",
1562
0
     function );
1563
1564
0
    goto on_error;
1565
0
  }
1566
2.62k
  if( libfsapfs_btree_node_get_number_of_entries(
1567
2.62k
       node,
1568
2.62k
       &number_of_entries,
1569
2.62k
       error ) != 1 )
1570
0
  {
1571
0
    libcerror_error_set(
1572
0
     error,
1573
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1574
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1575
0
     "%s: unable to retrieve number of entries from B-tree node.",
1576
0
     function );
1577
1578
0
    goto on_error;
1579
0
  }
1580
2.62k
  for( btree_entry_index = 0;
1581
2.85k
       btree_entry_index < number_of_entries;
1582
2.62k
       btree_entry_index++ )
1583
473
  {
1584
473
    if( libfsapfs_btree_node_get_entry_by_index(
1585
473
         node,
1586
473
         btree_entry_index,
1587
473
         &entry,
1588
473
         error ) != 1 )
1589
0
    {
1590
0
      libcerror_error_set(
1591
0
       error,
1592
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1593
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1594
0
       "%s: unable to retrieve number of entries from B-tree node.",
1595
0
       function );
1596
1597
0
      goto on_error;
1598
0
    }
1599
473
    if( entry == NULL )
1600
0
    {
1601
0
      libcerror_error_set(
1602
0
       error,
1603
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1604
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1605
0
       "%s: invalid B-tree entry: %d.",
1606
0
       function,
1607
0
       btree_entry_index );
1608
1609
0
      goto on_error;
1610
0
    }
1611
473
    if( entry->key_data == NULL )
1612
20
    {
1613
20
      libcerror_error_set(
1614
20
       error,
1615
20
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1616
20
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1617
20
       "%s: invalid B-tree entry: %d - missing key data.",
1618
20
       function,
1619
20
       btree_entry_index );
1620
1621
20
      goto on_error;
1622
20
    }
1623
453
    if( entry->key_data_size < 8 )
1624
9
    {
1625
9
      libcerror_error_set(
1626
9
       error,
1627
9
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1628
9
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1629
9
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
1630
9
       function,
1631
9
       btree_entry_index );
1632
1633
9
      return( -1 );
1634
9
    }
1635
444
    byte_stream_copy_to_uint64_little_endian(
1636
444
     entry->key_data,
1637
444
     snapshot_metadata_identifier );
1638
1639
444
    snapshot_metadata_data_type = (uint8_t) ( snapshot_metadata_identifier >> 60 );
1640
1641
#if defined( HAVE_DEBUG_OUTPUT )
1642
    if( libcnotify_verbose != 0 )
1643
    {
1644
      libcnotify_printf(
1645
       "%s: B-tree entry: %d, identifier: %" PRIu64 ", data type: 0x%" PRIx8 " %s\n",
1646
       function,
1647
       btree_entry_index,
1648
       snapshot_metadata_identifier & 0x0fffffffffffffffUL,
1649
       snapshot_metadata_data_type,
1650
       libfsapfs_debug_print_file_system_data_type(
1651
        snapshot_metadata_data_type ) );
1652
    }
1653
#endif
1654
444
    if( snapshot_metadata_data_type > LIBFSAPFS_FILE_SYSTEM_DATA_TYPE_SNAPSHOT_METADATA )
1655
128
    {
1656
128
      break;
1657
128
    }
1658
316
    if( libfsapfs_snapshot_metadata_initialize(
1659
316
         &snapshot_metadata,
1660
316
         error ) != 1 )
1661
0
    {
1662
0
      libcerror_error_set(
1663
0
       error,
1664
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1665
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1666
0
       "%s: unable to create snapshot metadata.",
1667
0
       function );
1668
1669
0
      goto on_error;
1670
0
    }
1671
316
    if( libfsapfs_snapshot_metadata_read_key_data(
1672
316
         snapshot_metadata,
1673
316
         entry->key_data,
1674
316
         (size_t) entry->key_data_size,
1675
316
         error ) != 1 )
1676
0
    {
1677
0
      libcerror_error_set(
1678
0
       error,
1679
0
       LIBCERROR_ERROR_DOMAIN_IO,
1680
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1681
0
       "%s: unable to read snapshot metadata key data.",
1682
0
       function );
1683
1684
0
      goto on_error;
1685
0
    }
1686
316
    if( libfsapfs_snapshot_metadata_read_value_data(
1687
316
         snapshot_metadata,
1688
316
         entry->value_data,
1689
316
         (size_t) entry->value_data_size,
1690
316
         error ) != 1 )
1691
84
    {
1692
84
      libcerror_error_set(
1693
84
       error,
1694
84
       LIBCERROR_ERROR_DOMAIN_IO,
1695
84
       LIBCERROR_IO_ERROR_READ_FAILED,
1696
84
       "%s: unable to read snapshot metadata value data.",
1697
84
       function );
1698
1699
84
      goto on_error;
1700
84
    }
1701
232
    if( libcdata_array_append_entry(
1702
232
         snapshots,
1703
232
         &entry_index,
1704
232
         (intptr_t *) snapshot_metadata,
1705
232
         error ) != 1 )
1706
0
    {
1707
0
      libcerror_error_set(
1708
0
       error,
1709
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1710
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1711
0
       "%s: unable to append snapshot metadata to array.",
1712
0
       function );
1713
1714
0
      goto on_error;
1715
0
    }
1716
232
    snapshot_metadata = NULL;
1717
1718
232
    found_snapshot_metadata = 1;
1719
232
  }
1720
2.51k
  return( found_snapshot_metadata );
1721
1722
104
on_error:
1723
104
  if( snapshot_metadata != NULL )
1724
84
  {
1725
84
    libfsapfs_snapshot_metadata_free(
1726
84
     &snapshot_metadata,
1727
84
     NULL );
1728
84
  }
1729
104
  libcdata_array_empty(
1730
104
   snapshots,
1731
104
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_snapshot_metadata_free,
1732
104
   NULL );
1733
1734
104
  return( -1 );
1735
2.62k
}
1736
1737
/* Retrieves snapshots for a specific parent identifier from the snapshot metadata tree branch node
1738
 * Returns 1 if successful, 0 if not found or -1 on error
1739
 */
1740
int libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node(
1741
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1742
     libbfio_handle_t *file_io_handle,
1743
     libfsapfs_btree_node_t *node,
1744
     uint64_t transaction_identifier,
1745
     libcdata_array_t *snapshots,
1746
     int recursion_depth,
1747
     libcerror_error_t **error )
1748
1.96k
{
1749
1.96k
  libfsapfs_btree_entry_t *entry        = NULL;
1750
1.96k
  libfsapfs_btree_node_t *sub_node      = NULL;
1751
1.96k
  static char *function                 = "libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node";
1752
1.96k
  uint64_t snapshot_metadata_identifier = 0;
1753
1.96k
  uint64_t sub_node_block_number        = 0;
1754
1.96k
  uint8_t snapshot_metadata_data_type   = 0;
1755
1.96k
  int entry_index                       = 0;
1756
1.96k
  int found_snapshot_metadata           = 0;
1757
1.96k
  int is_leaf_node                      = 0;
1758
1.96k
  int number_of_entries                 = 0;
1759
1.96k
  int result                            = 0;
1760
1761
1.96k
  if( snapshot_metadata_tree == NULL )
1762
0
  {
1763
0
    libcerror_error_set(
1764
0
     error,
1765
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1766
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1767
0
     "%s: invalid snapshot metadata tree.",
1768
0
     function );
1769
1770
0
    return( -1 );
1771
0
  }
1772
1.96k
  if( node == NULL )
1773
0
  {
1774
0
    libcerror_error_set(
1775
0
     error,
1776
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1777
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1778
0
     "%s: invalid node.",
1779
0
     function );
1780
1781
0
    return( -1 );
1782
0
  }
1783
1.96k
  if( ( recursion_depth < 0 )
1784
1.96k
   || ( recursion_depth > LIBFSAPFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1785
3
  {
1786
3
    libcerror_error_set(
1787
3
     error,
1788
3
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1789
3
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1790
3
     "%s: invalid recursion depth value out of bounds.",
1791
3
     function );
1792
1793
3
    return( -1 );
1794
3
  }
1795
1.96k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1796
1.96k
                  node,
1797
1.96k
                  error );
1798
1799
1.96k
  if( is_leaf_node == -1 )
1800
0
  {
1801
0
    libcerror_error_set(
1802
0
     error,
1803
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1804
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1805
0
     "%s: unable to determine if B-tree node is a leaf node.",
1806
0
     function );
1807
1808
0
    goto on_error;
1809
0
  }
1810
1.96k
  else if( is_leaf_node != 0 )
1811
0
  {
1812
0
    libcerror_error_set(
1813
0
     error,
1814
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1815
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1816
0
     "%s: invalid node - not a branch node.",
1817
0
     function );
1818
1819
0
    goto on_error;
1820
0
  }
1821
1.96k
  if( libfsapfs_btree_node_get_number_of_entries(
1822
1.96k
       node,
1823
1.96k
       &number_of_entries,
1824
1.96k
       error ) != 1 )
1825
0
  {
1826
0
    libcerror_error_set(
1827
0
     error,
1828
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1829
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1830
0
     "%s: unable to retrieve number of entries from B-tree node.",
1831
0
     function );
1832
1833
0
    goto on_error;
1834
0
  }
1835
1.96k
  for( entry_index = 0;
1836
2.08k
       entry_index < number_of_entries;
1837
1.96k
       entry_index++ )
1838
1.70k
  {
1839
1.70k
    if( libfsapfs_btree_node_get_entry_by_index(
1840
1.70k
         node,
1841
1.70k
         entry_index,
1842
1.70k
         &entry,
1843
1.70k
         error ) != 1 )
1844
0
    {
1845
0
      libcerror_error_set(
1846
0
       error,
1847
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1848
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1849
0
       "%s: unable to retrieve number of entries from B-tree node.",
1850
0
       function );
1851
1852
0
      goto on_error;
1853
0
    }
1854
1.70k
    if( entry == NULL )
1855
0
    {
1856
0
      libcerror_error_set(
1857
0
       error,
1858
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1859
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1860
0
       "%s: invalid B-tree entry: %d.",
1861
0
       function,
1862
0
       entry_index );
1863
1864
0
      goto on_error;
1865
0
    }
1866
1.70k
    if( entry->key_data == NULL )
1867
17
    {
1868
17
      libcerror_error_set(
1869
17
       error,
1870
17
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1871
17
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1872
17
       "%s: invalid B-tree entry: %d - missing key data.",
1873
17
       function,
1874
17
       entry_index );
1875
1876
17
      goto on_error;
1877
17
    }
1878
1.68k
    if( entry->key_data_size < 8 )
1879
9
    {
1880
9
      libcerror_error_set(
1881
9
       error,
1882
9
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1883
9
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1884
9
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
1885
9
       function,
1886
9
       entry_index );
1887
1888
9
      goto on_error;
1889
9
    }
1890
1.67k
    byte_stream_copy_to_uint64_little_endian(
1891
1.67k
     entry->key_data,
1892
1.67k
     snapshot_metadata_identifier );
1893
1894
1.67k
    snapshot_metadata_data_type = (uint8_t) ( snapshot_metadata_identifier >> 60 );
1895
1896
#if defined( HAVE_DEBUG_OUTPUT )
1897
    if( libcnotify_verbose != 0 )
1898
    {
1899
      libcnotify_printf(
1900
       "%s: B-tree entry: %d, identifier: %" PRIu64 ", data type: 0x%" PRIx8 " %s\n",
1901
       function,
1902
       entry_index,
1903
       snapshot_metadata_identifier & 0x0fffffffffffffffUL,
1904
       snapshot_metadata_data_type,
1905
       libfsapfs_debug_print_file_system_data_type(
1906
        snapshot_metadata_data_type ) );
1907
    }
1908
#endif
1909
1.67k
    if( snapshot_metadata_data_type > LIBFSAPFS_FILE_SYSTEM_DATA_TYPE_SNAPSHOT_METADATA )
1910
40
    {
1911
40
      break;
1912
40
    }
1913
1.63k
    if( libfsapfs_snapshot_metadata_tree_get_sub_node_block_number_from_entry(
1914
1.63k
         snapshot_metadata_tree,
1915
1.63k
         file_io_handle,
1916
1.63k
         entry,
1917
1.63k
         transaction_identifier,
1918
1.63k
         &sub_node_block_number,
1919
1.63k
         error ) != 1 )
1920
418
    {
1921
418
      libcerror_error_set(
1922
418
       error,
1923
418
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1924
418
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1925
418
       "%s: unable to determine sub node block number.",
1926
418
       function );
1927
1928
418
      goto on_error;
1929
418
    }
1930
1.22k
    if( libfsapfs_snapshot_metadata_tree_get_sub_node(
1931
1.22k
         snapshot_metadata_tree,
1932
1.22k
         file_io_handle,
1933
1.22k
         sub_node_block_number,
1934
1.22k
         &sub_node,
1935
1.22k
         error ) != 1 )
1936
322
    {
1937
322
      libcerror_error_set(
1938
322
       error,
1939
322
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1940
322
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1941
322
       "%s: unable to retrieve B-tree sub node from block: %" PRIu64 ".",
1942
322
       function,
1943
322
       sub_node_block_number );
1944
1945
322
      goto on_error;
1946
322
    }
1947
899
    is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1948
899
                    sub_node,
1949
899
                    error );
1950
1951
899
    if( is_leaf_node == -1 )
1952
0
    {
1953
0
      libcerror_error_set(
1954
0
       error,
1955
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1956
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1957
0
       "%s: unable to determine if B-tree sub node is a leaf node.",
1958
0
       function );
1959
1960
0
      goto on_error;
1961
0
    }
1962
899
    if( is_leaf_node != 0 )
1963
60
    {
1964
60
      result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node(
1965
60
                snapshot_metadata_tree,
1966
60
                sub_node,
1967
60
                snapshots,
1968
60
                error );
1969
60
    }
1970
839
    else
1971
839
    {
1972
839
      result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node(
1973
839
                snapshot_metadata_tree,
1974
839
                file_io_handle,
1975
839
                sub_node,
1976
839
                transaction_identifier,
1977
839
                snapshots,
1978
839
                recursion_depth + 1,
1979
839
                error );
1980
839
    }
1981
899
    if( result == -1 )
1982
775
    {
1983
775
      libcerror_error_set(
1984
775
       error,
1985
775
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1986
775
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1987
775
       "%s: unable to retrieve snapshots from snapshot metadata tree sub node.",
1988
775
       function );
1989
1990
775
      goto on_error;
1991
775
    }
1992
124
    else if( result != 0 )
1993
0
    {
1994
0
      found_snapshot_metadata = 1;
1995
0
    }
1996
124
    sub_node = NULL;
1997
124
  }
1998
423
  return( found_snapshot_metadata );
1999
2000
1.54k
on_error:
2001
1.54k
  libcdata_array_empty(
2002
1.54k
   snapshots,
2003
1.54k
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_snapshot_metadata_free,
2004
1.54k
   NULL );
2005
2006
1.54k
  return( -1 );
2007
1.96k
}
2008
2009
/* Retrieves snapshots for a specific parent identifier from the snapshot metadata tree
2010
 * Returns 1 if successful, 0 if not found or -1 on error
2011
 */
2012
int libfsapfs_snapshot_metadata_tree_get_snapshots(
2013
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
2014
     libbfio_handle_t *file_io_handle,
2015
     uint64_t transaction_identifier,
2016
     libcdata_array_t *snapshots,
2017
     libcerror_error_t **error )
2018
4.52k
{
2019
4.52k
  libfsapfs_btree_node_t *root_node = NULL;
2020
4.52k
  static char *function             = "libfsapfs_snapshot_metadata_tree_get_snapshots";
2021
4.52k
  int is_leaf_node                  = 0;
2022
4.52k
  int result                        = 0;
2023
2024
#if defined( HAVE_PROFILER )
2025
  int64_t profiler_start_timestamp  = 0;
2026
#endif
2027
2028
4.52k
  if( snapshot_metadata_tree == NULL )
2029
0
  {
2030
0
    libcerror_error_set(
2031
0
     error,
2032
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2033
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2034
0
     "%s: invalid snapshot metadata tree.",
2035
0
     function );
2036
2037
0
    return( -1 );
2038
0
  }
2039
#if defined( HAVE_PROFILER )
2040
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
2041
  {
2042
    if( libfsapfs_profiler_start_timing(
2043
         snapshot_metadata_tree->io_handle->profiler,
2044
         &profiler_start_timestamp,
2045
         error ) != 1 )
2046
    {
2047
      libcerror_error_set(
2048
       error,
2049
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2050
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2051
       "%s: unable to start timing.",
2052
       function );
2053
2054
      goto on_error;
2055
    }
2056
  }
2057
#endif /* defined( HAVE_PROFILER ) */
2058
2059
4.52k
  if( libfsapfs_snapshot_metadata_tree_get_root_node(
2060
4.52k
       snapshot_metadata_tree,
2061
4.52k
       file_io_handle,
2062
4.52k
       snapshot_metadata_tree->root_node_block_number,
2063
4.52k
       &root_node,
2064
4.52k
       error ) != 1 )
2065
826
  {
2066
826
    libcerror_error_set(
2067
826
     error,
2068
826
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2069
826
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2070
826
     "%s: unable to retrieve B-tree root node.",
2071
826
     function );
2072
2073
826
    goto on_error;
2074
826
  }
2075
3.69k
  if( root_node == NULL )
2076
0
  {
2077
0
    libcerror_error_set(
2078
0
     error,
2079
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2080
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2081
0
     "%s: invalid B-tree root node.",
2082
0
     function );
2083
2084
0
    goto on_error;
2085
0
  }
2086
3.69k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
2087
3.69k
                  root_node,
2088
3.69k
                  error );
2089
2090
3.69k
  if( is_leaf_node == -1 )
2091
0
  {
2092
0
    libcerror_error_set(
2093
0
     error,
2094
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2095
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2096
0
     "%s: unable to determine if B-tree root node is a leaf node.",
2097
0
     function );
2098
2099
0
    goto on_error;
2100
0
  }
2101
3.69k
  if( is_leaf_node != 0 )
2102
2.56k
  {
2103
2.56k
    result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node(
2104
2.56k
              snapshot_metadata_tree,
2105
2.56k
              root_node,
2106
2.56k
              snapshots,
2107
2.56k
              error );
2108
2.56k
  }
2109
1.12k
  else
2110
1.12k
  {
2111
1.12k
    result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node(
2112
1.12k
              snapshot_metadata_tree,
2113
1.12k
              file_io_handle,
2114
1.12k
              root_node,
2115
1.12k
              transaction_identifier,
2116
1.12k
              snapshots,
2117
1.12k
              0,
2118
1.12k
              error );
2119
1.12k
  }
2120
3.69k
  if( result == -1 )
2121
882
  {
2122
882
    libcerror_error_set(
2123
882
     error,
2124
882
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2125
882
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2126
882
     "%s: unable to retrieve snapshots from snapshot metadata tree root node.",
2127
882
     function );
2128
2129
882
    goto on_error;
2130
882
  }
2131
#if defined( HAVE_PROFILER )
2132
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
2133
  {
2134
    if( libfsapfs_profiler_stop_timing(
2135
         snapshot_metadata_tree->io_handle->profiler,
2136
         profiler_start_timestamp,
2137
         function,
2138
         0,
2139
         0,
2140
         error ) != 1 )
2141
    {
2142
      libcerror_error_set(
2143
       error,
2144
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2145
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2146
       "%s: unable to stop timing.",
2147
       function );
2148
2149
      goto on_error;
2150
    }
2151
  }
2152
#endif /* defined( HAVE_PROFILER ) */
2153
2154
2.81k
  return( result );
2155
2156
1.70k
on_error:
2157
1.70k
  libcdata_array_empty(
2158
1.70k
   snapshots,
2159
1.70k
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_snapshot_metadata_free,
2160
1.70k
   NULL );
2161
2162
1.70k
  return( -1 );
2163
3.69k
}
2164