Coverage Report

Created: 2026-03-05 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsntfs/libfsntfs/libfsntfs_volume_header.c
Line
Count
Source
1
/*
2
 * The NTFS volume header functions
3
 *
4
 * Copyright (C) 2010-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 "libfsntfs_io_handle.h"
28
#include "libfsntfs_libbfio.h"
29
#include "libfsntfs_libcerror.h"
30
#include "libfsntfs_libcnotify.h"
31
#include "libfsntfs_volume_header.h"
32
33
#include "fsntfs_index.h"
34
#include "fsntfs_mft_entry.h"
35
#include "fsntfs_volume_header.h"
36
37
/* Creates a volume header
38
 * Make sure the value volume_header is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libfsntfs_volume_header_initialize(
42
     libfsntfs_volume_header_t **volume_header,
43
     libcerror_error_t **error )
44
9.10k
{
45
9.10k
  static char *function = "libfsntfs_volume_header_initialize";
46
47
9.10k
  if( volume_header == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid volume header.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
9.10k
  if( *volume_header != NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64
0
     "%s: invalid volume header value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
9.10k
  *volume_header = memory_allocate_structure(
70
9.10k
                    libfsntfs_volume_header_t );
71
72
9.10k
  if( *volume_header == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
77
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
78
0
     "%s: unable to create volume header.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
9.10k
  if( memory_set(
84
9.10k
       *volume_header,
85
9.10k
       0,
86
9.10k
       sizeof( libfsntfs_volume_header_t ) ) == NULL )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
91
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
92
0
     "%s: unable to clear volume header.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
9.10k
  return( 1 );
98
99
0
on_error:
100
0
  if( *volume_header != NULL )
101
0
  {
102
0
    memory_free(
103
0
     *volume_header );
104
105
0
    *volume_header = NULL;
106
0
  }
107
0
  return( -1 );
108
9.10k
}
109
110
/* Frees a volume header
111
 * Returns 1 if successful or -1 on error
112
 */
113
int libfsntfs_volume_header_free(
114
     libfsntfs_volume_header_t **volume_header,
115
     libcerror_error_t **error )
116
9.10k
{
117
9.10k
  static char *function = "libfsntfs_volume_header_free";
118
119
9.10k
  if( volume_header == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
124
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
125
0
     "%s: invalid volume header.",
126
0
     function );
127
128
0
    return( -1 );
129
0
  }
130
9.10k
  if( *volume_header != NULL )
131
9.10k
  {
132
9.10k
    memory_free(
133
9.10k
     *volume_header );
134
135
9.10k
    *volume_header = NULL;
136
9.10k
  }
137
9.10k
  return( 1 );
138
9.10k
}
139
140
/* Reads the volume header
141
 * Returns 1 if successful or -1 on error
142
 */
143
int libfsntfs_volume_header_read_data(
144
     libfsntfs_volume_header_t *volume_header,
145
     const uint8_t *data,
146
     size_t data_size,
147
     libcerror_error_t **error )
148
9.07k
{
149
9.07k
  static char *function                    = "libfsntfs_volume_header_read_data";
150
9.07k
  uint64_t mft_cluster_block_number        = 0;
151
9.07k
  uint64_t mirror_mft_cluster_block_number = 0;
152
9.07k
  uint64_t volume_size                     = 0;
153
154
#if defined( HAVE_DEBUG_OUTPUT )
155
  uint32_t value_32bit                     = 0;
156
  uint16_t value_16bit                     = 0;
157
#endif
158
159
9.07k
  if( volume_header == NULL )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
164
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
165
0
     "%s: invalid volume header.",
166
0
     function );
167
168
0
    return( -1 );
169
0
  }
170
9.07k
  if( data == NULL )
171
0
  {
172
0
    libcerror_error_set(
173
0
     error,
174
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
175
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
176
0
     "%s: invalid data.",
177
0
     function );
178
179
0
    return( -1 );
180
0
  }
