Coverage Report

Created: 2026-05-24 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvhdi/libvhdi/libvhdi_block_descriptor.c
Line
Count
Source
1
/*
2
 * Block descriptor 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 "libvhdi_block_descriptor.h"
28
#include "libvhdi_debug.h"
29
#include "libvhdi_definitions.h"
30
#include "libvhdi_libbfio.h"
31
#include "libvhdi_libcdata.h"
32
#include "libvhdi_libcerror.h"
33
#include "libvhdi_libcnotify.h"
34
#include "libvhdi_sector_range_descriptor.h"
35
36
/* Creates a block descriptor
37
 * Make sure the value block_descriptor is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libvhdi_block_descriptor_initialize(
41
     libvhdi_block_descriptor_t **block_descriptor,
42
     libcerror_error_t **error )
43
0
{
44
0
  static char *function = "libvhdi_block_descriptor_initialize";
45
46
0
  if( block_descriptor == NULL )
47
0
  {
48
0
    libcerror_error_set(
49
0
     error,
50
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
51
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
52
0
     "%s: invalid block descriptor.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
0
  if( *block_descriptor != NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
62
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
63
0
     "%s: invalid block descriptor value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
0
  *block_descriptor = memory_allocate_structure(
69
0
                       libvhdi_block_descriptor_t );
70
71
0
  if( *block_descriptor == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
76
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
77
0
     "%s: unable to create block descriptor.",
78
0
     function );
79
80
0
    goto on_error;
81
0
  }
82
0
  if( memory_set(
83
0
       *block_descriptor,
84
0
       0,
85
0
       sizeof( libvhdi_block_descriptor_t ) ) == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
91
0
     "%s: unable to clear block descriptor.",
92
0
     function );
93
94
0
    memory_free(
95
0
     *block_descriptor );
96
97
0
    *block_descriptor = NULL;
98
99
0
    return( -1 );
100
0
  }
101
0
  if( libcdata_array_initialize(
102
0
       &( ( *block_descriptor )->sector_ranges_array ),
103
0
       0,
104
0
       error ) != 1 )
105
0
  {
106
0
    libcerror_error_set(
107
0
     error,
108
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
109
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
110
0
     "%s: unable to create sector ranges array.",
111
0
     function );
112
113
0
    goto on_error;
114
0
  }
115
0
  return( 1 );
116
117
0
on_error:
118
0
  if( *block_descriptor != NULL )
119
0
  {
120
0
    memory_free(
121
0
     *block_descriptor );
122
123
0
    *block_descriptor = NULL;
124
0
  }
125
0
  return( -1 );
126
0
}
127
128
/* Frees a block descriptor
129
 * Returns 1 if successful or -1 on error
130
 */
131
int libvhdi_block_descriptor_free(
132
     libvhdi_block_descriptor_t **block_descriptor,
133
     libcerror_error_t **error )
134
0
{
135
0
  static char *function = "libvhdi_block_descriptor_free";
136
0
  int result            = 1;
137
138
0
  if( block_descriptor == NULL )
139
0
  {
140
0
    libcerror_error_set(
141
0
     error,
142
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
143
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
144
0
     "%s: invalid block descriptor.",
145
0
     function );
146
147
0
    return( -1 );
148
0
  }
149
0
  if( *block_descriptor != NULL )
150
0
  {
151
0
    if( libcdata_array_free(
152
0
         &( ( *block_descriptor )->sector_ranges_array ),
153
0
         (int (*)(intptr_t **, libcerror_error_t **)) &libvhdi_sector_range_descriptor_free,
154
0
         error ) != 1 )
155
0
    {
156
0
      libcerror_error_set(
157
0
       error,
158
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
159
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
160
0
       "%s: unable to free sector ranges array.",
161
0
       function );
162
163
0
      result = -1;
164
0
    }
165
0
    memory_free(
166
0
     *block_descriptor );
167
168
0
    *block_descriptor = NULL;
169
0
  }
170
0
  return( result );
171
0
}
172
173
/* Reads a block allocation table entry
174
 * Returns 1 if successful or -1 on error
175
 */
