1 /*
2  * Extent table 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 <memory.h>
24 #include <narrow_string.h>
25 #include <system_string.h>
26 #include <types.h>
27 #include <wide_string.h>
28 
29 #include "libvmdk_definitions.h"
30 #include "libvmdk_extent_descriptor.h"
31 #include "libvmdk_extent_file.h"
32 #include "libvmdk_extent_table.h"
33 #include "libvmdk_libbfio.h"
34 #include "libvmdk_libcdata.h"
35 #include "libvmdk_libcerror.h"
36 #include "libvmdk_libfcache.h"
37 #include "libvmdk_libfdata.h"
38 #include "libvmdk_system_string.h"
39 
40 /* Creates an extent table
41  * Make sure the value extent_table is referencing, is set to NULL
42  * Returns 1 if successful or -1 on error
43  */
libvmdk_extent_table_initialize(libvmdk_extent_table_t ** extent_table,libvmdk_io_handle_t * io_handle,libcerror_error_t ** error)44 int libvmdk_extent_table_initialize(
45      libvmdk_extent_table_t **extent_table,
46      libvmdk_io_handle_t *io_handle,
47      libcerror_error_t **error )
48 {
49 	static char *function = "libvmdk_extent_table_initialize";
50 
51 	if( extent_table == NULL )
52 	{
53 		libcerror_error_set(
54 		 error,
55 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
56 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
57 		 "%s: invalid extent table.",
58 		 function );
59 
60 		return( -1 );
61 	}
62 	if( *extent_table != NULL )
63 	{
64 		libcerror_error_set(
65 		 error,
66 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
67 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
68 		 "%s: invalid extent table value already set.",
69 		 function );
70 
71 		return( -1 );
72 	}
73 	if( io_handle == NULL )
74 	{
75 		libcerror_error_set(
76 		 error,
77 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
78 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
79 		 "%s: invalid IO handle.",
80 		 function );
81 
82 		return( -1 );
83 	}
84 	*extent_table = memory_allocate_structure(
85 	                 libvmdk_extent_table_t );
86 
87 	if( *extent_table == NULL )
88 	{
89 		libcerror_error_set(
90 		 error,
91 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
92 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
93 		 "%s: unable to create extent table.",
94 		 function );
95 
96 		goto on_error;
97 	}
98 	if( memory_set(
99 	     *extent_table,
100 	     0,
101 	     sizeof( libvmdk_extent_table_t ) ) == NULL )
102 	{
103 		libcerror_error_set(
104 		 error,
105 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
106 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
107 		 "%s: unable to clear extent table.",
108 		 function );
109 
110 		goto on_error;
111 	}
112 	( *extent_table )->io_handle = io_handle;
113 
114 	return( 1 );
115 
116 on_error:
117 	if( *extent_table != NULL )
118 	{
119 		memory_free(
120 		 *extent_table );
121 
122 		*extent_table = NULL;
123 	}
124 	return( -1 );
125 }
126 
127 /* Frees an extent table
128  * Returns 1 if successful or -1 on error
129  */
libvmdk_extent_table_free(libvmdk_extent_table_t ** extent_table,libcerror_error_t ** error)130 int libvmdk_extent_table_free(
131      libvmdk_extent_table_t **extent_table,
132      libcerror_error_t **error )
133 {
134 	static char *function = "libvmdk_extent_table_free";
135 	int result            = 1;
136 
137 	if( extent_table == NULL )
138 	{
139 		libcerror_error_set(
140 		 error,
141 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
142 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
143 		 "%s: invalid extent table.",
144 		 function );
145 
146 		return( -1 );
147 	}
148 	if( *extent_table != NULL )
149 	{
150 		if( libvmdk_extent_table_clear(
151 		     *extent_table,
152 		     error ) != 1 )
153 		{
154 			libcerror_error_set(
155 			 error,
156 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
157 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
158 			 "%s: unable to clear extent table.",
159 			 function );
160 
161 			result = -1;
162 		}
163 		memory_free(
164 		 *extent_table );
165 
166 		*extent_table = NULL;
167 	}
168 	return( result );
169 }
170 
171 /* Clears the extent table
172  * Returns 1 if successful or -1 on error
173  */
libvmdk_extent_table_clear(libvmdk_extent_table_t * extent_table,libcerror_error_t ** error)174 int libvmdk_extent_table_clear(
175      libvmdk_extent_table_t *extent_table,
176      libcerror_error_t **error )
177 {
178 	static char *function = "libvmdk_extent_table_clear";
179 	int result            = 1;
180 
181 	if( extent_table == NULL )
182 	{
183 		libcerror_error_set(
184 		 error,
185 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
186 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
187 		 "%s: invalid extent table.",
188 		 function );
189 
190 		return( -1 );
191 	}
192 	if( extent_table->data_files_path != NULL )
193 	{
194 		memory_free(
195 		 extent_table->data_files_path );
196 
197 		extent_table->data_files_path      = NULL;
198 		extent_table->data_files_path_size = 0;
199 	}
200 	if( extent_table->extent_files_list != NULL )
201 	{
202 		if( libfdata_list_free(
203 		     &( extent_table->extent_files_list ),
204 		     error ) != 1 )
205 		{
206 			libcerror_error_set(
207 			 error,
208 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
209 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
210 			 "%s: unable to free extent files list.",
211 			 function );
212 
213 			result = -1;
214 		}
215 	}
216 	if( extent_table->extent_files_cache != NULL )
217 	{
218 		if( libfcache_cache_free(
219 		     &( extent_table->extent_files_cache ),
220 		     error ) != 1 )
221 		{
222 			libcerror_error_set(
223 			 error,
224 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
225 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
226 			 "%s: unable to free extent files cache.",
227 			 function );
228 
229 			result = -1;
230 		}
231 	}
232 	if( extent_table->extent_files_stream != NULL )
233 	{
234 		if( libfdata_stream_free(
235 		     &( extent_table->extent_files_stream ),
236 		     error ) != 1 )
237 		{
238 			libcerror_error_set(
239 			 error,
240 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
241 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
242 			 "%s: unable to free extent files stream.",
243 			 function );
244 
245 			result = -1;
246 		}
247 	}
248 	if( memory_set(
249 	     extent_table,
250 	     0,
251 	     sizeof( libvmdk_extent_table_t ) ) == NULL )
252 	{
253 		libcerror_error_set(
254 		 error,
255 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
256 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
257 		 "%s: unable to extent table.",
258 		 function );
259 
260 		result = -1;
261 	}
262 	return( result );
263 }
264 
265 /* Clones the extent table
266  * Returns 1 if successful or -1 on error
267  */
libvmdk_extent_table_clone(libvmdk_extent_table_t ** destination_extent_table,libvmdk_extent_table_t * source_extent_table,libcerror_error_t ** error)268 int libvmdk_extent_table_clone(
269      libvmdk_extent_table_t **destination_extent_table,
270      libvmdk_extent_table_t *source_extent_table,
271      libcerror_error_t **error )
272 {
273 	static char *function = "libvmdk_extent_table_clone";
274 
275 	if( destination_extent_table == NULL )
276 	{
277 		libcerror_error_set(
278 		 error,
279 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
280 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
281 		 "%s: invalid destination extent table.",
282 		 function );
283 
284 		return( -1 );
285 	}
286 	if( *destination_extent_table != NULL )
287 	{
288 		libcerror_error_set(
289 		 error,
290 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
291 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
292 		 "%s: invalid destination extent table value already set.",
293 		 function );
294 
295 		return( -1 );
296 	}
297 	if( source_extent_table == NULL )
298 	{
299 		*destination_extent_table = NULL;
300 
301 		return( 1 );
302 	}
303 	*destination_extent_table = memory_allocate_structure(
304 	                             libvmdk_extent_table_t );
305 
306 	if( *destination_extent_table == NULL )
307 	{
308 		libcerror_error_set(
309 		 error,
310 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
311 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
312 		 "%s: unable to create destination extent table.",
313 		 function );
314 
315 		goto on_error;
316 	}
317 	if( memory_set(
318 	     *destination_extent_table,
319 	     0,
320 	     sizeof( libvmdk_extent_table_t ) ) == NULL )
321 	{
322 		libcerror_error_set(
323 		 error,
324 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
325 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
326 		 "%s: unable to clear source to destination extent table.",
327 		 function );
328 
329 		memory_free(
330 		 *destination_extent_table );
331 
332 		*destination_extent_table = NULL;
333 
334 		return( -1 );
335 	}
336 	if( source_extent_table->data_files_path != NULL )
337 	{
338 		( *destination_extent_table )->data_files_path = system_string_allocate(
339 		                                                  source_extent_table->data_files_path_size );
340 
341 		if( *destination_extent_table == NULL )
342 		{
343 			libcerror_error_set(
344 			 error,
345 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
346 			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
347 			 "%s: unable to create destination extent table.",
348 			 function );
349 
350 			goto on_error;
351 		}
352 		if( memory_copy(
353 		     ( *destination_extent_table )->data_files_path,
354 		     source_extent_table->data_files_path,
355 		     sizeof( system_character_t ) * source_extent_table->data_files_path_size ) == NULL )
356 		{
357 			libcerror_error_set(
358 			 error,
359 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
360 			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
361 			 "%s: unable to copy source to destination data files path.",
362 			 function );
363 
364 			goto on_error;
365 		}
366 		( *destination_extent_table )->data_files_path_size = source_extent_table->data_files_path_size;
367 	}
368 	if( libfdata_list_clone(
369 	     &( ( *destination_extent_table )->extent_files_list ),
370 	     source_extent_table->extent_files_list,
371 	     error ) != 1 )
372 	{
373 		libcerror_error_set(
374 		 error,
375 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
376 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
377 		 "%s: unable to create destination extent files list.",
378 		 function );
379 
380 		goto on_error;
381 	}
382 	if( libfcache_cache_clone(
383 	     &( ( *destination_extent_table )->extent_files_cache ),
384 	     source_extent_table->extent_files_cache,
385 	     error ) != 1 )
386 	{
387 		libcerror_error_set(
388 		 error,
389 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
390 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
391 		 "%s: unable to create destination extent files cache.",
392 		 function );
393 
394 		goto on_error;
395 	}
396 	if( libfdata_stream_clone(
397 	     &( ( *destination_extent_table )->extent_files_stream ),
398 	     source_extent_table->extent_files_stream,
399 	     error ) != 1 )
400 	{
401 		libcerror_error_set(
402 		 error,
403 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
404 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
405 		 "%s: unable to create destination extent files stream.",
406 		 function );
407 
408 		goto on_error;
409 	}
410 	return( 1 );
411 
412 on_error:
413 	if( *destination_extent_table != NULL )
414 	{
415 		if( ( *destination_extent_table )->extent_files_cache != NULL )
416 		{
417 			libfcache_cache_free(
418 			 &( ( *destination_extent_table )->extent_files_cache ),
419 			 NULL );
420 		}
421 		if( ( *destination_extent_table )->extent_files_list != NULL )
422 		{
423 			libfdata_list_free(
424 			 &( ( *destination_extent_table )->extent_files_list ),
425 			 NULL );
426 		}
427 		if( ( *destination_extent_table )->data_files_path != NULL )
428 		{
429 			memory_free(
430 			 ( *destination_extent_table )->data_files_path );
431 		}
432 		memory_free(
433 		 *destination_extent_table );
434 
435 		*destination_extent_table = NULL;
436 	}
437 	return( -1 );
438 }
439 
440 /* Retrieves the size of the data file_path
441  * Returns 1 if successful, 0 if value not present or -1 on error
442  */
libvmdk_extent_table_get_data_files_path_size(libvmdk_extent_table_t * extent_table,size_t * path_size,libcerror_error_t ** error)443 int libvmdk_extent_table_get_data_files_path_size(
444      libvmdk_extent_table_t *extent_table,
445      size_t *path_size,
446      libcerror_error_t **error )
447 {
448 	static char *function = "libvmdk_extent_table_get_data_files_path_size";
449 
450 	if( extent_table == NULL )
451 	{
452 		libcerror_error_set(
453 		 error,
454 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
455 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
456 		 "%s: invalid extent table.",
457 		 function );
458 
459 		return( -1 );
460 	}
461 	if( extent_table->data_files_path == NULL )
462 	{
463 		return( 0 );
464 	}
465 	if( libvmdk_system_string_size_to_narrow_string(
466 	     extent_table->data_files_path,
467 	     extent_table->data_files_path_size,
468 	     path_size,
469 	     error ) != 1 )
470 	{
471 		libcerror_error_set(
472 		 error,
473 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
474 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
475 		 "%s: unable to determine data files path size.",
476 		 function );
477 
478 		return( -1 );
479 	}
480 	return( 1 );
481 }
482 
483 /* Retrieves the data files path
484  * Returns 1 if successful, 0 if value not present or -1 on error
485  */
libvmdk_extent_table_get_data_files_path(libvmdk_extent_table_t * extent_table,char * path,size_t path_size,libcerror_error_t ** error)486 int libvmdk_extent_table_get_data_files_path(
487      libvmdk_extent_table_t *extent_table,
488      char *path,
489      size_t path_size,
490      libcerror_error_t **error )
491 {
492 	static char *function   = "libvmdk_extent_table_get_data_files_path";
493 	size_t narrow_path_size = 0;
494 
495 	if( extent_table == NULL )
496 	{
497 		libcerror_error_set(
498 		 error,
499 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
500 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
501 		 "%s: invalid extent table.",
502 		 function );
503 
504 		return( -1 );
505 	}
506 	if( path == NULL )
507 	{
508 		libcerror_error_set(
509 		 error,
510 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
511 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
512 		 "%s: invalid path.",
513 		 function );
514 
515 		return( -1 );
516 	}
517 	if( path_size > (size_t) SSIZE_MAX )
518 	{
519 		libcerror_error_set(
520 		 error,
521 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
522 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
523 		 "%s: invalid path size value exceeds maximum.",
524 		 function );
525 
526 		return( -1 );
527 	}
528 	if( extent_table->data_files_path == NULL )
529 	{
530 		return( 0 );
531 	}
532 	if( libvmdk_system_string_size_to_narrow_string(
533 	     extent_table->data_files_path,
534 	     extent_table->data_files_path_size,
535 	     &narrow_path_size,
536 	     error ) != 1 )
537 	{
538 		libcerror_error_set(
539 		 error,
540 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
541 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
542 		 "%s: unable to determine data files path size.",
543 		 function );
544 
545 		return( -1 );
546 	}
547 	if( path_size < narrow_path_size )
548 	{
549 		libcerror_error_set(
550 		 error,
551 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
552 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
553 		 "%s: path too small.",
554 		 function );
555 
556 		return( -1 );
557 	}
558 	if( libvmdk_system_string_copy_to_narrow_string(
559 	     extent_table->data_files_path,
560 	     extent_table->data_files_path_size,
561 	     path,
562 	     path_size,
563 	     error ) != 1 )
564 	{
565 		libcerror_error_set(
566 		 error,
567 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
568 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
569 		 "%s: unable to set data files path.",
570 		 function );
571 
572 		return( -1 );
573 	}
574 	return( 1 );
575 }
576 
577 /* Sets the data files path
578  * Returns 1 if successful or -1 on error
579  */
libvmdk_extent_table_set_data_files_path(libvmdk_extent_table_t * extent_table,const char * path,size_t path_length,libcerror_error_t ** error)580 int libvmdk_extent_table_set_data_files_path(
581      libvmdk_extent_table_t *extent_table,
582      const char *path,
583      size_t path_length,
584      libcerror_error_t **error )
585 {
586 	static char *function = "libvmdk_extent_table_set_data_files_path";
587 
588 	if( extent_table == NULL )
589 	{
590 		libcerror_error_set(
591 		 error,
592 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
593 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
594 		 "%s: invalid extent table.",
595 		 function );
596 
597 		return( -1 );
598 	}
599 	if( path == NULL )
600 	{
601 		libcerror_error_set(
602 		 error,
603 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
604 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
605 		 "%s: invalid path.",
606 		 function );
607 
608 		return( -1 );
609 	}
610 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
611 	{
612 		libcerror_error_set(
613 		 error,
614 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
615 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
616 		 "%s: invalid path length value exceeds maximum.",
617 		 function );
618 
619 		return( -1 );
620 	}
621 	if( extent_table->data_files_path != NULL )
622 	{
623 		memory_free(
624 		 extent_table->data_files_path );
625 
626 		extent_table->data_files_path      = NULL;
627 		extent_table->data_files_path_size = 0;
628 	}
629 	if( libvmdk_system_string_size_from_narrow_string(
630 	     path,
631 	     path_length + 1,
632 	     &( extent_table->data_files_path_size ),
633 	     error ) != 1 )
634 	{
635 		libcerror_error_set(
636 		 error,
637 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
638 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
639 		 "%s: unable to determine data files path size.",
640 		 function );
641 
642 		goto on_error;
643 	}
644 	extent_table->data_files_path = system_string_allocate(
645 	                                 extent_table->data_files_path_size );
646 
647 	if( extent_table->data_files_path == NULL )
648 	{
649 		libcerror_error_set(
650 		 error,
651 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
652 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
653 		 "%s: unable to create data files path.",
654 		 function );
655 
656 		goto on_error;
657 	}
658 	if( libvmdk_system_string_copy_from_narrow_string(
659 	     extent_table->data_files_path,
660 	     extent_table->data_files_path_size,
661 	     path,
662 	     path_length + 1,
663 	     error ) != 1 )
664 	{
665 		libcerror_error_set(
666 		 error,
667 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
668 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
669 		 "%s: unable to set data files path.",
670 		 function );
671 
672 		goto on_error;
673 	}
674 	return( 1 );
675 
676 on_error:
677 	if( extent_table->data_files_path != NULL )
678 	{
679 		memory_free(
680 		 extent_table->data_files_path );
681 
682 		extent_table->data_files_path = NULL;
683 	}
684 	extent_table->data_files_path_size = 0;
685 
686 	return( -1 );
687 }
688 
689 #if defined( HAVE_WIDE_CHARACTER_TYPE )
690 
691 /* Retrieves the size of the data files path
692  * Returns 1 if successful, 0 if value not present or -1 on error
693  */
libvmdk_extent_table_get_data_files_path_size_wide(libvmdk_extent_table_t * extent_table,size_t * path_size,libcerror_error_t ** error)694 int libvmdk_extent_table_get_data_files_path_size_wide(
695      libvmdk_extent_table_t *extent_table,
696      size_t *path_size,
697      libcerror_error_t **error )
698 {
699 	static char *function = "libvmdk_extent_table_get_data_files_path_size_wide";
700 
701 	if( extent_table == NULL )
702 	{
703 		libcerror_error_set(
704 		 error,
705 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
706 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
707 		 "%s: invalid extent table.",
708 		 function );
709 
710 		return( -1 );
711 	}
712 	if( path_size == NULL )
713 	{
714 		libcerror_error_set(
715 		 error,
716 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
717 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
718 		 "%s: invalid path size.",
719 		 function );
720 
721 		return( -1 );
722 	}
723 	if( extent_table->data_files_path == NULL )
724 	{
725 		return( 0 );
726 	}
727 	if( libvmdk_system_string_size_to_wide_string(
728 	     extent_table->data_files_path,
729 	     extent_table->data_files_path_size,
730 	     path_size,
731 	     error ) != 1 )
732 	{
733 		libcerror_error_set(
734 		 error,
735 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
736 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
737 		 "%s: unable to determine data files path size.",
738 		 function );
739 
740 		return( -1 );
741 	}
742 	return( 1 );
743 }
744 
745 /* Retrieves the data files path
746  * Returns 1 if successful, 0 if value not present or -1 on error
747  */
libvmdk_extent_table_get_data_files_path_wide(libvmdk_extent_table_t * extent_table,wchar_t * path,size_t path_size,libcerror_error_t ** error)748 int libvmdk_extent_table_get_data_files_path_wide(
749      libvmdk_extent_table_t *extent_table,
750      wchar_t *path,
751      size_t path_size,
752      libcerror_error_t **error )
753 {
754 	static char *function = "libvmdk_extent_table_get_data_files_path_wide";
755 	size_t wide_path_size = 0;
756 
757 	if( extent_table == NULL )
758 	{
759 		libcerror_error_set(
760 		 error,
761 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
762 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
763 		 "%s: invalid extent table.",
764 		 function );
765 
766 		return( -1 );
767 	}
768 	if( path == NULL )
769 	{
770 		libcerror_error_set(
771 		 error,
772 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
773 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
774 		 "%s: invalid path.",
775 		 function );
776 
777 		return( -1 );
778 	}
779 	if( path_size > (size_t) SSIZE_MAX )
780 	{
781 		libcerror_error_set(
782 		 error,
783 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
784 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
785 		 "%s: invalid path size value exceeds maximum.",
786 		 function );
787 
788 		return( -1 );
789 	}
790 	if( extent_table->data_files_path == NULL )
791 	{
792 		return( 0 );
793 	}
794 	if( libvmdk_system_string_size_to_wide_string(
795 	     extent_table->data_files_path,
796 	     extent_table->data_files_path_size,
797 	     &wide_path_size,
798 	     error ) != 1 )
799 	{
800 		libcerror_error_set(
801 		 error,
802 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
803 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
804 		 "%s: unable to determine data files path size.",
805 		 function );
806 
807 		return( -1 );
808 	}
809 	if( path_size < wide_path_size )
810 	{
811 		libcerror_error_set(
812 		 error,
813 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
814 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
815 		 "%s: path too small.",
816 		 function );
817 
818 		return( -1 );
819 	}
820 	if( libvmdk_system_string_copy_to_wide_string(
821 	     extent_table->data_files_path,
822 	     extent_table->data_files_path_size,
823 	     path,
824 	     path_size,
825 	     error ) != 1 )
826 	{
827 		libcerror_error_set(
828 		 error,
829 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
830 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
831 		 "%s: unable to set data files path.",
832 		 function );
833 
834 		return( -1 );
835 	}
836 	return( 1 );
837 }
838 
839 /* Sets the data files path
840  * Returns 1 if successful or -1 on error
841  */
libvmdk_extent_table_set_data_files_path_wide(libvmdk_extent_table_t * extent_table,const wchar_t * path,size_t path_length,libcerror_error_t ** error)842 int libvmdk_extent_table_set_data_files_path_wide(
843      libvmdk_extent_table_t *extent_table,
844      const wchar_t *path,
845      size_t path_length,
846      libcerror_error_t **error )
847 {
848 	static char *function = "libvmdk_extent_table_set_data_files_path_wide";
849 
850 	if( extent_table == NULL )
851 	{
852 		libcerror_error_set(
853 		 error,
854 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
855 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
856 		 "%s: invalid extent table.",
857 		 function );
858 
859 		return( -1 );
860 	}
861 	if( path == NULL )
862 	{
863 		libcerror_error_set(
864 		 error,
865 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
866 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
867 		 "%s: invalid  path.",
868 		 function );
869 
870 		return( -1 );
871 	}
872 	if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
873 	{
874 		libcerror_error_set(
875 		 error,
876 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
877 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
878 		 "%s: invalid path length value exceeds maximum.",
879 		 function );
880 
881 		return( -1 );
882 	}
883 	if( extent_table->data_files_path != NULL )
884 	{
885 		memory_free(
886 		 extent_table->data_files_path );
887 
888 		extent_table->data_files_path      = NULL;
889 		extent_table->data_files_path_size = 0;
890 	}
891 	if( libvmdk_system_string_size_from_wide_string(
892 	     path,
893 	     path_length + 1,
894 	     &( extent_table->data_files_path_size ),
895 	     error ) != 1 )
896 	{
897 		libcerror_error_set(
898 		 error,
899 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
900 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
901 		 "%s: unable to determine data files path size.",
902 		 function );
903 
904 		goto on_error;
905 	}
906 	extent_table->data_files_path = system_string_allocate(
907 	                                 extent_table->data_files_path_size );
908 
909 	if( extent_table->data_files_path == NULL )
910 	{
911 		libcerror_error_set(
912 		 error,
913 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
914 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
915 		 "%s: unable to create data files path.",
916 		 function );
917 
918 		goto on_error;
919 	}
920 	if( libvmdk_system_string_copy_from_wide_string(
921 	     extent_table->data_files_path,
922 	     extent_table->data_files_path_size,
923 	     path,
924 	     path_length + 1,
925 	     error ) != 1 )
926 	{
927 		libcerror_error_set(
928 		 error,
929 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
930 		 LIBCERROR_CONVERSION_ERROR_GENERIC,
931 		 "%s: unable to set data files path.",
932 		 function );
933 
934 		goto on_error;
935 	}
936 	return( 1 );
937 
938 on_error:
939 	if( extent_table->data_files_path != NULL )
940 	{
941 		memory_free(
942 		 extent_table->data_files_path );
943 
944 		extent_table->data_files_path = NULL;
945 	}
946 	extent_table->data_files_path_size = 0;
947 
948 	return( -1 );
949 }
950 
951 #endif /* defined( HAVE_WIDE_CHARACTER_TYPE ) */
952 
953 /* Initializes the extents
954  * Returns 1 if successful or -1 on error
955  */
libvmdk_extent_table_initialize_extents(libvmdk_extent_table_t * extent_table,int number_of_extents,int disk_type,libcerror_error_t ** error)956 int libvmdk_extent_table_initialize_extents(
957      libvmdk_extent_table_t *extent_table,
958      int number_of_extents,
959      int disk_type,
960      libcerror_error_t **error )
961 {
962 	static char *function = "libvmdk_extent_table_initialize_extents";
963 	int result            = 0;
964 
965 	if( extent_table == NULL )
966 	{
967 		libcerror_error_set(
968 		 error,
969 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
970 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
971 		 "%s: invalid extent table.",
972 		 function );
973 
974 		return( -1 );
975 	}
976 	if( ( disk_type != LIBVMDK_DISK_TYPE_FLAT_2GB_EXTENT )
977 	 && ( disk_type != LIBVMDK_DISK_TYPE_MONOLITHIC_FLAT )
978 	 && ( disk_type != LIBVMDK_DISK_TYPE_SPARSE_2GB_EXTENT )
979 	 && ( disk_type != LIBVMDK_DISK_TYPE_MONOLITHIC_SPARSE )
980 	 && ( disk_type != LIBVMDK_DISK_TYPE_STREAM_OPTIMIZED )
981 	 && ( disk_type != LIBVMDK_DISK_TYPE_VMFS_FLAT )
982 	 && ( disk_type != LIBVMDK_DISK_TYPE_VMFS_FLAT_PRE_ALLOCATED )
983 	 && ( disk_type != LIBVMDK_DISK_TYPE_VMFS_FLAT_ZEROED )
984 	 && ( disk_type != LIBVMDK_DISK_TYPE_VMFS_SPARSE )
985 	 && ( disk_type != LIBVMDK_DISK_TYPE_VMFS_SPARSE_THIN ) )
986 	{
987 		libcerror_error_set(
988 		 error,
989 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
990 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
991 		 "%s: unsupported disk type.",
992 		 function );
993 
994 		return( -1 );
995 	}
996 	if( ( disk_type == LIBVMDK_DISK_TYPE_FLAT_2GB_EXTENT )
997 	 || ( disk_type == LIBVMDK_DISK_TYPE_MONOLITHIC_FLAT )
998 	 || ( disk_type == LIBVMDK_DISK_TYPE_VMFS_FLAT )
999 	 || ( disk_type == LIBVMDK_DISK_TYPE_VMFS_FLAT_PRE_ALLOCATED )
1000 	 || ( disk_type == LIBVMDK_DISK_TYPE_VMFS_FLAT_ZEROED ) )
1001 	{
1002 /* TODO add write support ? */
1003 		result = libfdata_stream_initialize(
1004 		          &( extent_table->extent_files_stream ),
1005 		          (intptr_t *) extent_table->io_handle,
1006 		          NULL,
1007 		          NULL,
1008 		          NULL,
1009 		          (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libvmdk_extent_file_read_segment_data,
1010 		          NULL,
1011 		          (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libvmdk_extent_file_seek_segment_offset,
1012 		          LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
1013 		          error );
1014 
1015 		if( result != 1 )
1016 		{
1017 			libcerror_error_set(
1018 			 error,
1019 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1020 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1021 			 "%s: unable to create extent files stream.",
1022 			 function );
1023 
1024 			goto on_error;
1025 		}
1026 		if( libfdata_stream_resize(
1027 		     extent_table->extent_files_stream,
1028 		     number_of_extents,
1029 		     error ) != 1 )
1030 		{
1031 			libcerror_error_set(
1032 			 error,
1033 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1034 			 LIBCERROR_RUNTIME_ERROR_RESIZE_FAILED,
1035 			 "%s: unable to resize extents file stream.",
1036 			 function );
1037 
1038 			goto on_error;
1039 		}
1040 	}
1041 	else if( ( disk_type == LIBVMDK_DISK_TYPE_SPARSE_2GB_EXTENT )
1042 	      || ( disk_type == LIBVMDK_DISK_TYPE_MONOLITHIC_SPARSE )
1043 	      || ( disk_type == LIBVMDK_DISK_TYPE_STREAM_OPTIMIZED )
1044 	      || ( disk_type == LIBVMDK_DISK_TYPE_VMFS_SPARSE )
1045 	      || ( disk_type == LIBVMDK_DISK_TYPE_VMFS_SPARSE_THIN ) )
1046 	{
1047 /* TODO add write support ? */
1048 		result = libfdata_list_initialize(
1049 		          &( extent_table->extent_files_list ),
1050 		          (intptr_t *) extent_table->io_handle,
1051 		          NULL,
1052 		          NULL,
1053 		          (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_element_data,
1054 		          NULL,
1055 		          LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
1056 		          error );
1057 
1058 		if( result != 1 )
1059 		{
1060 			libcerror_error_set(
1061 			 error,
1062 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1063 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1064 			 "%s: unable to create extent files list.",
1065 			 function );
1066 
1067 			goto on_error;
1068 		}
1069 		if( libfdata_list_resize(
1070 		     extent_table->extent_files_list,
1071 		     number_of_extents,
1072 		     error ) != 1 )
1073 		{
1074 			libcerror_error_set(
1075 			 error,
1076 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1077 			 LIBCERROR_RUNTIME_ERROR_RESIZE_FAILED,
1078 			 "%s: unable to resize extent files list.",
1079 			 function );
1080 
1081 			goto on_error;
1082 		}
1083 		result = libfcache_cache_initialize(
1084 			  &( extent_table->extent_files_cache ),
1085 			  LIBVMDK_MAXIMUM_CACHE_ENTRIES_EXTENT_FILES,
1086 			  error );
1087 
1088 		if( result != 1 )
1089 		{
1090 			libcerror_error_set(
1091 			 error,
1092 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1093 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1094 			 "%s: unable to create extent files cache.",
1095 			 function );
1096 
1097 			goto on_error;
1098 		}
1099 	}
1100 	extent_table->disk_type         = disk_type;
1101 	extent_table->number_of_extents = number_of_extents;
1102 
1103 	return( 1 );
1104 
1105 on_error:
1106 	if( extent_table->extent_files_list != NULL )
1107 	{
1108 		libfdata_list_free(
1109 		 &( extent_table->extent_files_list ),
1110 		 NULL );
1111 	}
1112 	return( -1 );
1113 }
1114 
1115 /* Retrieves the number of extents
1116  * Returns 1 if successful or -1 on error
1117  */
libvmdk_extent_table_get_number_of_extents(libvmdk_extent_table_t * extent_table,int * number_of_extents,libcerror_error_t ** error)1118 int libvmdk_extent_table_get_number_of_extents(
1119      libvmdk_extent_table_t *extent_table,
1120      int *number_of_extents,
1121      libcerror_error_t **error )
1122 {
1123 	static char *function = "libvmdk_extent_table_get_number_of_extents";
1124 
1125 	if( extent_table == NULL )
1126 	{
1127 		libcerror_error_set(
1128 		 error,
1129 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1130 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1131 		 "%s: invalid extent table.",
1132 		 function );
1133 
1134 		return( -1 );
1135 	}
1136 	if( number_of_extents == NULL )
1137 	{
1138 		libcerror_error_set(
1139 		 error,
1140 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1141 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1142 		 "%s: invalid number of extents.",
1143 		 function );
1144 
1145 		return( -1 );
1146 	}
1147 	*number_of_extents = extent_table->number_of_extents;
1148 
1149 	return( 1 );
1150 }
1151 
1152 /* Retrieves a specific extent from the extent table
1153  * Returns 1 if successful or -1 on error
1154  */
libvmdk_extent_table_get_extent_by_index(libvmdk_extent_table_t * extent_table,int extent_index,int * file_io_pool_entry,size64_t * extent_file_size,libcerror_error_t ** error)1155 int libvmdk_extent_table_get_extent_by_index(
1156      libvmdk_extent_table_t *extent_table,
1157      int extent_index,
1158      int *file_io_pool_entry,
1159      size64_t *extent_file_size,
1160      libcerror_error_t **error )
1161 {
1162 	static char *function  = "libvmdk_extent_table_get_extent_by_index";
1163 	off64_t element_offset = 0;
1164 	uint32_t element_flags = 0;
1165 
1166 	if( extent_table == NULL )
1167 	{
1168 		libcerror_error_set(
1169 		 error,
1170 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1171 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1172 		 "%s: invalid extent table.",
1173 		 function );
1174 
1175 		return( -1 );
1176 	}
1177 	if( libfdata_list_get_element_by_index(
1178 	     extent_table->extent_files_list,
1179 	     extent_index,
1180 	     file_io_pool_entry,
1181 	     &element_offset,
1182 	     extent_file_size,
1183 	     &element_flags,
1184 	     error ) != 1 )
1185 	{
1186 		libcerror_error_set(
1187 		 error,
1188 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1189 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1190 		 "%s: unable to retrieve element: %d from extent files list.",
1191 		 function,
1192 		 extent_index );
1193 
1194 		return( -1 );
1195 	}
1196 	return( 1 );
1197 }
1198 
1199 /* Retrieves an extent at a specific offset from the extent table
1200  * Returns 1 if successful, 0 if not or -1 on error
1201  */
libvmdk_extent_table_get_extent_at_offset(libvmdk_extent_table_t * extent_table,off64_t offset,int * file_io_pool_entry,size64_t * extent_file_size,libcerror_error_t ** error)1202 int libvmdk_extent_table_get_extent_at_offset(
1203      libvmdk_extent_table_t *extent_table,
1204      off64_t offset,
1205      int *file_io_pool_entry,
1206      size64_t *extent_file_size,
1207      libcerror_error_t **error )
1208 {
1209 	static char *function           = "libvmdk_extent_table_get_extent_at_offset";
1210 	off64_t element_offset          = 0;
1211 	off64_t extent_file_data_offset = 0;
1212 	uint32_t element_flags          = 0;
1213 	int extent_index                = 0;
1214 	int result                      = 0;
1215 
1216 	if( extent_table == NULL )
1217 	{
1218 		libcerror_error_set(
1219 		 error,
1220 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1221 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1222 		 "%s: invalid extent table.",
1223 		 function );
1224 
1225 		return( -1 );
1226 	}
1227 	result = libfdata_list_get_element_at_offset(
1228 	          extent_table->extent_files_list,
1229 	          offset,
1230 	          &extent_index,
1231 	          &extent_file_data_offset,
1232 	          file_io_pool_entry,
1233 	          &element_offset,
1234 	          extent_file_size,
1235 	          &element_flags,
1236 	          error );
1237 
1238 	if( result == -1 )
1239 	{
1240 		libcerror_error_set(
1241 		 error,
1242 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1243 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1244 		 "%s: unable to retrieve element at offset: %" PRIi64 " from extent files list.",
1245 		 function,
1246 		 offset );
1247 
1248 		return( -1 );
1249 	}
1250 	return( result );
1251 }
1252 
1253 /* Sets the extent storage media size for a specific extent in the extent table
1254  * Returns 1 if successful or -1 on error
1255  */
libvmdk_extent_table_set_extent_storage_media_size_by_index(libvmdk_extent_table_t * extent_table,int extent_index,size64_t storage_media_size,libcerror_error_t ** error)1256 int libvmdk_extent_table_set_extent_storage_media_size_by_index(
1257      libvmdk_extent_table_t *extent_table,
1258      int extent_index,
1259      size64_t storage_media_size,
1260      libcerror_error_t **error )
1261 {
1262 	static char *function = "libvmdk_extent_table_set_extent_storage_media_size_by_index";
1263 
1264 	if( extent_table == NULL )
1265 	{
1266 		libcerror_error_set(
1267 		 error,
1268 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1269 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1270 		 "%s: invalid extent table.",
1271 		 function );
1272 
1273 		return( -1 );
1274 	}
1275 	if( libfdata_list_set_mapped_size_by_index(
1276 	     extent_table->extent_files_list,
1277 	     extent_index,
1278 	     storage_media_size,
1279 	     error ) != 1 )
1280 	{
1281 		libcerror_error_set(
1282 		 error,
1283 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1284 		 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1285 		 "%s: unable to set mapped size of element: %d in extent files list.",
1286 		 function,
1287 		 extent_index );
1288 
1289 		return( -1 );
1290 	}
1291 	return( 1 );
1292 }
1293 
1294 /* Retrieves a specific extent file from the extent table
1295  * Returns 1 if successful or -1 on error
1296  */
libvmdk_extent_table_get_extent_file_by_index(libvmdk_extent_table_t * extent_table,int extent_index,libbfio_pool_t * file_io_pool,libvmdk_extent_file_t ** extent_file,libcerror_error_t ** error)1297 int libvmdk_extent_table_get_extent_file_by_index(
1298      libvmdk_extent_table_t *extent_table,
1299      int extent_index,
1300      libbfio_pool_t *file_io_pool,
1301      libvmdk_extent_file_t **extent_file,
1302      libcerror_error_t **error )
1303 {
1304 	static char *function = "libvmdk_extent_table_get_extent_file_by_index";
1305 
1306 	if( extent_table == NULL )
1307 	{
1308 		libcerror_error_set(
1309 		 error,
1310 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1311 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1312 		 "%s: invalid extent table.",
1313 		 function );
1314 
1315 		return( -1 );
1316 	}
1317 	if( libfdata_list_get_element_value_by_index(
1318 	     extent_table->extent_files_list,
1319 	     (intptr_t *) file_io_pool,
1320 	     (libfdata_cache_t *) extent_table->extent_files_cache,
1321 	     extent_index,
1322 	     (intptr_t **) extent_file,
1323 	     0,
1324 	     error ) != 1 )
1325 	{
1326 		libcerror_error_set(
1327 		 error,
1328 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1329 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1330 		 "%s: unable to retrieve element value: %d from extent files list.",
1331 		 function,
1332 		 extent_index );
1333 
1334 		return( -1 );
1335 	}
1336 	return( 1 );
1337 }
1338 
1339 /* Retrieves an extent file at a specific offset from the extent table
1340  * Returns 1 if successful, 0 if not or -1 on error
1341  */
libvmdk_extent_table_get_extent_file_at_offset(libvmdk_extent_table_t * extent_table,off64_t offset,libbfio_pool_t * file_io_pool,int * extent_index,off64_t * extent_file_data_offset,libvmdk_extent_file_t ** extent_file,libcerror_error_t ** error)1342 int libvmdk_extent_table_get_extent_file_at_offset(
1343      libvmdk_extent_table_t *extent_table,
1344      off64_t offset,
1345      libbfio_pool_t *file_io_pool,
1346      int *extent_index,
1347      off64_t *extent_file_data_offset,
1348      libvmdk_extent_file_t **extent_file,
1349      libcerror_error_t **error )
1350 {
1351 	static char *function = "libvmdk_extent_table_get_extent_file_at_offset";
1352 	int result            = 0;
1353 
1354 	if( extent_table == NULL )
1355 	{
1356 		libcerror_error_set(
1357 		 error,
1358 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1359 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1360 		 "%s: invalid extent table.",
1361 		 function );
1362 
1363 		return( -1 );
1364 	}
1365 	result = libfdata_list_get_element_value_at_offset(
1366 	          extent_table->extent_files_list,
1367 	          (intptr_t *) file_io_pool,
1368 	          (libfdata_cache_t *) extent_table->extent_files_cache,
1369 	          offset,
1370 	          extent_index,
1371 	          extent_file_data_offset,
1372 	          (intptr_t **) extent_file,
1373 	          0,
1374 	          error );
1375 
1376 	if( result == -1 )
1377 	{
1378 		libcerror_error_set(
1379 		 error,
1380 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1381 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1382 		 "%s: unable to retrieve element at offset: %" PRIi64 " from extent files list.",
1383 		 function,
1384 		 offset );
1385 
1386 		return( -1 );
1387 	}
1388 	return( result );
1389 }
1390 
1391 /* Sets a specific extent file in the extent table
1392  * Returns 1 if successful or -1 on error
1393  */
libvmdk_extent_table_set_extent_file_by_index(libvmdk_extent_table_t * extent_table,libbfio_pool_t * file_io_pool,int extent_index,libvmdk_extent_file_t * extent_file,libcerror_error_t ** error)1394 int libvmdk_extent_table_set_extent_file_by_index(
1395      libvmdk_extent_table_t *extent_table,
1396      libbfio_pool_t *file_io_pool,
1397      int extent_index,
1398      libvmdk_extent_file_t *extent_file,
1399      libcerror_error_t **error )
1400 {
1401 	static char *function = "libvmdk_extent_table_set_extent_file_by_index";
1402 
1403 	if( extent_table == NULL )
1404 	{
1405 		libcerror_error_set(
1406 		 error,
1407 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1408 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1409 		 "%s: invalid extent table.",
1410 		 function );
1411 
1412 		return( -1 );
1413 	}
1414 	if( libfdata_list_set_element_value_by_index(
1415 	     extent_table->extent_files_list,
1416 	     (intptr_t *) file_io_pool,
1417 	     (libfdata_cache_t *) extent_table->extent_files_cache,
1418 	     extent_index,
1419 	     (intptr_t *) extent_file,
1420 	     (int (*)(intptr_t **, libcerror_error_t **)) &libvmdk_extent_file_free,
1421 	     LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
1422 	     error ) != 1 )
1423 	{
1424 		libcerror_error_set(
1425 		 error,
1426 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1427 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1428 		 "%s: unable to set element value: %d extent files list.",
1429 		 function,
1430 		 extent_index );
1431 
1432 		return( -1 );
1433 	}
1434 	return( 1 );
1435 }
1436 
1437 /* Sets an extent in the extent table based on the extent descriptor
1438  * Returns 1 if successful or -1 on error
1439  */
libvmdk_extent_table_set_extent_by_extent_descriptor(libvmdk_extent_table_t * extent_table,libvmdk_internal_extent_descriptor_t * extent_descriptor,int extent_index,int file_io_pool_entry,size64_t extent_file_size,off64_t extent_offset,size64_t extent_size,libcerror_error_t ** error)1440 int libvmdk_extent_table_set_extent_by_extent_descriptor(
1441      libvmdk_extent_table_t *extent_table,
1442      libvmdk_internal_extent_descriptor_t *extent_descriptor,
1443      int extent_index,
1444      int file_io_pool_entry,
1445      size64_t extent_file_size,
1446      off64_t extent_offset,
1447      size64_t extent_size,
1448      libcerror_error_t **error )
1449 {
1450 	static char *function = "libvmdk_extent_table_set_extent_by_extent_descriptor";
1451 
1452 	if( extent_table == NULL )
1453 	{
1454 		libcerror_error_set(
1455 		 error,
1456 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1457 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1458 		 "%s: invalid extent table.",
1459 		 function );
1460 
1461 		return( -1 );
1462 	}
1463 	if( extent_descriptor == NULL )
1464 	{
1465 		libcerror_error_set(
1466 		 error,
1467 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1468 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1469 		 "%s: invalid extent descriptor.",
1470 		 function );
1471 
1472 		return( -1 );
1473 	}
1474 	if( ( extent_index < 0 )
1475 	 || ( extent_index > extent_table->number_of_extents ) )
1476 	{
1477 		libcerror_error_set(
1478 		 error,
1479 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1480 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1481 		 "%s: invalid extent index value out of bounds.",
1482 		 function );
1483 
1484 		return( -1 );
1485 	}
1486 	if( extent_index == 0 )
1487 	{
1488 		if( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_FLAT )
1489 		{
1490 			if( ( extent_table->disk_type != LIBVMDK_DISK_TYPE_FLAT_2GB_EXTENT )
1491 			 && ( extent_table->disk_type != LIBVMDK_DISK_TYPE_MONOLITHIC_FLAT ) )
1492 			{
1493 				libcerror_error_set(
1494 				 error,
1495 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1496 				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1497 				 "%s: extent type not supported for disk type.",
1498 				 function );
1499 
1500 				return( -1 );
1501 			}
1502 		}
1503 		else if( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_SPARSE )
1504 		{
1505 			if( ( extent_table->disk_type != LIBVMDK_DISK_TYPE_SPARSE_2GB_EXTENT )
1506 			 && ( extent_table->disk_type != LIBVMDK_DISK_TYPE_MONOLITHIC_SPARSE )
1507 			 && ( extent_table->disk_type != LIBVMDK_DISK_TYPE_STREAM_OPTIMIZED ) )
1508 			{
1509 				libcerror_error_set(
1510 				 error,
1511 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1512 				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1513 				 "%s: extent type not supported for disk type.",
1514 				 function );
1515 
1516 				return( -1 );
1517 			}
1518 		}
1519 		else if( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_VMFS_FLAT )
1520 		{
1521 			if( ( extent_table->disk_type != LIBVMDK_DISK_TYPE_VMFS_FLAT )
1522 			 && ( extent_table->disk_type != LIBVMDK_DISK_TYPE_VMFS_FLAT_PRE_ALLOCATED )
1523 			 && ( extent_table->disk_type != LIBVMDK_DISK_TYPE_VMFS_FLAT_ZEROED ) )
1524 			{
1525 				libcerror_error_set(
1526 				 error,
1527 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1528 				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1529 				 "%s: extent type not supported for disk type.",
1530 				 function );
1531 
1532 				return( -1 );
1533 			}
1534 		}
1535 		else if( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_VMFS_SPARSE )
1536 		{
1537 			if( ( extent_table->disk_type != LIBVMDK_DISK_TYPE_VMFS_SPARSE )
1538 			 && ( extent_table->disk_type != LIBVMDK_DISK_TYPE_VMFS_SPARSE_THIN ) )
1539 			{
1540 				libcerror_error_set(
1541 				 error,
1542 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1543 				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1544 				 "%s: extent type not supported for disk type.",
1545 				 function );
1546 
1547 				return( -1 );
1548 			}
1549 		}
1550 		else
1551 		{
1552 			libcerror_error_set(
1553 			 error,
1554 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1555 			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1556 			 "%s: unsupported extent type.",
1557 			 function );
1558 
1559 			return( -1 );
1560 		}
1561 		extent_table->extent_type = extent_descriptor->type;
1562 	}
1563 	else if( extent_table->extent_type != extent_descriptor->type )
1564 	{
1565 		libcerror_error_set(
1566 		 error,
1567 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1568 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1569 		 "%s: mixed extent types not supported.",
1570 		 function );
1571 
1572 		return( -1 );
1573 	}
1574 	if( ( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_FLAT )
1575 	 || ( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_VMFS_FLAT ) )
1576 	{
1577 		if( ( extent_offset < 0 )
1578 		 || ( (size64_t) extent_offset > extent_file_size ) )
1579 		{
1580 			libcerror_error_set(
1581 			 error,
1582 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1583 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1584 			 "%s: invalid extent offset value out of bounds.",
1585 			 function );
1586 
1587 			return( -1 );
1588 		}
1589 		if( extent_size > ( extent_file_size - (size64_t) extent_offset ) )
1590 		{
1591 			libcerror_error_set(
1592 			 error,
1593 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1594 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1595 			 "%s: invalid extent size value out of bounds.",
1596 			 function );
1597 
1598 			return( -1 );
1599 		}
1600 		if( libfdata_stream_set_segment_by_index(
1601 		     extent_table->extent_files_stream,
1602 		     extent_index,
1603 		     file_io_pool_entry,
1604 		     extent_offset,
1605 		     extent_size,
1606 		     0,
1607 		     error ) != 1 )
1608 		{
1609 			libcerror_error_set(
1610 			 error,
1611 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1612 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1613 			 "%s: unable to set segment: %d in extent files stream.",
1614 			 function,
1615 			 extent_index );
1616 
1617 			return( -1 );
1618 		}
1619 	}
1620 	else if( ( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_SPARSE )
1621 	      || ( extent_descriptor->type == LIBVMDK_EXTENT_TYPE_VMFS_SPARSE ) )
1622 	{
1623 		if( extent_offset != 0 )
1624 		{
1625 			libcerror_error_set(
1626 			 error,
1627 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1628 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1629 			 "%s: invalid extent offset value out of bounds.",
1630 			 function );
1631 
1632 			return( -1 );
1633 		}
1634 		if( libfdata_list_set_element_by_index_with_mapped_size(
1635 		     extent_table->extent_files_list,
1636 		     extent_index,
1637 		     file_io_pool_entry,
1638 		     0,
1639 		     extent_file_size,
1640 		     0,
1641 		     extent_size,
1642 		     error ) != 1 )
1643 		{
1644 			libcerror_error_set(
1645 			 error,
1646 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1647 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1648 			 "%s: unable to set element: %d in extent files list.",
1649 			 function,
1650 			 extent_index );
1651 
1652 			return( -1 );
1653 		}
1654 	}
1655 	return( 1 );
1656 }
1657 
1658