181
9.07k
  if( ( data_size < sizeof( fsntfs_volume_header_t ) )
182
9.07k
   || ( data_size > (size_t) SSIZE_MAX ) )
183
0
  {
184
0
    libcerror_error_set(
185
0
     error,
186
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
187
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
188
0
     "%s: invalid data size value out of bounds.",
189
0
     function );
190
191
0
    return( -1 );
192
0
  }
193
#if defined( HAVE_DEBUG_OUTPUT )
194
  if( libcnotify_verbose != 0 )
195
  {
196
    libcnotify_printf(
197
     "%s: volume header data:\n",
198
     function );
199
    libcnotify_print_data(
200
     data,
201
     sizeof( fsntfs_volume_header_t ),
202
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
203
  }
204
#endif
205
9.07k
  if( memory_compare(
206
9.07k
       ( (fsntfs_volume_header_t *) data )->file_system_signature,
207
9.07k
       fsntfs_volume_file_system_signature,
208
9.07k
       8 ) != 0 )
209
87
  {
210
87
    libcerror_error_set(
211
87
     error,
212
87
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
213
87
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
214
87
     "%s: invalid volume system signature.",
215
87
     function );
216
217
87
    return( -1 );
218
87
  }
219
8.98k
  byte_stream_copy_to_uint16_little_endian(
220
8.98k
   ( (fsntfs_volume_header_t *) data )->bytes_per_sector,
221
8.98k
   volume_header->bytes_per_sector );
222
223
8.98k
  byte_stream_copy_to_uint64_little_endian(
224
8.98k
   ( (fsntfs_volume_header_t *) data )->total_number_of_sectors,
225
8.98k
   volume_size );
226
227
8.98k
  byte_stream_copy_to_uint64_little_endian(
228
8.98k
   ( (fsntfs_volume_header_t *) data )->mft_cluster_block_number,
229
8.98k
   mft_cluster_block_number );
230
231
8.98k
  byte_stream_copy_to_uint64_little_endian(
232
8.98k
   ( (fsntfs_volume_header_t *) data )->mirror_mft_cluster_block_number,
233
8.98k
   mirror_mft_cluster_block_number );
234
235
8.98k
  byte_stream_copy_to_uint32_little_endian(
236
8.98k
   ( (fsntfs_volume_header_t *) data )->mft_entry_size,
237
8.98k
   volume_header->mft_entry_size );
238
239
8.98k
  byte_stream_copy_to_uint32_little_endian(
240
8.98k
   ( (fsntfs_volume_header_t *) data )->index_entry_size,
241
8.98k
   volume_header->index_entry_size );
242
243
8.98k
  byte_stream_copy_to_uint64_little_endian(
244
8.98k
   ( (fsntfs_volume_header_t *) data )->volume_serial_number,
245
8.98k
   volume_header->volume_serial_number );
246
247
#if defined( HAVE_DEBUG_OUTPUT )
248
  if( libcnotify_verbose != 0 )
249
  {
250
    libcnotify_printf(
251
     "%s: boot entry point\t\t\t: 0x%02x 0x%02x 0x%02x\n",
252
     function,
253
     ( (fsntfs_volume_header_t *) data )->boot_entry_point[ 0 ],
254
     ( (fsntfs_volume_header_t *) data )->boot_entry_point[ 1 ],
255
     ( (fsntfs_volume_header_t *) data )->boot_entry_point[ 2 ] );
256
257
    libcnotify_printf(
258
     "%s: file system signature\t\t: %c%c%c%c%c%c%c%c\n",
259
     function,
260
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 0 ],
261
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 1 ],
262
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 2 ],
263
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 3 ],
264
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 4 ],
265
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 5 ],
266
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 6 ],
267
     ( (fsntfs_volume_header_t *) data )->file_system_signature[ 7 ] );
