Coverage Report

Created: 2026-03-05 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvmdk/libvmdk/libvmdk_extent_file.c
Line
Count
Source
1
/*
2
 * Extent file functions
3
 *
4
 * Copyright (C) 2009-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 "libvmdk_debug.h"
28
#include "libvmdk_definitions.h"
29
#include "libvmdk_extent_file.h"
30
#include "libvmdk_grain_data.h"
31
#include "libvmdk_grain_group.h"
32
#include "libvmdk_libbfio.h"
33
#include "libvmdk_libcerror.h"
34
#include "libvmdk_libcnotify.h"
35
#include "libvmdk_libfcache.h"
36
#include "libvmdk_libfdata.h"
37
#include "libvmdk_types.h"
38
#include "libvmdk_unused.h"
39
40
#include "cowd_sparse_file_header.h"
41
#include "vmdk_sparse_file_header.h"
42
43
const char *cowd_sparse_file_signature = "COWD";
44
const char *vmdk_sparse_file_signature = "KDMV";
45
46
/* Creates an extent file
47
 * Make sure the value extent_file is referencing, is set to NULL
48
 * Returns 1 if successful or -1 on error
49
 */
50
int libvmdk_extent_file_initialize(
51
     libvmdk_extent_file_t **extent_file,
52
     libvmdk_io_handle_t *io_handle,
53
     libcerror_error_t **error )
54
719
{
55
719
  static char *function = "libvmdk_extent_file_initialize";
56
57
719
  if( extent_file == NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
62
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
63
0
     "%s: invalid extent file.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
719
  if( *extent_file != NULL )
69
0
  {
70
0
    libcerror_error_set(
71
0
     error,
72
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
73
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
74
0
     "%s: invalid extent file value already set.",
75
0
     function );
76
77
0
    return( -1 );
78
0
  }
79
719
  if( io_handle == NULL )
80
0
  {
81
0
    libcerror_error_set(
82
0
     error,
83
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
84
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
85
0
     "%s: invalid IO handle.",
86
0
     function );
87
88
0
    return( -1 );
89
0
  }
90
719
  *extent_file = memory_allocate_structure(
91
719
                  libvmdk_extent_file_t );
92
93
719
  if( *extent_file == NULL )
94
0
  {
95
0
    libcerror_error_set(
96
0
     error,
97
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
98
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
99
0
     "%s: unable to create extent file.",
100
0
     function );
101
102
0
    goto on_error;
103
0
  }
104
719
  if( memory_set(
105
719
       *extent_file,
106
719
       0,
107
719
       sizeof( libvmdk_extent_file_t ) ) == NULL )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
112
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
113
0
     "%s: unable to clear extent file.",
114
0
     function );
115
116
0
    memory_free(
117
0
     *extent_file );
118
119
0
    *extent_file = NULL;
120
121
0
    return( -1 );
122
0
  }
123
719
  if( libfdata_list_initialize(
124
719
       &( ( *extent_file )->grain_groups_list ),
125
719
       (intptr_t *) *extent_file,
126
719
       NULL,
127
719
       NULL,
128
719
       (int (*)(intptr_t *, intptr_t *, libfdata_list_element_t *, libfdata_cache_t *, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libvmdk_extent_file_read_grain_group_element_data,
129
719
       NULL,
130
719
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
131
719
       error ) != 1 )
132
0
  {
133
0
    libcerror_error_set(
134
0
     error,
135
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
136
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
137
0
     "%s: unable to create grain groups list.",
138
0
     function );
139
140
0
    goto on_error;
141
0
  }
142
/* TODO set mapped offset in grain_groups_list ? */
143
719
  if( libfcache_cache_initialize(
144
719
       &( ( *extent_file )->grain_groups_cache ),
145
719
       LIBVMDK_MAXIMUM_CACHE_ENTRIES_GRAIN_GROUPS,
146
719
       error ) != 1 )
147
0
  {
148
0
    libcerror_error_set(
149
0
     error,
150
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
151
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
152
0
     "%s: unable to create grain groups cache.",
153
0
     function );
154
155
0
    goto on_error;
156
0
  }
157
719
  ( *extent_file )->io_handle = io_handle;
158
159
719
  return( 1 );
160
161
0
on_error:
162
0
  if( *extent_file != NULL )
163
0
  {
164
0
    if( ( *extent_file )->grain_groups_list != NULL )
165
0
    {
166
0
      libfdata_list_free(
167
0
       &( ( *extent_file )->grain_groups_list ),
168
0
       NULL );
169
0
    }
170
0
    memory_free(
171
0
     *extent_file );
172
173
0
    *extent_file = NULL;
174
0
  }
175
0
  return( -1 );
176
719
}
177
178
/* Frees an extent file
179
 * Returns 1 if successful or -1 on error
180
 */
181
int libvmdk_extent_file_free(
182
     libvmdk_extent_file_t **extent_file,
183
     libcerror_error_t **error )
184
719
{
185
719
  static char *function = "libvmdk_extent_file_free";
186
719
  int result            = 1;
187
188
719
  if( extent_file == 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 extent file.",
195
0
     function );
196
197
0
    return( -1 );
198
0
  }
199
719
  if( *extent_file != NULL )
200
719
  {
201
719
    if( libfdata_list_free(
202
719
         &( ( *extent_file )->grain_groups_list ),
203
719
         error ) != 1 )
204
0
    {
205
0
      libcerror_error_set(
206
0
       error,
207
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
208
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
209
0
       "%s: unable to free grain groups list.",
210
0
       function );
211
212
0
      result = -1;
213
0
    }
214
719
    if( libfcache_cache_free(
215
719
         &( ( *extent_file )->grain_groups_cache ),
216
719
         error ) != 1 )
217
0
    {
218
0
      libcerror_error_set(
219
0
       error,
220
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
221
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
222
0
       "%s: unable to free grain groups cache.",
223
0
       function );
224
225
0
      result = -1;
226
0
    }
227
719
    memory_free(
228
719
     *extent_file );
229
230
719
    *extent_file = NULL;
231
719
  }
232
719
  return( result );
233
719
}
234
235
/* Checks if a buffer containing the chunk data is filled with same value bytes (empty-block)
236
 * Returns 1 if a pattern was found, 0 if not or -1 on error
237
 */
238
int libvmdk_extent_file_check_for_empty_block(
239
     const uint8_t *data,
240
     size_t data_size,
241
     libcerror_error_t **error )
242
0
{
243
0
  libvmdk_aligned_t *aligned_data_index = NULL;
244
0
  libvmdk_aligned_t *aligned_data_start = NULL;
245
0
  uint8_t *data_index                   = NULL;
246
0
  uint8_t *data_start                   = NULL;
247
0
  static char *function                 = "libvmdk_extent_file_check_for_empty_block";
248
249
0
  if( data == NULL )
250
0
  {
251
0
    libcerror_error_set(
252
0
     error,
253
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
254
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
255
0
     "%s: invalid data.",
256
0
     function );
257
258
0
    return( -1 );
259
0
  }
260
0
  if( data_size > (size_t) SSIZE_MAX )
261
0
  {
262
0
    libcerror_error_set(
263
0
     error,
264
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
265
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
266
0
     "%s: invalid data size value exceeds maximum.",
267
0
     function );
268
269
0
    return( -1 );
270
0
  }
271
0
  data_start = (uint8_t *) data;
272
0
  data_index = (uint8_t *) data + 1;
273
0
  data_size -= 1;
274
275
  /* Only optimize for data larger than the alignment
276
   */
277
0
  if( data_size > ( 2 * sizeof( libvmdk_aligned_t ) ) )
278
0
  {
279
    /* Align the data start
280
     */
281
0
    while( ( (intptr_t) data_start % sizeof( libvmdk_aligned_t ) ) != 0 )
282
0
    {
283
0
      if( *data_start != *data_index )
284
0
      {
285
0
        return( 0 );
286
0
      }
287
0
      data_start += 1;
288
0
      data_index += 1;
289
0
      data_size  -= 1;
290
0
    }
291
    /* Align the data index
292
     */
293
0
    while( ( (intptr_t) data_index % sizeof( libvmdk_aligned_t ) ) != 0 )
294
0
    {
295
0
      if( *data_start != *data_index )
296
0
      {
297
0
        return( 0 );
298
0
      }
299
0
      data_index += 1;
300
0
      data_size  -= 1;
301
0
    }
302
0
    aligned_data_start = (libvmdk_aligned_t *) data_start;
303
0
    aligned_data_index = (libvmdk_aligned_t *) data_index;
304
305
0
    while( data_size > sizeof( libvmdk_aligned_t ) )
306
0
    {
307
0
      if( *aligned_data_start != *aligned_data_index )
308
0
      {
309
0
        return( 0 );
310
0
      }
311
0
      aligned_data_index += 1;
312
0
      data_size          -= sizeof( libvmdk_aligned_t );
313
0
    }
314
0
    data_index = (uint8_t *) aligned_data_index;
315
0
  }
316
0
  while( data_size != 0 )
317
0
  {
318
0
    if( *data_start != *data_index )
319
0
    {
320
0
      return( 0 );
321
0
    }
322
0
    data_index += 1;
323
0
    data_size  -= 1;
324
0
  }
325
0
  return( 1 );
326
0
}
327
328
/* Reads the file header from the extent file using the file IO handle
329
 * Returns 1 if successful, or -1 on error
330
 */
331
int libvmdk_extent_file_read_file_header_file_io_handle(
332
     libvmdk_extent_file_t *extent_file,
333
     libbfio_handle_t *file_io_handle,
334
     off64_t file_offset,
335
     libcerror_error_t **error )
