Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsapfs/libfsapfs/libfsapfs_volume_superblock.c
Line
Count
Source
1
/*
2
 * The volume superblock 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_checksum.h"
28
#include "libfsapfs_debug.h"
29
#include "libfsapfs_io_handle.h"
30
#include "libfsapfs_libbfio.h"
31
#include "libfsapfs_libcerror.h"
32
#include "libfsapfs_libcnotify.h"
33
#include "libfsapfs_libfdatetime.h"
34
#include "libfsapfs_libfguid.h"
35
#include "libfsapfs_libuna.h"
36
#include "libfsapfs_volume_superblock.h"
37
38
#include "fsapfs_volume_superblock.h"
39
40
/* Creates a volume superblock
41
 * Make sure the value volume_superblock is referencing, is set to NULL
42
 * Returns 1 if successful or -1 on error
43
 */
44
int libfsapfs_volume_superblock_initialize(
45
     libfsapfs_volume_superblock_t **volume_superblock,
46
     libcerror_error_t **error )
47
850
{
48
850
  static char *function = "libfsapfs_volume_superblock_initialize";
49
50
850
  if( volume_superblock == NULL )
51
0
  {
52
0
    libcerror_error_set(
53
0
     error,
54
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56
0
     "%s: invalid volume superblock.",
57
0
     function );
58
59
0
    return( -1 );
60
0
  }
61
850
  if( *volume_superblock != NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
66
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67
0
     "%s: invalid volume superblock value already set.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
850
  *volume_superblock = memory_allocate_structure(
73
850
                        libfsapfs_volume_superblock_t );
74
75
850
  if( *volume_superblock == NULL )
76
0
  {
77
0
    libcerror_error_set(
78
0
     error,
79
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
80
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
81
0
     "%s: unable to create volume superblock.",
82
0
     function );
83
84
0
    goto on_error;
85
0
  }
86
850
  if( memory_set(
87
850
       *volume_superblock,
88
850
       0,
89
850
       sizeof( libfsapfs_volume_superblock_t ) ) == NULL )
90
0
  {
91
0
    libcerror_error_set(
92
0
     error,
93
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
94
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
95
0
     "%s: unable to clear volume superblock.",
96
0
     function );
97
98
0
    goto on_error;
99
0
  }
100
850
  return( 1 );
101
102
0
on_error:
103
0
  if( *volume_superblock != NULL )
104
0
  {
105
0
    memory_free(
106
0
     *volume_superblock );
107
108
0
    *volume_superblock = NULL;
109
0
  }
110
0
  return( -1 );
111
850
}
112
113
/* Frees a volume superblock
114
 * Returns 1 if successful or -1 on error
115
 */
116
int libfsapfs_volume_superblock_free(
117
     libfsapfs_volume_superblock_t **volume_superblock,
118
     libcerror_error_t **error )
119
850
{
120
850
  static char *function = "libfsapfs_volume_superblock_free";
121
122
850
  if( volume_superblock == NULL )
123
0
  {
124
0
    libcerror_error_set(
125
0
     error,
126
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
127
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
128
0
     "%s: invalid volume superblock.",
129
0
     function );
130
131
0
    return( -1 );
132
0
  }
133
850
  if( *volume_superblock != NULL )
134
850
  {
135
850
    memory_free(
136
850
     *volume_superblock );
137
138
850
    *volume_superblock = NULL;
139
850
  }
140
850
  return( 1 );
141
850
}
142
143
/* Reads the volume superblock
144
 * Returns 1 if successful or -1 on error
145
 */
146
int libfsapfs_volume_superblock_read_file_io_handle(
147
     libfsapfs_volume_superblock_t *volume_superblock,
148
     libbfio_handle_t *file_io_handle,
149
     off64_t file_offset,
150
     int8_t is_snapshot,
151
     libcerror_error_t **error )
152
850
{
153
850
  uint8_t volume_superblock_data[ 4096 ];
154
155
850
  static char *function = "libfsapfs_volume_superblock_read_file_io_handle";
156
850
  ssize_t read_count    = 0;
157
158
850
  if( volume_superblock == NULL )
159
0
  {
160
0
    libcerror_error_set(
161
0
     error,
162
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
163
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
164
0
     "%s: invalid volume superblock.",
165
0
     function );
166
167
0
    return( -1 );
168
0
  }
169
#if defined( HAVE_DEBUG_OUTPUT )
170
  if( libcnotify_verbose != 0 )
171
  {
172
    libcnotify_printf(
173
     "%s: reading volume superblock at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
174
     function,
175
     file_offset,
176
     file_offset );
177
  }
178
#endif
179
850
  read_count = libbfio_handle_read_buffer_at_offset(
180
850
                file_io_handle,
181
850
                (uint8_t *) &volume_superblock_data,
182
850
                4096,
183
850
                file_offset,
184
850
                error );
185
186
850
  if( read_count != (ssize_t) 4096 )
187
80
  {
188
80
    libcerror_error_set(
189
80
     error,
190
80
     LIBCERROR_ERROR_DOMAIN_IO,
191
80
     LIBCERROR_IO_ERROR_READ_FAILED,
192
80
     "%s: unable to read volume superblock data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
193
80
     function,
194
80
     file_offset,
195
80
     file_offset );
196
197
80
    return( -1 );
198
80
  }
199
770
  if( libfsapfs_volume_superblock_read_data(
200
770
       volume_superblock,
201
770
       (uint8_t *) &volume_superblock_data,
202
770
       4096,
203
770
       is_snapshot,
204
770
       error ) != 1 )
205
204
  {
206
204
    libcerror_error_set(
207
204
     error,
208
204
     LIBCERROR_ERROR_DOMAIN_IO,
209
204
     LIBCERROR_IO_ERROR_READ_FAILED,
210
204
     "%s: unable to read volume superblock data.",
211
204
     function );
212
213
204
    return( -1 );
214
204
  }
215
566
  return( 1 );
216
770
}
217
218
/* Reads the volume superblock
219
 * Returns 1 if successful or -1 on error
220
 */
221
int libfsapfs_volume_superblock_read_data(
222
     libfsapfs_volume_superblock_t *volume_superblock,
223
     const uint8_t *data,
224
     size_t data_size,
225
     int8_t is_snapshot,
226
     libcerror_error_t **error )
227
770
{
228
770
  static char *function            = "libfsapfs_volume_superblock_read_data";
229
770
  uint64_t calculated_checksum     = 0;
230
770
  uint64_t stored_checksum         = 0;
231
770
  uint32_t expected_object_type    = 0;
232
770
  uint32_t object_subtype          = 0;
233
770
  uint32_t object_type             = 0;
234
235
#if defined( HAVE_DEBUG_OUTPUT )
236
  uint8_t *change_information_data = NULL;
237
  uint64_t value_64bit             = 0;
238
  uint32_t value_32bit             = 0;
239
  uint8_t change_information_index = 0;
240
#endif
241
242
770
  if( volume_superblock == NULL )
243
0
  {
244
0
    libcerror_error_set(
245
0
     error,
246
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
247
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
248
0
     "%s: invalid volume superblock.",
249
0
     function );
250
251
0
    return( -1 );
252
0
  }
253
770
  if( data == NULL )
254
0
  {
255
0
    libcerror_error_set(
256
0
     error,
257
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
258
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
259
0
     "%s: invalid data.",
260
0
     function );
261
262
0
    return( -1 );
263
0
  }
264
770
  if( ( data_size < sizeof( fsapfs_volume_superblock_t ) )
265
770
   || ( data_size > (size_t) SSIZE_MAX ) )
266
0
  {
267
0
    libcerror_error_set(
268
0
     error,
269
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
270
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
271
0
     "%s: invalid data size value out of bounds.",
272
0
     function );
273
274
0
    return( -1 );
275
0
  }
276
770
  if( is_snapshot == 0 )
277
770
  {
278
770
    expected_object_type = 0x0000000dUL;
279
770
  }
280
0
  else
281
0
  {
282
0
    expected_object_type = 0x4000000dUL;
283
0
  }
284
#if defined( HAVE_DEBUG_OUTPUT )
285
  if( libcnotify_verbose != 0 )
286
  {
287
    libcnotify_printf(
288
     "%s: volume superblock data:\n",
289
     function );
290
    libcnotify_print_data(
291
     data,
292
     sizeof( fsapfs_volume_superblock_t ),
293
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
294
  }
295
#endif
296
770
  byte_stream_copy_to_uint64_little_endian(
297
770
   ( (fsapfs_volume_superblock_t *) data )->object_transaction_identifier,
298
770
   volume_superblock->transaction_identifier );
299
300
770
  byte_stream_copy_to_uint64_little_endian(
301
770
   ( (fsapfs_volume_superblock_t *) data )->object_checksum,
302
770
   stored_checksum );
303
304
770
  byte_stream_copy_to_uint32_little_endian(
305
770
   ( (fsapfs_volume_superblock_t *) data )->object_type,
306
770
   object_type );
307
308
770
  if( object_type != expected_object_type )
309
61
  {
310
61
    libcerror_error_set(
311
61
     error,
312
61
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
313
61
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
314
61
     "%s: invalid object type: 0x%08" PRIx32 ".",
315
61
     function,
316
61
     object_type );
317
318
61
    return( -1 );
319
61
  }
320
709
  byte_stream_copy_to_uint32_little_endian(
321
709
   ( (fsapfs_volume_superblock_t *) data )->object_subtype,
322
709
   object_subtype );
323
324
709
  if( object_subtype != 0x00000000UL )
325
45
  {
326
45
    libcerror_error_set(
327
45
     error,
328
45
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
329
45
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
330
45
     "%s: invalid object subtype: 0x%08" PRIx32 ".",
331
45
     function,
332
45
     object_subtype );
333
334
45
    return( -1 );
335
45
  }
336
664
  if( memory_compare(
337
664
       ( (fsapfs_volume_superblock_t *) data )->signature,
338
664
       fsapfs_volume_signature,
339
664
       4 ) != 0 )
340
2
  {
341
2
    libcerror_error_set(
342
2
     error,
343
2
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
344
2
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
345
2
     "%s: invalid signature.",
346
2
     function );
347
348
2
    return( -1 );
349
2
  }
350
662
  byte_stream_copy_to_uint64_little_endian(
351
662
   ( (fsapfs_volume_superblock_t *) data )->compatible_features_flags,
352
662
   volume_superblock->compatible_features_flags );
353
354
662
  byte_stream_copy_to_uint64_little_endian(
355
662
   ( (fsapfs_volume_superblock_t *) data )->read_only_compatible_features_flags,
356
662
   volume_superblock->read_only_compatible_features_flags );
357
358
662
  byte_stream_copy_to_uint64_little_endian(
359
662
   ( (fsapfs_volume_superblock_t *) data )->incompatible_features_flags,
360
662
   volume_superblock->incompatible_features_flags );
361
362
662
  byte_stream_copy_to_uint64_little_endian(
363
662
   ( (fsapfs_volume_superblock_t *) data )->object_map_block_number,
364
662
   volume_superblock->object_map_block_number );
365
366
662
  byte_stream_copy_to_uint64_little_endian(
367
662
   ( (fsapfs_volume_superblock_t *) data )->file_system_root_object_identifier,
368
662
   volume_superblock->file_system_root_object_identifier );
369
370
662
  byte_stream_copy_to_uint64_little_endian(
371
662
   ( (fsapfs_volume_superblock_t *) data )->extent_reference_tree_block_number,
372
662
   volume_superblock->extent_reference_tree_block_number );
373
374
662
  byte_stream_copy_to_uint64_little_endian(
375
662
   ( (fsapfs_volume_superblock_t *) data )->snapshot_metadata_tree_block_number,
376
662
   volume_superblock->snapshot_metadata_tree_block_number );
377
378
662
  byte_stream_copy_to_uint64_little_endian(
379
662
   ( (fsapfs_volume_superblock_t *) data )->next_file_system_object_identifier,
380
662
   volume_superblock->next_file_system_object_identifier );
381
382
662
  if( memory_copy(
383
662
       volume_superblock->volume_identifier,
384
662
       ( (fsapfs_volume_superblock_t *) data )->volume_identifier,
385
662
       16 ) == NULL )
386
0
  {
387
0
    libcerror_error_set(
388
0
     error,
389
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
390
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
391
0
     "%s: unable to copy volume identifier.",
392
0
     function );
393
394
0
    return( -1 );
395
0
  }
396
/* TODO preserve modification time */
397
398
662
  byte_stream_copy_to_uint64_little_endian(
399
662
   ( (fsapfs_volume_superblock_t *) data )->volume_flags,
400
662
   volume_superblock->volume_flags );
401
402
662
  if( memory_copy(
403
662
       volume_superblock->volume_name,
404
662
       ( (fsapfs_volume_superblock_t *) data )->volume_name,
405
662
       256 ) == NULL )
406
0
  {
407
0
    libcerror_error_set(
408
0
     error,
409
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
410
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
411
0
     "%s: unable to copy volume name.",
412
0
     function );
413
414
0
    return( -1 );
415
0
  }
416
#if defined( HAVE_DEBUG_OUTPUT )
417
  if( libcnotify_verbose != 0 )
418
  {
419
    libcnotify_printf(
420
     "%s: object checksum\t\t\t\t: 0x%08" PRIx64 "\n",
421
     function,
422
     stored_checksum );
423
424
    byte_stream_copy_to_uint64_little_endian(
425
     ( (fsapfs_volume_superblock_t *) data )->object_identifier,
426
     value_64bit );
427
    libcnotify_printf(
428
     "%s: object identifier\t\t\t: %" PRIu64 "\n",
429
     function,
430
     value_64bit );
431
432
    libcnotify_printf(
433
     "%s: object transaction identifier\t\t: %" PRIu64 "\n",
434
     function,
435
     volume_superblock->transaction_identifier );
436
437
    libcnotify_printf(
438
     "%s: object type\t\t\t\t: 0x%08" PRIx32 "\n",
439
     function,
440
     object_type );
441
442
    libcnotify_printf(
443
     "%s: object subtype\t\t\t\t: 0x%08" PRIx32 "\n",
444
     function,
445
     object_subtype );
446
447
    libcnotify_printf(
448
     "%s: signature\t\t\t\t: %c%c%c%c\n",
449
     function,
450
     ( (fsapfs_volume_superblock_t *) data )->signature[ 0 ],
451
     ( (fsapfs_volume_superblock_t *) data )->signature[ 1 ],
452
     ( (fsapfs_volume_superblock_t *) data )->signature[ 2 ],
453
     ( (fsapfs_volume_superblock_t *) data )->signature[ 3 ] );
454
455
    byte_stream_copy_to_uint32_little_endian(
456
     ( (fsapfs_volume_superblock_t *) data )->unknown1,
457
     value_32bit );
458
    libcnotify_printf(
459
     "%s: unknown1\t\t\t\t\t: 0x%08" PRIx32 "\n",
460
     function,
461
     value_32bit );
462
463
    libcnotify_printf(
464
     "%s: compatible features flags\t\t: 0x%08" PRIx64 "\n",
465
     function,
466
     volume_superblock->compatible_features_flags );
467
    libfsapfs_debug_print_volume_compatible_features_flags(
468
     volume_superblock->compatible_features_flags );
469
    libcnotify_printf(
470
     "\n" );
471
472
    libcnotify_printf(
473
     "%s: read-only compatible features flags\t: 0x%08" PRIx64 "\n",
474
     function,
475
     volume_superblock->read_only_compatible_features_flags );
476
    libfsapfs_debug_print_volume_read_only_compatible_features_flags(
477
     volume_superblock->read_only_compatible_features_flags );
478
    libcnotify_printf(
479
     "\n" );
480
481
    libcnotify_printf(
482
     "%s: incompatible features flags\t\t: 0x%08" PRIx64 "\n",
483
     function,
484
     volume_superblock->incompatible_features_flags );
485
    libfsapfs_debug_print_volume_incompatible_features_flags(
486
     volume_superblock->incompatible_features_flags );
487
    libcnotify_printf(
488
     "\n" );
489
490
    if( libfsapfs_debug_print_posix_time_value(
491
         function,
492
         "unmount time\t\t\t\t",
493
         ( (fsapfs_volume_superblock_t *) data )->unmount_time,
494
         8,
495
         LIBFDATETIME_ENDIAN_LITTLE,
496
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
497
         LIBFDATETIME_STRING_FORMAT_TYPE_ISO8601 | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
498
         error ) != 1 )
499
    {
500
      libcerror_error_set(
501
       error,
502
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
503
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
504
       "%s: unable to print POSIX time value.",
505
       function );
506
507
      return( -1 );
508
    }
509
    byte_stream_copy_to_uint64_little_endian(
510
     ( (fsapfs_volume_superblock_t *) data )->number_of_reserved_blocks,
511
     value_64bit );
512
    libcnotify_printf(
513
     "%s: number of reserved blocks\t\t: %" PRIu64 "\n",
514
     function,
515
     value_64bit );
516
517
    byte_stream_copy_to_uint64_little_endian(
518
     ( (fsapfs_volume_superblock_t *) data )->number_of_quota_blocks,
519
     value_64bit );
520
    libcnotify_printf(
521
     "%s: number of quota blocks\t\t\t: %" PRIu64 "\n",
522
     function,
523
     value_64bit );
524
525
    byte_stream_copy_to_uint64_little_endian(
526
     ( (fsapfs_volume_superblock_t *) data )->number_of_allocated_blocks,
527
     value_64bit );
528
    libcnotify_printf(
529
     "%s: number of allocated blocks\t\t: %" PRIu64 "\n",
530
     function,
531
     value_64bit );
532
533
    libcnotify_printf(
534
     "%s: encryption state:\n",
535
     function );
536
    libcnotify_print_data(
537
     ( (fsapfs_volume_superblock_t *) data )->encryption_state,
538
     20,
539
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
540
541
    byte_stream_copy_to_uint32_little_endian(
542
     ( (fsapfs_volume_superblock_t *) data )->file_system_root_tree_object_type,
543
     value_32bit );
544
    libcnotify_printf(
545
     "%s: file system root tree object type\t: 0x%08" PRIx32 "\n",
546
     function,
547
     value_32bit );
548
549
    byte_stream_copy_to_uint32_little_endian(
550
     ( (fsapfs_volume_superblock_t *) data )->extent_reference_tree_object_type,
551
     value_32bit );
552
    libcnotify_printf(
553
     "%s: extent-reference tree object type\t: 0x%08" PRIx32 "\n",
554
     function,
555
     value_32bit );
556
557
    byte_stream_copy_to_uint32_little_endian(
558
     ( (fsapfs_volume_superblock_t *) data )->snapshot_metadata_tree_object_type,
559
     value_32bit );
560
    libcnotify_printf(
561
     "%s: snapshot metadata tree object type\t: 0x%08" PRIx32 "\n",
562
     function,
563
     value_32bit );
564
565
    libcnotify_printf(
566
     "%s: object map block number\t\t\t: %" PRIu64 "\n",
567
     function,
568
     volume_superblock->object_map_block_number );
569
570
    libcnotify_printf(
571
     "%s: file system root object identifier\t: %" PRIu64 "\n",
572
     function,
573
     volume_superblock->file_system_root_object_identifier );
574
575
    libcnotify_printf(
576
     "%s: extent-reference tree block number\t: %" PRIu64 "\n",
577
     function,
578
     volume_superblock->extent_reference_tree_block_number );
579
580
    libcnotify_printf(
581
     "%s: snapshot metadata tree block number\t: %" PRIu64 "\n",
582
     function,
583
     volume_superblock->snapshot_metadata_tree_block_number );
584
585
    byte_stream_copy_to_uint64_little_endian(
586
     ( (fsapfs_volume_superblock_t *) data )->unknown20,
587
     value_64bit );
588
    libcnotify_printf(
589
     "%s: unknown20\t\t\t\t: 0x%08" PRIx64 "\n",
590
     function,
591
     value_64bit );
592
593
    byte_stream_copy_to_uint64_little_endian(
594
     ( (fsapfs_volume_superblock_t *) data )->unknown21,
595
     value_64bit );
596
    libcnotify_printf(
597
     "%s: unknown21\t\t\t\t: 0x%08" PRIx64 "\n",
598
     function,
599
     value_64bit );
600
601
    libcnotify_printf(
602
     "%s: next file system object identifier\t: %" PRIu64 "\n",
603
     function,
604
     volume_superblock->next_file_system_object_identifier );
605
606
    byte_stream_copy_to_uint64_little_endian(
607
     ( (fsapfs_volume_superblock_t *) data )->number_of_files,
608
     value_64bit );
609
    libcnotify_printf(
610
     "%s: number of files\t\t\t\t: %" PRIu64 "\n",
611
     function,
612
     value_64bit );
613
614
    byte_stream_copy_to_uint64_little_endian(
615
     ( (fsapfs_volume_superblock_t *) data )->number_of_directories,
616
     value_64bit );
617
    libcnotify_printf(
618
     "%s: number of directories\t\t\t: %" PRIu64 "\n",
619
     function,
620
     value_64bit );
621
622
    byte_stream_copy_to_uint64_little_endian(
623
     ( (fsapfs_volume_superblock_t *) data )->number_of_symbolic_links,
624
     value_64bit );
625
    libcnotify_printf(
626
     "%s: number of symbolic links\t\t\t: %" PRIu64 "\n",
627
     function,
628
     value_64bit );
629
630
    byte_stream_copy_to_uint64_little_endian(
631
     ( (fsapfs_volume_superblock_t *) data )->number_of_other_objects,
632
     value_64bit );
633
    libcnotify_printf(
634
     "%s: number of other objects\t\t\t: %" PRIu64 "\n",
635
     function,
636
     value_64bit );
637
638
    byte_stream_copy_to_uint64_little_endian(
639
     ( (fsapfs_volume_superblock_t *) data )->number_of_snapshots,
640
     value_64bit );
641
    libcnotify_printf(
642
     "%s: number of snapshots\t\t\t: %" PRIu64 "\n",
643
     function,
644
     value_64bit );
645
646
    byte_stream_copy_to_uint64_little_endian(
647
     ( (fsapfs_volume_superblock_t *) data )->total_number_of_blocks_allocated,
648
     value_64bit );
649
    libcnotify_printf(
650
     "%s: total number of blocks allocated\t\t: %" PRIu64 "\n",
651
     function,
652
     value_64bit );
653
654
    byte_stream_copy_to_uint64_little_endian(
655
     ( (fsapfs_volume_superblock_t *) data )->total_number_of_blocks_freed,
656
     value_64bit );
657
    libcnotify_printf(
658
     "%s: total number of blocks freed\t\t: %" PRIu64 "\n",
659
     function,
660
     value_64bit );
661
662
    if( libfsapfs_debug_print_guid_value(
663
         function,
664
         "volume identifier\t\t\t",
665
         ( (fsapfs_volume_superblock_t *) data )->volume_identifier,
666
         16,
667
         LIBFGUID_ENDIAN_BIG,
668
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
669
         error ) != 1 )
670
    {
671
      libcerror_error_set(
672
       error,
673
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
674
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
675
       "%s: unable to print UUID value.",
676
       function );
677
678
      return( -1 );
679
    }
680
    if( libfsapfs_debug_print_posix_time_value(
681
         function,
682
         "modification time\t\t\t",
683
         ( (fsapfs_volume_superblock_t *) data )->modification_time,
684
         8,
685
         LIBFDATETIME_ENDIAN_LITTLE,
686
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
687
         LIBFDATETIME_STRING_FORMAT_TYPE_ISO8601 | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
688
         error ) != 1 )
689
    {
690
      libcerror_error_set(
691
       error,
692
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
693
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
694
       "%s: unable to print POSIX time value.",
695
       function );
696
697
      return( -1 );
698
    }
699
    libcnotify_printf(
700
     "%s: volume flags\t\t\t\t: 0x%08" PRIx64 "\n",
701
     function,
702
     volume_superblock->volume_flags );
703
    libfsapfs_debug_print_volume_flags(
704
     volume_superblock->volume_flags );
705
    libcnotify_printf(
706
     "\n" );
707
708
    change_information_data = ( (fsapfs_volume_superblock_t *) data )->creation_change_information;
709
710
    libcnotify_printf(
711
     "%s: creation application:\n",
712
     function );
713
    libcnotify_print_data(
714
     ( (fsapfs_volume_superblock_change_information_t *) change_information_data )->application,
715
     32,
716
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
717
718
    if( libfsapfs_debug_print_posix_time_value(
719
         function,
720
         "creation change time\t\t\t",
721
         ( (fsapfs_volume_superblock_change_information_t *) change_information_data )->change_time,
722
         8,
723
         LIBFDATETIME_ENDIAN_LITTLE,
724
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
725
         LIBFDATETIME_STRING_FORMAT_TYPE_ISO8601 | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
726
         error ) != 1 )
727
    {
728
      libcerror_error_set(
729
       error,
730
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
731
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
732
       "%s: unable to print POSIX time value.",
733
       function );
734
735
      return( -1 );
736
    }
737
    byte_stream_copy_to_uint64_little_endian(
738
     ( (fsapfs_volume_superblock_change_information_t *) change_information_data )->change_transaction_identifier,
739
     value_64bit );
740
    libcnotify_printf(
741
     "%s: creation transaction identifier\t\t: %" PRIu64 "\n",
742
     function,
743
     value_64bit );
744
745
    change_information_data = ( (fsapfs_volume_superblock_t *) data )->modification_change_information;
746
747
    for( change_information_index = 0;
748
         change_information_index < 8;
749
         change_information_index++ )
750
    {
751
      libcnotify_printf(
752
       "%s: modification: %" PRIu8 " application:\n",
753
       function,
754
       change_information_index );
755
      libcnotify_print_data(
756
       ( (fsapfs_volume_superblock_change_information_t *) change_information_data )->application,
757
       32,
758
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
759
760
      if( libfsapfs_debug_print_posix_time_value(
761
           function,
762
           "modification change time\t\t\t",
763
           ( (fsapfs_volume_superblock_change_information_t *) change_information_data )->change_time,
764
           8,
765
           LIBFDATETIME_ENDIAN_LITTLE,
766
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
767
           LIBFDATETIME_STRING_FORMAT_TYPE_ISO8601 | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
768
           error ) != 1 )
769
      {
770
        libcerror_error_set(
771
         error,
772
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
773
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
774
         "%s: unable to print POSIX time value.",
775
         function );
776
777
        return( -1 );
778
      }
779
      byte_stream_copy_to_uint64_little_endian(
780
       ( (fsapfs_volume_superblock_change_information_t *) change_information_data )->change_transaction_identifier,
781
       value_64bit );
782
      libcnotify_printf(
783
       "%s: modification: %" PRIu8 " transaction identifier\t: %" PRIu64 "\n",
784
       function,
785
       change_information_index,
786
       value_64bit );
787
788
      change_information_data += sizeof( fsapfs_volume_superblock_change_information_t );
789
    }
790
    libcnotify_printf(
791
     "%s: volume name:\n",
792
     function );
793
    libcnotify_print_data(
794
     ( (fsapfs_volume_superblock_t *) data )->volume_name,
795
     256,
796
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
797
798
    byte_stream_copy_to_uint32_little_endian(
799
     ( (fsapfs_volume_superblock_t *) data )->next_document_identifier,
800
     value_32bit );
801
    libcnotify_printf(
802
     "%s: next document identifier\t\t\t: %" PRIu32 "\n",
803
     function,
804
     value_32bit );
805
806
    byte_stream_copy_to_uint32_little_endian(
807
     ( (fsapfs_volume_superblock_t *) data )->unknown60,
808
     value_32bit );
809
    libcnotify_printf(
810
     "%s: unknown60\t\t\t\t: 0x%08" PRIx32 "\n",
811
     function,
812
     value_32bit );
813
814
    byte_stream_copy_to_uint64_little_endian(
815
     ( (fsapfs_volume_superblock_t *) data )->unknown61,
816
     value_64bit );
817
    libcnotify_printf(
818
     "%s: unknown61\t\t\t\t: 0x%08" PRIx64 "\n",
819
     function,
820
     value_64bit );
821
822
    byte_stream_copy_to_uint64_little_endian(
823
     ( (fsapfs_volume_superblock_t *) data )->unknown62,
824
     value_64bit );
825
    libcnotify_printf(
826
     "%s: unknown62\t\t\t\t: 0x%08" PRIx64 "\n",
827
     function,
828
     value_64bit );
829
830
    byte_stream_copy_to_uint64_little_endian(
831
     ( (fsapfs_volume_superblock_t *) data )->unknown63,
832
     value_64bit );
833
    libcnotify_printf(
834
     "%s: unknown63\t\t\t\t: 0x%08" PRIx64 "\n",
835
     function,
836
     value_64bit );
837
838
    byte_stream_copy_to_uint64_little_endian(
839
     ( (fsapfs_volume_superblock_t *) data )->unknown64,
840
     value_64bit );
841
    libcnotify_printf(
842
     "%s: unknown64\t\t\t\t: 0x%08" PRIx64 "\n",
843
     function,
844
     value_64bit );
845
846
    byte_stream_copy_to_uint64_little_endian(
847
     ( (fsapfs_volume_superblock_t *) data )->unknown65,
848
     value_64bit );
849
    libcnotify_printf(
850
     "%s: unknown65\t\t\t\t: 0x%08" PRIx64 "\n",
851
     function,
852
     value_64bit );
853
854
    if( libfsapfs_debug_print_guid_value(
855
         function,
856
         "volume group identifier\t\t\t",
857
         ( (fsapfs_volume_superblock_t *) data )->volume_group_identifier,
858
         16,
859
         LIBFGUID_ENDIAN_BIG,
860
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
861
         error ) != 1 )
862
    {
863
      libcerror_error_set(
864
       error,
865
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
866
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
867
       "%s: unable to print UUID value.",
868
       function );
869
870
      return( -1 );
871
    }
872
    byte_stream_copy_to_uint64_little_endian(
873
     ( (fsapfs_volume_superblock_t *) data )->unknown66,
874
     value_64bit );
875
    libcnotify_printf(
876
     "%s: unknown66\t\t\t\t: 0x%08" PRIx64 "\n",
877
     function,
878
     value_64bit );
879
880
    byte_stream_copy_to_uint64_little_endian(
881
     ( (fsapfs_volume_superblock_t *) data )->unknown67,
882
     value_64bit );
883
    libcnotify_printf(
884
     "%s: unknown67\t\t\t\t: 0x%08" PRIx64 "\n",
885
     function,
886
     value_64bit );
887
888
    byte_stream_copy_to_uint32_little_endian(
889
     ( (fsapfs_volume_superblock_t *) data )->unknown68,
890
     value_32bit );
891
    libcnotify_printf(
892
     "%s: unknown68\t\t\t\t: 0x%08" PRIx32 "\n",
893
     function,
894
     value_32bit );
895
896
    byte_stream_copy_to_uint32_little_endian(
897
     ( (fsapfs_volume_superblock_t *) data )->unknown69,
898
     value_32bit );
899
    libcnotify_printf(
900
     "%s: unknown69\t\t\t\t: 0x%08" PRIx32 "\n",
901
     function,
902
     value_32bit );
903
904
    byte_stream_copy_to_uint64_little_endian(
905
     ( (fsapfs_volume_superblock_t *) data )->unknown70,
906
     value_64bit );
907
    libcnotify_printf(
908
     "%s: unknown70\t\t\t\t: 0x%08" PRIx64 "\n",
909
     function,
910
     value_64bit );
911
912
    libcnotify_printf(
913
     "\n" );
914
  }
915
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
916
917
662
  if( libfsapfs_checksum_calculate_fletcher64(
918
662
       &calculated_checksum,
919
662
       &( data[ 8 ] ),
920
662
       data_size - 8,
921
662
       0,
922
662
       error ) != 1 )
923
0
  {
924
0
    libcerror_error_set(
925
0
     error,
926
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
927
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
928
0
     "%s: unable to calculate Fletcher-64 checksum.",
929
0
     function );
930
931
0
    return( -1 );
932
0
  }
933
662
  if( stored_checksum != calculated_checksum )
934
96
  {
935
96
    libcerror_error_set(
936
96
     error,
937
96
     LIBCERROR_ERROR_DOMAIN_INPUT,
938
96
     LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
939
96
     "%s: mismatch in checksum ( 0x%08" PRIx64 " != 0x%08" PRIx64 " ).\n",
940
96
     function,
941
96
     stored_checksum,
942
96
     calculated_checksum );
943
944
96
    return( -1 );
945
96
  }
946
566
  return( 1 );
947
662
}
948
949
/* Retrieves the volume identifier
950
 * The identifier is an UUID stored in big-endian and is 16 bytes of size
951
 * Returns 1 if successful or -1 on error
952
 */
953
int libfsapfs_volume_superblock_get_volume_identifier(
954
     libfsapfs_volume_superblock_t *volume_superblock,
955
     uint8_t *uuid_data,
956
     size_t uuid_data_size,
957
     libcerror_error_t **error )
958
26
{
959
26
  static char *function = "libfsapfs_volume_superblock_get_volume_identifier";
960
961
26
  if( volume_superblock == NULL )
962
0
  {
963
0
    libcerror_error_set(
964
0
     error,
965
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
966
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
967
0
     "%s: invalid volume superblock.",
968
0
     function );
969
970
0
    return( -1 );
971
0
  }
972
26
  if( uuid_data == NULL )
973
0
  {
974
0
    libcerror_error_set(
975
0
     error,
976
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
977
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
978
0
     "%s: invalid UUID data.",
979
0
     function );
980
981
0
    return( -1 );
982
0
  }
983
26
  if( ( uuid_data_size < 16 )
984
26
   || ( uuid_data_size > (size_t) SSIZE_MAX ) )
985
0
  {
986
0
    libcerror_error_set(
987
0
     error,
988
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
989
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
990
0
     "%s: invalid UUID data size value out of bounds.",
991
0
     function );
992
993
0
    return( -1 );
994
0
  }
995
26
  if( memory_copy(
996
26
       uuid_data,
997
26
       volume_superblock->volume_identifier,
998
26
       16 ) == NULL )
999
0
  {
1000
0
    libcerror_error_set(
1001
0
     error,
1002
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1003
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
1004
0
     "%s: unable to copy volume identifier.",
1005
0
     function );
1006
1007
0
    return( -1 );
1008
0
  }
1009
26
  return( 1 );
1010
26
}
1011
1012
/* Retrieves the size of the UTF-8 encoded volume name
1013
 * The returned size includes the end of string character
1014
 * Returns 1 if successful or -1 on error
1015
 */
1016
int libfsapfs_volume_superblock_get_utf8_volume_name_size(
1017
     libfsapfs_volume_superblock_t *volume_superblock,
1018
     size_t *utf8_string_size,
1019
     libcerror_error_t **error )
1020
26
{
1021
26
  static char *function = "libfsapfs_volume_superblock_get_utf8_volume_name_size";
1022
1023
26
  if( volume_superblock == NULL )
1024
0
  {
1025
0
    libcerror_error_set(
1026
0
     error,
1027
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1028
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1029
0
     "%s: invalid volume superblock.",
1030
0
     function );
1031
1032
0
    return( -1 );
1033
0
  }
1034
26
  if( libuna_utf8_string_size_from_utf8_stream(
1035
26
       volume_superblock->volume_name,
1036
26
       256,
1037
26
       utf8_string_size,
1038
26
       error ) != 1 )
1039
4
  {
1040
4
    libcerror_error_set(
1041
4
     error,
1042
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1043
4
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1044
4
     "%s: unable to retrieve UTF-8 string size.",
1045
4
     function );
1046
1047
4
    return( -1 );
1048
4
  }
1049
22
  return( 1 );
1050
26
}
1051
1052
/* Retrieves the UTF-8 encoded volume name
1053
 * The size should include the end of string character
1054
 * Returns 1 if successful or -1 on error
1055
 */
1056
int libfsapfs_volume_superblock_get_utf8_volume_name(
1057
     libfsapfs_volume_superblock_t *volume_superblock,
1058
     uint8_t *utf8_string,
1059
     size_t utf8_string_size,
1060
     libcerror_error_t **error )
1061
26
{
1062
26
  static char *function = "libfsapfs_volume_superblock_get_utf8_volume_name";
1063
1064
26
  if( volume_superblock == NULL )
1065
0
  {
1066
0
    libcerror_error_set(
1067
0
     error,
1068
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1069
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1070
0
     "%s: invalid volume superblock.",
1071
0
     function );
1072
1073
0
    return( -1 );
1074
0
  }
1075
26
  if( libuna_utf8_string_copy_from_utf8_stream(
1076
26
       utf8_string,
1077
26
       utf8_string_size,
1078
26
       volume_superblock->volume_name,
1079
26
       256,
1080
26
       error ) != 1 )
1081
4
  {
1082
4
    libcerror_error_set(
1083
4
     error,
1084
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1085
4
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1086
4
     "%s: unable to retrieve UTF-8 string.",
1087
4
     function );
1088
1089
4
    return( -1 );
1090
4
  }
1091
22
  return( 1 );
1092
26
}
1093
1094
/* Retrieves the size of the UTF-16 encoded volume name
1095
 * The returned size includes the end of string character
1096
 * Returns 1 if successful or -1 on error
1097
 */
1098
int libfsapfs_volume_superblock_get_utf16_volume_name_size(
1099
     libfsapfs_volume_superblock_t *volume_superblock,
1100
     size_t *utf16_string_size,
1101
     libcerror_error_t **error )
1102
0
{
1103
0
  static char *function = "libfsapfs_volume_superblock_get_utf16_volume_name_size";
1104
1105
0
  if( volume_superblock == NULL )
1106
0
  {
1107
0
    libcerror_error_set(
1108
0
     error,
1109
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1110
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1111
0
     "%s: invalid volume superblock.",
1112
0
     function );
1113
1114
0
    return( -1 );
1115
0
  }
1116
0
  if( libuna_utf16_string_size_from_utf8_stream(
1117
0
       volume_superblock->volume_name,
1118
0
       256,
1119
0
       utf16_string_size,
1120
0
       error ) != 1 )
1121
0
  {
1122
0
    libcerror_error_set(
1123
0
     error,
1124
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1125
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1126
0
     "%s: unable to retrieve UTF-16 string size.",
1127
0
     function );
1128
1129
0
    return( -1 );
1130
0
  }
1131
0
  return( 1 );
1132
0
}
1133
1134
/* Retrieves the UTF-16 encoded volume name
1135
 * The size should include the end of string character
1136
 * Returns 1 if successful or -1 on error
1137
 */
1138
int libfsapfs_volume_superblock_get_utf16_volume_name(
1139
     libfsapfs_volume_superblock_t *volume_superblock,
1140
     uint16_t *utf16_string,
1141
     size_t utf16_string_size,
1142
     libcerror_error_t **error )
1143
0
{
1144
0
  static char *function = "libfsapfs_volume_superblock_get_utf16_volume_name";
1145
1146
0
  if( volume_superblock == NULL )
1147
0
  {
1148
0
    libcerror_error_set(
1149
0
     error,
1150
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1151
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1152
0
     "%s: invalid volume superblock.",
1153
0
     function );
1154
1155
0
    return( -1 );
1156
0
  }
1157
0
  if( libuna_utf16_string_copy_from_utf8_stream(
1158
0
       utf16_string,
1159
0
       utf16_string_size,
1160
0
       volume_superblock->volume_name,
1161
0
       256,
1162
0
       error ) != 1 )
1163
0
  {
1164
0
    libcerror_error_set(
1165
0
     error,
1166
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1167
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1168
0
     "%s: unable to retrieve UTF-16 string.",
1169
0
     function );
1170
1171
0
    return( -1 );
1172
0
  }
1173
0
  return( 1 );
1174
0
}
1175