Coverage Report

Created: 2025-06-22 07:35

/src/libvhdi/libvhdi/libvhdi_image_header.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Image header functions
3
 *
4
 * Copyright (C) 2012-2024, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libvhdi_debug.h"
28
#include "libvhdi_definitions.h"
29
#include "libvhdi_image_header.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_image_header.h"
36
37
/* Creates image header
38
 * Make sure the value image_header is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libvhdi_image_header_initialize(
42
     libvhdi_image_header_t **image_header,
43
     libcerror_error_t **error )
44
1.69k
{
45
1.69k
  static char *function = "libvhdi_image_header_initialize";
46
47
1.69k
  if( image_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 image header.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
1.69k
  if( *image_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 image header value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
1.69k
  *image_header = memory_allocate_structure(
70
1.69k
                   libvhdi_image_header_t );
71
72
1.69k
  if( *image_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 image header.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
1.69k
  if( memory_set(
84
1.69k
       *image_header,
85
1.69k
       0,
86
1.69k
       sizeof( libvhdi_image_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 image header.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
1.69k
  return( 1 );
98
99
0
on_error:
100
0
  if( *image_header != NULL )
101
0
  {
102
0
    memory_free(
103
0
     *image_header );
104
105
0
    *image_header = NULL;
106
0
  }
107
0
  return( -1 );
108
1.69k
}
109
110
/* Frees image header
111
 * Returns 1 if successful or -1 on error
112
 */
113
int libvhdi_image_header_free(
114
     libvhdi_image_header_t **image_header,
115
     libcerror_error_t **error )
116
1.69k
{
117
1.69k
  static char *function = "libvhdi_image_header_free";
118
119
1.69k
  if( image_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 image header.",
126
0
     function );
127
128
0
    return( -1 );
129
0
  }
130
1.69k
  if( *image_header != NULL )
131
1.69k
  {
132
1.69k
    memory_free(
133
1.69k
     *image_header );
134
135
1.69k
    *image_header = NULL;
136
1.69k
  }
137
1.69k
  return( 1 );
138
1.69k
}
139
140
/* Reads the image header data
141
 * Returns 1 if successful or -1 on error
142
 */
143
int libvhdi_image_header_read_data(
144
     libvhdi_image_header_t *image_header,
145
     const uint8_t *data,
146
     size_t data_size,
147
     libcerror_error_t **error )
148
1.66k
{
149
1.66k
  static char *function = "libvhdi_image_header_read_data";
150
151
#if defined( HAVE_DEBUG_OUTPUT )
152
  uint64_t value_64bit  = 0;
153
  uint32_t value_32bit  = 0;
154
  uint16_t value_16bit  = 0;
155
#endif
156
157
1.66k
  if( image_header == 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 image header.",
164
0
     function );
165
166
0
    return( -1 );
167
0
  }