268
269
    libcnotify_printf(
270
     "%s: bytes per sector\t\t\t: %" PRIu16 "\n",
271
     function,
272
     volume_header->bytes_per_sector );
273
274
    libcnotify_printf(
275
     "%s: sectors per cluster block\t\t: %" PRIu8 "\n",
276
     function,
277
     ( (fsntfs_volume_header_t *) data )->sectors_per_cluster_block );
278
279
    libcnotify_printf(
280
     "%s: unknown1\n",
281
     function );
282
    libcnotify_print_data(
283
     ( (fsntfs_volume_header_t *) data )->unknown1,
284
     7,
285
     0 );
286
287
    libcnotify_printf(
288
     "%s: media descriptor\t\t\t: 0x%02" PRIx8 "\n",
289
     function,
290
     ( (fsntfs_volume_header_t *) data )->media_descriptor );
291
292
    byte_stream_copy_to_uint16_little_endian(
293
     ( (fsntfs_volume_header_t *) data )->unknown2,
294
     value_16bit );
295
    libcnotify_printf(
296
     "%s: unknown2\t\t\t\t: %" PRIu16 "\n",
297
     function,
298
     value_16bit );
299
300
    byte_stream_copy_to_uint16_little_endian(
301
     ( (fsntfs_volume_header_t *) data )->sectors_per_track,
302
     value_16bit );
303
    libcnotify_printf(
304
     "%s: sectors per track\t\t\t: %" PRIu16 "\n",
305
     function,
306
     value_16bit );
307
308
    byte_stream_copy_to_uint16_little_endian(
309
     ( (fsntfs_volume_header_t *) data )->number_of_heads,
310
     value_16bit );
311
    libcnotify_printf(
312
     "%s: number of heads\t\t\t: %" PRIu16 "\n",
313
     function,
314
     value_16bit );
315
316
    byte_stream_copy_to_uint32_little_endian(
317
     ( (fsntfs_volume_header_t *) data )->number_of_hidden_sectors,
318
     value_32bit );
319
    libcnotify_printf(
320
     "%s: number of hidden sectors\t\t: %" PRIu32 "\n",
321
     function,
322
     value_32bit );
323
324
    byte_stream_copy_to_uint32_little_endian(
325
     ( (fsntfs_volume_header_t *) data )->unknown3,
326
     value_32bit );
327
    libcnotify_printf(
328
     "%s: unknown3\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
329
     function,
330
     value_32bit,
331
     value_32bit );
332
333
    byte_stream_copy_to_uint32_little_endian(
334
     ( (fsntfs_volume_header_t *) data )->unknown4,
335
     value_32bit );
336
    libcnotify_printf(
337
     "%s: unknown4\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
338
     function,
339
     value_32bit,
340
     value_32bit );
341
342
    libcnotify_printf(
343
     "%s: total number of sectors\t\t: %" PRIu64 "\n",
344
     function,
345
     volume_size );
346
347
    libcnotify_printf(
348
     "%s: MFT cluster block number\t\t: %" PRIu64 "\n",
349
     function,
350
     mft_cluster_block_number );
351
352
    libcnotify_printf(
353
     "%s: mirror MFT cluster block number\t: %" PRIu64 "\n",
354
     function,
355
     mirror_mft_cluster_block_number );
356
357
    libcnotify_printf(
358
     "%s: MFT entry size\t\t\t: %" PRIu32 "\n",
359
     function,
360
     volume_header->mft_entry_size );
361
362
    libcnotify_printf(
363
     "%s: index entry size\t\t\t: %" PRIu32 "\n",
364
     function,
365
     volume_header->index_entry_size );
366
367
    libcnotify_printf(
368
     "%s: volume serial number\t\t\t: 0x%08" PRIx64 "\n",
369
     function,
370
     volume_header->volume_serial_number );
371
372
    byte_stream_copy_to_uint32_little_endian(
373
     ( (fsntfs_volume_header_t *) data )->checksum,
374
     value_32bit );
