Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvhdi/libvhdi/libvhdi_file_footer.c
Line
Count
Source
1
/*
2
 * File footer functions
3
 *
4
 * Copyright (C) 2012-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 "libvhdi_debug.h"
28
#include "libvhdi_definitions.h"
29
#include "libvhdi_file_footer.h"
30
#include "libvhdi_libbfio.h"
31
#include "libvhdi_libcerror.h"
32
#include "libvhdi_libcnotify.h"
33
#include "libvhdi_libfguid.h"
34
35
#include "vhdi_file_footer.h"
36
37
/* Creates file footer
38
 * Make sure the value file_footer is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libvhdi_file_footer_initialize(
42
     libvhdi_file_footer_t **file_footer,
43
     libcerror_error_t **error )
44
1.08k
{
45
1.08k
  static char *function = "libvhdi_file_footer_initialize";
46
47
1.08k
  if( file_footer == 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 file footer.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
1.08k
  if( *file_footer != 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 file footer value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
1.08k
  *file_footer = memory_allocate_structure(
70
1.08k
                  libvhdi_file_footer_t );
71
72
1.08k
  if( *file_footer == 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 file footer.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
1.08k
  if( memory_set(
84
1.08k
       *file_footer,
85
1.08k
       0,
86
1.08k
       sizeof( libvhdi_file_footer_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 file footer.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
1.08k
  return( 1 );
98
99
0
on_error:
100
0
  if( *file_footer != NULL )
101
0
  {
102
0
    memory_free(
103
0
     *file_footer );
104
105
0
    *file_footer = NULL;
106
0
  }
107
0
  return( -1 );
108
1.08k
}
109
110
/* Frees file footer
111
 * Returns 1 if successful or -1 on error
112
 */
113
int libvhdi_file_footer_free(
114
     libvhdi_file_footer_t **file_footer,
115
     libcerror_error_t **error )
116
1.08k
{
117
1.08k
  static char *function = "libvhdi_file_footer_free";
118
119
1.08k
  if( file_footer == 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 file footer.",
126
0
     function );
127
128
0
    return( -1 );
129
0
  }
130
1.08k
  if( *file_footer != NULL )
131
1.08k
  {
132
1.08k
    memory_free(
133
1.08k
     *file_footer );
134
135
1.08k
    *file_footer = NULL;
136
1.08k
  }
137
1.08k
  return( 1 );
138
1.08k
}
139
140
/* Reads the file footer data
141
 * Returns 1 if successful or -1 on error
142
 */
143
int libvhdi_file_footer_read_data(
144
     libvhdi_file_footer_t *file_footer,
145
     const uint8_t *data,
146
     size_t data_size,
147
     libcerror_error_t **error )
