Coverage Report

Created: 2026-04-04 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmodi/libmodi/libmodi_sparse_image_header.c
Line
Count
Source
1
/*
2
 * Sparse image header functions
3
 *
4
 * Copyright (C) 2012-2025, 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 "libmodi_io_handle.h"
28
#include "libmodi_libbfio.h"
29
#include "libmodi_libcerror.h"
30
#include "libmodi_libcnotify.h"
31
#include "libmodi_sparse_image_header.h"
32
33
#include "modi_sparse_image_header.h"
34
35
/* Creates a sparse image header
36
 * Make sure the value sparse_image_header is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libmodi_sparse_image_header_initialize(
40
     libmodi_sparse_image_header_t **sparse_image_header,
41
     libcerror_error_t **error )
42
310
{
43
310
  static char *function = "libmodi_sparse_image_header_initialize";
44
45
310
  if( sparse_image_header == NULL )
46
0
  {
47
0
    libcerror_error_set(
48
0
     error,
49
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
50
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
51
0
     "%s: invalid sparse image header.",
52
0
     function );
53
54
0
    return( -1 );
55
0
  }
56
310
  if( *sparse_image_header != NULL )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
61
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
62
0
     "%s: invalid sparse image header value already set.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
310
  *sparse_image_header = memory_allocate_structure(
68
310
                          libmodi_sparse_image_header_t );
69
70
310
  if( *sparse_image_header == NULL )
71
0
  {
72
0
    libcerror_error_set(
73
0
     error,
74
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
75
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
76
0
     "%s: unable to create sparse image header.",
77
0
     function );
78
79
0
    goto on_error;
80
0
  }
81
310
  if( memory_set(
82
310
       *sparse_image_header,
83
310
       0,
84
310
       sizeof( libmodi_sparse_image_header_t ) ) == NULL )
85
0
  {
86
0
    libcerror_error_set(
87
0
     error,
88
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
89
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
90
0
     "%s: unable to clear sparse image header.",
91
0
     function );
92
93
0
    goto on_error;
94
0
  }
95
310
  return( 1 );
96
97
0
on_error:
98
0
  if( *sparse_image_header != NULL )
99
0
  {
100
0
    memory_free(
101
0
     *sparse_image_header );
102
103
0
    *sparse_image_header = NULL;
104
0
  }
105
0
  return( -1 );
106
310
}
107
108
/* Frees a sparse image header
109
 * Returns 1 if successful or -1 on error
110
 */
111
int libmodi_sparse_image_header_free(
112
     libmodi_sparse_image_header_t **sparse_image_header,
113
     libcerror_error_t **error )
114
310
{
115
310
  static char *function = "libmodi_sparse_image_header_free";
116
117
310
  if( sparse_image_header == NULL )
118
0
  {
119
0
    libcerror_error_set(
120
0
     error,
121
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
122
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
123
0
     "%s: invalid sparse image header.",
124
0
     function );
125
126
0
    return( -1 );
127
0
  }
128
310
  if( *sparse_image_header != NULL )
129
310
  {
130
310
    if( ( *sparse_image_header )->band_references != NULL )
131
28
    {
132
28
      memory_free(
133
28
       ( *sparse_image_header )->band_references );
134
28
    }
135
310
    memory_free(
136
310
     *sparse_image_header );
137
138
310
    *sparse_image_header = NULL;
139
310
  }
140
310
  return( 1 );
141
310
}
142
143
/* Reads a sparse image header
144
 * Returns 1 if successful, 0 if the signature does not match or -1 on error
145
 */
146
int libmodi_sparse_image_header_read_data(
147
     libmodi_sparse_image_header_t *sparse_image_header,
148
     const uint8_t *data,
149
     size_t data_size,
150
     libcerror_error_t **error )