375
    libcnotify_printf(
376
     "%s: checksum\t\t\t\t: 0x%08" PRIx32 "\n",
377
     function,
378
     value_32bit );
379
380
    libcnotify_printf(
381
     "%s: bootcode\n",
382
     function );
383
    libcnotify_print_data(
384
     ( (fsntfs_volume_header_t *) data )->bootcode,
385
     426,
386
     0 );
387
388
    byte_stream_copy_to_uint16_little_endian(
389
     ( (fsntfs_volume_header_t *) data )->sector_signature,
390
     value_16bit );
391
    libcnotify_printf(
392
     "%s: sector signature\t\t\t: 0x%04" PRIx16 "\n",
393
     function,
394
     value_16bit );
395
396
    libcnotify_printf(
397
     "\n" );
398
  }
399
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
400
401
8.98k
  if( ( volume_header->bytes_per_sector != 256 )
402
293
   && ( volume_header->bytes_per_sector != 512 )
403
128
   && ( volume_header->bytes_per_sector != 1024 )
404
111
   && ( volume_header->bytes_per_sector != 2048 )
405
98
   && ( volume_header->bytes_per_sector != 4096 ) )
406
75
  {
407
75
    libcerror_error_set(
408
75
     error,
409
75
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
410
75
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
411
75
     "%s: unsupported bytes per sector: %" PRIu16 ".",
412
75
     function,
413
75
     volume_header->bytes_per_sector );
414
415
75
    return( -1 );
416
75
  }
417
8.91k
  volume_header->cluster_block_size = ( (fsntfs_volume_header_t *) data )->sectors_per_cluster_block;
418
419
8.91k
  if( volume_header->cluster_block_size > 128 )
420
79
  {
421
    /* The size is calculated as: 2 ^ ( 256 - value )
422
     */
423
79
    volume_header->cluster_block_size = 256 - volume_header->cluster_block_size;
424
425
79
    if( volume_header->cluster_block_size > 12 )
426
8
    {
427
8
      libcerror_error_set(
428
8
       error,
429
8
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
430
8
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
431
8
       "%s: invalid cluster block size value out of bounds.",
432
8
       function );
433
434
8
      return( -1 );
435
8
    }
436
71
    volume_header->cluster_block_size = 1 << volume_header->cluster_block_size;
437
71
  }
438
8.90k
  volume_header->cluster_block_size *= volume_header->bytes_per_sector;
439
440
8.90k
  if( ( volume_header->cluster_block_size != 256 )
441
336
   && ( volume_header->cluster_block_size != 512 )
442
311
   && ( volume_header->cluster_block_size != 1024 )
443
303
   && ( volume_header->cluster_block_size != 2048 )
444
299
   && ( volume_header->cluster_block_size != 4096 )
445
155
   && ( volume_header->cluster_block_size != 8192 )
446
149
   && ( volume_header->cluster_block_size != 16384 )
447
145
   && ( volume_header->cluster_block_size != 32768 )
448
140
   && ( volume_header->cluster_block_size != 65536 )
449
135
   && ( volume_header->cluster_block_size != 131072 )
450
128
   && ( volume_header->cluster_block_size != 262144 )
451
125
   && ( volume_header->cluster_block_size != 524288 )
452
117
   && ( volume_header->cluster_block_size != 1048576 )
453
88
   && ( volume_header->cluster_block_size != 2097152 ) )
454
82
  {
455
82
    libcerror_error_set(
456
82
     error,
457
82
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
458
82
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
459
82
     "%s: unsupported cluster block size: %" PRIu32 ".",
460
82
     function,
461
82
     volume_header->cluster_block_size );
462
463
82
    return( -1 );
464
82
  }
465
8.82k
  if( ( volume_header->mft_entry_size == 0 )
466
8.81k
   || ( volume_header->mft_entry_size > 255 ) )