148
1.08k
{
149
1.08k
  static char *function     = "libvhdi_file_footer_read_data";
150
1.08k
  uint64_t safe_next_offset = 0;
151
152
#if defined( HAVE_DEBUG_OUTPUT )
153
  uint64_t value_64bit      = 0;
154
  uint32_t value_32bit      = 0;
155
#endif
156
157
1.08k
  if( file_footer == NULL )
158
0
  {
159
0
    libcerror_error_set(
160
0
     error,
161
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
162
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
163
0
     "%s: invalid file footer.",
164
0
     function );
165
166
0
    return( -1 );
167
0
  }
168
1.08k
  if( data == NULL )
169
0
  {
170
0
    libcerror_error_set(
171
0
     error,
172
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
173
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
174
0
     "%s: invalid data.",
175
0
     function );
176
177
0
    return( -1 );
178
0
  }
179
1.08k
  if( ( data_size < sizeof( vhdi_file_footer_t ) )
180
1.08k
   || ( data_size > (size_t) SSIZE_MAX ) )
181
0
  {
182
0
    libcerror_error_set(
183
0
     error,
184
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
185
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
186
0
     "%s: invalid data size value out of bounds.",
187
0
     function );
188
189
0
    return( -1 );
190
0
  }
191
#if defined( HAVE_DEBUG_OUTPUT )
192
  if( libcnotify_verbose != 0 )
193
  {
194
    libcnotify_printf(
195
     "%s: file footer data:\n",
196
     function );
197
    libcnotify_print_data(
198
     data,
199
     sizeof( vhdi_file_footer_t ),
200
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
201
  }
202
#endif
203
1.08k
  if( memory_compare(
204
1.08k
       ( (vhdi_file_footer_t *) data )->signature,
205
1.08k
       "conectix",
206
1.08k
       8 ) != 0 )
207
42
  {
208
42
    libcerror_error_set(
209
42
     error,
210
42
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
211
42
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
212
42
     "%s: unsupported signature.",
213
42
     function );
214
215
42
    return( -1 );
216
42
  }
217
1.03k
  byte_stream_copy_to_uint32_big_endian(
218
1.03k
   ( (vhdi_file_footer_t *) data )->format_version,
219
1.03k
   file_footer->format_version );
220
221
1.03k
  byte_stream_copy_to_uint64_big_endian(
222
1.03k
   ( (vhdi_file_footer_t *) data )->next_offset,
223
1.03k
   safe_next_offset );
224
225
1.03k
  byte_stream_copy_to_uint64_big_endian(
226
1.03k
   ( (vhdi_file_footer_t *) data )->disk_size,
227
1.03k
   file_footer->media_size );
228
229
1.03k
  byte_stream_copy_to_uint32_big_endian(
230
1.03k
   ( (vhdi_file_footer_t *) data )->disk_type,
231
1.03k
   file_footer->disk_type );
232
233
1.03k
  byte_stream_copy_to_uint32_big_endian(
234
1.03k
   ( (vhdi_file_footer_t *) data )->checksum,
235
1.03k
   file_footer->checksum );
236
237
1.03k
  if( memory_copy(
238
1.03k
       file_footer->identifier,
239
1.03k
       ( (vhdi_file_footer_t *) data )->identifier,
240
1.03k
       16 ) == NULL )
241
0
  {
242
0
    libcerror_error_set(
243
0
     error,
244
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
245
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
246
0
     "%s: unable to copy identifier.",
247
0
     function );
248
249
0
    return( -1 );
250
0
  }
251
#if defined( HAVE_DEBUG_OUTPUT )
252
  if( libcnotify_verbose != 0 )
253
  {
254
    libcnotify_printf(
255
     "%s: signature\t\t\t\t: %c%c%c%c%c%c%c%c\n",
256
     function,
257
     ( (vhdi_file_footer_t *) data )->signature[ 0 ],
258
     ( (vhdi_file_footer_t *) data )->signature[ 1 ],
259
     ( (vhdi_file_footer_t *) data )->signature[ 2 ],
260
     ( (vhdi_file_footer_t *) data )->signature[ 3 ],
261
     ( (vhdi_file_footer_t *) data )->signature[ 4 ],
262
     ( (vhdi_file_footer_t *) data )->signature[ 5 ],
263
     ( (vhdi_file_footer_t *) data )->signature[ 6 ],
264
     ( (vhdi_file_footer_t *) data )->signature[ 7 ] );
265
266
    byte_stream_copy_to_uint32_big_endian(
267
     ( (vhdi_file_footer_t *) data )->features,
268
     value_32bit );
269
    libcnotify_printf(
270
     "%s: features\t\t\t\t\t: 0x%08" PRIx32 "\n",
271
     function,
272
     value_32bit );
273
    libvhdi_debug_print_feature_flags(
274
     value_32bit );
275
    libcnotify_printf(
276
     "\n" );
277
278
    libcnotify_printf(
279
     "%s: format version\t\t\t\t: %" PRIu16 ".%" PRIu16 "\n",
280
     function,
281
     file_footer->format_version >> 16,
282
     file_footer->format_version & 0x0000ffffUL );
283
284
    libcnotify_printf(
285
     "%s: next offset\t\t\t\t: 0x%08" PRIx64 "\n",
286
     function,
287
     safe_next_offset );
288
289
    byte_stream_copy_to_uint32_big_endian(
290
     ( (vhdi_file_footer_t *) data )->modification_time,
291
     value_32bit );
292
    libcnotify_printf(
293
     "%s: modification time\t\t\t: 0x%08" PRIx32 "\n",
294
     function,
295
     value_32bit );
296
297
    byte_stream_copy_to_uint32_big_endian(
298
     ( (vhdi_file_footer_t *) data )->creator_application,
299
     value_32bit );
300
    libcnotify_printf(
301
     "%s: creators application\t\t\t: 0x%08" PRIx32 "\n",
302
     function,
303
     value_32bit );
304
305
    byte_stream_copy_to_uint32_big_endian(
306
     ( (vhdi_file_footer_t *) data )->creator_version,
307
     value_32bit );
308
    libcnotify_printf(
309
     "%s: creators version\t\t\t\t: %" PRIu16 ".%" PRIu16 "\n",
310
     function,
311
     value_32bit >> 16,
312
     value_32bit & 0x0000ffffUL );
313
314
    byte_stream_copy_to_uint32_big_endian(
315
     ( (vhdi_file_footer_t *) data )->creator_operating_system,
316
     value_32bit );
317
    libcnotify_printf(
318
     "%s: creators operating system\t\t: 0x%08" PRIx32 "\n",
319
     function,
320
     value_32bit );
321
322
    libcnotify_printf(
323
     "%s: disk size\t\t\t\t: %" PRIu64 "\n",
324
     function,
325
     file_footer->media_size );
326
327
    byte_stream_copy_to_uint64_big_endian(
328
     ( (vhdi_file_footer_t *) data )->data_size,
329
     value_64bit );
330
    libcnotify_printf(
331
     "%s: data size\t\t\t\t: %" PRIu64 "\n",
332
     function,
333
     value_64bit );
334
335
    byte_stream_copy_to_uint32_big_endian(
336
     ( (vhdi_file_footer_t *) data )->disk_geometry,
337
     value_32bit );
338
    libcnotify_printf(
339
     "%s: disk geometry\t\t\t\t: 0x%08" PRIx32 "\n",
340
     function,
341
     value_32bit );
342
343
    libcnotify_printf(
344
     "%s: disk type\t\t\t\t: 0x%08" PRIx32 " (%s)\n",
345
     function,
346
     file_footer->disk_type,
347
     libvhdi_debug_print_disk_type(
348
      file_footer->disk_type ) );
349
350
    libcnotify_printf(
351
     "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
352
     function,
353
     file_footer->checksum );
354
355
    if( libvhdi_debug_print_guid_value(
356
         function,
357
         "identifier\t\t\t\t",
358
         ( (vhdi_file_footer_t *) data )->identifier,
359
         16,
360
         LIBFGUID_ENDIAN_BIG,
361
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
362
         error ) != 1 )
363
    {
364
      libcerror_error_set(
365
       error,
366
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
367
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
368
       "%s: unable to print GUID value.",
369
       function );
370
371
      return( -1 );
372
    }
373
    libcnotify_printf(
374
     "%s: saved state\t\t\t\t: 0x%02" PRIx8 "\n",
375
     function,
376
     ( (vhdi_file_footer_t *) data )->saved_state );
377
378
    libcnotify_printf(
379
     "%s: unknown1:\n",
380
     function );
381
    libcnotify_print_data(
382
     ( (vhdi_file_footer_t *) data )->unknown1,
383
     427,
384
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
385
  }
386
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
387
388
1.03k
  if( file_footer->format_version != 0x00010000UL )
389
40
  {
390
40
    libcerror_error_set(
391
40
     error,
392
40
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
393
40
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
394
40
     "%s: unsupported format version: 0x%08" PRIx32 ".",
395
40
     function,
396
40
     file_footer->format_version );
397
398
40
    return( -1 );
399
40
  }
400
999
  if( ( file_footer->disk_type != LIBVHDI_DISK_TYPE_FIXED )
401
798
   && ( file_footer->disk_type != LIBVHDI_DISK_TYPE_DYNAMIC )
402
393
   && ( file_footer->disk_type != LIBVHDI_DISK_TYPE_DIFFERENTIAL ) )
403
49
  {
404
49
    libcerror_error_set(
405
49
     error,
406
49
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
407
49
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
408
49
     "%s: unsupported disk type: 0x%08" PRIx32 ".",
409
49
     function,
410
49
     file_footer->disk_type );
411
412
49
    return( -1 );
413
49
  }
414
950
  if( file_footer->disk_type == LIBVHDI_DISK_TYPE_FIXED )
415
201
  {
416
201
    if( (off64_t) safe_next_offset != -1LL )
417
84
    {
418
84
      libcerror_error_set(
419
84
       error,
420
84
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
421
84
       LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
422
84
       "%s: unsupported next offset.",
423
84
       function );
424
425
84
      return( -1 );
426
84
    }
427
201
  }
428
749
  else
429
749
  {
430
749
    if( (off64_t) safe_next_offset < 512 )
431
63
    {
432
63
      libcerror_error_set(
433
63
       error,
434
63
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
435
63
       LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
436
63
       "%s: unsupported next offset.",
437
63
       function );
438
439
63
      return( -1 );
440
63
    }
441
749
  }
442
803
  file_footer->next_offset = (off64_t) safe_next_offset;
443
444
803
  return( 1 );
445
950
}
446
447
/* Reads the file footer
448
 * Returns 1 if successful or -1 on error
449
 */
450
int libvhdi_file_footer_read_file_io_handle(
451
     libvhdi_file_footer_t *file_footer,
452
     libbfio_handle_t *file_io_handle,
453
     off64_t file_offset,
454
     libcerror_error_t **error )
455
1.08k
{
456
1.08k
  uint8_t file_footer_data[ sizeof( vhdi_file_footer_t ) ];
457
458
1.08k
  static char *function = "libvhdi_file_footer_read_file_io_handle";
459
1.08k
  ssize_t read_count    = 0;
460
461
1.08k
  if( file_footer == NULL )
462
0
  {
463
0
    libcerror_error_set(
464
0
     error,
465
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
466
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
467
0
     "%s: invalid file footer.",
468
0
     function );
469
470
0
    return( -1 );
471
0
  }
472
#if defined( HAVE_DEBUG_OUTPUT )
473
  if( libcnotify_verbose != 0 )
474
  {
475
    libcnotify_printf(
476
     "%s: reading file footer at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
477
     function,
478
     file_offset,
479
     file_offset );
480
  }
481
#endif
482
1.08k
  read_count = libbfio_handle_read_buffer_at_offset(
483
1.08k
                file_io_handle,
484
1.08k
                file_footer_data,
485
1.08k
                sizeof( vhdi_file_footer_t ),
486
1.08k
                file_offset,
487
1.08k
                error );
488
489
1.08k
  if( read_count != (ssize_t) sizeof( vhdi_file_footer_t ) )
490
0
  {
491
0
    libcerror_error_set(
492
0
     error,
493
0
     LIBCERROR_ERROR_DOMAIN_IO,
494
0
     LIBCERROR_IO_ERROR_READ_FAILED,
495
0
     "%s: unable to read file footer data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
496
0
     function,
497
0
     file_offset,
498
0
     file_offset );
499
500
0
    return( -1 );
501
0
  }
502
1.08k
  if( libvhdi_file_footer_read_data(
503
1.08k
       file_footer,
504
1.08k
       file_footer_data,
505
1.08k
       sizeof( vhdi_file_footer_t ),
506
1.08k
       error ) != 1 )
507
278
  {
508
278
    libcerror_error_set(
509
278
     error,
510
278
     LIBCERROR_ERROR_DOMAIN_IO,
511
278
     LIBCERROR_IO_ERROR_READ_FAILED,
512
278
     "%s: unable to read file footer.",
513
278
     function );
514
515
278
    return( -1 );
516
278
  }
517
803
  return( 1 );
518
1.08k
}
519
520
/* Retrieves the format version
521
 * Returns 1 if successful or -1 on error
522
 */
523
int libvhdi_file_footer_get_format_version(
524
     libvhdi_file_footer_t *file_footer,
525
     uint16_t *major_version,
526
     uint16_t *minor_version,
527
     libcerror_error_t **error )
528
557
{
529
557
  static char *function = "libvhdi_file_footer_get_format_version";
530
531
557
  if( file_footer == NULL )
532
0
  {
533
0
    libcerror_error_set(
534
0
     error,
535
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
536
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
537
0
     "%s: invalid file footer.",
538
0
     function );
539
540
0
    return( -1 );
541
0
  }
542
557
  if( major_version == NULL )
543
0
  {
544
0
    libcerror_error_set(
545
0
     error,
546
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
547
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
548
0
     "%s: invalid major version.",
549
0
     function );
550
551
0
    return( -1 );
552
0
  }
553
557
  if( minor_version == NULL )
554
0
  {
555
0
    libcerror_error_set(
556
0
     error,
557
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
558
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
559
0
     "%s: invalid minor version.",
560
0
     function );
561
562
0
    return( -1 );
563
0
  }
564
557
  *major_version = ( file_footer->format_version >> 16 ) & 0x0000ffffUL;
565
557
  *minor_version = file_footer->format_version & 0x0000ffffUL;
566
567
557
  return( 1 );
568
557
}
569
570
/* Retrieves the identifier
571
 * The identifier is a big-endian GUID and is 16 bytes of size
572
 * Returns 1 if successful or -1 on error
573
 */
574
int libvhdi_file_footer_get_identifier(
575
     libvhdi_file_footer_t *file_footer,
576
     uint8_t *guid_data,
577
     size_t guid_data_size,
578
     libcerror_error_t **error )
579
557
{
580
557
  static char *function = "libvhdi_file_footer_get_identifier";
581
582
557
  if( file_footer == NULL )
583
0
  {
584
0
    libcerror_error_set(
585
0
     error,
586
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
587
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
588
0
     "%s: invalid file footer.",
589
0
     function );
590
591
0
    return( -1 );
592
0
  }
593
557
  if( guid_data == NULL )
594
0
  {
595
0
    libcerror_error_set(
596
0
     error,
597
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
598
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
599
0
     "%s: invalid GUID data.",
600
0
     function );
601
602
0
    return( -1 );
603
0
  }
604
557
  if( ( guid_data_size < 16 )
605
557
   || ( guid_data_size > SSIZE_MAX ) )
606
0
  {
607
0
    libcerror_error_set(
608
0
     error,
609
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
610
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
611
0
     "%s: invalid GUID data size value out of bounds.",
612
0
     function );
613
614
0
    return( -1 );
615
0
  }
616
557
  if( memory_copy(
617
557
       guid_data,
618
557
       file_footer->identifier,
619
557
       16 ) == NULL )
620
0
  {
621
0
    libcerror_error_set(
622
0
     error,
623
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
624
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
625
0
     "%s: unable to copy identifier.",
626
0
     function );
627
628
0
    return( -1 );
629
0
  }
630
557
  return( 1 );
631
557
}
632