151
310
{
152
310
  static char *function          = "libmodi_sparse_image_header_read_data";
153
310
  size_t bands_table_data_size   = 0;
154
310
  size_t data_offset             = 0;
155
310
  uint32_t bands_table_index     = 0;
156
310
  uint32_t bands_table_reference = 0;
157
158
#if defined( HAVE_DEBUG_OUTPUT )
159
  uint32_t value_32bit           = 0;
160
#endif
161
162
310
  if( sparse_image_header == NULL )
163
0
  {
164
0
    libcerror_error_set(
165
0
     error,
166
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
167
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
168
0
     "%s: invalid sparse image header.",
169
0
     function );
170
171
0
    return( -1 );
172
0
  }
173
310
  if( sparse_image_header->band_references != NULL )
174
0
  {
175
0
    libcerror_error_set(
176
0
     error,
177
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
178
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
179
0
     "%s: invalid sparse image header - band references value already set.",
180
0
     function );
181
182
0
    return( -1 );
183
0
  }
184
310
  if( data == NULL )
185
0
  {
186
0
    libcerror_error_set(
187
0
     error,
188
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
189
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
190
0
     "%s: invalid data.",
191
0
     function );
192
193
0
    return( -1 );
194
0
  }
195
310
  if( ( data_size < sizeof( modi_sparse_image_header_t ) )
196
310
   || ( data_size > (size_t) SSIZE_MAX ) )
197
0
  {
198
0
    libcerror_error_set(
199
0
     error,
200
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
201
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
202
0
     "%s: invalid data size value out of bounds.",
203
0
     function );
204
205
0
    return( -1 );
206
0
  }
207
#if defined( HAVE_DEBUG_OUTPUT )
208
  if( libcnotify_verbose != 0 )
209
  {
210
    libcnotify_printf(
211
     "%s: sparse image header data:\n",
212
     function );
213
    libcnotify_print_data(
214
     data,
215
     sizeof( modi_sparse_image_header_t ),
216
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
217
  }
218
#endif
219
310
  if( memory_compare(
220
310
       ( (modi_sparse_image_header_t *) data )->signature,
221
310
       modi_sparse_image_signature,
222
310
       4 ) != 0 )
223
144
  {
224
144
    return( 0 );
225
144
  }
226
166
  byte_stream_copy_to_uint32_big_endian(
227
166
   ( (modi_sparse_image_header_t *) data )->sectors_per_band,
228
166
   sparse_image_header->sectors_per_band );
229
230
166
  byte_stream_copy_to_uint32_big_endian(
231
166
   ( (modi_sparse_image_header_t *) data )->number_of_sectors,
232
166
   sparse_image_header->number_of_sectors );
233
234
#if defined( HAVE_DEBUG_OUTPUT )
235
  if( libcnotify_verbose != 0 )
236
  {
237
    libcnotify_printf(
238
     "%s: signature\t\t\t: %c%c%c%c\n",
239
     function,
240
     ( (modi_sparse_image_header_t *) data )->signature[ 0 ],
241
     ( (modi_sparse_image_header_t *) data )->signature[ 1 ],
242
     ( (modi_sparse_image_header_t *) data )->signature[ 2 ],
243
     ( (modi_sparse_image_header_t *) data )->signature[ 3 ] );
244
245
    byte_stream_copy_to_uint32_big_endian(
246
     ( (modi_sparse_image_header_t *) data )->unknown1,
247
     value_32bit );
248
    libcnotify_printf(
249
     "%s: unknown1\t\t\t\t: %" PRIu32 "\n",
250
     function,
251
     value_32bit );
252
253
    libcnotify_printf(
254
     "%s: sectors per band\t\t\t: %" PRIu32 "\n",
255
     function,
256
     sparse_image_header->sectors_per_band );
257
258
    byte_stream_copy_to_uint32_big_endian(
259
     ( (modi_sparse_image_header_t *) data )->unknown2,
260
     value_32bit );
261
    libcnotify_printf(
262
     "%s: unknown2\t\t\t\t: %" PRIu32 "\n",
263
     function,
264
     value_32bit );
265
266
    libcnotify_printf(
267
     "%s: number of sectors\t\t: %" PRIu32 "\n",
268
     function,
269
     sparse_image_header->number_of_sectors );
270
271
    libcnotify_printf(
272
     "%s: unknown3:\n",
273
     function );
274
    libcnotify_print_data(
275
     ( (modi_sparse_image_header_t *) data )->unknown3,
276
     12,
277
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
278
279
    byte_stream_copy_to_uint32_big_endian(
280
     ( (modi_sparse_image_header_t *) data )->unknown4,
281
     value_32bit );
282
    libcnotify_printf(
283
     "%s: unknown4\t\t\t\t: 0x%08" PRIx32 "\n",
284
     function,
285
     value_32bit );
286
287
    libcnotify_printf(
288
     "%s: unknown5:\n",
289
     function );
290
    libcnotify_print_data(
291
     ( (modi_sparse_image_header_t *) data )->unknown5,
292
     28,
293
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
294
  }
295
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
296
297
166
  data_offset = sizeof( modi_sparse_image_header_t );
298
299
166
  if( sparse_image_header->sectors_per_band == 0 )
300
1
  {
301
1
    libcerror_error_set(
302
1
     error,
303
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
304
1
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
305
1
     "%s: invalid sectors per band value out of bounds.",
306
1
     function );
307
308
1
    goto on_error;
309
1
  }
310
165
  sparse_image_header->number_of_bands = sparse_image_header->number_of_sectors / sparse_image_header->sectors_per_band;
311
312
165
  if( ( sparse_image_header->number_of_sectors % sparse_image_header->sectors_per_band ) != 0 )
313
120
  {
314
120
    sparse_image_header->number_of_bands += 1;
315
120
  }
316
165
  if( sparse_image_header->number_of_bands > 0 )
317
164
  {
318
164
    if( sparse_image_header->number_of_bands > (uint32_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE / sizeof( uint32_t ) ) )
319
34
    {
320
34
      libcerror_error_set(
321
34
       error,
322
34
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
323
34
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
324
34
       "%s: invalid number of bands value exceeds maximum.",
325
34
       function );
326
327
34
      goto on_error;
328
34
    }
329
130
    bands_table_data_size = sparse_image_header->number_of_bands * sizeof( uint32_t );
330
331
130
    if( bands_table_data_size > ( data_size - data_offset ) )
332
26
    {
333
26
      libcerror_error_set(
334
26
       error,
335
26
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
26
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
337
26
       "%s: invalid bands table data size value out of bounds.",
338
26
       function );
339
340
26
      goto on_error;
341
26
    }
342
#if defined( HAVE_DEBUG_OUTPUT )
343
    if( libcnotify_verbose != 0 )
344
    {
345
      libcnotify_printf(
346
       "%s: bands table data:\n",
347
       function );
348
      libcnotify_print_data(
349
       &( data[ data_offset ] ),
350
       bands_table_data_size,
351
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
352
    }
353
#endif
354
104
    sparse_image_header->band_references = (uint32_t *) memory_allocate(
355
104
                                                         bands_table_data_size );
356
357
104
    if( sparse_image_header->band_references == NULL )
358
0
    {
359
0
      libcerror_error_set(
360
0
       error,
361
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
362
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
363
0
       "%s: unable to create band references.",
364
0
       function );
365
366
0
      goto on_error;
367
0
    }
368
104
    if( memory_set(
369
104
         sparse_image_header->band_references,
370
104
         0xff,
371
104
         bands_table_data_size ) == NULL )
372
0
    {
373
0
      libcerror_error_set(
374
0
       error,
375
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
376
0
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
377
0
       "%s: unable to clear band references.",
378
0
       function );
379
380
0
      goto on_error;
381
0
    }
382
104
    for( bands_table_index = 0;
383
4.55k
         bands_table_index < sparse_image_header->number_of_bands;
384
4.45k
         bands_table_index++ )
385
4.53k
    {
386
4.53k
      byte_stream_copy_to_uint32_big_endian(
387
4.53k
       &( data[ data_offset ] ),
388
4.53k
       bands_table_reference );
389
390
4.53k
      data_offset += 4;
391
392
#if defined( HAVE_DEBUG_OUTPUT )
393
      if( libcnotify_verbose != 0 )
394
      {
395
        libcnotify_printf(
396
         "%s: bands table reference: %03" PRIu32 "\t: 0x%08" PRIx32 " (%" PRIi32 ")\n",
397
         function,
398
         bands_table_index,
399
         bands_table_reference,
400
         (int32_t) bands_table_reference );
401
      }
402
#endif
403
4.53k
      if( bands_table_reference != 0 )
404
1.20k
      {
405
1.20k
        if( bands_table_reference > sparse_image_header->number_of_bands )
406
76
        {
407
76
          libcerror_error_set(
408
76
           error,
409
76
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
410
76
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
411
76
           "%s: invalid bands table reference value out of bounds.",
412
76
           function );
413
414
76
          goto on_error;
415
76
        }
416
1.13k
        ( sparse_image_header->band_references )[ bands_table_reference - 1 ] = bands_table_index;
417
1.13k
      }
418
4.53k
    }
419
#if defined( HAVE_DEBUG_OUTPUT )
420
    if( libcnotify_verbose != 0 )
421
    {
422
      libcnotify_printf(
423
       "\n" );
424
    }
425
#endif
426
104
  }
427
29
  data_offset += bands_table_data_size;
428
429
#if defined( HAVE_DEBUG_OUTPUT )
430
  if( ( libcnotify_verbose != 0 )
431
   && ( data_offset < data_size ) )
432
  {
433
    libcnotify_printf(
434
     "%s: trailing data:\n",
435
     function );
436
    libcnotify_print_data(
437
     &( data[ data_offset ] ),
438
     data_size - data_offset,
439
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
440
  }
441
#endif
442
29
  return( 1 );
443
444
137
on_error:
445
137
  if( sparse_image_header->band_references != NULL )
446
76
  {
447
76
    memory_free(
448
76
     sparse_image_header->band_references );
449
450
76
    sparse_image_header->band_references = 0;
451
76
  }
452
137
  return( -1 );
453
165
}
454
455
/* Reads a sparse image header
456
 * Returns 1 if successful, 0 if the signature does not match or -1 on error
457
 */
458
int libmodi_sparse_image_header_read_file_io_handle(
459
     libmodi_sparse_image_header_t *sparse_image_header,
460
     libbfio_handle_t *file_io_handle,
461
     off64_t offset,
462
     libcerror_error_t **error )
463
310
{
464
310
  uint8_t *sparse_image_header_data = NULL;
465
310
  static char *function             = "libmodi_sparse_image_header_read_file_io_handle";
466
310
  size_t read_size                  = 4096;
467
310
  ssize_t read_count                = 0;
468
310
  int result                        = 0;
469
470
310
  if( sparse_image_header == NULL )
471
0
  {
472
0
    libcerror_error_set(
473
0
     error,
474
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
475
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
476
0
     "%s: invalid sparse image header.",
477
0
     function );
478
479
0
    return( -1 );
480
0
  }
481
310
  sparse_image_header_data = (uint8_t *) memory_allocate(
482
310
                                          read_size );
483
484
310
  if( sparse_image_header_data == NULL )
485
0
  {
486
0
    libcerror_error_set(
487
0
     error,
488
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
489
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
490
0
     "%s: unable to create sparse image header data.",
491
0
     function );
492
493
0
    goto on_error;
494
0
  }
495
#if defined( HAVE_DEBUG_OUTPUT )
496
  if( libcnotify_verbose != 0 )
497
  {
498
    libcnotify_printf(
499
     "%s: reading sparse image header at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
500
     function,
501
     offset,
502
     offset );
503
  }
504
#endif
505
310
  read_count = libbfio_handle_read_buffer_at_offset(
506
310
                file_io_handle,
507
310
                sparse_image_header_data,
508
310
                read_size,
509
310
                offset,
510
310
                error );
511
512
310
  if( read_count != (ssize_t) read_size )
513
0
  {
514
0
    libcerror_error_set(
515
0
     error,
516
0
     LIBCERROR_ERROR_DOMAIN_IO,
517
0
     LIBCERROR_IO_ERROR_READ_FAILED,
518
0
     "%s: unable to read sparse image header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
519
0
     function,
520
0
     offset,
521
0
     offset );
522
523
0
    goto on_error;
524
0
  }
525
310
  result = libmodi_sparse_image_header_read_data(
526
310
            sparse_image_header,
527
310
            sparse_image_header_data,
528
310
            read_size,
529
310
            error );
530
531
310
  if( result == -1 )
532
137
  {
533
137
    libcerror_error_set(
534
137
     error,
535
137
     LIBCERROR_ERROR_DOMAIN_IO,
536
137
     LIBCERROR_IO_ERROR_READ_FAILED,
537
137
     "%s: unable to read sparse image header.",
538
137
     function );
539
540
137
    goto on_error;
541
137
  }
542
173
  memory_free(
543
173
   sparse_image_header_data );
544
545
173
  sparse_image_header_data = NULL;
546
547
173
  return( result );
548
549
137
on_error:
550
137
  if( sparse_image_header_data != NULL )
551
137
  {
552
137
    memory_free(
553
137
     sparse_image_header_data );
554
137
  }
555
137
  return( -1 );
556
310
}
557