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