Coverage Report

Created: 2024-02-25 07:19

/src/libfsext/libfsext/libfsext_superblock.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Superblock functions
3
 *
4
 * Copyright (C) 2010-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 <narrow_string.h>
26
#include <system_string.h>
27
#include <types.h>
28
#include <wide_string.h>
29
30
#include "libfsext_debug.h"
31
#include "libfsext_libbfio.h"
32
#include "libfsext_libcerror.h"
33
#include "libfsext_libcnotify.h"
34
#include "libfsext_libfdatetime.h"
35
#include "libfsext_libfguid.h"
36
#include "libfsext_libuna.h"
37
#include "libfsext_superblock.h"
38
39
#include "fsext_superblock.h"
40
41
const char *fsext_superblock_signature = "\x53\xef";
42
43
/* Creates a superblock
44
 * Make sure the value superblock is referencing, is set to NULL
45
 * Returns 1 if successful or -1 on error
46
 */
47
int libfsext_superblock_initialize(
48
     libfsext_superblock_t **superblock,
49
     libcerror_error_t **error )
50
1.85k
{
51
1.85k
  static char *function = "libfsext_superblock_initialize";
52
53
1.85k
  if( superblock == NULL )
54
0
  {
55
0
    libcerror_error_set(
56
0
     error,
57
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59
0
     "%s: invalid superblock.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
1.85k
  if( *superblock != NULL )
65
0
  {
66
0
    libcerror_error_set(
67
0
     error,
68
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
69
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70
0
     "%s: invalid superblock value already set.",
71
0
     function );
72
73
0
    return( -1 );
74
0
  }
75
1.85k
  *superblock = memory_allocate_structure(
76
1.85k
                 libfsext_superblock_t );
77
78
1.85k
  if( *superblock == NULL )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
83
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84
0
     "%s: unable to create superblock.",
85
0
     function );
86
87
0
    goto on_error;
88
0
  }
89
1.85k
  if( memory_set(
90
1.85k
       *superblock,
91
1.85k
       0,
92
1.85k
       sizeof( libfsext_superblock_t ) ) == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
97
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
98
0
     "%s: unable to clear superblock.",
99
0
     function );
100
101
0
    goto on_error;
102
0
  }
103
1.85k
  return( 1 );
104
105
0
on_error:
106
0
  if( *superblock != NULL )
107
0
  {
108
0
    memory_free(
109
0
     *superblock );
110
111
0
    *superblock = NULL;
112
0
  }
113
0
  return( -1 );
114
1.85k
}
115
116
/* Frees a superblock
117
 * Returns 1 if successful or -1 on error
118
 */
119
int libfsext_superblock_free(
120
     libfsext_superblock_t **superblock,
121
     libcerror_error_t **error )
122
1.85k
{
123
1.85k
  static char *function = "libfsext_superblock_free";
124
125
1.85k
  if( superblock == NULL )
126
0
  {
127
0
    libcerror_error_set(
128
0
     error,
129
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
130
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
131
0
     "%s: invalid superblock.",
132
0
     function );
133
134
0
    return( -1 );
135
0
  }
136
1.85k
  if( *superblock != NULL )
137
1.85k
  {
138
1.85k
    memory_free(
139
1.85k
     *superblock );
140
141
1.85k
    *superblock = NULL;
142
1.85k
  }
143
1.85k
  return( 1 );
144
1.85k
}
145
146
/* Reads the superblock data
147
 * Returns 1 if successful or -1 on error
148
 */
149
int libfsext_superblock_read_data(
150
     libfsext_superblock_t *superblock,
151
     const uint8_t *data,
152
     size_t data_size,
153
     libcerror_error_t **error )
