Coverage Report

Created: 2026-05-30 07:13

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-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 "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
319
{
43
319
  static char *function = "libmodi_sparse_image_header_initialize";
44
45
319
  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
319
  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
319
  *sparse_image_header = memory_allocate_structure(
68
319
                          libmodi_sparse_image_header_t );
69
70
319
  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
319
  if( memory_set(
82
319
       *sparse_image_header,
83
319
       0,
84
319
       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
319
  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
319
}
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
319
{
115
319
  static char *function = "libmodi_sparse_image_header_free";
116
117
319
  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
319
  if( *sparse_image_header != NULL )
129
319
  {
130
319
    if( ( *sparse_image_header )->band_references != NULL )
131
34
    {
132
34
      memory_free(
133
34
       ( *sparse_image_header )->band_references );
134
34
    }
135
319
    memory_free(
136
319
     *sparse_image_header );
137
138
319
    *sparse_image_header = NULL;
139
319
  }
140
319
  return( 1 );
141
319
}
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
319
{
152
319
  static char *function          = "libmodi_sparse_image_header_read_data";
153
319
  size_t bands_table_data_size   = 0;
154
319
  size_t data_offset             = 0;
155
319
  uint32_t bands_table_index     = 0;
156
319
  uint32_t bands_table_reference = 0;
157
158
#if defined( HAVE_DEBUG_OUTPUT )
159
  uint32_t value_32bit           = 0;
160
#endif
161
162
319
  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
319
  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
319
  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
319
  if( ( data_size < sizeof( modi_sparse_image_header_t ) )
196
319
   || ( 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
319
  if( memory_compare(
220
319
       ( (modi_sparse_image_header_t *) data )->signature,
221
319
       modi_sparse_image_signature,
222
319
       4 ) != 0 )
223
142
  {
224
142
    return( 0 );
225
142
  }
226
177
  byte_stream_copy_to_uint32_big_endian(
227
177
   ( (modi_sparse_image_header_t *) data )->sectors_per_band,
228
177
   sparse_image_header->sectors_per_band );
229
230
177
  byte_stream_copy_to_uint32_big_endian(
231
177
   ( (modi_sparse_image_header_t *) data )->number_of_sectors,
232
177
   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
177
  data_offset = sizeof( modi_sparse_image_header_t );
298
299
177
  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
176
  sparse_image_header->number_of_bands = sparse_image_header->number_of_sectors / sparse_image_header->sectors_per_band;
311
312
176
  if( ( sparse_image_header->number_of_sectors % sparse_image_header->sectors_per_band ) != 0 )
313
131
  {
314
131
    sparse_image_header->number_of_bands += 1;
315
131
  }
316
176
  if( sparse_image_header->number_of_bands > 0 )
317
174
  {
318
174
    if( sparse_image_header->number_of_bands > (uint32_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE / sizeof( uint32_t ) ) )
319
31
    {
320
31
      libcerror_error_set(
321
31
       error,
322
31
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
323
31
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
324
31
       "%s: invalid number of bands value exceeds maximum.",
325
31
       function );
326
327
31
      goto on_error;
328
31
    }
329
143
    bands_table_data_size = sparse_image_header->number_of_bands * sizeof( uint32_t );
330
331
143
    if( bands_table_data_size > ( data_size - data_offset ) )
332
30
    {
333
30
      libcerror_error_set(
334
30
       error,
335
30
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
30
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
337
30
       "%s: invalid bands table data size value out of bounds.",
338
30
       function );
339
340
30
      goto on_error;
341
30
    }
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
113
    sparse_image_header->band_references = (uint32_t *) memory_allocate(
355
113
                                                         bands_table_data_size );
356
357
113
    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
113
    if( memory_set(
369
113
         sparse_image_header->band_references,
370
113
         0xff,
371
113
         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
113
    for( bands_table_index = 0;
383
3.28k
         bands_table_index < sparse_image_header->number_of_bands;
384
3.17k
         bands_table_index++ )
385
3.25k
    {
386
3.25k
      byte_stream_copy_to_uint32_big_endian(
387
3.25k
       &( data[ data_offset ] ),
388
3.25k
       bands_table_reference );
389
390
3.25k
      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
3.25k
      if( bands_table_reference != 0 )
404
726
      {
405
726
        if( bands_table_reference > sparse_image_header->number_of_bands )
406
79
        {
407
79
          libcerror_error_set(
408
79
           error,
409
79
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
410
79
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
411
79
           "%s: invalid bands table reference value out of bounds.",
412
79
           function );
413
414
79
          goto on_error;
415
79
        }
416
647
        ( sparse_image_header->band_references )[ bands_table_reference - 1 ] = bands_table_index;
417
647
      }
418
3.25k
    }
419
#if defined( HAVE_DEBUG_OUTPUT )
420
    if( libcnotify_verbose != 0 )
421
    {
422
      libcnotify_printf(
423
       "\n" );
424
    }
425
#endif
426
113
  }
427
36
  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
36
  return( 1 );
443
444
141
on_error:
445
141
  if( sparse_image_header->band_references != NULL )
446
79
  {
447
79
    memory_free(
448
79
     sparse_image_header->band_references );
449
450
79
    sparse_image_header->band_references = 0;
451
79
  }
452
141
  return( -1 );
453
176
}
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
319
{
464
319
  uint8_t *sparse_image_header_data = NULL;
465
319
  static char *function             = "libmodi_sparse_image_header_read_file_io_handle";
466
319
  size_t read_size                  = 4096;
467
319
  ssize_t read_count                = 0;
468
319
  int result                        = 0;
469
470
319
  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
319
  sparse_image_header_data = (uint8_t *) memory_allocate(
482
319
                                          read_size );
483
484
319
  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
319
  read_count = libbfio_handle_read_buffer_at_offset(
506
319
                file_io_handle,
507
319
                sparse_image_header_data,
508
319
                read_size,
509
319
                offset,
510
319
                error );
511
512
319
  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
319
  result = libmodi_sparse_image_header_read_data(
526
319
            sparse_image_header,
527
319
            sparse_image_header_data,
528
319
            read_size,
529
319
            error );
530
531
319
  if( result == -1 )
532
141
  {
533
141
    libcerror_error_set(
534
141
     error,
535
141
     LIBCERROR_ERROR_DOMAIN_IO,
536
141
     LIBCERROR_IO_ERROR_READ_FAILED,
537
141
     "%s: unable to read sparse image header.",
538
141
     function );
539
540
141
    goto on_error;
541
141
  }
542
178
  memory_free(
543
178
   sparse_image_header_data );
544
545
178
  sparse_image_header_data = NULL;
546
547
178
  return( result );
548
549
141
on_error:
550
141
  if( sparse_image_header_data != NULL )
551
141
  {
552
141
    memory_free(
553
141
     sparse_image_header_data );
554
141
  }
555
141
  return( -1 );
556
319
}
557