Coverage Report

Created: 2025-09-05 06:58

/src/libfsapfs/libfsapfs/libfsapfs_snapshot_metadata.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The snapshot metadata 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_debug.h"
28
#include "libfsapfs_libcerror.h"
29
#include "libfsapfs_libcnotify.h"
30
#include "libfsapfs_libfdatetime.h"
31
#include "libfsapfs_libuna.h"
32
#include "libfsapfs_snapshot_metadata.h"
33
34
#include "fsapfs_snapshot_metadata.h"
35
36
/* Creates physical_map_entry
37
 * Make sure the value snapshot_metadata is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsapfs_snapshot_metadata_initialize(
41
     libfsapfs_snapshot_metadata_t **snapshot_metadata,
42
     libcerror_error_t **error )
43
135
{
44
135
  static char *function = "libfsapfs_snapshot_metadata_initialize";
45
46
135
  if( snapshot_metadata == NULL )
47
0
  {
48
0
    libcerror_error_set(
49
0
     error,
50
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
51
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
52
0
     "%s: invalid snapshot metadata.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
135
  if( *snapshot_metadata != NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
62
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
63
0
     "%s: invalid snapshot metadata value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
135
  *snapshot_metadata = memory_allocate_structure(
69
135
                        libfsapfs_snapshot_metadata_t );
70
71
135
  if( *snapshot_metadata == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
76
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
77
0
     "%s: unable to create snapshot metadata.",
78
0
     function );
79
80
0
    goto on_error;
81
0
  }
82
135
  if( memory_set(
83
135
       *snapshot_metadata,
84
135
       0,
85
135
       sizeof( libfsapfs_snapshot_metadata_t ) ) == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
91
0
     "%s: unable to clear snapshot metadata.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
135
  return( 1 );
97
98
0
on_error:
99
0
  if( *snapshot_metadata != NULL )
100
0
  {
101
0
    memory_free(
102
0
     *snapshot_metadata );
103
104
0
    *snapshot_metadata = NULL;
105
0
  }
106
0
  return( -1 );
107
135
}
108
109
/* Frees snapshot metadata
110
 * Returns 1 if successful or -1 on error
111
 */
112
int libfsapfs_snapshot_metadata_free(
113
     libfsapfs_snapshot_metadata_t **snapshot_metadata,
114
     libcerror_error_t **error )
115
135
{
116
135
  static char *function = "libfsapfs_snapshot_metadata_free";
117
118
135
  if( snapshot_metadata == NULL )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
123
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
124
0
     "%s: invalid snapshot metadata.",
125
0
     function );
126
127
0
    return( -1 );
128
0
  }
129
135
  if( *snapshot_metadata != NULL )
130
135
  {
131
135
    if( ( *snapshot_metadata )->name != NULL )
132
82
    {
133
82
      memory_free(
134
82
       ( *snapshot_metadata )->name );
135
82
    }
136
135
    memory_free(
137
135
     *snapshot_metadata );
138
139
135
    *snapshot_metadata = NULL;
140
135
  }
141
135
  return( 1 );
142
135
}
143
144
/* Reads the snapshot metadata B-tree key data
145
 * Returns 1 if successful or -1 on error
146
 */
147
int libfsapfs_snapshot_metadata_read_key_data(
148
     libfsapfs_snapshot_metadata_t *snapshot_metadata,
149
     const uint8_t *data,
150
     size_t data_size,
151
     libcerror_error_t **error )
152
135
{
153
135
  static char *function = "libfsapfs_snapshot_metadata_read_key_data";
154
155
#if defined( HAVE_DEBUG_OUTPUT )
156
  uint64_t value_64bit  = 0;
157
#endif
158
159
135
  if( snapshot_metadata == NULL )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
164
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
165
0
     "%s: invalid snapshot metadata.",
166
0
     function );
167
168
0
    return( -1 );
169
0
  }
170
135
  if( data == NULL )
171
0
  {
172
0
    libcerror_error_set(
173
0
     error,
174
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
175
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
176
0
     "%s: invalid data.",
177
0
     function );
178
179
0
    return( -1 );
180
0
  }
181
135
  if( ( data_size < sizeof( fsapfs_snapshot_metadata_btree_key_t ) )
182
135
   || ( data_size > (size_t) SSIZE_MAX ) )
183
0
  {
184
0
    libcerror_error_set(
185
0
     error,
186
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
187
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
188
0
     "%s: invalid data size value out of bounds.",
189
0
     function );
190
191
0
    return( -1 );
192
0
  }
193
#if defined( HAVE_DEBUG_OUTPUT )
194
  if( libcnotify_verbose != 0 )
