Coverage Report

Created: 2024-02-25 07:20

/src/libvmdk/libvmdk/libvmdk_extent_file.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Extent file functions
3
 *
4
 * Copyright (C) 2009-2023, 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
591
{
55
591
  static char *function = "libvmdk_extent_file_initialize";
56
57
591
  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
591
  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
591
  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
591
  *extent_file = memory_allocate_structure(
91
591
                  libvmdk_extent_file_t );
92
93
591
  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
591
  if( memory_set(
105
591
       *extent_file,
106
591
       0,
107
591
       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
591
  if( libfdata_list_initialize(
124
591
       &( ( *extent_file )->grain_groups_list ),
125
591
       (intptr_t *) *extent_file,
126
591
       NULL,
127
591
       NULL,
128
591
       (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
591
       NULL,
130
591
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
131
591
       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
591
  if( libfcache_cache_initialize(
144
591
       &( ( *extent_file )->grain_groups_cache ),
145
591
       LIBVMDK_MAXIMUM_CACHE_ENTRIES_GRAIN_GROUPS,
146
591
       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
591
  ( *extent_file )->io_handle = io_handle;
158
159
591
  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
591
}
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
591
{
185
591
  static char *function = "libvmdk_extent_file_free";
186
591
  int result            = 1;
187
188
591
  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
591
  if( *extent_file != NULL )
200
591
  {
201
591
    if( libfdata_list_free(
202
591
         &( ( *extent_file )->grain_groups_list ),
203
591
         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
591
    if( libfcache_cache_free(
215
591
         &( ( *extent_file )->grain_groups_cache ),
216
591
         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
591
    memory_free(
228
591
     *extent_file );
229
230
591
    *extent_file = NULL;
231
591
  }
232
591
  return( result );
233
591
}
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
591
{
337
591
  uint8_t *file_header_data = NULL;
338
591
  static char *function     = "libvmdk_extent_file_read_file_header_file_io_handle";
339
591
  size_t read_size          = 0;
340
591
  ssize_t read_count        = 0;
341
342
591
  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
591
  file_header_data = (uint8_t *) memory_allocate(
354
591
                                  sizeof( uint8_t ) * 2048 );
355
356
591
  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
591
  read_count = libbfio_handle_read_buffer_at_offset(
378
591
                file_io_handle,
379
591
                file_header_data,
380
591
                4,
381
591
                file_offset,
382
591
                error );
383
384
591
  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
591
  if( memory_compare(
398
591
       file_header_data,
399
591
       cowd_sparse_file_signature,
400
591
       4 ) == 0 )
401
0
  {
402
0
    read_size = sizeof( cowd_sparse_file_header_t );
403
0
  }
404
591
  else if( memory_compare(
405
591
            file_header_data,
406
591
            vmdk_sparse_file_signature,
407
591
            4 ) == 0 )
408
591
  {
409
591
    read_size = sizeof( vmdk_sparse_file_header_t );
410
591
  }
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
591
  read_count = libbfio_handle_read_buffer(
423
591
                file_io_handle,
424
591
                &( file_header_data[ 4 ] ),
425
591
                read_size - 4,
426
591
                error );
427
428
591
  if( read_count != (ssize_t) ( read_size - 4 ) )
429
13
  {
430
13
    libcerror_error_set(
431
13
     error,
432
13
     LIBCERROR_ERROR_DOMAIN_IO,
433
13
     LIBCERROR_IO_ERROR_READ_FAILED,
434
13
     "%s: unable to read file header data.",
435
13
     function );
436
437
13
    goto on_error;
438
13
  }
439
578
  if( libvmdk_extent_file_read_file_header_data(
440
578
       extent_file,
441
578
       file_header_data,
442
578
       read_size,
443
578
       error ) != 1 )
444
419
  {
445
419
    libcerror_error_set(
446
419
     error,
447
419
     LIBCERROR_ERROR_DOMAIN_IO,
448
419
     LIBCERROR_IO_ERROR_READ_FAILED,
449
419
     "%s: unable to read file header data.",
450
419
     function );
451
452
419
    goto on_error;
453
419
  }
454
159
  memory_free(
455
159
   file_header_data );
456
457
159
  file_header_data = NULL;
458
459
159
  return( 1 );
460
461
432
on_error:
462
432
  if( file_header_data != NULL )
463
432
  {
464
432
    memory_free(
465
432
     file_header_data );
466
432
  }
467
432
  return( -1 );
468
578
}
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
578
{
639
578
  static char *function                          = "libvmdk_extent_file_read_file_header_data";
640
578
  size64_t grain_table_size                      = 0;
641
578
  uint64_t safe_descriptor_offset                = 0;
642
578
  uint64_t safe_primary_grain_directory_offset   = 0;
643
578
  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
578
  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
578
  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
578
  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
578
  if( memory_compare(
683
578
       file_header_data,
684
578
       cowd_sparse_file_signature,
685
578
       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
578
  else if( memory_compare(
701
578
            file_header_data,
702
578
            vmdk_sparse_file_signature,
703
578
            4 ) == 0 )
704
578
  {
705
578
    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
578
    extent_file->file_type = LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA;
717
578
  }
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
578
  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
578
  else if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
768
578
  {
769
578
    byte_stream_copy_to_uint32_little_endian(
770
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->version,
771
578
     extent_file->format_version );
772
773
578
    byte_stream_copy_to_uint32_little_endian(
774
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->flags,
775
578
     extent_file->flags );
776
777
578
    byte_stream_copy_to_uint64_little_endian(
778
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->maximum_data_number_of_sectors,
779
578
     extent_file->maximum_data_size );
780
781
578
    byte_stream_copy_to_uint64_little_endian(
782
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->grain_number_of_sectors,
783
578
     extent_file->grain_size );
784
785
578
    byte_stream_copy_to_uint64_little_endian(
786
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->descriptor_sector_number,
787
578
     safe_descriptor_offset );
788
789
578
    byte_stream_copy_to_uint64_little_endian(
790
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->descriptor_number_of_sectors,
791
578
     extent_file->descriptor_size );
792
793
578
    byte_stream_copy_to_uint32_little_endian(
794
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->number_of_grain_table_entries,
795
578
     extent_file->number_of_grain_table_entries );
796
797
578
    byte_stream_copy_to_uint64_little_endian(
798
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->secondary_grain_directory_sector_number,
799
578
     safe_secondary_grain_directory_offset );
800
801
578
    byte_stream_copy_to_uint64_little_endian(
802
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->primary_grain_directory_sector_number,
803
578
     safe_primary_grain_directory_offset );
804
805
578
    extent_file->is_dirty = ( (vmdk_sparse_file_header_t *) file_header_data )->is_dirty;
806
807
578
    byte_stream_copy_to_uint16_little_endian(
808
578
     ( (vmdk_sparse_file_header_t *) file_header_data )->compression_method,
809
578
     extent_file->compression_method );
810
578
  }
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
578
  if( ( extent_file->grain_size == 0 )
957
578
   || ( extent_file->grain_size > ( (uint64_t) INT64_MAX / 512 ) ) )
958
61
  {
959
61
    libcerror_error_set(
960
61
     error,
961
61
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
962
61
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
963
61
     "%s: invalid grain number of sectors value out of bounds.",
964
61
     function );
965
966
61
    return( -1 );
967
61
  }
968
517
  if( safe_descriptor_offset > (uint64_t) INT64_MAX )
969
65
  {
970
65
    libcerror_error_set(
971
65
     error,
972
65
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
973
65
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
974
65
     "%s: invalid descriptor offset value out of bounds.",
975
65
     function );
976
977
65
    return( -1 );
978
65
  }
979
452
  extent_file->descriptor_offset = (off64_t) safe_descriptor_offset;
980
981
  /* Note that the primary grain directory offsets can be -1
982
   */
983
452
  extent_file->primary_grain_directory_offset = (off64_t) safe_primary_grain_directory_offset;
984
985
452
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
986
452
  {
987
452
    if( safe_secondary_grain_directory_offset > ( (uint64_t) INT64_MAX / 512 ) )
988
14
    {
989
14
      libcerror_error_set(
990
14
       error,
991
14
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
992
14
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
993
14
       "%s: invalid secondary grain directory offset value out of bounds.",
994
14
       function );
995
996
14
      return( -1 );
997
14
    }
998
438
    extent_file->secondary_grain_directory_offset = (off64_t) safe_secondary_grain_directory_offset;
999
1000
438
    if( extent_file->grain_size <= 8 )
1001
1
    {
1002
1
      libcerror_error_set(
1003
1
       error,
1004
1
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1005
1
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1006
1
       "%s: unsupported grain number of sectors value is less than or equal to 8.",
1007
1
       function );
1008
1009
1
      return( -1 );
1010
1
    }
1011
437
    if( ( extent_file->grain_size % 2 ) != 0 )
1012
2
    {
1013
2
      libcerror_error_set(
1014
2
       error,
1015
2
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1016
2
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1017
2
       "%s: unsupported grain number of sectors value is not a power of 2.",
1018
2
       function );
1019
1020
2
      return( -1 );
1021
2
    }
1022
435
    if( extent_file->number_of_grain_table_entries == 0 )
1023
2
    {
1024
2
      libcerror_error_set(
1025
2
       error,
1026
2
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1027
2
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1028
2
       "%s: unsupported number of grain table entries value is 0.",
1029
2
       function );
1030
1031
2
      return( -1 );
1032
2
    }
1033
433
    if( (size_t) extent_file->number_of_grain_table_entries > (size_t) INT_MAX )
1034
32
    {
1035
32
      libcerror_error_set(
1036
32
       error,
1037
32
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1038
32
       LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1039
32
       "%s: invalid number of grain table entries value exceeds maximum.",
1040
32
       function );
1041
1042
32
      return( -1 );
1043
32
    }
1044
433
  }
1045
#if defined( HAVE_DEBUG_OUTPUT )
1046
  if( libcnotify_verbose != 0 )
1047
  {
1048
    if( ( extent_file->maximum_data_size % extent_file->grain_size ) != 0 )
1049
    {
1050
      libcnotify_printf(
1051
       "%s: unsupported maximum data number of sectors not a multide of the grain number of sectors.\n",
1052
       function );
1053
    }
1054
  }
1055
#endif
1056
401
  if( extent_file->number_of_grain_table_entries > extent_file->maximum_data_size )
1057
40
  {
1058
40
    extent_file->number_of_grain_table_entries = (uint32_t) ( extent_file->maximum_data_size / extent_file->grain_size );
1059
1060
40
    if( ( extent_file->maximum_data_size % extent_file->grain_size ) != 0 )
1061
38
    {
1062
38
      extent_file->number_of_grain_table_entries += 1;
1063
38
    }
1064
#if defined( HAVE_DEBUG_OUTPUT )
1065
    if( libcnotify_verbose != 0 )
1066
    {
1067
      libcnotify_printf(
1068
       "%s: number of grain table entries exceeds maximum data number of sectors changing to: %" PRIu32 ".\n",
1069
       function,
1070
       extent_file->number_of_grain_table_entries );
1071
    }
1072
#endif
1073
40
  }
1074
401
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1075
401
  {
1076
401
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->single_end_of_line_character != (uint8_t) '\n' )
1077
14
    {
1078
14
      libcerror_error_set(
1079
14
       error,
1080
14
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1081
14
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1082
14
       "%s: unsupported single end of line character.",
1083
14
       function );
1084
1085
14
      return( -1 );
1086
14
    }
1087
387
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->non_end_of_line_character != (uint8_t) ' ' )
1088
3
    {
1089
3
      libcerror_error_set(
1090
3
       error,
1091
3
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1092
3
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1093
3
       "%s: unsupported non end of line character.",
1094
3
       function );
1095
1096
3
      return( -1 );
1097
3
    }
1098
384
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->first_double_end_of_line_character != (uint8_t) '\r' )
1099
3
    {
1100
3
      libcerror_error_set(
1101
3
       error,
1102
3
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1103
3
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1104
3
       "%s: unsupported first double end of line character.",
1105
3
       function );
1106
1107
3
      return( -1 );
1108
3
    }
1109
381
    if( ( (vmdk_sparse_file_header_t *) file_header_data )->second_double_end_of_line_character != (uint8_t) '\n' )
1110
7
    {
1111
7
      libcerror_error_set(
1112
7
       error,
1113
7
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1114
7
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1115
7
       "%s: unsupported second double end of line character.",
1116
7
       function );
1117
1118
7
      return( -1 );
1119
7
    }
1120
381
  }
1121
374
  if( ( extent_file->compression_method != LIBVMDK_COMPRESSION_METHOD_NONE )
1122
374
   && ( extent_file->compression_method != LIBVMDK_COMPRESSION_METHOD_DEFLATE ) )
1123
14
  {
1124
14
    libcerror_error_set(
1125
14
     error,
1126
14
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1127
14
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1128
14
     "%s: unsupported compression method: %" PRIu16 ".",
1129
14
     function,
1130
14
     extent_file->compression_method );
1131
1132
14
    return( -1 );
1133
14
  }
1134
  /* Change all sector values to byte values
1135
   */
1136
360
  extent_file->maximum_data_size *= 512;
1137
360
  extent_file->grain_size        *= 512;
1138
1139
360
  if( ( extent_file->primary_grain_directory_offset >= 0 )
1140
360
   && ( extent_file->primary_grain_directory_offset <= (off64_t) ( INT64_MAX / 512 ) ) )
1141
259
  {
1142
259
    extent_file->primary_grain_directory_offset *= 512;
1143
259
  }
1144
  /* In a compressed VMDK sparse data file a primary grain directory sector of -1
1145
   * seems to indicate that there is a copy of the file header at the end of the file.
1146
   */
1147
101
  else if( ( extent_file->file_type != LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1148
101
        || ( extent_file->primary_grain_directory_offset != (off64_t) -1 )
1149
101
        || ( extent_file->compression_method != LIBVMDK_COMPRESSION_METHOD_DEFLATE ) )
1150
97
  {
1151
97
    libcerror_error_set(
1152
97
     error,
1153
97
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1154
97
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1155
97
     "%s: invalid primary grain directory offset value out of bounds.",
1156
97
     function );
1157
1158
97
    return( -1 );
1159
97
  }
1160
263
  if( extent_file->file_type == LIBVMDK_FILE_TYPE_COWD_SPARSE_DATA )
1161
0
  {
1162
0
    extent_file->number_of_grain_table_entries = 4096;
1163
0
  }
1164
263
  else if( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1165
263
  {
1166
263
    grain_table_size = (size64_t) extent_file->number_of_grain_table_entries * extent_file->grain_size;
1167
1168
263
    if( grain_table_size == 0 )
1169
1
    {
1170
1
      libcerror_error_set(
1171
1
       error,
1172
1
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1173
1
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1174
1
       "%s: invalid grain table size value out of bounds.",
1175
1
       function );
1176
1177
1
      return( -1 );
1178
1
    }
1179
262
    extent_file->number_of_grain_directory_entries = (uint32_t) ( extent_file->maximum_data_size / grain_table_size );
1180
1181
262
    if( ( extent_file->maximum_data_size % grain_table_size ) != 0 )
1182
253
    {
1183
253
      extent_file->number_of_grain_directory_entries += 1;
1184
253
    }
1185
262
    if( extent_file->descriptor_offset > (off64_t) ( INT64_MAX / 512 ) )
1186
25
    {
1187
25
      libcerror_error_set(
1188
25
       error,
1189
25
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1190
25
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1191
25
       "%s: invalid descriptor offset value out of bounds.",
1192
25
       function );
1193
1194
25
      return( -1 );
1195
25
    }
1196
237
    extent_file->descriptor_offset *= 512;
1197
237
    extent_file->descriptor_size   *= 512;
1198
1199
237
    extent_file->secondary_grain_directory_offset *= 512;
1200
237
  }
1201
#if defined( HAVE_DEBUG_OUTPUT )
1202
  if( libcnotify_verbose != 0 )
1203
  {
1204
    libcnotify_printf(
1205
     "%s: number of grain directory entries\t\t: %" PRIu32 "\n",
1206
     function,
1207
     extent_file->number_of_grain_directory_entries );
1208
  }
1209
#endif
1210
237
  if( extent_file->descriptor_size > (size_t) SSIZE_MAX )
1211
53
  {
1212
53
    libcerror_error_set(
1213
53
     error,
1214
53
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1215
53
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1216
53
     "%s: invalid descriptor size value exceeds maximum.",
1217
53
     function );
1218
1219
53
    return( -1 );
1220
53
  }
1221
184
  if( (size_t) extent_file->number_of_grain_directory_entries > (size_t) INT_MAX )
1222
25
  {
1223
25
    libcerror_error_set(
1224
25
     error,
1225
25
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1226
25
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1227
25
     "%s: invalid number of grain directory entries value exceeds maximum.",
1228
25
     function );
1229
1230
25
    return( -1 );
1231
25
  }
1232
#if SIZEOF_SIZE_T <= 4
1233
  if( (size_t) extent_file->number_of_grain_table_entries > (size_t) ( SSIZE_MAX / 4 ) )
1234
  {
1235
    libcerror_error_set(
1236
     error,
1237
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1238
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1239
     "%s: invalid grain table size value exceeds maximum.",
1240
     function );
1241
1242
    return( -1 );
1243
  }
1244
  if( (size_t) extent_file->number_of_grain_directory_entries > (size_t) ( SSIZE_MAX / 4 ) )
1245
  {
1246
    libcerror_error_set(
1247
     error,
1248
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1249
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1250
     "%s: invalid grain directory size value exceeds maximum.",
1251
     function );
1252
1253
    return( -1 );
1254
  }
1255
#endif
1256
159
  extent_file->grain_table_size = (size_t) extent_file->number_of_grain_table_entries * 4;
1257
1258
  /* The grain table data is sector aligned
1259
   */
1260
159
  if( ( extent_file->grain_table_size % 512 ) != 0 )
1261
120
  {
1262
120
    extent_file->grain_table_size /= 512;
1263
120
    extent_file->grain_table_size += 1;
1264
120
    extent_file->grain_table_size *= 512;
1265
120
  }
1266
159
  extent_file->grain_directory_size = (size_t) extent_file->number_of_grain_directory_entries * 4;
1267
1268
  /* The grain directory data is sector aligned
1269
   */
1270
159
  if( ( extent_file->grain_directory_size % 512 ) != 0 )
1271
146
  {
1272
146
    extent_file->grain_directory_size /= 512;
1273
146
    extent_file->grain_directory_size += 1;
1274
146
    extent_file->grain_directory_size *= 512;
1275
146
  }
1276
#if defined( HAVE_DEBUG_OUTPUT )
1277
  if( libcnotify_verbose != 0 )
1278
  {
1279
    libcnotify_printf(
1280
     "\n" );
1281
  }
1282
#endif
1283
159
  return( 1 );
1284
184
}
1285
1286
/* Reads the descriptor data from the extent file
1287
 * Returns 1 if successful, 0 if no descriptor data, or -1 on error
1288
 */
1289
int libvmdk_extent_file_read_descriptor_data_file_io_handle(
1290
     libvmdk_extent_file_t *extent_file,
1291
     libbfio_handle_t *file_io_handle,
1292
     uint8_t *descriptor_data,
1293
     size_t descriptor_data_size,
1294
     libcerror_error_t **error )
1295
110
{
1296
110
  static char *function = "libvmdk_extent_file_read_descriptor_data_file_io_handle";
1297
110
  ssize_t read_count    = 0;
1298
1299
110
  if( extent_file == NULL )
1300
0
  {
1301
0
    libcerror_error_set(
1302
0
     error,
1303
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1304
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1305
0
     "%s: invalid extent file.",
1306
0
     function );
1307
1308
0
    return( -1 );
1309
0
  }
1310
110
  if( descriptor_data == NULL )
1311
0
  {
1312
0
    libcerror_error_set(
1313
0
     error,
1314
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1315
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1316
0
     "%s: invalid descriptor data.",
1317
0
     function );
1318
1319
0
    return( -1 );
1320
0
  }
1321
110
  if( descriptor_data_size > (size_t) SSIZE_MAX )
1322
0
  {
1323
0
    libcerror_error_set(
1324
0
     error,
1325
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1326
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1327
0
     "%s: invalid descriptor data size value exceeds maximum.",
1328
0
     function );
1329
1330
0
    return( -1 );
1331
0
  }
1332
110
  if( descriptor_data_size < extent_file->descriptor_size )
1333
0
  {
1334
0
    libcerror_error_set(
1335
0
     error,
1336
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1337
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1338
0
     "%s: invalid descriptor data value too small.",
1339
0
     function );
1340
1341
0
    return( -1 );
1342
0
  }
1343
#if defined( HAVE_DEBUG_OUTPUT )
1344
  if( libcnotify_verbose != 0 )
1345
  {
1346
    libcnotify_printf(
1347
     "%s: reading descriptor at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1348
     function,
1349
     extent_file->descriptor_offset,
1350
     extent_file->descriptor_offset );
1351
  }
1352
#endif
1353
110
  read_count = libbfio_handle_read_buffer_at_offset(
1354
110
                file_io_handle,
1355
110
                descriptor_data,
1356
110
                (size_t) extent_file->descriptor_size,
1357
110
                extent_file->descriptor_offset,
1358
110
                error );
1359
1360
110
  if( read_count != (ssize_t) extent_file->descriptor_size )
1361
102
  {
1362
102
    libcerror_error_set(
1363
102
     error,
1364
102
     LIBCERROR_ERROR_DOMAIN_IO,
1365
102
     LIBCERROR_IO_ERROR_READ_FAILED,
1366
102
     "%s: unable to read descriptor data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1367
102
     function,
1368
102
     extent_file->descriptor_offset,
1369
102
     extent_file->descriptor_offset );
1370
1371
102
    return( -1 );
1372
102
  }
1373
8
  return( 1 );
1374
110
}
1375
1376
/* Reads the grain directories
1377
 * Returns 1 if successful or -1 on error
1378
 */
1379
int libvmdk_extent_file_read_grain_directories(
1380
     libvmdk_extent_file_t *extent_file,
1381
     libbfio_pool_t *file_io_pool,
1382
     int file_io_pool_entry,
1383
     libcerror_error_t **error )
1384
0
{
1385
0
  static char *function = "libvmdk_extent_file_read_grain_directories";
1386
1387
0
  if( extent_file == NULL )
1388
0
  {
1389
0
    libcerror_error_set(
1390
0
     error,
1391
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1392
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1393
0
     "%s: invalid extent file.",
1394
0
     function );
1395
1396
0
    return( -1 );
1397
0
  }
1398
0
  if( ( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
1399
0
   && ( ( extent_file->flags & LIBVMDK_FLAG_USE_SECONDARY_GRAIN_DIRECTORY ) != 0 ) )
1400
0
  {
1401
0
    if( extent_file->secondary_grain_directory_offset < 0 )
1402
0
    {
1403
0
      libcerror_error_set(
1404
0
       error,
1405
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1406
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1407
0
       "%s: invalid secondary grain directory offset value out of bounds.",
1408
0
       function );
1409
1410
0
      return( -1 );
1411
0
    }
1412
0
    if( extent_file->secondary_grain_directory_offset == 0 )
1413
0
    {
1414
0
      libcerror_error_set(
1415
0
       error,
1416
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1417
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1418
0
       "%s: missing secondary grain directory offset.",
1419
0
       function );
1420
1421
0
      return( -1 );
1422
0
    }
1423
#if defined( HAVE_DEBUG_OUTPUT )
1424
    if( libcnotify_verbose != 0 )
1425
    {
1426
      libcnotify_printf(
1427
       "%s: reading secondary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1428
       function,
1429
       extent_file->secondary_grain_directory_offset,
1430
       extent_file->secondary_grain_directory_offset );
1431
    }
1432
#endif
1433
0
    if( libvmdk_extent_file_read_grain_directory(
1434
0
         extent_file,
1435
0
         file_io_pool,
1436
0
         file_io_pool_entry,
1437
0
         extent_file->secondary_grain_directory_offset,
1438
0
         error ) != 1 )
1439
0
    {
1440
0
      libcerror_error_set(
1441
0
       error,
1442
0
       LIBCERROR_ERROR_DOMAIN_IO,
1443
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1444
0
       "%s: unable to read secondary grain directory.",
1445
0
       function );
1446
1447
0
      return( -1 );
1448
0
    }
1449
0
    if( extent_file->primary_grain_directory_offset > 0 )
1450
0
    {
1451
#if defined( HAVE_DEBUG_OUTPUT )
1452
      if( libcnotify_verbose != 0 )
1453
      {
1454
        libcnotify_printf(
1455
         "%s: reading primary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1456
         function,
1457
         extent_file->primary_grain_directory_offset,
1458
         extent_file->primary_grain_directory_offset );
1459
      }
1460
#endif
1461
0
      if( libvmdk_extent_file_read_backup_grain_directory(
1462
0
           extent_file,
1463
0
           file_io_pool,
1464
0
           file_io_pool_entry,
1465
0
           extent_file->primary_grain_directory_offset,
1466
0
           error ) != 1 )
1467
0
      {
1468
0
        libcerror_error_set(
1469
0
         error,
1470
0
         LIBCERROR_ERROR_DOMAIN_IO,
1471
0
         LIBCERROR_IO_ERROR_READ_FAILED,
1472
0
         "%s: unable to read primary backup grain directory.",
1473
0
         function );
1474
1475
0
        return( -1 );
1476
0
      }
1477
0
    }
1478
0
  }
1479
0
  else
1480
0
  {
1481
0
    if( extent_file->primary_grain_directory_offset < 0 )
1482
0
    {
1483
0
      libcerror_error_set(
1484
0
       error,
1485
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1486
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1487
0
       "%s: invalid primary grain directory offset value out of bounds.",
1488
0
       function );
1489
1490
0
      return( -1 );
1491
0
    }
1492
0
    if( extent_file->primary_grain_directory_offset == 0 )
1493
0
    {
1494
0
      libcerror_error_set(
1495
0
       error,
1496
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1497
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1498
0
       "%s: missing primary grain directory offset.",
1499
0
       function );
1500
1501
0
      return( -1 );
1502
0
    }
1503
#if defined( HAVE_DEBUG_OUTPUT )
1504
    if( libcnotify_verbose != 0 )
1505
    {
1506
      libcnotify_printf(
1507
       "%s: reading primary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1508
       function,
1509
       extent_file->primary_grain_directory_offset,
1510
       extent_file->primary_grain_directory_offset );
1511
    }
1512
#endif
1513
0
    if( libvmdk_extent_file_read_grain_directory(
1514
0
         extent_file,
1515
0
         file_io_pool,
1516
0
         file_io_pool_entry,
1517
0
         extent_file->primary_grain_directory_offset,
1518
0
         error ) != 1 )
1519
0
    {
1520
0
      libcerror_error_set(
1521
0
       error,
1522
0
       LIBCERROR_ERROR_DOMAIN_IO,
1523
0
       LIBCERROR_IO_ERROR_READ_FAILED,
1524
0
       "%s: unable to read primary grain directory.",
1525
0
       function );
1526
1527
0
      return( -1 );
1528
0
    }
1529
0
    if( extent_file->secondary_grain_directory_offset > 0 )
1530
0
    {
1531
#if defined( HAVE_DEBUG_OUTPUT )
1532
      if( libcnotify_verbose != 0 )
1533
      {
1534
        libcnotify_printf(
1535
         "%s: reading secondary grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1536
         function,
1537
         extent_file->secondary_grain_directory_offset,
1538
         extent_file->secondary_grain_directory_offset );
1539
      }
1540
#endif
1541
0
      if( libvmdk_extent_file_read_backup_grain_directory(
1542
0
           extent_file,
1543
0
           file_io_pool,
1544
0
           file_io_pool_entry,
1545
0
           extent_file->secondary_grain_directory_offset,
1546
0
           error ) != 1 )
1547
0
      {
1548
0
        libcerror_error_set(
1549
0
         error,
1550
0
         LIBCERROR_ERROR_DOMAIN_IO,
1551
0
         LIBCERROR_IO_ERROR_READ_FAILED,
1552
0
         "%s: unable to read secondary backup grain directory.",
1553
0
         function );
1554
1555
0
        return( -1 );
1556
0
      }
1557
0
    }
1558
0
  }
1559
0
  return( 1 );
1560
0
}
1561
1562
/* Reads the grain directory
1563
 * Returns 1 if successful or -1 on error
1564
 */
1565
int libvmdk_extent_file_read_grain_directory(
1566
     libvmdk_extent_file_t *extent_file,
1567
     libbfio_pool_t *file_io_pool,
1568
     int file_io_pool_entry,
1569
     off64_t file_offset,
1570
     libcerror_error_t **error )
1571
0
{
1572
0
  uint8_t *grain_directory_data        = NULL;
1573
0
  uint8_t *grain_directory_entry       = NULL;
1574
0
  static char *function                = "libvmdk_extent_file_read_grain_directory";
1575
0
  off64_t grain_table_offset           = 0;
1576
0
  size64_t grain_data_size             = 0;
1577
0
  size64_t storage_media_size          = 0;
1578
0
  size64_t total_grain_data_size       = 0;
1579
0
  ssize_t read_count                   = 0;
1580
0
  uint32_t grain_directory_entry_index = 0;
1581
0
  uint32_t range_flags                 = 0;
1582
0
  int element_index                    = 0;
1583
0
  int number_of_grain_table_entries    = 0;
1584
1585
#if defined( HAVE_DEBUG_OUTPUT )
1586
  int result                           = 0;
1587
#endif
1588
1589
0
  if( extent_file == NULL )
1590
0
  {
1591
0
    libcerror_error_set(
1592
0
     error,
1593
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1594
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1595
0
     "%s: invalid extent file.",
1596
0
     function );
1597
1598
0
    return( -1 );
1599
0
  }
1600
0
  if( ( extent_file->grain_directory_size == 0 )
1601
0
   || ( extent_file->grain_directory_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
1602
0
  {
1603
0
    libcerror_error_set(
1604
0
     error,
1605
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1606
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1607
0
     "%s: invalid extent file - grain directory size value out of bounds.",
1608
0
     function );
1609
1610
0
    goto on_error;
1611
0
  }
1612
#if defined( HAVE_DEBUG_OUTPUT )
1613
  if( libcnotify_verbose != 0 )
1614
  {
1615
    libcnotify_printf(
1616
     "%s: reading grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1617
     function,
1618
     file_offset,
1619
     file_offset );
1620
  }
1621
#endif
1622
0
  if( libbfio_pool_seek_offset(
1623
0
       file_io_pool,
1624
0
       file_io_pool_entry,
1625
0
       file_offset,
1626
0
       SEEK_SET,
1627
0
       error ) == -1 )
1628
0
  {
1629
0
    libcerror_error_set(
1630
0
     error,
1631
0
     LIBCERROR_ERROR_DOMAIN_IO,
1632
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
1633
0
     "%s: unable to seek grain directory offset: %" PRIi64 ".",
1634
0
     function,
1635
0
     file_offset );
1636
1637
0
    goto on_error;
1638
0
  }
1639
0
  grain_directory_data = (uint8_t *) memory_allocate(
1640
0
                                      sizeof( uint8_t ) * extent_file->grain_directory_size );
1641
1642
0
  if( grain_directory_data == NULL )
1643
0
  {
1644
0
    libcerror_error_set(
1645
0
     error,
1646
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1647
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1648
0
     "%s: unable to create grain directory data.",
1649
0
     function );
1650
1651
0
    goto on_error;
1652
0
  }
1653
0
  read_count = libbfio_pool_read_buffer(
1654
0
                file_io_pool,
1655
0
                file_io_pool_entry,
1656
0
                grain_directory_data,
1657
0
                extent_file->grain_directory_size,
1658
0
                error );
1659
1660
0
  if( read_count != (ssize_t) extent_file->grain_directory_size )
1661
0
  {
1662
0
    libcerror_error_set(
1663
0
     error,
1664
0
     LIBCERROR_ERROR_DOMAIN_IO,
1665
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1666
0
     "%s: unable to read grain directory data.",
1667
0
     function );
1668
1669
0
    goto on_error;
1670
0
  }
1671
#if defined( HAVE_DEBUG_OUTPUT )
1672
  if( libcnotify_verbose != 0 )
1673
  {
1674
    libcnotify_printf(
1675
     "%s: grain directory data:\n",
1676
     function );
1677
    libcnotify_print_data(
1678
     grain_directory_data,
1679
     extent_file->grain_directory_size,
1680
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1681
  }
1682
#endif
1683
0
  grain_directory_entry = grain_directory_data;
1684
1685
0
  for( grain_directory_entry_index = 0;
1686
0
       grain_directory_entry_index < extent_file->number_of_grain_directory_entries;
1687
0
       grain_directory_entry_index++ )
1688
0
  {
1689
0
    byte_stream_copy_to_uint32_little_endian(
1690
0
     grain_directory_entry,
1691
0
     grain_table_offset );
1692
1693
#if defined( HAVE_DEBUG_OUTPUT )
1694
    if( libcnotify_verbose != 0 )
1695
    {
1696
      libcnotify_printf(
1697
       "%s: grain directory entry: %05" PRIu32 " sector number\t\t: %" PRIi64 "\n",
1698
       function,
1699
       grain_directory_entry_index,
1700
       grain_table_offset );
1701
    }
1702
#endif
1703
0
    if( grain_table_offset != 0 )
1704
0
    {
1705
0
      range_flags         = 0;
1706
0
      grain_table_offset *= 512;
1707
0
    }
1708
0
    else
1709
0
    {
1710
0
      range_flags = LIBVMDK_RANGE_FLAG_IS_SPARSE;
1711
0
    }
1712
0
    number_of_grain_table_entries = (int) extent_file->number_of_grain_table_entries;
1713
0
    grain_data_size               = number_of_grain_table_entries * extent_file->grain_size;
1714
1715
0
    if( ( total_grain_data_size + grain_data_size ) > extent_file->maximum_data_size )
1716
0
    {
1717
0
      grain_data_size = extent_file->maximum_data_size - total_grain_data_size;
1718
1719
0
      number_of_grain_table_entries = (int)( grain_data_size / extent_file->grain_size );
1720
1721
0
      if( ( grain_data_size % extent_file->grain_size ) != 0 )
1722
0
      {
1723
0
        number_of_grain_table_entries += 1;
1724
0
      }
1725
0
    }
1726
#if defined( HAVE_DEBUG_OUTPUT )
1727
    if( libcnotify_verbose != 0 )
1728
    {
1729
      libcnotify_printf(
1730
       "%s: grain directory entry: %05" PRIu32 " offset\t\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
1731
       function,
1732
       grain_directory_entry_index,
1733
       grain_table_offset * 512,
1734
       grain_table_offset * 512 );
1735
1736
      libcnotify_printf(
1737
       "%s: grain directory entry: %05" PRIu32 " size\t\t\t: %" PRIu64 " (%d)\n",
1738
       function,
1739
       grain_directory_entry_index,
1740
       grain_data_size,
1741
       number_of_grain_table_entries );
1742
1743
      libcnotify_printf(
1744
       "%s: grain directory entry: %05" PRIu32 " file IO pool entry\t: %d\n",
1745
       function,
1746
       grain_directory_entry_index,
1747
       file_io_pool_entry );
1748
1749
      libcnotify_printf(
1750
       "%s: grain directory entry: %05" PRIu32 " range flags\t\t: 0x%08" PRIx64 "\n",
1751
       function,
1752
       grain_directory_entry_index,
1753
       range_flags );
1754
1755
      if( ( range_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
1756
      {
1757
        libcnotify_printf(
1758
         "\tIs sparse.\n" );
1759
      }
1760
      libcnotify_printf(
1761
       "\n" );
1762
    }
1763
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1764
1765
0
    storage_media_size = (size64_t) extent_file->grain_size * number_of_grain_table_entries;
1766
1767
0
    if( libfdata_list_append_element_with_mapped_size(
1768
0
         extent_file->grain_groups_list,
1769
0
         &element_index,
1770
0
         file_io_pool_entry,
1771
0
         grain_table_offset,
1772
0
         (size64_t) extent_file->grain_table_size,
1773
0
         range_flags,
1774
0
         storage_media_size,
1775
0
         error ) != 1 )
1776
0
    {
1777
0
      libcerror_error_set(
1778
0
       error,
1779
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1780
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1781
0
       "%s: unable to append element with mapped size to grain groups list.",
1782
0
       function );
1783
1784
0
      goto on_error;
1785
0
    }
1786
0
    total_grain_data_size           += grain_data_size;
1787
0
    grain_directory_entry           += sizeof( uint32_t );
1788
0
    extent_file->storage_media_size += storage_media_size;
1789
0
  }
1790
#if defined( HAVE_DEBUG_OUTPUT )
1791
  if( libcnotify_verbose != 0 )
1792
  {
1793
    if( total_grain_data_size < extent_file->grain_directory_size )
1794
    {
1795
      result = libvmdk_extent_file_check_for_empty_block(
1796
          grain_directory_entry,
1797
          extent_file->grain_directory_size - total_grain_data_size,
1798
                error );
1799
1800
      if( result == -1 )
1801
      {
1802
        libcerror_error_set(
1803
         error,
1804
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1805
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1806
         "%s: unable to determine if remainder of grain directory is empty.",
1807
         function );
1808
1809
        goto on_error;
1810
      }
1811
      else if( result == 0 )
1812
      {
1813
        libcnotify_printf(
1814
         "%s: remainder of grain directory not empty.",
1815
         function );
1816
      }
1817
    }
1818
  }
1819
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1820
1821
0
  memory_free(
1822
0
   grain_directory_data );
1823
1824
0
  grain_directory_data = NULL;
1825
1826
0
  return( 1 );
1827
1828
0
on_error:
1829
0
  if( grain_directory_data != NULL )
1830
0
  {
1831
0
    memory_free(
1832
0
     grain_directory_data );
1833
0
  }
1834
0
  return( -1 );
1835
0
}
1836
1837
/* Reads the backup grain directory
1838
 * Returns 1 if successful or -1 on error
1839
 */
1840
int libvmdk_extent_file_read_backup_grain_directory(
1841
     libvmdk_extent_file_t *extent_file,
1842
     libbfio_pool_t *file_io_pool,
1843
     int file_io_pool_entry,
1844
     off64_t file_offset,
1845
     libcerror_error_t **error )
1846
0
{
1847
0
  uint8_t *grain_directory_data        = NULL;
1848
0
  uint8_t *grain_directory_entry       = NULL;
1849
0
  static char *function                = "libvmdk_extent_file_read_backup_grain_directory";
1850
0
  off64_t grain_group_offset           = 0;
1851
0
  size64_t grain_data_size             = 0;
1852
0
  size64_t grain_group_size            = 0;
1853
0
  size64_t total_grain_data_size       = 0;
1854
0
  ssize_t read_count                   = 0;
1855
0
  uint32_t grain_directory_entry_index = 0;
1856
0
  uint32_t grain_group_range_flags     = 0;
1857
0
  int grain_group_file_io_pool_entry   = 0;
1858
0
  int number_of_grain_table_entries    = 0;
1859
1860
#if defined( HAVE_DEBUG_OUTPUT )
1861
  off64_t grain_table_offset           = 0;
1862
  uint32_t range_flags                 = 0;
1863
  int result                           = 0;
1864
#endif
1865
1866
0
  if( extent_file == NULL )
1867
0
  {
1868
0
    libcerror_error_set(
1869
0
     error,
1870
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1871
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1872
0
     "%s: invalid extent file.",
1873
0
     function );
1874
1875
0
    return( -1 );
1876
0
  }
1877
0
  if( ( extent_file->grain_directory_size == 0 )
1878
0
   || ( extent_file->grain_directory_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
1879
0
  {
1880
0
    libcerror_error_set(
1881
0
     error,
1882
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1883
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1884
0
     "%s: invalid extent file - grain directory size value out of bounds.",
1885
0
     function );
1886
1887
0
    goto on_error;
1888
0
  }
1889
#if defined( HAVE_DEBUG_OUTPUT )
1890
  if( libcnotify_verbose != 0 )
1891
  {
1892
    libcnotify_printf(
1893
     "%s: reading backup grain directory at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1894
     function,
1895
     file_offset,
1896
     file_offset );
1897
  }
1898
#endif
1899
0
  if( libbfio_pool_seek_offset(
1900
0
       file_io_pool,
1901
0
       file_io_pool_entry,
1902
0
       file_offset,
1903
0
       SEEK_SET,
1904
0
       error ) == -1 )
1905
0
  {
1906
0
    libcerror_error_set(
1907
0
     error,
1908
0
     LIBCERROR_ERROR_DOMAIN_IO,
1909
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
1910
0
     "%s: unable to seek backup grain directory offset: %" PRIi64 ".",
1911
0
     function,
1912
0
     file_offset );
1913
1914
0
    goto on_error;
1915
0
  }
1916
0
  grain_directory_data = (uint8_t *) memory_allocate(
1917
0
                                      sizeof( uint8_t ) * extent_file->grain_directory_size );
1918
1919
0
  if( grain_directory_data == NULL )
1920
0
  {
1921
0
    libcerror_error_set(
1922
0
     error,
1923
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1924
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1925
0
     "%s: unable to create grain directory data.",
1926
0
     function );
1927
1928
0
    goto on_error;
1929
0
  }
1930
0
  read_count = libbfio_pool_read_buffer(
1931
0
                file_io_pool,
1932
0
                file_io_pool_entry,
1933
0
                grain_directory_data,
1934
0
                extent_file->grain_directory_size,
1935
0
                error );
1936
1937
0
  if( read_count != (ssize_t) extent_file->grain_directory_size )
1938
0
  {
1939
0
    libcerror_error_set(
1940
0
     error,
1941
0
     LIBCERROR_ERROR_DOMAIN_IO,
1942
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1943
0
     "%s: unable to read grain directory data.",
1944
0
     function );
1945
1946
0
    goto on_error;
1947
0
  }
1948
#if defined( HAVE_DEBUG_OUTPUT )
1949
  if( libcnotify_verbose != 0 )
1950
  {
1951
    libcnotify_printf(
1952
     "%s: grain directory data:\n",
1953
     function );
1954
    libcnotify_print_data(
1955
     grain_directory_data,
1956
     extent_file->grain_directory_size,
1957
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1958
  }
1959
#endif
1960
0
  grain_directory_entry = grain_directory_data;
1961
1962
0
  for( grain_directory_entry_index = 0;
1963
0
       grain_directory_entry_index < extent_file->number_of_grain_directory_entries;
1964
0
       grain_directory_entry_index++ )
1965
0
  {
1966
#if defined( HAVE_DEBUG_OUTPUT )
1967
    byte_stream_copy_to_uint32_little_endian(
1968
     grain_directory_entry,
1969
     grain_table_offset );
1970
1971
    if( libcnotify_verbose != 0 )
1972
    {
1973
      libcnotify_printf(
1974
       "%s: grain directory entry: %05" PRIu32 " sector number\t\t: %" PRIi64 "\n",
1975
       function,
1976
       grain_directory_entry_index,
1977
       grain_table_offset );
1978
    }
1979
    if( grain_table_offset != 0 )
1980
    {
1981
      range_flags         = 0;
1982
      grain_table_offset *= 512;
1983
    }
1984
    else
1985
    {
1986
      range_flags = LIBVMDK_RANGE_FLAG_IS_SPARSE;
1987
    }
1988
#endif
1989
0
    number_of_grain_table_entries = (int) extent_file->number_of_grain_table_entries;
1990
0
    grain_data_size               = number_of_grain_table_entries * extent_file->grain_size;
1991
1992
0
    if( ( total_grain_data_size + grain_data_size ) > extent_file->maximum_data_size )
1993
0
    {
1994
0
      grain_data_size = extent_file->maximum_data_size - total_grain_data_size;
1995
1996
#if defined( HAVE_DEBUG_OUTPUT )
1997
      number_of_grain_table_entries = (int) ( grain_data_size / extent_file->grain_size );
1998
1999
      if( ( grain_data_size % extent_file->grain_size ) != 0 )
2000
      {
2001
        number_of_grain_table_entries += 1;
2002
      }
2003
#endif
2004
0
    }
2005
#if defined( HAVE_DEBUG_OUTPUT )
2006
    if( libcnotify_verbose != 0 )
2007
    {
2008
      libcnotify_printf(
2009
       "%s: grain directory entry: %05" PRIu32 " offset\t\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
2010
       function,
2011
       grain_directory_entry_index,
2012
       grain_table_offset * 512,
2013
       grain_table_offset * 512 );
2014
2015
      libcnotify_printf(
2016
       "%s: grain directory entry: %05" PRIu32 " size\t\t\t: %" PRIu64 " (%d)\n",
2017
       function,
2018
       grain_directory_entry_index,
2019
       grain_data_size,
2020
       number_of_grain_table_entries );
2021
2022
      libcnotify_printf(
2023
       "%s: grain directory entry: %05" PRIu32 " file IO pool entry\t: %d\n",
2024
       function,
2025
       grain_directory_entry_index,
2026
       file_io_pool_entry );
2027
2028
      libcnotify_printf(
2029
       "%s: grain directory entry: %05" PRIu32 " range flags\t\t: 0x%08" PRIx64 "\n",
2030
       function,
2031
       grain_directory_entry_index,
2032
       range_flags );
2033
2034
      if( ( range_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
2035
      {
2036
        libcnotify_printf(
2037
         "\tIs sparse.\n" );
2038
      }
2039
      libcnotify_printf(
2040
       "\n" );
2041
    }
2042
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
2043
2044
0
    if( libfdata_list_get_element_by_index(
2045
0
         extent_file->grain_groups_list,
2046
0
         grain_directory_entry_index,
2047
0
         &grain_group_file_io_pool_entry,
2048
0
         &grain_group_offset,
2049
0
         &grain_group_size,
2050
0
         &grain_group_range_flags,
2051
0
         error ) != 1 )
2052
0
    {
2053
0
      libcerror_error_set(
2054
0
       error,
2055
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
2056
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2057
0
       "%s: unable to retrieve element: %d from chunk groups list.",
2058
0
       function,
2059
0
       grain_directory_entry_index );
2060
2061
0
      goto on_error;
2062
0
    }
2063
/* TODO compare grain directory entry with back up ? */
2064
2065
0
    total_grain_data_size += grain_data_size;
2066
0
    grain_directory_entry += sizeof( uint32_t );
2067
0
  }
2068
#if defined( HAVE_DEBUG_OUTPUT )
2069
  if( libcnotify_verbose != 0 )
2070
  {
2071
    if( total_grain_data_size < extent_file->grain_directory_size )
2072
    {
2073
      result = libvmdk_extent_file_check_for_empty_block(
2074
          grain_directory_entry,
2075
          extent_file->grain_directory_size - total_grain_data_size,
2076
                error );
2077
2078
      if( result == -1 )
2079
      {
2080
        libcerror_error_set(
2081
         error,
2082
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
2083
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2084
         "%s: unable to determine if remainder of grain directory is empty.",
2085
         function );
2086
2087
        goto on_error;
2088
      }
2089
      else if( result == 0 )
2090
      {
2091
        libcnotify_printf(
2092
         "%s: remainder of grain directory not empty.",
2093
         function );
2094
      }
2095
    }
2096
  }
2097
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
2098
2099
0
  memory_free(
2100
0
   grain_directory_data );
2101
2102
0
  grain_directory_data = NULL;
2103
2104
0
  return( 1 );
2105
2106
0
on_error:
2107
0
  if( grain_directory_data != NULL )
2108
0
  {
2109
0
    memory_free(
2110
0
     grain_directory_data );
2111
0
  }
2112
0
  return( -1 );
2113
0
}
2114
2115
/* Reads the extent file
2116
 * Callback function for the extent files list
2117
 * Returns 1 if successful or -1 on error
2118
 */
2119
int libvmdk_extent_file_read_element_data(
2120
     libvmdk_io_handle_t *io_handle,
2121
     libbfio_pool_t *file_io_pool,
2122
     libfdata_list_element_t *element,
2123
     libfdata_cache_t *cache,
2124
     int file_io_pool_entry,
2125
     off64_t element_offset LIBVMDK_ATTRIBUTE_UNUSED,
2126
     size64_t extent_file_size,
2127
     uint32_t element_flags LIBVMDK_ATTRIBUTE_UNUSED,
2128
     uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
2129
     libcerror_error_t **error )
2130
0
{
2131
0
  libvmdk_extent_file_t *extent_file = NULL;
2132
0
  static char *function              = "libvmdk_extent_file_read_element_data";
2133
2134
0
  LIBVMDK_UNREFERENCED_PARAMETER( element_offset )
2135
0
  LIBVMDK_UNREFERENCED_PARAMETER( element_flags )
2136
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
2137
2138
0
  if( io_handle == NULL )
2139
0
  {
2140
0
    libcerror_error_set(
2141
0
     error,
2142
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2143
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2144
0
     "%s: invalid IO handle.",
2145
0
     function );
2146
2147
0
    return( -1 );
2148
0
  }
2149
0
  if( libvmdk_extent_file_initialize(
2150
0
       &extent_file,
2151
0
       io_handle,
2152
0
       error ) != 1 )
2153
0
  {
2154
0
    libcerror_error_set(
2155
0
     error,
2156
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2157
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2158
0
     "%s: unable to create extent file.",
2159
0
     function );
2160
2161
0
    goto on_error;
2162
0
  }
2163
0
  if( libvmdk_extent_file_read_file_header(
2164
0
       extent_file,
2165
0
       file_io_pool,
2166
0
       file_io_pool_entry,
2167
0
       0,
2168
0
       error ) != 1 )
2169
0
  {
2170
0
    libcerror_error_set(
2171
0
     error,
2172
0
     LIBCERROR_ERROR_DOMAIN_IO,
2173
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2174
0
     "%s: unable to read extent file header from file IO pool entry: %d.",
2175
0
     function,
2176
0
     file_io_pool_entry );
2177
2178
0
    goto on_error;
2179
0
  }
2180
0
  if( ( extent_file->file_type == LIBVMDK_FILE_TYPE_VMDK_SPARSE_DATA )
2181
0
   && ( extent_file->primary_grain_directory_offset == (off64_t) -1 )
2182
0
   && ( extent_file->compression_method == LIBVMDK_COMPRESSION_METHOD_DEFLATE ) )
2183
0
  {
2184
0
    if( libvmdk_extent_file_read_file_header(
2185
0
         extent_file,
2186
0
         file_io_pool,
2187
0
         file_io_pool_entry,
2188
0
         extent_file_size - 1024,
2189
0
         error ) != 1 )
2190
0
    {
2191
0
      libcerror_error_set(
2192
0
       error,
2193
0
       LIBCERROR_ERROR_DOMAIN_IO,
2194
0
       LIBCERROR_IO_ERROR_READ_FAILED,
2195
0
       "%s: unable to read secondary extent file header from file IO pool entry: %d.",
2196
0
       function,
2197
0
       file_io_pool_entry );
2198
2199
0
      goto on_error;
2200
0
    }
2201
0
  }
2202
0
  if( libvmdk_extent_file_read_grain_directory(
2203
0
       extent_file,
2204
0
       file_io_pool,
2205
0
       file_io_pool_entry,
2206
0
       extent_file->primary_grain_directory_offset,
2207
0
       error ) != 1 )
2208
0
  {
2209
0
    libcerror_error_set(
2210
0
     error,
2211
0
     LIBCERROR_ERROR_DOMAIN_IO,
2212
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2213
0
     "%s: unable to read primary grain directory.",
2214
0
     function );
2215
2216
0
    goto on_error;
2217
0
  }
2218
0
  if( libfdata_list_element_set_element_value(
2219
0
       element,
2220
0
       (intptr_t *) file_io_pool,
2221
0
       cache,
2222
0
       (intptr_t *) extent_file,
2223
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libvmdk_extent_file_free,
2224
0
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
2225
0
       error ) != 1 )
2226
0
  {
2227
0
    libcerror_error_set(
2228
0
     error,
2229
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2230
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2231
0
     "%s: unable to set extent file as element value.",
2232
0
     function );
2233
2234
0
    goto on_error;
2235
0
  }
2236
0
  return( 1 );
2237
2238
0
on_error:
2239
0
  if( extent_file != NULL )
2240
0
  {
2241
0
    libvmdk_extent_file_free(
2242
0
     &extent_file,
2243
0
     NULL );
2244
0
  }
2245
0
  return( -1 );
2246
0
}
2247
2248
/* Reads a grain group
2249
 * Callback function for the grain groups list
2250
 * Returns 1 if successful or -1 on error
2251
 */
2252
int libvmdk_extent_file_read_grain_group_element_data(
2253
     libvmdk_extent_file_t *extent_file,
2254
     libbfio_pool_t *file_io_pool,
2255
     libfdata_list_element_t *element,
2256
     libfdata_cache_t *cache,
2257
     int file_io_pool_entry,
2258
     off64_t grain_group_data_offset,
2259
     size64_t grain_group_data_size,
2260
     uint32_t grain_group_data_flags,
2261
     uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
2262
     libcerror_error_t **error )
2263
0
{
2264
0
  libfdata_list_t *grains_list = NULL;
2265
0
  uint8_t *grain_table_data    = NULL;
2266
0
  static char *function        = "libvmdk_extent_file_read_grain_group_element_data";
2267
0
  ssize_t read_count           = 0;
2268
0
  int grain_index              = 0;
2269
0
  int number_of_entries        = 0;
2270
2271
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
2272
2273
0
  if( extent_file == NULL )
2274
0
  {
2275
0
    libcerror_error_set(
2276
0
     error,
2277
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2278
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2279
0
     "%s: invalid extent file.",
2280
0
     function );
2281
2282
0
    return( -1 );
2283
0
  }
2284
0
  if( extent_file->grain_groups_list == NULL )
2285
0
  {
2286
0
    libcerror_error_set(
2287
0
     error,
2288
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2289
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2290
0
     "%s: invalid extent file - missing grain groups list.",
2291
0
     function );
2292
2293
0
    return( -1 );
2294
0
  }
2295
0
  if( extent_file->io_handle == NULL )
2296
0
  {
2297
0
    libcerror_error_set(
2298
0
     error,
2299
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2300
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2301
0
     "%s: invalid extent file - missing IO handle.",
2302
0
     function );
2303
2304
0
    return( -1 );
2305
0
  }
2306
0
  if( ( grain_group_data_size == 0 )
2307
0
   || ( grain_group_data_size > (size64_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
2308
0
  {
2309
0
    libcerror_error_set(
2310
0
     error,
2311
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2312
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2313
0
     "%s: invalid grain group data size value out of bounds.",
2314
0
     function );
2315
2316
0
    goto on_error;
2317
0
  }
2318
0
  grain_table_data = (uint8_t *) memory_allocate(
2319
0
                                  sizeof( uint8_t ) * (size_t) grain_group_data_size );
2320
2321
0
  if( grain_table_data == NULL )
2322
0
  {
2323
0
    libcerror_error_set(
2324
0
     error,
2325
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
2326
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2327
0
     "%s: unable to create grain table data.",
2328
0
     function );
2329
2330
0
    goto on_error;
2331
0
  }
2332
0
  if( ( grain_group_data_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
2333
0
  {
2334
0
    libcerror_error_set(
2335
0
     error,
2336
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2337
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
2338
0
     "%s: sparse grain table not supported.",
2339
0
     function );
2340
2341
0
    goto on_error;
2342
0
  }
2343
#if defined( HAVE_DEBUG_OUTPUT )
2344
  if( libcnotify_verbose != 0 )
2345
  {
2346
    libcnotify_printf(
2347
     "%s: reading grain table at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
2348
     function,
2349
     grain_group_data_offset,
2350
     grain_group_data_offset );
2351
  }
2352
#endif
2353
0
  if( libbfio_pool_seek_offset(
2354
0
       file_io_pool,
2355
0
       file_io_pool_entry,
2356
0
       grain_group_data_offset,
2357
0
       SEEK_SET,
2358
0
       error ) == -1 )
2359
0
  {
2360
0
    libcerror_error_set(
2361
0
     error,
2362
0
     LIBCERROR_ERROR_DOMAIN_IO,
2363
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
2364
0
     "%s: unable to seek grain table offset: %" PRIi64 ".",
2365
0
     function,
2366
0
     grain_group_data_offset );
2367
2368
0
    goto on_error;
2369
0
  }
2370
0
  read_count = libbfio_pool_read_buffer(
2371
0
                file_io_pool,
2372
0
                file_io_pool_entry,
2373
0
                grain_table_data,
2374
0
                (size_t) grain_group_data_size,
2375
0
                error );
2376
2377
0
  if( read_count != (ssize_t) grain_group_data_size )
2378
0
  {
2379
0
    libcerror_error_set(
2380
0
     error,
2381
0
     LIBCERROR_ERROR_DOMAIN_IO,
2382
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2383
0
     "%s: unable to read grain table data.",
2384
0
     function );
2385
2386
0
    goto on_error;
2387
0
  }
2388
#if defined( HAVE_DEBUG_OUTPUT )
2389
  if( libcnotify_verbose != 0 )
2390
  {
2391
    libcnotify_printf(
2392
     "%s: grain table data:\n",
2393
     function );
2394
    libcnotify_print_data(
2395
     grain_table_data,
2396
     (size_t) grain_group_data_size,
2397
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
2398
  }
2399
#endif
2400
0
  if( libfdata_list_initialize(
2401
0
       &grains_list,
2402
0
       (intptr_t *) extent_file->io_handle,
2403
0
       NULL,
2404
0
       NULL,
2405
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,
2406
0
       NULL,
2407
0
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
2408
0
       error ) != 1 )
2409
0
  {
2410
0
    libcerror_error_set(
2411
0
     error,
2412
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2413
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2414
0
     "%s: unable to create grains list.",
2415
0
     function );
2416
2417
0
    goto on_error;
2418
0
  }
2419
/* TODO makes sure to compensate for the last grain table */
2420
0
  number_of_entries = extent_file->number_of_grain_table_entries;
2421
2422
0
  if( libvmdk_grain_group_fill(
2423
0
       grains_list,
2424
0
       grain_index,
2425
0
       extent_file->io_handle->grain_size,
2426
0
       file_io_pool,
2427
0
       file_io_pool_entry,
2428
0
       grain_table_data,
2429
0
       (size_t) grain_group_data_size,
2430
0
       number_of_entries,
2431
0
       extent_file->flags,
2432
0
       error ) != 1 )
2433
0
  {
2434
0
    libcerror_error_set(
2435
0
     error,
2436
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2437
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2438
0
     "%s: unable to fill grain table.",
2439
0
     function );
2440
2441
0
    goto on_error;
2442
0
  }
2443
/* TODO what about backup range */
2444
/* TODO check if remainder of sector block is empty */
2445
2446
0
  memory_free(
2447
0
   grain_table_data );
2448
2449
0
  grain_table_data = NULL;
2450
2451
0
  if( libfdata_list_element_set_element_value(
2452
0
       element,
2453
0
       (intptr_t *) file_io_pool,
2454
0
       cache,
2455
0
       (intptr_t *) grains_list,
2456
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libfdata_list_free,
2457
0
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
2458
0
       error ) != 1 )
2459
0
  {
2460
0
    libcerror_error_set(
2461
0
     error,
2462
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2463
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2464
0
     "%s: unable to set grains list as element value.",
2465
0
     function );
2466
2467
0
    goto on_error;
2468
0
  }
2469
0
  return( 1 );
2470
2471
0
on_error:
2472
0
  if( grains_list != NULL )
2473
0
  {
2474
0
    libfdata_list_free(
2475
0
     &grains_list,
2476
0
     NULL );
2477
0
  }
2478
0
  if( grain_table_data != NULL )
2479
0
  {
2480
0
    memory_free(
2481
0
     grain_table_data );
2482
0
  }
2483
0
  return( -1 );
2484
0
}
2485
2486
/* Determines if the grain group at a specific offset is sparse
2487
 * Returns 1 if the grain is sparse, 0 if not or -1 on error
2488
 */
2489
int libvmdk_extent_file_grain_group_is_sparse_at_offset(
2490
     libvmdk_extent_file_t *extent_file,
2491
     off64_t offset,
2492
     int *grain_group_index,
2493
     off64_t *grain_group_data_offset,
2494
     libcerror_error_t **error )
2495
0
{
2496
0
  static char *function      = "libvmdk_extent_file_grain_group_is_sparse_at_offset";
2497
0
  off64_t grain_group_offset = 0;
2498
0
  size64_t grain_group_size  = 0;
2499
0
  uint32_t grain_group_flags = 0;
2500
0
  int grain_group_file_index = 0;
2501
0
  int result                 = 0;
2502
2503
0
  if( extent_file == NULL )
2504
0
  {
2505
0
    libcerror_error_set(
2506
0
     error,
2507
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2508
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2509
0
     "%s: invalid extent file.",
2510
0
     function );
2511
2512
0
    return( -1 );
2513
0
  }
2514
0
  result = libfdata_list_get_element_at_offset(
2515
0
      extent_file->grain_groups_list,
2516
0
      offset,
2517
0
      grain_group_index,
2518
0
      grain_group_data_offset,
2519
0
      &grain_group_file_index,
2520
0
      &grain_group_offset,
2521
0
      &grain_group_size,
2522
0
      &grain_group_flags,
2523
0
      error );
2524
2525
0
  if( result != 1 )
2526
0
  {
2527
0
    libcerror_error_set(
2528
0
     error,
2529
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2530
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2531
0
     "%s: unable to retrieve grains group element at offset: %" PRIi64 ".",
2532
0
     function,
2533
0
     offset );
2534
2535
0
    return( -1 );
2536
0
  }
2537
0
  if( ( grain_group_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
2538
0
  {
2539
0
    return( 1 );
2540
0
  }
2541
0
  return( 0 );
2542
0
}
2543
2544
/* Retrieves the grain group at a specific offset
2545
 * Returns 1 if successful, 0 if not or -1 on error
2546
 */
2547
int libvmdk_extent_file_get_grain_group_at_offset(
2548
     libvmdk_extent_file_t *extent_file,
2549
     libbfio_pool_t *file_io_pool,
2550
     off64_t offset,
2551
     int *grain_group_index,
2552
     off64_t *grain_group_data_offset,
2553
     libfdata_list_t **grains_list,
2554
     libcerror_error_t **error )
2555
0
{
2556
0
  static char *function = "libvmdk_extent_file_get_grain_group_at_offset";
2557
0
  int result            = 0;
2558
2559
0
  if( extent_file == NULL )
2560
0
  {
2561
0
    libcerror_error_set(
2562
0
     error,
2563
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2564
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2565
0
     "%s: invalid extent file.",
2566
0
     function );
2567
2568
0
    return( -1 );
2569
0
  }
2570
0
  result = libfdata_list_get_element_value_at_offset(
2571
0
      extent_file->grain_groups_list,
2572
0
      (intptr_t *) file_io_pool,
2573
0
      (libfdata_cache_t *) extent_file->grain_groups_cache,
2574
0
      offset,
2575
0
      grain_group_index,
2576
0
      grain_group_data_offset,
2577
0
      (intptr_t **) grains_list,
2578
0
      0,
2579
0
      error );
2580
2581
0
  if( result == -1 )
2582
0
  {
2583
0
    libcerror_error_set(
2584
0
     error,
2585
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2586
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2587
0
     "%s: unable to retrieve grains list at offset: %" PRIi64 ".",
2588
0
     function,
2589
0
     offset );
2590
2591
0
    return( -1 );
2592
0
  }
2593
0
  return( result );
2594
0
}
2595
2596
/* Reads segment data into a buffer
2597
 * Callback function for the segments stream
2598
 * Returns the number of bytes read or -1 on error
2599
 */
2600
ssize_t libvmdk_extent_file_read_segment_data(
2601
         intptr_t *data_handle LIBVMDK_ATTRIBUTE_UNUSED,
2602
         libbfio_pool_t *file_io_pool,
2603
         int segment_index LIBVMDK_ATTRIBUTE_UNUSED,
2604
         int segment_file_index,
2605
         uint8_t *segment_data,
2606
         size_t segment_data_size,
2607
         uint32_t segment_flags LIBVMDK_ATTRIBUTE_UNUSED,
2608
         uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
2609
         libcerror_error_t **error )
2610
0
{
2611
0
  static char *function = "libvmdk_extent_file_read_segment_data";
2612
0
  ssize_t read_count    = 0;
2613
2614
0
  LIBVMDK_UNREFERENCED_PARAMETER( data_handle )
2615
0
  LIBVMDK_UNREFERENCED_PARAMETER( segment_index )
2616
0
  LIBVMDK_UNREFERENCED_PARAMETER( segment_flags )
2617
0
  LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
2618
2619
0
  read_count = libbfio_pool_read_buffer(
2620
0
                file_io_pool,
2621
0
                segment_file_index,
2622
0
                segment_data,
2623
0
                segment_data_size,
2624
0
                error );
2625
2626
0
  if( read_count == -1 )
2627
0
  {
2628
0
    libcerror_error_set(
2629
0
     error,
2630
0
     LIBCERROR_ERROR_DOMAIN_IO,
2631
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2632
0
     "%s: unable to read segment data.",
2633
0
     function );
2634
2635
0
    return( -1 );
2636
0
  }
2637
0
  return( read_count );
2638
0
}
2639
2640
/* Seeks a certain segment offset
2641
 * Callback function for the segments stream
2642
 * Returns the offset or -1 on error
2643
 */
2644
off64_t libvmdk_extent_file_seek_segment_offset(
2645
         intptr_t *data_handle LIBVMDK_ATTRIBUTE_UNUSED,
2646
         libbfio_pool_t *file_io_pool,
2647
         int segment_index LIBVMDK_ATTRIBUTE_UNUSED,
2648
         int segment_file_index,
2649
         off64_t segment_offset,
2650
         libcerror_error_t **error )
2651
0
{
2652
0
  static char *function = "libvmdk_extent_file_seek_segment_offset";
2653
2654
0
  LIBVMDK_UNREFERENCED_PARAMETER( data_handle )
2655
0
  LIBVMDK_UNREFERENCED_PARAMETER( segment_index )
2656
2657
0
  segment_offset = libbfio_pool_seek_offset(
2658
0
                    file_io_pool,
2659
0
                    segment_file_index,
2660
0
                    segment_offset,
2661
0
                    SEEK_SET,
2662
0
                    error );
2663
2664
0
  if( segment_offset == -1 )
2665
0
  {
2666
0
    libcerror_error_set(
2667
0
     error,
2668
0
     LIBCERROR_ERROR_DOMAIN_IO,
2669
0
     LIBCERROR_IO_ERROR_READ_FAILED,
2670
0
     "%s: unable to seek segment offset.",
2671
0
     function );
2672
2673
0
    return( -1 );
2674
0
  }
2675
0
  return( segment_offset );
2676
0
}
2677