336
719
{
337
719
  uint8_t *file_header_data = NULL;
338
719
  static char *function     = "libvmdk_extent_file_read_file_header_file_io_handle";
339
719
  size_t read_size          = 0;
340
719
  ssize_t read_count        = 0;
341
342
719
  if( extent_file == NULL )
343
0
  {
344
0
    libcerror_error_set(
345
0
     error,
346
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
347
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
348
0
     "%s: invalid extent file.",
349
0
     function );
350
351
0
    return( -1 );
352
0
  }
353
719
  file_header_data = (uint8_t *) memory_allocate(
354
719
                                  sizeof( uint8_t ) * 2048 );
355
356
719
  if( file_header_data == NULL )
357
0
  {
358
0
    libcerror_error_set(
359
0
     error,
360
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
361
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
362
0
     "%s: unable to create file header data.",
363
0
     function );
364
365
0
    goto on_error;
366
0
  }
367
#if defined( HAVE_DEBUG_OUTPUT )
368
  if( libcnotify_verbose != 0 )
369
  {
370
    libcnotify_printf(
371
     "%s: reading file header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
372
     function,
373
     file_offset,
374
     file_offset );
375
  }
376
#endif
377
719
  read_count = libbfio_handle_read_buffer_at_offset(
378
719
                file_io_handle,
379
719
                file_header_data,
380
719
                4,
381
719
                file_offset,
382
719
                error );
383
384
719
  if( read_count != (ssize_t) 4 )
385
0
  {
386
0
    libcerror_error_set(
387
0
     error,
388
0
     LIBCERROR_ERROR_DOMAIN_IO,
389
0
     LIBCERROR_IO_ERROR_READ_FAILED,
390
0
     "%s: unable to read file header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
391
0
     function,
392
0
     file_offset,
393
0
     file_offset );
394
395
0
    goto on_error;
396
0
  }
397
719
  if( memory_compare(
398
719
       file_header_data,
399
719
       cowd_sparse_file_signature,
400
719
       4 ) == 0 )
401
0
  {
402
0
    read_size = sizeof( cowd_sparse_file_header_t );
403
0
  }
404
719
  else if( memory_compare(
405
719
            file_header_data,
406
719
            vmdk_sparse_file_signature,
407
719
            4 ) == 0 )
408
719
  {
409
719
    read_size = sizeof( vmdk_sparse_file_header_t );
410
719
  }
411
0
  else
412
0
  {
413
0
    libcerror_error_set(
414
0
     error,
415
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
416
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
417
0
     "%s: unsupported file signature.",
418
0
     function );
419
420
0
    goto on_error;
421
0
  }
422
719
  read_count = libbfio_handle_read_buffer(
423
719
                file_io_handle,
424
719
                &( file_header_data[ 4 ] ),
425
719
                read_size - 4,
426
719
                error );
427
428
719
  if( read_count != (ssize_t) ( read_size - 4 ) )
429
12
  {
430
12
    libcerror_error_set(
431
12
     error,
432
12
     LIBCERROR_ERROR_DOMAIN_IO,
433
12
     LIBCERROR_IO_ERROR_READ_FAILED,
434
12
     "%s: unable to read file header data.",
435
12
     function );
436
437
12
    goto on_error;
438
12
  }
439
707
  if( libvmdk_extent_file_read_file_header_data(
440
707
       extent_file,
441
707
       file_header_data,
442
707
       read_size,
443
707
       error ) != 1 )
444
507
  {
445
507
    libcerror_error_set(
446
507
     error,
447
507
     LIBCERROR_ERROR_DOMAIN_IO,
448
507
     LIBCERROR_IO_ERROR_READ_FAILED,
449
507
     "%s: unable to read file header data.",
450
507
     function );
451
452
507
    goto on_error;
453
507
  }
454
200
  memory_free(
455
200
   file_header_data );
456
457
200
  file_header_data = NULL;
458
459
200
  return( 1 );
460
461
519
on_error:
462
519
  if( file_header_data != NULL )
463
519
  {
464
519
    memory_free(
465
519
     file_header_data );
466
519
  }
467
519
  return( -1 );
468
707
}
469
470
/* Reads the file header from the extent file using the file IO pool entry
471
 * Returns 1 if successful, or -1 on error
472
 */
473
int libvmdk_extent_file_read_file_header(
474
     libvmdk_extent_file_t *extent_file,
475
     libbfio_pool_t *file_io_pool,
476
     int file_io_pool_entry,
477
     off64_t file_offset,
478
     libcerror_error_t **error )
479
0
{
480
0
  uint8_t *file_header_data = NULL;
481
0
  static char *function     = "libvmdk_extent_file_read_file_header";
482
0
  size_t read_size          = 0;
483
0
  ssize_t read_count        = 0;
484
485
0
  if( extent_file == NULL )
486
0
  {
487
0
    libcerror_error_set(
488
0
     error,
489
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
490
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
491
0
     "%s: invalid extent file.",
492
0
     function );
493
494
0
    return( -1 );
495
0
  }
496
#if defined( HAVE_DEBUG_OUTPUT )
497
  if( libcnotify_verbose != 0 )
498
  {
499
    libcnotify_printf(
500
     "%s: reading file header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
501
     function,
502
     file_offset,
503
     file_offset );
504
  }
505
#endif
506
0
  if( libbfio_pool_seek_offset(
507
0
       file_io_pool,
508
0
       file_io_pool_entry,
509
0
       file_offset,
510
0
       SEEK_SET,
511
0
       error ) == -1 )
512
0
  {
513
0
    libcerror_error_set(
514
0
     error,
515
0
     LIBCERROR_ERROR_DOMAIN_IO,
516
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
517
0
     "%s: unable to seek file header offset: %" PRIi64 " (0x%08" PRIx64 ").",
518
0
     function,
519
0
     file_offset,
520
0
     file_offset );
521
522
0
    goto on_error;
523
0
  }
524
0
  file_header_data = (uint8_t *) memory_allocate(
525
0
                                  sizeof( uint8_t ) * 2048 );
526
527
0
  if( file_header_data == NULL )
528
0
  {
529
0
    libcerror_error_set(
530
0
     error,
531
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
532
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
533
0
     "%s: unable to create file header data.",
534
0
     function );
535
536
0
    goto on_error;
537
0
  }
538
0
  read_count = libbfio_pool_read_buffer(
539
0
                file_io_pool,
540
0
                file_io_pool_entry,
541
0
                file_header_data,
542
0
                4,
543
0
                error );
544
545
0
  if( read_count != (ssize_t) 4 )
546
0
  {
547
0
    libcerror_error_set(
548
0
     error,
549
0
     LIBCERROR_ERROR_DOMAIN_IO,
550
0
     LIBCERROR_IO_ERROR_READ_FAILED,
551
0
     "%s: unable to read file header data.",
552
0
     function );
553
554
0
    goto on_error;
555
0
  }
556
0
  if( memory_compare(
557
0
       file_header_data,
558
0
       cowd_sparse_file_signature,
559
0
       4 ) == 0 )
560
0
  {
561
0
    read_size = sizeof( cowd_sparse_file_header_t );
562
0
  }
563
0
  else if( memory_compare(
564
0
            file_header_data,
565
0
            vmdk_sparse_file_signature,
566
0
            4 ) == 0 )
567
0
  {
568
0
    read_size = sizeof( vmdk_sparse_file_header_t );
569
0
  }
570
0
  else
571
0
  {
572
0
    libcerror_error_set(
573
0
     error,
574
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
575
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
576
0
     "%s: unsupported file signature.",
577
0
     function );
578
579
0
    goto on_error;
580
0
  }
581
0
  read_count = libbfio_pool_read_buffer(
582
0
                file_io_pool,
583
0
                file_io_pool_entry,
584
0
                &( file_header_data[ 4 ] ),
585
0
                read_size - 4,
586
0
                error );
587
588
0
  if( read_count != (ssize_t) ( read_size - 4 ) )
589
0
  {
590
0
    libcerror_error_set(
591
0
     error,
592
0
     LIBCERROR_ERROR_DOMAIN_IO,
593
0
     LIBCERROR_IO_ERROR_READ_FAILED,
594
0
     "%s: unable to read file header data.",
595
0
     function );
596
597
0
    goto on_error;
598
0
  }
599
0
  if( libvmdk_extent_file_read_file_header_data(
600
0
       extent_file,
601
0
       file_header_data,
602
0
       read_size,
603
0
       error ) != 1 )
604
0
  {
605
0
    libcerror_error_set(
606
0
     error,
607
0
     LIBCERROR_ERROR_DOMAIN_IO,
608
0
     LIBCERROR_IO_ERROR_READ_FAILED,
609
0
     "%s: unable to read file header data.",
610
0
     function );
611
612
0
    goto on_error;
613
0
  }
614
0
  memory_free(
615
0
   file_header_data );
616
617
0
  file_header_data = NULL;
618
619
0
  return( 1 );
620
621
0
on_error:
622
0
  if( file_header_data != NULL )
623
0
  {
624
0
    memory_free(
625
0
     file_header_data );
626
0
  }
627
0
  return( -1 );
628
0
}
629
630
/* Reads the file header from the extent file
631
 * Returns 1 if successful, or -1 on error
632
 */
633
int libvmdk_extent_file_read_file_header_data(
634
     libvmdk_extent_file_t *extent_file,
635
     const uint8_t *file_header_data,
636
     size_t file_header_data_size,
637
     libcerror_error_t **error )