176
int libvhdi_block_descriptor_read_table_entry_data(
177
     libvhdi_block_descriptor_t *block_descriptor,
178
     const uint8_t *data,
179
     size_t data_size,
180
     int file_type,
181
     uint32_t sector_bitmap_size,
182
     libcerror_error_t **error )
183
0
{
184
0
  static char *function   = "libvhdi_block_descriptor_read_table_entry_data";
185
0
  size_t table_entry_size = 0;
186
0
  uint64_t table_entry    = 0;
187
188
0
  if( block_descriptor == NULL )
189
0
  {
190
0
    libcerror_error_set(
191
0
     error,
192
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
193
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
194
0
     "%s: invalid block descriptor.",
195
0
     function );
196
197
0
    return( -1 );
198
0
  }
199
0
  if( data == NULL )
200
0
  {
201
0
    libcerror_error_set(
202
0
     error,
203
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
204
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
205
0
     "%s: invalid data.",
206
0
     function );
207
208
0
    return( -1 );
209
0
  }
210
0
  if( file_type == LIBVHDI_FILE_TYPE_VHD )
211
0
  {
212
0
    table_entry_size = 4;
213
0
  }
214
0
  else if( file_type == LIBVHDI_FILE_TYPE_VHDX )
215
0
  {
216
0
    table_entry_size = 8;
217
0
  }
218
0
  else
219
0
  {
220
0
    libcerror_error_set(
221
0
     error,
222
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
223
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
224
0
     "%s: unsupported file type.",
225
0
     function );
226
227
0
    return( -1 );
228
0
  }
229
0
  if( data_size != table_entry_size )
230
0
  {
231
0
    libcerror_error_set(
232
0
     error,
233
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
234
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
235
0
     "%s: invalid data size value out of bounds.",
236
0
     function );
237
238
0
    return( -1 );
239
0
  }
240
#if defined( HAVE_DEBUG_OUTPUT )
241
  if( libcnotify_verbose != 0 )
242
  {
243
    libcnotify_printf(
244
     "%s: block allocation table entry data:\n",
245
     function );
246
    libcnotify_print_data(
247
     data,
248
     data_size,
249
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
250
  }
251
#endif
252
0
  if( file_type == LIBVHDI_FILE_TYPE_VHD )
253
0
  {
254
0
    byte_stream_copy_to_uint32_big_endian(
255
0
     data,
256
0
     table_entry );
257
0
  }
258
0
  else if( file_type == LIBVHDI_FILE_TYPE_VHDX )
259
0
  {
260
0
    byte_stream_copy_to_uint64_little_endian(
261
0
     data,
262
0
     table_entry );
263
0
  }
264
#if defined( HAVE_DEBUG_OUTPUT )
265
  if( libcnotify_verbose != 0 )
266
  {
267
    libcnotify_printf(
268
     "%s: entry\t\t\t: 0x%08" PRIx64 "\n",
269
     function,
270
     table_entry );
271
  }
272
#endif
273
0
  if( file_type == LIBVHDI_FILE_TYPE_VHD )
274
0
  {
275
0
    if( table_entry == 0xffffffffUL )
276
0
    {
277
0
      block_descriptor->file_offset = -1;
278
0
    }
279
0
    else
280
0
    {
281
0
      block_descriptor->file_offset = ( table_entry * 512 ) + sector_bitmap_size;
282
0
    }
283
0
  }
284
0
  else if( file_type == LIBVHDI_FILE_TYPE_VHDX )
285
0
  {
286
0
    block_descriptor->block_state = (uint8_t) ( table_entry & 0x7 );
287
0
    block_descriptor->file_offset = ( table_entry >> 20 ) * 1024 * 1024;
288
289
#if defined( HAVE_DEBUG_OUTPUT )
290
    if( libcnotify_verbose != 0 )
291
    {
292
      libcnotify_printf(
293
       "%s: block state\t\t: %" PRIu64 " (%s)\n",
294
       function,
295
       block_descriptor->block_state,
296
       libvhdi_debug_print_block_state(
297
        block_descriptor->block_state ) );
298
299
      libcnotify_printf(
300
       "%s: unknown1\t\t: 0x%04" PRIx64 "\n",
301
       function,
302
       ( table_entry >> 3 ) & 0x1ffff );
303
    }
304
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
305
0
  }
306
#if defined( HAVE_DEBUG_OUTPUT )
307
  if( libcnotify_verbose != 0 )
308
  {
309
    libcnotify_printf(
310
     "%s: offset\t\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
311
     function,
312
     block_descriptor->file_offset,
313
     block_descriptor->file_offset );
314
315
    libcnotify_printf(
316
     "\n" );
317
  }
318
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
319
320
0
  return( 1 );
321
0
}
322
323
/* Reads a block allocation table entry
324
 * Returns 1 if successful or -1 on error
325
 */
326
int libvhdi_block_descriptor_read_table_entry_file_io_handle(
327
     libvhdi_block_descriptor_t *block_descriptor,
328
     libbfio_handle_t *file_io_handle,
329
     int file_type,
330
     off64_t file_offset,
331
     uint32_t sector_bitmap_size,
332
     libcerror_error_t **error )
333
0
{
334
0
  uint8_t table_entry_data[ 8 ];
335
336
0
  static char *function   = "libvhdi_block_descriptor_read_table_entry_file_io_handle";
337
0
  size_t table_entry_size = 0;
338
0
  ssize_t read_count      = 0;
339
340
0
  if( block_descriptor == NULL )
341
0
  {
342
0
    libcerror_error_set(
343
0
     error,
344
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
345
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
346
0
     "%s: invalid block descriptor.",
347
0
     function );
348
349
0
    return( -1 );
350
0
  }
351
0
  if( file_type == LIBVHDI_FILE_TYPE_VHD )
352
0
  {
353
0
    table_entry_size = 4;
354
0
  }
355
0
  else if( file_type == LIBVHDI_FILE_TYPE_VHDX )
356
0
  {
357
0
    table_entry_size = 8;
358
0
  }
359
0
  else
360
0
  {
361
0
    libcerror_error_set(
362
0
     error,
363
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
365
0
     "%s: unsupported file type.",
366
0
     function );
367
368
0
    return( -1 );
369
0
  }
370
#if defined( HAVE_DEBUG_OUTPUT )
371
  if( libcnotify_verbose != 0 )
372
  {
373
    libcnotify_printf(
374
     "%s: reading block allocation table entry at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
375
     function,
376
     file_offset,
377
     file_offset );
378
  }
379
#endif
380
0
  read_count = libbfio_handle_read_buffer_at_offset(
381
0
                file_io_handle,
382
0
                table_entry_data,
383
0
                table_entry_size,
384
0
                file_offset,
385
0
                error );
386
387
0
  if( read_count != (ssize_t) table_entry_size )
388
0
  {
389
0
    libcerror_error_set(
390
0
     error,
391
0
     LIBCERROR_ERROR_DOMAIN_IO,
392
0
     LIBCERROR_IO_ERROR_READ_FAILED,
393
0
     "%s: unable to read block allocation table entry data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
394
0
     function,
395
0
     file_offset,
396
0
     file_offset );
397
398
0
    return( -1 );
399
0
  }
400
0
  if( libvhdi_block_descriptor_read_table_entry_data(
401
0
       block_descriptor,
402
0
       table_entry_data,
403
0
       table_entry_size,
404
0
       file_type,
405
0
       sector_bitmap_size,
406
0
       error ) != 1 )
407
0
  {
408
0
    libcerror_error_set(
409
0
     error,
410
0
     LIBCERROR_ERROR_DOMAIN_IO,
411
0
     LIBCERROR_IO_ERROR_READ_FAILED,
412
0
     "%s: unable to read allocation table entry.",
413
0
     function );
414
415
0
    return( -1 );
416
0
  }
417
0
  return( 1 );
418
0
}
419
420
/* Reads the sector bitmap
421
 * Returns 1 if successful or -1 on error
422
 */
423
int libvhdi_block_descriptor_read_sector_bitmap_data(
424
     libvhdi_block_descriptor_t *block_descriptor,
425
     const uint8_t *data,
426
     size_t data_size,
427
     int file_type,
428
     uint32_t bytes_per_sector,
429
     libcerror_error_t **error )
430
0
{
431
0
  libvhdi_sector_range_descriptor_t *sector_range_descriptor = NULL;
432
0
  static char *function                                      = "libvhdi_block_descriptor_read_sector_bitmap_data";
433
0
  size64_t range_size                                        = 0;
434
0
  size_t data_offset                                         = 0;
435
0
  off64_t range_offset                                       = 0;
436
0
  uint8_t bit_index                                          = 0;
437
0
  uint8_t byte_value                                         = 0;
438
0
  uint8_t element_value                                      = 0;
439
0
  uint8_t first_element_value                                = 0;
440
0
  int element_index                                          = 0;
441
0
  int entry_index                                            = 0;
442
0
  int first_element_index                                    = 0;
443
444
#if defined( HAVE_DEBUG_OUTPUT )
445
  char *range_type                                           = NULL;
446
#endif
447
448
0
  if( block_descriptor == NULL )
449
0
  {
450
0
    libcerror_error_set(
451
0
     error,
452
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
453
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
454
0
     "%s: invalid block descriptor.",
455
0
     function );
456
457
0
    return( -1 );
458
0
  }
459
0
  if( data == NULL )
460
0
  {
461
0
    libcerror_error_set(
462
0
     error,
463
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
464
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
465
0
     "%s: invalid data.",
466
0
     function );
467
468
0
    return( -1 );
469
0
  }
470
0
  if( ( data_size < 1 )
471
0
   || ( data_size > (size_t) SSIZE_MAX ) )
472
0
  {
473
0
    libcerror_error_set(
474
0
     error,
475
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
476
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
477
0
     "%s: invalid data size value out of bounds.",
478
0
     function );
479
480
0
    return( -1 );
481
0
  }
482
0
  if( ( file_type != LIBVHDI_FILE_TYPE_VHD )
483
0
   && ( file_type != LIBVHDI_FILE_TYPE_VHDX ) )
484
0
  {
485
0
    libcerror_error_set(
486
0
     error,
487
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
488
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
489
0
     "%s: unsupported file type.",
490
0
     function );
491
492
0
    return( -1 );
493
0
  }
494
0
  if( ( bytes_per_sector != 512 )
495
0
   && ( bytes_per_sector != 4096 ) )
496
0
  {
497
0
    libcerror_error_set(
498
0
     error,
499
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
500
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
501
0
     "%s: unsupported bytes per sector.",
502
0
     function );
503
504
0
    return( -1 );
505
0
  }
506
#if defined( HAVE_DEBUG_OUTPUT )
507
  if( libcnotify_verbose != 0 )
508
  {
509
    libcnotify_printf(
510
     "%s: sector bitmap data:\n",
511
     function );
512
    libcnotify_print_data(
513
     data,
514
     data_size,
515
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
516
  }
517
#endif
518
0
  if( file_type == LIBVHDI_FILE_TYPE_VHD )
519
0
  {
520
0
    first_element_value = data[ data_offset ] >> 7;
521
0
  }
522
0
  else if( file_type == LIBVHDI_FILE_TYPE_VHDX )
523
0
  {
524
0
    first_element_value = data[ data_offset ] & 0x01;
525
0
  }
526
0
  while( data_offset < data_size )
527
0
  {
528
0
    byte_value = data[ data_offset ];
529
530
0
    data_offset++;
531
532
0
    for( bit_index = 0;
533
0
         bit_index < 8;
534
0
         bit_index++ )
535
0
    {
536
0
      if( file_type == LIBVHDI_FILE_TYPE_VHD )
537
0
      {
538
0
        element_value = byte_value >> ( 7 - bit_index );
539
0
      }
540
0
      else if( file_type == LIBVHDI_FILE_TYPE_VHDX )
541
0
      {
542
0
        element_value = byte_value & 0x01;
543
0
        byte_value  >>= 1;
544
0
      }
545
0
      if( element_value != first_element_value )
546
0
      {
547
0
        range_offset = (off64_t) first_element_index * bytes_per_sector;
548
0
        range_size   = ( (size64_t) element_index - first_element_index ) * bytes_per_sector;
549
550
#if defined( HAVE_DEBUG_OUTPUT )
551
        if( libcnotify_verbose != 0 )
552
        {
553
          if( first_element_value == 0 )
554
          {
555
            range_type = "unallocated";
556
          }
557
          else
558
          {
559
            range_type = "allocated";
560
          }
561
          libcnotify_printf(
562
           "%s: %s sector range\t: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ")\n",
563
           function,
564
           range_type,
565
           range_offset,
566
           range_offset + range_size,
567
           range_size );
568
        }
569
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
570
571
0
        if( libvhdi_sector_range_descriptor_initialize(
572
0
             &sector_range_descriptor,
573
0
             error ) != 1 )
574
0
        {
575
0
          libcerror_error_set(
576
0
           error,
577
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
578
0
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
579
0
           "%s: unable to create sector range descriptor.",
580
0
           function );
581
582
0
          goto on_error;
583
0
        }
584
0
        sector_range_descriptor->start_offset = range_offset;
585
0
        sector_range_descriptor->end_offset   = range_offset + range_size;
586
587
0
        if( first_element_value == 0 )
588
0
        {
589
0
          sector_range_descriptor->flags = LIBFDATA_SECTOR_RANGE_FLAG_IS_UNALLOCATED;
590
0
        }
591
0
        if( libcdata_array_append_entry(
592
0
             block_descriptor->sector_ranges_array,
593
0
             &entry_index,
594
0
             (intptr_t *) sector_range_descriptor,
595
0
             error ) != 1 )
596
0
        {
597
0
          libcerror_error_set(
598
0
           error,
599
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
600
0
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
601
0
           "%s: unable to append sector range to array.",
602
0
           function );
603
604
0
          goto on_error;
605
0
        }
606
0
        sector_range_descriptor = NULL;
607
608
0
        first_element_value = element_value;
609
0
        first_element_index = element_index;
610
0
      }
611
0
      element_index++;
612
0
    }
613
0
  }
614
0
  range_offset = (off64_t) first_element_index * bytes_per_sector;
615
0
  range_size   = ( (size64_t) element_index - first_element_index ) * bytes_per_sector;
616
617
#if defined( HAVE_DEBUG_OUTPUT )
618
  if( libcnotify_verbose != 0 )
619
  {
620
    if( first_element_value == 0 )
621
    {
622
      range_type = "unallocated";
623
    }
624
    else
625
    {
626
      range_type = "allocated";
627
    }
628
    libcnotify_printf(
629
     "%s: %s sector range\t: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ")\n",
630
     function,
631
     range_type,
632
     range_offset,
633
     range_offset + range_size,
634
     range_size );
635
  }
636
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
637
638
0
  if( libvhdi_sector_range_descriptor_initialize(
639
0
       &sector_range_descriptor,
640
0
       error ) != 1 )
641
0
  {
642
0
    libcerror_error_set(
643
0
     error,
644
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
645
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
646
0
     "%s: unable to create sector range descriptor.",
647
0
     function );
648
649
0
    goto on_error;
650
0
  }
651
0
  sector_range_descriptor->start_offset = range_offset;
652
0
  sector_range_descriptor->end_offset   = range_offset + range_size;
653
654
0
  if( first_element_value == 0 )
655
0
  {
656
0
    sector_range_descriptor->flags = LIBFDATA_SECTOR_RANGE_FLAG_IS_UNALLOCATED;
657
0
  }
658
0
  if( libcdata_array_append_entry(
659
0
       block_descriptor->sector_ranges_array,
660
0
       &entry_index,
661
0
       (intptr_t *) sector_range_descriptor,
662
0
       error ) != 1 )
663
0
  {
664
0
    libcerror_error_set(
665
0
     error,
666
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
667
0
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
668
0
     "%s: unable to append sector range to array.",
669
0
     function );
670
671
0
    goto on_error;
672
0
  }
673
0
  sector_range_descriptor = NULL;
674
675
#if defined( HAVE_DEBUG_OUTPUT )
676
  if( libcnotify_verbose != 0 )
677
  {
678
    libcnotify_printf(
679
     "\n" );
680
  }
681
#endif
682
0
  return( 1 );
683
684
0
on_error:
685
0
  if( sector_range_descriptor != NULL )
686
0
  {
687
0
    libvhdi_sector_range_descriptor_free(
688
0
     &sector_range_descriptor,
689
0
     NULL );
690
0
  }
691
0
  return( -1 );
692
0
}
693
694
/* Reads the sector bitmap
695
 * Returns 1 if successful or -1 on error
696
 */
