Coverage Report

Created: 2026-07-25 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsapfs/libfsapfs/libfsapfs_snapshot_metadata_tree.c
Line
Count
Source
1
/*
2
 * The snapshot metadata tree functions
3
 *
4
 * Copyright (C) 2018-2026, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <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
2.37k
{
58
2.37k
  static char *function = "libfsapfs_snapshot_metadata_tree_initialize";
59
60
2.37k
  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
2.37k
  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
2.37k
  *snapshot_metadata_tree = memory_allocate_structure(
83
2.37k
                             libfsapfs_snapshot_metadata_tree_t );
84
85
2.37k
  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
2.37k
  if( memory_set(
97
2.37k
       *snapshot_metadata_tree,
98
2.37k
       0,
99
2.37k
       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
2.37k
  if( libfcache_cache_initialize(
116
2.37k
       &( ( *snapshot_metadata_tree )->data_block_cache ),
117
2.37k
       LIBFSAPFS_MAXIMUM_CACHE_ENTRIES_DATA_BLOCKS,
118
2.37k
       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
2.37k
  if( libfcache_cache_initialize(
130
2.37k
       &( ( *snapshot_metadata_tree )->node_cache ),
131
2.37k
       LIBFSAPFS_MAXIMUM_CACHE_ENTRIES_BTREE_NODES,
132
2.37k
       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
2.37k
  ( *snapshot_metadata_tree )->io_handle              = io_handle;
144
2.37k
  ( *snapshot_metadata_tree )->data_block_vector      = data_block_vector;
145
2.37k
  ( *snapshot_metadata_tree )->object_map_btree       = object_map_btree;
146
2.37k
  ( *snapshot_metadata_tree )->root_node_block_number = root_node_block_number;
147
148
2.37k
  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
2.37k
}
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
2.37k
{
168
2.37k
  static char *function = "libfsapfs_snapshot_metadata_tree_free";
169
2.37k
  int result            = 1;
170
171
2.37k
  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
2.37k
  if( *snapshot_metadata_tree != NULL )
183
2.37k
  {
184
    /* The data_block_vector is referenced and freed elsewhere
185
     */