467
73
  {
468
73
    libcerror_error_set(
469
73
     error,
470
73
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
471
73
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
472
73
     "%s: unsupported MFT entry size: %" PRIu32 ".",
473
73
     function,
474
73
     volume_header->mft_entry_size );
475
476
73
    return( -1 );
477
73
  }
478
8.74k
  if( volume_header->mft_entry_size < 128 )
479
5.63k
  {
480
5.63k
    if( volume_header->mft_entry_size >= (size32_t) ( ( UINT32_MAX / volume_header->cluster_block_size ) + 1 ) )
481
0
    {
482
0
      libcerror_error_set(
483
0
       error,
484
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
485
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
486
0
       "%s: invalid MFT entry size value out of bounds.",
487
0
       function );
488
489
0
      return( -1 );
490
0
    }
491
5.63k
    volume_header->mft_entry_size *= volume_header->cluster_block_size;
492
5.63k
  }
493
3.11k
  else
494
3.11k
  {
495
    /* The size is calculated as: 2 ^ ( 256 - value )
496
     */
497
3.11k
    volume_header->mft_entry_size = 256 - volume_header->mft_entry_size;
498
499
3.11k
    if( volume_header->mft_entry_size >= 32 )
500
10
    {
501
10
      libcerror_error_set(
502
10
       error,
503
10
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
504
10
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
505
10
       "%s: invalid MFT entry size value out of bounds.",
506
10
       function );
507
508
10
      return( -1 );
509
10
    }
510
3.10k
    volume_header->mft_entry_size = (uint32_t) 1UL << volume_header->mft_entry_size;
511
3.10k
  }