638
707
{
639
707
  static char *function                          = "libvmdk_extent_file_read_file_header_data";
640
707
  size64_t grain_table_size                      = 0;
641
707
  uint64_t safe_descriptor_offset                = 0;
642
707
  uint64_t safe_primary_grain_directory_offset   = 0;
643
707
  uint64_t safe_secondary_grain_directory_offset = 0;
644
645
#if defined( HAVE_DEBUG_OUTPUT )
646
  uint64_t value_64bit                           = 0;
647
#endif
648
649
707
  if( extent_file == NULL )
650
0
  {
651
0
    libcerror_error_set(
652
0
     error,
653
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
654
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
655
0
     "%s: invalid extent file.",
656
0
     function );
657
658
0
    return( -1 );
659
0
  }
660
707
  if( file_header_data == NULL )
661
0
  {
662
0
    libcerror_error_set(
663
0
     error,
664
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
665
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
666
0
     "%s: invalid file header data.",
667
0
     function );
668
669
0
    return( -1 );
670
0
  }
671
707
  if( file_header_data_size > (size_t) SSIZE_MAX )
672
0
  {
673
0
    libcerror_error_set(
674
0
     error,
675
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
676
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
677
0
     "%s: invalid file header data size value exceeds maximum.",
678
0
     function );
679
680
0
    return( -1 );
681
0
  }
682
707
  if( memory_compare(
683
707
       file_header_data,
684
707
       cowd_sparse_file_signature,
685
707
       4 ) == 0 )
686
0
  {
687
0
    if( file_header_data_size < sizeof( cowd_sparse_file_header_t ) )
688
0
    {
689
0
      libcerror_error_set(
690
0
       error,
691
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
692
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
693
0
       "%s: invalid file header data value too small.",
694
0
       function );
695
696
0
      return( -1 );
697
0
    }
698
0
    extent_file->file_type = LIBVMDK_FILE_TYPE_COWD_SPARSE_DATA;
699
0
  }
700
707
  else if( memory_compare(
701
707
            file_header_data,
702
707
            vmdk_sparse_file_signature,
703
707
            4 ) == 0 )
704
707
  {
705
707
    if( file_header_data_size < sizeof( vmdk_sparse_file_header_t ) )
706
0
    {
707
0
      libcerror_error_set(
708
0
       error,
709
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
710
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
711
0
       "%s: invalid file header data value too small.",
712
0
       function );
713
714
0
      return( -1 );
715
0
    }
716
707
    extent_file->file_type = LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA;
717
707
  }
718
0
  else
719
0
  {
720
0
    libcerror_error_set(
721
0
     error,
722
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
723
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
724
0
     "%s: unsupported file signature.",
725
0
     function );
726
727
0
    return( -1 );
728
0
  }
729
#if defined( HAVE_DEBUG_OUTPUT )
730
  if( libcnotify_verbose != 0 )
731
  {
732
    libcnotify_printf(
733
     "%s: file header:\n",
734
     function );
735
    libcnotify_print_data(
736
     file_header_data,
737
     file_header_data_size,
738
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
739
  }
740
#endif
741
707
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_COWD_SPARSE_DATA )
742
0
  {
743
0
    byte_stream_copy_to_uint32_little_endian(
744
0
     ( (cowd_sparse_file_header_t *) file_header_data )->version,
745
0
     extent_file->format_version );
746
747
0
    byte_stream_copy_to_uint32_little_endian(
748
0
     ( (cowd_sparse_file_header_t *) file_header_data )->flags,
749
0
     extent_file->flags );
750
751
0
    byte_stream_copy_to_uint32_little_endian(
752
0
     ( (cowd_sparse_file_header_t *) file_header_data )->maximum_data_number_of_sectors,
753
0
     extent_file->maximum_data_size );
754
755
0
    byte_stream_copy_to_uint32_little_endian(
756
0
     ( (cowd_sparse_file_header_t *) file_header_data )->grain_number_of_sectors,
757
0
     extent_file->grain_size );
758
759
0
    byte_stream_copy_to_uint32_little_endian(
760
0
     ( (cowd_sparse_file_header_t *) file_header_data )->primary_grain_directory_sector_number,
761
0
     safe_primary_grain_directory_offset );
762
763
0
    byte_stream_copy_to_uint32_little_endian(
764
0
     ( (cowd_sparse_file_header_t *) file_header_data )->number_of_grain_directory_entries,
765
0
     extent_file->number_of_grain_directory_entries );
766
0
  }
767
707
  else if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
768
707
  {
769
707
    byte_stream_copy_to_uint32_little_endian(
770
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->version,
771
707
     extent_file->format_version );
772
773
707
    byte_stream_copy_to_uint32_little_endian(
774
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->flags,
775
707
     extent_file->flags );
776
777
707
    byte_stream_copy_to_uint64_little_endian(
778
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->maximum_data_number_of_sectors,
779
707
     extent_file->maximum_data_size );
780
781
707
    byte_stream_copy_to_uint64_little_endian(
782
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->grain_number_of_sectors,
783
707
     extent_file->grain_size );
784
785
707
    byte_stream_copy_to_uint64_little_endian(
786
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->descriptor_sector_number,
787
707
     safe_descriptor_offset );
788
789
707
    byte_stream_copy_to_uint64_little_endian(
790
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->descriptor_number_of_sectors,
791
707
     extent_file->descriptor_size );
792
793
707
    byte_stream_copy_to_uint32_little_endian(
794
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->number_of_grain_table_entries,
795
707
     extent_file->number_of_grain_table_entries );
796
797
707
    byte_stream_copy_to_uint64_little_endian(
798
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->secondary_grain_directory_sector_number,
799
707
     safe_secondary_grain_directory_offset );
800
801
707
    byte_stream_copy_to_uint64_little_endian(
802
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->primary_grain_directory_sector_number,
803
707
     safe_primary_grain_directory_offset );
804
805
707
    extent_file->is_dirty = ( (vmdk_sparse_file_header_t *) file_header_data )->is_dirty;
806
807
707
    byte_stream_copy_to_uint16_little_endian(
808
707
     ( (vmdk_sparse_file_header_t *) file_header_data )->compression_method,
809
707
     extent_file->compression_method );
810
707
  }
811
#if defined( HAVE_DEBUG_OUTPUT )
812
  if( libcnotify_verbose != 0 )
813
  {
814
    libcnotify_printf(
815
     "%s: signature\t\t\t\t\t: %c%c%c%c\n",
816
     function,
817
     (char) file_header_data[ 0 ],
818
     (char) file_header_data[ 1 ],
819
     (char) file_header_data[ 2 ],
820
     (char) file_header_data[ 3 ] );
821
822
    libcnotify_printf(
823
     "%s: format version\t\t\t\t: %" PRIu32 "\n",
824
     function,
825
     extent_file->format_version );
826
827
    libcnotify_printf(
828
     "%s: flags\t\t\t\t\t: 0x%08" PRIx32 "\n",
829
     function,
830
     extent_file->flags );
831
832
    if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
833
    {
834
      libvmdk_debug_print_vmdk_flags(
835
       extent_file->flags );
836
    }
837
    libcnotify_printf(
838
     "%s: maximum data number of sectors\t\t: %" PRIu64 "\n",
839
     function,
840
     extent_file->maximum_data_size );
841
842
    libcnotify_printf(
843
     "%s: grain number of sectors\t\t\t: %" PRIu64 "\n",
844
     function,
845
     extent_file->grain_size );
846
847
    if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
848
    {
849
      libcnotify_printf(
850
       "%s: descriptor sector number\t\t\t: %" PRIu64 "\n",
851
       function,
852
       safe_descriptor_offset );
853
854
      libcnotify_printf(
855
       "%s: descriptor number of sectors\t\t\t: %" PRIu64 "\n",
856
       function,
857
       extent_file->descriptor_size );
858
859
      libcnotify_printf(
860
       "%s: number of grain table entries\t\t: %" PRIu32 "\n",
861
       function,
862
       extent_file->number_of_grain_table_entries );
863
864
      if( safe_secondary_grain_directory_offset <= ( (uint64_t) INT64_MAX / 512 ) )
865
      {
866
        libcnotify_printf(
867
         "%s: secondary grain directory sector number\t: %" PRIu64 "\n",
868
         function,
869
         safe_secondary_grain_directory_offset );
870
      }
871
      else
872
      {
873
        libcnotify_printf(
874
         "%s: secondary grain directory sector number\t: 0x%08" PRIx64 "\n",
875
         function,
876
         safe_secondary_grain_directory_offset );
877
      }
878
    }
879
    if( safe_primary_grain_directory_offset <= ( (uint64_t) INT64_MAX / 512 ) )
880
    {
881
      libcnotify_printf(
882
       "%s: primary grain directory sector number\t: %" PRIu64 "\n",
883
       function,
884
       safe_primary_grain_directory_offset );
885
    }
886
    else
887
    {
888
      libcnotify_printf(
889
       "%s: primary grain directory sector number\t: 0x%08" PRIx64 "\n",
890
       function,
891
       safe_primary_grain_directory_offset );
892
    }
893
    if( extent_file->file_type == LIBVMDK_FILE_TYPE_COWD_SPARSE_DATA )
894
    {
895
      libcnotify_printf(
896
       "%s: padding:\n",
897
       function );
898
      libcnotify_print_data(
899
       (uint8_t *) ( (vmdk_sparse_file_header_t *) file_header_data )->padding,
900
       433,
901
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
902
    }
903
    else if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
904
    {
905
      byte_stream_copy_to_uint64_little_endian(
906
       ( (vmdk_sparse_file_header_t *) file_header_data )->metadata_number_of_sectors,
907
       value_64bit );
908
      libcnotify_printf(
909
       "%s: metadata number of sectors\t\t\t: %" PRIu64 "\n",
910
       function,
911
       value_64bit );
912
913
      libcnotify_printf(
914
       "%s: is dirty\t\t\t\t\t: 0x%02" PRIx8 "\n",
915
       function,
916
       extent_file->is_dirty );
917
918
      libcnotify_printf(
919
       "%s: single end of line character\t\t\t: 0x%02" PRIx8 "\n",
920
       function,
921
       ( (vmdk_sparse_file_header_t *) file_header_data )->single_end_of_line_character );
922
923
      libcnotify_printf(
924
       "%s: non end of line character\t\t\t: 0x%02" PRIx8 "\n",
925
       function,
926
       ( (vmdk_sparse_file_header_t *) file_header_data )->non_end_of_line_character );
927
928
      libcnotify_printf(
929
       "%s: first double end of line character\t\t: 0x%02" PRIx8 "\n",
930
       function,
931
       ( (vmdk_sparse_file_header_t *) file_header_data )->first_double_end_of_line_character );
932
933
      libcnotify_printf(
934
       "%s: second double end of line character\t\t: 0x%02" PRIx8 "\n",
935
       function,
936
       ( (vmdk_sparse_file_header_t *) file_header_data )->second_double_end_of_line_character );
937
938
      libcnotify_printf(
939
       "%s: compression method\t\t\t\t: %" PRIu16 " (%s)\n",
940
       function,
941
       extent_file->compression_method,
942
       libvmdk_debug_get_compression_method_description(
943
        extent_file->compression_method ) );
944
945
      libcnotify_printf(
946
       "%s: padding:\n",
947
       function );
948
      libcnotify_print_data(
949
       ( (vmdk_sparse_file_header_t *) file_header_data )->padding,
950
       433,
951
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
952
    }
953
  }
954
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
955
956
707
  if( ( extent_file->grain_size == 0 )
957
706
   || ( extent_file->grain_size > ( (uint64_t) INT64_MAX / 512 ) ) )
958
59
  {
959
59
    libcerror_error_set(
960
59
     error,
961
59
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
962
59
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
963
59
     "%s: invalid grain number of sectors value out of bounds.",
964
59
     function );
965
966
59
    return( -1 );
967
59
  }
968
648
  if( safe_descriptor_offset > (uint64_t) INT64_MAX )
969
64
  {
970
64
    libcerror_error_set(
971
64
     error,
972
64
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
973
64
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
974
64
     "%s: invalid descriptor offset value out of bounds.",
975
64
     function );
976
977
64
    return( -1 );
978
64
  }
979
584
  extent_file->descriptor_offset = (off64_t) safe_descriptor_offset;
980
981
  /* Note that the primary grain directory offsets can be -1
982
   */
983
584
  extent_file->primary_grain_directory_offset = (off64_t) safe_primary_grain_directory_offset;
984
985
584
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
986
584
  {
987
584
    if( safe_secondary_grain_directory_offset > ( (uint64_t) INT64_MAX / 512 ) )
988
16
    {
989
16
      libcerror_error_set(
990
16
       error,
991
16
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
992
16
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
993
16
       "%s: invalid secondary grain directory offset value out of bounds.",
994
16
       function );
995
996
16
      return( -1 );
997
16
    }
998
568
    extent_file->secondary_grain_directory_offset = (off64_t) safe_secondary_grain_directory_offset;
999
1000
568
    if( extent_file->grain_size <= 8 )
1001
4
    {
1002
4
      libcerror_error_set(
1003
4
       error,
1004
4
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1005
4
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1006
4
       "%s: unsupported grain number of sectors value is less than or equal to 8.",
1007
4
       function );
1008
1009
4
      return( -1 );
1010
4
    }
1011
    /* grain size & (grain size - 1) is 0 when grain size is a power of 2 */
1012
564
    if( ( extent_file->grain_size & ( extent_file->grain_size - 1 ) ) != 0 )
1013
70
    {
1014
70
      libcerror_error_set(
1015
70
       error,
1016
70
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1017
70
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1018
70
       "%s: unsupported grain number of sectors value is not a power of 2.",
1019
70
       function );
1020
1021
70
      return( -1 );
1022
70
    }
1023
494
    if( extent_file->number_of_grain_table_entries == 0 )
1024
1
    {
1025
1
      libcerror_error_set(
1026
1
       error,
1027
1
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1028
1
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1029
1
       "%s: unsupported number of grain table entries value is 0.",
1030
1
       function );
1031
1032
1
      return( -1 );
1033
1
    }
1034
493
    if( (size_t) extent_file->number_of_grain_table_entries > (size_t) INT_MAX )
1035
30
    {
1036
30
      libcerror_error_set(
1037
30
       error,
1038
30
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1039
30
       LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1040
30
       "%s: invalid number of grain table entries value exceeds maximum.",
1041
30
       function );
1042
1043
30
      return( -1 );
1044
30
    }
1045
493
  }
1046
#if defined( HAVE_DEBUG_OUTPUT )
1047
  if( libcnotify_verbose != 0 )
1048
  {
1049
    if( ( extent_file->maximum_data_size % extent_file->grain_size ) != 0 )
1050
    {
1051
      libcnotify_printf(
1052
       "%s: unsupported maximum data number of sectors not a multide of the grain number of sectors.\n",
1053
       function );
1054
    }
1055
  }
1056
#endif
1057
463
  if( extent_file->number_of_grain_table_entries > extent_file->maximum_data_size )
1058
49
  {
1059
49
    extent_file->number_of_grain_table_entries = (uint32_t) ( extent_file->maximum_data_size / extent_file->grain_size );
1060
1061
49
    if( ( extent_file->maximum_data_size % extent_file->grain_size ) != 0 )
1062
35
    {
1063
35
      extent_file->number_of_grain_table_entries += 1;
1064
35
    }
1065
#if defined( HAVE_DEBUG_OUTPUT )
1066
    if( libcnotify_verbose != 0 )
1067
    {
1068
      libcnotify_printf(
1069
       "%s: number of grain table entries exceeds maximum data number of sectors changing to: %" PRIu32 ".\n",
1070
       function,
1071
       extent_file->number_of_grain_table_entries );
1072
    }
1073
#endif
1074
49
  }
1075
463
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1076
463
  {
1077
463
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->single_end_of_line_character != (uint8_t) '\n' )
1078
32
    {
1079
32
      libcerror_error_set(
1080
32
       error,
1081
32
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1082
32
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1083
32
       "%s: unsupported single end of line character.",
1084
32
       function );
1085
1086
32
      return( -1 );
1087
32
    }
1088
431
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->non_end_of_line_character != (uint8_t) ' ' )
1089
10
    {
1090
10
      libcerror_error_set(
1091
10
       error,
1092
10
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1093
10
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1094
10
       "%s: unsupported non end of line character.",
1095
10
       function );
1096
1097
10
      return( -1 );
1098
10
    }
1099
421
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->first_double_end_of_line_character != (uint8_t) '\r' )
1100
1
    {
1101
1
      libcerror_error_set(
1102
1
       error,
1103
1
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1104
1
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1105
1
       "%s: unsupported first double end of line character.",
1106
1
       function );
1107
1108
1
      return( -1 );
1109
1
    }
1110
420
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->second_double_end_of_line_character != (uint8_t) '\n' )
1111
4
    {
1112
4
      libcerror_error_set(
1113
4
       error,
1114
4
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1115
4
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1116
4
       "%s: unsupported second double end of line character.",
1117
4
       function );
1118
1119
4
      return( -1 );
1120
4
    }
