1 /*
2  * File functions
3  *
4  * Copyright (C) 2010-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 <types.h>
26 #include <wide_string.h>
27 
28 #include "libqcow_cluster_block.h"
29 #include "libqcow_cluster_table.h"
30 #include "libqcow_codepage.h"
31 #include "libqcow_compression.h"
32 #include "libqcow_debug.h"
33 #include "libqcow_definitions.h"
34 #include "libqcow_encryption.h"
35 #include "libqcow_file_header.h"
36 #include "libqcow_i18n.h"
37 #include "libqcow_io_handle.h"
38 #include "libqcow_file.h"
39 #include "libqcow_libbfio.h"
40 #include "libqcow_libcerror.h"
41 #include "libqcow_libcnotify.h"
42 #include "libqcow_libcthreads.h"
43 #include "libqcow_libfcache.h"
44 #include "libqcow_libfdata.h"
45 #include "libqcow_libuna.h"
46 
47 /* Creates a file
48  * Make sure the value file is referencing, is set to NULL
49  * Returns 1 if successful or -1 on error
50  */
libqcow_file_initialize(libqcow_file_t ** file,libcerror_error_t ** error)51 int libqcow_file_initialize(
52      libqcow_file_t **file,
53      libcerror_error_t **error )
54 {
55 	libqcow_internal_file_t *internal_file = NULL;
56 	static char *function                  = "libqcow_file_initialize";
57 
58 	if( file == NULL )
59 	{
60 		libcerror_error_set(
61 		 error,
62 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
63 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
64 		 "%s: invalid file.",
65 		 function );
66 
67 		return( -1 );
68 	}
69 	if( *file != NULL )
70 	{
71 		libcerror_error_set(
72 		 error,
73 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
74 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
75 		 "%s: invalid file value already set.",
76 		 function );
77 
78 		return( -1 );
79 	}
80 	internal_file = memory_allocate_structure(
81 	                 libqcow_internal_file_t );
82 
83 	if( internal_file == NULL )
84 	{
85 		libcerror_error_set(
86 		 error,
87 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
88 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
89 		 "%s: unable to create file.",
90 		 function );
91 
92 		goto on_error;
93 	}
94 	if( memory_set(
95 	     internal_file,
96 	     0,
97 	     sizeof( libqcow_internal_file_t ) ) == NULL )
98 	{
99 		libcerror_error_set(
100 		 error,
101 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
102 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
103 		 "%s: unable to clear file.",
104 		 function );
105 
106 		memory_free(
107 		 internal_file );
108 
109 		return( -1 );
110 	}
111 	if( libqcow_io_handle_initialize(
112 	     &( internal_file->io_handle ),
113 	     error ) != 1 )
114 	{
115 		libcerror_error_set(
116 		 error,
117 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
118 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
119 		 "%s: unable to create IO handle.",
120 		 function );
121 
122 		goto on_error;
123 	}
124 	if( libqcow_i18n_initialize(
125 	     error ) != 1 )
126 	{
127 		libcerror_error_set(
128 		 error,
129 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
130 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
131 		 "%s: unable to initalize internationalization (i18n).",
132 		 function );
133 
134 		goto on_error;
135 	}
136 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
137 	if( libcthreads_read_write_lock_initialize(
138 	     &( internal_file->read_write_lock ),
139 	     error ) != 1 )
140 	{
141 		libcerror_error_set(
142 		 error,
143 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
144 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
145 		 "%s: unable to initialize read/write lock.",
146 		 function );
147 
148 		goto on_error;
149 	}
150 #endif
151 	internal_file->is_locked = 1;
152 
153 	*file = (libqcow_file_t *) internal_file;
154 
155 	return( 1 );
156 
157 on_error:
158 	if( internal_file != NULL )
159 	{
160 		if( internal_file->io_handle != NULL )
161 		{
162 			libqcow_io_handle_free(
163 			 &( internal_file->io_handle ),
164 			 NULL );
165 		}
166 		memory_free(
167 		 internal_file );
168 	}
169 	return( -1 );
170 }
171 
172 /* Frees a file
173  * Returns 1 if successful or -1 on error
174  */
libqcow_file_free(libqcow_file_t ** file,libcerror_error_t ** error)175 int libqcow_file_free(
176      libqcow_file_t **file,
177      libcerror_error_t **error )
178 {
179 	libqcow_internal_file_t *internal_file = NULL;
180 	static char *function                  = "libqcow_file_free";
181 	int result                             = 1;
182 
183 	if( file == NULL )
184 	{
185 		libcerror_error_set(
186 		 error,
187 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
188 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
189 		 "%s: invalid file.",
190 		 function );
191 
192 		return( -1 );
193 	}
194 	if( *file != NULL )
195 	{
196 		internal_file = (libqcow_internal_file_t *) *file;
197 
198 		if( internal_file->file_io_handle != NULL )
199 		{
200 			if( libqcow_file_close(
201 			     *file,
202 			     error ) != 0 )
203 			{
204 				libcerror_error_set(
205 				 error,
206 				 LIBCERROR_ERROR_DOMAIN_IO,
207 				 LIBCERROR_IO_ERROR_CLOSE_FAILED,
208 				 "%s: unable to close file.",
209 				 function );
210 
211 				result = -1;
212 			}
213 		}
214 		*file = NULL;
215 
216 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
217 		if( libcthreads_read_write_lock_free(
218 		     &( internal_file->read_write_lock ),
219 		     error ) != 1 )
220 		{
221 			libcerror_error_set(
222 			 error,
223 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
224 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
225 			 "%s: unable to free read/write lock.",
226 			 function );
227 
228 			result = -1;
229 		}
230 #endif
231 		if( libqcow_io_handle_free(
232 		     &( internal_file->io_handle ),
233 		     error ) != 1 )
234 		{
235 			libcerror_error_set(
236 			 error,
237 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
238 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
239 			 "%s: unable to free IO handle.",
240 			 function );
241 
242 			result = -1;
243 		}
244 		if( memory_set(
245 		     internal_file->key_data,
246 		     0,
247 		     16 ) == NULL )
248 		{
249 			libcerror_error_set(
250 			 error,
251 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
252 			 LIBCERROR_MEMORY_ERROR_SET_FAILED,
253 			 "%s: unable to clear key data.",
254 			 function );
255 
256 			result = -1;
257 		}
258 		memory_free(
259 		 internal_file );
260 	}
261 	return( result );
262 }
263 
264 /* Signals a file to abort its current activity
265  * Returns 1 if successful or -1 on error
266  */
libqcow_file_signal_abort(libqcow_file_t * file,libcerror_error_t ** error)267 int libqcow_file_signal_abort(
268      libqcow_file_t *file,
269      libcerror_error_t **error )
270 {
271 	libqcow_internal_file_t *internal_file = NULL;
272 	static char *function                  = "libqcow_file_signal_abort";
273 
274 	if( file == NULL )
275 	{
276 		libcerror_error_set(
277 		 error,
278 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
279 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
280 		 "%s: invalid file.",
281 		 function );
282 
283 		return( -1 );
284 	}
285 	internal_file = (libqcow_internal_file_t *) file;
286 
287 	if( internal_file->io_handle == NULL )
288 	{
289 		libcerror_error_set(
290 		 error,
291 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
292 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
293 		 "%s: invalid file - missing IO handle.",
294 		 function );
295 
296 		return( -1 );
297 	}
298 	internal_file->io_handle->abort = 1;
299 
300 	return( 1 );
301 }
302 
303 /* Opens a file
304  * Returns 1 if successful or -1 on error
305  */
libqcow_file_open(libqcow_file_t * file,const char * filename,int access_flags,libcerror_error_t ** error)306 int libqcow_file_open(
307      libqcow_file_t *file,
308      const char *filename,
309      int access_flags,
310      libcerror_error_t **error )
311 {
312 	libbfio_handle_t *file_io_handle       = NULL;
313 	libqcow_internal_file_t *internal_file = NULL;
314 	static char *function                  = "libqcow_file_open";
315 
316 	if( file == NULL )
317 	{
318 		libcerror_error_set(
319 		 error,
320 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
321 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
322 		 "%s: invalid file.",
323 		 function );
324 
325 		return( -1 );
326 	}
327 	if( filename == NULL )
328 	{
329 		libcerror_error_set(
330 		 error,
331 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
332 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
333 		 "%s: invalid filename.",
334 		 function );
335 
336 		return( -1 );
337 	}
338 	if( ( ( access_flags & LIBQCOW_ACCESS_FLAG_READ ) == 0 )
339 	 && ( ( access_flags & LIBQCOW_ACCESS_FLAG_WRITE ) == 0 ) )
340 	{
341 		libcerror_error_set(
342 		 error,
343 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
344 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
345 		 "%s: unsupported access flags.",
346 		 function );
347 
348 		return( -1 );
349 	}
350 	if( ( access_flags & LIBQCOW_ACCESS_FLAG_WRITE ) != 0 )
351 	{
352 		libcerror_error_set(
353 		 error,
354 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
355 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
356 		 "%s: write access currently not supported.",
357 		 function );
358 
359 		return( -1 );
360 	}
361 	internal_file = (libqcow_internal_file_t *) file;
362 
363 	if( libbfio_file_initialize(
364 	     &file_io_handle,
365 	     error ) != 1 )
366 	{
367 		libcerror_error_set(
368 		 error,
369 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
370 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
371 		 "%s: unable to create file IO handle.",
372 		 function );
373 
374 		goto on_error;
375 	}
376 #if defined( HAVE_DEBUG_OUTPUT )
377 	if( libbfio_handle_set_track_offsets_read(
378 	     file_io_handle,
379 	     1,
380 	     error ) != 1 )
381 	{
382                 libcerror_error_set(
383                  error,
384                  LIBCERROR_ERROR_DOMAIN_RUNTIME,
385                  LIBCERROR_RUNTIME_ERROR_SET_FAILED,
386                  "%s: unable to set track offsets read in file IO handle.",
387                  function );
388 
389 		goto on_error;
390 	}
391 #endif
392 	if( libbfio_file_set_name(
393 	     file_io_handle,
394 	     filename,
395 	     narrow_string_length(
396 	      filename ) + 1,
397 	     error ) != 1 )
398 	{
399                 libcerror_error_set(
400                  error,
401                  LIBCERROR_ERROR_DOMAIN_RUNTIME,
402                  LIBCERROR_RUNTIME_ERROR_SET_FAILED,
403                  "%s: unable to set filename in file IO handle.",
404                  function );
405 
406 		goto on_error;
407 	}
408 	if( libqcow_file_open_file_io_handle(
409 	     file,
410 	     file_io_handle,
411 	     access_flags,
412 	     error ) != 1 )
413 	{
414 		libcerror_error_set(
415 		 error,
416 		 LIBCERROR_ERROR_DOMAIN_IO,
417 		 LIBCERROR_IO_ERROR_OPEN_FAILED,
418 		 "%s: unable to open file: %s.",
419 		 function,
420 		 filename );
421 
422 		goto on_error;
423 	}
424 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
425 	if( libcthreads_read_write_lock_grab_for_write(
426 	     internal_file->read_write_lock,
427 	     error ) != 1 )
428 	{
429 		libcerror_error_set(
430 		 error,
431 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
432 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
433 		 "%s: unable to grab read/write lock for writing.",
434 		 function );
435 
436 		return( -1 );
437 	}
438 #endif
439 	internal_file->file_io_handle_created_in_library = 1;
440 
441 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
442 	if( libcthreads_read_write_lock_release_for_write(
443 	     internal_file->read_write_lock,
444 	     error ) != 1 )
445 	{
446 		libcerror_error_set(
447 		 error,
448 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
449 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
450 		 "%s: unable to release read/write lock for writing.",
451 		 function );
452 
453 		return( -1 );
454 	}
455 #endif
456 	return( 1 );
457 
458 on_error:
459 	if( file_io_handle != NULL )
460 	{
461 		libbfio_handle_free(
462 		 &file_io_handle,
463 		 NULL );
464 	}
465 	return( -1 );
466 }
467 
468 #if defined( HAVE_WIDE_CHARACTER_TYPE )
469 
470 /* Opens a file
471  * Returns 1 if successful or -1 on error
472  */
libqcow_file_open_wide(libqcow_file_t * file,const wchar_t * filename,int access_flags,libcerror_error_t ** error)473 int libqcow_file_open_wide(
474      libqcow_file_t *file,
475      const wchar_t *filename,
476      int access_flags,
477      libcerror_error_t **error )
478 {
479 	libbfio_handle_t *file_io_handle       = NULL;
480 	libqcow_internal_file_t *internal_file = NULL;
481 	static char *function                  = "libqcow_file_open_wide";
482 
483 	if( file == NULL )
484 	{
485 		libcerror_error_set(
486 		 error,
487 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
488 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
489 		 "%s: invalid file.",
490 		 function );
491 
492 		return( -1 );
493 	}
494 	if( filename == NULL )
495 	{
496 		libcerror_error_set(
497 		 error,
498 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
499 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
500 		 "%s: invalid filename.",
501 		 function );
502 
503 		return( -1 );
504 	}
505 	if( ( ( access_flags & LIBQCOW_ACCESS_FLAG_READ ) == 0 )
506 	 && ( ( access_flags & LIBQCOW_ACCESS_FLAG_WRITE ) == 0 ) )
507 	{
508 		libcerror_error_set(
509 		 error,
510 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
511 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
512 		 "%s: unsupported access flags.",
513 		 function );
514 
515 		return( -1 );
516 	}
517 	if( ( access_flags & LIBQCOW_ACCESS_FLAG_WRITE ) != 0 )
518 	{
519 		libcerror_error_set(
520 		 error,
521 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
522 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
523 		 "%s: write access currently not supported.",
524 		 function );
525 
526 		return( -1 );
527 	}
528 	internal_file = (libqcow_internal_file_t *) file;
529 
530 	if( libbfio_file_initialize(
531 	     &file_io_handle,
532 	     error ) != 1 )
533 	{
534 		libcerror_error_set(
535 		 error,
536 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
537 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
538 		 "%s: unable to create file IO handle.",
539 		 function );
540 
541 		goto on_error;
542 	}
543 #if defined( HAVE_DEBUG_OUTPUT )
544 	if( libbfio_handle_set_track_offsets_read(
545 	     file_io_handle,
546 	     1,
547 	     error ) != 1 )
548 	{
549                 libcerror_error_set(
550                  error,
551                  LIBCERROR_ERROR_DOMAIN_RUNTIME,
552                  LIBCERROR_RUNTIME_ERROR_SET_FAILED,
553                  "%s: unable to set track offsets read in file IO handle.",
554                  function );
555 
556 		goto on_error;
557 	}
558 #endif
559 	if( libbfio_file_set_name_wide(
560 	     file_io_handle,
561 	     filename,
562 	     wide_string_length(
563 	      filename ) + 1,
564 	     error ) != 1 )
565 	{
566                 libcerror_error_set(
567                  error,
568                  LIBCERROR_ERROR_DOMAIN_RUNTIME,
569                  LIBCERROR_RUNTIME_ERROR_SET_FAILED,
570                  "%s: unable to set filename in file IO handle.",
571                  function );
572 
573 		goto on_error;
574 	}
575 	if( libqcow_file_open_file_io_handle(
576 	     file,
577 	     file_io_handle,
578 	     access_flags,
579 	     error ) != 1 )
580 	{
581 		libcerror_error_set(
582 		 error,
583 		 LIBCERROR_ERROR_DOMAIN_IO,
584 		 LIBCERROR_IO_ERROR_OPEN_FAILED,
585 		 "%s: unable to open file: %ls.",
586 		 function,
587 		 filename );
588 
589 		goto on_error;
590 	}
591 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
592 	if( libcthreads_read_write_lock_grab_for_write(
593 	     internal_file->read_write_lock,
594 	     error ) != 1 )
595 	{
596 		libcerror_error_set(
597 		 error,
598 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
599 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
600 		 "%s: unable to grab read/write lock for writing.",
601 		 function );
602 
603 		return( -1 );
604 	}
605 #endif
606 	internal_file->file_io_handle_created_in_library = 1;
607 
608 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
609 	if( libcthreads_read_write_lock_release_for_write(
610 	     internal_file->read_write_lock,
611 	     error ) != 1 )
612 	{
613 		libcerror_error_set(
614 		 error,
615 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
616 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
617 		 "%s: unable to release read/write lock for writing.",
618 		 function );
619 
620 		return( -1 );
621 	}
622 #endif
623 	return( 1 );
624 
625 on_error:
626 	if( file_io_handle != NULL )
627 	{
628 		libbfio_handle_free(
629 		 &file_io_handle,
630 		 NULL );
631 	}
632 	return( -1 );
633 }
634 
635 #endif /* defined( HAVE_WIDE_CHARACTER_TYPE ) */
636 
637 /* Opens a file using a Basic File IO (bfio) handle
638  * Returns 1 if successful or -1 on error
639  */
libqcow_file_open_file_io_handle(libqcow_file_t * file,libbfio_handle_t * file_io_handle,int access_flags,libcerror_error_t ** error)640 int libqcow_file_open_file_io_handle(
641      libqcow_file_t *file,
642      libbfio_handle_t *file_io_handle,
643      int access_flags,
644      libcerror_error_t **error )
645 {
646 	libqcow_internal_file_t *internal_file = NULL;
647 	static char *function                  = "libqcow_file_open_file_io_handle";
648 	int bfio_access_flags                  = 0;
649 	int file_io_handle_is_open             = 0;
650 	int file_io_handle_opened_in_library   = 0;
651 	int result                             = 0;
652 
653 	if( file == NULL )
654 	{
655 		libcerror_error_set(
656 		 error,
657 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
658 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
659 		 "%s: invalid file.",
660 		 function );
661 
662 		return( -1 );
663 	}
664 	internal_file = (libqcow_internal_file_t *) file;
665 
666 	if( internal_file->file_io_handle != NULL )
667 	{
668 		libcerror_error_set(
669 		 error,
670 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
671 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
672 		 "%s: invalid file - file IO handle already set.",
673 		 function );
674 
675 		return( -1 );
676 	}
677 	if( file_io_handle == NULL )
678 	{
679 		libcerror_error_set(
680 		 error,
681 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
682 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
683 		 "%s: invalid file IO handle.",
684 		 function );
685 
686 		return( -1 );
687 	}
688 	if( ( ( access_flags & LIBQCOW_ACCESS_FLAG_READ ) == 0 )
689 	 && ( ( access_flags & LIBQCOW_ACCESS_FLAG_WRITE ) == 0 ) )
690 	{
691 		libcerror_error_set(
692 		 error,
693 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
694 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
695 		 "%s: unsupported access flags.",
696 		 function );
697 
698 		return( -1 );
699 	}
700 	if( ( access_flags & LIBQCOW_ACCESS_FLAG_WRITE ) != 0 )
701 	{
702 		libcerror_error_set(
703 		 error,
704 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
705 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
706 		 "%s: write access currently not supported.",
707 		 function );
708 
709 		return( -1 );
710 	}
711 	if( ( access_flags & LIBQCOW_ACCESS_FLAG_READ ) != 0 )
712 	{
713 		bfio_access_flags = LIBBFIO_ACCESS_FLAG_READ;
714 	}
715 	file_io_handle_is_open = libbfio_handle_is_open(
716 	                          file_io_handle,
717 	                          error );
718 
719 	if( file_io_handle_is_open == -1 )
720 	{
721 		libcerror_error_set(
722 		 error,
723 		 LIBCERROR_ERROR_DOMAIN_IO,
724 		 LIBCERROR_IO_ERROR_OPEN_FAILED,
725 		 "%s: unable to determine if file IO handle is open.",
726 		 function );
727 
728 		goto on_error;
729 	}
730 	else if( file_io_handle_is_open == 0 )
731 	{
732 		if( libbfio_handle_open(
733 		     file_io_handle,
734 		     bfio_access_flags,
735 		     error ) != 1 )
736 		{
737 			libcerror_error_set(
738 			 error,
739 			 LIBCERROR_ERROR_DOMAIN_IO,
740 			 LIBCERROR_IO_ERROR_OPEN_FAILED,
741 			 "%s: unable to open file IO handle.",
742 			 function );
743 
744 			goto on_error;
745 		}
746 		file_io_handle_opened_in_library = 1;
747 	}
748 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
749 	if( libcthreads_read_write_lock_grab_for_write(
750 	     internal_file->read_write_lock,
751 	     error ) != 1 )
752 	{
753 		libcerror_error_set(
754 		 error,
755 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
756 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
757 		 "%s: unable to grab read/write lock for writing.",
758 		 function );
759 
760 		return( -1 );
761 	}
762 #endif
763 	result = libqcow_internal_file_open_read(
764 	          internal_file,
765 	          file_io_handle,
766 	          error );
767 
768 	if( result != 1 )
769 	{
770 		libcerror_error_set(
771 		 error,
772 		 LIBCERROR_ERROR_DOMAIN_IO,
773 		 LIBCERROR_IO_ERROR_READ_FAILED,
774 		 "%s: unable to read from file IO handle.",
775 		 function );
776 	}
777 	else
778 	{
779 		internal_file->file_io_handle                   = file_io_handle;
780 		internal_file->file_io_handle_opened_in_library = (uint8_t) file_io_handle_opened_in_library;
781 	}
782 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
783 	if( libcthreads_read_write_lock_release_for_write(
784 	     internal_file->read_write_lock,
785 	     error ) != 1 )
786 	{
787 		libcerror_error_set(
788 		 error,
789 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
790 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
791 		 "%s: unable to release read/write lock for writing.",
792 		 function );
793 
794 		return( -1 );
795 	}
796 #endif
797 	return( result );
798 
799 on_error:
800 	if( file_io_handle_opened_in_library != 0 )
801 	{
802 		libbfio_handle_close(
803 		 file_io_handle,
804 		 error );
805 	}
806 	return( -1 );
807 }
808 
809 /* Closes a file
810  * Returns 0 if successful or -1 on error
811  */
libqcow_file_close(libqcow_file_t * file,libcerror_error_t ** error)812 int libqcow_file_close(
813      libqcow_file_t *file,
814      libcerror_error_t **error )
815 {
816 	libqcow_internal_file_t *internal_file = NULL;
817 	static char *function                  = "libqcow_file_close";
818 	int result                             = 0;
819 
820 	if( file == NULL )
821 	{
822 		libcerror_error_set(
823 		 error,
824 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
825 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
826 		 "%s: invalid file.",
827 		 function );
828 
829 		return( -1 );
830 	}
831 	internal_file = (libqcow_internal_file_t *) file;
832 
833 	if( internal_file->file_io_handle == NULL )
834 	{
835 		libcerror_error_set(
836 		 error,
837 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
838 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
839 		 "%s: invalid file - missing file IO handle.",
840 		 function );
841 
842 		return( -1 );
843 	}
844 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
845 	if( libcthreads_read_write_lock_grab_for_write(
846 	     internal_file->read_write_lock,
847 	     error ) != 1 )
848 	{
849 		libcerror_error_set(
850 		 error,
851 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
852 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
853 		 "%s: unable to grab read/write lock for writing.",
854 		 function );
855 
856 		return( -1 );
857 	}
858 #endif
859 #if defined( HAVE_DEBUG_OUTPUT )
860 	if( libcnotify_verbose != 0 )
861 	{
862 		if( internal_file->file_io_handle_created_in_library != 0 )
863 		{
864 			if( libqcow_debug_print_read_offsets(
865 			     internal_file->file_io_handle,
866 			     error ) != 1 )
867 			{
868 				libcerror_error_set(
869 				 error,
870 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
871 				 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
872 				 "%s: unable to print the read offsets.",
873 				 function );
874 
875 				result = -1;
876 			}
877 		}
878 	}
879 #endif
880 	if( internal_file->file_io_handle_opened_in_library != 0 )
881 	{
882 		if( libbfio_handle_close(
883 		     internal_file->file_io_handle,
884 		     error ) != 0 )
885 		{
886 			libcerror_error_set(
887 			 error,
888 			 LIBCERROR_ERROR_DOMAIN_IO,
889 			 LIBCERROR_IO_ERROR_CLOSE_FAILED,
890 			 "%s: unable to close file IO handle.",
891 			 function );
892 
893 			result = -1;
894 		}
895 		internal_file->file_io_handle_opened_in_library = 0;
896 	}
897 	if( internal_file->file_io_handle_created_in_library != 0 )
898 	{
899 		if( libbfio_handle_free(
900 		     &( internal_file->file_io_handle ),
901 		     error ) != 1 )
902 		{
903 			libcerror_error_set(
904 			 error,
905 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
906 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
907 			 "%s: unable to free file IO handle.",
908 			 function );
909 
910 			result = -1;
911 		}
912 		internal_file->file_io_handle_created_in_library = 0;
913 	}
914 	internal_file->file_io_handle = NULL;
915 	internal_file->current_offset = 0;
916 	internal_file->is_locked      = 1;
917 
918 	if( libqcow_io_handle_clear(
919 	     internal_file->io_handle,
920 	     error ) != 1 )
921 	{
922 		libcerror_error_set(
923 		 error,
924 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
925 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
926 		 "%s: unable to clear IO handle.",
927 		 function );
928 
929 		result = -1;
930 	}
931 	if( libqcow_file_header_free(
932 	     &( internal_file->file_header ),
933 	     error ) != 1 )
934 	{
935 		libcerror_error_set(
936 		 error,
937 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
938 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
939 		 "%s: unable to free file header.",
940 		 function );
941 
942 		result = -1;
943 	}
944 	if( internal_file->backing_filename != NULL )
945 	{
946 		memory_free(
947 		 internal_file->backing_filename );
948 
949 		internal_file->backing_filename      = NULL;
950 		internal_file->backing_filename_size = 0;
951 	}
952 	if( libqcow_cluster_table_free(
953 	     &( internal_file->level1_table ),
954 	     error ) != 1 )
955 	{
956 		libcerror_error_set(
957 		 error,
958 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
959 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
960 		 "%s: unable to free level 1 table.",
961 		 function );
962 
963 		result = -1;
964 	}
965 	if( libfdata_vector_free(
966 	     &( internal_file->level2_table_vector ),
967 	     error ) != 1 )
968 	{
969 		libcerror_error_set(
970 		 error,
971 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
972 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
973 		 "%s: unable to free level2 table vector.",
974 		 function );
975 
976 		result = -1;
977 	}
978 	if( libfcache_cache_free(
979 	     &( internal_file->level2_table_cache ),
980 	     error ) != 1 )
981 	{
982 		libcerror_error_set(
983 		 error,
984 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
985 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
986 		 "%s: unable to free level2 table cache.",
987 		 function );
988 
989 		result = -1;
990 	}
991 	if( libfdata_vector_free(
992 	     &( internal_file->cluster_block_vector ),
993 	     error ) != 1 )
994 	{
995 		libcerror_error_set(
996 		 error,
997 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
998 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
999 		 "%s: unable to free cluster block vector.",
1000 		 function );
1001 
1002 		result = -1;
1003 	}
1004 	if( libfcache_cache_free(
1005 	     &( internal_file->cluster_block_cache ),
1006 	     error ) != 1 )
1007 	{
1008 		libcerror_error_set(
1009 		 error,
1010 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1011 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1012 		 "%s: unable to free cluster block cache.",
1013 		 function );
1014 
1015 		result = -1;
1016 	}
1017 	if( libfcache_cache_free(
1018 	     &( internal_file->compressed_cluster_block_cache ),
1019 	     error ) != 1 )
1020 	{
1021 		libcerror_error_set(
1022 		 error,
1023 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1024 		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1025 		 "%s: unable to free compressed cluster block cache.",
1026 		 function );
1027 
1028 		result = -1;
1029 	}
1030 	if( internal_file->encryption_context != NULL )
1031 	{
1032 		if( libqcow_encryption_free(
1033 		     &( internal_file->encryption_context ),
1034 		     error ) != 1 )
1035 		{
1036 			libcerror_error_set(
1037 			 error,
1038 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1039 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1040 			 "%s: unable to free encryption context.",
1041 			 function );
1042 
1043 			result = -1;
1044 		}
1045 	}
1046 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
1047 	if( libcthreads_read_write_lock_release_for_write(
1048 	     internal_file->read_write_lock,
1049 	     error ) != 1 )
1050 	{
1051 		libcerror_error_set(
1052 		 error,
1053 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1054 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1055 		 "%s: unable to release read/write lock for writing.",
1056 		 function );
1057 
1058 		return( -1 );
1059 	}
1060 #endif
1061 	return( result );
1062 }
1063 
1064 /* Opens a file for reading
1065  * Returns 1 if successful or -1 on error
1066  */
libqcow_internal_file_open_read(libqcow_internal_file_t * internal_file,libbfio_handle_t * file_io_handle,libcerror_error_t ** error)1067 int libqcow_internal_file_open_read(
1068      libqcow_internal_file_t *internal_file,
1069      libbfio_handle_t *file_io_handle,
1070      libcerror_error_t **error )
1071 {
1072 	static char *function                      = "libqcow_internal_file_open_read";
1073 	size_t level1_table_size                   = 0;
1074 	size_t level2_table_size                   = 0;
1075 	uint32_t number_of_level1_table_references = 0;
1076 	uint32_t number_of_level2_table_bits       = 0;
1077 	int entry_index                            = 0;
1078 
1079 	if( internal_file == NULL )
1080 	{
1081 		libcerror_error_set(
1082 		 error,
1083 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1084 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1085 		 "%s: invalid file.",
1086 		 function );
1087 
1088 		return( -1 );
1089 	}
1090 	if( internal_file->io_handle == NULL )
1091 	{
1092 		libcerror_error_set(
1093 		 error,
1094 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1095 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1096 		 "%s: invalid file - missing IO handle.",
1097 		 function );
1098 
1099 		return( -1 );
1100 	}
1101 	if( internal_file->file_header != NULL )
1102 	{
1103 		libcerror_error_set(
1104 		 error,
1105 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1106 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1107 		 "%s: invalid file - file header value already set.",
1108 		 function );
1109 
1110 		return( -1 );
1111 	}
1112 	if( internal_file->backing_filename != NULL )
1113 	{
1114 		libcerror_error_set(
1115 		 error,
1116 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1117 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1118 		 "%s: invalid file - backing filename value already set.",
1119 		 function );
1120 
1121 		return( -1 );
1122 	}
1123 	if( internal_file->level1_table != NULL )
1124 	{
1125 		libcerror_error_set(
1126 		 error,
1127 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1128 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1129 		 "%s: invalid file - level 1 table already set.",
1130 		 function );
1131 
1132 		return( -1 );
1133 	}
1134 	if( internal_file->level2_table_vector != NULL )
1135 	{
1136 		libcerror_error_set(
1137 		 error,
1138 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1139 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1140 		 "%s: invalid file - level2 table vector already set.",
1141 		 function );
1142 
1143 		return( -1 );
1144 	}
1145 	if( internal_file->level2_table_cache != NULL )
1146 	{
1147 		libcerror_error_set(
1148 		 error,
1149 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1150 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1151 		 "%s: invalid file - level2 table cache already set.",
1152 		 function );
1153 
1154 		return( -1 );
1155 	}
1156 	if( internal_file->cluster_block_vector != NULL )
1157 	{
1158 		libcerror_error_set(
1159 		 error,
1160 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1161 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1162 		 "%s: invalid file - cluster block vector already set.",
1163 		 function );
1164 
1165 		return( -1 );
1166 	}
1167 	if( internal_file->cluster_block_cache != NULL )
1168 	{
1169 		libcerror_error_set(
1170 		 error,
1171 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1172 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1173 		 "%s: invalid file - cluster block cache already set.",
1174 		 function );
1175 
1176 		return( -1 );
1177 	}
1178 	if( internal_file->compressed_cluster_block_cache != NULL )
1179 	{
1180 		libcerror_error_set(
1181 		 error,
1182 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1183 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1184 		 "%s: invalid file - compressed cluster block cache already set.",
1185 		 function );
1186 
1187 		return( -1 );
1188 	}
1189 	if( libbfio_handle_get_size(
1190 	     file_io_handle,
1191 	     &( internal_file->size ),
1192 	     error ) != 1 )
1193 	{
1194 		libcerror_error_set(
1195 		 error,
1196 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1197 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1198 		 "%s: unable to retrieve file size.",
1199 		 function );
1200 
1201 		goto on_error;
1202 	}
1203 	if( internal_file->size == 0 )
1204 	{
1205 		libcerror_error_set(
1206 		 error,
1207 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1208 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1209 		 "%s: invalid file size.",
1210 		 function );
1211 
1212 		goto on_error;
1213 	}
1214 #if defined( HAVE_DEBUG_OUTPUT )
1215 	if( libcnotify_verbose != 0 )
1216 	{
1217 		libcnotify_printf(
1218 		 "Reading file header:\n" );
1219 	}
1220 #endif
1221 	if( libqcow_file_header_initialize(
1222 	     &( internal_file->file_header ),
1223 	     error ) != 1 )
1224 	{
1225 		libcerror_error_set(
1226 		 error,
1227 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1228 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1229 		 "%s: unable to create file header.",
1230 		 function );
1231 
1232 		goto on_error;
1233 	}
1234 	if( libqcow_file_header_read_file_io_handle(
1235 	     internal_file->file_header,
1236 	     file_io_handle,
1237 	     error ) != 1 )
1238 	{
1239 		libcerror_error_set(
1240 		 error,
1241 		 LIBCERROR_ERROR_DOMAIN_IO,
1242 		 LIBCERROR_IO_ERROR_READ_FAILED,
1243 		 "%s: unable to read file header.",
1244 		 function );
1245 
1246 		goto on_error;
1247 	}
1248 
1249 	internal_file->encryption_method  = internal_file->file_header->encryption_method;
1250 
1251 	number_of_level1_table_references = internal_file->file_header->number_of_level1_table_references;
1252 
1253 	if( internal_file->file_header->format_version == 1 )
1254 	{
1255 		if( internal_file->file_header->number_of_cluster_block_bits > 63 )
1256 		{
1257 			libcerror_error_set(
1258 			 error,
1259 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1260 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1261 			 "%s: invalid number of cluster block bits value out of bounds.",
1262 			 function );
1263 
1264 			goto on_error;
1265 		}
1266 		if( internal_file->file_header->number_of_level2_table_bits > 63 )
1267 		{
1268 			libcerror_error_set(
1269 			 error,
1270 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1271 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1272 			 "%s: invalid number of cluster block bits value out of bounds.",
1273 			 function );
1274 
1275 			goto on_error;
1276 		}
1277 		number_of_level2_table_bits = internal_file->file_header->number_of_level2_table_bits;
1278 
1279 		internal_file->offset_bit_mask           = 0x7fffffffffffffffULL;
1280 		internal_file->compression_flag_bit_mask = (uint64_t) 1UL << 63;
1281 		internal_file->compression_bit_shift     = 63 - internal_file->file_header->number_of_cluster_block_bits;
1282 	}
1283 	else if( ( internal_file->file_header->format_version == 2 )
1284 	      || ( internal_file->file_header->format_version == 3 ) )
1285 	{
1286 		if( ( internal_file->file_header->number_of_cluster_block_bits <= 8 )
1287 		 || ( internal_file->file_header->number_of_cluster_block_bits > 63 ) )
1288 		{
1289 			libcerror_error_set(
1290 			 error,
1291 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1292 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1293 			 "%s: invalid number of cluster block bits value out of bounds.",
1294 			 function );
1295 
1296 			goto on_error;
1297 		}
1298 		number_of_level2_table_bits = internal_file->file_header->number_of_cluster_block_bits - 3;
1299 
1300 		internal_file->offset_bit_mask           = 0x3fffffffffffffffULL;
1301 		internal_file->compression_flag_bit_mask = (uint64_t) 1UL << 62;
1302 		internal_file->compression_bit_shift     = 62 - ( internal_file->file_header->number_of_cluster_block_bits - 8 );
1303 	}
1304 	internal_file->level1_index_bit_shift = internal_file->file_header->number_of_cluster_block_bits + number_of_level2_table_bits;
1305 
1306 	if( internal_file->level1_index_bit_shift > 63 )
1307 	{
1308 		libcerror_error_set(
1309 		 error,
1310 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1311 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1312 		 "%s: invalid level1 index bit shift value out of bounds.",
1313 		 function );
1314 
1315 		goto on_error;
1316 	}
1317 	internal_file->level2_index_bit_mask  = ~( (uint64_t) -1 << number_of_level2_table_bits );
1318 	internal_file->cluster_block_bit_mask = ~( (uint64_t) -1 << internal_file->file_header->number_of_cluster_block_bits );
1319 	internal_file->compression_bit_mask   = ~( (uint64_t) -1 << internal_file->compression_bit_shift );
1320 	internal_file->cluster_block_size     = (size64_t) 1 << internal_file->file_header->number_of_cluster_block_bits;
1321 
1322 	level2_table_size = (size_t) 1 << number_of_level2_table_bits;
1323 
1324 	if( internal_file->file_header->format_version == 1 )
1325 	{
1326 		if( internal_file->cluster_block_size > ( (size64_t) MEMORY_MAXIMUM_ALLOCATION_SIZE / level2_table_size ) )
1327 		{
1328 			libcerror_error_set(
1329 			 error,
1330 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1331 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1332 			 "%s: invalid cluster block size value out of bounds.",
1333 			 function );
1334 
1335 			goto on_error;
1336 		}
1337 		level1_table_size = (size_t) ( internal_file->cluster_block_size * level2_table_size );
1338 
1339 		if( ( internal_file->file_header->media_size / level1_table_size ) > ( (size64_t) UINT32_MAX - 1 ) )
1340 		{
1341 			libcerror_error_set(
1342 			 error,
1343 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1344 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1345 			 "%s: invalid level1 table size value out of bounds: %zd.",
1346 			 function, level1_table_size );
1347 
1348 			goto on_error;
1349 		}
1350 		number_of_level1_table_references = (uint32_t) ( internal_file->file_header->media_size / level1_table_size );
1351 
1352 		if( ( internal_file->file_header->media_size % level1_table_size ) != 0 )
1353 		{
1354 			number_of_level1_table_references += 1;
1355 		}
1356 		level1_table_size = (size_t) number_of_level1_table_references;
1357 	}
1358 	else if( ( internal_file->file_header->format_version == 2 )
1359 	      || ( internal_file->file_header->format_version == 3 ) )
1360 	{
1361 		if( internal_file->cluster_block_size > (size64_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
1362 		{
1363 			libcerror_error_set(
1364 			 error,
1365 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1366 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1367 			 "%s: invalid cluster block size value out of bounds.",
1368 			 function );
1369 
1370 			goto on_error;
1371 		}
1372 		level1_table_size = (size_t) number_of_level1_table_references;
1373 	}
1374 	if( ( level1_table_size == 0 )
1375 	 || ( level1_table_size > ( (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE / 8 ) ) )
1376 	{
1377 		libcerror_error_set(
1378 		 error,
1379 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1380 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1381 		 "%s: invalid level1 table size value out of bounds.",
1382 		 function );
1383 
1384 		goto on_error;
1385 	}
1386 	if( ( level2_table_size == 0 )
1387 	 || ( level2_table_size > ( (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE / 8 ) ) )
1388 	{
1389 		libcerror_error_set(
1390 		 error,
1391 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1392 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1393 		 "%s: invalid level2 table size value out of bounds.",
1394 		 function );
1395 
1396 		goto on_error;
1397 	}
1398 	level1_table_size *= 8;
1399 	level2_table_size *= 8;
1400 
1401 #if defined( HAVE_DEBUG_OUTPUT )
1402 	if( libcnotify_verbose != 0 )
1403 	{
1404 		libcnotify_printf(
1405 		 "%s: level 1 table size\t\t\t: %" PRIzd "\n",
1406 		 function,
1407 		 level1_table_size );
1408 
1409 		libcnotify_printf(
1410 		 "%s: level 2 table size\t\t\t: %" PRIzd "\n",
1411 		 function,
1412 		 level2_table_size );
1413 
1414 		libcnotify_printf(
1415 		 "%s: cluster block size\t\t\t: %" PRIu64 "\n",
1416 		 function,
1417 		 internal_file->cluster_block_size );
1418 
1419 		libcnotify_printf(
1420 		 "\n" );
1421 	}
1422 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
1423 
1424 	if( ( internal_file->file_header->backing_filename_offset > 0 )
1425 	 && ( internal_file->file_header->backing_filename_size > 0 ) )
1426 	{
1427 		if( libqcow_internal_file_open_read_backing_filename(
1428 		     internal_file,
1429 		     file_io_handle,
1430 		     internal_file->file_header->backing_filename_offset,
1431 		     internal_file->file_header->backing_filename_size,
1432 		     error ) != 1 )
1433 		{
1434 			libcerror_error_set(
1435 			 error,
1436 			 LIBCERROR_ERROR_DOMAIN_IO,
1437 			 LIBCERROR_IO_ERROR_READ_FAILED,
1438 			 "%s: unable to read backing filename.",
1439 			 function );
1440 
1441 			goto on_error;
1442 		}
1443 	}
1444 	if( internal_file->encryption_method != LIBQCOW_ENCRYPTION_METHOD_NONE )
1445 	{
1446 		if( libqcow_encryption_initialize(
1447 		     &( internal_file->encryption_context ),
1448 		     internal_file->encryption_method,
1449 		     error ) != 1 )
1450 		{
1451 			libcerror_error_set(
1452 			 error,
1453 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1454 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1455 			 "%s: unable to create encryption context.",
1456 			 function );
1457 
1458 			goto on_error;
1459 		}
1460 #if defined( HAVE_DEBUG_OUTPUT )
1461 		if( libcnotify_verbose != 0 )
1462 		{
1463 			libcnotify_printf(
1464 			 "%s: key:\n",
1465 			 function );
1466 			libcnotify_print_data(
1467 			 internal_file->key_data,
1468 			 16,
1469 			 0 );
1470 		}
1471 #endif
1472 		if( libqcow_encryption_set_keys(
1473 		     internal_file->encryption_context,
1474 		     internal_file->key_data,
1475 		     16,
1476 		     error ) != 1 )
1477 		{
1478 			libcerror_error_set(
1479 			 error,
1480 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1481 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1482 			 "%s: unable to set key data in encryption context.",
1483 			 function );
1484 
1485 			goto on_error;
1486 		}
1487 	}
1488 #if defined( HAVE_DEBUG_OUTPUT )
1489 	if( libcnotify_verbose != 0 )
1490 	{
1491 		libcnotify_printf(
1492 		 "Reading level 1 table:\n" );
1493 	}
1494 #endif
1495 	if( libqcow_cluster_table_initialize(
1496 	     &( internal_file->level1_table ),
1497 	     error ) != 1 )
1498 	{
1499 		libcerror_error_set(
1500 		 error,
1501 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1502 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1503 		 "%s: unable to create level 1 table.",
1504 		 function );
1505 
1506 		goto on_error;
1507 	}
1508 	if( libqcow_cluster_table_read(
1509 	     internal_file->level1_table,
1510 	     file_io_handle,
1511 	     internal_file->file_header->level1_table_offset,
1512 	     level1_table_size,
1513 	     error ) != 1 )
1514 	{
1515 		libcerror_error_set(
1516 		 error,
1517 		 LIBCERROR_ERROR_DOMAIN_IO,
1518 		 LIBCERROR_IO_ERROR_READ_FAILED,
1519 		 "%s: unable to read level 1 table.",
1520 		 function );
1521 
1522 		goto on_error;
1523 	}
1524 /* TODO clone function ? */
1525 	if( libfdata_vector_initialize(
1526 	     &( internal_file->level2_table_vector ),
1527 	     (size64_t) level2_table_size,
1528 	     (intptr_t *) internal_file->io_handle,
1529 	     NULL,
1530 	     NULL,
1531 	     (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libqcow_io_handle_read_level2_table,
1532 	     NULL,
1533 	     LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
1534 	     error ) != 1 )
1535 	{
1536 		libcerror_error_set(
1537 		 error,
1538 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1539 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1540 		 "%s: unable to create level2 table vector.",
1541 		 function );
1542 
1543 		goto on_error;
1544 	}
1545 	if( libfdata_vector_append_segment(
1546 	     internal_file->level2_table_vector,
1547 	     &entry_index,
1548 	     0,
1549 	     0,
1550 	     internal_file->size,
1551 	     0,
1552 	     error ) != 1 )
1553 	{
1554 		libcerror_error_set(
1555 		 error,
1556 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1557 		 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1558 		 "%s: unable to append segment to level2 table vector.",
1559 		 function );
1560 
1561 		goto on_error;
1562 	}
1563 	if( libfcache_cache_initialize(
1564 	     &( internal_file->level2_table_cache ),
1565 	     LIBQCOW_MAXIMUM_CACHE_ENTRIES_LEVEL2_TABLES,
1566 	     error ) != 1 )
1567 	{
1568 		libcerror_error_set(
1569 		 error,
1570 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1571 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1572 		 "%s: unable to create level2 table cache.",
1573 		 function );
1574 
1575 		goto on_error;
1576 	}
1577 /* TODO clone function ? */
1578 	if( libfdata_vector_initialize(
1579 	     &( internal_file->cluster_block_vector ),
1580 	     internal_file->cluster_block_size,
1581 	     (intptr_t *) internal_file->io_handle,
1582 	     NULL,
1583 	     NULL,
1584 	     (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libqcow_io_handle_read_cluster_block,
1585 	     NULL,
1586 	     LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
1587 	     error ) != 1 )
1588 	{
1589 		libcerror_error_set(
1590 		 error,
1591 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1592 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1593 		 "%s: unable to create cluster block vector.",
1594 		 function );
1595 
1596 		goto on_error;
1597 	}
1598 	if( libfdata_vector_append_segment(
1599 	     internal_file->cluster_block_vector,
1600 	     &entry_index,
1601 	     0,
1602 	     0,
1603 	     internal_file->size,
1604 	     0,
1605 	     error ) != 1 )
1606 	{
1607 		libcerror_error_set(
1608 		 error,
1609 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1610 		 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1611 		 "%s: unable to append segment to cluster block vector.",
1612 		 function );
1613 
1614 		goto on_error;
1615 	}
1616 	if( libfcache_cache_initialize(
1617 	     &( internal_file->cluster_block_cache ),
1618 	     LIBQCOW_MAXIMUM_CACHE_ENTRIES_CLUSTER_BLOCKS,
1619 	     error ) != 1 )
1620 	{
1621 		libcerror_error_set(
1622 		 error,
1623 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1624 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1625 		 "%s: unable to create cluster block cache.",
1626 		 function );
1627 
1628 		goto on_error;
1629 	}
1630 	if( libfcache_cache_initialize(
1631 	     &( internal_file->compressed_cluster_block_cache ),
1632 	     LIBQCOW_MAXIMUM_CACHE_ENTRIES_CLUSTER_BLOCKS,
1633 	     error ) != 1 )
1634 	{
1635 		libcerror_error_set(
1636 		 error,
1637 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1638 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1639 		 "%s: unable to create compressed cluster block cache.",
1640 		 function );
1641 
1642 		goto on_error;
1643 	}
1644 	internal_file->is_locked = 0;
1645 
1646 	return( 1 );
1647 
1648 on_error:
1649 	if( internal_file->cluster_block_cache != NULL )
1650 	{
1651 		libfcache_cache_free(
1652 		 &( internal_file->cluster_block_cache ),
1653 		 NULL );
1654 	}
1655 	if( internal_file->cluster_block_vector != NULL )
1656 	{
1657 		libfdata_vector_free(
1658 		 &( internal_file->cluster_block_vector ),
1659 		 NULL );
1660 	}
1661 	if( internal_file->level2_table_cache != NULL )
1662 	{
1663 		libfcache_cache_free(
1664 		 &( internal_file->level2_table_cache ),
1665 		 NULL );
1666 	}
1667 	if( internal_file->level2_table_vector != NULL )
1668 	{
1669 		libfdata_vector_free(
1670 		 &( internal_file->level2_table_vector ),
1671 		 NULL );
1672 	}
1673 	if( internal_file->level1_table != NULL )
1674 	{
1675 		libqcow_cluster_table_free(
1676 		 &( internal_file->level1_table ),
1677 		 NULL );
1678 	}
1679 	if( internal_file->encryption_context != NULL )
1680 	{
1681 		libqcow_encryption_free(
1682 		 &( internal_file->encryption_context ),
1683 		 NULL );
1684 	}
1685 	if( internal_file->backing_filename != NULL )
1686 	{
1687 		memory_free(
1688 		 internal_file->backing_filename );
1689 
1690 		internal_file->backing_filename = NULL;
1691 	}
1692 	internal_file->backing_filename_size = 0;
1693 
1694 	if( internal_file->file_header != NULL )
1695 	{
1696 		libqcow_file_header_free(
1697 		 &( internal_file->file_header ),
1698 		 NULL );
1699 	}
1700 	return( -1 );
1701 }
1702 
1703 /* Reads the backing filename
1704  * Returns 1 if successful or -1 on error
1705  */
libqcow_internal_file_open_read_backing_filename(libqcow_internal_file_t * internal_file,libbfio_handle_t * file_io_handle,off64_t backing_filename_offset,uint32_t backing_filename_size,libcerror_error_t ** error)1706 int libqcow_internal_file_open_read_backing_filename(
1707      libqcow_internal_file_t *internal_file,
1708      libbfio_handle_t *file_io_handle,
1709      off64_t backing_filename_offset,
1710      uint32_t backing_filename_size,
1711      libcerror_error_t **error )
1712 {
1713 	static char *function = "libqcow_internal_file_open_read_backing_filename";
1714 	ssize_t read_count    = 0;
1715 
1716 	if( internal_file == NULL )
1717 	{
1718 		libcerror_error_set(
1719 		 error,
1720 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1721 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1722 		 "%s: invalid file.",
1723 		 function );
1724 
1725 		return( -1 );
1726 	}
1727 	if( internal_file->backing_filename != NULL )
1728 	{
1729 		libcerror_error_set(
1730 		 error,
1731 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1732 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1733 		 "%s: invalid file - backing filename value already set.",
1734 		 function );
1735 
1736 		return( -1 );
1737 	}
1738 	if( ( backing_filename_size == 0 )
1739 	 || ( backing_filename_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
1740 	{
1741 		libcerror_error_set(
1742 		 error,
1743 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1744 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1745 		 "%s: invalid backing filename size value out of bounds.",
1746 		 function );
1747 
1748 		goto on_error;
1749 	}
1750 	internal_file->backing_filename = (uint8_t *) memory_allocate(
1751 	                                               sizeof( uint8_t ) * backing_filename_size );
1752 
1753 	if( internal_file->backing_filename == NULL )
1754 	{
1755 		libcerror_error_set(
1756 		 error,
1757 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
1758 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1759 		 "%s: unable to create backing filename.",
1760 		 function );
1761 
1762 		goto on_error;
1763 	}
1764 	internal_file->backing_filename_size = (size_t) backing_filename_size;
1765 
1766 #if defined( HAVE_DEBUG_OUTPUT )
1767 	if( libcnotify_verbose != 0 )
1768 	{
1769 		libcnotify_printf(
1770 		 "%s: reading backing filename at offset: %" PRIu64 " (0x%08" PRIx64 ")\n",
1771 		 function,
1772 		 backing_filename_offset,
1773 		 backing_filename_offset );
1774 	}
1775 #endif
1776 	read_count = libbfio_handle_read_buffer_at_offset(
1777 		      file_io_handle,
1778 		      internal_file->backing_filename,
1779 		      (size_t) backing_filename_size,
1780 		      backing_filename_offset,
1781 		      error );
1782 
1783 	if( read_count != (ssize_t) backing_filename_size )
1784 	{
1785 		libcerror_error_set(
1786 		 error,
1787 		 LIBCERROR_ERROR_DOMAIN_IO,
1788 		 LIBCERROR_IO_ERROR_READ_FAILED,
1789 		 "%s: unable to read backing filename data at offset: %" PRIu64 " (0x%08" PRIx64 ").",
1790 		 function,
1791 		 backing_filename_offset,
1792 		 backing_filename_offset );
1793 
1794 		goto on_error;
1795 	}
1796 #if defined( HAVE_DEBUG_OUTPUT )
1797 	if( libcnotify_verbose != 0 )
1798 	{
1799 		libcnotify_printf(
1800 		 "%s: backing filename data:\n",
1801 		 function );
1802 		libcnotify_print_data(
1803 		 internal_file->backing_filename,
1804 		 (size_t) backing_filename_size,
1805 		 0 );
1806 	}
1807 #endif
1808 	return( 1 );
1809 
1810 on_error:
1811 	if( internal_file->backing_filename != NULL )
1812 	{
1813 		memory_free(
1814 		 internal_file->backing_filename );
1815 
1816 		internal_file->backing_filename = NULL;
1817 	}
1818 	internal_file->backing_filename_size = 0;
1819 
1820 	return( -1 );
1821 }
1822 
1823 /* Determines if the file is locked
1824  * Returns 1 if locked, 0 if not or -1 on error
1825  */
libqcow_file_is_locked(libqcow_file_t * file,libcerror_error_t ** error)1826 int libqcow_file_is_locked(
1827      libqcow_file_t *file,
1828      libcerror_error_t **error )
1829 {
1830 	libqcow_internal_file_t *internal_file = NULL;
1831 	static char *function                  = "libqcow_file_is_locked";
1832 	uint8_t is_locked                      = 0;
1833 
1834 	if( file == NULL )
1835 	{
1836 		libcerror_error_set(
1837 		 error,
1838 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1839 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1840 		 "%s: invalid file.",
1841 		 function );
1842 
1843 		return( -1 );
1844 	}
1845 	internal_file = (libqcow_internal_file_t *) file;
1846 
1847 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
1848 	if( libcthreads_read_write_lock_grab_for_read(
1849 	     internal_file->read_write_lock,
1850 	     error ) != 1 )
1851 	{
1852 		libcerror_error_set(
1853 		 error,
1854 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1855 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1856 		 "%s: unable to grab read/write lock for reading.",
1857 		 function );
1858 
1859 		return( -1 );
1860 	}
1861 #endif
1862 	is_locked = internal_file->is_locked;
1863 
1864 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
1865 	if( libcthreads_read_write_lock_release_for_read(
1866 	     internal_file->read_write_lock,
1867 	     error ) != 1 )
1868 	{
1869 		libcerror_error_set(
1870 		 error,
1871 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1872 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1873 		 "%s: unable to release read/write lock for reading.",
1874 		 function );
1875 
1876 		return( -1 );
1877 	}
1878 #endif
1879 	return( is_locked );
1880 }
1881 
1882 /* Retrieves the cluster block offset for a specific offset
1883  * Returns 1 if successful or -1 on error
1884  */
libqcow_internal_file_get_cluster_block_offset(libqcow_internal_file_t * internal_file,libbfio_handle_t * file_io_handle,off64_t offset,uint64_t * cluster_block_offset,uint64_t * cluster_block_data_offset,uint8_t * cluster_block_is_compressed,libcerror_error_t ** error)1885 int libqcow_internal_file_get_cluster_block_offset(
1886      libqcow_internal_file_t *internal_file,
1887      libbfio_handle_t *file_io_handle,
1888      off64_t offset,
1889      uint64_t *cluster_block_offset,
1890      uint64_t *cluster_block_data_offset,
1891      uint8_t *cluster_block_is_compressed,
1892      libcerror_error_t **error )
1893 {
1894 	libqcow_cluster_table_t *level2_table = NULL;
1895 	static char *function                 = "libqcow_internal_file_get_cluster_block_offset";
1896 	off64_t element_data_offset           = 0;
1897 	uint64_t level1_table_index           = 0;
1898 	uint64_t level2_table_index           = 0;
1899 	uint64_t level2_table_offset          = 0;
1900 	uint64_t safe_cluster_block_offset    = 0;
1901 	uint8_t is_compressed                 = 0;
1902 
1903 	if( internal_file == NULL )
1904 	{
1905 		libcerror_error_set(
1906 		 error,
1907 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1908 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1909 		 "%s: invalid file.",
1910 		 function );
1911 
1912 		return( -1 );
1913 	}
1914 	if( internal_file->file_header == NULL )
1915 	{
1916 		libcerror_error_set(
1917 		 error,
1918 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1919 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1920 		 "%s: invalid file - missing file header.",
1921 		 function );
1922 
1923 		return( -1 );
1924 	}
1925 	if( offset < 0 )
1926 	{
1927 		libcerror_error_set(
1928 		 error,
1929 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1930 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1931 		 "%s: invalid offset value out of bounds.",
1932 		 function );
1933 
1934 		return( -1 );
1935 	}
1936 	if( cluster_block_offset == NULL )
1937 	{
1938 		libcerror_error_set(
1939 		 error,
1940 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1941 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1942 		 "%s: invalid cluster block offset.",
1943 		 function );
1944 
1945 		return( -1 );
1946 	}
1947 	if( cluster_block_data_offset == NULL )
1948 	{
1949 		libcerror_error_set(
1950 		 error,
1951 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1952 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1953 		 "%s: invalid cluster block data offset.",
1954 		 function );
1955 
1956 		return( -1 );
1957 	}
1958 	if( cluster_block_is_compressed == NULL )
1959 	{
1960 		libcerror_error_set(
1961 		 error,
1962 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1963 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1964 		 "%s: invalid cluster block is compressed.",
1965 		 function );
1966 
1967 		return( -1 );
1968 	}
1969 	level1_table_index = offset >> internal_file->level1_index_bit_shift;
1970 
1971 #if defined( HAVE_DEBUG_OUTPUT )
1972 	if( libcnotify_verbose != 0 )
1973 	{
1974 		libcnotify_printf(
1975 		 "%s: level 1 table index\t: %" PRIu64 "\n",
1976 		 function,
1977 		 level1_table_index );
1978 	}
1979 #endif
1980 	if( level1_table_index > (uint64_t) INT_MAX )
1981 	{
1982 		libcerror_error_set(
1983 		 error,
1984 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1985 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1986 		 "%s: invalid level 1 table index value out of bounds.",
1987 		 function );
1988 
1989 		return( -1 );
1990 	}
1991 	if( libqcow_cluster_table_get_reference_by_index(
1992 	     internal_file->level1_table,
1993 	     (int) level1_table_index,
1994 	     &level2_table_offset,
1995 	     error ) != 1 )
1996 	{
1997 		libcerror_error_set(
1998 		 error,
1999 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2000 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2001 		 "%s: unable to retrieve level 2 table offset: %" PRIi64 " from level 1 table.",
2002 		 function,
2003 		 level1_table_index );
2004 
2005 		return( -1 );
2006 	}
2007 #if defined( HAVE_DEBUG_OUTPUT )
2008 	if( libcnotify_verbose != 0 )
2009 	{
2010 		libcnotify_printf(
2011 		 "%s: level 2 table offset\t: 0x%08" PRIx64 "\n",
2012 		 function,
2013 		 level2_table_offset );
2014 
2015 		libcnotify_printf(
2016 		 "\n" );
2017 	}
2018 #endif
2019 	level2_table_offset &= internal_file->offset_bit_mask;
2020 
2021 	/* If level2_table_offset is 0 the level 2 table is sparse
2022 	 */
2023 	if( level2_table_offset > 0 )
2024 	{
2025 		if( libfdata_vector_get_element_value_at_offset(
2026 		     internal_file->level2_table_vector,
2027 		     (intptr_t *) file_io_handle,
2028 		     (libfdata_cache_t *) internal_file->level2_table_cache,
2029 		     (off64_t) level2_table_offset,
2030 		     &element_data_offset,
2031 		     (intptr_t **) &level2_table,
2032 		     0,
2033 		     error ) != 1 )
2034 		{
2035 			libcerror_error_set(
2036 			 error,
2037 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2038 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2039 			 "%s: unable to retrieve level2 table at offset: 0x%08" PRIx64 ".",
2040 			 function,
2041 			 level2_table_offset );
2042 
2043 			return( -1 );
2044 		}
2045 		level2_table_index = ( internal_file->current_offset >> internal_file->file_header->number_of_cluster_block_bits ) & internal_file->level2_index_bit_mask;
2046 
2047 #if defined( HAVE_DEBUG_OUTPUT )
2048 		if( libcnotify_verbose != 0 )
2049 		{
2050 			libcnotify_printf(
2051 			 "%s: level 2 table index\t: %" PRIu64 "\n",
2052 			 function,
2053 			 level2_table_index );
2054 		}
2055 #endif
2056 		if( level2_table_index > (uint64_t) INT_MAX )
2057 		{
2058 			libcerror_error_set(
2059 			 error,
2060 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2061 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2062 			 "%s: invalid level 2 table index value out of bounds.",
2063 			 function );
2064 
2065 			return( -1 );
2066 		}
2067 		if( libqcow_cluster_table_get_reference_by_index(
2068 		     level2_table,
2069 		     (int) level2_table_index,
2070 		     &safe_cluster_block_offset,
2071 		     error ) != 1 )
2072 		{
2073 			libcerror_error_set(
2074 			 error,
2075 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2076 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2077 			 "%s: unable to retrieve level 2 table entry: %" PRIu64 ".",
2078 			 function,
2079 			 level2_table_index );
2080 
2081 			return( -1 );
2082 		}
2083 	}
2084 #if defined( HAVE_DEBUG_OUTPUT )
2085 	if( libcnotify_verbose != 0 )
2086 	{
2087 		libcnotify_printf(
2088 		 "%s: table2 entry: %" PRIu64 "\t\t: 0x%08" PRIx64 "\n",
2089 		 function,
2090 		 level2_table_index,
2091 		 safe_cluster_block_offset );
2092 
2093 		libcnotify_printf(
2094 		 "%s: cluster block offset\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
2095 		 function,
2096 		 safe_cluster_block_offset & internal_file->offset_bit_mask,
2097 		 safe_cluster_block_offset & internal_file->offset_bit_mask );
2098 	}
2099 #endif
2100 	if( ( safe_cluster_block_offset & internal_file->compression_flag_bit_mask ) != 0 )
2101 	{
2102 		if( internal_file->encryption_method != LIBQCOW_ENCRYPTION_METHOD_NONE )
2103 		{
2104 			libcerror_error_set(
2105 			 error,
2106 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2107 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2108 			 "%s: simultaneous encryption and compression not supported.",
2109 			 function );
2110 
2111 			return( -1 );
2112 		}
2113 #if defined( HAVE_DEBUG_OUTPUT )
2114 		if( libcnotify_verbose != 0 )
2115 		{
2116 			libcnotify_printf(
2117 			 "%s: is compressed\n",
2118 			 function );
2119 		}
2120 #endif
2121 		is_compressed = 1;
2122 	}
2123 #if defined( HAVE_DEBUG_OUTPUT )
2124 	if( libcnotify_verbose != 0 )
2125 	{
2126 		libcnotify_printf(
2127 		 "\n" );
2128 	}
2129 #endif
2130 	*cluster_block_offset        = safe_cluster_block_offset & internal_file->offset_bit_mask;
2131 	*cluster_block_data_offset   = offset & internal_file->cluster_block_bit_mask;
2132 	*cluster_block_is_compressed = is_compressed;
2133 
2134 	return( 1 );
2135 }
2136 
2137 /* Reads a cluster block
2138  * Returns 1 if successful or -1 on error
2139  */
libqcow_internal_file_read_cluster_block(libqcow_internal_file_t * internal_file,libbfio_handle_t * file_io_handle,uint64_t cluster_block_offset,uint64_t cluster_block_data_offset,uint8_t cluster_block_is_compressed,libqcow_cluster_block_t ** cluster_block,libcerror_error_t ** error)2140 int libqcow_internal_file_read_cluster_block(
2141      libqcow_internal_file_t *internal_file,
2142      libbfio_handle_t *file_io_handle,
2143      uint64_t cluster_block_offset,
2144      uint64_t cluster_block_data_offset,
2145      uint8_t cluster_block_is_compressed,
2146      libqcow_cluster_block_t **cluster_block,
2147      libcerror_error_t **error )
2148 {
2149 	libfcache_cache_t *cluster_block_cache       = NULL;
2150 	libqcow_cluster_block_t *safe_cluster_block  = NULL;
2151 	static char *function                        = "libqcow_internal_file_read_cluster_block";
2152 	size_t cluster_block_size                    = 0;
2153 	size_t safe_cluster_block_data_size          = 0;
2154 	off64_t element_data_offset                  = 0;
2155 	uint64_t block_key                           = 0;
2156 	uint64_t compressed_cluster_block_end_offset = 0;
2157 	int cache_entry_index                        = 0;
2158 
2159 	if( internal_file == NULL )
2160 	{
2161 		libcerror_error_set(
2162 		 error,
2163 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2164 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2165 		 "%s: invalid file.",
2166 		 function );
2167 
2168 		return( -1 );
2169 	}
2170 	if( internal_file->file_header == NULL )
2171 	{
2172 		libcerror_error_set(
2173 		 error,
2174 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2175 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2176 		 "%s: invalid file - missing file header.",
2177 		 function );
2178 
2179 		return( -1 );
2180 	}
2181 	if( internal_file->cluster_block_size == 0 )
2182 	{
2183 		libcerror_error_set(
2184 		 error,
2185 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2186 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2187 		 "%s: invalid file - cluster block size value out of bounds.",
2188 		 function );
2189 
2190 		return( -1 );
2191 	}
2192 	if( cluster_block == NULL )
2193 	{
2194 		libcerror_error_set(
2195 		 error,
2196 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2197 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2198 		 "%s: invalid cluster block.",
2199 		 function );
2200 
2201 		return( -1 );
2202 	}
2203 	if( cluster_block_is_compressed != 0 )
2204 	{
2205 		/* Handle compressed cluster block
2206 		 */
2207 		cluster_block_size    = (size_t) ( cluster_block_offset >> internal_file->compression_bit_shift );
2208 		cluster_block_offset &= internal_file->compression_bit_mask;
2209 
2210 		if( ( internal_file->file_header->format_version == 2 )
2211 		 || ( internal_file->file_header->format_version == 3 ) )
2212 		{
2213 			cluster_block_size += 1;
2214 			cluster_block_size *= 512;
2215 
2216 			/* Make sure the compressed block size stays within the bounds
2217 			 * of the cluster block size and the size of the file
2218 			 */
2219 			compressed_cluster_block_end_offset = cluster_block_offset / internal_file->cluster_block_size;
2220 
2221 			if( ( cluster_block_offset % internal_file->cluster_block_size ) != 0 )
2222 			{
2223 				compressed_cluster_block_end_offset += 1;
2224 			}
2225 			compressed_cluster_block_end_offset += 1;
2226 			compressed_cluster_block_end_offset *= internal_file->cluster_block_size;
2227 
2228 			if( compressed_cluster_block_end_offset > internal_file->size )
2229 			{
2230 				compressed_cluster_block_end_offset = internal_file->size;
2231 			}
2232 			if( ( cluster_block_offset + cluster_block_size ) > compressed_cluster_block_end_offset )
2233 			{
2234 				cluster_block_size = (size_t) ( compressed_cluster_block_end_offset - cluster_block_offset );
2235 			}
2236 		}
2237 #if defined( HAVE_DEBUG_OUTPUT )
2238 		if( libcnotify_verbose != 0 )
2239 		{
2240 			libcnotify_printf(
2241 			 "%s: compressed cluster block offset\t\t: 0x%08" PRIx64 "\n",
2242 			 function,
2243 			 cluster_block_offset );
2244 
2245 			libcnotify_printf(
2246 			 "%s: compressed cluster block size\t\t: %" PRIzd "\n",
2247 			 function,
2248 			 cluster_block_size );
2249 		}
2250 #endif
2251 		cluster_block_cache = internal_file->compressed_cluster_block_cache;
2252 	}
2253 	else
2254 	{
2255 		/* For version 2 and 3 make sure the sure the last cluster block size
2256 		 * stays within the bounds of the size of the file
2257 		 */
2258 		if( ( ( internal_file->file_header->format_version == 2 )
2259 		  ||  ( internal_file->file_header->format_version == 3 ) )
2260 		 && ( ( cluster_block_offset + internal_file->cluster_block_size ) > internal_file->size ) )
2261 		{
2262 			cluster_block_size = (size_t) ( internal_file->size - cluster_block_offset );
2263 
2264 #if defined( HAVE_DEBUG_OUTPUT )
2265 			if( libcnotify_verbose != 0 )
2266 			{
2267 				libcnotify_printf(
2268 				 "%s: last cluster block offset\t\t: 0x%08" PRIx64 "\n",
2269 				 function,
2270 				 cluster_block_offset );
2271 
2272 				libcnotify_printf(
2273 				 "%s: last cluster block size\t\t\t: %" PRIzd "\n",
2274 				 function,
2275 				 cluster_block_size );
2276 			}
2277 #endif
2278 		}
2279 		cluster_block_cache = internal_file->cluster_block_cache;
2280 	}
2281 	if( cluster_block_size != 0 )
2282 	{
2283 /* TODO check cache  */
2284 		if( libqcow_cluster_block_initialize(
2285 		     &safe_cluster_block,
2286 		     cluster_block_size,
2287 		     error ) != 1 )
2288 		{
2289 			libcerror_error_set(
2290 			 error,
2291 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2292 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2293 			 "%s: unable to create cluster block.",
2294 			 function );
2295 
2296 			goto on_error;
2297 		}
2298 		if( libqcow_cluster_block_read(
2299 		     safe_cluster_block,
2300 		     file_io_handle,
2301 		     cluster_block_offset,
2302 		     error ) != 1 )
2303 		{
2304 			libcerror_error_set(
2305 			 error,
2306 			 LIBCERROR_ERROR_DOMAIN_IO,
2307 			 LIBCERROR_IO_ERROR_READ_FAILED,
2308 			 "%s: unable to read cluster block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
2309 			 function,
2310 			 cluster_block_offset,
2311 			 cluster_block_offset );
2312 
2313 			goto on_error;
2314 		}
2315 	}
2316 	else
2317 	{
2318 		if( libfdata_vector_get_element_value_at_offset(
2319 		     internal_file->cluster_block_vector,
2320 		     (intptr_t *) file_io_handle,
2321 		     (libfdata_cache_t *) cluster_block_cache,
2322 		     (off64_t) cluster_block_offset,
2323 		     &element_data_offset,
2324 		     (intptr_t **) cluster_block,
2325 		     0,
2326 		     error ) != 1 )
2327 		{
2328 			libcerror_error_set(
2329 			 error,
2330 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2331 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2332 			 "%s: unable to retrieve cluster block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
2333 			 function,
2334 			 cluster_block_offset,
2335 			 cluster_block_offset );
2336 
2337 			goto on_error;
2338 		}
2339 	}
2340 	if( cluster_block_is_compressed != 0 )
2341 	{
2342 		safe_cluster_block->compressed_data = safe_cluster_block->data;
2343 
2344 		safe_cluster_block->data = (uint8_t *) memory_allocate(
2345 		                                        sizeof( uint8_t ) * internal_file->cluster_block_size );
2346 
2347 		if( safe_cluster_block->data == NULL )
2348 		{
2349 			libcerror_error_set(
2350 			 error,
2351 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
2352 			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2353 			 "%s: unable to create cluster block data.",
2354 			 function );
2355 
2356 			goto on_error;
2357 		}
2358 		safe_cluster_block->data_size = internal_file->cluster_block_size;
2359 
2360 		safe_cluster_block_data_size = safe_cluster_block->data_size;
2361 
2362 		if( libqcow_decompress_data(
2363 		     safe_cluster_block->compressed_data,
2364 		     cluster_block_size,
2365 		     LIBQCOW_COMPRESSION_METHOD_DEFLATE,
2366 		     safe_cluster_block->data,
2367 		     &safe_cluster_block_data_size,
2368 		     error ) != 1 )
2369 		{
2370 			libcerror_error_set(
2371 			 error,
2372 			 LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
2373 			 LIBCERROR_ENCRYPTION_ERROR_GENERIC,
2374 			 "%s: unable to decompress cluster block data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
2375 			 function,
2376 			 cluster_block_offset,
2377 			 cluster_block_offset );
2378 
2379 			goto on_error;
2380 		}
2381 /* TODO check safe_cluster_block_data_size
2382 		if( safe_cluster_block_data_size != safe_cluster_block->data_size )
2383 		{
2384 			libcerror_error_set(
2385 			 error,
2386 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2387 			 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
2388 			 "%s: invalid cluster block size value out of bounds.",
2389 			 function );
2390 
2391 			goto on_error;
2392 		}
2393 */
2394 	}
2395 	if( safe_cluster_block != NULL )
2396 	{
2397 		cache_entry_index = ( cluster_block_offset & internal_file->cluster_block_bit_mask ) % LIBQCOW_MAXIMUM_CACHE_ENTRIES_CLUSTER_BLOCKS;
2398 
2399 		if( libfcache_cache_set_value_by_index(
2400 		     cluster_block_cache,
2401 		     cache_entry_index,
2402 		     0,
2403 		     cluster_block_offset,
2404 		     0,
2405 		     (intptr_t *) safe_cluster_block,
2406 		     (int (*)(intptr_t **, libcerror_error_t **)) &libqcow_cluster_block_free,
2407 		     LIBFCACHE_CACHE_VALUE_FLAG_MANAGED,
2408 		     error ) != 1 )
2409 		{
2410 			libcerror_error_set(
2411 			 error,
2412 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2413 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2414 			 "%s: unable to set value in cache entry: %d.",
2415 			 function,
2416 			 cache_entry_index );
2417 
2418 			goto on_error;
2419 		}
2420 		*cluster_block = safe_cluster_block;
2421 	}
2422 	if( internal_file->encryption_method != LIBQCOW_ENCRYPTION_METHOD_NONE )
2423 	{
2424 		if( *cluster_block == NULL )
2425 		{
2426 			libcerror_error_set(
2427 			 error,
2428 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2429 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2430 			 "%s: missing cluster block.",
2431 			 function );
2432 
2433 			goto on_error;
2434 		}
2435 		if( ( *cluster_block )->encrypted_data == NULL )
2436 		{
2437 			( *cluster_block )->encrypted_data = ( *cluster_block )->data;
2438 
2439 			( *cluster_block )->data = (uint8_t *) memory_allocate(
2440 			                                        sizeof( uint8_t ) * ( *cluster_block )->data_size );
2441 
2442 			if( ( *cluster_block )->data == NULL )
2443 			{
2444 				libcerror_error_set(
2445 				 error,
2446 				 LIBCERROR_ERROR_DOMAIN_MEMORY,
2447 				 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2448 				 "%s: unable to create cluster block data.",
2449 				 function );
2450 
2451 				goto on_error;
2452 			}
2453 			block_key = (uint64_t) ( internal_file->current_offset - cluster_block_data_offset ) / 512;
2454 
2455 			if( libqcow_encryption_crypt(
2456 			     internal_file->encryption_context,
2457 			     LIBQCOW_ENCYPTION_CRYPT_MODE_DECRYPT,
2458 			     ( *cluster_block )->encrypted_data,
2459 			     ( *cluster_block )->data_size,
2460 			     ( *cluster_block )->data,
2461 			     ( *cluster_block )->data_size,
2462 			     block_key,
2463 			     error ) != 1 )
2464 			{
2465 				libcerror_error_set(
2466 				 error,
2467 				 LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
2468 				 LIBCERROR_ENCRYPTION_ERROR_GENERIC,
2469 				 "%s: unable to decrypt cluster block data.",
2470 				 function );
2471 
2472 				goto on_error;
2473 			}
2474 		}
2475 	}
2476 	return( 1 );
2477 
2478 on_error:
2479 	if( safe_cluster_block != NULL )
2480 	{
2481 		libqcow_cluster_block_free(
2482 		 &safe_cluster_block,
2483 		 NULL );
2484 	}
2485 	return( -1 );
2486 }
2487 
2488 /* Reads (media) data from the current offset into a buffer using a Basic File IO (bfio) handle
2489  * This function is not multi-thread safe acquire write lock before call
2490  * Returns the number of bytes read or -1 on error
2491  */
libqcow_internal_file_read_buffer_from_file_io_handle(libqcow_internal_file_t * internal_file,libbfio_handle_t * file_io_handle,void * buffer,size_t buffer_size,libcerror_error_t ** error)2492 ssize_t libqcow_internal_file_read_buffer_from_file_io_handle(
2493          libqcow_internal_file_t *internal_file,
2494          libbfio_handle_t *file_io_handle,
2495          void *buffer,
2496          size_t buffer_size,
2497          libcerror_error_t **error )
2498 {
2499 	libqcow_cluster_block_t *cluster_block = NULL;
2500 	static char *function                  = "libqcow_internal_file_read_buffer_from_file_io_handle";
2501 	size_t buffer_offset                   = 0;
2502 	size_t read_size                       = 0;
2503 	ssize_t read_count                     = 0;
2504 	uint64_t cluster_block_data_offset     = 0;
2505 	uint64_t cluster_block_file_offset     = 0;
2506 	uint8_t cluster_block_is_compressed    = 0;
2507 
2508 	if( internal_file == NULL )
2509 	{
2510 		libcerror_error_set(
2511 		 error,
2512 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2513 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2514 		 "%s: invalid file.",
2515 		 function );
2516 
2517 		return( -1 );
2518 	}
2519 	if( internal_file->file_header == NULL )
2520 	{
2521 		libcerror_error_set(
2522 		 error,
2523 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2524 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2525 		 "%s: invalid file - missing file header.",
2526 		 function );
2527 
2528 		return( -1 );
2529 	}
2530 	if( internal_file->current_offset < 0 )
2531 	{
2532 		libcerror_error_set(
2533 		 error,
2534 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2535 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2536 		 "%s: invalid file - current offset value out of bounds.",
2537 		 function );
2538 
2539 		return( -1 );
2540 	}
2541 	if( internal_file->cluster_block_size == 0 )
2542 	{
2543 		libcerror_error_set(
2544 		 error,
2545 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2546 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2547 		 "%s: invalid file - cluster block size value out of bounds.",
2548 		 function );
2549 
2550 		return( -1 );
2551 	}
2552 	if( internal_file->backing_filename != NULL )
2553 	{
2554 		if( internal_file->parent_file == NULL )
2555 		{
2556 			libcerror_error_set(
2557 			 error,
2558 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2559 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2560 			 "%s: invalid file - missing parent file.",
2561 			 function );
2562 
2563 			return( -1 );
2564 		}
2565 	}
2566 	if( buffer == NULL )
2567 	{
2568 		libcerror_error_set(
2569 		 error,
2570 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2571 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2572 		 "%s: invalid buffer.",
2573 		 function );
2574 
2575 		return( -1 );
2576 	}
2577 	if( buffer_size > (size_t) SSIZE_MAX )
2578 	{
2579 		libcerror_error_set(
2580 		 error,
2581 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2582 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2583 		 "%s: invalid buffer size value exceeds maximum.",
2584 		 function );
2585 
2586 		return( -1 );
2587 	}
2588 	if( (size64_t) internal_file->current_offset >= internal_file->file_header->media_size )
2589 	{
2590 		return( 0 );
2591 	}
2592 	while( buffer_offset < buffer_size )
2593 	{
2594 #if defined( HAVE_DEBUG_OUTPUT )
2595 		if( libcnotify_verbose != 0 )
2596 		{
2597 			libcnotify_printf(
2598 			 "%s: current offset\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
2599 			 function,
2600 			 internal_file->current_offset,
2601 			 internal_file->current_offset );
2602 		}
2603 #endif
2604 		if( libqcow_internal_file_get_cluster_block_offset(
2605 		     internal_file,
2606 		     file_io_handle,
2607 		     internal_file->current_offset,
2608 		     &cluster_block_file_offset,
2609 		     &cluster_block_data_offset,
2610 		     &cluster_block_is_compressed,
2611 		     error ) != 1 )
2612 		{
2613 			libcerror_error_set(
2614 			 error,
2615 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2616 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2617 			 "%s: unable to retrieve cluster block offset for offset: %" PRIi64 " (0x%08" PRIx64 ").",
2618 			 function,
2619 			 internal_file->current_offset,
2620 			 internal_file->current_offset );
2621 
2622 			return( -1 );
2623 		}
2624 		read_size = internal_file->cluster_block_size - (size_t) cluster_block_data_offset;
2625 
2626 		if( ( (size64_t) internal_file->current_offset + read_size ) > internal_file->file_header->media_size )
2627 		{
2628 			read_size = (size_t) ( internal_file->file_header->media_size - internal_file->current_offset );
2629 		}
2630 		if( ( buffer_offset + read_size ) > buffer_size )
2631 		{
2632 			read_size = buffer_size - buffer_offset;
2633 		}
2634 		if( cluster_block_file_offset > 0 )
2635 		{
2636 			if( libqcow_internal_file_read_cluster_block(
2637 			     internal_file,
2638 			     file_io_handle,
2639 			     cluster_block_file_offset,
2640 			     cluster_block_data_offset,
2641 			     cluster_block_is_compressed,
2642 			     &cluster_block,
2643 			     error ) != 1 )
2644 			{
2645 				libcerror_error_set(
2646 				 error,
2647 				 LIBCERROR_ERROR_DOMAIN_IO,
2648 				 LIBCERROR_IO_ERROR_READ_FAILED,
2649 				 "%s: unable to read cluster block.",
2650 				 function );
2651 
2652 				return( -1 );
2653 			}
2654 			if( cluster_block == NULL )
2655 			{
2656 				libcerror_error_set(
2657 				 error,
2658 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2659 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2660 				 "%s: invalid cluster block.",
2661 				 function );
2662 
2663 				return( -1 );
2664 			}
2665 			if( cluster_block->data == NULL )
2666 			{
2667 				libcerror_error_set(
2668 				 error,
2669 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2670 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2671 				 "%s: invalid cluster block - missing data.",
2672 				 function );
2673 
2674 				return( -1 );
2675 			}
2676 			if( memory_copy(
2677 			     &( ( (uint8_t *) buffer )[ buffer_offset ] ),
2678 			     &( cluster_block->data[ cluster_block_data_offset ] ),
2679 			     read_size ) == NULL )
2680 			{
2681 				libcerror_error_set(
2682 				 error,
2683 				 LIBCERROR_ERROR_DOMAIN_MEMORY,
2684 				 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
2685 				 "%s: unable to copy cluster block data to buffer.",
2686 				 function );
2687 
2688 				return( -1 );
2689 			}
2690 		}
2691 		else if( internal_file->parent_file != NULL )
2692 		{
2693 			read_count = libqcow_file_read_buffer_at_offset(
2694 				      internal_file->parent_file,
2695 				      &( ( (uint8_t *) buffer )[ buffer_offset ] ),
2696 				      buffer_size - buffer_offset,
2697 				      internal_file->current_offset,
2698 				      error );
2699 
2700 			if( read_count == -1 )
2701 			{
2702 				libcerror_error_set(
2703 				 error,
2704 				 LIBCERROR_ERROR_DOMAIN_IO,
2705 				 LIBCERROR_IO_ERROR_READ_FAILED,
2706 				 "%s: unable to read buffer from parent file.",
2707 				 function );
2708 
2709 				return( -1 );
2710 			}
2711 			read_size = (size_t) read_count;
2712 		}
2713 		else
2714 		{
2715 			/* Handle sparse cluster block
2716 			 */
2717 			if( memory_set(
2718 			     &( ( (uint8_t *) buffer )[ buffer_offset ] ),
2719 			     0,
2720 			     read_size ) == NULL )
2721 			{
2722 				libcerror_error_set(
2723 				 error,
2724 				 LIBCERROR_ERROR_DOMAIN_MEMORY,
2725 				 LIBCERROR_MEMORY_ERROR_SET_FAILED,
2726 				 "%s: unable to set sparse data in buffer.",
2727 				 function );
2728 
2729 				return( -1 );
2730 			}
2731 		}
2732 		internal_file->current_offset += read_size;
2733 		buffer_offset                 += read_size;
2734 
2735 #if defined( HAVE_DEBUG_OUTPUT )
2736 		if( libcnotify_verbose != 0 )
2737 		{
2738 			libcnotify_printf(
2739 			 "\n" );
2740 		}
2741 #endif
2742 		if( (size64_t) internal_file->current_offset >= internal_file->file_header->media_size )
2743 		{
2744 			break;
2745 		}
2746 	}
2747 	return( (ssize_t) buffer_offset );
2748 }
2749 
2750 /* Reads (media) data from the current offset into a buffer
2751  * Returns the number of bytes read or -1 on error
2752  */
libqcow_file_read_buffer(libqcow_file_t * file,void * buffer,size_t buffer_size,libcerror_error_t ** error)2753 ssize_t libqcow_file_read_buffer(
2754          libqcow_file_t *file,
2755          void *buffer,
2756          size_t buffer_size,
2757          libcerror_error_t **error )
2758 {
2759 	libqcow_internal_file_t *internal_file = NULL;
2760 	static char *function                  = "libqcow_file_read_buffer";
2761 	ssize_t read_count                     = 0;
2762 
2763 	if( file == NULL )
2764 	{
2765 		libcerror_error_set(
2766 		 error,
2767 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2768 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2769 		 "%s: invalid file.",
2770 		 function );
2771 
2772 		return( -1 );
2773 	}
2774 	internal_file = (libqcow_internal_file_t *) file;
2775 
2776 	if( internal_file->file_io_handle == NULL )
2777 	{
2778 		libcerror_error_set(
2779 		 error,
2780 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2781 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2782 		 "%s: invalid file - missing file IO handle.",
2783 		 function );
2784 
2785 		return( -1 );
2786 	}
2787 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
2788 	if( libcthreads_read_write_lock_grab_for_write(
2789 	     internal_file->read_write_lock,
2790 	     error ) != 1 )
2791 	{
2792 		libcerror_error_set(
2793 		 error,
2794 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2795 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2796 		 "%s: unable to grab read/write lock for writing.",
2797 		 function );
2798 
2799 		return( -1 );
2800 	}
2801 #endif
2802 	read_count = libqcow_internal_file_read_buffer_from_file_io_handle(
2803 		      internal_file,
2804 		      internal_file->file_io_handle,
2805 		      buffer,
2806 		      buffer_size,
2807 		      error );
2808 
2809 	if( read_count == -1 )
2810 	{
2811 		libcerror_error_set(
2812 		 error,
2813 		 LIBCERROR_ERROR_DOMAIN_IO,
2814 		 LIBCERROR_IO_ERROR_READ_FAILED,
2815 		 "%s: unable to read buffer.",
2816 		 function );
2817 
2818 		read_count = -1;
2819 	}
2820 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
2821 	if( libcthreads_read_write_lock_release_for_write(
2822 	     internal_file->read_write_lock,
2823 	     error ) != 1 )
2824 	{
2825 		libcerror_error_set(
2826 		 error,
2827 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2828 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2829 		 "%s: unable to release read/write lock for writing.",
2830 		 function );
2831 
2832 		return( -1 );
2833 	}
2834 #endif
2835 	return( read_count );
2836 }
2837 
2838 /* Reads (media) data at a specific offset
2839  * Returns the number of bytes read or -1 on error
2840  */
libqcow_file_read_buffer_at_offset(libqcow_file_t * file,void * buffer,size_t buffer_size,off64_t offset,libcerror_error_t ** error)2841 ssize_t libqcow_file_read_buffer_at_offset(
2842          libqcow_file_t *file,
2843          void *buffer,
2844          size_t buffer_size,
2845          off64_t offset,
2846          libcerror_error_t **error )
2847 {
2848 	libqcow_internal_file_t *internal_file = NULL;
2849 	static char *function                  = "libqcow_file_read_buffer_at_offset";
2850 	ssize_t read_count                     = 0;
2851 
2852 	if( file == NULL )
2853 	{
2854 		libcerror_error_set(
2855 		 error,
2856 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2857 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2858 		 "%s: invalid file.",
2859 		 function );
2860 
2861 		return( -1 );
2862 	}
2863 	internal_file = (libqcow_internal_file_t *) file;
2864 
2865 	if( internal_file->file_io_handle == NULL )
2866 	{
2867 		libcerror_error_set(
2868 		 error,
2869 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2870 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2871 		 "%s: invalid file - missing file IO handle.",
2872 		 function );
2873 
2874 		return( -1 );
2875 	}
2876 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
2877 	if( libcthreads_read_write_lock_grab_for_write(
2878 	     internal_file->read_write_lock,
2879 	     error ) != 1 )
2880 	{
2881 		libcerror_error_set(
2882 		 error,
2883 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2884 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2885 		 "%s: unable to grab read/write lock for writing.",
2886 		 function );
2887 
2888 		return( -1 );
2889 	}
2890 #endif
2891 	if( libqcow_internal_file_seek_offset(
2892 	     internal_file,
2893 	     offset,
2894 	     SEEK_SET,
2895 	     error ) == -1 )
2896 	{
2897 		libcerror_error_set(
2898 		 error,
2899 		 LIBCERROR_ERROR_DOMAIN_IO,
2900 		 LIBCERROR_IO_ERROR_SEEK_FAILED,
2901 		 "%s: unable to seek offset.",
2902 		 function );
2903 
2904 		read_count = -1;
2905 	}
2906 	else
2907 	{
2908 		read_count = libqcow_internal_file_read_buffer_from_file_io_handle(
2909 			      internal_file,
2910 			      internal_file->file_io_handle,
2911 			      buffer,
2912 			      buffer_size,
2913 			      error );
2914 
2915 		if( read_count == -1 )
2916 		{
2917 			libcerror_error_set(
2918 			 error,
2919 			 LIBCERROR_ERROR_DOMAIN_IO,
2920 			 LIBCERROR_IO_ERROR_READ_FAILED,
2921 			 "%s: unable to read buffer.",
2922 			 function );
2923 
2924 			read_count = -1;
2925 		}
2926 	}
2927 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
2928 	if( libcthreads_read_write_lock_release_for_write(
2929 	     internal_file->read_write_lock,
2930 	     error ) != 1 )
2931 	{
2932 		libcerror_error_set(
2933 		 error,
2934 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2935 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2936 		 "%s: unable to release read/write lock for writing.",
2937 		 function );
2938 
2939 		return( -1 );
2940 	}
2941 #endif
2942 	return( read_count );
2943 }
2944 
2945 /* Seeks a certain offset of the (media) data
2946  * This function is not multi-thread safe acquire write lock before call
2947  * Returns the offset if seek is successful or -1 on error
2948  */
libqcow_internal_file_seek_offset(libqcow_internal_file_t * internal_file,off64_t offset,int whence,libcerror_error_t ** error)2949 off64_t libqcow_internal_file_seek_offset(
2950          libqcow_internal_file_t *internal_file,
2951          off64_t offset,
2952          int whence,
2953          libcerror_error_t **error )
2954 {
2955 	static char *function = "libqcow_internal_file_seek_offset";
2956 
2957 	if( internal_file == NULL )
2958 	{
2959 		libcerror_error_set(
2960 		 error,
2961 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2962 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2963 		 "%s: invalid file.",
2964 		 function );
2965 
2966 		return( -1 );
2967 	}
2968 	if( internal_file->file_header == NULL )
2969 	{
2970 		libcerror_error_set(
2971 		 error,
2972 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2973 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2974 		 "%s: invalid file - missing file header.",
2975 		 function );
2976 
2977 		return( -1 );
2978 	}
2979 	if( internal_file->backing_filename != NULL )
2980 	{
2981 		if( internal_file->parent_file == NULL )
2982 		{
2983 			libcerror_error_set(
2984 			 error,
2985 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2986 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
2987 			 "%s: invalid file - missing parent file.",
2988 			 function );
2989 
2990 			return( -1 );
2991 		}
2992 	}
2993 	if( ( whence != SEEK_CUR )
2994 	 && ( whence != SEEK_END )
2995 	 && ( whence != SEEK_SET ) )
2996 	{
2997 		libcerror_error_set(
2998 		 error,
2999 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3000 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
3001 		 "%s: unsupported whence.",
3002 		 function );
3003 
3004 		return( -1 );
3005 	}
3006 	if( whence == SEEK_CUR )
3007 	{
3008 		offset += internal_file->current_offset;
3009 	}
3010 	else if( whence == SEEK_END )
3011 	{
3012 		offset += (off64_t) internal_file->file_header->media_size;
3013 	}
3014 	if( offset < 0 )
3015 	{
3016 		libcerror_error_set(
3017 		 error,
3018 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3019 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
3020 		 "%s: invalid offset value out of bounds.",
3021 		 function );
3022 
3023 		return( -1 );
3024 	}
3025 	internal_file->current_offset = offset;
3026 
3027 	return( offset );
3028 }
3029 
3030 /* Seeks a certain offset of the (media) data
3031  * Returns the offset if seek is successful or -1 on error
3032  */
libqcow_file_seek_offset(libqcow_file_t * file,off64_t offset,int whence,libcerror_error_t ** error)3033 off64_t libqcow_file_seek_offset(
3034          libqcow_file_t *file,
3035          off64_t offset,
3036          int whence,
3037          libcerror_error_t **error )
3038 {
3039 	libqcow_internal_file_t *internal_file = NULL;
3040 	static char *function                  = "libqcow_file_seek_offset";
3041 
3042 	if( file == NULL )
3043 	{
3044 		libcerror_error_set(
3045 		 error,
3046 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3047 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3048 		 "%s: invalid file.",
3049 		 function );
3050 
3051 		return( -1 );
3052 	}
3053 	internal_file = (libqcow_internal_file_t *) file;
3054 
3055 	if( internal_file->file_io_handle == NULL )
3056 	{
3057 		libcerror_error_set(
3058 		 error,
3059 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3060 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3061 		 "%s: invalid file - missing file IO handle.",
3062 		 function );
3063 
3064 		return( -1 );
3065 	}
3066 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3067 	if( libcthreads_read_write_lock_grab_for_write(
3068 	     internal_file->read_write_lock,
3069 	     error ) != 1 )
3070 	{
3071 		libcerror_error_set(
3072 		 error,
3073 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3074 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3075 		 "%s: unable to grab read/write lock for writing.",
3076 		 function );
3077 
3078 		return( -1 );
3079 	}
3080 #endif
3081 	offset = libqcow_internal_file_seek_offset(
3082 	          internal_file,
3083 	          offset,
3084 	          whence,
3085 	          error );
3086 
3087 	if( offset == -1 )
3088 	{
3089 		libcerror_error_set(
3090 		 error,
3091 		 LIBCERROR_ERROR_DOMAIN_IO,
3092 		 LIBCERROR_IO_ERROR_SEEK_FAILED,
3093 		 "%s: unable to seek offset.",
3094 		 function );
3095 
3096 		offset = -1;
3097 	}
3098 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3099 	if( libcthreads_read_write_lock_release_for_write(
3100 	     internal_file->read_write_lock,
3101 	     error ) != 1 )
3102 	{
3103 		libcerror_error_set(
3104 		 error,
3105 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3106 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3107 		 "%s: unable to release read/write lock for writing.",
3108 		 function );
3109 
3110 		return( -1 );
3111 	}
3112 #endif
3113 	return( offset );
3114 }
3115 
3116 /* Retrieves the current offset of the (media) data
3117  * Returns 1 if successful or -1 on error
3118  */
libqcow_file_get_offset(libqcow_file_t * file,off64_t * offset,libcerror_error_t ** error)3119 int libqcow_file_get_offset(
3120      libqcow_file_t *file,
3121      off64_t *offset,
3122      libcerror_error_t **error )
3123 {
3124 	libqcow_internal_file_t *internal_file = NULL;
3125 	static char *function                  = "libqcow_file_get_offset";
3126 
3127 	if( file == NULL )
3128 	{
3129 		libcerror_error_set(
3130 		 error,
3131 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3132 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3133 		 "%s: invalid file.",
3134 		 function );
3135 
3136 		return( -1 );
3137 	}
3138 	internal_file = (libqcow_internal_file_t *) file;
3139 
3140 	if( internal_file->file_io_handle == NULL )
3141 	{
3142 		libcerror_error_set(
3143 		 error,
3144 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3145 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3146 		 "%s: invalid file - missing file IO handle.",
3147 		 function );
3148 
3149 		return( -1 );
3150 	}
3151 	if( offset == NULL )
3152 	{
3153 		libcerror_error_set(
3154 		 error,
3155 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3156 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3157 		 "%s: invalid offset.",
3158 		 function );
3159 
3160 		return( -1 );
3161 	}
3162 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3163 	if( libcthreads_read_write_lock_grab_for_read(
3164 	     internal_file->read_write_lock,
3165 	     error ) != 1 )
3166 	{
3167 		libcerror_error_set(
3168 		 error,
3169 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3170 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3171 		 "%s: unable to grab read/write lock for reading.",
3172 		 function );
3173 
3174 		return( -1 );
3175 	}
3176 #endif
3177 	*offset = internal_file->current_offset;
3178 
3179 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3180 	if( libcthreads_read_write_lock_release_for_read(
3181 	     internal_file->read_write_lock,
3182 	     error ) != 1 )
3183 	{
3184 		libcerror_error_set(
3185 		 error,
3186 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3187 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3188 		 "%s: unable to release read/write lock for reading.",
3189 		 function );
3190 
3191 		return( -1 );
3192 	}
3193 #endif
3194 	return( 1 );
3195 }
3196 
3197 /* Sets the parent (backing) file of a differential image
3198  * Returns 1 if successful or -1 on error
3199  */
libqcow_file_set_parent_file(libqcow_file_t * file,libqcow_file_t * parent_file,libcerror_error_t ** error)3200 int libqcow_file_set_parent_file(
3201      libqcow_file_t *file,
3202      libqcow_file_t *parent_file,
3203      libcerror_error_t **error )
3204 {
3205 	libqcow_internal_file_t *internal_file = NULL;
3206 	static char *function                  = "libqcow_file_set_parent_file";
3207 
3208 	if( file == NULL )
3209 	{
3210 		libcerror_error_set(
3211 		 error,
3212 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3213 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3214 		 "%s: invalid file.",
3215 		 function );
3216 
3217 		return( -1 );
3218 	}
3219 	internal_file = (libqcow_internal_file_t *) file;
3220 
3221 	if( internal_file->backing_filename == NULL )
3222 	{
3223 		libcerror_error_set(
3224 		 error,
3225 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3226 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3227 		 "%s: invalid file - missing backing filename.",
3228 		 function );
3229 
3230 		return( -1 );
3231 	}
3232 	if( internal_file->parent_file != NULL )
3233 	{
3234 		libcerror_error_set(
3235 		 error,
3236 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3237 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3238 		 "%s: invalid file - parent file already set.",
3239 		 function );
3240 
3241 		return( -1 );
3242 	}
3243 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3244 	if( libcthreads_read_write_lock_grab_for_write(
3245 	     internal_file->read_write_lock,
3246 	     error ) != 1 )
3247 	{
3248 		libcerror_error_set(
3249 		 error,
3250 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3251 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3252 		 "%s: unable to grab read/write lock for writing.",
3253 		 function );
3254 
3255 		return( -1 );
3256 	}
3257 #endif
3258 	internal_file->parent_file = parent_file;
3259 
3260 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3261 	if( libcthreads_read_write_lock_release_for_write(
3262 	     internal_file->read_write_lock,
3263 	     error ) != 1 )
3264 	{
3265 		libcerror_error_set(
3266 		 error,
3267 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3268 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3269 		 "%s: unable to release read/write lock for writing.",
3270 		 function );
3271 
3272 		return( -1 );
3273 	}
3274 #endif
3275 	return( 1 );
3276 }
3277 
3278 /* Set the keys
3279  * This function needs to be used before one of the open functions
3280  * Returns 1 if successful or -1 on error
3281  */
libqcow_file_set_keys(libqcow_file_t * file,const uint8_t * key,size_t key_size,libcerror_error_t ** error)3282 int libqcow_file_set_keys(
3283      libqcow_file_t *file,
3284      const uint8_t *key,
3285      size_t key_size,
3286      libcerror_error_t **error )
3287 {
3288 	libqcow_internal_file_t *internal_file = NULL;
3289 	static char *function                  = "libqcow_file_set_keys";
3290 
3291 	if( file == NULL )
3292 	{
3293 		libcerror_error_set(
3294 		 error,
3295 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3296 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3297 		 "%s: invalid file.",
3298 		 function );
3299 
3300 		return( -1 );
3301 	}
3302 	internal_file = (libqcow_internal_file_t *) file;
3303 
3304 	if( internal_file->file_io_handle != NULL )
3305 	{
3306 		libcerror_error_set(
3307 		 error,
3308 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3309 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3310 		 "%s: invalid file - file IO handle already set.",
3311 		 function );
3312 
3313 		return( -1 );
3314 	}
3315 	if( key == NULL )
3316 	{
3317 		libcerror_error_set(
3318 		 error,
3319 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3320 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3321 		 "%s: invalid key.",
3322 		 function );
3323 
3324 		return( -1 );
3325 	}
3326 	if( key_size != 16 )
3327 	{
3328 		libcerror_error_set(
3329 		 error,
3330 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3331 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
3332 		 "%s: unsupported key size.",
3333 		 function );
3334 
3335 		return( -1 );
3336 	}
3337 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3338 	if( libcthreads_read_write_lock_grab_for_write(
3339 	     internal_file->read_write_lock,
3340 	     error ) != 1 )
3341 	{
3342 		libcerror_error_set(
3343 		 error,
3344 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3345 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3346 		 "%s: unable to grab read/write lock for writing.",
3347 		 function );
3348 
3349 		return( -1 );
3350 	}
3351 #endif
3352 	if( memory_copy(
3353 	     internal_file->key_data,
3354 	     key,
3355 	     key_size ) == NULL )
3356 	{
3357 		libcerror_error_set(
3358 		 error,
3359 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3360 		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
3361 		 "%s: unable to copy key.",
3362 		 function );
3363 
3364 		goto on_error;
3365 	}
3366 	internal_file->key_data_is_set = 1;
3367 
3368 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3369 	if( libcthreads_read_write_lock_release_for_write(
3370 	     internal_file->read_write_lock,
3371 	     error ) != 1 )
3372 	{
3373 		libcerror_error_set(
3374 		 error,
3375 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3376 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3377 		 "%s: unable to release read/write lock for writing.",
3378 		 function );
3379 
3380 		return( -1 );
3381 	}
3382 #endif
3383 	return( 1 );
3384 
3385 on_error:
3386 	memory_set(
3387 	 internal_file->key_data,
3388 	 0,
3389 	 16 );
3390 
3391 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3392 	libcthreads_read_write_lock_release_for_write(
3393 	 internal_file->read_write_lock,
3394 	 NULL );
3395 #endif
3396 	return( -1 );
3397 }
3398 
3399 /* Sets an UTF-8 formatted password
3400  * This function needs to be used before one of the open functions
3401  * Returns 1 if successful, 0 if password is invalid or -1 on error
3402  */
libqcow_file_set_utf8_password(libqcow_file_t * file,const uint8_t * utf8_string,size_t utf8_string_length,libcerror_error_t ** error)3403 int libqcow_file_set_utf8_password(
3404      libqcow_file_t *file,
3405      const uint8_t *utf8_string,
3406      size_t utf8_string_length,
3407      libcerror_error_t **error )
3408 {
3409 	libqcow_internal_file_t *internal_file = NULL;
3410 	static char *function                  = "libqcow_file_set_utf8_password";
3411 
3412 	if( file == NULL )
3413 	{
3414 		libcerror_error_set(
3415 		 error,
3416 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3417 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3418 		 "%s: invalid file.",
3419 		 function );
3420 
3421 		return( -1 );
3422 	}
3423 	internal_file = (libqcow_internal_file_t *) file;
3424 
3425 	if( internal_file->file_io_handle != NULL )
3426 	{
3427 		libcerror_error_set(
3428 		 error,
3429 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3430 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3431 		 "%s: invalid file - file IO handle already set.",
3432 		 function );
3433 
3434 		return( -1 );
3435 	}
3436 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3437 	if( libcthreads_read_write_lock_grab_for_write(
3438 	     internal_file->read_write_lock,
3439 	     error ) != 1 )
3440 	{
3441 		libcerror_error_set(
3442 		 error,
3443 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3444 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3445 		 "%s: unable to grab read/write lock for writing.",
3446 		 function );
3447 
3448 		return( -1 );
3449 	}
3450 #endif
3451 	if( memory_set(
3452 	     internal_file->key_data,
3453 	     0,
3454 	     16 ) == NULL )
3455 	{
3456 		libcerror_error_set(
3457 		 error,
3458 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3459 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
3460 		 "%s: unable to clear key data.",
3461 		 function );
3462 
3463 		goto on_error;
3464 	}
3465 	if( libuna_byte_stream_copy_from_utf8(
3466 	     internal_file->key_data,
3467 	     16,
3468 	     LIBQCOW_CODEPAGE_US_ASCII,
3469 	     utf8_string,
3470 	     utf8_string_length,
3471 	     error ) != 1 )
3472 	{
3473 		libcerror_error_set(
3474 		 error,
3475 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3476 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3477 		 "%s: unable to copy password.",
3478 		 function );
3479 
3480 		goto on_error;
3481 	}
3482 	internal_file->key_data_is_set = 1;
3483 
3484 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3485 	if( libcthreads_read_write_lock_release_for_write(
3486 	     internal_file->read_write_lock,
3487 	     error ) != 1 )
3488 	{
3489 		libcerror_error_set(
3490 		 error,
3491 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3492 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3493 		 "%s: unable to release read/write lock for writing.",
3494 		 function );
3495 
3496 		return( -1 );
3497 	}
3498 #endif
3499 	return( 1 );
3500 
3501 on_error:
3502 	memory_set(
3503 	 internal_file->key_data,
3504 	 0,
3505 	 16 );
3506 
3507 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3508 	libcthreads_read_write_lock_release_for_write(
3509 	 internal_file->read_write_lock,
3510 	 NULL );
3511 #endif
3512 	return( -1 );
3513 }
3514 
3515 /* Sets an UTF-16 formatted password
3516  * This function needs to be used before one of the open functions
3517  * Returns 1 if successful, 0 if password is invalid or -1 on error
3518  */
libqcow_file_set_utf16_password(libqcow_file_t * file,const uint16_t * utf16_string,size_t utf16_string_length,libcerror_error_t ** error)3519 int libqcow_file_set_utf16_password(
3520      libqcow_file_t *file,
3521      const uint16_t *utf16_string,
3522      size_t utf16_string_length,
3523      libcerror_error_t **error )
3524 {
3525 	libqcow_internal_file_t *internal_file = NULL;
3526 	static char *function                  = "libqcow_file_set_utf16_password";
3527 
3528 	if( file == NULL )
3529 	{
3530 		libcerror_error_set(
3531 		 error,
3532 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3533 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3534 		 "%s: invalid file.",
3535 		 function );
3536 
3537 		return( -1 );
3538 	}
3539 	internal_file = (libqcow_internal_file_t *) file;
3540 
3541 	if( internal_file->file_io_handle != NULL )
3542 	{
3543 		libcerror_error_set(
3544 		 error,
3545 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3546 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
3547 		 "%s: invalid file - file IO handle already set.",
3548 		 function );
3549 
3550 		return( -1 );
3551 	}
3552 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3553 	if( libcthreads_read_write_lock_grab_for_write(
3554 	     internal_file->read_write_lock,
3555 	     error ) != 1 )
3556 	{
3557 		libcerror_error_set(
3558 		 error,
3559 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3560 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3561 		 "%s: unable to grab read/write lock for writing.",
3562 		 function );
3563 
3564 		return( -1 );
3565 	}
3566 #endif
3567 	if( memory_set(
3568 	     internal_file->key_data,
3569 	     0,
3570 	     16 ) == NULL )
3571 	{
3572 		libcerror_error_set(
3573 		 error,
3574 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
3575 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
3576 		 "%s: unable to clear key data.",
3577 		 function );
3578 
3579 		goto on_error;
3580 	}
3581 	if( libuna_byte_stream_copy_from_utf16(
3582 	     internal_file->key_data,
3583 	     16,
3584 	     LIBQCOW_CODEPAGE_US_ASCII,
3585 	     utf16_string,
3586 	     utf16_string_length,
3587 	     error ) != 1 )
3588 	{
3589 		libcerror_error_set(
3590 		 error,
3591 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3592 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3593 		 "%s: unable to copy password.",
3594 		 function );
3595 
3596 		goto on_error;
3597 	}
3598 	internal_file->key_data_is_set = 1;
3599 
3600 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3601 	if( libcthreads_read_write_lock_release_for_write(
3602 	     internal_file->read_write_lock,
3603 	     error ) != 1 )
3604 	{
3605 		libcerror_error_set(
3606 		 error,
3607 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3608 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3609 		 "%s: unable to release read/write lock for writing.",
3610 		 function );
3611 
3612 		return( -1 );
3613 	}
3614 #endif
3615 	return( 1 );
3616 
3617 on_error:
3618 	memory_set(
3619 	 internal_file->key_data,
3620 	 0,
3621 	 16 );
3622 
3623 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3624 	libcthreads_read_write_lock_release_for_write(
3625 	 internal_file->read_write_lock,
3626 	 NULL );
3627 #endif
3628 	return( -1 );
3629 }
3630 
3631 /* Retrieves the media size
3632  * Returns 1 if successful or -1 on error
3633  */
libqcow_file_get_media_size(libqcow_file_t * file,size64_t * media_size,libcerror_error_t ** error)3634 int libqcow_file_get_media_size(
3635      libqcow_file_t *file,
3636      size64_t *media_size,
3637      libcerror_error_t **error )
3638 {
3639 	libqcow_internal_file_t *internal_file = NULL;
3640 	static char *function                  = "libqcow_file_get_media_size";
3641 
3642 	if( file == NULL )
3643 	{
3644 		libcerror_error_set(
3645 		 error,
3646 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3647 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3648 		 "%s: invalid file.",
3649 		 function );
3650 
3651 		return( -1 );
3652 	}
3653 	internal_file = (libqcow_internal_file_t *) file;
3654 
3655 	if( internal_file->file_header == NULL )
3656 	{
3657 		libcerror_error_set(
3658 		 error,
3659 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3660 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3661 		 "%s: invalid file - missing file header.",
3662 		 function );
3663 
3664 		return( -1 );
3665 	}
3666 	if( media_size == NULL )
3667 	{
3668 		libcerror_error_set(
3669 		 error,
3670 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3671 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3672 		 "%s: invalid media size.",
3673 		 function );
3674 
3675 		return( -1 );
3676 	}
3677 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3678 	if( libcthreads_read_write_lock_grab_for_read(
3679 	     internal_file->read_write_lock,
3680 	     error ) != 1 )
3681 	{
3682 		libcerror_error_set(
3683 		 error,
3684 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3685 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3686 		 "%s: unable to grab read/write lock for reading.",
3687 		 function );
3688 
3689 		return( -1 );
3690 	}
3691 #endif
3692 	*media_size = internal_file->file_header->media_size;
3693 
3694 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3695 	if( libcthreads_read_write_lock_release_for_read(
3696 	     internal_file->read_write_lock,
3697 	     error ) != 1 )
3698 	{
3699 		libcerror_error_set(
3700 		 error,
3701 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3702 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3703 		 "%s: unable to release read/write lock for reading.",
3704 		 function );
3705 
3706 		return( -1 );
3707 	}
3708 #endif
3709 	return( 1 );
3710 }
3711 
3712 /* Retrieves the format version
3713  * Returns 1 if successful or -1 on error
3714  */
libqcow_file_get_format_version(libqcow_file_t * file,uint32_t * format_version,libcerror_error_t ** error)3715 int libqcow_file_get_format_version(
3716      libqcow_file_t *file,
3717      uint32_t *format_version,
3718      libcerror_error_t **error )
3719 {
3720 	libqcow_internal_file_t *internal_file = NULL;
3721 	static char *function                  = "libqcow_file_get_format_version";
3722 
3723 	if( file == NULL )
3724 	{
3725 		libcerror_error_set(
3726 		 error,
3727 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3728 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3729 		 "%s: invalid file.",
3730 		 function );
3731 
3732 		return( -1 );
3733 	}
3734 	internal_file = (libqcow_internal_file_t *) file;
3735 
3736 	if( internal_file->file_header == NULL )
3737 	{
3738 		libcerror_error_set(
3739 		 error,
3740 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3741 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3742 		 "%s: invalid file - missing file header.",
3743 		 function );
3744 
3745 		return( -1 );
3746 	}
3747 	if( format_version == NULL )
3748 	{
3749 		libcerror_error_set(
3750 		 error,
3751 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3752 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3753 		 "%s: invalid format version.",
3754 		 function );
3755 
3756 		return( -1 );
3757 	}
3758 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3759 	if( libcthreads_read_write_lock_grab_for_read(
3760 	     internal_file->read_write_lock,
3761 	     error ) != 1 )
3762 	{
3763 		libcerror_error_set(
3764 		 error,
3765 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3766 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3767 		 "%s: unable to grab read/write lock for reading.",
3768 		 function );
3769 
3770 		return( -1 );
3771 	}
3772 #endif
3773 	*format_version = internal_file->file_header->format_version;
3774 
3775 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3776 	if( libcthreads_read_write_lock_release_for_read(
3777 	     internal_file->read_write_lock,
3778 	     error ) != 1 )
3779 	{
3780 		libcerror_error_set(
3781 		 error,
3782 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3783 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3784 		 "%s: unable to release read/write lock for reading.",
3785 		 function );
3786 
3787 		return( -1 );
3788 	}
3789 #endif
3790 	return( 1 );
3791 }
3792 
3793 /* Retrieves the encryption method
3794  * Returns 1 if successful or -1 on error
3795  */
libqcow_file_get_encryption_method(libqcow_file_t * file,uint32_t * encryption_method,libcerror_error_t ** error)3796 int libqcow_file_get_encryption_method(
3797      libqcow_file_t *file,
3798      uint32_t *encryption_method,
3799      libcerror_error_t **error )
3800 {
3801 	libqcow_internal_file_t *internal_file = NULL;
3802 	static char *function                  = "libqcow_file_get_encryption_method";
3803 
3804 	if( file == NULL )
3805 	{
3806 		libcerror_error_set(
3807 		 error,
3808 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3809 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3810 		 "%s: invalid file.",
3811 		 function );
3812 
3813 		return( -1 );
3814 	}
3815 	internal_file = (libqcow_internal_file_t *) file;
3816 
3817 	if( internal_file->file_io_handle == NULL )
3818 	{
3819 		libcerror_error_set(
3820 		 error,
3821 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3822 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3823 		 "%s: invalid file - missing file IO handle.",
3824 		 function );
3825 
3826 		return( -1 );
3827 	}
3828 	if( encryption_method == NULL )
3829 	{
3830 		libcerror_error_set(
3831 		 error,
3832 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3833 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3834 		 "%s: invalid encryption method.",
3835 		 function );
3836 
3837 		return( -1 );
3838 	}
3839 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3840 	if( libcthreads_read_write_lock_grab_for_read(
3841 	     internal_file->read_write_lock,
3842 	     error ) != 1 )
3843 	{
3844 		libcerror_error_set(
3845 		 error,
3846 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3847 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3848 		 "%s: unable to grab read/write lock for reading.",
3849 		 function );
3850 
3851 		return( -1 );
3852 	}
3853 #endif
3854 	*encryption_method = internal_file->encryption_method;
3855 
3856 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3857 	if( libcthreads_read_write_lock_release_for_read(
3858 	     internal_file->read_write_lock,
3859 	     error ) != 1 )
3860 	{
3861 		libcerror_error_set(
3862 		 error,
3863 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3864 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3865 		 "%s: unable to release read/write lock for reading.",
3866 		 function );
3867 
3868 		return( -1 );
3869 	}
3870 #endif
3871 	return( 1 );
3872 }
3873 
3874 /* Retrieves the size of the UTF-8 encoded backing filename
3875  * The returned size includes the end of string character
3876  * Returns 1 if successful, 0 if not available or -1 on error
3877  */
libqcow_file_get_utf8_backing_filename_size(libqcow_file_t * file,size_t * utf8_string_size,libcerror_error_t ** error)3878 int libqcow_file_get_utf8_backing_filename_size(
3879      libqcow_file_t *file,
3880      size_t *utf8_string_size,
3881      libcerror_error_t **error )
3882 {
3883 	libqcow_internal_file_t *internal_file = NULL;
3884 	static char *function                  = "libqcow_file_get_utf8_backing_filename_size";
3885 	int result                             = 0;
3886 
3887 	if( file == NULL )
3888 	{
3889 		libcerror_error_set(
3890 		 error,
3891 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3892 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3893 		 "%s: invalid file.",
3894 		 function );
3895 
3896 		return( -1 );
3897 	}
3898 	internal_file = (libqcow_internal_file_t *) file;
3899 
3900 	if( internal_file->file_io_handle == NULL )
3901 	{
3902 		libcerror_error_set(
3903 		 error,
3904 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3905 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3906 		 "%s: invalid file - missing file IO handle.",
3907 		 function );
3908 
3909 		return( -1 );
3910 	}
3911 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3912 	if( libcthreads_read_write_lock_grab_for_read(
3913 	     internal_file->read_write_lock,
3914 	     error ) != 1 )
3915 	{
3916 		libcerror_error_set(
3917 		 error,
3918 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3919 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3920 		 "%s: unable to grab read/write lock for reading.",
3921 		 function );
3922 
3923 		return( -1 );
3924 	}
3925 #endif
3926 	if( internal_file->backing_filename != NULL )
3927 	{
3928 		result = libuna_utf8_string_size_from_utf8_stream(
3929 		          internal_file->backing_filename,
3930 		          internal_file->backing_filename_size,
3931 		          utf8_string_size,
3932 		          error );
3933 
3934 		if( result != 1 )
3935 		{
3936 			libcerror_error_set(
3937 			 error,
3938 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3939 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
3940 			 "%s: unable to retrieve UTF-8 string size of backing filename.",
3941 			 function );
3942 
3943 			result = -1;
3944 		}
3945 	}
3946 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
3947 	if( libcthreads_read_write_lock_release_for_read(
3948 	     internal_file->read_write_lock,
3949 	     error ) != 1 )
3950 	{
3951 		libcerror_error_set(
3952 		 error,
3953 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3954 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
3955 		 "%s: unable to release read/write lock for reading.",
3956 		 function );
3957 
3958 		return( -1 );
3959 	}
3960 #endif
3961 	return( result );
3962 }
3963 
3964 /* Retrieves the UTF-8 encoded backing filename
3965  * The size should include the end of string character
3966  * Returns 1 if successful, 0 if not available or -1 on error
3967  */
libqcow_file_get_utf8_backing_filename(libqcow_file_t * file,uint8_t * utf8_string,size_t utf8_string_size,libcerror_error_t ** error)3968 int libqcow_file_get_utf8_backing_filename(
3969      libqcow_file_t *file,
3970      uint8_t *utf8_string,
3971      size_t utf8_string_size,
3972      libcerror_error_t **error )
3973 {
3974 	libqcow_internal_file_t *internal_file = NULL;
3975 	static char *function                  = "libqcow_file_get_utf8_backing_filename";
3976 	int result                             = 0;
3977 
3978 	if( file == NULL )
3979 	{
3980 		libcerror_error_set(
3981 		 error,
3982 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
3983 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
3984 		 "%s: invalid file.",
3985 		 function );
3986 
3987 		return( -1 );
3988 	}
3989 	internal_file = (libqcow_internal_file_t *) file;
3990 
3991 	if( internal_file->file_io_handle == NULL )
3992 	{
3993 		libcerror_error_set(
3994 		 error,
3995 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
3996 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
3997 		 "%s: invalid file - missing file IO handle.",
3998 		 function );
3999 
4000 		return( -1 );
4001 	}
4002 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4003 	if( libcthreads_read_write_lock_grab_for_read(
4004 	     internal_file->read_write_lock,
4005 	     error ) != 1 )
4006 	{
4007 		libcerror_error_set(
4008 		 error,
4009 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4010 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4011 		 "%s: unable to grab read/write lock for reading.",
4012 		 function );
4013 
4014 		return( -1 );
4015 	}
4016 #endif
4017 	if( internal_file->backing_filename != NULL )
4018 	{
4019 		result = libuna_utf8_string_copy_from_utf8_stream(
4020 		          utf8_string,
4021 		          utf8_string_size,
4022 		          internal_file->backing_filename,
4023 		          internal_file->backing_filename_size,
4024 		          error );
4025 
4026 		if( result != 1 )
4027 		{
4028 			libcerror_error_set(
4029 			 error,
4030 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4031 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4032 			 "%s: unable to retrieve UTF-8 string of backing filename.",
4033 			 function );
4034 
4035 			result = -1;
4036 		}
4037 	}
4038 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4039 	if( libcthreads_read_write_lock_release_for_read(
4040 	     internal_file->read_write_lock,
4041 	     error ) != 1 )
4042 	{
4043 		libcerror_error_set(
4044 		 error,
4045 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4046 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4047 		 "%s: unable to release read/write lock for reading.",
4048 		 function );
4049 
4050 		return( -1 );
4051 	}
4052 #endif
4053 	return( result );
4054 }
4055 
4056 /* Retrieves the size of the UTF-16 encoded backing filename
4057  * The returned size includes the end of string character
4058  * Returns 1 if successful, 0 if not available or -1 on error
4059  */
libqcow_file_get_utf16_backing_filename_size(libqcow_file_t * file,size_t * utf16_string_size,libcerror_error_t ** error)4060 int libqcow_file_get_utf16_backing_filename_size(
4061      libqcow_file_t *file,
4062      size_t *utf16_string_size,
4063      libcerror_error_t **error )
4064 {
4065 	libqcow_internal_file_t *internal_file = NULL;
4066 	static char *function                  = "libqcow_file_get_utf16_backing_filename_size";
4067 	int result                             = 0;
4068 
4069 	if( file == NULL )
4070 	{
4071 		libcerror_error_set(
4072 		 error,
4073 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4074 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4075 		 "%s: invalid file.",
4076 		 function );
4077 
4078 		return( -1 );
4079 	}
4080 	internal_file = (libqcow_internal_file_t *) file;
4081 
4082 	if( internal_file->file_io_handle == NULL )
4083 	{
4084 		libcerror_error_set(
4085 		 error,
4086 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4087 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4088 		 "%s: invalid file - missing file IO handle.",
4089 		 function );
4090 
4091 		return( -1 );
4092 	}
4093 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4094 	if( libcthreads_read_write_lock_grab_for_read(
4095 	     internal_file->read_write_lock,
4096 	     error ) != 1 )
4097 	{
4098 		libcerror_error_set(
4099 		 error,
4100 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4101 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4102 		 "%s: unable to grab read/write lock for reading.",
4103 		 function );
4104 
4105 		return( -1 );
4106 	}
4107 #endif
4108 	if( internal_file->backing_filename != NULL )
4109 	{
4110 		result = libuna_utf16_string_size_from_utf8_stream(
4111 		          internal_file->backing_filename,
4112 		          internal_file->backing_filename_size,
4113 		          utf16_string_size,
4114 		          error );
4115 
4116 		if( result != 1 )
4117 		{
4118 			libcerror_error_set(
4119 			 error,
4120 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4121 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4122 			 "%s: unable to retrieve UTF-16 string size of backing filename.",
4123 			 function );
4124 
4125 			result = -1;
4126 		}
4127 	}
4128 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4129 	if( libcthreads_read_write_lock_release_for_read(
4130 	     internal_file->read_write_lock,
4131 	     error ) != 1 )
4132 	{
4133 		libcerror_error_set(
4134 		 error,
4135 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4136 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4137 		 "%s: unable to release read/write lock for reading.",
4138 		 function );
4139 
4140 		return( -1 );
4141 	}
4142 #endif
4143 	return( result );
4144 }
4145 
4146 /* Retrieves the UTF-16 encoded backing filename
4147  * The size should include the end of string character
4148  * Returns 1 if successful, 0 if not available or -1 on error
4149  */
libqcow_file_get_utf16_backing_filename(libqcow_file_t * file,uint16_t * utf16_string,size_t utf16_string_size,libcerror_error_t ** error)4150 int libqcow_file_get_utf16_backing_filename(
4151      libqcow_file_t *file,
4152      uint16_t *utf16_string,
4153      size_t utf16_string_size,
4154      libcerror_error_t **error )
4155 {
4156 	libqcow_internal_file_t *internal_file = NULL;
4157 	static char *function                  = "libqcow_file_get_utf16_backing_filename";
4158 	int result                             = 0;
4159 
4160 	if( file == NULL )
4161 	{
4162 		libcerror_error_set(
4163 		 error,
4164 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4165 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4166 		 "%s: invalid file.",
4167 		 function );
4168 
4169 		return( -1 );
4170 	}
4171 	internal_file = (libqcow_internal_file_t *) file;
4172 
4173 	if( internal_file->file_io_handle == NULL )
4174 	{
4175 		libcerror_error_set(
4176 		 error,
4177 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4178 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4179 		 "%s: invalid file - missing file IO handle.",
4180 		 function );
4181 
4182 		return( -1 );
4183 	}
4184 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4185 	if( libcthreads_read_write_lock_grab_for_read(
4186 	     internal_file->read_write_lock,
4187 	     error ) != 1 )
4188 	{
4189 		libcerror_error_set(
4190 		 error,
4191 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4192 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4193 		 "%s: unable to grab read/write lock for reading.",
4194 		 function );
4195 
4196 		return( -1 );
4197 	}
4198 #endif
4199 	if( internal_file->backing_filename != NULL )
4200 	{
4201 		result = libuna_utf16_string_copy_from_utf8_stream(
4202 		          utf16_string,
4203 		          utf16_string_size,
4204 		          internal_file->backing_filename,
4205 		          internal_file->backing_filename_size,
4206 		          error );
4207 
4208 		if( result != 1 )
4209 		{
4210 			libcerror_error_set(
4211 			 error,
4212 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4213 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
4214 			 "%s: unable to retrieve UTF-16 string of backing filename.",
4215 			 function );
4216 
4217 			result = -1;
4218 		}
4219 	}
4220 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4221 	if( libcthreads_read_write_lock_release_for_read(
4222 	     internal_file->read_write_lock,
4223 	     error ) != 1 )
4224 	{
4225 		libcerror_error_set(
4226 		 error,
4227 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4228 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4229 		 "%s: unable to release read/write lock for reading.",
4230 		 function );
4231 
4232 		return( -1 );
4233 	}
4234 #endif
4235 	return( result );
4236 }
4237 
4238 /* Retrieves the number of snapshots
4239  * Returns 1 if successful or -1 on error
4240  */
libqcow_file_get_number_of_snapshots(libqcow_file_t * file,int * number_of_snapshots,libcerror_error_t ** error)4241 int libqcow_file_get_number_of_snapshots(
4242      libqcow_file_t *file,
4243      int *number_of_snapshots,
4244      libcerror_error_t **error )
4245 {
4246 	libqcow_internal_file_t *internal_file = NULL;
4247 	static char *function                  = "libqcow_file_get_number_of_snapshots";
4248 
4249 	if( file == NULL )
4250 	{
4251 		libcerror_error_set(
4252 		 error,
4253 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4254 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4255 		 "%s: invalid file.",
4256 		 function );
4257 
4258 		return( -1 );
4259 	}
4260 	internal_file = (libqcow_internal_file_t *) file;
4261 
4262 	if( internal_file->file_header == NULL )
4263 	{
4264 		libcerror_error_set(
4265 		 error,
4266 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4267 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
4268 		 "%s: invalid file - missing file header.",
4269 		 function );
4270 
4271 		return( -1 );
4272 	}
4273 	if( number_of_snapshots == NULL )
4274 	{
4275 		libcerror_error_set(
4276 		 error,
4277 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
4278 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
4279 		 "%s: invalid number of snapshots.",
4280 		 function );
4281 
4282 		return( -1 );
4283 	}
4284 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4285 	if( libcthreads_read_write_lock_grab_for_read(
4286 	     internal_file->read_write_lock,
4287 	     error ) != 1 )
4288 	{
4289 		libcerror_error_set(
4290 		 error,
4291 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4292 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4293 		 "%s: unable to grab read/write lock for reading.",
4294 		 function );
4295 
4296 		return( -1 );
4297 	}
4298 #endif
4299 	/* TODO retrieve number of snapshots from array */
4300 	*number_of_snapshots = (int) internal_file->file_header->number_of_snapshots;
4301 
4302 #if defined( HAVE_LIBQCOW_MULTI_THREAD_SUPPORT )
4303 	if( libcthreads_read_write_lock_release_for_read(
4304 	     internal_file->read_write_lock,
4305 	     error ) != 1 )
4306 	{
4307 		libcerror_error_set(
4308 		 error,
4309 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
4310 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
4311 		 "%s: unable to release read/write lock for reading.",
4312 		 function );
4313 
4314 		return( -1 );
4315 	}
4316 #endif
4317 	return( 1 );
4318 }
4319 
4320