195
  {
196
    libcnotify_printf(
197
     "%s: snapshot metadata tree key data:\n",
198
     function );
199
    libcnotify_print_data(
200
     data,
201
     sizeof( fsapfs_snapshot_metadata_btree_key_t ),
202
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
203
  }
204
#endif
205
206
#if defined( HAVE_DEBUG_OUTPUT )
207
  if( libcnotify_verbose != 0 )
208
  {
209
    byte_stream_copy_to_uint64_little_endian(
210
     ( (fsapfs_snapshot_metadata_btree_key_t *) data )->object_identifier,
211
     value_64bit );
212
    libcnotify_printf(
213
     "%s: object identifier\t\t: 0x%08" PRIx64 "\n",
214
     function,
215
     value_64bit );
216
217
    libcnotify_printf(
218
     "\n" );
219
  }
220
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
221
222
135
  return( 1 );
223
135
}
224
225
/* Reads the snapshot metadata B-tree value data
226
 * Returns 1 if successful or -1 on error
227
 */
228
int libfsapfs_snapshot_metadata_read_value_data(
229
     libfsapfs_snapshot_metadata_t *snapshot_metadata,
230
     const uint8_t *data,
231
     size_t data_size,
232
     libcerror_error_t **error )
233
135
{
234
135
  static char *function = "libfsapfs_snapshot_metadata_read_value_data";
235
135
  size_t data_offset    = 0;
236
135
  uint16_t name_size    = 0;
237
238
#if defined( HAVE_DEBUG_OUTPUT )
239
  uint64_t value_64bit  = 0;
240
  uint32_t value_32bit  = 0;
241
#endif
242
243
135
  if( snapshot_metadata == NULL )
244
0
  {
245
0
    libcerror_error_set(
246
0
     error,
247
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
248
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
249
0
     "%s: invalid snapshot metadata.",
250
0
     function );
251
252
0
    return( -1 );
253
0
  }
254
135
  if( data == NULL )
255
14
  {
256
14
    libcerror_error_set(
257
14
     error,
258
14
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
259
14
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
260
14
     "%s: invalid data.",
261
14
     function );
262
263
14
    return( -1 );
264
14
  }
265
121
  if( ( data_size < sizeof( fsapfs_snapshot_metadata_btree_value_t ) )
266
121
   || ( data_size > (size_t) SSIZE_MAX ) )
267
9
  {
268
9
    libcerror_error_set(
269
9
     error,
270
9
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
271
9
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
272
9
     "%s: invalid data size value out of bounds.",
273
9
     function );
274
275
9
    return( -1 );
276
9
  }
277
#if defined( HAVE_DEBUG_OUTPUT )
278
  if( libcnotify_verbose != 0 )
279
  {
280
    libcnotify_printf(
281
     "%s: snapshot metadata tree value data:\n",
282
     function );
283
    libcnotify_print_data(
284
     data,
285
     sizeof( fsapfs_snapshot_metadata_btree_value_t ),
286
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
287
  }
288
#endif
289
112
  byte_stream_copy_to_uint32_little_endian(
290
112
   ( (fsapfs_snapshot_metadata_btree_value_t *) data )->volume_superblock_block_number,
291
112
   snapshot_metadata->volume_superblock_block_number );
292
293
112
  byte_stream_copy_to_uint16_little_endian(
294
112
   ( (fsapfs_snapshot_metadata_btree_value_t *) data )->name_size,
295
112
   name_size );
296
297
#if defined( HAVE_DEBUG_OUTPUT )
298
  if( libcnotify_verbose != 0 )
299
  {
300
    byte_stream_copy_to_uint32_little_endian(
301
     ( (fsapfs_snapshot_metadata_btree_value_t *) data )->extent_reference_tree_block_number,
302
     value_64bit );
303
    libcnotify_printf(
304
     "%s: extent-reference tree block number\t\t: %" PRIu32 "\n",
305
     function,
306
     value_64bit );
307
308
    libcnotify_printf(
309
     "%s: volume superblock block number\t\t: %" PRIu32 "\n",
310
     function,
311
     snapshot_metadata->volume_superblock_block_number );
312
313
    if( libfsapfs_debug_print_posix_time_value(
314
         function,
315
         "creation time\t\t\t\t",
316
         ( (fsapfs_snapshot_metadata_btree_value_t *) data )->creation_time,
317
         8,
318
         LIBFDATETIME_ENDIAN_LITTLE,
319
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
320
         LIBFDATETIME_STRING_FORMAT_TYPE_ISO8601 | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
321
         error ) != 1 )
322
    {
323
      libcerror_error_set(
324
       error,
325
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
326
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
327
       "%s: unable to print POSIX time value.",
328
       function );
329
330
      goto on_error;
331
    }
332
    if( libfsapfs_debug_print_posix_time_value(
333
         function,
334
         "change time\t\t\t\t",
335
         ( (fsapfs_snapshot_metadata_btree_value_t *) data )->change_time,
336
         8,
337
         LIBFDATETIME_ENDIAN_LITTLE,
338
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
339
         LIBFDATETIME_STRING_FORMAT_TYPE_ISO8601 | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
340
         error ) != 1 )
341
    {
342
      libcerror_error_set(
343
       error,
344
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
345
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
346
       "%s: unable to print POSIX time value.",
347
       function );
348
349
      goto on_error;
350
    }
351
    byte_stream_copy_to_uint32_little_endian(
352
     ( (fsapfs_snapshot_metadata_btree_value_t *) data )->extent_reference_tree_object_type,
353
     value_32bit );
354
    libcnotify_printf(
355
     "%s: extent-reference tree object type\t\t: 0x%08" PRIx32 "\n",
356
     function,
357
     value_32bit );
358
359
    byte_stream_copy_to_uint32_little_endian(
360
     ( (fsapfs_snapshot_metadata_btree_value_t *) data )->flags,
361
     value_32bit );
362
    libcnotify_printf(
363
     "%s: flags\t\t\t\t\t: 0x%08" PRIx32 "\n",
364
     function,
365
     value_32bit );
366
367
    libcnotify_printf(
368
     "%s: name size\t\t\t\t\t: %" PRIu16 "\n",
369
     function,
370
     name_size );
371
  }
372
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
373
374
112
  data_offset = sizeof( fsapfs_snapshot_metadata_btree_value_t );
375
376
112
  if( ( name_size == 0 )
377
112
   || ( (size_t) name_size > ( data_size - data_offset ) ) )
378
30
  {
379
30
    libcerror_error_set(
380
30
     error,
381
30
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
382
30
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
383
30
     "%s: invalid name size value out of bounds.",
384
30
     function );
385
386
30
    goto on_error;
387
30
  }
388
#if defined( HAVE_DEBUG_OUTPUT )
389
  if( libcnotify_verbose != 0 )
390
  {
391
    libcnotify_printf(
392
     "%s: name data:\n",
393
     function );
394
    libcnotify_print_data(
395
     &( data[ data_offset ] ),
396
     (size_t) name_size,
397
     0 );
398
  }
399
#endif
400
82
  snapshot_metadata->name = (uint8_t *) memory_allocate(
401
82
                                         sizeof( uint8_t ) * name_size );
402
403
82
  if( snapshot_metadata->name == NULL )
404
0
  {
405
0
    libcerror_error_set(
406
0
     error,
407
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
408
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
409
0
     "%s: unable to create name.",
410
0
     function );
411
412
0
    goto on_error;
413
0
  }
414
82
  snapshot_metadata->name_size = name_size;
415
416
82
  if( memory_copy(
417
82
       snapshot_metadata->name,
418
82
       &( data[ data_offset ] ),
419
82
       name_size ) == NULL )
420
0
  {
421
0
    libcerror_error_set(
422
0
     error,
423
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
424
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
425
0
     "%s: unable to copy name.",
426
0
     function );
427
428
0
    goto on_error;
429
0
  }
430
431
#if defined( HAVE_DEBUG_OUTPUT )
432
  if( libcnotify_verbose != 0 )
433
  {
434
    libcnotify_printf(
435
     "%s: name\t\t\t\t\t: %s\n",
436
     function,
437
     snapshot_metadata->name );
438
439
    libcnotify_printf(
440
     "\n" );
441
  }
442
#endif
443
82
  return( 1 );
444
445
30
on_error:
446
30
  if( snapshot_metadata->name != NULL )
447
0
  {
448
0
    memory_free(
449
0
     snapshot_metadata->name );
450
451
0
    snapshot_metadata->name = NULL;
452
0
  }
453
30
  snapshot_metadata->name_size = 0;
454
455
30
  return( -1 );
456
82
}
457
458
/* Retrieves the size of the UTF-8 encoded name
459
 * The returned size includes the end of string character
460
 * Returns 1 if successful or -1 on error
461
 */
462
int libfsapfs_snapshot_metadata_get_utf8_name_size(
463
     libfsapfs_snapshot_metadata_t *snapshot_metadata,
464
     size_t *utf8_string_size,
465
     libcerror_error_t **error )
466
0
{
467
0
  static char *function = "libfsapfs_snapshot_metadata_get_utf8_name_size";
468
469
0
  if( snapshot_metadata == NULL )
470
0
  {
471
0
    libcerror_error_set(
472
0
     error,
473
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
474
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
475
0
     "%s: invalid snapshot metadata.",
476
0
     function );
477
478
0
    return( -1 );
479
0
  }
480
0
  if( libuna_utf8_string_size_from_utf8_stream(
481
0
       snapshot_metadata->name,
482
0
       256,
483
0
       utf8_string_size,
484
0
       error ) != 1 )
485
0
  {
486
0
    libcerror_error_set(
487
0
     error,
488
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
489
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
490
0
     "%s: unable to retrieve UTF-8 string size.",
491
0
     function );
492
493
0
    return( -1 );
494
0
  }
495
0
  return( 1 );
496
0
}
497
498
/* Retrieves the UTF-8 encoded name
499
 * The size should include the end of string character
500
 * Returns 1 if successful or -1 on error
501
 */
502
int libfsapfs_snapshot_metadata_get_utf8_name(
503
     libfsapfs_snapshot_metadata_t *snapshot_metadata,
504
     uint8_t *utf8_string,
505
     size_t utf8_string_size,
506
     libcerror_error_t **error )
507
0
{
508
0
  static char *function = "libfsapfs_snapshot_metadata_get_utf8_name";
509
510
0
  if( snapshot_metadata == NULL )
511
0
  {
512
0
    libcerror_error_set(
513
0
     error,
514
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
515
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
516
0
     "%s: invalid snapshot metadata.",
517
0
     function );
518
519
0
    return( -1 );
520
0
  }
521
0
  if( libuna_utf8_string_copy_from_utf8_stream(
522
0
       utf8_string,
523
0
       utf8_string_size,
524
0
       snapshot_metadata->name,
525
0
       256,
526
0
       error ) != 1 )
527
0
  {
528
0
    libcerror_error_set(
529
0
     error,
530
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
531
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
532
0
     "%s: unable to retrieve UTF-8 string.",
533
0
     function );
534
535
0
    return( -1 );
536
0
  }
537
0
  return( 1 );
538
0
}
539
540
/* Retrieves the size of the UTF-16 encoded name
541
 * The returned size includes the end of string character
542
 * Returns 1 if successful or -1 on error
543
 */
544
int libfsapfs_snapshot_metadata_get_utf16_name_size(
545
     libfsapfs_snapshot_metadata_t *snapshot_metadata,
546
     size_t *utf16_string_size,
547
     libcerror_error_t **error )
548
0
{
549
0
  static char *function = "libfsapfs_snapshot_metadata_get_utf16_name_size";
550
551
0
  if( snapshot_metadata == NULL )
552
0
  {
553
0
    libcerror_error_set(
554
0
     error,
555
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
556
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
557
0
     "%s: invalid snapshot metadata.",
558
0
     function );
559
560
0
    return( -1 );
561
0
  }
562
0
  if( libuna_utf16_string_size_from_utf8_stream(
563
0
       snapshot_metadata->name,
564
0
       256,
565
0
       utf16_string_size,
566
0
       error ) != 1 )
567
0
  {
568
0
    libcerror_error_set(
569
0
     error,
570
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
571
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
572
0
     "%s: unable to retrieve UTF-16 string size.",
573
0
     function );
574
575
0
    return( -1 );
576
0
  }
577
0
  return( 1 );
578
0
}
579
580
/* Retrieves the UTF-16 encoded name
581
 * The size should include the end of string character
582
 * Returns 1 if successful or -1 on error
583
 */
584
int libfsapfs_snapshot_metadata_get_utf16_name(
585
     libfsapfs_snapshot_metadata_t *snapshot_metadata,
586
     uint16_t *utf16_string,
587
     size_t utf16_string_size,
588
     libcerror_error_t **error )
589
0
{
590
0
  static char *function = "libfsapfs_snapshot_metadata_get_utf16_name";
591
592
0
  if( snapshot_metadata == NULL )
593
0
  {
594
0
    libcerror_error_set(
595
0
     error,
596
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
597
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
598
0
     "%s: invalid snapshot metadata.",
599
0
     function );
600
601
0
    return( -1 );
602
0
  }
603
0
  if( libuna_utf16_string_copy_from_utf8_stream(
604
0
       utf16_string,
605
0
       utf16_string_size,
606
0
       snapshot_metadata->name,
607
0
       256,
608
0
       error ) != 1 )
609
0
  {
610
0
    libcerror_error_set(
611
0
     error,
612
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
613
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
614
0
     "%s: unable to retrieve UTF-16 string.",
615
0
     function );
616
617
0
    return( -1 );
618
0
  }
619
0
  return( 1 );
620
0
}
621