1121
420
  }
1122
416
  if( ( extent_file->compression_method != LIBVMDK_COMPRESSION_METHOD_NONE )
1123
120
   && ( extent_file->compression_method != LIBVMDK_COMPRESSION_METHOD_DEFLATE ) )
1124
9
  {
1125
9
    libcerror_error_set(
1126
9
     error,
1127
9
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1128
9
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1129
9
     "%s: unsupported compression method: %" PRIu16 ".",
1130
9
     function,
1131
9
     extent_file->compression_method );
1132
1133
9
    return( -1 );
1134
9
  }
1135
  /* Change all sector values to byte values
1136
   */
1137
407
  extent_file->maximum_data_size *= 512;
1138
407
  extent_file->grain_size        *= 512;
1139
1140
407
  if( ( extent_file->primary_grain_directory_offset >= 0 )
1141
334
   && ( extent_file->primary_grain_directory_offset <= (off64_t) ( INT64_MAX / 512 ) ) )
1142
310
  {
1143
310
    extent_file->primary_grain_directory_offset *= 512;
1144
310
  }
1145
  /* In a compressed VMDK sparse data file a primary grain directory sector of -1
1146
   * seems to indicate that there is a copy of the file header at the end of the file.
1147
   */
1148
97
  else if( ( extent_file->file_type != LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1149
97
        || ( extent_file->primary_grain_directory_offset != (off64_t) -1 )
1150
6
        || ( extent_file->compression_method != LIBVMDK_COMPRESSION_METHOD_DEFLATE ) )
1151
92
  {
1152
92
    libcerror_error_set(
1153
92
     error,
1154
92
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1155
92
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1156
92
     "%s: invalid primary grain directory offset value out of bounds.",
1157
92
     function );
1158
1159
92
    return( -1 );
1160
92
  }
1161
315
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_COWD_SPARSE_DATA )
1162
0
  {
1163
0
    extent_file->number_of_grain_table_entries = 4096;
1164
0
  }
1165
315
  else if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1166
315
  {
1167
315
    grain_table_size = (size64_t) extent_file->number_of_grain_table_entries * extent_file->grain_size;
1168
1169
315
    if( grain_table_size == 0 )
1170
1
    {
1171
1
      libcerror_error_set(
1172
1
       error,
1173
1
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1174
1
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1175
1
       "%s: invalid grain table size value out of bounds.",
1176
1
       function );
1177
1178
1
      return( -1 );
1179
1
    }
1180
314
    extent_file->number_of_grain_directory_entries = (uint32_t) ( extent_file->maximum_data_size / grain_table_size );
1181
1182
314
    if( ( extent_file->maximum_data_size % grain_table_size ) != 0 )
1183
294
    {
1184
294
      extent_file->number_of_grain_directory_entries += 1;
1185
294
    }
1186
314
    if( extent_file->descriptor_offset > (off64_t) ( INT64_MAX / 512 ) )
1187
15
    {
1188
15
      libcerror_error_set(
1189
15
       error,
1190
15
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1191
15
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1192
15
       "%s: invalid descriptor offset value out of bounds.",
1193
15
       function );
1194
1195
15
      return( -1 );
1196
15
    }
1197
299
    extent_file->descriptor_offset *= 512;
1198
299
    extent_file->descriptor_size   *= 512;
1199
1200
299
    extent_file->secondary_grain_directory_offset *= 512;
1201
299
  }
1202
#if defined( HAVE_DEBUG_OUTPUT )
1203
  if( libcnotify_verbose != 0 )
1204
  {
1205
    libcnotify_printf(
1206
     "%s: number of grain directory entries\t\t: %" PRIu32 "\n",
1207
     function,
1208
     extent_file->number_of_grain_directory_entries );
1209
  }
1210
#endif
1211
299
  if( extent_file->descriptor_size > (size_t) SSIZE_MAX )
1212
67
  {
1213
67
    libcerror_error_set(
1214
67
     error,
1215
67
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1216
67
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1217
67
     "%s: invalid descriptor size value exceeds maximum.",
1218
67
     function );
1219
1220
67
    return( -1 );
1221
67
  }
1222
232
  if( (size_t) extent_file->number_of_grain_directory_entries > (size_t) INT_MAX )
1223
32
  {
1224
32
    libcerror_error_set(
1225
32
     error,
1226
32
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1227
32
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1228
32
     "%s: invalid number of grain directory entries value exceeds maximum.",
1229
32
     function );
1230
1231
32
    return( -1 );
1232
32
  }
1233
#if SIZEOF_SIZE_T <= 4
1234
  if( (size_t) extent_file->number_of_grain_table_entries > (size_t) ( SSIZE_MAX / 4 ) )
1235
  {
1236
    libcerror_error_set(
1237
     error,
1238
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1239
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1240
     "%s: invalid grain table size value exceeds maximum.",
1241
     function );
1242
1243
    return( -1 );
1244
  }
1245
  if( (size_t) extent_file->number_of_grain_directory_entries > (size_t) ( SSIZE_MAX / 4 ) )
1246
  {
1247
    libcerror_error_set(
1248
     error,
1249
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1250
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1251
     "%s: invalid grain directory size value exceeds maximum.",
1252
     function );
1253
1254
    return( -1 );
1255
  }
1256
#endif
1257
200
  extent_file->grain_table_size = (size_t) extent_file->number_of_grain_table_entries * 4;
1258
1259
  /* The grain table data is sector aligned
1260
   */
1261
200
  if( ( extent_file->grain_table_size % 512 ) != 0 )
1262
122
  {
1263
122
    extent_file->grain_table_size /= 512;
1264
122
    extent_file->grain_table_size += 1;
1265
122
    extent_file->grain_table_size *= 512;
1266
122
  }
1267
200
  extent_file->grain_directory_size = (size_t) extent_file->number_of_grain_directory_entries * 4;
1268
1269
  /* The grain directory data is sector aligned
1270
   */
1271
200
  if( ( extent_file->grain_directory_size % 512 ) != 0 )
1272
186
  {
1273
186
    extent_file->grain_directory_size /= 512;
1274
186
    extent_file->grain_directory_size += 1;
1275
186
    extent_file->grain_directory_size *= 512;
1276
186
  }
1277
#if defined( HAVE_DEBUG_OUTPUT )
1278
  if( libcnotify_verbose != 0 )
1279
  {
1280
    libcnotify_printf(
1281
     "\n" );
1282
  }
1283
#endif
1284
200
  return( 1 );
1285
232
}
1286
1287
/* Reads the descriptor data from the extent file
1288
 * Returns 1 if successful, 0 if no descriptor data, or -1 on error
1289
 */
1290
int libvmdk_extent_file_read_descriptor_data_file_io_handle(
1291
     libvmdk_extent_file_t *extent_file,
1292
     libbfio_handle_t *file_io_handle,
1293
     uint8_t *descriptor_data,
1294
     size_t descriptor_data_size,
1295
     libcerror_error_t **error )
1296
146
{
1297
146
  static char *function = "libvmdk_extent_file_read_descriptor_data_file_io_handle";
1298
146
  ssize_t read_count    = 0;
1299
1300
146
  if( extent_file == NULL )
1301
0
  {
1302
0
    libcerror_error_set(
1303
0
     error,
1304
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1305
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1306
0
     "%s: invalid extent file.",
1307
0
     function );
1308
1309
0
    return( -1 );
1310
0
  }
1311
146
  if( descriptor_data == NULL )
1312
0
  {
1313
0
    libcerror_error_set(
1314
0
     error,
1315
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1316
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1317
0
     "%s: invalid descriptor data.",
1318
0
     function );
1319
1320
0
    return( -1 );
1321
0
  }
1322
146
  if( descriptor_data_size > (size_t) SSIZE_MAX )
1323
0
  {
1324
0
    libcerror_error_set(
1325
0
     error,
1326
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1327
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1328
0
     "%s: invalid descriptor data size value exceeds maximum.",
1329
0
     function );
1330
1331
0
    return( -1 );
1332
0
  }
1333
146
  if( descriptor_data_size < extent_file->descriptor_size )
1334
0
  {
1335
0
    libcerror_error_set(
1336
0
     error,
1337
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1338
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1339
0
     "%s: invalid descriptor data value too small.",
1340
0
     function );
1341
1342
0
    return( -1 );
1343
0
  }
1344
#if defined( HAVE_DEBUG_OUTPUT )
1345
  if( libcnotify_verbose != 0 )
1346
  {
1347
    libcnotify_printf(
1348
     "%s: reading descriptor at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1349
     function,
1350
     extent_file->descriptor_offset,
1351
     extent_file->descriptor_offset );
1352
  }
1353
#endif
1354
146
  read_count = libbfio_handle_read_buffer_at_offset(
1355
146
                file_io_handle,
1356
146
                descriptor_data,
1357
146
                (size_t) extent_file->descriptor_size,
1358
146
                extent_file->descriptor_offset,
1359
146
                error );
1360
1361
146
  if( read_count != (ssize_t) extent_file->descriptor_size )
1362
138
  {
1363
138
    libcerror_error_set(
1364
138
     error,
1365
138
     LIBCERROR_ERROR_DOMAIN_IO,
1366
138
     LIBCERROR_IO_ERROR_READ_FAILED,
1367
138
     "%s: unable to read descriptor data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1368
138
     function,
1369
138
     extent_file->descriptor_offset,
1370
138
     extent_file->descriptor_offset );
1371
1372
138
    return( -1 );
1373
138
  }
1374
8
  return( 1 );
1375
146
}
1376
1377
/* Reads the grain directories
1378
 * Returns 1 if successful or -1 on error
1379
 */