512
8.73k
  if( ( (size_t) volume_header->mft_entry_size < sizeof( fsntfs_mft_entry_header_t ) )
513
8.73k
   || ( volume_header->mft_entry_size >= (uint32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
514
7
  {
515
7
    libcerror_error_set(
516
7
     error,
517
7
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
518
7
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
519
7
     "%s: invalid MFT entry size: %" PRIu32 " value out of bounds.",
520
7
     function,
521
7
     volume_header->mft_entry_size );
522
523
7
    return( -1 );
524
7
  }
525
8.73k
  if( ( volume_header->index_entry_size == 0 )
526
8.72k
   || ( volume_header->index_entry_size > 255 ) )
527
69
  {
528
69
    libcerror_error_set(
529
69
     error,
530
69
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
531
69
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
532
69
     "%s: unsupported index entry size: %" PRIu32 ".",
533
69
     function,
534
69
     volume_header->index_entry_size );
535
536
69
    return( -1 );
537
69
  }
538
8.66k
  if( volume_header->index_entry_size < 128 )
539
7.78k
  {
540
7.78k
    if( volume_header->index_entry_size >= (size32_t) ( ( UINT32_MAX / volume_header->cluster_block_size ) + 1 ) )
541
0
    {
542
0
      libcerror_error_set(
543
0
       error,
544
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
545
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
546
0
       "%s: invalid index entry size value out of bounds.",
547
0
       function );
548
549
0
      return( -1 );
550
0
    }
551
7.78k
    volume_header->index_entry_size *= volume_header->cluster_block_size;
552
7.78k
  }
553
878
  else
554
878
  {
555
    /* The size is calculated as: 2 ^ ( 256 - value )
556
     */
557
878
    volume_header->index_entry_size = 256 - volume_header->index_entry_size;
558
559
878
    if( volume_header->index_entry_size >= 32 )
560
7
    {
561
7
      libcerror_error_set(
562
7
       error,
563
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
564
7
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
565
7
       "%s: invalid index entry size value out of bounds.",
566
7
       function );
567
568
7
      return( -1 );
569
7
    }
570
871
    volume_header->index_entry_size = (uint32_t) 1UL << volume_header->index_entry_size;
571
871
  }
572
8.65k
  if( (size_t) volume_header->index_entry_size < sizeof( fsntfs_index_entry_header_t ) )
573
4
  {
574
4
    libcerror_error_set(
575
4
     error,
576
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
577
4
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
578
4
     "%s: invalid index entry size: %" PRIu32 " value out of bounds.",
579
4
     function,
580
4
     volume_header->index_entry_size );
581
582
4
    return( -1 );
583
4
  }
584
8.65k
  if( volume_size > (size64_t) ( ( UINT64_MAX / volume_header->bytes_per_sector ) + 1 ) )
585
128
  {
586
128
    libcerror_error_set(
587
128
     error,
588
128
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
589
128
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
590
128
     "%s: invalid volume size value out of bounds.",
591
128
     function );
592
593
128
    return( -1 );
594
128
  }
595
8.52k
  volume_size *= volume_header->bytes_per_sector;
596
8.52k
  volume_size += volume_header->bytes_per_sector;
597
598
8.52k
  volume_header->mft_offset = mft_cluster_block_number
599
8.52k
                            * volume_header->cluster_block_size;
600
601
8.52k
  volume_header->mirror_mft_offset = mirror_mft_cluster_block_number
602
8.52k
                                   * volume_header->cluster_block_size;
603
604
#if defined( HAVE_DEBUG_OUTPUT )
605
  if( libcnotify_verbose != 0 )
606
  {
607
    libcnotify_printf(
608
     "%s: calculated cluster block size\t: %" PRIu32 "\n",
609
     function,
610
     volume_header->cluster_block_size );
611
612
    libcnotify_printf(
613
     "%s: calculated MFT entry size\t\t: %" PRIu32 "\n",
614
     function,
615
     volume_header->mft_entry_size );
616
617
    libcnotify_printf(
618
     "%s: calculated index entry size\t\t: %" PRIu32 "\n",
619
     function,
620
     volume_header->index_entry_size );
621
622
    libcnotify_printf(
623
     "%s: calculated volume size\t\t: %" PRIu64 "\n",
624
     function,
625
     volume_size );
626
627
    libcnotify_printf(
628
     "%s: calculated MFT offset\t\t: 0x%08" PRIx64 "\n",
629
     function,
630
     volume_header->mft_offset );
631
632
    libcnotify_printf(
633
     "%s: calculated mirror MFT offset\t\t: 0x%08" PRIx64 "\n",
634
     function,
635
     volume_header->mirror_mft_offset );
636
637
    libcnotify_printf(
638
     "\n" );
639
  }
640
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
641
642
8.52k
  return( 1 );
643
8.65k
}
644
645
/* Reads the volume header
646
 * Returns 1 if successful or -1 on error
647
 */
648
int libfsntfs_volume_header_read_file_io_handle(
649
     libfsntfs_volume_header_t *volume_header,
650
     libbfio_handle_t *file_io_handle,
651
     off64_t file_offset,
652
     libcerror_error_t **error )
653
9.10k
{
654
9.10k
  uint8_t volume_header_data[ sizeof( fsntfs_volume_header_t ) ];
655
656
9.10k
  static char *function = "libfsntfs_volume_header_read_file_io_handle";
657
9.10k
  ssize_t read_count    = 0;
658
659
9.10k
  if( volume_header == NULL )
660
0
  {
661
0
    libcerror_error_set(
662
0
     error,
663
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
664
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
665
0
     "%s: invalid volume header.",
666
0
     function );
667
668
0
    return( -1 );
669
0
  }
670
#if defined( HAVE_DEBUG_OUTPUT )
671
  if( libcnotify_verbose != 0 )
672
  {
673
    libcnotify_printf(
674
     "%s: reading volume header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
675
     function,
676
     file_offset,
677
     file_offset );
678
  }
679
#endif
680
9.10k
  read_count = libbfio_handle_read_buffer_at_offset(
681
9.10k
                file_io_handle,
682
9.10k
                volume_header_data,
683
9.10k
                sizeof( fsntfs_volume_header_t ),
684
9.10k
                file_offset,
685
9.10k
                error );
686
687
9.10k
  if( read_count != (ssize_t) sizeof( fsntfs_volume_header_t ) )
688
32
  {
689
32
    libcerror_error_set(
690
32
     error,
691
32
     LIBCERROR_ERROR_DOMAIN_IO,
692
32
     LIBCERROR_IO_ERROR_READ_FAILED,
693
32
     "%s: unable to read volume header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
694
32
     function,
695
32
     file_offset,
696
32
     file_offset );
697
698
32
    return( -1 );
699
32
  }
700
9.07k
  if( libfsntfs_volume_header_read_data(
701
9.07k
       volume_header,
702
9.07k
       volume_header_data,
703
9.07k
       sizeof( fsntfs_volume_header_t ),
704
9.07k
       error ) != 1 )
705
550
  {
706
550
    libcerror_error_set(
707
550
     error,
708
550
     LIBCERROR_ERROR_DOMAIN_IO,
709
550
     LIBCERROR_IO_ERROR_READ_FAILED,
710
550
     "%s: unable to read volume header data.",
711
550
     function );
712
713
550
    return( -1 );
714
550
  }
715
8.52k
  return( 1 );
716
9.07k
}
717
718
/* Retrieves the bytes per sector
719
 * Returns 1 if successful or -1 on error
720
 */
721
int libfsntfs_volume_header_get_bytes_per_sector(
722
     libfsntfs_volume_header_t *volume_header,
723
     uint16_t *bytes_per_sector,
724
     libcerror_error_t **error )
725
8.52k
{
726
8.52k
  static char *function = "libfsntfs_volume_header_get_bytes_per_sector";
727
728
8.52k
  if( volume_header == NULL )
729
0
  {
730
0
    libcerror_error_set(
731
0
     error,
732
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
733
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
734
0
     "%s: invalid volume header.",
735
0
     function );
736
737
0
    return( -1 );
738
0
  }
739
8.52k
  if( bytes_per_sector == NULL )
740
0
  {
741
0
    libcerror_error_set(
742
0
     error,
743
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
744
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
745
0
     "%s: invalid bytes per sector.",
746
0
     function );
747
748
0
    return( -1 );
749
0
  }
750
8.52k
  *bytes_per_sector = volume_header->bytes_per_sector;
751
752
8.52k
  return( 1 );
753
8.52k
}
754
755
/* Retrieves the cluster block size
756
 * Returns 1 if successful or -1 on error
757
 */
758
int libfsntfs_volume_header_get_cluster_block_size(
759
     libfsntfs_volume_header_t *volume_header,
760
     size32_t *cluster_block_size,
761
     libcerror_error_t **error )
762
8.52k
{
763
8.52k
  static char *function = "libfsntfs_volume_header_get_cluster_block_size";
764
765
8.52k
  if( volume_header == NULL )
766
0
  {
767
0
    libcerror_error_set(
768
0
     error,
769
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
770
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
771
0
     "%s: invalid volume header.",
772
0
     function );
773
774
0
    return( -1 );
775
0
  }
776
8.52k
  if( cluster_block_size == NULL )
777
0
  {
778
0
    libcerror_error_set(
779
0
     error,
780
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
781
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
782
0
     "%s: invalid cluster block size.",
783
0
     function );
784
785
0
    return( -1 );
786
0
  }
787
8.52k
  *cluster_block_size = volume_header->cluster_block_size;
788
789
8.52k
  return( 1 );
790
8.52k
}
791
792
/* Retrieves the MFT entry size
793
 * Returns 1 if successful or -1 on error
794
 */
795
int libfsntfs_volume_header_get_mft_entry_size(
796
     libfsntfs_volume_header_t *volume_header,
797
     size32_t *mft_entry_size,
798
     libcerror_error_t **error )
799
8.52k
{
800
8.52k
  static char *function = "libfsntfs_volume_header_get_mft_entry_size";
801
802
8.52k
  if( volume_header == NULL )
803
0
  {
804
0
    libcerror_error_set(
805
0
     error,
806
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
807
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
808
0
     "%s: invalid volume header.",
809
0
     function );
810
811
0
    return( -1 );
812
0
  }
813
8.52k
  if( mft_entry_size == NULL )
814
0
  {
815
0
    libcerror_error_set(
816
0
     error,
817
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
818
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
819
0
     "%s: invalid MFT entry size.",
820
0
     function );
821
822
0
    return( -1 );
823
0
  }
824
8.52k
  *mft_entry_size = volume_header->mft_entry_size;
825
826
8.52k
  return( 1 );
827
8.52k
}
828
829
/* Retrieves the index entry size
830
 * Returns 1 if successful or -1 on error
831
 */
832
int libfsntfs_volume_header_get_index_entry_size(
833
     libfsntfs_volume_header_t *volume_header,
834
     size32_t *index_entry_size,
835
     libcerror_error_t **error )
836
8.52k
{
837
8.52k
  static char *function = "libfsntfs_volume_header_get_index_entry_size";
838
839
8.52k
  if( volume_header == NULL )
840
0
  {
841
0
    libcerror_error_set(
842
0
     error,
843
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
844
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
845
0
     "%s: invalid volume header.",
846
0
     function );
847
848
0
    return( -1 );
849
0
  }
850
8.52k
  if( index_entry_size == NULL )
851
0
  {
852
0
    libcerror_error_set(
853
0
     error,
854
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
855
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
856
0
     "%s: invalid index entry size.",
857
0
     function );
858
859
0
    return( -1 );
860
0
  }
861
8.52k
  *index_entry_size = volume_header->index_entry_size;
862
863
8.52k
  return( 1 );
864
8.52k
}
865
866
/* Retrieves the volume serial number
867
 * Returns 1 if successful or -1 on error
868
 */
869
int libfsntfs_volume_header_get_volume_serial_number(
870
     libfsntfs_volume_header_t *volume_header,
871
     uint64_t *volume_serial_number,
872
     libcerror_error_t **error )
873
0
{
874
0
  static char *function = "libfsntfs_volume_header_get_volume_serial_number";
875
876
0
  if( volume_header == NULL )
877
0
  {
878
0
    libcerror_error_set(
879
0
     error,
880
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
881
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
882
0
     "%s: invalid volume header.",
883
0
     function );
884
885
0
    return( -1 );
886
0
  }
887
0
  if( volume_serial_number == NULL )
888
0
  {
889
0
    libcerror_error_set(
890
0
     error,
891
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
892
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
893
0
     "%s: invalid volume serial number.",
894
0
     function );
895
896
0
    return( -1 );
897
0
  }
898
0
  *volume_serial_number = volume_header->volume_serial_number;
899
900
0
  return( 1 );
901
0
}
902
903
/* Retrieves the MFT offset
904
 * Returns 1 if successful or -1 on error
905
 */
906
int libfsntfs_volume_header_get_mft_offset(
907
     libfsntfs_volume_header_t *volume_header,
908
     off64_t *mft_offset,
909
     libcerror_error_t **error )
910
8.52k
{
911
8.52k
  static char *function = "libfsntfs_volume_header_get_mft_offset";
912
913
8.52k
  if( volume_header == NULL )
914
0
  {
915
0
    libcerror_error_set(
916
0
     error,
917
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
918
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
919
0
     "%s: invalid volume header.",
920
0
     function );
921
922
0
    return( -1 );
923
0
  }
924
8.52k
  if( mft_offset == NULL )
925
0
  {
926
0
    libcerror_error_set(
927
0
     error,
928
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
929
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
930
0
     "%s: invalid MFT offset.",
931
0
     function );
932
933
0
    return( -1 );
934
0
  }
935
8.52k
  *mft_offset = volume_header->mft_offset;
936
937
8.52k
  return( 1 );
938
8.52k
}
939