168
1.66k
  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.66k
  if( ( data_size < sizeof( vhdi_image_header_t ) )
180
1.66k
   || ( 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: image header data:\n",
196
     function );
197
    libcnotify_print_data(
198
     data,
199
     sizeof( vhdi_image_header_t ),
200
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
201
  }
202
#endif
203
1.66k
  if( memory_compare(
204
1.66k
       ( (vhdi_image_header_t *) data )->signature,
205
1.66k
       "head",
206
1.66k
       4 ) != 0 )
207
4
  {
208
4
    libcerror_error_set(
209
4
     error,
210
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
211
4
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
212
4
     "%s: unsupported signature.",
213
4
     function );
214
215
4
    return( -1 );
216
4
  }
217
1.66k
  byte_stream_copy_to_uint32_little_endian(
218
1.66k
   ( (vhdi_image_header_t *) data )->checksum,
219
1.66k
   image_header->checksum );
220
221
1.66k
  byte_stream_copy_to_uint64_little_endian(
222
1.66k
   ( (vhdi_image_header_t *) data )->sequence_number,
223
1.66k
   image_header->sequence_number );
224
225
1.66k
  byte_stream_copy_to_uint16_little_endian(
226
1.66k
   ( (vhdi_image_header_t *) data )->format_version,
227
1.66k
   image_header->format_version );
228
229
1.66k
  if( memory_copy(
230
1.66k
       image_header->data_write_identifier,
231
1.66k
       ( (vhdi_image_header_t *) data )->data_write_identifier,
232
1.66k
       16 ) == NULL )
233
0
  {
234
0
    libcerror_error_set(
235
0
     error,
236
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
237
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
238
0
     "%s: unable to copy data write identifier.",
239
0
     function );
240
241
0
    return( -1 );
242
0
  }
243
1.66k
  image_header->data_write_identifier[ 0 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 3 ];
244
1.66k
  image_header->data_write_identifier[ 1 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 2 ];
245
1.66k
  image_header->data_write_identifier[ 2 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 1 ];
246
1.66k
  image_header->data_write_identifier[ 3 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 0 ];
247
248
1.66k
  image_header->data_write_identifier[ 4 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 5 ];
249
1.66k
  image_header->data_write_identifier[ 5 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 4 ];
250
251
1.66k
  image_header->data_write_identifier[ 6 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 7 ];
252
1.66k
  image_header->data_write_identifier[ 7 ] = ( (vhdi_image_header_t *) data )->data_write_identifier[ 6 ];
253
254
1.66k
  if( memory_copy(
255
1.66k
       &( image_header->data_write_identifier[ 8 ] ),
256
1.66k
       &( ( (vhdi_image_header_t *) data )->data_write_identifier[ 8 ] ),
257
1.66k
       8 ) == NULL )
258
0
  {
259
0
    libcerror_error_set(
260
0
     error,
261
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
262
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
263
0
     "%s: unable to copy data write identifier.",
264
0
     function );
265
266
0
    return( -1 );
267
0
  }
268
#if defined( HAVE_DEBUG_OUTPUT )
269
  if( libcnotify_verbose != 0 )
270
  {
271
    libcnotify_printf(
272
     "%s: signature\t\t\t\t: %c%c%c%c\n",
273
     function,
274
     ( (vhdi_image_header_t *) data )->signature[ 0 ],
275
     ( (vhdi_image_header_t *) data )->signature[ 1 ],
276
     ( (vhdi_image_header_t *) data )->signature[ 2 ],
277
     ( (vhdi_image_header_t *) data )->signature[ 3 ] );
278
279
    libcnotify_printf(
280
     "%s: checksum\t\t\t\t: 0x%08" PRIx32 "\n",
281
     function,
282
     image_header->checksum );
283
284
    libcnotify_printf(
285
     "%s: sequence number\t\t\t\t: %" PRIu64 "\n",
286
     function,
287
     image_header->sequence_number );
288
289
    if( libvhdi_debug_print_guid_value(
290
         function,
291
         "file write identifier\t\t\t",
292
         ( (vhdi_image_header_t *) data )->file_write_identifier,
293
         16,
294
         LIBFGUID_ENDIAN_LITTLE,
295
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
296
         error ) != 1 )
297
    {
298
      libcerror_error_set(
299
       error,
300
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
301
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
302
       "%s: unable to print GUID value.",
303
       function );
304
305
      return( -1 );
306
    }
307
    if( libvhdi_debug_print_guid_value(
308
         function,
309
         "data write identifier\t\t\t",
310
         ( (vhdi_image_header_t *) data )->data_write_identifier,
311
         16,
312
         LIBFGUID_ENDIAN_LITTLE,
313
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
314
         error ) != 1 )
315
    {
316
      libcerror_error_set(
317
       error,
318
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
319
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
320
       "%s: unable to print GUID value.",
321
       function );
322
323
      return( -1 );
324
    }
325
326
    if( libvhdi_debug_print_guid_value(
327
         function,
328
         "log identifier\t\t\t\t",
329
         ( (vhdi_image_header_t *) data )->log_identifier,
330
         16,
331
         LIBFGUID_ENDIAN_LITTLE,
332
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
333
         error ) != 1 )
334
    {
335
      libcerror_error_set(
336
       error,
337
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
338
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
339
       "%s: unable to print GUID value.",
340
       function );
341
342
      return( -1 );
343
    }
344
    byte_stream_copy_to_uint16_little_endian(
345
     ( (vhdi_image_header_t *) data )->log_format_version,
346
     value_16bit );
347
    libcnotify_printf(
348
     "%s: log format version\t\t\t: %" PRIu16 "\n",
349
     function,
350
     value_16bit );
351
352
    libcnotify_printf(
353
     "%s: format version\t\t\t\t: %" PRIu16 "\n",
354
     function,
355
     image_header->format_version );
356
357
    byte_stream_copy_to_uint32_little_endian(
358
     ( (vhdi_image_header_t *) data )->log_size,
359
     value_32bit );
360
    libcnotify_printf(
361
     "%s: log size\t\t\t\t: %" PRIu32 "\n",
362
     function,
363
     value_32bit );
364
365
    byte_stream_copy_to_uint64_little_endian(
366
     ( (vhdi_image_header_t *) data )->log_offset,
367
     value_64bit );
368
    libcnotify_printf(
369
     "%s: log offset\t\t\t\t: %" PRIu64 "\n",
370
     function,
371
     value_64bit );
372
373
    libcnotify_printf(
374
     "%s: unknown1:\n",
375
     function );
376
    libcnotify_print_data(
377
     ( (vhdi_image_header_t *) data )->unknown1,
378
     4016,
379
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
380
  }
381
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
382
383
1.66k
  if( image_header->format_version != 0x0001 )
384
1
  {
385
1
    libcerror_error_set(
386
1
     error,
387
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
388
1
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
389
1
     "%s: unsupported format version: 0x%04" PRIx16 ".",
390
1
     function,
391
1
     image_header->format_version );
392
393
1
    return( -1 );
394
1
  }
395
1.66k
  return( 1 );
396
1.66k
}
397
398
/* Reads the image header
399
 * Returns 1 if successful or -1 on error
400
 */
401
int libvhdi_image_header_read_file_io_handle(
402
     libvhdi_image_header_t *image_header,
403
     libbfio_handle_t *file_io_handle,
404
     off64_t file_offset,
405
     libcerror_error_t **error )
406
1.69k
{
407
1.69k
  uint8_t image_header_data[ sizeof( vhdi_image_header_t ) ];
408
409
1.69k
  static char *function = "libvhdi_image_header_read_file_io_handle";
410
1.69k
  ssize_t read_count    = 0;
411
412
1.69k
  if( image_header == NULL )
413
0
  {
414
0
    libcerror_error_set(
415
0
     error,
416
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
417
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
418
0
     "%s: invalid image header.",
419
0
     function );
420
421
0
    return( -1 );
422
0
  }
423
#if defined( HAVE_DEBUG_OUTPUT )
424
  if( libcnotify_verbose != 0 )
425
  {
426
    libcnotify_printf(
427
     "%s: reading image header at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
428
     function,
429
     file_offset,
430
     file_offset );
431
  }
432
#endif
433
1.69k
  read_count = libbfio_handle_read_buffer_at_offset(
434
1.69k
                file_io_handle,
435
1.69k
                image_header_data,
436
1.69k
                sizeof( vhdi_image_header_t ),
437
1.69k
                file_offset,
438
1.69k
                error );
439
440
1.69k
  if( read_count != (ssize_t) sizeof( vhdi_image_header_t ) )
441
28
  {
442
28
    libcerror_error_set(
443
28
     error,
444
28
     LIBCERROR_ERROR_DOMAIN_IO,
445
28
     LIBCERROR_IO_ERROR_READ_FAILED,
446
28
     "%s: unable to read image header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
447
28
     function,
448
28
     file_offset,
449
28
     file_offset );
450
451
28
    return( -1 );
452
28
  }
453
1.66k
  if( libvhdi_image_header_read_data(
454
1.66k
       image_header,
455
1.66k
       image_header_data,
456
1.66k
       sizeof( vhdi_image_header_t ),
457
1.66k
       error ) != 1 )
458
5
  {
459
5
    libcerror_error_set(
460
5
     error,
461
5
     LIBCERROR_ERROR_DOMAIN_IO,
462
5
     LIBCERROR_IO_ERROR_READ_FAILED,
463
5
     "%s: unable to read image header.",
464
5
     function );
465
466
5
    return( -1 );
467
5
  }
468
1.66k
  return( 1 );
469
1.66k
}
470
471
/* Retrieves the format version
472
 * Returns 1 if successful or -1 on error
473
 */
474
int libvhdi_image_header_get_format_version(
475
     libvhdi_image_header_t *image_header,
476
     uint16_t *major_version,
477
     libcerror_error_t **error )
478
0
{
479
0
  static char *function = "libvhdi_image_header_get_format_version";
480
481
0
  if( image_header == NULL )
482
0
  {
483
0
    libcerror_error_set(
484
0
     error,
485
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
486
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
487
0
     "%s: invalid file footer.",
488
0
     function );
489
490
0
    return( -1 );
491
0
  }
492
0
  if( major_version == NULL )
493
0
  {
494
0
    libcerror_error_set(
495
0
     error,
496
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
497
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
498
0
     "%s: invalid major version.",
499
0
     function );
500
501
0
    return( -1 );
502
0
  }
503
0
  *major_version = image_header->format_version;
504
505
0
  return( 1 );
506
0
}
507
508
/* Retrieves the data write identifier
509
 * The identifier is a big-endian GUID and is 16 bytes of size
510
 * Returns 1 if successful or -1 on error
511
 */
512
int libvhdi_image_header_get_data_write_identifier(
513
     libvhdi_image_header_t *image_header,
514
     uint8_t *guid_data,
515
     size_t guid_data_size,
516
     libcerror_error_t **error )
517
0
{
518
0
  static char *function = "libvhdi_image_header_get_data_write_identifier";
519
520
0
  if( image_header == NULL )
521
0
  {
522
0
    libcerror_error_set(
523
0
     error,
524
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
525
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
526
0
     "%s: invalid metadata values.",
527
0
     function );
528
529
0
    return( -1 );
530
0
  }
531
0
  if( guid_data == 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 GUID data.",
538
0
     function );
539
540
0
    return( -1 );
541
0
  }
542
0
  if( ( guid_data_size < 16 )
543
0
   || ( guid_data_size > SSIZE_MAX ) )
544
0
  {
545
0
    libcerror_error_set(
546
0
     error,
547
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
548
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
549
0
     "%s: invalid GUID data size value out of bounds.",
550
0
     function );
551
552
0
    return( -1 );
553
0
  }
554
0
  if( memory_copy(
555
0
       guid_data,
556
0
       image_header->data_write_identifier,
557
0
       16 ) == NULL )
558
0
  {
559
0
    libcerror_error_set(
560
0
     error,
561
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
562
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
563
0
     "%s: unable to copy data write identifier.",
564
0
     function );
565
566
0
    return( -1 );
567
0
  }
568
0
  return( 1 );
569
0
}
570