1 /*
2 * Mounts a QEMU Copy-On-Write (QCOW) image file
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 <file_stream.h>
24 #include <memory.h>
25 #include <system_string.h>
26 #include <types.h>
27
28 #include <stdio.h>
29
30 #if defined( HAVE_IO_H ) || defined( WINAPI )
31 #include <io.h>
32 #endif
33
34 #if defined( HAVE_STDLIB_H ) || defined( WINAPI )
35 #include <stdlib.h>
36 #endif
37
38 #if defined( HAVE_UNISTD_H )
39 #include <unistd.h>
40 #endif
41
42 #include "mount_dokan.h"
43 #include "mount_fuse.h"
44 #include "mount_handle.h"
45 #include "qcowtools_getopt.h"
46 #include "qcowtools_i18n.h"
47 #include "qcowtools_libcerror.h"
48 #include "qcowtools_libclocale.h"
49 #include "qcowtools_libcnotify.h"
50 #include "qcowtools_libqcow.h"
51 #include "qcowtools_output.h"
52 #include "qcowtools_signal.h"
53 #include "qcowtools_unused.h"
54
55 mount_handle_t *qcowmount_mount_handle = NULL;
56 int qcowmount_abort = 0;
57
58 /* Prints usage information
59 */
usage_fprint(FILE * stream)60 void usage_fprint(
61 FILE *stream )
62 {
63 if( stream == NULL )
64 {
65 return;
66 }
67 fprintf( stream, "Use qcowmount to mount a QEMU Copy-On-Write (QCOW) image file\n\n" );
68
69 fprintf( stream, "Usage: qcowmount [ -k keys ] [ -p password ] [ -X extended_options ] [ -hvV ]\n"
70 " image mount_point\n\n" );
71
72 fprintf( stream, "\timage: a QEMU Copy-On-Write (QCOW) image file\n\n" );
73 fprintf( stream, "\tmount_point: the directory to serve as mount point\n\n" );
74
75 fprintf( stream, "\t-h: shows this help\n" );
76 fprintf( stream, "\t-k: specify the key formatted in base16\n" );
77 fprintf( stream, "\t-p: specify the password/passphrase\n" );
78 fprintf( stream, "\t-v: verbose output to stderr, while qcowmount will remain running in the\n"
79 "\t foreground\n" );
80 fprintf( stream, "\t-V: print version\n" );
81 fprintf( stream, "\t-X: extended options to pass to sub system\n" );
82 }
83
84 /* Signal handler for qcowmount
85 */
qcowmount_signal_handler(qcowtools_signal_t signal QCOWTOOLS_ATTRIBUTE_UNUSED)86 void qcowmount_signal_handler(
87 qcowtools_signal_t signal QCOWTOOLS_ATTRIBUTE_UNUSED )
88 {
89 libcerror_error_t *error = NULL;
90 static char *function = "qcowmount_signal_handler";
91
92 QCOWTOOLS_UNREFERENCED_PARAMETER( signal )
93
94 qcowmount_abort = 1;
95
96 if( qcowmount_mount_handle != NULL )
97 {
98 if( mount_handle_signal_abort(
99 qcowmount_mount_handle,
100 &error ) != 1 )
101 {
102 libcnotify_printf(
103 "%s: unable to signal mount handle to abort.\n",
104 function );
105
106 libcnotify_print_error_backtrace(
107 error );
108 libcerror_error_free(
109 &error );
110 }
111 }
112 /* Force stdin to close otherwise any function reading it will remain blocked
113 */
114 #if defined( WINAPI ) && !defined( __CYGWIN__ )
115 if( _close(
116 0 ) != 0 )
117 #else
118 if( close(
119 0 ) != 0 )
120 #endif
121 {
122 libcnotify_printf(
123 "%s: unable to close stdin.\n",
124 function );
125 }
126 }
127
128 /* The main program
129 */
130 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
wmain(int argc,wchar_t * const argv[])131 int wmain( int argc, wchar_t * const argv[] )
132 #else
133 int main( int argc, char * const argv[] )
134 #endif
135 {
136 libqcow_error_t *error = NULL;
137 system_character_t *mount_point = NULL;
138 system_character_t *option_extended_options = NULL;
139 system_character_t *option_keys = NULL;
140 system_character_t *option_password = NULL;
141 const system_character_t *path_prefix = NULL;
142 system_character_t *source = NULL;
143 char *program = "qcowmount";
144 system_integer_t option = 0;
145 size_t path_prefix_size = 0;
146 int result = 0;
147 int verbose = 0;
148
149 #if defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE )
150 struct fuse_operations qcowmount_fuse_operations;
151
152 struct fuse_args qcowmount_fuse_arguments = FUSE_ARGS_INIT(0, NULL);
153 struct fuse_chan *qcowmount_fuse_channel = NULL;
154 struct fuse *qcowmount_fuse_handle = NULL;
155
156 #elif defined( HAVE_LIBDOKAN )
157 DOKAN_OPERATIONS qcowmount_dokan_operations;
158 DOKAN_OPTIONS qcowmount_dokan_options;
159 #endif
160
161 libcnotify_stream_set(
162 stderr,
163 NULL );
164 libcnotify_verbose_set(
165 1 );
166
167 if( libclocale_initialize(
168 "qcowtools",
169 &error ) != 1 )
170 {
171 fprintf(
172 stderr,
173 "Unable to initialize locale values.\n" );
174
175 goto on_error;
176 }
177 if( qcowtools_output_initialize(
178 _IONBF,
179 &error ) != 1 )
180 {
181 fprintf(
182 stderr,
183 "Unable to initialize output settings.\n" );
184
185 goto on_error;
186 }
187 qcowtools_output_version_fprint(
188 stdout,
189 program );
190
191 while( ( option = qcowtools_getopt(
192 argc,
193 argv,
194 _SYSTEM_STRING( "hk:p:vVX:" ) ) ) != (system_integer_t) -1 )
195 {
196 switch( option )
197 {
198 case (system_integer_t) '?':
199 default:
200 fprintf(
201 stderr,
202 "Invalid argument: %" PRIs_SYSTEM "\n",
203 argv[ optind - 1 ] );
204
205 usage_fprint(
206 stdout );
207
208 return( EXIT_FAILURE );
209
210 case (system_integer_t) 'h':
211 usage_fprint(
212 stdout );
213
214 return( EXIT_SUCCESS );
215
216 case (system_integer_t) 'k':
217 option_keys = optarg;
218
219 break;
220
221 case (system_integer_t) 'p':
222 option_password = optarg;
223
224 break;
225
226 case (system_integer_t) 'v':
227 verbose = 1;
228
229 break;
230
231 case (system_integer_t) 'V':
232 qcowtools_output_copyright_fprint(
233 stdout );
234
235 return( EXIT_SUCCESS );
236
237 case (system_integer_t) 'X':
238 option_extended_options = optarg;
239
240 break;
241 }
242 }
243 if( optind == argc )
244 {
245 fprintf(
246 stderr,
247 "Missing source image.\n" );
248
249 usage_fprint(
250 stdout );
251
252 return( EXIT_FAILURE );
253 }
254 source = argv[ optind++ ];
255
256 if( optind == argc )
257 {
258 fprintf(
259 stderr,
260 "Missing mount point.\n" );
261
262 usage_fprint(
263 stdout );
264
265 return( EXIT_FAILURE );
266 }
267 mount_point = argv[ optind ];
268
269 libcnotify_verbose_set(
270 verbose );
271 libqcow_notify_set_stream(
272 stderr,
273 NULL );
274 libqcow_notify_set_verbose(
275 verbose );
276
277 if( mount_handle_initialize(
278 &qcowmount_mount_handle,
279 &error ) != 1 )
280 {
281 fprintf(
282 stderr,
283 "Unable to initialize mount handle.\n" );
284
285 goto on_error;
286 }
287 if( option_keys != NULL )
288 {
289 if( mount_handle_set_keys(
290 qcowmount_mount_handle,
291 option_keys,
292 &error ) != 1 )
293 {
294 fprintf(
295 stderr,
296 "Unable to set keys.\n" );
297
298 goto on_error;
299 }
300 }
301 if( option_password != NULL )
302 {
303 if( mount_handle_set_password(
304 qcowmount_mount_handle,
305 option_password,
306 &error ) != 1 )
307 {
308 fprintf(
309 stderr,
310 "Unable to set password.\n" );
311
312 goto on_error;
313 }
314 }
315 #if defined( WINAPI )
316 path_prefix = _SYSTEM_STRING( "\\QCOW" );
317 #else
318 path_prefix = _SYSTEM_STRING( "/qcow" );
319 #endif
320 path_prefix_size = 1 + system_string_length(
321 path_prefix );
322
323 if( mount_handle_set_path_prefix(
324 qcowmount_mount_handle,
325 path_prefix,
326 path_prefix_size,
327 &error ) != 1 )
328 {
329 fprintf(
330 stderr,
331 "Unable to set path prefix.\n" );
332
333 goto on_error;
334 }
335 if( mount_handle_open(
336 qcowmount_mount_handle,
337 source,
338 &error ) != 1 )
339 {
340 fprintf(
341 stderr,
342 "Unable to open source image\n" );
343
344 goto on_error;
345 }
346 if( mount_handle_is_locked(
347 qcowmount_mount_handle,
348 &error ) != 0 )
349 {
350 fprintf(
351 stderr,
352 "Unable to unlock source image\n" );
353
354 goto on_error;
355 }
356 #if defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE )
357 if( option_extended_options != NULL )
358 {
359 /* This argument is required but ignored
360 */
361 if( fuse_opt_add_arg(
362 &qcowmount_fuse_arguments,
363 "" ) != 0 )
364 {
365 fprintf(
366 stderr,
367 "Unable add fuse arguments.\n" );
368
369 goto on_error;
370 }
371 if( fuse_opt_add_arg(
372 &qcowmount_fuse_arguments,
373 "-o" ) != 0 )
374 {
375 fprintf(
376 stderr,
377 "Unable add fuse arguments.\n" );
378
379 goto on_error;
380 }
381 if( fuse_opt_add_arg(
382 &qcowmount_fuse_arguments,
383 option_extended_options ) != 0 )
384 {
385 fprintf(
386 stderr,
387 "Unable add fuse arguments.\n" );
388
389 goto on_error;
390 }
391 }
392 if( memory_set(
393 &qcowmount_fuse_operations,
394 0,
395 sizeof( struct fuse_operations ) ) == NULL )
396 {
397 fprintf(
398 stderr,
399 "Unable to clear fuse operations.\n" );
400
401 goto on_error;
402 }
403 qcowmount_fuse_operations.open = &mount_fuse_open;
404 qcowmount_fuse_operations.read = &mount_fuse_read;
405 qcowmount_fuse_operations.release = &mount_fuse_release;
406 qcowmount_fuse_operations.opendir = &mount_fuse_opendir;
407 qcowmount_fuse_operations.readdir = &mount_fuse_readdir;
408 qcowmount_fuse_operations.releasedir = &mount_fuse_releasedir;
409 qcowmount_fuse_operations.getattr = &mount_fuse_getattr;
410 qcowmount_fuse_operations.destroy = &mount_fuse_destroy;
411
412 qcowmount_fuse_channel = fuse_mount(
413 mount_point,
414 &qcowmount_fuse_arguments );
415
416 if( qcowmount_fuse_channel == NULL )
417 {
418 fprintf(
419 stderr,
420 "Unable to create fuse channel.\n" );
421
422 goto on_error;
423 }
424 qcowmount_fuse_handle = fuse_new(
425 qcowmount_fuse_channel,
426 &qcowmount_fuse_arguments,
427 &qcowmount_fuse_operations,
428 sizeof( struct fuse_operations ),
429 qcowmount_mount_handle );
430
431 if( qcowmount_fuse_handle == NULL )
432 {
433 fprintf(
434 stderr,
435 "Unable to create fuse handle.\n" );
436
437 goto on_error;
438 }
439 if( verbose == 0 )
440 {
441 if( fuse_daemonize(
442 0 ) != 0 )
443 {
444 fprintf(
445 stderr,
446 "Unable to daemonize fuse.\n" );
447
448 goto on_error;
449 }
450 }
451 result = fuse_loop(
452 qcowmount_fuse_handle );
453
454 if( result != 0 )
455 {
456 fprintf(
457 stderr,
458 "Unable to run fuse loop.\n" );
459
460 goto on_error;
461 }
462 fuse_destroy(
463 qcowmount_fuse_handle );
464
465 fuse_opt_free_args(
466 &qcowmount_fuse_arguments );
467
468 return( EXIT_SUCCESS );
469
470 #elif defined( HAVE_LIBDOKAN )
471 if( memory_set(
472 &qcowmount_dokan_operations,
473 0,
474 sizeof( DOKAN_OPERATIONS ) ) == NULL )
475 {
476 fprintf(
477 stderr,
478 "Unable to clear dokan operations.\n" );
479
480 goto on_error;
481 }
482 if( memory_set(
483 &qcowmount_dokan_options,
484 0,
485 sizeof( DOKAN_OPTIONS ) ) == NULL )
486 {
487 fprintf(
488 stderr,
489 "Unable to clear dokan options.\n" );
490
491 goto on_error;
492 }
493 qcowmount_dokan_options.Version = DOKAN_VERSION;
494 qcowmount_dokan_options.ThreadCount = 0;
495 qcowmount_dokan_options.MountPoint = mount_point;
496
497 if( verbose != 0 )
498 {
499 qcowmount_dokan_options.Options |= DOKAN_OPTION_STDERR;
500 #if defined( HAVE_DEBUG_OUTPUT )
501 qcowmount_dokan_options.Options |= DOKAN_OPTION_DEBUG;
502 #endif
503 }
504 /* This will only affect the drive properties
505 qcowmount_dokan_options.Options |= DOKAN_OPTION_REMOVABLE;
506 */
507
508 #if ( DOKAN_VERSION >= 600 ) && ( DOKAN_VERSION < 800 )
509 qcowmount_dokan_options.Options |= DOKAN_OPTION_KEEP_ALIVE;
510
511 qcowmount_dokan_operations.CreateFile = &mount_dokan_CreateFile;
512 qcowmount_dokan_operations.OpenDirectory = &mount_dokan_OpenDirectory;
513 qcowmount_dokan_operations.CreateDirectory = NULL;
514 qcowmount_dokan_operations.Cleanup = NULL;
515 qcowmount_dokan_operations.CloseFile = &mount_dokan_CloseFile;
516 qcowmount_dokan_operations.ReadFile = &mount_dokan_ReadFile;
517 qcowmount_dokan_operations.WriteFile = NULL;
518 qcowmount_dokan_operations.FlushFileBuffers = NULL;
519 qcowmount_dokan_operations.GetFileInformation = &mount_dokan_GetFileInformation;
520 qcowmount_dokan_operations.FindFiles = &mount_dokan_FindFiles;
521 qcowmount_dokan_operations.FindFilesWithPattern = NULL;
522 qcowmount_dokan_operations.SetFileAttributes = NULL;
523 qcowmount_dokan_operations.SetFileTime = NULL;
524 qcowmount_dokan_operations.DeleteFile = NULL;
525 qcowmount_dokan_operations.DeleteDirectory = NULL;
526 qcowmount_dokan_operations.MoveFile = NULL;
527 qcowmount_dokan_operations.SetEndOfFile = NULL;
528 qcowmount_dokan_operations.SetAllocationSize = NULL;
529 qcowmount_dokan_operations.LockFile = NULL;
530 qcowmount_dokan_operations.UnlockFile = NULL;
531 qcowmount_dokan_operations.GetFileSecurity = NULL;
532 qcowmount_dokan_operations.SetFileSecurity = NULL;
533 qcowmount_dokan_operations.GetDiskFreeSpace = NULL;
534 qcowmount_dokan_operations.GetVolumeInformation = &mount_dokan_GetVolumeInformation;
535 qcowmount_dokan_operations.Unmount = &mount_dokan_Unmount;
536
537 #else
538 qcowmount_dokan_operations.ZwCreateFile = &mount_dokan_ZwCreateFile;
539 qcowmount_dokan_operations.Cleanup = NULL;
540 qcowmount_dokan_operations.CloseFile = &mount_dokan_CloseFile;
541 qcowmount_dokan_operations.ReadFile = &mount_dokan_ReadFile;
542 qcowmount_dokan_operations.WriteFile = NULL;
543 qcowmount_dokan_operations.FlushFileBuffers = NULL;
544 qcowmount_dokan_operations.GetFileInformation = &mount_dokan_GetFileInformation;
545 qcowmount_dokan_operations.FindFiles = &mount_dokan_FindFiles;
546 qcowmount_dokan_operations.FindFilesWithPattern = NULL;
547 qcowmount_dokan_operations.SetFileAttributes = NULL;
548 qcowmount_dokan_operations.SetFileTime = NULL;
549 qcowmount_dokan_operations.DeleteFile = NULL;
550 qcowmount_dokan_operations.DeleteDirectory = NULL;
551 qcowmount_dokan_operations.MoveFile = NULL;
552 qcowmount_dokan_operations.SetEndOfFile = NULL;
553 qcowmount_dokan_operations.SetAllocationSize = NULL;
554 qcowmount_dokan_operations.LockFile = NULL;
555 qcowmount_dokan_operations.UnlockFile = NULL;
556 qcowmount_dokan_operations.GetFileSecurity = NULL;
557 qcowmount_dokan_operations.SetFileSecurity = NULL;
558 qcowmount_dokan_operations.GetDiskFreeSpace = NULL;
559 qcowmount_dokan_operations.GetVolumeInformation = &mount_dokan_GetVolumeInformation;
560 qcowmount_dokan_operations.Unmounted = NULL;
561 qcowmount_dokan_operations.FindStreams = NULL;
562 qcowmount_dokan_operations.Mounted = NULL;
563
564 #endif /* ( DOKAN_VERSION >= 600 ) && ( DOKAN_VERSION < 800 ) */
565
566 result = DokanMain(
567 &qcowmount_dokan_options,
568 &qcowmount_dokan_operations );
569
570 switch( result )
571 {
572 case DOKAN_SUCCESS:
573 break;
574
575 case DOKAN_ERROR:
576 fprintf(
577 stderr,
578 "Unable to run dokan main: generic error\n" );
579 break;
580
581 case DOKAN_DRIVE_LETTER_ERROR:
582 fprintf(
583 stderr,
584 "Unable to run dokan main: bad drive letter\n" );
585 break;
586
587 case DOKAN_DRIVER_INSTALL_ERROR:
588 fprintf(
589 stderr,
590 "Unable to run dokan main: unable to load driver\n" );
591 break;
592
593 case DOKAN_START_ERROR:
594 fprintf(
595 stderr,
596 "Unable to run dokan main: driver error\n" );
597 break;
598
599 case DOKAN_MOUNT_ERROR:
600 fprintf(
601 stderr,
602 "Unable to run dokan main: unable to assign drive letter\n" );
603 break;
604
605 case DOKAN_MOUNT_POINT_ERROR:
606 fprintf(
607 stderr,
608 "Unable to run dokan main: mount point error\n" );
609 break;
610
611 default:
612 fprintf(
613 stderr,
614 "Unable to run dokan main: unknown error: %d\n",
615 result );
616 break;
617 }
618 return( EXIT_SUCCESS );
619
620 #else
621 fprintf(
622 stderr,
623 "No sub system to mount QCOW format.\n" );
624
625 return( EXIT_FAILURE );
626
627 #endif /* defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE ) */
628
629 on_error:
630 if( error != NULL )
631 {
632 libcnotify_print_error_backtrace(
633 error );
634 libcerror_error_free(
635 &error );
636 }
637 #if defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE )
638 if( qcowmount_fuse_handle != NULL )
639 {
640 fuse_destroy(
641 qcowmount_fuse_handle );
642 }
643 fuse_opt_free_args(
644 &qcowmount_fuse_arguments );
645 #endif
646 if( qcowmount_mount_handle != NULL )
647 {
648 mount_handle_free(
649 &qcowmount_mount_handle,
650 NULL );
651 }
652 return( EXIT_FAILURE );
653 }
654
655