186
2.37k
    if( libfcache_cache_free(
187
2.37k
         &( ( *snapshot_metadata_tree )->node_cache ),
188
2.37k
         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
2.37k
    if( libfcache_cache_free(
200
2.37k
         &( ( *snapshot_metadata_tree )->data_block_cache ),
201
2.37k
         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
2.37k
    memory_free(
213
2.37k
     *snapshot_metadata_tree );
214
215
2.37k
    *snapshot_metadata_tree = NULL;
216
2.37k
  }
217
2.37k
  return( result );
218
2.37k
}
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.06k
{
231
1.06k
  libfsapfs_object_map_descriptor_t *object_map_descriptor = NULL;
232
1.06k
  static char *function                                    = "libfsapfs_snapshot_metadata_tree_get_sub_node_block_number_from_entry";
233
1.06k
  uint64_t sub_node_object_identifier                      = 0;
234
1.06k
  int result                                               = 0;
235
236
1.06k
  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.06k
  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.06k
  if( entry->value_data == NULL )
259
12
  {
260
12
    libcerror_error_set(
261
12
     error,
262
12
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
263
12
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
264
12
     "%s: invalid B-tree entry - missing value data.",
265
12
     function );
266
267
12
    return( -1 );
268
12
  }
269
1.05k
  if( entry->value_data_size != 8 )
270
20
  {
271
20
    libcerror_error_set(
272
20
     error,
273
20
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
274
20
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
275
20
     "%s: invalid B-tree entry - unsupported value data size.",
276
20
     function );
277
278
20
    return( -1 );
279
20
  }
280
1.03k
  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.03k
  byte_stream_copy_to_uint64_little_endian(
292
1.03k
   entry->value_data,
293
1.03k
   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.03k
  result = libfsapfs_object_map_btree_get_descriptor_by_object_identifier(
306
1.03k
            snapshot_metadata_tree->object_map_btree,
307
1.03k
            file_io_handle,
308
1.03k
            sub_node_object_identifier,
309
1.03k
            transaction_identifier,
310
1.03k
            &object_map_descriptor,
311
1.03k
            error );
312
313
1.03k
  if( result == -1 )
314
90
  {
315
90
    libcerror_error_set(
316
90
     error,
317
90
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
318
90
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
319
90
     "%s: unable to retrieve object map descriptor for sub node object identifier: %" PRIu64 " (transaction: %" PRIu64 ").",
320
90
     function,
321
90
     sub_node_object_identifier,
322
90
     transaction_identifier );
323
324
90
    goto on_error;
325
90
  }
326
943
  else if( result != 0 )
327
845
  {
328
845
    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
845
    *sub_node_block_number = object_map_descriptor->physical_address;
349
350
845
    if( libfsapfs_object_map_descriptor_free(
351
845
         &object_map_descriptor,
352
845
         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
845
  }
364
943
  return( result );
365
366
90
on_error:
367
90
  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
90
  return( -1 );
374
1.03k
}
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
2.37k
{
386
2.37k
  libfcache_cache_value_t *cache_value = NULL;
387
2.37k
  libfsapfs_btree_node_t *node         = NULL;
388
2.37k
  libfsapfs_data_block_t *data_block   = NULL;
389
2.37k
  static char *function                = "libfsapfs_snapshot_metadata_tree_get_root_node";
390
2.37k
  int result                           = 0;
391
392
#if defined( HAVE_PROFILER )
393
  int64_t profiler_start_timestamp     = 0;
394
#endif
395
396
2.37k
  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
2.37k
  if( root_node_block_number > (uint64_t) INT_MAX )
408
79
  {
409
79
    libcerror_error_set(
410
79
     error,
411
79
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
412
79
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
413
79
     "%s: invalid root node block number value out of bounds.",
414
79
     function );
415
416
79
    return( -1 );
417
79
  }
418
2.29k
  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
2.29k
  result = libfcache_cache_get_value_by_identifier(
450
2.29k
            snapshot_metadata_tree->node_cache,
451
2.29k
            0,
452
2.29k
            (off64_t) root_node_block_number,
453
2.29k
            0,
454
2.29k
            &cache_value,
455
2.29k
            error );
456
457
2.29k
  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
2.29k
  else if( result == 0 )
469
2.29k
  {
470
2.29k
    if( libfdata_vector_get_element_value_by_index(
471
2.29k
         snapshot_metadata_tree->data_block_vector,
472
2.29k
         (intptr_t *) file_io_handle,
473
2.29k
         (libfdata_cache_t *) snapshot_metadata_tree->data_block_cache,
474
2.29k
         (int) root_node_block_number,
475
2.29k
         (intptr_t **) &data_block,
476
2.29k
         0,
477
2.29k
         error ) != 1 )
478
25
    {
479
25
      libcerror_error_set(
480
25
       error,
481
25
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
482
25
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
483
25
       "%s: unable to retrieve data block: %" PRIu64 ".",
484
25
       function,
485
25
       root_node_block_number );
486
487
25
      goto on_error;
488
25
    }
489
2.27k
    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
2.27k
    if( libfsapfs_btree_node_initialize(
502
2.27k
         &node,
503
2.27k
         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
2.27k
    if( libfsapfs_btree_node_read_data(
515
2.27k
         node,
516
2.27k
         data_block->data,
517
2.27k
         data_block->data_size,
518
2.27k
         error ) != 1 )
519
25
    {
520
25
      libcerror_error_set(
521
25
       error,
522
25
       LIBCERROR_ERROR_DOMAIN_IO,
523
25
       LIBCERROR_IO_ERROR_READ_FAILED,
524
25
       "%s: unable to read B-tree node.",
525
25
       function );
526
527
25
      goto on_error;
528
25
    }
529
2.24k
    if( node->object_type != 0x40000002UL )
530
35
    {
531
35
      libcerror_error_set(
532
35
       error,
533
35
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
534
35
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
535
35
       "%s: invalid object type: 0x%08" PRIx32 ".",
536
35
       function,
537
35
       node->object_type );
538
539
35
      goto on_error;
540
35
    }
541
2.21k
    if( node->object_subtype != 0x00000010UL )
542
61
    {
543
61
      libcerror_error_set(
544
61
       error,
545
61
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
546
61
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
547
61
       "%s: invalid object subtype: 0x%08" PRIx32 ".",
548
61
       function,
549
61
       node->object_subtype );
550
551
61
      goto on_error;
552
61
    }
553
2.15k
    if( ( node->node_header->flags & 0x0001 ) == 0 )
554
7
    {
555
7
      libcerror_error_set(
556
7
       error,
557
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
558
7
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
559
7
       "%s: unsupported flags: 0x%04" PRIx16 ".",
560
7
       function,
561
7
       node->node_header->flags );
562
563
7
      goto on_error;
564
7
    }
565
2.14k
    if( node->footer->node_size != 4096 )
566
103
    {
567
103
      libcerror_error_set(
568
103
       error,
569
103
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
570
103
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
571
103
       "%s: invalid node size value out of bounds.",
572
103
       function );
573
574
103
      goto on_error;
575
103
    }
576
2.04k
    if( node->footer->key_size != 0 )
577
74
    {
578
74
      libcerror_error_set(
579
74
       error,
580
74
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
581
74
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
582
74
       "%s: invalid key size value out of bounds.",
583
74
       function );
584
585
74
      goto on_error;
586
74
    }
587
1.96k
    if( node->footer->value_size != 0 )
588
76
    {
589
76
      libcerror_error_set(
590
76
       error,
591
76
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
592
76
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
593
76
       "%s: invalid value size value out of bounds.",
594
76
       function );
595
596
76
      goto on_error;
597
76
    }
598
1.89k
    if( libfcache_cache_set_value_by_identifier(
599
1.89k
         snapshot_metadata_tree->node_cache,
600
1.89k
         0,
601
1.89k
         (off64_t) root_node_block_number,
602
1.89k
         0,
603
1.89k
         (intptr_t *) node,
604
1.89k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_node_free,
605
1.89k
         LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
606
1.89k
         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
1.89k
    node = NULL;
618
619
1.89k
    if( libfcache_cache_get_value_by_identifier(
620
1.89k
         snapshot_metadata_tree->node_cache,
621
1.89k
         0,
622
1.89k
         (off64_t) root_node_block_number,
623
1.89k
         0,
624
1.89k
         &cache_value,
625
1.89k
         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
1.89k
  }
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
1.89k
  if( libfcache_cache_value_get_value(
661
1.89k
       cache_value,
662
1.89k
       (intptr_t **) root_node,
663
1.89k
       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
1.89k
  return( 1 );
675
676
406
on_error:
677
406
  if( node != NULL )
678
381
  {
679
381
    libfsapfs_btree_node_free(
680
381
     &node,
681
381
     NULL );
682
381
  }
683
406
  return( -1 );
684
1.89k
}
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
845
{
696
845
  libfcache_cache_value_t *cache_value = NULL;
697
845
  libfsapfs_btree_node_t *node         = NULL;
698
845
  libfsapfs_data_block_t *data_block   = NULL;
699
845
  static char *function                = "libfsapfs_snapshot_metadata_tree_get_sub_node";
700
845
  int result                           = 0;
701
702
#if defined( HAVE_PROFILER )
703
  int64_t profiler_start_timestamp     = 0;
704
#endif
705
706
845
  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
845
  if( sub_node_block_number > (uint64_t) INT_MAX )
718
109
  {
719
109
    libcerror_error_set(
720
109
     error,
721
109
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
722
109
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
723
109
     "%s: invalid sub node block number value out of bounds.",
724
109
     function );
725
726
109
    return( -1 );
727
109
  }
728
736
  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
736
  result = libfcache_cache_get_value_by_identifier(
760
736
            snapshot_metadata_tree->node_cache,
761
736
            0,
762
736
            (off64_t) sub_node_block_number,
763
736
            0,
764
736
            &cache_value,
765
736
            error );
766
767
736
  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
736
  else if( result == 0 )
779
170
  {
780
170
    if( libfdata_vector_get_element_value_by_index(
781
170
         snapshot_metadata_tree->data_block_vector,
782
170
         (intptr_t *) file_io_handle,
783
170
         (libfdata_cache_t *) snapshot_metadata_tree->data_block_cache,
784
170
         (int) sub_node_block_number,
785
170
         (intptr_t **) &data_block,
786
170
         0,
787
170
         error ) != 1 )
788
51
    {
789
51
      libcerror_error_set(
790
51
       error,
791
51
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
792
51
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
793
51
       "%s: unable to retrieve data block: %" PRIu64 ".",
794
51
       function,
795
51
       sub_node_block_number );
796
797
51
      goto on_error;
798
51
    }
799
119
    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
119
    if( libfsapfs_btree_node_initialize(
812
119
         &node,
813
119
         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
119
    if( libfsapfs_btree_node_read_data(
825
119
         node,
826
119
         data_block->data,
827
119
         data_block->data_size,
828
119
         error ) != 1 )
829
4
    {
830
4
      libcerror_error_set(
831
4
       error,
832
4
       LIBCERROR_ERROR_DOMAIN_IO,
833
4
       LIBCERROR_IO_ERROR_READ_FAILED,
834
4
       "%s: unable to read B-tree node.",
835
4
       function );
836
837
4
      goto on_error;
838
4
    }
839
115
    if( node->object_type != 0x40000003UL )
840
24
    {
841
24
      libcerror_error_set(
842
24
       error,
843
24
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
844
24
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
845
24
       "%s: invalid object type: 0x%08" PRIx32 ".",
846
24
       function,
847
24
       node->object_type );
848
849
24
      goto on_error;
850
24
    }
851
91
    if( node->object_subtype != 0x00000010UL )
852
58
    {
853
58
      libcerror_error_set(
854
58
       error,
855
58
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
856
58
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
857
58
       "%s: invalid object subtype: 0x%08" PRIx32 ".",
858
58
       function,
859
58
       node->object_subtype );
860
861
58
      goto on_error;
862
58
    }
863
33
    if( ( node->node_header->flags & 0x0001 ) != 0 )
864
2
    {
865
2
      libcerror_error_set(
866
2
       error,
867
2
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
868
2
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
869
2
       "%s: unsupported flags: 0x%04" PRIx16 ".",
870
2
       function,
871
2
       node->node_header->flags );
872
873
2
      goto on_error;
874
2
    }
875
31
    if( libfcache_cache_set_value_by_identifier(
876
31
         snapshot_metadata_tree->node_cache,
877
31
         0,
878
31
         (off64_t) sub_node_block_number,
879
31
         0,
880
31
         (intptr_t *) node,
881
31
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_btree_node_free,
882
31
         LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
883
31
         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
31
    node = NULL;
895
896
31
    if( libfcache_cache_get_value_by_identifier(
897
31
         snapshot_metadata_tree->node_cache,
898
31
         0,
899
31
         (off64_t) sub_node_block_number,
900
31
         0,
901
31
         &cache_value,
902
31
         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
31
  }
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
597
  if( libfcache_cache_value_get_value(
938
597
       cache_value,
939
597
       (intptr_t **) sub_node,
940
597
       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
597
  return( 1 );
952
953
139
on_error:
954
139
  if( node != NULL )
955
88
  {
956
88
    libfsapfs_btree_node_free(
957
88
     &node,
958
88
     NULL );
959
88
  }
960
139
  return( -1 );
961
597
}
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
  int btree_entry_index                   = 0;
978
0
  int is_leaf_node                        = 0;
979
0
  int number_of_entries                   = 0;
980
981
#if defined( HAVE_DEBUG_OUTPUT )
982
  uint8_t snapshot_metadata_data_type     = 0;
983
#endif
984
985
0
  if( snapshot_metadata_tree == NULL )
986
0
  {
987
0
    libcerror_error_set(
988
0
     error,
989
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
990
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
991
0
     "%s: invalid snapshot metadata tree.",
992
0
     function );
993
994
0
    return( -1 );
995
0
  }
996
0
  if( btree_entry == NULL )
997
0
  {
998
0
    libcerror_error_set(
999
0
     error,
1000
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1001
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1002
0
     "%s: invalid B-tree entry.",
1003
0
     function );
1004
1005
0
    return( -1 );
1006
0
  }
1007
#if defined( HAVE_DEBUG_OUTPUT )
1008
  if( libcnotify_verbose != 0 )
1009
  {
1010
    libcnotify_printf(
1011
     "%s: retrieving B-tree entry identifier: %" PRIu64 ".\n",
1012
     function,
1013
     object_identifier );
1014
  }
1015
#endif
1016
0
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1017
0
                  node,
1018
0
                  error );
1019
1020
0
  if( is_leaf_node == -1 )
1021
0
  {
1022
0
    libcerror_error_set(
1023
0
     error,
1024
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1025
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1026
0
     "%s: unable to determine if B-tree node is a leaf node.",
1027
0
     function );
1028
1029
0
    return( -1 );
1030
0
  }
1031
0
  if( libfsapfs_btree_node_get_number_of_entries(
1032
0
       node,
1033
0
       &number_of_entries,
1034
0
       error ) != 1 )
1035
0
  {
1036
0
    libcerror_error_set(
1037
0
     error,
1038
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1039
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1040
0
     "%s: unable to retrieve number of entries from B-tree node.",
1041
0
     function );
1042
1043
0
    return( -1 );
1044
0
  }
1045
0
  for( btree_entry_index = 0;
1046
0
       btree_entry_index < number_of_entries;
1047
0
       btree_entry_index++ )
1048
0
  {
1049
0
    if( libfsapfs_btree_node_get_entry_by_index(
1050
0
         node,
1051
0
         btree_entry_index,
1052
0
         &entry,
1053
0
         error ) != 1 )
1054
0
    {
1055
0
      libcerror_error_set(
1056
0
       error,
1057
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1058
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1059
0
       "%s: unable to retrieve number of entries from B-tree node.",
1060
0
       function );
1061
1062
0
      return( -1 );
1063
0
    }
1064
0
    if( entry == NULL )
1065
0
    {
1066
0
      libcerror_error_set(
1067
0
       error,
1068
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1069
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1070
0
       "%s: invalid B-tree entry: %d.",
1071
0
       function,
1072
0
       btree_entry_index );
1073
1074
0
      return( -1 );
1075
0
    }
1076
0
    if( entry->key_data == NULL )
1077
0
    {
1078
0
      libcerror_error_set(
1079
0
       error,
1080
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1081
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1082
0
       "%s: invalid B-tree entry: %d - missing key data.",
1083
0
       function,
1084
0
       btree_entry_index );
1085
1086
0
      return( -1 );
1087
0
    }
1088
0
    if( entry->key_data_size < 8 )
1089
0
    {
1090
0
      libcerror_error_set(
1091
0
       error,
1092
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1093
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1094
0
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
1095
0
       function,
1096
0
       btree_entry_index );
1097
1098
0
      return( -1 );
1099
0
    }
1100
0
    byte_stream_copy_to_uint64_little_endian(
1101
0
     entry->key_data,
1102
0
     snapshot_metadata_identifier );
1103
1104
#if defined( HAVE_DEBUG_OUTPUT )
1105
    if( libcnotify_verbose != 0 )
1106
    {
1107
      snapshot_metadata_data_type = (uint8_t) ( snapshot_metadata_identifier >> 60 );
1108
1109
      libcnotify_printf(
1110
       "%s: B-tree entry: %d, identifier: %" PRIu64 ", data type: 0x%" PRIx8 " %s\n",
1111
       function,
1112
       btree_entry_index,
1113
       snapshot_metadata_identifier & 0x0fffffffffffffffUL,
1114
       snapshot_metadata_data_type,
1115
       libfsapfs_debug_print_file_system_data_type(
1116
        snapshot_metadata_data_type ) );
1117
    }
1118
#endif
1119
0
    snapshot_metadata_identifier &= 0x0fffffffffffffffUL;
1120
1121
0
    if( is_leaf_node != 0 )
1122
0
    {
1123
0
      if( snapshot_metadata_identifier == object_identifier )
1124
0
      {
1125
0
        *btree_entry = entry;
1126
1127
0
        return( 1 );
1128
0
      }
1129
0
    }
1130
0
    else
1131
0
    {
1132
0
      if( snapshot_metadata_identifier >= object_identifier )
1133
0
      {
1134
0
        if( ( previous_entry == NULL )
1135
0
         || ( snapshot_metadata_identifier == object_identifier ) )
1136
0
        {
1137
0
          previous_entry = entry;
1138
0
        }
1139
0
        *btree_entry = previous_entry;
1140
1141
0
        return( 1 );
1142
0
      }
1143
0
      previous_entry = entry;
1144
0
    }
1145
0
  }
1146
0
  if( is_leaf_node == 0 )
1147
0
  {
1148
0
    *btree_entry = previous_entry;
1149
1150
0
    return( 1 );
1151
0
  }
1152
0
  return( 0 );
1153
0
}
1154
1155
/* Retrieves an entry for a specific identifier from the snapshot metadata tree
1156
 * Returns 1 if successful, 0 if not found or -1 on error
1157
 */
1158
int libfsapfs_snapshot_metadata_tree_get_entry_by_identifier(
1159
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1160
     libbfio_handle_t *file_io_handle,
1161
     uint64_t object_identifier,
1162
     libfsapfs_btree_node_t **btree_node,
1163
     libfsapfs_btree_entry_t **btree_entry,
1164
     libcerror_error_t **error )
1165
0
{
1166
0
  libfsapfs_btree_entry_t *entry = NULL;
1167
0
  libfsapfs_btree_node_t *node   = NULL;
1168
0
  static char *function          = "libfsapfs_snapshot_metadata_tree_get_entry_by_identifier";
1169
0
  uint64_t sub_node_block_number = 0;
1170
0
  int is_leaf_node               = 0;
1171
0
  int recursion_depth            = 0;
1172
0
  int result                     = 0;
1173
1174
0
  if( snapshot_metadata_tree == NULL )
1175
0
  {
1176
0
    libcerror_error_set(
1177
0
     error,
1178
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1179
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1180
0
     "%s: invalid snapshot metadata tree.",
1181
0
     function );
1182
1183
0
    return( -1 );
1184
0
  }
1185
0
  if( btree_node == NULL )
1186
0
  {
1187
0
    libcerror_error_set(
1188
0
     error,
1189
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1190
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1191
0
     "%s: invalid B-tree node.",
1192
0
     function );
1193
1194
0
    return( -1 );
1195
0
  }
1196
0
  if( btree_entry == NULL )
1197
0
  {
1198
0
    libcerror_error_set(
1199
0
     error,
1200
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1201
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1202
0
     "%s: invalid B-tree entry.",
1203
0
     function );
1204
1205
0
    return( -1 );
1206
0
  }
1207
0
  if( libfsapfs_snapshot_metadata_tree_get_root_node(
1208
0
       snapshot_metadata_tree,
1209
0
       file_io_handle,
1210
0
       snapshot_metadata_tree->root_node_block_number,
1211
0
       &node,
1212
0
       error ) != 1 )
1213
0
  {
1214
0
    libcerror_error_set(
1215
0
     error,
1216
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1217
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1218
0
     "%s: unable to retrieve B-tree root node.",
1219
0
     function );
1220
1221
0
    return( -1 );
1222
0
  }
1223
0
  do
1224
0
  {
1225
0
    if( ( recursion_depth < 0 )
1226
0
     || ( recursion_depth > LIBFSAPFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1227
0
    {
1228
0
      libcerror_error_set(
1229
0
       error,
1230
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1231
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1232
0
       "%s: invalid recursion depth value out of bounds.",
1233
0
       function );
1234
1235
0
      return( -1 );
1236
0
    }
1237
0
    is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1238
0
                    node,
1239
0
                    error );
1240
1241
0
    if( is_leaf_node == -1 )
1242
0
    {
1243
0
      libcerror_error_set(
1244
0
       error,
1245
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1246
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1247
0
       "%s: unable to determine if B-tree node is a leaf node.",
1248
0
       function );
1249
1250
0
      return( -1 );
1251
0
    }
1252
0
    result = libfsapfs_snapshot_metadata_tree_get_entry_from_node_by_identifier(
1253
0
              snapshot_metadata_tree,
1254
0
              node,
1255
0
              object_identifier,
1256
0
              &entry,
1257
0
              error );
1258
1259
0
    if( result == -1 )
1260
0
    {
1261
0
      libcerror_error_set(
1262
0
       error,
1263
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1264
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1265
0
       "%s: unable to retrieve entry from B-tree node.",
1266
0
       function );
1267
1268
0
      return( -1 );
1269
0
    }
1270
0
    else if( result == 0 )
1271
0
    {
1272
0
      break;
1273
0
    }
1274
0
    if( is_leaf_node != 0 )
1275
0
    {
1276
0
      *btree_node  = node;
1277
0
      *btree_entry = entry;
1278
1279
0
      return( 1 );
1280
0
    }
1281
0
    if( entry == NULL )
1282
0
    {
1283
0
      libcerror_error_set(
1284
0
       error,
1285
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1286
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1287
0
       "%s: invalid B-tree entry.",
1288
0
       function );
1289
1290
0
      return( -1 );
1291
0
    }
1292
0
    if( entry->value_data == NULL )
1293
0
    {
1294
0
      libcerror_error_set(
1295
0
       error,
1296
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1297
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1298
0
       "%s: invalid B-tree entry - missing value data.",
1299
0
       function );
1300
1301
0
      return( -1 );
1302
0
    }
1303
0
    if( entry->value_data_size != 8 )
1304
0
    {
1305
0
      libcerror_error_set(
1306
0
       error,
1307
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1308
0
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1309
0
       "%s: invalid B-tree entry - unsupported value data size.",
1310
0
       function );
1311
1312
0
      return( -1 );
1313
0
    }
1314
0
    byte_stream_copy_to_uint64_little_endian(
1315
0
     entry->value_data,
1316
0
     sub_node_block_number );
1317
1318
#if defined( HAVE_DEBUG_OUTPUT )
1319
    if( libcnotify_verbose != 0 )
1320
    {
1321
      libcnotify_printf(
1322
       "%s: B-tree sub node block number: %" PRIu64 "\n",
1323
       function,
1324
       sub_node_block_number );
1325
    }
1326
#endif
1327
0
    node = NULL;
1328
1329
0
    if( libfsapfs_snapshot_metadata_tree_get_sub_node(
1330
0
         snapshot_metadata_tree,
1331
0
         file_io_handle,
1332
0
         sub_node_block_number,
1333
0
         &node,
1334
0
         error ) != 1 )
1335
0
    {
1336
0
      libcerror_error_set(
1337
0
       error,
1338
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1339
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1340
0
       "%s: unable to retrieve B-tree sub node from block: %" PRIu64 ".",
1341
0
       function,
1342
0
       sub_node_block_number );
1343
1344
0
      return( -1 );
1345
0
    }
1346
0
    recursion_depth++;
1347
0
  }
1348
0
  while( is_leaf_node == 0 );
1349
1350
0
  return( 0 );
1351
0
}
1352
1353
/* Retrieves the snapshot metadata of a specific object identifier
1354
 * Returns 1 if successful, 0 if no such value or -1 on error
1355
 */
1356
int libfsapfs_snapshot_metadata_tree_get_metadata_by_object_identifier(
1357
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1358
     libbfio_handle_t *file_io_handle,
1359
     uint64_t object_identifier,
1360
     libfsapfs_snapshot_metadata_t **metadata,
1361
     libcerror_error_t **error )
1362
0
{
1363
0
  libfsapfs_btree_entry_t *entry = NULL;
1364
0
  libfsapfs_btree_node_t *node   = NULL;
1365
0
  static char *function          = "libfsapfs_snapshot_metadata_tree_get_metadata_by_object_identifier";
1366
0
  int result                     = 0;
1367
1368
0
  if( snapshot_metadata_tree == NULL )
1369
0
  {
1370
0
    libcerror_error_set(
1371
0
     error,
1372
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1373
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1374
0
     "%s: invalid snapshot metadata tree.",
1375
0
     function );
1376
1377
0
    return( -1 );
1378
0
  }
1379
0
  if( metadata == NULL )
1380
0
  {
1381
0
    libcerror_error_set(
1382
0
     error,
1383
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1384
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1385
0
     "%s: invalid metadata.",
1386
0
     function );
1387
1388
0
    return( -1 );
1389
0
  }
1390
0
  if( *metadata != NULL )
1391
0
  {
1392
0
    libcerror_error_set(
1393
0
     error,
1394
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1395
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1396
0
     "%s: invalid metadata value already set.",
1397
0
     function );
1398
1399
0
    return( -1 );
1400
0
  }
1401
0
  result = libfsapfs_snapshot_metadata_tree_get_entry_by_identifier(
1402
0
            snapshot_metadata_tree,
1403
0
            file_io_handle,
1404
0
            object_identifier,
1405
0
            &node,
1406
0
            &entry,
1407
0
            error );
1408
1409
0
  if( result == -1 )
1410
0
  {
1411
0
    libcerror_error_set(
1412
0
     error,
1413
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1414
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1415
0
     "%s: unable to retrieve entry from B-tree.",
1416
0
     function );
1417
1418
0
    goto on_error;
1419
0
  }
1420
0
  else if( result != 0 )
1421
0
  {
1422
0
    if( node == NULL )
1423
0
    {
1424
0
      libcerror_error_set(
1425
0
       error,
1426
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1427
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1428
0
       "%s: invalid B-tree node.",
1429
0
       function );
1430
1431
0
      goto on_error;
1432
0
    }
1433
0
    if( entry == NULL )
1434
0
    {
1435
0
      libcerror_error_set(
1436
0
       error,
1437
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1438
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1439
0
       "%s: invalid B-tree entry.",
1440
0
       function );
1441
1442
0
      goto on_error;
1443
0
    }
1444
0
    if( libfsapfs_snapshot_metadata_initialize(
1445
0
         metadata,
1446
0
         error ) != 1 )
1447
0
    {
1448
0
      libcerror_error_set(
1449
0
       error,
1450
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1451
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1452
0
       "%s: unable to create snapshot metadata.",
1453
0
       function );
1454
1455
0
      goto on_error;
1456
0
    }
1457
0
    if( libfsapfs_snapshot_metadata_read_key_data(
1458
0
         *metadata,
1459
0
         entry->key_data,
1460
0
         (size_t) entry->key_data_size,
1461
0
         error ) != 1 )
1462
0
    {
1463
0
      libcerror_error_set(
1464
0
       error,
1465
0
       LIBCERROR_ERROR_DOMAIN_IO,
1466
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1467
0
       "%s: unable to read snapshot metadata key data.",
1468
0
       function );
1469
1470
0
      goto on_error;
1471
0
    }
1472
0
    if( libfsapfs_snapshot_metadata_read_value_data(
1473
0
         *metadata,
1474
0
         entry->value_data,
1475
0
         (size_t) entry->value_data_size,
1476
0
         error ) != 1 )
1477
0
    {
1478
0
      libcerror_error_set(
1479
0
       error,
1480
0
       LIBCERROR_ERROR_DOMAIN_IO,
1481
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1482
0
       "%s: unable to read snapshot metadata value data.",
1483
0
       function );
1484
1485
0
      goto on_error;
1486
0
    }
1487
0
    node = NULL;
1488
0
  }
1489
0
  return( result );
1490
1491
0
on_error:
1492
0
  if( *metadata != NULL )
1493
0
  {
1494
0
    libfsapfs_snapshot_metadata_free(
1495
0
     metadata,
1496
0
     NULL );
1497
0
  }
1498
0
  return( -1 );
1499
0
}
1500
1501
/* Retrieves snapshots for a specific parent identifier from the snapshot metadata tree leaf node
1502
 * Returns 1 if successful, 0 if not found or -1 on error
1503
 */
1504
int libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node(
1505
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1506
     libfsapfs_btree_node_t *node,
1507
     libcdata_array_t *snapshots,
1508
     libcerror_error_t **error )
1509
1.39k
{
1510
1.39k
  libfsapfs_btree_entry_t *entry                   = NULL;
1511
1.39k
  libfsapfs_snapshot_metadata_t *snapshot_metadata = NULL;
1512
1.39k
  static char *function                            = "libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node";
1513
1.39k
  uint64_t snapshot_metadata_identifier            = 0;
1514
1.39k
  uint8_t snapshot_metadata_data_type              = 0;
1515
1.39k
  int btree_entry_index                            = 0;
1516
1.39k
  int entry_index                                  = 0;
1517
1.39k
  int found_snapshot_metadata                      = 0;
1518
1.39k
  int is_leaf_node                                 = 0;
1519
1.39k
  int number_of_entries                            = 0;
1520
1521
1.39k
  if( snapshot_metadata_tree == NULL )
1522
0
  {
1523
0
    libcerror_error_set(
1524
0
     error,
1525
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1526
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1527
0
     "%s: invalid snapshot metadata tree.",
1528
0
     function );
1529
1530
0
    return( -1 );
1531
0
  }
1532
1.39k
  if( node == NULL )
1533
0
  {
1534
0
    libcerror_error_set(
1535
0
     error,
1536
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1537
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1538
0
     "%s: invalid node.",
1539
0
     function );
1540
1541
0
    return( -1 );
1542
0
  }
1543
1.39k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1544
1.39k
                  node,
1545
1.39k
                  error );
1546
1547
1.39k
  if( is_leaf_node == -1 )
1548
0
  {
1549
0
    libcerror_error_set(
1550
0
     error,
1551
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1552
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1553
0
     "%s: unable to determine if B-tree node is a leaf node.",
1554
0
     function );
1555
1556
0
    goto on_error;
1557
0
  }
1558
1.39k
  else if( is_leaf_node == 0 )
1559
0
  {
1560
0
    libcerror_error_set(
1561
0
     error,
1562
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1563
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1564
0
     "%s: invalid node - not a leaf node.",
1565
0
     function );
1566
1567
0
    goto on_error;
1568
0
  }
1569
1.39k
  if( libfsapfs_btree_node_get_number_of_entries(
1570
1.39k
       node,
1571
1.39k
       &number_of_entries,
1572
1.39k
       error ) != 1 )
1573
0
  {
1574
0
    libcerror_error_set(
1575
0
     error,
1576
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1577
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1578
0
     "%s: unable to retrieve number of entries from B-tree node.",
1579
0
     function );
1580
1581
0
    goto on_error;
1582
0
  }
1583
1.39k
  for( btree_entry_index = 0;
1584
1.59k
       btree_entry_index < number_of_entries;
1585
1.39k
       btree_entry_index++ )
1586
379
  {
1587
379
    if( libfsapfs_btree_node_get_entry_by_index(
1588
379
         node,
1589
379
         btree_entry_index,
1590
379
         &entry,
1591
379
         error ) != 1 )
1592
0
    {
1593
0
      libcerror_error_set(
1594
0
       error,
1595
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1596
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1597
0
       "%s: unable to retrieve number of entries from B-tree node.",
1598
0
       function );
1599
1600
0
      goto on_error;
1601
0
    }
1602
379
    if( entry == NULL )
1603
0
    {
1604
0
      libcerror_error_set(
1605
0
       error,
1606
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1607
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1608
0
       "%s: invalid B-tree entry: %d.",
1609
0
       function,
1610
0
       btree_entry_index );
1611
1612
0
      goto on_error;
1613
0
    }
1614
379
    if( entry->key_data == NULL )
1615
14
    {
1616
14
      libcerror_error_set(
1617
14
       error,
1618
14
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1619
14
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1620
14
       "%s: invalid B-tree entry: %d - missing key data.",
1621
14
       function,
1622
14
       btree_entry_index );
1623
1624
14
      goto on_error;
1625
14
    }
1626
365
    if( entry->key_data_size < 8 )
1627
5
    {
1628
5
      libcerror_error_set(
1629
5
       error,
1630
5
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1631
5
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1632
5
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
1633
5
       function,
1634
5
       btree_entry_index );
1635
1636
5
      return( -1 );
1637
5
    }
1638
360
    byte_stream_copy_to_uint64_little_endian(
1639
360
     entry->key_data,
1640
360
     snapshot_metadata_identifier );
1641
1642
360
    snapshot_metadata_data_type = (uint8_t) ( snapshot_metadata_identifier >> 60 );
1643
1644
#if defined( HAVE_DEBUG_OUTPUT )
1645
    if( libcnotify_verbose != 0 )
1646
    {
1647
      libcnotify_printf(
1648
       "%s: B-tree entry: %d, identifier: %" PRIu64 ", data type: 0x%" PRIx8 " %s\n",
1649
       function,
1650
       btree_entry_index,
1651
       snapshot_metadata_identifier & 0x0fffffffffffffffUL,
1652
       snapshot_metadata_data_type,
1653
       libfsapfs_debug_print_file_system_data_type(
1654
        snapshot_metadata_data_type ) );
1655
    }
1656
#endif
1657
360
    if( snapshot_metadata_data_type > LIBFSAPFS_FILE_SYSTEM_DATA_TYPE_SNAPSHOT_METADATA )
1658
89
    {
1659
89
      break;
1660
89
    }
1661
271
    if( libfsapfs_snapshot_metadata_initialize(
1662
271
         &snapshot_metadata,
1663
271
         error ) != 1 )
1664
0
    {
1665
0
      libcerror_error_set(
1666
0
       error,
1667
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1668
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1669
0
       "%s: unable to create snapshot metadata.",
1670
0
       function );
1671
1672
0
      goto on_error;
1673
0
    }
1674
271
    if( libfsapfs_snapshot_metadata_read_key_data(
1675
271
         snapshot_metadata,
1676
271
         entry->key_data,
1677
271
         (size_t) entry->key_data_size,
1678
271
         error ) != 1 )
1679
0
    {
1680
0
      libcerror_error_set(
1681
0
       error,
1682
0
       LIBCERROR_ERROR_DOMAIN_IO,
1683
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1684
0
       "%s: unable to read snapshot metadata key data.",
1685
0
       function );
1686
1687
0
      goto on_error;
1688
0
    }
1689
271
    if( libfsapfs_snapshot_metadata_read_value_data(
1690
271
         snapshot_metadata,
1691
271
         entry->value_data,
1692
271
         (size_t) entry->value_data_size,
1693
271
         error ) != 1 )
1694
78
    {
1695
78
      libcerror_error_set(
1696
78
       error,
1697
78
       LIBCERROR_ERROR_DOMAIN_IO,
1698
78
       LIBCERROR_IO_ERROR_READ_FAILED,
1699
78
       "%s: unable to read snapshot metadata value data.",
1700
78
       function );
1701
1702
78
      goto on_error;
1703
78
    }
1704
193
    if( libcdata_array_append_entry(
1705
193
         snapshots,
1706
193
         &entry_index,
1707
193
         (intptr_t *) snapshot_metadata,
1708
193
         error ) != 1 )
1709
0
    {
1710
0
      libcerror_error_set(
1711
0
       error,
1712
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1713
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1714
0
       "%s: unable to append snapshot metadata to array.",
1715
0
       function );
1716
1717
0
      goto on_error;
1718
0
    }
1719
193
    snapshot_metadata = NULL;
1720
1721
193
    found_snapshot_metadata = 1;
1722
193
  }
1723
1.30k
  return( found_snapshot_metadata );
1724
1725
92
on_error:
1726
92
  if( snapshot_metadata != NULL )
1727
78
  {
1728
78
    libfsapfs_snapshot_metadata_free(
1729
78
     &snapshot_metadata,
1730
78
     NULL );
1731
78
  }
1732
92
  libcdata_array_empty(
1733
92
   snapshots,
1734
92
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_snapshot_metadata_free,
1735
92
   NULL );
1736
1737
92
  return( -1 );
1738
1.39k
}
1739
1740
/* Retrieves snapshots for a specific parent identifier from the snapshot metadata tree branch node
1741
 * Returns 1 if successful, 0 if not found or -1 on error
1742
 */
1743
int libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node(
1744
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
1745
     libbfio_handle_t *file_io_handle,
1746
     libfsapfs_btree_node_t *node,
1747
     uint64_t transaction_identifier,
1748
     libcdata_array_t *snapshots,
1749
     int recursion_depth,
1750
     libcerror_error_t **error )
1751
1.08k
{
1752
1.08k
  libfsapfs_btree_entry_t *entry        = NULL;
1753
1.08k
  libfsapfs_btree_node_t *sub_node      = NULL;
1754
1.08k
  static char *function                 = "libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node";
1755
1.08k
  uint64_t snapshot_metadata_identifier = 0;
1756
1.08k
  uint64_t sub_node_block_number        = 0;
1757
1.08k
  uint8_t snapshot_metadata_data_type   = 0;
1758
1.08k
  int entry_index                       = 0;
1759
1.08k
  int found_snapshot_metadata           = 0;
1760
1.08k
  int is_leaf_node                      = 0;
1761
1.08k
  int number_of_entries                 = 0;
1762
1.08k
  int result                            = 0;
1763
1764
1.08k
  if( snapshot_metadata_tree == NULL )
1765
0
  {
1766
0
    libcerror_error_set(
1767
0
     error,
1768
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1769
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1770
0
     "%s: invalid snapshot metadata tree.",
1771
0
     function );
1772
1773
0
    return( -1 );
1774
0
  }
1775
1.08k
  if( node == NULL )
1776
0
  {
1777
0
    libcerror_error_set(
1778
0
     error,
1779
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1780
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1781
0
     "%s: invalid node.",
1782
0
     function );
1783
1784
0
    return( -1 );
1785
0
  }
1786
1.08k
  if( ( recursion_depth < 0 )
1787
1.08k
   || ( recursion_depth > LIBFSAPFS_MAXIMUM_BTREE_NODE_RECURSION_DEPTH ) )
1788
2
  {
1789
2
    libcerror_error_set(
1790
2
     error,
1791
2
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1792
2
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1793
2
     "%s: invalid recursion depth value out of bounds.",
1794
2
     function );
1795
1796
2
    return( -1 );
1797
2
  }
1798
1.08k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1799
1.08k
                  node,
1800
1.08k
                  error );
1801
1802
1.08k
  if( is_leaf_node == -1 )
1803
0
  {
1804
0
    libcerror_error_set(
1805
0
     error,
1806
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1807
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1808
0
     "%s: unable to determine if B-tree node is a leaf node.",
1809
0
     function );
1810
1811
0
    goto on_error;
1812
0
  }
1813
1.08k
  else if( is_leaf_node != 0 )
1814
0
  {
1815
0
    libcerror_error_set(
1816
0
     error,
1817
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1818
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1819
0
     "%s: invalid node - not a branch node.",
1820
0
     function );
1821
1822
0
    goto on_error;
1823
0
  }
1824
1.08k
  if( libfsapfs_btree_node_get_number_of_entries(
1825
1.08k
       node,
1826
1.08k
       &number_of_entries,
1827
1.08k
       error ) != 1 )
1828
0
  {
1829
0
    libcerror_error_set(
1830
0
     error,
1831
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1832
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1833
0
     "%s: unable to retrieve number of entries from B-tree node.",
1834
0
     function );
1835
1836
0
    goto on_error;
1837
0
  }
1838
1.08k
  for( entry_index = 0;
1839
1.16k
       entry_index < number_of_entries;
1840
1.08k
       entry_index++ )
1841
1.12k
  {
1842
1.12k
    if( libfsapfs_btree_node_get_entry_by_index(
1843
1.12k
         node,
1844
1.12k
         entry_index,
1845
1.12k
         &entry,
1846
1.12k
         error ) != 1 )
1847
0
    {
1848
0
      libcerror_error_set(
1849
0
       error,
1850
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1851
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1852
0
       "%s: unable to retrieve number of entries from B-tree node.",
1853
0
       function );
1854
1855
0
      goto on_error;
1856
0
    }
1857
1.12k
    if( entry == NULL )
1858
0
    {
1859
0
      libcerror_error_set(
1860
0
       error,
1861
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1862
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1863
0
       "%s: invalid B-tree entry: %d.",
1864
0
       function,
1865
0
       entry_index );
1866
1867
0
      goto on_error;
1868
0
    }
1869
1.12k
    if( entry->key_data == NULL )
1870
10
    {
1871
10
      libcerror_error_set(
1872
10
       error,
1873
10
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1874
10
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1875
10
       "%s: invalid B-tree entry: %d - missing key data.",
1876
10
       function,
1877
10
       entry_index );
1878
1879
10
      goto on_error;
1880
10
    }
1881
1.11k
    if( entry->key_data_size < 8 )
1882
7
    {
1883
7
      libcerror_error_set(
1884
7
       error,
1885
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1886
7
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1887
7
       "%s: invalid B-tree entry: %d - key data size value out of bounds.",
1888
7
       function,
1889
7
       entry_index );
1890
1891
7
      goto on_error;
1892
7
    }
1893
1.10k
    byte_stream_copy_to_uint64_little_endian(
1894
1.10k
     entry->key_data,
1895
1.10k
     snapshot_metadata_identifier );
1896
1897
1.10k
    snapshot_metadata_data_type = (uint8_t) ( snapshot_metadata_identifier >> 60 );
1898
1899
#if defined( HAVE_DEBUG_OUTPUT )
1900
    if( libcnotify_verbose != 0 )
1901
    {
1902
      libcnotify_printf(
1903
       "%s: B-tree entry: %d, identifier: %" PRIu64 ", data type: 0x%" PRIx8 " %s\n",
1904
       function,
1905
       entry_index,
1906
       snapshot_metadata_identifier & 0x0fffffffffffffffUL,
1907
       snapshot_metadata_data_type,
1908
       libfsapfs_debug_print_file_system_data_type(
1909
        snapshot_metadata_data_type ) );
1910
    }
1911
#endif
1912
1.10k
    if( snapshot_metadata_data_type > LIBFSAPFS_FILE_SYSTEM_DATA_TYPE_SNAPSHOT_METADATA )
1913
40
    {
1914
40
      break;
1915
40
    }
1916
1.06k
    if( libfsapfs_snapshot_metadata_tree_get_sub_node_block_number_from_entry(
1917
1.06k
         snapshot_metadata_tree,
1918
1.06k
         file_io_handle,
1919
1.06k
         entry,
1920
1.06k
         transaction_identifier,
1921
1.06k
         &sub_node_block_number,
1922
1.06k
         error ) != 1 )
1923
220
    {
1924
220
      libcerror_error_set(
1925
220
       error,
1926
220
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1927
220
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1928
220
       "%s: unable to determine sub node block number.",
1929
220
       function );
1930
1931
220
      goto on_error;
1932
220
    }
1933
845
    if( libfsapfs_snapshot_metadata_tree_get_sub_node(
1934
845
         snapshot_metadata_tree,
1935
845
         file_io_handle,
1936
845
         sub_node_block_number,
1937
845
         &sub_node,
1938
845
         error ) != 1 )
1939
248
    {
1940
248
      libcerror_error_set(
1941
248
       error,
1942
248
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1943
248
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1944
248
       "%s: unable to retrieve B-tree sub node from block: %" PRIu64 ".",
1945
248
       function,
1946
248
       sub_node_block_number );
1947
1948
248
      goto on_error;
1949
248
    }
1950
597
    is_leaf_node = libfsapfs_btree_node_is_leaf_node(
1951
597
                    sub_node,
1952
597
                    error );
1953
1954
597
    if( is_leaf_node == -1 )
1955
0
    {
1956
0
      libcerror_error_set(
1957
0
       error,
1958
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1959
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1960
0
       "%s: unable to determine if B-tree sub node is a leaf node.",
1961
0
       function );
1962
1963
0
      goto on_error;
1964
0
    }
1965
597
    if( is_leaf_node != 0 )
1966
40
    {
1967
40
      result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node(
1968
40
                snapshot_metadata_tree,
1969
40
                sub_node,
1970
40
                snapshots,
1971
40
                error );
1972
40
    }
1973
557
    else
1974
557
    {
1975
557
      result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node(
1976
557
                snapshot_metadata_tree,
1977
557
                file_io_handle,
1978
557
                sub_node,
1979
557
                transaction_identifier,
1980
557
                snapshots,
1981
557
                recursion_depth + 1,
1982
557
                error );
1983
557
    }
1984
597
    if( result == -1 )
1985
516
    {
1986
516
      libcerror_error_set(
1987
516
       error,
1988
516
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1989
516
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1990
516
       "%s: unable to retrieve snapshots from snapshot metadata tree sub node.",
1991
516
       function );
1992
1993
516
      goto on_error;
1994
516
    }
1995
81
    else if( result != 0 )
1996
0
    {
1997
0
      found_snapshot_metadata = 1;
1998
0
    }
1999
81
    sub_node = NULL;
2000
81
  }
2001
85
  return( found_snapshot_metadata );
2002
2003
1.00k
on_error:
2004
1.00k
  libcdata_array_empty(
2005
1.00k
   snapshots,
2006
1.00k
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_snapshot_metadata_free,
2007
1.00k
   NULL );
2008
2009
1.00k
  return( -1 );
2010
1.08k
}
2011
2012
/* Retrieves snapshots for a specific parent identifier from the snapshot metadata tree
2013
 * Returns 1 if successful, 0 if not found or -1 on error
2014
 */
2015
int libfsapfs_snapshot_metadata_tree_get_snapshots(
2016
     libfsapfs_snapshot_metadata_tree_t *snapshot_metadata_tree,
2017
     libbfio_handle_t *file_io_handle,
2018
     uint64_t transaction_identifier,
2019
     libcdata_array_t *snapshots,
2020
     libcerror_error_t **error )
2021
2.37k
{
2022
2.37k
  libfsapfs_btree_node_t *root_node = NULL;
2023
2.37k
  static char *function             = "libfsapfs_snapshot_metadata_tree_get_snapshots";
2024
2.37k
  int is_leaf_node                  = 0;
2025
2.37k
  int result                        = 0;
2026
2027
#if defined( HAVE_PROFILER )
2028
  int64_t profiler_start_timestamp  = 0;
2029
#endif
2030
2031
2.37k
  if( snapshot_metadata_tree == NULL )
2032
0
  {
2033
0
    libcerror_error_set(
2034
0
     error,
2035
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2036
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2037
0
     "%s: invalid snapshot metadata tree.",
2038
0
     function );
2039
2040
0
    return( -1 );
2041
0
  }
2042
#if defined( HAVE_PROFILER )
2043
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
2044
  {
2045
    if( libfsapfs_profiler_start_timing(
2046
         snapshot_metadata_tree->io_handle->profiler,
2047
         &profiler_start_timestamp,
2048
         error ) != 1 )
2049
    {
2050
      libcerror_error_set(
2051
       error,
2052
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2053
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2054
       "%s: unable to start timing.",
2055
       function );
2056
2057
      goto on_error;
2058
    }
2059
  }
2060
#endif /* defined( HAVE_PROFILER ) */
2061
2062
2.37k
  if( libfsapfs_snapshot_metadata_tree_get_root_node(
2063
2.37k
       snapshot_metadata_tree,
2064
2.37k
       file_io_handle,
2065
2.37k
       snapshot_metadata_tree->root_node_block_number,
2066
2.37k
       &root_node,
2067
2.37k
       error ) != 1 )
2068
485
  {
2069
485
    libcerror_error_set(
2070
485
     error,
2071
485
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2072
485
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2073
485
     "%s: unable to retrieve B-tree root node.",
2074
485
     function );
2075
2076
485
    goto on_error;
2077
485
  }
2078
1.89k
  if( root_node == NULL )
2079
0
  {
2080
0
    libcerror_error_set(
2081
0
     error,
2082
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2083
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2084
0
     "%s: invalid B-tree root node.",
2085
0
     function );
2086
2087
0
    goto on_error;
2088
0
  }
2089
1.89k
  is_leaf_node = libfsapfs_btree_node_is_leaf_node(
2090
1.89k
                  root_node,
2091
1.89k
                  error );
2092
2093
1.89k
  if( is_leaf_node == -1 )
2094
0
  {
2095
0
    libcerror_error_set(
2096
0
     error,
2097
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2098
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2099
0
     "%s: unable to determine if B-tree root node is a leaf node.",
2100
0
     function );
2101
2102
0
    goto on_error;
2103
0
  }
2104
1.89k
  if( is_leaf_node != 0 )
2105
1.35k
  {
2106
1.35k
    result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_leaf_node(
2107
1.35k
              snapshot_metadata_tree,
2108
1.35k
              root_node,
2109
1.35k
              snapshots,
2110
1.35k
              error );
2111
1.35k
  }
2112
531
  else
2113
531
  {
2114
531
    result = libfsapfs_snapshot_metadata_tree_get_snapshots_from_branch_node(
2115
531
              snapshot_metadata_tree,
2116
531
              file_io_handle,
2117
531
              root_node,
2118
531
              transaction_identifier,
2119
531
              snapshots,
2120
531
              0,
2121
531
              error );
2122
531
  }
2123
1.89k
  if( result == -1 )
2124
584
  {
2125
584
    libcerror_error_set(
2126
584
     error,
2127
584
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2128
584
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2129
584
     "%s: unable to retrieve snapshots from snapshot metadata tree root node.",
2130
584
     function );
2131
2132
584
    goto on_error;
2133
584
  }
2134
#if defined( HAVE_PROFILER )
2135
  if( snapshot_metadata_tree->io_handle->profiler != NULL )
2136
  {
2137
    if( libfsapfs_profiler_stop_timing(
2138
         snapshot_metadata_tree->io_handle->profiler,
2139
         profiler_start_timestamp,
2140
         function,
2141
         0,
2142
         0,
2143
         error ) != 1 )
2144
    {
2145
      libcerror_error_set(
2146
       error,
2147
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2148
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2149
       "%s: unable to stop timing.",
2150
       function );
2151
2152
      goto on_error;
2153
    }
2154
  }
2155
#endif /* defined( HAVE_PROFILER ) */
2156
2157
1.30k
  return( result );
2158
2159
1.06k
on_error:
2160
1.06k
  libcdata_array_empty(
2161
1.06k
   snapshots,
2162
1.06k
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_snapshot_metadata_free,
2163
1.06k
   NULL );
2164
2165
1.06k
  return( -1 );
2166
1.89k
}
2167