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