Coverage Report

Created: 2024-10-02 06:58

/src/libmodi/libmodi/libmodi_udif_block_table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Universal Disk Image Format (UDIF) block table 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 "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
2.08k
{
47
2.08k
  static char *function = "libmodi_udif_block_table_initialize";
48
49
2.08k
  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
2.08k
  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
2.08k
  *block_table = memory_allocate_structure(
72
2.08k
                  libmodi_udif_block_table_t );
73
74
2.08k
  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
2.08k
  if( memory_set(
86
2.08k
       *block_table,
87
2.08k
       0,
88
2.08k
       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
2.08k
  if( libcdata_array_initialize(
105
2.08k
       &( ( *block_table )->entries_array ),
106
2.08k
       0,
107
2.08k
       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
2.08k
  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
2.08k
}
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
2.08k
{
138
2.08k
  static char *function = "libmodi_udif_block_table_free";
139
2.08k
  int result            = 1;
140
141
2.08k
  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
2.08k
  if( *block_table != NULL )
153
2.08k
  {
154
2.08k
    if( libcdata_array_free(
155
2.08k
         &( ( *block_table )->entries_array ),
156
2.08k
         (int (*)(intptr_t **, libcerror_error_t **)) &libmodi_udif_block_table_entry_free,
157
2.08k
         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
2.08k
    memory_free(
169
2.08k
     *block_table );
170
171
2.08k
    *block_table = NULL;
172
2.08k
  }
173
2.08k
  return( result );
174
2.08k
}
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
2.08k
{
185
2.08k
  libmodi_udif_block_table_entry_t *block_table_entry = NULL;
186
2.08k
  static char *function                               = "libmodi_udif_block_table_read_data";
187
2.08k
  size_t data_offset                                  = 0;
188
2.08k
  uint64_t calculated_number_of_sectors               = 0;
189
2.08k
  uint64_t number_of_sectors                          = 0;
190
2.08k
  uint32_t block_table_entry_index                    = 0;
191
2.08k
  uint32_t format_version                             = 0;
192
2.08k
  uint32_t number_of_entries                          = 0;
193
2.08k
  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
2.08k
  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
2.08k
  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
2.08k
  if( ( data_size < sizeof( modi_udif_block_table_header_t ) )
223
2.08k
   || ( data_size > (size_t) SSIZE_MAX ) )
224
9
  {
225
9
    libcerror_error_set(
226
9
     error,
227
9
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
228
9
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
229
9
     "%s: invalid data size value out of bounds.",
230
9
     function );
231
232
9
    return( -1 );
233
9
  }
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
2.07k
  if( memory_compare(
247
2.07k
       ( (modi_udif_block_table_header_t *) data )->signature,
248
2.07k
       modi_udif_block_table_signature,
249
2.07k
       4 ) != 0 )
250
5
  {
251
5
    libcerror_error_set(
252
5
     error,
253
5
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
254
5
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
255
5
     "%s: unsupported signature.",
256
5
     function );
257
258
5
    goto on_error;
259
5
  }
260
2.06k
  byte_stream_copy_to_uint32_big_endian(
261
2.06k
   ( (modi_udif_block_table_header_t *) data )->format_version,
262
2.06k
   format_version );
263
264
2.06k
  byte_stream_copy_to_uint64_big_endian(
265
2.06k
   ( (modi_udif_block_table_header_t *) data )->start_sector,
266
2.06k
   block_table->start_sector );
267
268
2.06k
  byte_stream_copy_to_uint64_big_endian(
269
2.06k
   ( (modi_udif_block_table_header_t *) data )->number_of_sectors,
270
2.06k
   number_of_sectors );
271
272
2.06k
  byte_stream_copy_to_uint32_big_endian(
273
2.06k
   ( (modi_udif_block_table_header_t *) data )->number_of_entries,
274
2.06k
   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
2.06k
  if( format_version != 1 )
393
39
  {
394
39
    libcerror_error_set(
395
39
     error,
396
39
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
397
39
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
398
39
     "%s: unsupported format version.",
399
39
     function );
400
401
39
    goto on_error;
402
39
  }
403
2.02k
  data_offset = sizeof( modi_udif_block_table_header_t );
404
405
2.02k
  for( block_table_entry_index = 0;
406
6.91k
       block_table_entry_index < number_of_entries;
407
4.88k
       block_table_entry_index++ )
408
5.08k
  {
409
5.08k
    if( data_offset > ( data_size - sizeof( modi_udif_block_table_entry_t ) ) )
410
19
    {
411
19
      libcerror_error_set(
412
19
       error,
413
19
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
414
19
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
415
19
       "%s: invalid data size value out of bounds.",
416
19
       function );
417
418
19
      goto on_error;
419
19
    }
420
5.06k
    if( libmodi_udif_block_table_entry_initialize(
421
5.06k
         &block_table_entry,
422
5.06k
         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
5.06k
    if( libmodi_udif_block_table_entry_read_data(
434
5.06k
         block_table_entry,
435
5.06k
         &( data[ data_offset ] ),
436
5.06k
         sizeof( modi_udif_block_table_entry_t ),
437
5.06k
         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
5.06k
    if( ( block_table_entry_index + 1 ) == number_of_entries )
449
1.33k
    {
450
1.33k
      if( block_table_entry->type != LIBMODI_UDIF_BLOCK_TABLE_ENTRY_TYPE_TERMINATOR )
451
51
      {
452
51
        libcerror_error_set(
453
51
         error,
454
51
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
455
51
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
456
51
         "%s: unsupported last block table entry type.",
457
51
         function );
458
459
51
        goto on_error;
460
51
      }
461
1.33k
    }
462
5.01k
    if( block_table_entry->start_sector != calculated_number_of_sectors )
463
128
    {
464
128
      libcerror_error_set(
465
128
       error,
466
128
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
467
128
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
468
128
       "%s: mismatch between start sector and number of sectors.",
469
128
       function );
470
471
128
      goto on_error;
472
128
    }
473
4.88k
    if( block_table_entry->type != LIBMODI_UDIF_BLOCK_TABLE_ENTRY_TYPE_TERMINATOR )
474
3.39k
    {
475
3.39k
      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
3.39k
      if( libcdata_array_append_entry(
480
3.39k
           block_table->entries_array,
481
3.39k
           &entry_index,
482
3.39k
           (intptr_t *) block_table_entry,
483
3.39k
           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
3.39k
      block_table_entry = NULL;
495
3.39k
    }
496
1.48k
    else
497
1.48k
    {
498
1.48k
      if( libmodi_udif_block_table_entry_free(
499
1.48k
           &block_table_entry,
500
1.48k
           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
1.48k
    }
512
4.88k
    data_offset += sizeof( modi_udif_block_table_entry_t );
513
4.88k
  }
514
1.83k
  if( number_of_sectors != calculated_number_of_sectors )
515
92
  {
516
92
    libcerror_error_set(
517
92
     error,
518
92
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
519
92
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
520
92
     "%s: mismatch between number of sectors in header and in table.",
521
92
     function );
522
523
92
    goto on_error;
524
92
  }
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
1.73k
  return( 1 );
541
542
334
on_error:
543
334
  if( block_table_entry != NULL )
544
179
  {
545
179
    libmodi_udif_block_table_entry_free(
546
179
     &block_table_entry,
547
179
     NULL );
548
179
  }
549
334
  return( -1 );
550
1.83k
}
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
762
{
560
762
  static char *function = "libmodi_udif_block_table_get_number_of_entries";
561
562
762
  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
762
  if( libcdata_array_get_number_of_entries(
574
762
       block_table->entries_array,
575
762
       number_of_entries,
576
762
       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
762
  return( 1 );
588
762
}
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
758
{
599
758
  static char *function = "libmodi_udif_block_table_get_entry_by_index";
600
601
758
  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
758
  if( libcdata_array_get_entry_by_index(
613
758
       block_table->entries_array,
614
758
       entry_index,
615
758
       (intptr_t **) block_table_entry,
616
758
       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
758
  return( 1 );
629
758
}
630