Coverage Report

Created: 2025-12-05 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmodi/libmodi/libmodi_udif_block_table.c
Line
Count
Source
1
/*
2
 * Universal Disk Image Format (UDIF) block table 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_definitions.h"
28
#include "libmodi_libcdata.h"
29
#include "libmodi_libcerror.h"
30
#include "libmodi_libcnotify.h"
31
#include "libmodi_udif_block_table.h"
32
#include "libmodi_udif_block_table_entry.h"
33
34
#include "modi_udif_block_table.h"
35
36
const uint8_t modi_udif_block_table_signature[ 4 ] = {
37
  'm', 'i', 's', 'h' };
38
39
/* Creates a block table
40
 * Make sure the value udif_block_table is referencing, is set to NULL
41
 * Returns 1 if successful or -1 on error
42
 */
43
int libmodi_udif_block_table_initialize(
44
     libmodi_udif_block_table_t **block_table,
45
     libcerror_error_t **error )
46
1.37k
{
47
1.37k
  static char *function = "libmodi_udif_block_table_initialize";
48
49
1.37k
  if( block_table == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid block table.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
1.37k
  if( *block_table != NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
65
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66
0
     "%s: invalid block table value already set.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
1.37k
  *block_table = memory_allocate_structure(
72
1.37k
                  libmodi_udif_block_table_t );
73
74
1.37k
  if( *block_table == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
79
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
80
0
     "%s: unable to create block table.",
81
0
     function );
82
83
0
    goto on_error;
84
0
  }
85
1.37k
  if( memory_set(
86
1.37k
       *block_table,
87
1.37k
       0,
88
1.37k
       sizeof( libmodi_udif_block_table_t ) ) == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
93
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
94
0
     "%s: unable to clear block table.",
95
0
     function );
96
97
0
    memory_free(
98
0
     *block_table );
99
100
0
    *block_table = NULL;
101
102
0
    return( -1 );
103
0
  }
104
1.37k
  if( libcdata_array_initialize(
105
1.37k
       &( ( *block_table )->entries_array ),
106
1.37k
       0,
107
1.37k
       error ) != 1 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
113
0
     "%s: unable to create entries array.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
1.37k
  return( 1 );
119
120
0
on_error:
121
0
  if( *block_table != NULL )
122
0
  {
123
0
    memory_free(
124
0
     *block_table );
125
126
0
    *block_table = NULL;
127
0
  }
128
0
  return( -1 );
129
1.37k
}
130
131
/* Frees a block table
132
 * Returns 1 if successful or -1 on error
133
 */
134
int libmodi_udif_block_table_free(
135
     libmodi_udif_block_table_t **block_table,
136
     libcerror_error_t **error )
137
1.37k
{
138
1.37k
  static char *function = "libmodi_udif_block_table_free";
139
1.37k
  int result            = 1;
140
141
1.37k
  if( block_table == NULL )
142
0
  {
143
0
    libcerror_error_set(
144
0
     error,
145
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
146
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
147
0
     "%s: invalid block table.",
148
0
     function );
149
150
0
    return( -1 );
151
0
  }
152
1.37k
  if( *block_table != NULL )
153
1.37k
  {
154
1.37k
    if( libcdata_array_free(
155
1.37k
         &( ( *block_table )->entries_array ),
156
1.37k
         (int (*)(intptr_t **, libcerror_error_t **)) &libmodi_udif_block_table_entry_free,
157
1.37k
         error ) != 1 )
158
0
    {
159
0
      libcerror_error_set(
160
0
       error,
161
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
162
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
163
0
       "%s: unable to free entries array.",
164
0
       function );
165
166
0
      result = -1;
167
0
    }
168
1.37k
    memory_free(
169
1.37k
     *block_table );
170
171
1.37k
    *block_table = NULL;
172
1.37k
  }
173
1.37k
  return( result );
174
1.37k
}
175
176
/* Reads a block table
177
 * Returns 1 if successful or -1 on error
178
 */
179
int libmodi_udif_block_table_read_data(
180
     libmodi_udif_block_table_t *block_table,
181
     const uint8_t *data,
182
     size_t data_size,
183
     libcerror_error_t **error )
184
1.37k
{
185
1.37k
  libmodi_udif_block_table_entry_t *block_table_entry = NULL;
186
1.37k
  static char *function                               = "libmodi_udif_block_table_read_data";
187
1.37k
  size_t data_offset                                  = 0;
188
1.37k
  uint64_t calculated_number_of_sectors               = 0;
189
1.37k
  uint64_t number_of_sectors                          = 0;
190
1.37k
  uint32_t block_table_entry_index                    = 0;
191
1.37k
  uint32_t format_version                             = 0;
192
1.37k
  uint32_t number_of_entries                          = 0;
193
1.37k
  int entry_index                                     = 0;
194
195
#if defined( HAVE_DEBUG_OUTPUT )
196
  uint64_t value_64bit                                = 0;
197
  uint32_t value_32bit                                = 0;
198
#endif
199
200
1.37k
  if( block_table == NULL )
201
0
  {
202
0
    libcerror_error_set(
203
0
     error,
204
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
205
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
206
0
     "%s: invalid block table.",
207
0
     function );
208
209
0
    return( -1 );
210
0
  }
211
1.37k
  if( data == NULL )
212
0
  {
213
0
    libcerror_error_set(
214
0
     error,
215
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
216
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
217
0
     "%s: invalid data.",
218
0
     function );
219
220
0
    return( -1 );
221
0
  }
222
1.37k
  if( ( data_size < sizeof( modi_udif_block_table_header_t ) )
223
1.36k
   || ( data_size > (size_t) SSIZE_MAX ) )
224
16
  {
225
16
    libcerror_error_set(
226
16
     error,
227
16
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
228
16
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
229
16
     "%s: invalid data size value out of bounds.",
230
16
     function );
231
232
16
    return( -1 );
233
16
  }
234
#if defined( HAVE_DEBUG_OUTPUT )
235
  if( libcnotify_verbose != 0 )
236
  {
237
    libcnotify_printf(
238
     "%s: block table data:\n",
239
     function );
240
    libcnotify_print_data(
241
     data,
242
     data_size,
243
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
244
  }
245
#endif
246
1.36k
  if( memory_compare(
247
1.36k
       ( (modi_udif_block_table_header_t *) data )->signature,
248
1.36k
       modi_udif_block_table_signature,
249
1.36k
       4 ) != 0 )
250
10
  {
251
10
    libcerror_error_set(
252
10
     error,
253
10
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
254
10
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
255
10
     "%s: unsupported signature.",
256
10
     function );
257
258
10
    goto on_error;
259
10
  }
260
1.35k
  byte_stream_copy_to_uint32_big_endian(
261
1.35k
   ( (modi_udif_block_table_header_t *) data )->format_version,
262
1.35k
   format_version );
263
264
1.35k
  byte_stream_copy_to_uint64_big_endian(
265
1.35k
   ( (modi_udif_block_table_header_t *) data )->start_sector,
266
1.35k
   block_table->start_sector );
267
268
1.35k
  byte_stream_copy_to_uint64_big_endian(
269
1.35k
   ( (modi_udif_block_table_header_t *) data )->number_of_sectors,
270
1.35k
   number_of_sectors );
271
272
1.35k
  byte_stream_copy_to_uint32_big_endian(
273
1.35k
   ( (modi_udif_block_table_header_t *) data )->number_of_entries,
274
1.35k
   number_of_entries );
275
276
#if defined( HAVE_DEBUG_OUTPUT )
277
  if( libcnotify_verbose != 0 )
278
  {
279
    libcnotify_printf(
280
     "%s: signature\t\t\t\t: %c%c%c%c\n",
281
     function,
282
     ( (modi_udif_block_table_header_t *) data )->signature[ 0 ],
283
     ( (modi_udif_block_table_header_t *) data )->signature[ 1 ],
284
     ( (modi_udif_block_table_header_t *) data )->signature[ 2 ],
285
     ( (modi_udif_block_table_header_t *) data )->signature[ 3 ] );
286
287
    libcnotify_printf(
288
     "%s: format version\t\t\t: %" PRIu32 "\n",
289
     function,
290
     format_version );
291
292
    libcnotify_printf(
293
     "%s: start sector\t\t\t: %" PRIu64 "\n",
294
     function,
295
     block_table->start_sector );
296
297
    libcnotify_printf(
298
     "%s: number of sectors\t\t\t: %" PRIu64 "\n",
299
     function,
300
     number_of_sectors );
301
302
    byte_stream_copy_to_uint64_big_endian(
303
     ( (modi_udif_block_table_header_t *) data )->data_offset,
304
     value_64bit );
305
    libcnotify_printf(
306
     "%s: data offset\t\t\t\t: %" PRIu64 "\n",
307
     function,
308
     value_64bit );
309
310
    byte_stream_copy_to_uint32_big_endian(
311
     ( (modi_udif_block_table_header_t *) data )->unknown1,
312
     value_32bit );
313
    libcnotify_printf(
314
     "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
315
     function,
316
     value_32bit );
317
318
    byte_stream_copy_to_uint32_big_endian(
319
     ( (modi_udif_block_table_header_t *) data )->number_of_descriptors,
320
     value_32bit );
321
    libcnotify_printf(
322
     "%s: number of descriptors\t\t: %" PRIu32 "\n",
323
     function,
324
     value_32bit );
325
326
    byte_stream_copy_to_uint32_big_endian(
327
     ( (modi_udif_block_table_header_t *) data )->unknown2,
328
     value_32bit );
329
    libcnotify_printf(
330
     "%s: unknown2\t\t\t\t: 0x%08" PRIx32 "\n",
331
     function,
332
     value_32bit );
333
334
    byte_stream_copy_to_uint32_big_endian(
335
     ( (modi_udif_block_table_header_t *) data )->unknown3,
336
     value_32bit );
337
    libcnotify_printf(
338
     "%s: unknown3\t\t\t\t: 0x%08" PRIx32 "\n",
339
     function,
340
     value_32bit );
341
342
    byte_stream_copy_to_uint32_big_endian(
343
     ( (modi_udif_block_table_header_t *) data )->unknown4,
344
     value_32bit );
345
    libcnotify_printf(
346
     "%s: unknown4\t\t\t\t: 0x%08" PRIx32 "\n",
347
     function,
348
     value_32bit );
349
350
    byte_stream_copy_to_uint32_big_endian(
351
     ( (modi_udif_block_table_header_t *) data )->unknown5,
352
     value_32bit );
353
    libcnotify_printf(
354
     "%s: unknown5\t\t\t\t: 0x%08" PRIx32 "\n",
355
     function,
356
     value_32bit );
357
358
    byte_stream_copy_to_uint32_big_endian(
359
     ( (modi_udif_block_table_header_t *) data )->unknown6,
360
     value_32bit );
361
    libcnotify_printf(
362
     "%s: unknown6\t\t\t\t: 0x%08" PRIx32 "\n",
363
     function,
364
     value_32bit );
365
366
    byte_stream_copy_to_uint32_big_endian(
367
     ( (modi_udif_block_table_header_t *) data )->unknown7,
368
     value_32bit );
369
    libcnotify_printf(
370
     "%s: unknown7\t\t\t\t: 0x%08" PRIx32 "\n",
371
     function,
372
     value_32bit );
373
374
    libcnotify_printf(
375
     "%s: checksum:\n",
376
     function );
377
    libcnotify_print_data(
378
     ( (modi_udif_block_table_header_t *) data )->checksum,
379
     136,
380
     0 );
381
382
    libcnotify_printf(
383
     "%s: number of entries\t\t\t: %" PRIu32 "\n",
384
     function,
385
     number_of_entries );
386
387
    libcnotify_printf(
388
     "\n" );
389
  }
390
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
391
392
1.35k
  if( format_version != 1 )
393
45
  {
394
45
    libcerror_error_set(
395
45
     error,
396
45
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
397
45
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
398
45
     "%s: unsupported format version.",
399
45
     function );
400
401
45
    goto on_error;
402
45
  }
403
1.30k
  data_offset = sizeof( modi_udif_block_table_header_t );
404
405
1.30k
  for( block_table_entry_index = 0;
406
3.78k
       block_table_entry_index < number_of_entries;
407
2.47k
       block_table_entry_index++ )
408
2.75k
  {
409
2.75k
    if( data_offset > ( data_size - sizeof( modi_udif_block_table_entry_t ) ) )
410
72
    {
411
72
      libcerror_error_set(
412
72
       error,
413
72
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
414
72
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
415
72
       "%s: invalid data size value out of bounds.",
416
72
       function );
417
418
72
      goto on_error;
419
72
    }
420
2.67k
    if( libmodi_udif_block_table_entry_initialize(
421
2.67k
         &block_table_entry,
422
2.67k
         error ) != 1 )
423
0
    {
424
0
      libcerror_error_set(
425
0
       error,
426
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
427
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
428
0
       "%s: unable to create block table entry.",
429
0
       function );
430
431
0
      goto on_error;
432
0
    }
433
2.67k
    if( libmodi_udif_block_table_entry_read_data(
434
2.67k
         block_table_entry,
435
2.67k
         &( data[ data_offset ] ),
436
2.67k
         sizeof( modi_udif_block_table_entry_t ),
437
2.67k
         error ) != 1 )
438
0
    {
439
0
      libcerror_error_set(
440
0
       error,
441
0
       LIBCERROR_ERROR_DOMAIN_IO,
442
0
       LIBCERROR_IO_ERROR_READ_FAILED,
443
0
       "%s: unable to read block table entry.",
444
0
       function );
445
446
0
      goto on_error;
447
0
    }
448
2.67k
    if( ( block_table_entry_index + 1 ) == number_of_entries )
449
779
    {
450
779
      if( block_table_entry->type != LIBMODI_UDIF_BLOCK_TABLE_ENTRY_TYPE_TERMINATOR )
451
53
      {
452
53
        libcerror_error_set(
453
53
         error,
454
53
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
455
53
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
456
53
         "%s: unsupported last block table entry type.",
457
53
         function );
458
459
53
        goto on_error;
460
53
      }
461
779
    }
462
2.62k
    if( block_table_entry->start_sector != calculated_number_of_sectors )
463
147
    {
464
147
      libcerror_error_set(
465
147
       error,
466
147
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
467
147
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
468
147
       "%s: mismatch between start sector and number of sectors.",
469
147
       function );
470
471
147
      goto on_error;
472
147
    }
473
2.47k
    if( block_table_entry->type != LIBMODI_UDIF_BLOCK_TABLE_ENTRY_TYPE_TERMINATOR )
474
1.51k
    {
475
1.51k
      calculated_number_of_sectors += block_table_entry->number_of_sectors;
476
477
      /* block_table->entries_array takes over management of block_table_entry
478
       */
479
1.51k
      if( libcdata_array_append_entry(
480
1.51k
           block_table->entries_array,
481
1.51k
           &entry_index,
482
1.51k
           (intptr_t *) block_table_entry,
483
1.51k
           error ) != 1 )
484
0
      {
485
0
        libcerror_error_set(
486
0
         error,
487
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
488
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
489
0
         "%s: unable to append entry to array.",
490
0
         function );
491
492
0
        goto on_error;
493
0
      }
494
1.51k
      block_table_entry = NULL;
495
1.51k
    }
496
968
    else
497
968
    {
498
968
      if( libmodi_udif_block_table_entry_free(
499
968
           &block_table_entry,
500
968
           error ) != 1 )
501
0
      {
502
0
        libcerror_error_set(
503
0
         error,
504
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
505
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
506
0
         "%s: unable to free block table entry.",
507
0
         function );
508
509
0
        goto on_error;
510
0
      }
511
968
    }
512
2.47k
    data_offset += sizeof( modi_udif_block_table_entry_t );
513
2.47k
  }
514
1.03k
  if( number_of_sectors != calculated_number_of_sectors )
515
84
  {
516
84
    libcerror_error_set(
517
84
     error,
518
84
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
519
84
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
520
84
     "%s: mismatch between number of sectors in header and in table.",
521
84
     function );
522
523
84
    goto on_error;
524
84
  }
525
#if defined( HAVE_DEBUG_OUTPUT )
526
  if( libcnotify_verbose != 0 )
527
  {
528
    if( data_offset < data_size )
529
    {
530
      libcnotify_printf(
531
       "%s: trailing data:\n",
532
       function );
533
      libcnotify_print_data(
534
       &( data[ data_offset ] ),
535
       data_size - data_offset,
536
       0 );
537
    }
538
  }
539
#endif
540
951
  return( 1 );
541
542
411
on_error:
543
411
  if( block_table_entry != NULL )
544
200
  {
545
200
    libmodi_udif_block_table_entry_free(
546
200
     &block_table_entry,
547
200
     NULL );
548
200
  }
549
411
  return( -1 );
550
1.03k
}
551
552
/* Retrieves the number of entries
553
 * Returns 1 if successful or -1 on error
554
 */
555
int libmodi_udif_block_table_get_number_of_entries(
556
     libmodi_udif_block_table_t *block_table,
557
     int *number_of_entries,
558
     libcerror_error_t **error )
559
567
{
560
567
  static char *function = "libmodi_udif_block_table_get_number_of_entries";
561
562
567
  if( block_table == NULL )
563
0
  {
564
0
    libcerror_error_set(
565
0
     error,
566
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
567
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
568
0
     "%s: invalid block table.",
569
0
     function );
570
571
0
    return( -1 );
572
0
  }
573
567
  if( libcdata_array_get_number_of_entries(
574
567
       block_table->entries_array,
575
567
       number_of_entries,
576
567
       error ) != 1 )
577
0
  {
578
0
    libcerror_error_set(
579
0
     error,
580
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
581
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
582
0
     "%s: unable to retrieve number of entries from entries array.",
583
0
     function );
584
585
0
    return( -1 );
586
0
  }
587
567
  return( 1 );
588
567
}
589
590
/* Retrieves a specific entry
591
 * Returns 1 if successful or -1 on error
592
 */
593
int libmodi_udif_block_table_get_entry_by_index(
594
     libmodi_udif_block_table_t *block_table,
595
     int entry_index,
596
     libmodi_udif_block_table_entry_t **block_table_entry,
597
     libcerror_error_t **error )
598
585
{
599
585
  static char *function = "libmodi_udif_block_table_get_entry_by_index";
600
601
585
  if( block_table == NULL )
602
0
  {
603
0
    libcerror_error_set(
604
0
     error,
605
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
606
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
607
0
     "%s: invalid block table.",
608
0
     function );
609
610
0
    return( -1 );
611
0
  }
612
585
  if( libcdata_array_get_entry_by_index(
613
585
       block_table->entries_array,
614
585
       entry_index,
615
585
       (intptr_t **) block_table_entry,
616
585
       error ) != 1 )
617
0
  {
618
0
    libcerror_error_set(
619
0
     error,
620
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
621
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
622
0
     "%s: unable to retrieve entry: %d from entries array.",
623
0
     function,
624
0
     entry_index );
625
626
0
    return( -1 );
627
0
  }
628
585
  return( 1 );
629
585
}
630