697
int libvhdi_block_descriptor_read_sector_bitmap_file_io_handle(
698
     libvhdi_block_descriptor_t *block_descriptor,
699
     libbfio_handle_t *file_io_handle,
700
     int file_type,
701
     off64_t file_offset,
702
     uint32_t block_size,
703
     uint32_t sector_bitmap_size,
704
     uint32_t bytes_per_sector,
705
     libcerror_error_t **error )
706
0
{
707
0
  libvhdi_sector_range_descriptor_t *sector_range_descriptor = NULL;
708
0
  uint8_t *data                                              = NULL;
709
0
  static char *function                                      = "libvhdi_block_descriptor_read_sector_bitmap_file_io_handle";
710
0
  ssize_t read_count                                         = 0;
711
0
  int entry_index                                            = 0;
712
713
0
  if( block_descriptor == NULL )
714
0
  {
715
0
    libcerror_error_set(
716
0
     error,
717
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
718
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
719
0
     "%s: invalid block descriptor.",
720
0
     function );
721
722
0
    return( -1 );
723
0
  }
724
0
  if( ( sector_bitmap_size == 0 )
725
0
   || ( sector_bitmap_size > (uint32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
726
0
  {
727
0
    libcerror_error_set(
728
0
     error,
729
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
730
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
731
0
     "%s: invalid block descriptor - invalid sector bitmap size value out of bounds.",
732
0
     function );
733
734
0
    return( -1 );
735
0
  }
736
0
  if( ( file_offset == -1 )
737
0
   || ( block_descriptor->block_state == 6 ) )
738
0
  {
739
0
    if( libvhdi_sector_range_descriptor_initialize(
740
0
         &sector_range_descriptor,
741
0
         error ) != 1 )
742
0
    {
743
0
      libcerror_error_set(
744
0
       error,
745
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
746
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
747
0
       "%s: unable to create sector range descriptor.",
748
0
       function );
749
750
0
      goto on_error;
751
0
    }
752
0
    sector_range_descriptor->start_offset = 0;
753
0
    sector_range_descriptor->end_offset   = block_size;
754
755
0
    if( ( file_type == LIBVHDI_FILE_TYPE_VHD )
756
0
     || ( block_descriptor->block_state < 6 ) )
757
0
    {
758
0
      sector_range_descriptor->flags = LIBFDATA_SECTOR_RANGE_FLAG_IS_UNALLOCATED;
759
0
    }
760
0
    if( libcdata_array_append_entry(
761
0
         block_descriptor->sector_ranges_array,
762
0
         &entry_index,
763
0
         (intptr_t *) sector_range_descriptor,
764
0
         error ) != 1 )
765
0
    {
766
0
      libcerror_error_set(
767
0
       error,
768
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
769
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
770
0
       "%s: unable to append sector range to array.",
771
0
       function );
772
773
0
      goto on_error;
774
0
    }
775
0
    sector_range_descriptor = NULL;
776
0
  }
777
0
  else
778
0
  {
779
#if defined( HAVE_DEBUG_OUTPUT )
780
    if( libcnotify_verbose != 0 )
781
    {
782
      libcnotify_printf(
783
       "%s: reading sector bitmap at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
784
       function,
785
       file_offset,
786
       file_offset );
787
    }
788
#endif
789
0
    data = (uint8_t *) memory_allocate(
790
0
                        sizeof( uint8_t ) * sector_bitmap_size );
791
792
0
    if( data == NULL )
793
0
    {
794
0
      libcerror_error_set(
795
0
       error,
796
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
797
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
798
0
       "%s: unable to create sector bitmap data.",
799
0
       function );
800
801
0
      goto on_error;
802
0
    }
803
0
    read_count = libbfio_handle_read_buffer_at_offset(
804
0
                  file_io_handle,
805
0
                  data,
806
0
                  (size_t) sector_bitmap_size,
807
0
                  file_offset,
808
0
                  error );
809
810
0
    if( read_count != (ssize_t) sector_bitmap_size )
811
0
    {
812
0
      libcerror_error_set(
813
0
       error,
814
0
       LIBCERROR_ERROR_DOMAIN_IO,
815
0
       LIBCERROR_IO_ERROR_READ_FAILED,
816
0
       "%s: unable to read sector bitmap data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
817
0
       function,
818
0
       file_offset,
819
0
       file_offset );
820
821
0
      goto on_error;
822
0
    }
823
0
    if( libvhdi_block_descriptor_read_sector_bitmap_data(
824
0
         block_descriptor,
825
0
         data,
826
0
         (size_t) sector_bitmap_size,
827
0
         file_type,
828
0
         bytes_per_sector,
829
0
         error ) != 1 )
830
0
    {
831
0
      libcerror_error_set(
832
0
       error,
833
0
       LIBCERROR_ERROR_DOMAIN_IO,
834
0
       LIBCERROR_IO_ERROR_READ_FAILED,
835
0
       "%s: unable to read sector bitmap.",
836
0
       function );
837
838
0
      goto on_error;
839
0
    }
840
0
    memory_free(
841
0
     data );
842
0
  }
843
0
  return( 1 );
844
845
0
on_error:
846
0
  if( data != NULL )
847
0
  {
848
0
    memory_free(
849
0
     data );
850
0
  }
851
0
  if( sector_range_descriptor != NULL )
852
0
  {
853
0
    libvhdi_sector_range_descriptor_free(
854
0
     &sector_range_descriptor,
855
0
     NULL );
856
0
  }
857
0
  return( -1 );
858
0
}
859
860
/* Retrieves the sector range descriptor for a specific offset
861
 * Returns 1 if successful, 0 if not available or -1 on error
862
 */
863
int libvhdi_block_descriptor_get_sector_range_descriptor_at_offset(
864
     libvhdi_block_descriptor_t *block_descriptor,
865
     off64_t offset,
866
     libvhdi_sector_range_descriptor_t **sector_range_descriptor,
867
     libcerror_error_t **error )
868
0
{
869
0
  libvhdi_sector_range_descriptor_t *safe_sector_range_descriptor = NULL;
870
0
  static char *function                                           = "libvhdi_block_descriptor_get_sector_range_descriptor_at_offset";
871
0
  int entry_index                                                 = 0;
872
0
  int number_of_entries                                           = 0;
873
874
/* TODO uses a sector number to sector range descriptor map for quick look up */
875
0
  if( block_descriptor == NULL )
876
0
  {
877
0
    libcerror_error_set(
878
0
     error,
879
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
880
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
881
0
     "%s: invalid block descriptor.",
882
0
     function );
883
884
0
    return( -1 );
885
0
  }
886
0
  if( libcdata_array_get_number_of_entries(
887
0
       block_descriptor->sector_ranges_array,
888
0
       &number_of_entries,
889
0
       error ) != 1 )
890
0
  {
891
0
    libcerror_error_set(
892
0
     error,
893
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
894
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
895
0
     "%s: unable to retrieve number of entries from sector ranges array.",
896
0
     function );
897
898
0
    return( -1 );
899
0
  }
900
0
  for( entry_index = 0;
901
0
       entry_index < number_of_entries;
902
0
       entry_index++ )
903
0
  {
904
0
    if( libcdata_array_get_entry_by_index(
905
0
         block_descriptor->sector_ranges_array,
906
0
         entry_index,
907
0
         (intptr_t **) &safe_sector_range_descriptor,
908
0
         error ) != 1 )
909
0
    {
910
0
      libcerror_error_set(
911
0
       error,
912
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
913
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
914
0
       "%s: unable to retrieve descriptor: %d from sector range array.",
915
0
       function,
916
0
       entry_index );
917
918
0
      return( -1 );
919
0
    }
920
0
    if( safe_sector_range_descriptor == NULL )
921
0
    {
922
0
      libcerror_error_set(
923
0
       error,
924
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
925
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
926
0
       "%s: missing sector range descriptor: %d.",
927
0
       function,
928
0
       entry_index );
929
930
0
      return( -1 );
931
0
    }
932
0
    if( ( offset >= safe_sector_range_descriptor->start_offset )
933
0
     && ( offset < safe_sector_range_descriptor->end_offset ) )
934
0
    {
935
0
      *sector_range_descriptor = safe_sector_range_descriptor;
936
937
0
      return( 1 );
938
0
    }
939
0
  }
940
0
  return( 0 );
941
0
}
942