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