154
1.77k
{
155
1.77k
  static char *function                         = "libfsext_superblock_read_data";
156
1.77k
  uint32_t supported_feature_flags              = 0;
157
1.77k
  uint8_t number_of_block_groups_per_flex_group = 0;
158
159
#if defined( HAVE_DEBUG_OUTPUT )
160
  uint64_t value_64bit                          = 0;
161
  uint32_t value_32bit                          = 0;
162
  uint16_t value_16bit                          = 0;
163
#endif
164
165
1.77k
  if( superblock == NULL )
166
0
  {
167
0
    libcerror_error_set(
168
0
     error,
169
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
170
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
171
0
     "%s: invalid superblock.",
172
0
     function );
173
174
0
    return( -1 );
175
0
  }
176
1.77k
  if( data == NULL )
177
0
  {
178
0
    libcerror_error_set(
179
0
     error,
180
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
181
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
182
0
     "%s: invalid data.",
183
0
     function );
184
185
0
    return( -1 );
186
0
  }
187
1.77k
  if( data_size < sizeof( fsext_superblock_ext2_t ) )
188
0
  {
189
0
    libcerror_error_set(
190
0
     error,
191
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
192
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
193
0
     "%s: invalid data size value too small.",
194
0
     function );
195
196
0
    return( -1 );
197
0
  }
198
1.77k
  if( data_size > (size_t) SSIZE_MAX )
199
0
  {
200
0
    libcerror_error_set(
201
0
     error,
202
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
203
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
204
0
     "%s: invalid data size value exceeds maximum.",
205
0
     function );
206
207
0
    return( -1 );
208
0
  }
209
#if defined( HAVE_DEBUG_OUTPUT )
210
  if( libcnotify_verbose != 0 )
211
  {
212
    libcnotify_printf(
213
     "%s: superblock data:\n",
214
     function );
215
    libcnotify_print_data(
216
     data,
217
     sizeof( fsext_superblock_ext2_t ),
218
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
219
  }
220
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
221
222
1.77k
  if( memory_compare(
223
1.77k
       ( (fsext_superblock_ext2_t *) data )->signature,
224
1.77k
       fsext_superblock_signature,
225
1.77k
       2 ) != 0 )
226
44
  {
227
44
    libcerror_error_set(
228
44
     error,
229
44
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
230
44
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
231
44
     "%s: invalid signature.",
232
44
     function );
233
234
44
    return( -1 );
235
44
  }
236
1.73k
  byte_stream_copy_to_uint32_little_endian(
237
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_inodes,
238
1.73k
   superblock->number_of_inodes );
239
240
1.73k
  byte_stream_copy_to_uint32_little_endian(
241
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_blocks,
242
1.73k
   superblock->number_of_blocks );
243
244
1.73k
  byte_stream_copy_to_uint32_little_endian(
245
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_reserved_blocks,
246
1.73k
   superblock->number_of_reserved_blocks );
247
248
1.73k
  byte_stream_copy_to_uint32_little_endian(
249
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_unallocated_blocks,
250
1.73k
   superblock->number_of_unallocated_blocks );
251
252
1.73k
  byte_stream_copy_to_uint32_little_endian(
253
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_unallocated_inodes,
254
1.73k
   superblock->number_of_unallocated_inodes );
255
256
1.73k
  byte_stream_copy_to_uint32_little_endian(
257
1.73k
   ( (fsext_superblock_ext2_t *) data )->block_size,
258
1.73k
   superblock->block_size );
259
260
1.73k
  byte_stream_copy_to_uint32_little_endian(
261
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_blocks_per_block_group,
262
1.73k
   superblock->number_of_blocks_per_block_group );
263
264
1.73k
  byte_stream_copy_to_uint32_little_endian(
265
1.73k
   ( (fsext_superblock_ext2_t *) data )->format_revision,
266
1.73k
   superblock->format_revision );
267
268
1.73k
  byte_stream_copy_to_uint32_little_endian(
269
1.73k
   ( (fsext_superblock_ext2_t *) data )->number_of_inodes_per_block_group,
270
1.73k
   superblock->number_of_inodes_per_block_group );
271
272
1.73k
  byte_stream_copy_to_uint32_little_endian(
273
1.73k
   ( (fsext_superblock_ext2_t *) data )->last_mount_time,
274
1.73k
   superblock->last_mount_time );
275
276
1.73k
  byte_stream_copy_to_uint32_little_endian(
277
1.73k
   ( (fsext_superblock_ext2_t *) data )->last_written_time,
278
1.73k
   superblock->last_written_time );
279
280
#if defined( HAVE_DEBUG_OUTPUT )
281
  if( libcnotify_verbose != 0 )
282
  {
283
    libcnotify_printf(
284
     "%s: number of inodes\t\t\t\t\t: %" PRIu32 "\n",
285
     function,
286
     superblock->number_of_inodes );
287
288
    libcnotify_printf(
289
     "%s: number of blocks\t\t\t\t\t: %" PRIu32 "\n",
290
     function,
291
     superblock->number_of_blocks );
292
293
    libcnotify_printf(
294
     "%s: number of reserved blocks\t\t\t: %" PRIu32 "\n",
295
     function,
296
     superblock->number_of_reserved_blocks );
297
298
    libcnotify_printf(
299
     "%s: number of unallocated blocks\t\t\t: %" PRIu32 "\n",
300
     function,
301
     superblock->number_of_unallocated_blocks );
302
303
    libcnotify_printf(
304
     "%s: number of unallocated inodes\t\t\t: %" PRIu32 "\n",
305
     function,
306
     superblock->number_of_unallocated_inodes );
307
308
    byte_stream_copy_to_uint32_little_endian(
309
     ( (fsext_superblock_ext2_t *) data )->first_data_block_number,
310
     value_32bit );
311
    libcnotify_printf(
312
     "%s: first data block number\t\t\t\t: %" PRIu32 "\n",
313
     function,
314
     value_32bit );
315
316
    libcnotify_printf(
317
     "%s: block size\t\t\t\t\t: %" PRIu64 " (%" PRIu32 ")\n",
318
     function,
319
     (uint64_t) 1024UL << superblock->block_size,
320
     superblock->block_size );
321
322
    byte_stream_copy_to_uint32_little_endian(
323
     ( (fsext_superblock_ext2_t *) data )->fragment_size,
324
     value_32bit );
325
    libcnotify_printf(
326
     "%s: fragment size\t\t\t\t\t: %" PRIu32 " (%" PRIu32 ")\n",
327
     function,
328
     1024 << value_32bit,
329
     value_32bit );
330
331
    libcnotify_printf(
332
     "%s: number of blocks per block group\t\t\t: %" PRIu32 "\n",
333
     function,
334
     superblock->number_of_blocks_per_block_group );
335
336
    byte_stream_copy_to_uint32_little_endian(
337
     ( (fsext_superblock_ext2_t *) data )->number_of_fragments_per_block_group,
338
     value_32bit );
339
    libcnotify_printf(
340
     "%s: number of fragments per block group\t\t: %" PRIu32 "\n",
341
     function,
342
     value_32bit );
343
344
    libcnotify_printf(
345
     "%s: number of inodes per block group\t\t\t: %" PRIu32 "\n",
346
     function,
347
     superblock->number_of_inodes_per_block_group );
348
349
    if( libfsext_debug_print_posix_time_value(
350
         function,
351
         "last mount time\t\t\t\t\t",
352
         ( (fsext_superblock_ext2_t *) data )->last_mount_time,
353
         4,
354
         LIBFDATETIME_ENDIAN_LITTLE,
355
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
356
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
357
         error ) != 1 )
358
    {
359
      libcerror_error_set(
360
       error,
361
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
362
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
363
       "%s: unable to print posix time value.",
364
       function );
365
366
      return( -1 );
367
    }
368
    if( libfsext_debug_print_posix_time_value(
369
         function,
370
         "last written time\t\t\t\t",
371
         ( (fsext_superblock_ext2_t *) data )->last_written_time,
372
         4,
373
         LIBFDATETIME_ENDIAN_LITTLE,
374
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
375
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
376
         error ) != 1 )
377
    {
378
      libcerror_error_set(
379
       error,
380
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
381
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
382
       "%s: unable to print posix time value.",
383
       function );
384
385
      return( -1 );
386
    }
387
    byte_stream_copy_to_uint16_little_endian(
388
     ( (fsext_superblock_ext2_t *) data )->mount_count,
389
     value_16bit );
390
    libcnotify_printf(
391
     "%s: mount count\t\t\t\t\t: %" PRIu16 "\n",
392
     function,
393
     value_16bit );
394
395
    byte_stream_copy_to_uint16_little_endian(
396
     ( (fsext_superblock_ext2_t *) data )->maximum_mount_count,
397
     value_16bit );
398
    libcnotify_printf(
399
     "%s: maximum mount count\t\t\t\t: %" PRIu16 "\n",
400
     function,
401
     value_16bit );
402
403
    libcnotify_printf(
404
     "%s: signature\t\t\t\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 "\n",
405
     function,
406
     ( (fsext_superblock_ext2_t *) data )->signature[ 0 ],
407
     ( (fsext_superblock_ext2_t *) data )->signature[ 1 ] );
408
409
    byte_stream_copy_to_uint16_little_endian(
410
     ( (fsext_superblock_ext2_t *) data )->file_system_state_flags,
411
     value_16bit );
412
    libcnotify_printf(
413
     "%s: file system state flags\t\t\t\t: 0x%04" PRIx16 "\n",
414
     function,
415
     value_16bit );
416
    libfsext_debug_print_file_system_state_flags(
417
     value_16bit );
418
    libcnotify_printf(
419
     "\n" );
420
421
    byte_stream_copy_to_uint16_little_endian(
422
     ( (fsext_superblock_ext2_t *) data )->error_handling_status,
423
     value_16bit );
424
    libcnotify_printf(
425
     "%s: error handling status\t\t\t\t: %" PRIu16 " (%s)\n",
426
     function,
427
     value_16bit,
428
     libfsext_debug_print_error_handling_status(
429
      value_16bit ) );
430
431
    byte_stream_copy_to_uint16_little_endian(
432
     ( (fsext_superblock_ext2_t *) data )->minor_format_revision,
433
     value_16bit );
434
    libcnotify_printf(
435
     "%s: minor format revision\t\t\t\t: %" PRIu16 "\n",
436
     function,
437
     value_16bit );
438
439
    if( libfsext_debug_print_posix_time_value(
440
         function,
441
         "last consistency check time\t\t\t",
442
         ( (fsext_superblock_ext2_t *) data )->last_consistency_check_time,
443
         4,
444
         LIBFDATETIME_ENDIAN_LITTLE,
445
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
446
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
447
         error ) != 1 )
448
    {
449
      libcerror_error_set(
450
       error,
451
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
452
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
453
       "%s: unable to print posix time value.",
454
       function );
455
456
      return( -1 );
457
    }
458
459
/* TODO print interval as duration? */
460
    byte_stream_copy_to_uint32_little_endian(
461
     ( (fsext_superblock_ext2_t *) data )->consistency_check_interval,
462
     value_32bit );
463
    libcnotify_printf(
464
     "%s: consistency check interval\t\t\t: %" PRIu32 "\n",
465
     function,
466
     value_32bit );
467
468
    byte_stream_copy_to_uint32_little_endian(
469
     ( (fsext_superblock_ext2_t *) data )->creator_operating_system,
470
     value_32bit );
471
    libcnotify_printf(
472
     "%s: creator operating system\t\t\t\t: %" PRIu32 " (%s)\n",
473
     function,
474
     value_32bit,
475
     libfsext_debug_print_creator_operating_system(
476
      value_32bit ) );
477
478
    libcnotify_printf(
479
     "%s: format revision\t\t\t\t\t: %" PRIu32 "\n",
480
     function,
481
     superblock->format_revision );
482
483
    byte_stream_copy_to_uint16_little_endian(
484
     ( (fsext_superblock_ext2_t *) data )->reserved_block_user_identifier,
485
     value_16bit );
486
    libcnotify_printf(
487
     "%s: reserved block user identifier\t\t\t: %" PRIu16 "\n",
488
     function,
489
     value_16bit );
490
491
    byte_stream_copy_to_uint16_little_endian(
492
     ( (fsext_superblock_ext2_t *) data )->reserved_block_group_identifier,
493
     value_16bit );
494
    libcnotify_printf(
495
     "%s: reserved block group identifier\t\t\t: %" PRIu16 "\n",
496
     function,
497
     value_16bit );
498
499
    libcnotify_printf(
500
     "\n" );
501
  }
502
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
503
504
1.73k
  if( superblock->block_size > ( 31 - 10 ) )
505
35
  {
506
35
    libcerror_error_set(
507
35
     error,
508
35
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
509
35
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
510
35
     "%s: invalid block size value out of bounds.",
511
35
     function );
512
513
35
    return( -1 );
514
35
  }
515
1.69k
  superblock->block_size = (uint32_t) ( 1024UL << superblock->block_size );
516
517
1.69k
  if( superblock->format_revision > 1 )
518
38
  {
519
38
    libcerror_error_set(
520
38
     error,
521
38
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
522
38
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
523
38
     "%s: unsupported format revision: %" PRIu32 ".",
524
38
     function,
525
38
     superblock->format_revision );
526
527
38
    return( -1 );
528
38
  }
529
/* TODO add sanity check of fragment size */
530
531
1.66k
  if( superblock->format_revision == 1 )
532
1.62k
  {
533
1.62k
    byte_stream_copy_to_uint16_little_endian(
534
1.62k
     ( (fsext_superblock_ext2_t *) data )->inode_size,
535
1.62k
     superblock->inode_size );
536
537
1.62k
    byte_stream_copy_to_uint16_little_endian(
538
1.62k
     ( (fsext_superblock_ext2_t *) data )->block_group,
539
1.62k
     superblock->block_group );
540
541
1.62k
    byte_stream_copy_to_uint32_little_endian(
542
1.62k
     ( (fsext_superblock_ext2_t *) data )->compatible_features_flags,
543
1.62k
     superblock->compatible_features_flags );
544
545
1.62k
    byte_stream_copy_to_uint32_little_endian(
546
1.62k
     ( (fsext_superblock_ext2_t *) data )->incompatible_features_flags,
547
1.62k
     superblock->incompatible_features_flags );
548
549
1.62k
    byte_stream_copy_to_uint32_little_endian(
550
1.62k
     ( (fsext_superblock_ext2_t *) data )->read_only_compatible_features_flags,
551
1.62k
     superblock->read_only_compatible_features_flags );
552
553
1.62k
    if( memory_copy(
554
1.62k
         superblock->file_system_identifier,
555
1.62k
         ( (fsext_superblock_ext2_t *) data )->file_system_identifier,
556
1.62k
         16 ) == NULL )
557
0
    {
558
0
      libcerror_error_set(
559
0
       error,
560
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
561
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
562
0
       "%s: unable to copy file system identifier.",
563
0
       function );
564
565
0
      return( -1 );
566
0
    }
567
1.62k
    if( memory_copy(
568
1.62k
         superblock->volume_label,
569
1.62k
         ( (fsext_superblock_ext2_t *) data )->volume_label,
570
1.62k
         16 ) == NULL )
571
0
    {
572
0
      libcerror_error_set(
573
0
       error,
574
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
575
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
576
0
       "%s: unable to copy volume label.",
577
0
       function );
578
579
0
      return( -1 );
580
0
    }
581
1.62k
    if( memory_copy(
582
1.62k
         superblock->last_mount_path,
583
1.62k
         ( (fsext_superblock_ext2_t *) data )->last_mount_path,
584
1.62k
         64 ) == NULL )
585
0
    {
586
0
      libcerror_error_set(
587
0
       error,
588
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
589
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
590
0
       "%s: unable to copy last mount path.",
591
0
       function );
592
593
0
      return( -1 );
594
0
    }
595
#if defined( HAVE_DEBUG_OUTPUT )
596
    if( libcnotify_verbose != 0 )
597
    {
598
      byte_stream_copy_to_uint32_little_endian(
599
       ( (fsext_superblock_ext2_t *) data )->first_non_reserved_inode,
600
       value_32bit );
601
      libcnotify_printf(
602
       "%s: first non-reserved inode\t\t\t\t: %" PRIu32 "\n",
603
       function,
604
       value_32bit );
605
606
      libcnotify_printf(
607
       "%s: inode size\t\t\t\t\t: %" PRIu16 "\n",
608
       function,
609
       superblock->inode_size );
610
611
      libcnotify_printf(
612
       "%s: block group\t\t\t\t\t: %" PRIu16 "\n",
613
       function,
614
       superblock->block_group );
615
616
      libcnotify_printf(
617
       "%s: compatible features flags\t\t\t: 0x%08" PRIx32 "\n",
618
       function,
619
       superblock->compatible_features_flags );
620
      libfsext_debug_print_compatible_features_flags(
621
       superblock->compatible_features_flags );
622
      libcnotify_printf(
623
       "\n" );
624
625
      libcnotify_printf(
626
       "%s: incompatible features flags\t\t\t: 0x%08" PRIx32 "\n",
627
       function,
628
       superblock->incompatible_features_flags );
629
      libfsext_debug_print_incompatible_features_flags(
630
       superblock->incompatible_features_flags );
631
      libcnotify_printf(
632
       "\n" );
633
634
      libcnotify_printf(
635
       "%s: read-only compatible features flags\t\t: 0x%08" PRIx32 "\n",
636
       function,
637
       superblock->read_only_compatible_features_flags );
638
      libfsext_debug_print_read_only_compatible_features_flags(
639
       superblock->read_only_compatible_features_flags );
640
      libcnotify_printf(
641
       "\n" );
642
643
      if( libfsext_debug_print_guid_value(
644
           function,
645
           "file system identifier\t\t\t\t",
646
           ( (fsext_superblock_ext2_t *) data )->file_system_identifier,
647
           16,
648
           LIBFGUID_ENDIAN_BIG,
649
           LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
650
           error ) != 1 )
651
      {
652
        libcerror_error_set(
653
         error,
654
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
655
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
656
         "%s: unable to print GUID value.",
657
         function );
658
659
        return( -1 );
660
      }
661
      if( libfsext_debug_print_utf8_string_value(
662
           function,
663
           "volume label\t\t\t\t\t",
664
           superblock->volume_label,
665
           16,
666
           error ) != 1 )
667
      {
668
        libcerror_error_set(
669
         error,
670
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
671
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
672
         "%s: unable to print UTF-8 string value.",
673
         function );
674
675
        return( -1 );
676
      }
677
      if( libfsext_debug_print_utf8_string_value(
678
           function,
679
           "last mount path\t\t\t\t\t",
680
           superblock->last_mount_path,
681
           64,
682
           error ) != 1 )
683
      {
684
        libcerror_error_set(
685
         error,
686
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
687
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
688
         "%s: unable to print UTF-8 string value.",
689
         function );
690
691
        return( -1 );
692
      }
693
      byte_stream_copy_to_uint32_little_endian(
694
       ( (fsext_superblock_ext2_t *) data )->algorithm_usage_bitmap,
695
       value_32bit );
696
      libcnotify_printf(
697
       "%s: algorithm usage bitmap\t\t\t\t: 0x%08" PRIx32 "\n",
698
       function,
699
       value_32bit );
700
701
      libcnotify_printf(
702
       "\n" );
703
    }
704
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
705
1.62k
  }
706
1.66k
  supported_feature_flags = 0x00000001UL
707
1.66k
                          | 0x00000004UL
708
1.66k
                          | 0x00000008UL
709
1.66k
                          | 0x00000010UL
710
1.66k
                          | 0x00000020UL;
711
712
1.66k
  if( ( superblock->compatible_features_flags & ~( supported_feature_flags ) ) != 0 )
713
31
  {
714
31
    libcerror_error_set(
715
31
     error,
716
31
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
717
31
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
718
31
     "%s: unsupported compatible features flags: 0x%08" PRIx32 ".",
719
31
     function,
720
31
     superblock->compatible_features_flags );
721
722
31
    return( -1 );
723
31
  }
724
1.63k
  supported_feature_flags = 0x00000002UL
725
1.63k
                          | 0x00000004UL
726
1.63k
                          | 0x00000008UL
727
1.63k
                          | 0x00000010UL
728
1.63k
                          | 0x00000040UL
729
1.63k
                          | 0x00000080UL
730
1.63k
                          | 0x00000200UL
731
1.63k
                          | 0x00000400UL
732
1.63k
                          | 0x00008000UL
733
1.63k
                          | 0x00010000UL
734
1.63k
                          | 0x00020000UL;
735
736
1.63k
  if( ( superblock->incompatible_features_flags & ~( supported_feature_flags ) ) != 0 )
737
23
  {
738
23
    libcerror_error_set(
739
23
     error,
740
23
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
741
23
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
742
23
     "%s: unsupported incompatible features flags: 0x%08" PRIx32 ".",
743
23
     function,
744
23
     superblock->incompatible_features_flags );
745
746
23
    return( -1 );
747
23
  }
748
1.60k
  if( ( ( superblock->compatible_features_flags & 0x00000200UL ) != 0 )
749
1.60k
   || ( ( superblock->incompatible_features_flags & 0x0001f7c0UL ) != 0 )
750
1.60k
   || ( ( superblock->read_only_compatible_features_flags & 0x00000378UL ) != 0 ) )
751
1.04k
  {
752
1.04k
    superblock->format_version = 4;
753
1.04k
  }
754
561
  else if( ( ( superblock->compatible_features_flags & 0x00000004UL ) != 0 )
755
561
        || ( ( superblock->incompatible_features_flags & 0x0000000cUL ) != 0 ) )
756
308
  {
757
308
    superblock->format_version = 3;
758
308
  }
759
253
  else
760
253
  {
761
253
    superblock->format_version = 2;
762
253
  }
763
1.60k
  if( ( superblock->compatible_features_flags & 0x00000001UL ) != 0 )
764
497
  {
765
#if defined( HAVE_DEBUG_OUTPUT )
766
    if( libcnotify_verbose != 0 )
767
    {
768
      libcnotify_printf(
769
       "%s: number of pre-allocated blocks per file\t\t: %" PRIu8 "\n",
770
       function,
771
       ( (fsext_superblock_ext2_t *) data )->number_of_pre_allocated_blocks_per_file );
772
773
      libcnotify_printf(
774
       "%s: number of pre-allocated blocks per directory\t\t: %" PRIu8 "\n",
775
       function,
776
       ( (fsext_superblock_ext2_t *) data )->number_of_pre_allocated_blocks_per_directory );
777
778
      libcnotify_printf(
779
       "%s: padding1:\n",
780
       function );
781
      libcnotify_print_data(
782
       ( (fsext_superblock_ext2_t *) data )->padding1,
783
       2,
784
       0 );
785
    }
786
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
787
497
  }
788
1.60k
  if( superblock->format_version == 4 )
789
1.04k
  {
790
1.04k
    byte_stream_copy_to_uint16_little_endian(
791
1.04k
     ( (fsext_superblock_ext4_t *) data )->group_descriptor_size,
792
1.04k
     superblock->group_descriptor_size );
793
1.04k
  }
794
1.60k
  byte_stream_copy_to_uint32_little_endian(
795
1.60k
   ( (fsext_superblock_ext2_t *) data )->first_metadata_block_group,
796
1.60k
   superblock->first_metadata_block_group );
797
798
1.60k
  if( superblock->format_version == 4 )
799
1.04k
  {
800
1.04k
    number_of_block_groups_per_flex_group = ( (fsext_superblock_ext4_t *) data )->number_of_block_groups_per_flex_group;
801
1.04k
  }
802
#if defined( HAVE_DEBUG_OUTPUT )
803
  if( libcnotify_verbose != 0 )
804
  {
805
    if( libfsext_debug_print_guid_value(
806
         function,
807
         "journal identifier\t\t\t\t",
808
         ( (fsext_superblock_ext2_t *) data )->journal_identifier,
809
         16,
810
         LIBFGUID_ENDIAN_BIG,
811
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
812
         error ) != 1 )
813
    {
814
      libcerror_error_set(
815
       error,
816
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
817
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
818
       "%s: unable to print GUID value.",
819
       function );
820
821
      return( -1 );
822
    }
823
    byte_stream_copy_to_uint32_little_endian(
824
     ( (fsext_superblock_ext2_t *) data )->journal_inode_number,
825
     value_32bit );
826
    libcnotify_printf(
827
     "%s: journal inode number\t\t\t\t: %" PRIu32 "\n",
828
     function,
829
     value_32bit );
830
831
    byte_stream_copy_to_uint32_little_endian(
832
     ( (fsext_superblock_ext2_t *) data )->journal_device,
833
     value_32bit );
834
    libcnotify_printf(
835
     "%s: journal device\t\t\t\t\t: %" PRIu32 "\n",
836
     function,
837
     value_32bit );
838
839
    byte_stream_copy_to_uint32_little_endian(
840
     ( (fsext_superblock_ext2_t *) data )->orphan_inode_list_head,
841
     value_32bit );
842
    libcnotify_printf(
843
     "%s: orphan inode list head\t\t\t\t: %" PRIu32 "\n",
844
     function,
845
     value_32bit );
846
847
    libcnotify_printf(
848
     "%s: HTREE hash seed:\n",
849
     function );
850
    libcnotify_print_data(
851
     ( (fsext_superblock_ext2_t *) data )->htree_hash_seed,
852
     16,
853
     0 );
854
855
    libcnotify_printf(
856
     "%s: default hash version\t\t\t\t: %" PRIu8 "\n",
857
     function,
858
     ( (fsext_superblock_ext2_t *) data )->default_hash_version );
859
860
    if( superblock->format_version < 4 )
861
    {
862
      libcnotify_printf(
863
       "%s: padding2:\n",
864
       function );
865
      libcnotify_print_data(
866
       ( (fsext_superblock_ext2_t *) data )->padding2,
867
       3,
868
       0 );
869
    }
870
    else
871
    {
872
      libcnotify_printf(
873
       "%s: journal backup type\t\t\t\t: %" PRIu8 "\n",
874
       function,
875
       ( (fsext_superblock_ext4_t *) data )->journal_backup_type );
876
877
      libcnotify_printf(
878
       "%s: group descriptor size\t\t\t\t: %" PRIu16 "\n",
879
       function,
880
       superblock->group_descriptor_size );
881
    }
882
    byte_stream_copy_to_uint32_little_endian(
883
     ( (fsext_superblock_ext2_t *) data )->default_mount_options,
884
     value_32bit );
885
    libcnotify_printf(
886
     "%s: default mount options\t\t\t\t: %" PRIu32 "\n",
887
     function,
888
     value_32bit );
889
890
    libcnotify_printf(
891
     "%s: first metadata block group\t\t\t: %" PRIu32 "\n",
892
     function,
893
     superblock->first_metadata_block_group );
894
895
    if( superblock->format_version == 4 )
896
    {
897
      if( libfsext_debug_print_posix_time_value(
898
           function,
899
           "file system creation time\t\t\t",
900
           ( (fsext_superblock_ext4_t *) data )->file_system_creation_time,
901
           4,
902
           LIBFDATETIME_ENDIAN_LITTLE,
903
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
904
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
905
           error ) != 1 )
906
      {
907
        libcerror_error_set(
908
         error,
909
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
910
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
911
         "%s: unable to print posix time value.",
912
         function );
913
914
        return( -1 );
915
      }
916
      libcnotify_printf(
917
       "%s: backup journal inodes:\n",
918
       function );
919
      libcnotify_print_data(
920
       ( (fsext_superblock_ext4_t *) data )->backup_journal_inodes,
921
       68,
922
       0 );
923
924
      byte_stream_copy_to_uint32_little_endian(
925
       ( (fsext_superblock_ext4_t *) data )->number_of_blocks_upper,
926
       value_32bit );
927
      libcnotify_printf(
928
       "%s: number of blocks (upper 32-bit)\t\t\t: %" PRIu32 "\n",
929
       function,
930
       value_32bit );
931
932
      byte_stream_copy_to_uint32_little_endian(
933
       ( (fsext_superblock_ext4_t *) data )->number_of_reserved_blocks_upper,
934
       value_32bit );
935
      libcnotify_printf(
936
       "%s: number of reserved blocks (upper 32-bit)\t\t: %" PRIu32 "\n",
937
       function,
938
       value_32bit );
939
940
      byte_stream_copy_to_uint32_little_endian(
941
       ( (fsext_superblock_ext4_t *) data )->number_of_unallocated_blocks_upper,
942
       value_32bit );
943
      libcnotify_printf(
944
       "%s: number of unallocated blocks (upper 32-bit)\t: %" PRIu32 "\n",
945
       function,
946
       value_32bit );
947
948
      byte_stream_copy_to_uint16_little_endian(
949
       ( (fsext_superblock_ext4_t *) data )->minimum_inode_size,
950
       value_16bit );
951
      libcnotify_printf(
952
       "%s: minimum inode size\t\t\t\t: %" PRIu16 "\n",
953
       function,
954
       value_16bit );
955
956
      byte_stream_copy_to_uint16_little_endian(
957
       ( (fsext_superblock_ext4_t *) data )->reserved_inode_size,
958
       value_16bit );
959
      libcnotify_printf(
960
       "%s: reserved inode size\t\t\t\t: %" PRIu16 "\n",
961
       function,
962
       value_16bit );
963
964
      byte_stream_copy_to_uint32_little_endian(
965
       ( (fsext_superblock_ext4_t *) data )->flags,
966
       value_32bit );
967
      libcnotify_printf(
968
       "%s: flags\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
969
       function,
970
       value_32bit );
971
972
      byte_stream_copy_to_uint16_little_endian(
973
       ( (fsext_superblock_ext4_t *) data )->read_stride,
974
       value_16bit );
975
      libcnotify_printf(
976
       "%s: read stride\t\t\t\t\t: %" PRIu16 "\n",
977
       function,
978
       value_16bit );
979
980
      byte_stream_copy_to_uint16_little_endian(
981
       ( (fsext_superblock_ext4_t *) data )->multi_mount_protection_update_interval,
982
       value_16bit );
983
      libcnotify_printf(
984
       "%s: multi-mount protection update interval\t\t: %" PRIu16 "\n",
985
       function,
986
       value_16bit );
987
988
      byte_stream_copy_to_uint64_little_endian(
989
       ( (fsext_superblock_ext4_t *) data )->multi_mount_protection_block,
990
       value_64bit );
991
      libcnotify_printf(
992
       "%s: multi-mount protection block\t\t\t: %" PRIu64 "\n",
993
       function,
994
       value_64bit );
995
996
      byte_stream_copy_to_uint32_little_endian(
997
       ( (fsext_superblock_ext4_t *) data )->raid_stripe_width,
998
       value_32bit );
999
      libcnotify_printf(
1000
       "%s: RAID stripe width\t\t\t\t: %" PRIu32 "\n",
1001
       function,
1002
       value_32bit );
1003
1004
      libcnotify_printf(
1005
       "%s: number of blocks per flex group\t\t\t: %" PRIu32 " (2 ^ %" PRIu8 ")\n",
1006
       function,
1007
       (uint64_t) 1 << number_of_block_groups_per_flex_group,
1008
       number_of_block_groups_per_flex_group );
1009
1010
      libcnotify_printf(
1011
       "%s: checksum type\t\t\t\t\t: %" PRIu8 "\n",
1012
       function,
1013
       ( (fsext_superblock_ext4_t *) data )->checksum_type );
1014
1015
      libcnotify_printf(
1016
       "%s: encryption level\t\t\t\t\t: %" PRIu8 "\n",
1017
       function,
1018
       ( (fsext_superblock_ext4_t *) data )->encryption_level );
1019
1020
      libcnotify_printf(
1021
       "%s: padding2\t\t\t\t\t\t: 0x%02" PRIx8 "\n",
1022
       function,
1023
       ( (fsext_superblock_ext4_t *) data )->padding2 );
1024
1025
      byte_stream_copy_to_uint64_little_endian(
1026
       ( (fsext_superblock_ext4_t *) data )->write_count,
1027
       value_64bit );
1028
      libcnotify_printf(
1029
       "%s: write count\t\t\t\t\t: %" PRIu64 "\n",
1030
       function,
1031
       value_64bit );
1032
1033
      byte_stream_copy_to_uint32_little_endian(
1034
       ( (fsext_superblock_ext4_t *) data )->snapshot_inode_number,
1035
       value_32bit );
1036
      libcnotify_printf(
1037
       "%s: snapshot inode number\t\t\t\t: %" PRIu32 "\n",
1038
       function,
1039
       value_32bit );
1040
1041
      byte_stream_copy_to_uint32_little_endian(
1042
       ( (fsext_superblock_ext4_t *) data )->snapshot_sequential_identifier,
1043
       value_32bit );
1044
      libcnotify_printf(
1045
       "%s: snapshot sequential identifier\t\t\t: %" PRIu32 "\n",
1046
       function,
1047
       value_32bit );
1048
1049
      byte_stream_copy_to_uint64_little_endian(
1050
       ( (fsext_superblock_ext4_t *) data )->snapshot_number_of_reserved_blocks,
1051
       value_64bit );
1052
      libcnotify_printf(
1053
       "%s: snapshot number of reserved blocks\t\t: %" PRIu64 "\n",
1054
       function,
1055
       value_64bit );
1056
1057
      byte_stream_copy_to_uint32_little_endian(
1058
       ( (fsext_superblock_ext4_t *) data )->snapshot_inode_list,
1059
       value_32bit );
1060
      libcnotify_printf(
1061
       "%s: snapshot inode list\t\t\t\t: %" PRIu32 "\n",
1062
       function,
1063
       value_32bit );
1064
1065
      byte_stream_copy_to_uint32_little_endian(
1066
       ( (fsext_superblock_ext4_t *) data )->number_of_errors,
1067
       value_32bit );
1068
      libcnotify_printf(
1069
       "%s: number of errors\t\t\t\t\t: %" PRIu32 "\n",
1070
       function,
1071
       value_32bit );
1072
1073
      byte_stream_copy_to_uint32_little_endian(
1074
       ( (fsext_superblock_ext4_t *) data )->first_error_time,
1075
       value_32bit );
1076
      libcnotify_printf(
1077
       "%s: first error time\t\t\t\t\t: %" PRIu32 "\n",
1078
       function,
1079
       value_32bit );
1080
1081
      byte_stream_copy_to_uint32_little_endian(
1082
       ( (fsext_superblock_ext4_t *) data )->first_error_inode_number,
1083
       value_32bit );
1084
      libcnotify_printf(
1085
       "%s: first error inode number\t\t\t\t: %" PRIu32 "\n",
1086
       function,
1087
       value_32bit );
1088
1089
      byte_stream_copy_to_uint32_little_endian(
1090
       ( (fsext_superblock_ext4_t *) data )->first_error_block_number,
1091
       value_32bit );
1092
      libcnotify_printf(
1093
       "%s: first error block number\t\t\t\t: %" PRIu32 "\n",
1094
       function,
1095
       value_32bit );
1096
1097
      libcnotify_printf(
1098
       "%s: first error function:\n",
1099
       function );
1100
      libcnotify_print_data(
1101
       ( (fsext_superblock_ext4_t *) data )->first_error_function,
1102
       32,
1103
       0 );
1104
1105
      byte_stream_copy_to_uint32_little_endian(
1106
       ( (fsext_superblock_ext4_t *) data )->first_error_function_line_number,
1107
       value_32bit );
1108
      libcnotify_printf(
1109
       "%s: first error function line number\t\t\t: %" PRIu32 "\n",
1110
       function,
1111
       value_32bit );
1112
1113
      byte_stream_copy_to_uint32_little_endian(
1114
       ( (fsext_superblock_ext4_t *) data )->last_error_time,
1115
       value_32bit );
1116
      libcnotify_printf(
1117
       "%s: last error time\t\t\t\t\t: %" PRIu32 "\n",
1118
       function,
1119
       value_32bit );
1120
1121
      byte_stream_copy_to_uint32_little_endian(
1122
       ( (fsext_superblock_ext4_t *) data )->last_error_inode_number,
1123
       value_32bit );
1124
      libcnotify_printf(
1125
       "%s: last error inode number\t\t\t\t: %" PRIu32 "\n",
1126
       function,
1127
       value_32bit );
1128
1129
      byte_stream_copy_to_uint32_little_endian(
1130
       ( (fsext_superblock_ext4_t *) data )->last_error_function_line_number,
1131
       value_32bit );
1132
      libcnotify_printf(
1133
       "%s: last error function line number\t\t\t: %" PRIu32 "\n",
1134
       function,
1135
       value_32bit );
1136
1137
      byte_stream_copy_to_uint32_little_endian(
1138
       ( (fsext_superblock_ext4_t *) data )->last_error_block_number,
1139
       value_32bit );
1140
      libcnotify_printf(
1141
       "%s: last error block number\t\t\t\t: %" PRIu32 "\n",
1142
       function,
1143
       value_32bit );
1144
1145
      libcnotify_printf(
1146
       "%s: last error function:\n",
1147
       function );
1148
      libcnotify_print_data(
1149
       ( (fsext_superblock_ext4_t *) data )->last_error_function,
1150
       32,
1151
       0 );
1152
1153
      libcnotify_printf(
1154
       "%s: mount options:\n",
1155
       function );
1156
      libcnotify_print_data(
1157
       ( (fsext_superblock_ext4_t *) data )->last_error_function,
1158
       64,
1159
       0 );
1160
1161
      byte_stream_copy_to_uint32_little_endian(
1162
       ( (fsext_superblock_ext4_t *) data )->user_quota_inode_number,
1163
       value_32bit );
1164
      libcnotify_printf(
1165
       "%s: user quota inode number\t\t\t\t: %" PRIu32 "\n",
1166
       function,
1167
       value_32bit );
1168
1169
      byte_stream_copy_to_uint32_little_endian(
1170
       ( (fsext_superblock_ext4_t *) data )->group_quota_inode_number,
1171
       value_32bit );
1172
      libcnotify_printf(
1173
       "%s: group quota inode number\t\t\t\t: %" PRIu32 "\n",
1174
       function,
1175
       value_32bit );
1176
1177
      byte_stream_copy_to_uint32_little_endian(
1178
       ( (fsext_superblock_ext4_t *) data )->overhead_number_of_clusters,
1179
       value_32bit );
1180
      libcnotify_printf(
1181
       "%s: overhead number of clusters\t\t\t: %" PRIu32 "\n",
1182
       function,
1183
       value_32bit );
1184
1185
      byte_stream_copy_to_uint32_little_endian(
1186
       ( (fsext_superblock_ext4_t *) data )->backup_block_group1,
1187
       value_32bit );
1188
      libcnotify_printf(
1189
       "%s: first backup block group\t\t\t\t: %" PRIu32 "\n",
1190
       function,
1191
       value_32bit );
1192
1193
      byte_stream_copy_to_uint32_little_endian(
1194
       ( (fsext_superblock_ext4_t *) data )->backup_block_group2,
1195
       value_32bit );
1196
      libcnotify_printf(
1197
       "%s: second backup block group\t\t\t: %" PRIu32 "\n",
1198
       function,
1199
       value_32bit );
1200
1201
      byte_stream_copy_to_uint32_little_endian(
1202
       ( (fsext_superblock_ext4_t *) data )->encryption_algorithms,
1203
       value_32bit );
1204
      libcnotify_printf(
1205
       "%s: encryption algorithms\t\t\t\t: %" PRIu32 "\n",
1206
       function,
1207
       value_32bit );
1208
1209
      libcnotify_printf(
1210
       "%s: encryption password salt:\n",
1211
       function );
1212
      libcnotify_print_data(
1213
       ( (fsext_superblock_ext4_t *) data )->encryption_password_salt,
1214
       16,
1215
       0 );
1216
1217
      byte_stream_copy_to_uint32_little_endian(
1218
       ( (fsext_superblock_ext4_t *) data )->lost_and_found_inode_number,
1219
       value_32bit );
1220
      libcnotify_printf(
1221
       "%s: lost and found inode number\t\t\t: %" PRIu32 "\n",
1222
       function,
1223
       value_32bit );
1224
1225
      byte_stream_copy_to_uint32_little_endian(
1226
       ( (fsext_superblock_ext4_t *) data )->project_quota_inode_number,
1227
       value_32bit );
1228
      libcnotify_printf(
1229
       "%s: project quota inode number\t\t\t: %" PRIu32 "\n",
1230
       function,
1231
       value_32bit );
1232
1233
      byte_stream_copy_to_uint32_little_endian(
1234
       ( (fsext_superblock_ext4_t *) data )->checksum_seed,
1235
       value_32bit );
1236
      libcnotify_printf(
1237
       "%s: checksum seed\t\t\t\t\t: 0x%08" PRIx32 "\n",
1238
       function,
1239
       value_32bit );
1240
    }
1241
    libcnotify_printf(
1242
     "%s: padding3:\n",
1243
     function );
1244
1245
    if( superblock->format_version < 4 )
1246
    {
1247
      libcnotify_print_data(
1248
       ( (fsext_superblock_ext2_t *) data )->padding3,
1249
       190,
1250
       0 );
1251
    }
1252
    else
1253
    {
1254
      libcnotify_print_data(
1255
       ( (fsext_superblock_ext4_t *) data )->padding3,
1256
       392,
1257
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1258
    }
1259
    if( superblock->format_version == 4 )
1260
    {
1261
      byte_stream_copy_to_uint32_little_endian(
1262
       ( (fsext_superblock_ext4_t *) data )->checksum,
1263
       value_32bit );
1264
      libcnotify_printf(
1265
       "%s: checksum\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
1266
       function,
1267
       value_32bit );
1268
1269
      libcnotify_printf(
1270
       "\n" );
1271
    }
1272
  }
1273
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1274
1275
1.60k
  if( superblock->number_of_blocks == 0 )
1276
1
  {
1277
1
    libcerror_error_set(
1278
1
     error,
1279
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1280
1
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1281
1
     "%s: invalid number of blocks value out of bounds.",
1282
1
     function );
1283
1284
1
    return( -1 );
1285
1
  }
1286
1.60k
  if( superblock->number_of_blocks_per_block_group == 0 )
1287
1
  {
1288
1
    libcerror_error_set(
1289
1
     error,
1290
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1291
1
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1292
1
     "%s: invalid number of blocks per block group value out of bounds.",
1293
1
     function );
1294
1295
1
    return( -1 );
1296
1
  }
1297
1.60k
  superblock->number_of_block_groups = superblock->number_of_blocks / superblock->number_of_blocks_per_block_group;
1298
1299
1.60k
  if( ( superblock->number_of_blocks % superblock->number_of_blocks_per_block_group ) != 0 )
1300
1.23k
  {
1301
1.23k
    superblock->number_of_block_groups += 1;
1302
1.23k
  }
1303
1.60k
  if( superblock->number_of_blocks_per_block_group > ( (uint64_t) UINT64_MAX / superblock->block_size ) )
1304
0
  {
1305
0
    libcerror_error_set(
1306
0
     error,
1307
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1308
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1309
0
     "%s: invalid number of blocks per flex group value out of bounds.",
1310
0
     function );
1311
1312
0
    return( -1 );
1313
0
  }
1314
1.60k
  superblock->block_group_size = superblock->number_of_blocks_per_block_group * superblock->block_size;
1315
1316
1.60k
  if( number_of_block_groups_per_flex_group > 0 )
1317
431
  {
1318
431
    if( number_of_block_groups_per_flex_group >= 16 )
1319
13
    {
1320
13
      libcerror_error_set(
1321
13
       error,
1322
13
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1323
13
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1324
13
       "%s: invalid number of block groups per flex group value out of bounds.",
1325
13
       function );
1326
1327
13
      return( -1 );
1328
13
    }
1329
418
    superblock->number_of_blocks_per_flex_group = (uint32_t) 1 << number_of_block_groups_per_flex_group;
1330
1331
418
    if( superblock->number_of_blocks_per_flex_group > ( (uint32_t) UINT32_MAX / superblock->number_of_blocks_per_block_group ) )
1332
6
    {
1333
6
      libcerror_error_set(
1334
6
       error,
1335
6
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1336
6
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1337
6
       "%s: invalid number of block groups per flex group value out of bounds.",
1338
6
       function );
1339
1340
6
      return( -1 );
1341
6
    }
1342
412
    superblock->number_of_blocks_per_flex_group *= superblock->number_of_blocks_per_block_group;
1343
1344
412
    if( superblock->number_of_blocks_per_flex_group > ( (uint64_t) UINT64_MAX / superblock->block_size ) )
1345
0
    {
1346
0
      libcerror_error_set(
1347
0
       error,
1348
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1349
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1350
0
       "%s: invalid number of blocks per flex group value out of bounds.",
1351
0
       function );
1352
1353
0
      return( -1 );
1354
0
    }
1355
412
    superblock->flex_group_size = superblock->number_of_blocks_per_flex_group * superblock->block_size;
1356
412
  }
1357
#if defined( HAVE_DEBUG_OUTPUT )
1358
  if( libcnotify_verbose != 0 )
1359
  {
1360
    libcnotify_printf(
1361
     "%s: format version\t\t\t\t\t: %" PRIu32 "\n",
1362
     function,
1363
     superblock->format_version );
1364
1365
    libcnotify_printf(
1366
     "%s: number of blocks per block group\t\t\t: %" PRIu64 "\n",
1367
     function,
1368
     superblock->number_of_blocks_per_block_group );
1369
1370
    libcnotify_printf(
1371
     "%s: block group size\t\t\t\t\t: %" PRIu64 "\n",
1372
     function,
1373
     superblock->block_group_size );
1374
1375
    libcnotify_printf(
1376
     "%s: number of blocks per flex group\t\t\t: %" PRIu64 "\n",
1377
     function,
1378
     superblock->number_of_blocks_per_flex_group );
1379
1380
    libcnotify_printf(
1381
     "%s: flex group size\t\t\t\t\t: %" PRIu64 "\n",
1382
     function,
1383
     superblock->flex_group_size );
1384
1385
    libcnotify_printf(
1386
     "%s: number of block groups\t\t\t\t: %" PRIu32 "\n",
1387
     function,
1388
     superblock->number_of_block_groups );
1389
1390
    libcnotify_printf(
1391
     "\n" );
1392
  }
1393
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1394
1395
1.58k
  return( 1 );
1396
1.60k
}
1397
1398
/* Reads the superblock from a Basic File IO (bfio) handle
1399
 * Returns 1 if successful or -1 on error
1400
 */
1401
int libfsext_superblock_read_file_io_handle(
1402
     libfsext_superblock_t *superblock,
1403
     libbfio_handle_t *file_io_handle,
1404
     off64_t file_offset,
1405
     libcerror_error_t **error )
1406
1.85k
{
1407
1.85k
  uint8_t data[ 1024 ];
1408
1409
1.85k
  static char *function = "libfsext_superblock_read_file_io_handle";
1410
1.85k
  ssize_t read_count    = 0;
1411
1412
#if defined( HAVE_DEBUG_OUTPUT )
1413
  if( libcnotify_verbose != 0 )
1414
  {
1415
    libcnotify_printf(
1416
     "%s: reading superblock at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1417
     function,
1418
     file_offset,
1419
     file_offset );
1420
  }
1421
#endif
1422
1.85k
  read_count = libbfio_handle_read_buffer_at_offset(
1423
1.85k
                file_io_handle,
1424
1.85k
                data,
1425
1.85k
                1024,
1426
1.85k
                file_offset,
1427
1.85k
                error );
1428
1429
1.85k
  if( read_count != (ssize_t) 1024 )
1430
81
  {
1431
81
    libcerror_error_set(
1432
81
     error,
1433
81
     LIBCERROR_ERROR_DOMAIN_IO,
1434
81
     LIBCERROR_IO_ERROR_READ_FAILED,
1435
81
     "%s: unable to read superblock at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1436
81
     function,
1437
81
     file_offset,
1438
81
     file_offset );
1439
1440
81
    return( -1 );
1441
81
  }
1442
1.77k
  if( libfsext_superblock_read_data(
1443
1.77k
       superblock,
1444
1.77k
       data,
1445
1.77k
       1024,
1446
1.77k
       error ) != 1 )
1447
192
  {
1448
192
    libcerror_error_set(
1449
192
     error,
1450
192
     LIBCERROR_ERROR_DOMAIN_IO,
1451
192
     LIBCERROR_IO_ERROR_READ_FAILED,
1452
192
     "%s: unable to read superblock at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1453
192
     function,
1454
192
     file_offset,
1455
192
     file_offset );
1456
1457
192
    return( -1 );
1458
192
  }
1459
1.58k
  return( 1 );
1460
1.77k
}
1461
1462
/* Retrieves the file system identifier
1463
 * The identifier is an UUID stored in big-endian and is 16 bytes of size
1464
 * Returns 1 if successful or -1 on error
1465
 */
1466
int libfsext_superblock_get_file_system_identifier(
1467
     libfsext_superblock_t *superblock,
1468
     uint8_t *uuid_data,
1469
     size_t uuid_data_size,
1470
     libcerror_error_t **error )
1471
148
{
1472
148
  static char *function = "libfsext_superblock_get_file_system_identifier";
1473
1474
148
  if( superblock == NULL )
1475
0
  {
1476
0
    libcerror_error_set(
1477
0
     error,
1478
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1479
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1480
0
     "%s: invalid superblock.",
1481
0
     function );
1482
1483
0
    return( -1 );
1484
0
  }
1485
148
  if( uuid_data == NULL )
1486
0
  {
1487
0
    libcerror_error_set(
1488
0
     error,
1489
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1490
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1491
0
     "%s: invalid UUID data.",
1492
0
     function );
1493
1494
0
    return( -1 );
1495
0
  }
1496
148
  if( ( uuid_data_size < 16 )
1497
148
   || ( uuid_data_size > (size_t) SSIZE_MAX ) )
1498
0
  {
1499
0
    libcerror_error_set(
1500
0
     error,
1501
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1502
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1503
0
     "%s: invalid UUID data size value out of bounds.",
1504
0
     function );
1505
1506
0
    return( -1 );
1507
0
  }
1508
148
  if( memory_copy(
1509
148
       uuid_data,
1510
148
       superblock->file_system_identifier,
1511
148
       16 ) == NULL )
1512
0
  {
1513
0
    libcerror_error_set(
1514
0
     error,
1515
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1516
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
1517
0
     "%s: unable to copy file system identifier.",
1518
0
     function );
1519
1520
0
    return( -1 );
1521
0
  }
1522
148
  return( 1 );
1523
148
}
1524
1525
/* Retrieves the size of the UTF-8 encoded volume label
1526
 * The returned size includes the end of string character
1527
 * Returns 1 if successful, 0 if not available or -1 on error
1528
 */
1529
int libfsext_superblock_get_utf8_volume_label_size(
1530
     libfsext_superblock_t *superblock,
1531
     size_t *utf8_string_size,
1532
     libcerror_error_t **error )
1533
148
{
1534
148
  static char *function = "libfsext_superblock_get_utf8_volume_label_size";
1535
1536
148
  if( superblock == NULL )
1537
0
  {
1538
0
    libcerror_error_set(
1539
0
     error,
1540
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1541
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1542
0
     "%s: invalid superblock.",
1543
0
     function );
1544
1545
0
    return( -1 );
1546
0
  }
1547
148
  if( libuna_utf8_string_size_from_utf8_stream(
1548
148
       superblock->volume_label,
1549
148
       16,
1550
148
       utf8_string_size,
1551
148
       error ) != 1 )
1552
90
  {
1553
90
    libcerror_error_set(
1554
90
     error,
1555
90
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1556
90
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1557
90
     "%s: unable to retrieve UTF-8 string size.",
1558
90
     function );
1559
1560
90
    return( -1 );
1561
90
  }
1562
58
  return( 1 );
1563
148
}
1564
1565
/* Retrieves the UTF-8 encoded volume label
1566
 * The size should include the end of string character
1567
 * Returns 1 if successful, 0 if not available or -1 on error
1568
 */
1569
int libfsext_superblock_get_utf8_volume_label(
1570
     libfsext_superblock_t *superblock,
1571
     uint8_t *utf8_string,
1572
     size_t utf8_string_size,
1573
     libcerror_error_t **error )
1574
148
{
1575
148
  static char *function = "libfsext_superblock_get_utf8_volume_label";
1576
1577
148
  if( superblock == NULL )
1578
0
  {
1579
0
    libcerror_error_set(
1580
0
     error,
1581
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1582
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1583
0
     "%s: invalid superblock.",
1584
0
     function );
1585
1586
0
    return( -1 );
1587
0
  }
1588
148
  if( libuna_utf8_string_copy_from_utf8_stream(
1589
148
       utf8_string,
1590
148
       utf8_string_size,
1591
148
       superblock->volume_label,
1592
148
       16,
1593
148
       error ) != 1 )
1594
90
  {
1595
90
    libcerror_error_set(
1596
90
     error,
1597
90
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1598
90
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1599
90
     "%s: unable to retrieve UTF-8 string.",
1600
90
     function );
1601
1602
90
    return( -1 );
1603
90
  }
1604
58
  return( 1 );
1605
148
}
1606
1607
/* Retrieves the size of the UTF-16 encoded volume label
1608
 * The returned size includes the end of string character
1609
 * Returns 1 if successful, 0 if not available or -1 on error
1610
 */
1611
int libfsext_superblock_get_utf16_volume_label_size(
1612
     libfsext_superblock_t *superblock,
1613
     size_t *utf16_string_size,
1614
     libcerror_error_t **error )
1615
0
{
1616
0
  static char *function = "libfsext_superblock_get_utf16_volume_label_size";
1617
1618
0
  if( superblock == NULL )
1619
0
  {
1620
0
    libcerror_error_set(
1621
0
     error,
1622
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1623
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1624
0
     "%s: invalid superblock.",
1625
0
     function );
1626
1627
0
    return( -1 );
1628
0
  }
1629
0
  if( libuna_utf16_string_size_from_utf8_stream(
1630
0
       superblock->volume_label,
1631
0
       16,
1632
0
       utf16_string_size,
1633
0
       error ) != 1 )
1634
0
  {
1635
0
    libcerror_error_set(
1636
0
     error,
1637
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1638
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1639
0
     "%s: unable to retrieve UTF-16 string size.",
1640
0
     function );
1641
1642
0
    return( -1 );
1643
0
  }
1644
0
  return( 1 );
1645
0
}
1646
1647
/* Retrieves the UTF-16 encoded volume label
1648
 * The size should include the end of string character
1649
 * Returns 1 if successful, 0 if not available or -1 on error
1650
 */
1651
int libfsext_superblock_get_utf16_volume_label(
1652
     libfsext_superblock_t *superblock,
1653
     uint16_t *utf16_string,
1654
     size_t utf16_string_size,
1655
     libcerror_error_t **error )
1656
0
{
1657
0
  static char *function = "libfsext_superblock_get_utf16_volume_label";
1658
1659
0
  if( superblock == NULL )
1660
0
  {
1661
0
    libcerror_error_set(
1662
0
     error,
1663
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1664
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1665
0
     "%s: invalid superblock.",
1666
0
     function );
1667
1668
0
    return( -1 );
1669
0
  }
1670
0
  if( libuna_utf16_string_copy_from_utf8_stream(
1671
0
       utf16_string,
1672
0
       utf16_string_size,
1673
0
       superblock->volume_label,
1674
0
       16,
1675
0
       error ) != 1 )
1676
0
  {
1677
0
    libcerror_error_set(
1678
0
     error,
1679
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1680
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1681
0
     "%s: unable to retrieve UTF-16 string.",
1682
0
     function );
1683
1684
0
    return( -1 );
1685
0
  }
1686
0
  return( 1 );
1687
0
}
1688
1689
/* Retrieves the size of the UTF-8 encoded last mount path
1690
 * The returned size includes the end of string character
1691
 * Returns 1 if successful, 0 if not available or -1 on error
1692
 */
1693
int libfsext_superblock_get_utf8_last_mount_path_size(
1694
     libfsext_superblock_t *superblock,
1695
     size_t *utf8_string_size,
1696
     libcerror_error_t **error )
1697
148
{
1698
148
  static char *function = "libfsext_superblock_get_utf8_last_mount_path_size";
1699
1700
148
  if( superblock == NULL )
1701
0
  {
1702
0
    libcerror_error_set(
1703
0
     error,
1704
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1705
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1706
0
     "%s: invalid superblock.",
1707
0
     function );
1708
1709
0
    return( -1 );
1710
0
  }
1711
148
  if( libuna_utf8_string_size_from_utf8_stream(
1712
148
       superblock->last_mount_path,
1713
148
       64,
1714
148
       utf8_string_size,
1715
148
       error ) != 1 )
1716
97
  {
1717
97
    libcerror_error_set(
1718
97
     error,
1719
97
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1720
97
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1721
97
     "%s: unable to retrieve UTF-8 string size.",
1722
97
     function );
1723
1724
97
    return( -1 );
1725
97
  }
1726
51
  return( 1 );
1727
148
}
1728
1729
/* Retrieves the UTF-8 encoded last mount path
1730
 * The size should include the end of string character
1731
 * Returns 1 if successful, 0 if not available or -1 on error
1732
 */
1733
int libfsext_superblock_get_utf8_last_mount_path(
1734
     libfsext_superblock_t *superblock,
1735
     uint8_t *utf8_string,
1736
     size_t utf8_string_size,
1737
     libcerror_error_t **error )
1738
148
{
1739
148
  static char *function = "libfsext_superblock_get_utf8_last_mount_path";
1740
1741
148
  if( superblock == NULL )
1742
0
  {
1743
0
    libcerror_error_set(
1744
0
     error,
1745
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1746
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1747
0
     "%s: invalid superblock.",
1748
0
     function );
1749
1750
0
    return( -1 );
1751
0
  }
1752
148
  if( libuna_utf8_string_copy_from_utf8_stream(
1753
148
       utf8_string,
1754
148
       utf8_string_size,
1755
148
       superblock->last_mount_path,
1756
148
       64,
1757
148
       error ) != 1 )
1758
102
  {
1759
102
    libcerror_error_set(
1760
102
     error,
1761
102
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1762
102
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1763
102
     "%s: unable to retrieve UTF-8 string.",
1764
102
     function );
1765
1766
102
    return( -1 );
1767
102
  }
1768
46
  return( 1 );
1769
148
}
1770
1771
/* Retrieves the size of the UTF-16 encoded last mount path
1772
 * The returned size includes the end of string character
1773
 * Returns 1 if successful, 0 if not available or -1 on error
1774
 */
1775
int libfsext_superblock_get_utf16_last_mount_path_size(
1776
     libfsext_superblock_t *superblock,
1777
     size_t *utf16_string_size,
1778
     libcerror_error_t **error )
1779
0
{
1780
0
  static char *function = "libfsext_superblock_get_utf16_last_mount_path_size";
1781
1782
0
  if( superblock == NULL )
1783
0
  {
1784
0
    libcerror_error_set(
1785
0
     error,
1786
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1787
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1788
0
     "%s: invalid superblock.",
1789
0
     function );
1790
1791
0
    return( -1 );
1792
0
  }
1793
0
  if( libuna_utf16_string_size_from_utf8_stream(
1794
0
       superblock->last_mount_path,
1795
0
       64,
1796
0
       utf16_string_size,
1797
0
       error ) != 1 )
1798
0
  {
1799
0
    libcerror_error_set(
1800
0
     error,
1801
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1802
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1803
0
     "%s: unable to retrieve UTF-16 string size.",
1804
0
     function );
1805
1806
0
    return( -1 );
1807
0
  }
1808
0
  return( 1 );
1809
0
}
1810
1811
/* Retrieves the UTF-16 encoded last mount path
1812
 * The size should include the end of string character
1813
 * Returns 1 if successful, 0 if not available or -1 on error
1814
 */
1815
int libfsext_superblock_get_utf16_last_mount_path(
1816
     libfsext_superblock_t *superblock,
1817
     uint16_t *utf16_string,
1818
     size_t utf16_string_size,
1819
     libcerror_error_t **error )
1820
0
{
1821
0
  static char *function = "libfsext_superblock_get_utf16_last_mount_path";
1822
1823
0
  if( superblock == NULL )
1824
0
  {
1825
0
    libcerror_error_set(
1826
0
     error,
1827
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1828
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1829
0
     "%s: invalid superblock.",
1830
0
     function );
1831
1832
0
    return( -1 );
1833
0
  }
1834
0
  if( libuna_utf16_string_copy_from_utf8_stream(
1835
0
       utf16_string,
1836
0
       utf16_string_size,
1837
0
       superblock->last_mount_path,
1838
0
       64,
1839
0
       error ) != 1 )
1840
0
  {
1841
0
    libcerror_error_set(
1842
0
     error,
1843
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1844
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1845
0
     "%s: unable to retrieve UTF-16 string.",
1846
0
     function );
1847
1848
0
    return( -1 );
1849
0
  }
1850
0
  return( 1 );
1851
0
}
1852