1380
int libvmdk_extent_file_read_grain_directories(
1381
     libvmdk_extent_file_t *extent_file,
1382
     libbfio_pool_t *file_io_pool,
1383
     int file_io_pool_entry,
1384
     libcerror_error_t **error )
1385
0
{
1386
0
  static char *function = "libvmdk_extent_file_read_grain_directories";
1387
1388
0
  if( extent_file == NULL )
1389
0
  {
1390
0
    libcerror_error_set(
1391
0
     error,
1392
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1393
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1394
0
     "%s: invalid extent file.",
1395
0
     function );
1396
1397
0
    return( -1 );
1398
0
  }
1399
0
  if( ( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1400
0
   && ( ( extent_file->flags & LIBVMDK_FLAG_USE_SECONDARY_GRAIN_DIRECTORY ) != 0 ) )
1401
0
  {
1402
0
    if( extent_file->secondary_grain_directory_offset < 0 )
1403
0
    {
1404
0
      libcerror_error_set(
1405
0
       error,
1406
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1407
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1408
0
       "%s: invalid secondary grain directory offset value out of bounds.",
1409
0
       function );
1410
1411
0
      return( -1 );
1412
0
    }
1413
0
    if( extent_file->secondary_grain_directory_offset == 0 )
1414
0
    {
1415
0
      libcerror_error_set(
1416
0
       error,
1417
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1418
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1419
0
       "%s: missing secondary grain directory offset.",
1420
0
       function );
1421
1422
0
      return( -1 );
1423
0
    }
1424
#if defined( HAVE_DEBUG_OUTPUT )
1425
    if( libcnotify_verbose != 0 )
1426
    {
1427
      libcnotify_printf(
1428
       "%s: reading secondary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1429
       function,
1430
       extent_file->secondary_grain_directory_offset,
1431
       extent_file->secondary_grain_directory_offset );
1432
    }
1433
#endif
1434
0
    if( libvmdk_extent_file_read_grain_directory(
1435
0
         extent_file,
1436
0
         file_io_pool,
1437
0
         file_io_pool_entry,
1438
0
         extent_file->secondary_grain_directory_offset,
1439
0
         error ) != 1 )
1440
0
    {
1441
0
      libcerror_error_set(
1442
0
       error,
1443
0
       LIBCERROR_ERROR_DOMAIN_IO,
1444
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1445
0
       "%s: unable to read secondary grain directory.",
1446
0
       function );
1447
1448
0
      return( -1 );
1449
0
    }
1450
0
    if( extent_file->primary_grain_directory_offset > 0 )
1451
0
    {
1452
#if defined( HAVE_DEBUG_OUTPUT )
1453
      if( libcnotify_verbose != 0 )
1454
      {
1455
        libcnotify_printf(
1456
         "%s: reading primary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1457
         function,
1458
         extent_file->primary_grain_directory_offset,
1459
         extent_file->primary_grain_directory_offset );
1460
      }
1461
#endif
1462
0
      if( libvmdk_extent_file_read_backup_grain_directory(
1463
0
           extent_file,
1464
0
           file_io_pool,
1465
0
           file_io_pool_entry,
1466
0
           extent_file->primary_grain_directory_offset,
1467
0
           error ) != 1 )
1468
0
      {
1469
0
        libcerror_error_set(
1470
0
         error,
1471
0
         LIBCERROR_ERROR_DOMAIN_IO,
1472
0
         LIBCERROR_IO_ERROR_READ_FAILED,
1473
0
         "%s: unable to read primary backup grain directory.",
1474
0
         function );
1475
1476
0
        return( -1 );
1477
0
      }
1478
0
    }
1479
0
  }
1480
0
  else
1481
0
  {
1482
0
    if( extent_file->primary_grain_directory_offset < 0 )
1483
0
    {
1484
0
      libcerror_error_set(
1485
0
       error,
1486
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1487
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1488
0
       "%s: invalid primary grain directory offset value out of bounds.",
1489
0
       function );
1490
1491
0
      return( -1 );
1492
0
    }
1493
0
    if( extent_file->primary_grain_directory_offset == 0 )
1494
0
    {
1495
0
      libcerror_error_set(
1496
0
       error,
1497
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1498
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1499
0
       "%s: missing primary grain directory offset.",
1500
0
       function );
1501
1502
0
      return( -1 );
1503
0
    }
1504
#if defined( HAVE_DEBUG_OUTPUT )
1505
    if( libcnotify_verbose != 0 )
1506
    {
1507
      libcnotify_printf(
1508
       "%s: reading primary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1509
       function,
1510
       extent_file->primary_grain_directory_offset,
1511
       extent_file->primary_grain_directory_offset );
1512
    }
1513
#endif
1514
0
    if( libvmdk_extent_file_read_grain_directory(
1515
0
         extent_file,
1516
0
         file_io_pool,
1517
0
         file_io_pool_entry,
1518
0
         extent_file->primary_grain_directory_offset,
1519
0
         error ) != 1 )
1520
0
    {
1521
0
      libcerror_error_set(
1522
0
       error,
1523
0
       LIBCERROR_ERROR_DOMAIN_IO,
1524
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1525
0
       "%s: unable to read primary grain directory.",
1526
0
       function );
1527
1528
0
      return( -1 );
1529
0
    }
1530
0
    if( extent_file->secondary_grain_directory_offset > 0 )
1531
0
    {
1532
#if defined( HAVE_DEBUG_OUTPUT )
1533
      if( libcnotify_verbose != 0 )
1534
      {
1535
        libcnotify_printf(
1536
         "%s: reading secondary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1537
         function,
1538
         extent_file->secondary_grain_directory_offset,
1539
         extent_file->secondary_grain_directory_offset );
1540
      }
1541
#endif
1542
0
      if( libvmdk_extent_file_read_backup_grain_directory(
1543
0
           extent_file,
1544
0
           file_io_pool,
1545
0
           file_io_pool_entry,
1546
0
           extent_file->secondary_grain_directory_offset,
1547
0
           error ) != 1 )
1548
0
      {
1549
0
        libcerror_error_set(
1550
0
         error,
1551
0
         LIBCERROR_ERROR_DOMAIN_IO,
1552
0
         LIBCERROR_IO_ERROR_READ_FAILED,
1553
0
         "%s: unable to read secondary backup grain directory.",
1554
0
         function );
1555
1556
0
        return( -1 );
1557
0
      }
1558
0
    }
1559
0
  }
1560
0
  return( 1 );
1561
0
}
1562
1563
/* Reads the grain directory
1564
 * Returns 1 if successful or -1 on error
1565
 */
1566
int libvmdk_extent_file_read_grain_directory(
1567
     libvmdk_extent_file_t *extent_file,
1568
     libbfio_pool_t *file_io_pool,
1569
     int file_io_pool_entry,
1570
     off64_t file_offset,
1571
     libcerror_error_t **error )
1572
0
{
1573
0
  uint8_t *grain_directory_data        = NULL;
1574
0
  uint8_t *grain_directory_entry       = NULL;
1575
0
  static char *function                = "libvmdk_extent_file_read_grain_directory";
1576
0
  off64_t grain_table_offset           = 0;
1577
0
  size64_t grain_data_size             = 0;
1578
0
  size64_t storage_media_size          = 0;
1579
0
  size64_t total_grain_data_size       = 0;
1580
0
  ssize_t read_count                   = 0;
1581
0
  uint32_t grain_directory_entry_index = 0;
1582
0
  uint32_t range_flags                 = 0;
1583
0
  int element_index                    = 0;
1584
0
  int number_of_grain_table_entries    = 0;
1585
1586
#if defined( HAVE_DEBUG_OUTPUT )
1587
  int result                           = 0;
1588
#endif
1589
1590
0
  if( extent_file == NULL )
1591
0
  {
1592
0
    libcerror_error_set(
1593
0
     error,
1594
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1595
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1596
0
     "%s: invalid extent file.",
1597
0
     function );
1598
1599
0
    return( -1 );
1600
0
  }
1601
0
  if( ( extent_file->grain_directory_size == 0 )
1602
0
   || ( extent_file->grain_directory_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
1603
0
  {
1604
0
    libcerror_error_set(
1605
0
     error,
1606
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1607
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1608
0
     "%s: invalid extent file - grain directory size value out of bounds.",
1609
0
     function );
1610
1611
0
    goto on_error;
1612
0
  }
1613
#if defined( HAVE_DEBUG_OUTPUT )
1614
  if( libcnotify_verbose != 0 )
1615
  {
1616
    libcnotify_printf(
1617
     "%s: reading grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1618
     function,
1619
     file_offset,
1620
     file_offset );
1621
  }
1622
#endif
1623
0
  if( libbfio_pool_seek_offset(
1624
0
       file_io_pool,
1625
0
       file_io_pool_entry,
1626
0
       file_offset,
1627
0
       SEEK_SET,
1628
0
       error ) == -1 )
1629
0
  {
1630
0
    libcerror_error_set(
1631
0
     error,
1632
0
     LIBCERROR_ERROR_DOMAIN_IO,
1633
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
1634
0
     "%s: unable to seek grain directory offset: %" PRIi64 ".",
1635
0
     function,
1636
0
     file_offset );
1637
1638
0
    goto on_error;
1639
0
  }
1640
0
  grain_directory_data = (uint8_t *) memory_allocate(
1641
0
                                      sizeof( uint8_t ) * extent_file->grain_directory_size );
1642
1643
0
  if( grain_directory_data == NULL )
1644
0
  {
1645
0
    libcerror_error_set(
1646
0
     error,
1647
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1648
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1649
0
     "%s: unable to create grain directory data.",
1650
0
     function );
1651
1652
0
    goto on_error;
1653
0
  }
1654
0
  read_count = libbfio_pool_read_buffer(
1655
0
                file_io_pool,
1656
0
                file_io_pool_entry,
1657
0
                grain_directory_data,
1658
0
                extent_file->grain_directory_size,
1659
0
                error );
1660
1661
0
  if( read_count != (ssize_t) extent_file->grain_directory_size )
1662
0
  {
1663
0
    libcerror_error_set(
1664
0
     error,
1665
0
     LIBCERROR_ERROR_DOMAIN_IO,
1666
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1667
0
     "%s: unable to read grain directory data.",
1668
0
     function );
1669
1670
0
    goto on_error;
1671
0
  }
1672
#if defined( HAVE_DEBUG_OUTPUT )
1673
  if( libcnotify_verbose != 0 )
1674
  {
1675
    libcnotify_printf(
1676
     "%s: grain directory data:\n",
1677
     function );
1678
    libcnotify_print_data(
1679
     grain_directory_data,
1680
     extent_file->grain_directory_size,
1681
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1682
  }
1683
#endif
1684
0
  grain_directory_entry = grain_directory_data;
1685
1686
0
  for( grain_directory_entry_index = 0;
1687
0
       grain_directory_entry_index < extent_file->number_of_grain_directory_entries;
1688
0
       grain_directory_entry_index++ )
1689
0
  {
1690
0
    byte_stream_copy_to_uint32_little_endian(
1691
0
     grain_directory_entry,
1692
0
     grain_table_offset );
1693
1694
#if defined( HAVE_DEBUG_OUTPUT )
1695
    if( libcnotify_verbose != 0 )
1696
    {
1697
      libcnotify_printf(
1698
       "%s: grain directory entry: %05" PRIu32 " sector number\t\t: %" PRIi64 "\n",
1699
       function,
1700
       grain_directory_entry_index,
1701
       grain_table_offset );
1702
    }
1703
#endif
1704
0
    if( grain_table_offset != 0 )
1705
0
    {
1706
0
      range_flags         = 0;
1707
0
      grain_table_offset *= 512;
1708
0
    }
1709
0
    else
1710
0
    {
1711
0
      range_flags = LIBVMDK_RANGE_FLAG_IS_SPARSE;
1712
0
    }
1713
0
    number_of_grain_table_entries = (int) extent_file->number_of_grain_table_entries;
1714
0
    grain_data_size               = number_of_grain_table_entries * extent_file->grain_size;
1715
1716
0
    if( ( total_grain_data_size + grain_data_size ) > extent_file->maximum_data_size )
1717
0
    {
1718
0
      grain_data_size = extent_file->maximum_data_size - total_grain_data_size;
1719
1720
0
      number_of_grain_table_entries = (int)( grain_data_size / extent_file->grain_size );
1721
1722
0
      if( ( grain_data_size % extent_file->grain_size ) != 0 )
1723
0
      {
1724
0
        number_of_grain_table_entries += 1;
1725
0
      }
1726
0
    }
1727
#if defined( HAVE_DEBUG_OUTPUT )
1728
    if( libcnotify_verbose != 0 )
1729
    {
1730
      libcnotify_printf(
1731
       "%s: grain directory entry: %05" PRIu32 " offset\t\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
1732
       function,
1733
       grain_directory_entry_index,
1734
       grain_table_offset * 512,
1735
       grain_table_offset * 512 );
1736
1737
      libcnotify_printf(
1738
       "%s: grain directory entry: %05" PRIu32 " size\t\t\t: %" PRIu64 " (%d)\n",
1739
       function,
1740
       grain_directory_entry_index,
1741
       grain_data_size,
1742
       number_of_grain_table_entries );
1743
1744
      libcnotify_printf(
1745
       "%s: grain directory entry: %05" PRIu32 " file IO pool entry\t: %d\n",
1746
       function,
1747
       grain_directory_entry_index,
1748
       file_io_pool_entry );
1749
1750
      libcnotify_printf(
1751
       "%s: grain directory entry: %05" PRIu32 " range flags\t\t: 0x%08" PRIx64 "\n",
1752
       function,
1753
       grain_directory_entry_index,
1754
       range_flags );
1755
1756
      if( ( range_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
1757
      {
1758
        libcnotify_printf(
1759
         "\tIs sparse.\n" );
1760
      }
1761
      libcnotify_printf(
1762
       "\n" );
1763
    }
1764
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1765
1766
0
    storage_media_size = (size64_t) extent_file->grain_size * number_of_grain_table_entries;
1767
1768
0
    if( libfdata_list_append_element_with_mapped_size(
1769
0
         extent_file->grain_groups_list,
1770
0
         &element_index,
1771
0
         file_io_pool_entry,
1772
0
         grain_table_offset,
1773
0
         (size64_t) extent_file->grain_table_size,
1774
0
         range_flags,
1775
0
         storage_media_size,
1776
0
         error ) != 1 )
1777
0
    {
1778
0
      libcerror_error_set(
1779
0
       error,
1780
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1781
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1782
0
       "%s: unable to append element with mapped size to grain groups list.",
1783
0
       function );
1784
1785
0
      goto on_error;
1786
0
    }
1787
0
    total_grain_data_size           += grain_data_size;
1788
0
    grain_directory_entry           += sizeof( uint32_t );
1789
0
    extent_file->storage_media_size += storage_media_size;
1790
0
  }
1791
#if defined( HAVE_DEBUG_OUTPUT )
1792
  if( libcnotify_verbose != 0 )
1793
  {
1794
    if( total_grain_data_size < extent_file->grain_directory_size )
1795
    {
1796
      result = libvmdk_extent_file_check_for_empty_block(
1797
          grain_directory_entry,
1798
          extent_file->grain_directory_size - total_grain_data_size,
1799
                error );
1800
1801
      if( result == -1 )
1802
      {
1803
        libcerror_error_set(
1804
         error,
1805
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1806
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1807
         "%s: unable to determine if remainder of grain directory is empty.",
1808
         function );
1809
1810
        goto on_error;
1811
      }
1812
      else if( result == 0 )
1813
      {
1814
        libcnotify_printf(
1815
         "%s: remainder of grain directory not empty.",
1816
         function );
1817
      }
1818
    }
1819
  }
1820
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1821
1822
0
  memory_free(
1823
0
   grain_directory_data );
1824
1825
0
  grain_directory_data = NULL;
1826
1827
0
  return( 1 );
1828
1829
0
on_error:
1830
0
  if( grain_directory_data != NULL )
1831
0
  {
1832
0
    memory_free(
1833
0
     grain_directory_data );
1834
0
  }
1835
0
  return( -1 );
1836
0
}
1837
1838
/* Reads the backup grain directory
1839
 * Returns 1 if successful or -1 on error
1840
 */
1841
int libvmdk_extent_file_read_backup_grain_directory(
1842
     libvmdk_extent_file_t *extent_file,
1843
     libbfio_pool_t *file_io_pool,
1844
     int file_io_pool_entry,
1845
     off64_t file_offset,
1846
     libcerror_error_t **error )
1847
0
{
1848
0
  uint8_t *grain_directory_data        = NULL;
1849
0
  uint8_t *grain_directory_entry       = NULL;
1850
0
  static char *function                = "libvmdk_extent_file_read_backup_grain_directory";
1851
0
  off64_t grain_group_offset           = 0;
1852
0
  size64_t grain_data_size             = 0;
1853
0
  size64_t grain_group_size            = 0;
1854
0
  size64_t total_grain_data_size       = 0;
1855
0
  ssize_t read_count                   = 0;
1856
0
  uint32_t grain_directory_entry_index = 0;
1857
0
  uint32_t grain_group_range_flags     = 0;
1858
0
  int grain_group_file_io_pool_entry   = 0;
1859
0
  int number_of_grain_table_entries    = 0;
1860
1861
#if defined( HAVE_DEBUG_OUTPUT )
1862
  off64_t grain_table_offset           = 0;
1863
  uint32_t range_flags                 = 0;
1864
  int result                           = 0;
1865
#endif
1866
1867
0
  if( extent_file == NULL )
1868
0
  {
1869
0
    libcerror_error_set(
1870
0
     error,
1871
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1872
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1873
0
     "%s: invalid extent file.",
1874
0
     function );
1875
1876
0
    return( -1 );
1877
0
  }
1878
0
  if( ( extent_file->grain_directory_size == 0 )
1879
0
   || ( extent_file->grain_directory_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
1880
0
  {
1881
0
    libcerror_error_set(
1882
0
     error,
1883
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1884
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1885
0
     "%s: invalid extent file - grain directory size value out of bounds.",
1886
0
     function );
1887
1888
0
    goto on_error;
1889
0
  }
1890
#if defined( HAVE_DEBUG_OUTPUT )
1891
  if( libcnotify_verbose != 0 )
1892
  {
1893
    libcnotify_printf(
1894
     "%s: reading backup grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1895
     function,
1896
     file_offset,
1897
     file_offset );
1898
  }
1899
#endif
1900
0
  if( libbfio_pool_seek_offset(
1901
0
       file_io_pool,
1902
0
       file_io_pool_entry,
1903
0
       file_offset,
1904
0
       SEEK_SET,
1905
0
       error ) == -1 )
1906
0
  {
1907
0
    libcerror_error_set(
1908
0
     error,
1909
0
     LIBCERROR_ERROR_DOMAIN_IO,
1910
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
1911
0
     "%s: unable to seek backup grain directory offset: %" PRIi64 ".",
1912
0
     function,
1913
0
     file_offset );
1914
1915
0
    goto on_error;
1916
0
  }
1917
0
  grain_directory_data = (uint8_t *) memory_allocate(
1918
0
                                      sizeof( uint8_t ) * extent_file->grain_directory_size );
1919
1920
0
  if( grain_directory_data == NULL )
1921
0
  {
1922
0
    libcerror_error_set(
1923
0
     error,
1924
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1925
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1926
0
     "%s: unable to create grain directory data.",
1927
0
     function );
1928
1929
0
    goto on_error;
1930
0
  }
1931
0
  read_count = libbfio_pool_read_buffer(
1932
0
                file_io_pool,
1933
0
                file_io_pool_entry,
1934
0
                grain_directory_data,
1935
0
                extent_file->grain_directory_size,
1936
0
                error );
1937
1938
0
  if( read_count != (ssize_t) extent_file->grain_directory_size )
1939
0
  {
1940
0
    libcerror_error_set(
1941
0
     error,
1942
0
     LIBCERROR_ERROR_DOMAIN_IO,
1943
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1944
0
     "%s: unable to read grain directory data.",
1945
0
     function );
1946
1947
0
    goto on_error;
1948
0
  }
1949
#if defined( HAVE_DEBUG_OUTPUT )
1950
  if( libcnotify_verbose != 0 )
1951
  {
1952
    libcnotify_printf(
1953
     "%s: grain directory data:\n",
1954
     function );
1955
    libcnotify_print_data(
1956
     grain_directory_data,
1957
     extent_file->grain_directory_size,
1958
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1959
  }
1960
#endif
1961
0
  grain_directory_entry = grain_directory_data;
1962
1963
0
  for( grain_directory_entry_index = 0;
1964
0
       grain_directory_entry_index < extent_file->number_of_grain_directory_entries;
1965
0
       grain_directory_entry_index++ )
1966
0
  {
1967
#if defined( HAVE_DEBUG_OUTPUT )
1968
    byte_stream_copy_to_uint32_little_endian(
1969
     grain_directory_entry,
1970
     grain_table_offset );
1971
1972
    if( libcnotify_verbose != 0 )
1973
    {
1974
      libcnotify_printf(
1975
       "%s: grain directory entry: %05" PRIu32 " sector number\t\t: %" PRIi64 "\n",
1976
       function,
1977
       grain_directory_entry_index,
1978
       grain_table_offset );
1979
    }
1980
    if( grain_table_offset != 0 )
1981
    {
1982
      range_flags         = 0;
1983
      grain_table_offset *= 512;
1984
    }
1985
    else
1986
    {
1987
      range_flags = LIBVMDK_RANGE_FLAG_IS_SPARSE;
1988
    }
1989
#endif
1990
0
    number_of_grain_table_entries = (int) extent_file->number_of_grain_table_entries;
1991
0
    grain_data_size               = number_of_grain_table_entries * extent_file->grain_size;
1992
1993
0
    if( ( total_grain_data_size + grain_data_size ) > extent_file->maximum_data_size )
1994
0
    {
1995
0
      grain_data_size = extent_file->maximum_data_size - total_grain_data_size;
1996
1997
#if defined( HAVE_DEBUG_OUTPUT )
1998
      number_of_grain_table_entries = (int) ( grain_data_size / extent_file->grain_size );
1999
2000
      if( ( grain_data_size % extent_file->grain_size ) != 0 )
2001
      {
2002
        number_of_grain_table_entries += 1;
2003
      }
2004
#endif
2005
0
    }
2006
#if defined( HAVE_DEBUG_OUTPUT )
2007
    if( libcnotify_verbose != 0 )
2008
    {
2009
      libcnotify_printf(
2010
       "%s: grain directory entry: %05" PRIu32 " offset\t\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
2011
       function,
2012
       grain_directory_entry_index,
2013
       grain_table_offset * 512,
2014
       grain_table_offset * 512 );
2015
2016
      libcnotify_printf(
2017
       "%s: grain directory entry: %05" PRIu32 " size\t\t\t: %" PRIu64 " (%d)\n",
2018
       function,
2019
       grain_directory_entry_index,
2020
       grain_data_size,
2021
       number_of_grain_table_entries );
2022
2023
      libcnotify_printf(
2024
       "%s: grain directory entry: %05" PRIu32 " file IO pool entry\t: %d\n",
2025
       function,
2026
       grain_directory_entry_index,
2027
       file_io_pool_entry );
2028
2029
      libcnotify_printf(
2030
       "%s: grain directory entry: %05" PRIu32 " range flags\t\t: 0x%08" PRIx64 "\n",
2031
       function,
2032
       grain_directory_entry_index,
2033
       range_flags );
2034
2035
      if( ( range_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
2036
      {
2037
        libcnotify_printf(
2038
         "\tIs sparse.\n" );
2039
      }
2040
      libcnotify_printf(
2041
       "\n" );
2042
    }
2043
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
2044
2045
0
    if( libfdata_list_get_element_by_index(
2046
0
         extent_file->grain_groups_list,
2047
0
         grain_directory_entry_index,
2048
0
         &grain_group_file_io_pool_entry,
2049
0
         &grain_group_offset,
2050
0
         &grain_group_size,
2051
0
         &grain_group_range_flags,
2052
0
         error ) != 1 )
2053
0
    {
2054
0
      libcerror_error_set(
2055
0
       error,
2056
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2057
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2058
0
       "%s: unable to retrieve element: %d from chunk groups list.",
2059
0
       function,
2060
0
       grain_directory_entry_index );
2061
2062
0
      goto on_error;
2063
0
    }
2064
/* TODO compare grain directory entry with back up ? */
2065
2066
0
    total_grain_data_size += grain_data_size;
2067
0
    grain_directory_entry += sizeof( uint32_t );
2068
0
  }
2069
#if defined( HAVE_DEBUG_OUTPUT )
2070
  if( libcnotify_verbose != 0 )
2071
  {
2072
    if( total_grain_data_size < extent_file->grain_directory_size )
2073
    {
2074
      result = libvmdk_extent_file_check_for_empty_block(
2075
          grain_directory_entry,
2076
          extent_file->grain_directory_size - total_grain_data_size,
2077
                error );
2078
2079
      if( result == -1 )
2080
      {
2081
        libcerror_error_set(
2082
         error,
2083
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
2084
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2085
         "%s: unable to determine if remainder of grain directory is empty.",
2086
         function );
2087
2088
        goto on_error;
2089
      }
2090
      else if( result == 0 )
2091
      {
2092
        libcnotify_printf(
2093
         "%s: remainder of grain directory not empty.",
2094
         function );
2095
      }
2096
    }
2097
  }
2098
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
2099
2100
0
  memory_free(
2101
0
   grain_directory_data );
2102
2103
0
  grain_directory_data = NULL;
2104
2105
0
  return( 1 );
2106
2107
0
on_error:
2108
0
  if( grain_directory_data != NULL )
2109
0
  {
2110
0
    memory_free(
2111
0
     grain_directory_data );
2112
0
  }
2113
0
  return( -1 );
2114
0
}
2115
2116
/* Reads the extent file
2117
 * Callback function for the extent files list
2118
 * Returns 1 if successful or -1 on error
2119
 */
2120
int libvmdk_extent_file_read_element_data(
2121
     libvmdk_io_handle_t *io_handle,
2122
     libbfio_pool_t *file_io_pool,
2123
     libfdata_list_element_t *element,
2124
     libfdata_cache_t *cache,
2125
     int file_io_pool_entry,
2126
     off64_t element_offset LIBVMDK_ATTRIBUTE_UNUSED,
2127
     size64_t extent_file_size,
2128
     uint32_t element_flags LIBVMDK_ATTRIBUTE_UNUSED,
2129
     uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
2130
     libcerror_error_t **error )
2131
0
{
2132
0
  libvmdk_extent_file_t *extent_file = NULL;
2133
0
  static char *function              = "libvmdk_extent_file_read_element_data";
2134
2135
0
  LIBVMDK_UNREFERENCED_PARAMETER( element_offset )
2136
0
  LIBVMDK_UNREFERENCED_PARAMETER( element_flags )
2137
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
2138
2139
0
  if( io_handle == NULL )
2140
0
  {
2141
0
    libcerror_error_set(
2142
0
     error,
2143
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2144
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2145
0
     "%s: invalid IO handle.",
2146
0
     function );
2147
2148
0
    return( -1 );
2149
0
  }
2150
0
  if( libvmdk_extent_file_initialize(
2151
0
       &extent_file,
2152
0
       io_handle,
2153
0
       error ) != 1 )
2154
0
  {
2155
0
    libcerror_error_set(
2156
0
     error,
2157
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2158
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2159
0
     "%s: unable to create extent file.",
2160
0
     function );
2161
2162
0
    goto on_error;
2163
0
  }
2164
0
  if( libvmdk_extent_file_read_file_header(
2165
0
       extent_file,
2166
0
       file_io_pool,
2167
0
       file_io_pool_entry,
2168
0
       0,
2169
0
       error ) != 1 )
2170
0
  {
2171
0
    libcerror_error_set(
2172
0
     error,
2173
0
     LIBCERROR_ERROR_DOMAIN_IO,
2174
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2175
0
     "%s: unable to read extent file header from file IO pool entry: %d.",
2176
0
     function,
2177
0
     file_io_pool_entry );
2178
2179
0
    goto on_error;
2180
0
  }
2181
0
  if( ( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
2182
0
   && ( extent_file->primary_grain_directory_offset == (off64_t) -1 )
2183
0
   && ( extent_file->compression_method == LIBVMDK_COMPRESSION_METHOD_DEFLATE ) )
2184
0
  {
2185
0
    if( libvmdk_extent_file_read_file_header(
2186
0
         extent_file,
2187
0
         file_io_pool,
2188
0
         file_io_pool_entry,
2189
0
         extent_file_size - 1024,
2190
0
         error ) != 1 )
2191
0
    {
2192
0
      libcerror_error_set(
2193
0
       error,
2194
0
       LIBCERROR_ERROR_DOMAIN_IO,
2195
0
       LIBCERROR_IO_ERROR_READ_FAILED,
2196
0
       "%s: unable to read secondary extent file header from file IO pool entry: %d.",
2197
0
       function,
2198
0
       file_io_pool_entry );
2199
2200
0
      goto on_error;
2201
0
    }
2202
0
  }
2203
0
  if( libvmdk_extent_file_read_grain_directory(
2204
0
       extent_file,
2205
0
       file_io_pool,
2206
0
       file_io_pool_entry,
2207
0
       extent_file->primary_grain_directory_offset,
2208
0
       error ) != 1 )
2209
0
  {
2210
0
    libcerror_error_set(
2211
0
     error,
2212
0
     LIBCERROR_ERROR_DOMAIN_IO,
2213
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2214
0
     "%s: unable to read primary grain directory.",
2215
0
     function );
2216
2217
0
    goto on_error;
2218
0
  }
2219
0
  if( libfdata_list_element_set_element_value(
2220
0
       element,
2221
0
       (intptr_t *) file_io_pool,
2222
0
       cache,
2223
0
       (intptr_t *) extent_file,
2224
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libvmdk_extent_file_free,
2225
0
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
2226
0
       error ) != 1 )
2227
0
  {
2228
0
    libcerror_error_set(
2229
0
     error,
2230
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2231
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2232
0
     "%s: unable to set extent file as element value.",
2233
0
     function );
2234
2235
0
    goto on_error;
2236
0
  }
2237
0
  return( 1 );
2238
2239
0
on_error:
2240
0
  if( extent_file != NULL )
2241
0
  {
2242
0
    libvmdk_extent_file_free(
2243
0
     &extent_file,
2244
0
     NULL );
2245
0
  }
2246
0
  return( -1 );
2247
0
}
2248
2249
/* Reads a grain group
2250
 * Callback function for the grain groups list
2251
 * Returns 1 if successful or -1 on error
2252
 */
2253
int libvmdk_extent_file_read_grain_group_element_data(
2254
     libvmdk_extent_file_t *extent_file,
2255
     libbfio_pool_t *file_io_pool,
2256
     libfdata_list_element_t *element,
2257
     libfdata_cache_t *cache,
2258
     int file_io_pool_entry,
2259
     off64_t grain_group_data_offset,
2260
     size64_t grain_group_data_size,
2261
     uint32_t grain_group_data_flags,
2262
     uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
2263
     libcerror_error_t **error )
2264
0
{
2265
0
  libfdata_list_t *grains_list = NULL;
2266
0
  uint8_t *grain_table_data    = NULL;
2267
0
  static char *function        = "libvmdk_extent_file_read_grain_group_element_data";
2268
0
  ssize_t read_count           = 0;
2269
0
  int grain_index              = 0;
2270
0
  int number_of_entries        = 0;
2271
2272
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
2273
2274
0
  if( extent_file == NULL )
2275
0
  {
2276
0
    libcerror_error_set(
2277
0
     error,
2278
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2279
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2280
0
     "%s: invalid extent file.",
2281
0
     function );
2282
2283
0
    return( -1 );
2284
0
  }
2285
0
  if( extent_file->grain_groups_list == NULL )
2286
0
  {
2287
0
    libcerror_error_set(
2288
0
     error,
2289
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2290
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2291
0
     "%s: invalid extent file - missing grain groups list.",
2292
0
     function );
2293
2294
0
    return( -1 );
2295
0
  }
2296
0
  if( extent_file->io_handle == NULL )
2297
0
  {
2298
0
    libcerror_error_set(
2299
0
     error,
2300
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2301
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2302
0
     "%s: invalid extent file - missing IO handle.",
2303
0
     function );
2304
2305
0
    return( -1 );
2306
0
  }
2307
0
  if( ( grain_group_data_size == 0 )
2308
0
   || ( grain_group_data_size > (size64_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
2309
0
  {
2310
0
    libcerror_error_set(
2311
0
     error,
2312
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2313
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2314
0
     "%s: invalid grain group data size value out of bounds.",
2315
0
     function );
2316
2317
0
    goto on_error;
2318
0
  }
2319
0
  grain_table_data = (uint8_t *) memory_allocate(
2320
0
                                  sizeof( uint8_t ) * (size_t) grain_group_data_size );
2321
2322
0
  if( grain_table_data == NULL )
2323
0
  {
2324
0
    libcerror_error_set(
2325
0
     error,
2326
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
2327
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2328
0
     "%s: unable to create grain table data.",
2329
0
     function );
2330
2331
0
    goto on_error;
2332
0
  }
2333
0
  if( ( grain_group_data_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
2334
0
  {
2335
0
    libcerror_error_set(
2336
0
     error,
2337
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2338
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
2339
0
     "%s: sparse grain table not supported.",
2340
0
     function );
2341
2342
0
    goto on_error;
2343
0
  }
2344
#if defined( HAVE_DEBUG_OUTPUT )
2345
  if( libcnotify_verbose != 0 )
2346
  {
2347
    libcnotify_printf(
2348
     "%s: reading grain table at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
2349
     function,
2350
     grain_group_data_offset,
2351
     grain_group_data_offset );
2352
  }
2353
#endif
2354
0
  if( libbfio_pool_seek_offset(
2355
0
       file_io_pool,
2356
0
       file_io_pool_entry,
2357
0
       grain_group_data_offset,
2358
0
       SEEK_SET,
2359
0
       error ) == -1 )
2360
0
  {
2361
0
    libcerror_error_set(
2362
0
     error,
2363
0
     LIBCERROR_ERROR_DOMAIN_IO,
2364
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
2365
0
     "%s: unable to seek grain table offset: %" PRIi64 ".",
2366
0
     function,
2367
0
     grain_group_data_offset );
2368
2369
0
    goto on_error;
2370
0
  }
2371
0
  read_count = libbfio_pool_read_buffer(
2372
0
                file_io_pool,
2373
0
                file_io_pool_entry,
2374
0
                grain_table_data,
2375
0
                (size_t) grain_group_data_size,
2376
0
                error );
2377
2378
0
  if( read_count != (ssize_t) grain_group_data_size )
2379
0
  {
2380
0
    libcerror_error_set(
2381
0
     error,
2382
0
     LIBCERROR_ERROR_DOMAIN_IO,
2383
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2384
0
     "%s: unable to read grain table data.",
2385
0
     function );
2386
2387
0
    goto on_error;
2388
0
  }
2389
#if defined( HAVE_DEBUG_OUTPUT )
2390
  if( libcnotify_verbose != 0 )
2391
  {
2392
    libcnotify_printf(
2393
     "%s: grain table data:\n",
2394
     function );
2395
    libcnotify_print_data(
2396
     grain_table_data,
2397
     (size_t) grain_group_data_size,
2398
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
2399
  }
2400
#endif
2401
0
  if( libfdata_list_initialize(
2402
0
       &grains_list,
2403
0
       (intptr_t *) extent_file->io_handle,
2404
0
       NULL,
2405
0
       NULL,
2406
0
       (int (*)(intptr_t *, intptr_t *, libfdata_list_element_t *, libfdata_cache_t *, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libvmdk_grain_data_read_element_data,
2407
0
       NULL,
2408
0
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
2409
0
       error ) != 1 )
2410
0
  {
2411
0
    libcerror_error_set(
2412
0
     error,
2413
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2414
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2415
0
     "%s: unable to create grains list.",
2416
0
     function );
2417
2418
0
    goto on_error;
2419
0
  }
2420
/* TODO makes sure to compensate for the last grain table */
2421
0
  number_of_entries = extent_file->number_of_grain_table_entries;
2422
2423
0
  if( libvmdk_grain_group_fill(
2424
0
       grains_list,
2425
0
       grain_index,
2426
0
       extent_file->io_handle->grain_size,
2427
0
       file_io_pool,
2428
0
       file_io_pool_entry,
2429
0
       grain_table_data,
2430
0
       (size_t) grain_group_data_size,
2431
0
       number_of_entries,
2432
0
       extent_file->flags,
2433
0
       error ) != 1 )
2434
0
  {
2435
0
    libcerror_error_set(
2436
0
     error,
2437
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2438
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2439
0
     "%s: unable to fill grain table.",
2440
0
     function );
2441
2442
0
    goto on_error;
2443
0
  }
2444
/* TODO what about backup range */
2445
/* TODO check if remainder of sector block is empty */
2446
2447
0
  memory_free(
2448
0
   grain_table_data );
2449
2450
0
  grain_table_data = NULL;
2451
2452
0
  if( libfdata_list_element_set_element_value(
2453
0
       element,
2454
0
       (intptr_t *) file_io_pool,
2455
0
       cache,
2456
0
       (intptr_t *) grains_list,
2457
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libfdata_list_free,
2458
0
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
2459
0
       error ) != 1 )
2460
0
  {
2461
0
    libcerror_error_set(
2462
0
     error,
2463
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2464
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2465
0
     "%s: unable to set grains list as element value.",
2466
0
     function );
2467
2468
0
    goto on_error;
2469
0
  }
2470
0
  return( 1 );
2471
2472
0
on_error:
2473
0
  if( grains_list != NULL )
2474
0
  {
2475
0
    libfdata_list_free(
2476
0
     &grains_list,
2477
0
     NULL );
2478
0
  }
2479
0
  if( grain_table_data != NULL )
2480
0
  {
2481
0
    memory_free(
2482
0
     grain_table_data );
2483
0
  }
2484
0
  return( -1 );
2485
0
}
2486
2487
/* Determines if the grain group at a specific offset is sparse
2488
 * Returns 1 if the grain is sparse, 0 if not or -1 on error
2489
 */
2490
int libvmdk_extent_file_grain_group_is_sparse_at_offset(
2491
     libvmdk_extent_file_t *extent_file,
2492
     off64_t offset,
2493
     int *grain_group_index,
2494
     off64_t *grain_group_data_offset,
2495
     libcerror_error_t **error )
2496
0
{
2497
0
  static char *function      = "libvmdk_extent_file_grain_group_is_sparse_at_offset";
2498
0
  off64_t grain_group_offset = 0;
2499
0
  size64_t grain_group_size  = 0;
2500
0
  uint32_t grain_group_flags = 0;
2501
0
  int grain_group_file_index = 0;
2502
0
  int result                 = 0;
2503
2504
0
  if( extent_file == NULL )
2505
0
  {
2506
0
    libcerror_error_set(
2507
0
     error,
2508
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2509
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2510
0
     "%s: invalid extent file.",
2511
0
     function );
2512
2513
0
    return( -1 );
2514
0
  }
2515
0
  result = libfdata_list_get_element_at_offset(
2516
0
      extent_file->grain_groups_list,
2517
0
      offset,
2518
0
      grain_group_index,
2519
0
      grain_group_data_offset,
2520
0
      &grain_group_file_index,
2521
0
      &grain_group_offset,
2522
0
      &grain_group_size,
2523
0
      &grain_group_flags,
2524
0
      error );
2525
2526
0
  if( result != 1 )
2527
0
  {
2528
0
    libcerror_error_set(
2529
0
     error,
2530
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2531
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2532
0
     "%s: unable to retrieve grains group element at offset: %" PRIi64 ".",
2533
0
     function,
2534
0
     offset );
2535
2536
0
    return( -1 );
2537
0
  }
2538
0
  if( ( grain_group_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
2539
0
  {
2540
0
    return( 1 );
2541
0
  }
2542
0
  return( 0 );
2543
0
}
2544
2545
/* Retrieves the grain group at a specific offset
2546
 * Returns 1 if successful, 0 if not or -1 on error
2547
 */
2548
int libvmdk_extent_file_get_grain_group_at_offset(
2549
     libvmdk_extent_file_t *extent_file,
2550
     libbfio_pool_t *file_io_pool,
2551
     off64_t offset,
2552
     int *grain_group_index,
2553
     off64_t *grain_group_data_offset,
2554
     libfdata_list_t **grains_list,
2555
     libcerror_error_t **error )
2556
0
{
2557
0
  static char *function = "libvmdk_extent_file_get_grain_group_at_offset";
2558
0
  int result            = 0;
2559
2560
0
  if( extent_file == NULL )
2561
0
  {
2562
0
    libcerror_error_set(
2563
0
     error,
2564
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2565
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2566
0
     "%s: invalid extent file.",
2567
0
     function );
2568
2569
0
    return( -1 );
2570
0
  }
2571
0
  result = libfdata_list_get_element_value_at_offset(
2572
0
      extent_file->grain_groups_list,
2573
0
      (intptr_t *) file_io_pool,
2574
0
      (libfdata_cache_t *) extent_file->grain_groups_cache,
2575
0
      offset,
2576
0
      grain_group_index,
2577
0
      grain_group_data_offset,
2578
0
      (intptr_t **) grains_list,
2579
0
      0,
2580
0
      error );
2581
2582
0
  if( result == -1 )
2583
0
  {
2584
0
    libcerror_error_set(
2585
0
     error,
2586
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2587
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2588
0
     "%s: unable to retrieve grains list at offset: %" PRIi64 ".",
2589
0
     function,
2590
0
     offset );
2591
2592
0
    return( -1 );
2593
0
  }
2594
0
  return( result );
2595
0
}
2596
2597
/* Reads segment data into a buffer
2598
 * Callback function for the segments stream
2599
 * Returns the number of bytes read or -1 on error
2600
 */
2601
ssize_t libvmdk_extent_file_read_segment_data(
2602
         intptr_t *data_handle LIBVMDK_ATTRIBUTE_UNUSED,
2603
         libbfio_pool_t *file_io_pool,
2604
         int segment_index LIBVMDK_ATTRIBUTE_UNUSED,
2605
         int segment_file_index,
2606
         uint8_t *segment_data,
2607
         size_t segment_data_size,
2608
         uint32_t segment_flags LIBVMDK_ATTRIBUTE_UNUSED,
2609
         uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
2610
         libcerror_error_t **error )
2611
0
{
2612
0
  static char *function = "libvmdk_extent_file_read_segment_data";
2613
0
  ssize_t read_count    = 0;
2614
2615
0
  LIBVMDK_UNREFERENCED_PARAMETER( data_handle )
2616
0
  LIBVMDK_UNREFERENCED_PARAMETER( segment_index )
2617
0
  LIBVMDK_UNREFERENCED_PARAMETER( segment_flags )
2618
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
2619
2620
0
  read_count = libbfio_pool_read_buffer(
2621
0
                file_io_pool,
2622
0
                segment_file_index,
2623
0
                segment_data,
2624
0
                segment_data_size,
2625
0
                error );
2626
2627
0
  if( read_count == -1 )
2628
0
  {
2629
0
    libcerror_error_set(
2630
0
     error,
2631
0
     LIBCERROR_ERROR_DOMAIN_IO,
2632
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2633
0
     "%s: unable to read segment data.",
2634
0
     function );
2635
2636
0
    return( -1 );
2637
0
  }
2638
0
  return( read_count );
2639
0
}
2640
2641
/* Seeks a certain segment offset
2642
 * Callback function for the segments stream
2643
 * Returns the offset or -1 on error
2644
 */
2645
off64_t libvmdk_extent_file_seek_segment_offset(
2646
         intptr_t *data_handle LIBVMDK_ATTRIBUTE_UNUSED,
2647
         libbfio_pool_t *file_io_pool,
2648
         int segment_index LIBVMDK_ATTRIBUTE_UNUSED,
2649
         int segment_file_index,
2650
         off64_t segment_offset,
2651
         libcerror_error_t **error )
2652
0
{
2653
0
  static char *function = "libvmdk_extent_file_seek_segment_offset";
2654
2655
0
  LIBVMDK_UNREFERENCED_PARAMETER( data_handle )
2656
0
  LIBVMDK_UNREFERENCED_PARAMETER( segment_index )
2657
2658
0
  segment_offset = libbfio_pool_seek_offset(
2659
0
                    file_io_pool,
2660
0
                    segment_file_index,
2661
0
                    segment_offset,
2662
0
                    SEEK_SET,
2663
0
                    error );
2664
2665
0
  if( segment_offset == -1 )
2666
0
  {
2667
0
    libcerror_error_set(
2668
0
     error,
2669
0
     LIBCERROR_ERROR_DOMAIN_IO,
2670
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2671
0
     "%s: unable to seek segment offset.",
2672
0
     function );
2673
2674
0
    return( -1 );
2675
0
  }
2676
0
  return( segment_offset );
2677
0
}
2678