VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp@ 56927

Last change on this file since 56927 was 56921, checked in by vboxsync, 9 years ago

FE/VBoxManage: Fix possible crash when resizing a medium and the call to IMedium::Resize returns a Null progress object

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.5 KB
Line 
1/* $Id: VBoxManageDisk.cpp 56921 2015-07-13 09:46:40Z vboxsync $ */
2/** @file
3 * VBoxManage - The disk/medium related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VBOX_ONLY_DOCS
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include <VBox/com/com.h>
24#include <VBox/com/array.h>
25#include <VBox/com/ErrorInfo.h>
26#include <VBox/com/errorprint.h>
27#include <VBox/com/VirtualBox.h>
28
29#include <iprt/asm.h>
30#include <iprt/file.h>
31#include <iprt/path.h>
32#include <iprt/param.h>
33#include <iprt/stream.h>
34#include <iprt/string.h>
35#include <iprt/ctype.h>
36#include <iprt/getopt.h>
37#include <VBox/log.h>
38#include <VBox/vd.h>
39
40#include "VBoxManage.h"
41using namespace com;
42
43
44// funcs
45///////////////////////////////////////////////////////////////////////////////
46
47
48static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
49{
50 RTMsgErrorV(pszFormat, va);
51 RTMsgError("Error code %Rrc at %s(%u) in function %s", rc, RT_SRC_POS_ARGS);
52}
53
54static int parseMediumVariant(const char *psz, MediumVariant_T *pMediumVariant)
55{
56 int rc = VINF_SUCCESS;
57 unsigned uMediumVariant = (unsigned)(*pMediumVariant);
58 while (psz && *psz && RT_SUCCESS(rc))
59 {
60 size_t len;
61 const char *pszComma = strchr(psz, ',');
62 if (pszComma)
63 len = pszComma - psz;
64 else
65 len = strlen(psz);
66 if (len > 0)
67 {
68 // Parsing is intentionally inconsistent: "standard" resets the
69 // variant, whereas the other flags are cumulative.
70 if (!RTStrNICmp(psz, "standard", len))
71 uMediumVariant = MediumVariant_Standard;
72 else if ( !RTStrNICmp(psz, "fixed", len)
73 || !RTStrNICmp(psz, "static", len))
74 uMediumVariant |= MediumVariant_Fixed;
75 else if (!RTStrNICmp(psz, "Diff", len))
76 uMediumVariant |= MediumVariant_Diff;
77 else if (!RTStrNICmp(psz, "split2g", len))
78 uMediumVariant |= MediumVariant_VmdkSplit2G;
79 else if ( !RTStrNICmp(psz, "stream", len)
80 || !RTStrNICmp(psz, "streamoptimized", len))
81 uMediumVariant |= MediumVariant_VmdkStreamOptimized;
82 else if (!RTStrNICmp(psz, "esx", len))
83 uMediumVariant |= MediumVariant_VmdkESX;
84 else
85 rc = VERR_PARSE_ERROR;
86 }
87 if (pszComma)
88 psz += len + 1;
89 else
90 psz += len;
91 }
92
93 if (RT_SUCCESS(rc))
94 *pMediumVariant = (MediumVariant_T)uMediumVariant;
95 return rc;
96}
97
98int parseMediumType(const char *psz, MediumType_T *penmMediumType)
99{
100 int rc = VINF_SUCCESS;
101 MediumType_T enmMediumType = MediumType_Normal;
102 if (!RTStrICmp(psz, "normal"))
103 enmMediumType = MediumType_Normal;
104 else if (!RTStrICmp(psz, "immutable"))
105 enmMediumType = MediumType_Immutable;
106 else if (!RTStrICmp(psz, "writethrough"))
107 enmMediumType = MediumType_Writethrough;
108 else if (!RTStrICmp(psz, "shareable"))
109 enmMediumType = MediumType_Shareable;
110 else if (!RTStrICmp(psz, "readonly"))
111 enmMediumType = MediumType_Readonly;
112 else if (!RTStrICmp(psz, "multiattach"))
113 enmMediumType = MediumType_MultiAttach;
114 else
115 rc = VERR_PARSE_ERROR;
116
117 if (RT_SUCCESS(rc))
118 *penmMediumType = enmMediumType;
119 return rc;
120}
121
122/** @todo move this into getopt, as getting bool values is generic */
123int parseBool(const char *psz, bool *pb)
124{
125 int rc = VINF_SUCCESS;
126 if ( !RTStrICmp(psz, "on")
127 || !RTStrICmp(psz, "yes")
128 || !RTStrICmp(psz, "true")
129 || !RTStrICmp(psz, "1")
130 || !RTStrICmp(psz, "enable")
131 || !RTStrICmp(psz, "enabled"))
132 {
133 *pb = true;
134 }
135 else if ( !RTStrICmp(psz, "off")
136 || !RTStrICmp(psz, "no")
137 || !RTStrICmp(psz, "false")
138 || !RTStrICmp(psz, "0")
139 || !RTStrICmp(psz, "disable")
140 || !RTStrICmp(psz, "disabled"))
141 {
142 *pb = false;
143 }
144 else
145 rc = VERR_PARSE_ERROR;
146
147 return rc;
148}
149
150HRESULT openMedium(HandlerArg *a, const char *pszFilenameOrUuid,
151 DeviceType_T enmDevType, AccessMode_T enmAccessMode,
152 ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
153 bool fSilent)
154{
155 HRESULT rc;
156 Guid id(pszFilenameOrUuid);
157 char szFilenameAbs[RTPATH_MAX] = "";
158
159 /* If it is no UUID, convert the filename to an absolute one. */
160 if (!id.isValid())
161 {
162 int irc = RTPathAbs(pszFilenameOrUuid, szFilenameAbs, sizeof(szFilenameAbs));
163 if (RT_FAILURE(irc))
164 {
165 if (!fSilent)
166 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilenameOrUuid);
167 return E_FAIL;
168 }
169 pszFilenameOrUuid = szFilenameAbs;
170 }
171
172 if (!fSilent)
173 CHECK_ERROR(a->virtualBox, OpenMedium(Bstr(pszFilenameOrUuid).raw(),
174 enmDevType,
175 enmAccessMode,
176 fForceNewUuidOnOpen,
177 pMedium.asOutParam()));
178 else
179 rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
180 enmDevType,
181 enmAccessMode,
182 fForceNewUuidOnOpen,
183 pMedium.asOutParam());
184
185 return rc;
186}
187
188static HRESULT createMedium(HandlerArg *a, const char *pszFormat,
189 const char *pszFilename, DeviceType_T enmDevType,
190 AccessMode_T enmAccessMode, ComPtr<IMedium> &pMedium)
191{
192 HRESULT rc;
193 char szFilenameAbs[RTPATH_MAX] = "";
194
195 /** @todo laziness shortcut. should really check the MediumFormatCapabilities */
196 if (RTStrICmp(pszFormat, "iSCSI"))
197 {
198 int irc = RTPathAbs(pszFilename, szFilenameAbs, sizeof(szFilenameAbs));
199 if (RT_FAILURE(irc))
200 {
201 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilename);
202 return E_FAIL;
203 }
204 pszFilename = szFilenameAbs;
205 }
206
207 CHECK_ERROR(a->virtualBox, CreateMedium(Bstr(pszFormat).raw(),
208 Bstr(pszFilename).raw(),
209 enmAccessMode,
210 enmDevType,
211 pMedium.asOutParam()));
212 return rc;
213}
214
215static const RTGETOPTDEF g_aCreateMediumOptions[] =
216{
217 { "disk", 'H', RTGETOPT_REQ_NOTHING },
218 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
219 { "floppy", 'L', RTGETOPT_REQ_NOTHING },
220 { "--filename", 'f', RTGETOPT_REQ_STRING },
221 { "-filename", 'f', RTGETOPT_REQ_STRING }, // deprecated
222 { "--diffparent", 'd', RTGETOPT_REQ_STRING },
223 { "--size", 's', RTGETOPT_REQ_UINT64 },
224 { "-size", 's', RTGETOPT_REQ_UINT64 }, // deprecated
225 { "--sizebyte", 'S', RTGETOPT_REQ_UINT64 },
226 { "--format", 'o', RTGETOPT_REQ_STRING },
227 { "-format", 'o', RTGETOPT_REQ_STRING }, // deprecated
228 { "--static", 'F', RTGETOPT_REQ_NOTHING },
229 { "-static", 'F', RTGETOPT_REQ_NOTHING }, // deprecated
230 { "--variant", 'm', RTGETOPT_REQ_STRING },
231 { "-variant", 'm', RTGETOPT_REQ_STRING }, // deprecated
232};
233
234RTEXITCODE handleCreateMedium(HandlerArg *a)
235{
236 HRESULT rc;
237 int vrc;
238 const char *filename = NULL;
239 const char *diffparent = NULL;
240 uint64_t size = 0;
241 enum {
242 CMD_NONE,
243 CMD_DISK,
244 CMD_DVD,
245 CMD_FLOPPY
246 } cmd = CMD_NONE;
247 const char *format = NULL;
248 bool fBase = true;
249 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
250
251 int c;
252 RTGETOPTUNION ValueUnion;
253 RTGETOPTSTATE GetState;
254 // start at 0 because main() has hacked both the argc and argv given to us
255 RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateMediumOptions, RT_ELEMENTS(g_aCreateMediumOptions),
256 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
257 while ((c = RTGetOpt(&GetState, &ValueUnion)))
258 {
259 switch (c)
260 {
261 case 'H': // disk
262 if (cmd != CMD_NONE)
263 return errorSyntax(USAGE_CREATEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
264 cmd = CMD_DISK;
265 break;
266
267 case 'D': // DVD
268 if (cmd != CMD_NONE)
269 return errorSyntax(USAGE_CREATEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
270 cmd = CMD_DVD;
271 break;
272
273 case 'L': // floppy
274 if (cmd != CMD_NONE)
275 return errorSyntax(USAGE_CREATEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
276 cmd = CMD_FLOPPY;
277 break;
278
279 case 'f': // --filename
280 filename = ValueUnion.psz;
281 break;
282
283 case 'd': // --diffparent
284 diffparent = ValueUnion.psz;
285 fBase = false;
286 break;
287
288 case 's': // --size
289 size = ValueUnion.u64 * _1M;
290 break;
291
292 case 'S': // --sizebyte
293 size = ValueUnion.u64;
294 break;
295
296 case 'o': // --format
297 format = ValueUnion.psz;
298 break;
299
300 case 'F': // --static ("fixed"/"flat")
301 {
302 unsigned uMediumVariant = (unsigned)enmMediumVariant;
303 uMediumVariant |= MediumVariant_Fixed;
304 enmMediumVariant = (MediumVariant_T)uMediumVariant;
305 break;
306 }
307
308 case 'm': // --variant
309 vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
310 if (RT_FAILURE(vrc))
311 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
312 break;
313
314 case VINF_GETOPT_NOT_OPTION:
315 return errorSyntax(USAGE_CREATEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
316
317 default:
318 if (c > 0)
319 {
320 if (RT_C_IS_PRINT(c))
321 return errorSyntax(USAGE_CREATEMEDIUM, "Invalid option -%c", c);
322 else
323 return errorSyntax(USAGE_CREATEMEDIUM, "Invalid option case %i", c);
324 }
325 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
326 return errorSyntax(USAGE_CREATEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
327 else if (ValueUnion.pDef)
328 return errorSyntax(USAGE_CREATEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
329 else
330 return errorSyntax(USAGE_CREATEMEDIUM, "error: %Rrs", c);
331 }
332 }
333
334 /* check the outcome */
335 if (cmd == CMD_NONE)
336 cmd = CMD_DISK;
337 ComPtr<IMedium> pParentMedium;
338 if (fBase)
339 {
340 if ( !filename
341 || !*filename
342 || size == 0)
343 return errorSyntax(USAGE_CREATEMEDIUM, "Parameters --filename and --size are required");
344 if (!format || !*format)
345 {
346 if (cmd == CMD_DISK)
347 format = "VDI";
348 else if (cmd == CMD_DVD || cmd == CMD_FLOPPY)
349 {
350 format = "RAW";
351 unsigned uMediumVariant = (unsigned)enmMediumVariant;
352 uMediumVariant |= MediumVariant_Fixed;
353 enmMediumVariant = (MediumVariant_T)uMediumVariant;
354 }
355 }
356 }
357 else
358 {
359 if ( !filename
360 || !*filename)
361 return errorSyntax(USAGE_CREATEMEDIUM, "Parameters --filename is required");
362 size = 0;
363 if (cmd != CMD_DISK)
364 return errorSyntax(USAGE_CREATEMEDIUM, "Creating a differencing medium is only supported for hard disks");
365 enmMediumVariant = MediumVariant_Diff;
366 if (!format || !*format)
367 {
368 const char *pszExt = RTPathSuffix(filename);
369 /* Skip over . if there is an extension. */
370 if (pszExt)
371 pszExt++;
372 if (!pszExt || !*pszExt)
373 format = "VDI";
374 else
375 format = pszExt;
376 }
377 rc = openMedium(a, diffparent, DeviceType_HardDisk,
378 AccessMode_ReadWrite, pParentMedium,
379 false /* fForceNewUuidOnOpen */, false /* fSilent */);
380 if (FAILED(rc))
381 return RTEXITCODE_FAILURE;
382 if (pParentMedium.isNull())
383 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid parent hard disk reference, avoiding crash");
384 MediumState_T state;
385 CHECK_ERROR(pParentMedium, COMGETTER(State)(&state));
386 if (FAILED(rc))
387 return RTEXITCODE_FAILURE;
388 if (state == MediumState_Inaccessible)
389 {
390 CHECK_ERROR(pParentMedium, RefreshState(&state));
391 if (FAILED(rc))
392 return RTEXITCODE_FAILURE;
393 }
394 }
395 /* check for filename extension */
396 /** @todo use IMediumFormat to cover all extensions generically */
397 Utf8Str strName(filename);
398 if (!RTPathHasSuffix(strName.c_str()))
399 {
400 Utf8Str strFormat(format);
401 if (cmd == CMD_DISK)
402 {
403 if (strFormat.compare("vmdk", RTCString::CaseInsensitive) == 0)
404 strName.append(".vmdk");
405 else if (strFormat.compare("vhd", RTCString::CaseInsensitive) == 0)
406 strName.append(".vhd");
407 else
408 strName.append(".vdi");
409 } else if (cmd == CMD_DVD)
410 strName.append(".iso");
411 else if (cmd == CMD_FLOPPY)
412 strName.append(".img");
413 filename = strName.c_str();
414 }
415
416 ComPtr<IMedium> pMedium;
417 if (cmd == CMD_DISK)
418 rc = createMedium(a, format, filename, DeviceType_HardDisk,
419 AccessMode_ReadWrite, pMedium);
420 else if (cmd == CMD_DVD)
421 rc = createMedium(a, format, filename, DeviceType_DVD,
422 AccessMode_ReadOnly, pMedium);
423 else if (cmd == CMD_FLOPPY)
424 rc = createMedium(a, format, filename, DeviceType_Floppy,
425 AccessMode_ReadWrite, pMedium);
426 else
427 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
428
429 if (SUCCEEDED(rc) && pMedium)
430 {
431 ComPtr<IProgress> pProgress;
432 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
433
434 for (ULONG i = 0; i < l_variants.size(); ++i)
435 {
436 ULONG temp = enmMediumVariant;
437 temp &= 1<<i;
438 l_variants [i] = (MediumVariant_T)temp;
439 }
440
441 if (fBase)
442 CHECK_ERROR(pMedium, CreateBaseStorage(size, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
443 else
444 CHECK_ERROR(pParentMedium, CreateDiffStorage(pMedium, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
445 if (SUCCEEDED(rc) && pProgress)
446 {
447 rc = showProgress(pProgress);
448 CHECK_PROGRESS_ERROR(pProgress, ("Failed to create medium"));
449 }
450 }
451
452 if (SUCCEEDED(rc) && pMedium)
453 {
454 Bstr uuid;
455 CHECK_ERROR(pMedium, COMGETTER(Id)(uuid.asOutParam()));
456 RTPrintf("Medium created. UUID: %s\n", Utf8Str(uuid).c_str());
457
458 //CHECK_ERROR(pMedium, Close());
459 }
460 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
461}
462
463static const RTGETOPTDEF g_aModifyMediumOptions[] =
464{
465 { "disk", 'H', RTGETOPT_REQ_NOTHING },
466 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
467 { "floppy", 'L', RTGETOPT_REQ_NOTHING },
468 { "--type", 't', RTGETOPT_REQ_STRING },
469 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
470 { "settype", 't', RTGETOPT_REQ_STRING }, // deprecated
471 { "--autoreset", 'z', RTGETOPT_REQ_STRING },
472 { "-autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
473 { "autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
474 { "--property", 'p', RTGETOPT_REQ_STRING },
475 { "--compact", 'c', RTGETOPT_REQ_NOTHING },
476 { "-compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
477 { "compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
478 { "--resize", 'r', RTGETOPT_REQ_UINT64 },
479 { "--resizebyte", 'R', RTGETOPT_REQ_UINT64 }
480};
481
482RTEXITCODE handleModifyMedium(HandlerArg *a)
483{
484 HRESULT rc;
485 int vrc;
486 enum {
487 CMD_NONE,
488 CMD_DISK,
489 CMD_DVD,
490 CMD_FLOPPY
491 } cmd = CMD_NONE;
492 ComPtr<IMedium> pMedium;
493 MediumType_T enmMediumType;
494 bool AutoReset = false;
495 SafeArray<BSTR> mediumPropNames;
496 SafeArray<BSTR> mediumPropValues;
497 bool fModifyMediumType = false;
498 bool fModifyAutoReset = false;
499 bool fModifyProperties = false;
500 bool fModifyCompact = false;
501 bool fModifyResize = false;
502 uint64_t cbResize = 0;
503 const char *pszFilenameOrUuid = NULL;
504
505 int c;
506 RTGETOPTUNION ValueUnion;
507 RTGETOPTSTATE GetState;
508 // start at 0 because main() has hacked both the argc and argv given to us
509 RTGetOptInit(&GetState, a->argc, a->argv, g_aModifyMediumOptions, RT_ELEMENTS(g_aModifyMediumOptions),
510 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
511 while ((c = RTGetOpt(&GetState, &ValueUnion)))
512 {
513 switch (c)
514 {
515 case 'H': // disk
516 if (cmd != CMD_NONE)
517 return errorSyntax(USAGE_MODIFYMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
518 cmd = CMD_DISK;
519 break;
520
521 case 'D': // DVD
522 if (cmd != CMD_NONE)
523 return errorSyntax(USAGE_MODIFYMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
524 cmd = CMD_DVD;
525 break;
526
527 case 'L': // floppy
528 if (cmd != CMD_NONE)
529 return errorSyntax(USAGE_MODIFYMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
530 cmd = CMD_FLOPPY;
531 break;
532
533 case 't': // --type
534 vrc = parseMediumType(ValueUnion.psz, &enmMediumType);
535 if (RT_FAILURE(vrc))
536 return errorArgument("Invalid medium type '%s'", ValueUnion.psz);
537 fModifyMediumType = true;
538 break;
539
540 case 'z': // --autoreset
541 vrc = parseBool(ValueUnion.psz, &AutoReset);
542 if (RT_FAILURE(vrc))
543 return errorArgument("Invalid autoreset parameter '%s'", ValueUnion.psz);
544 fModifyAutoReset = true;
545 break;
546
547 case 'p': // --property
548 {
549 /* Parse 'name=value' */
550 char *pszProperty = RTStrDup(ValueUnion.psz);
551 if (pszProperty)
552 {
553 char *pDelimiter = strchr(pszProperty, '=');
554 if (pDelimiter)
555 {
556 *pDelimiter = '\0';
557
558 Bstr bstrName(pszProperty);
559 Bstr bstrValue(&pDelimiter[1]);
560 bstrName.detachTo(mediumPropNames.appendedRaw());
561 bstrValue.detachTo(mediumPropValues.appendedRaw());
562 fModifyProperties = true;
563 }
564 else
565 {
566 errorArgument("Invalid --property argument '%s'", ValueUnion.psz);
567 rc = E_FAIL;
568 }
569 RTStrFree(pszProperty);
570 }
571 else
572 {
573 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for medium property '%s'\n", ValueUnion.psz);
574 rc = E_FAIL;
575 }
576 break;
577 }
578
579 case 'c': // --compact
580 fModifyCompact = true;
581 break;
582
583 case 'r': // --resize
584 cbResize = ValueUnion.u64 * _1M;
585 fModifyResize = true;
586 break;
587
588 case 'R': // --resizebyte
589 cbResize = ValueUnion.u64;
590 fModifyResize = true;
591 break;
592
593 case VINF_GETOPT_NOT_OPTION:
594 if (!pszFilenameOrUuid)
595 pszFilenameOrUuid = ValueUnion.psz;
596 else
597 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
598 break;
599
600 default:
601 if (c > 0)
602 {
603 if (RT_C_IS_PRINT(c))
604 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid option -%c", c);
605 else
606 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid option case %i", c);
607 }
608 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
609 return errorSyntax(USAGE_MODIFYMEDIUM, "unknown option: %s\n", ValueUnion.psz);
610 else if (ValueUnion.pDef)
611 return errorSyntax(USAGE_MODIFYMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
612 else
613 return errorSyntax(USAGE_MODIFYMEDIUM, "error: %Rrs", c);
614 }
615 }
616
617 if (cmd == CMD_NONE)
618 cmd = CMD_DISK;
619
620 if (!pszFilenameOrUuid)
621 return errorSyntax(USAGE_MODIFYMEDIUM, "Medium name or UUID required");
622
623 if (!fModifyMediumType && !fModifyAutoReset && !fModifyProperties && !fModifyCompact && !fModifyResize)
624 return errorSyntax(USAGE_MODIFYMEDIUM, "No operation specified");
625
626 /* Always open the medium if necessary, there is no other way. */
627 if (cmd == CMD_DISK)
628 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
629 AccessMode_ReadWrite, pMedium,
630 false /* fForceNewUuidOnOpen */, false /* fSilent */);
631 else if (cmd == CMD_DVD)
632 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
633 AccessMode_ReadOnly, pMedium,
634 false /* fForceNewUuidOnOpen */, false /* fSilent */);
635 else if (cmd == CMD_FLOPPY)
636 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
637 AccessMode_ReadWrite, pMedium,
638 false /* fForceNewUuidOnOpen */, false /* fSilent */);
639 else
640 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
641 if (FAILED(rc))
642 return RTEXITCODE_FAILURE;
643 if (pMedium.isNull())
644 {
645 RTMsgError("Invalid medium reference, avoiding crash");
646 return RTEXITCODE_FAILURE;
647 }
648
649 if (fModifyMediumType)
650 {
651 MediumType_T enmCurrMediumType;
652 CHECK_ERROR(pMedium, COMGETTER(Type)(&enmCurrMediumType));
653
654 if (enmCurrMediumType != enmMediumType)
655 CHECK_ERROR(pMedium, COMSETTER(Type)(enmMediumType));
656 }
657
658 if (fModifyAutoReset)
659 {
660 CHECK_ERROR(pMedium, COMSETTER(AutoReset)(AutoReset));
661 }
662
663 if (fModifyProperties)
664 {
665 CHECK_ERROR(pMedium, SetProperties(ComSafeArrayAsInParam(mediumPropNames), ComSafeArrayAsInParam(mediumPropValues)));
666 }
667
668 if (fModifyCompact)
669 {
670 ComPtr<IProgress> pProgress;
671 CHECK_ERROR(pMedium, Compact(pProgress.asOutParam()));
672 if (SUCCEEDED(rc))
673 rc = showProgress(pProgress);
674 if (FAILED(rc))
675 {
676 if (rc == E_NOTIMPL)
677 RTMsgError("Compact medium operation is not implemented!");
678 else if (rc == VBOX_E_NOT_SUPPORTED)
679 RTMsgError("Compact medium operation for this format is not implemented yet!");
680 else if (!pProgress.isNull())
681 CHECK_PROGRESS_ERROR(pProgress, ("Failed to compact medium"));
682 else
683 RTMsgError("Failed to compact medium!");
684 }
685 }
686
687 if (fModifyResize)
688 {
689 ComPtr<IProgress> pProgress;
690 CHECK_ERROR(pMedium, Resize(cbResize, pProgress.asOutParam()));
691 if (SUCCEEDED(rc))
692 rc = showProgress(pProgress);
693 if (FAILED(rc))
694 {
695 if (rc == E_NOTIMPL)
696 RTMsgError("Resize medium operation is not implemented!");
697 else if (rc == VBOX_E_NOT_SUPPORTED)
698 RTMsgError("Resize medium operation for this format is not implemented yet!");
699 else if (!pProgress.isNull())
700 CHECK_PROGRESS_ERROR(pProgress, ("Failed to resize medium"));
701 else
702 RTMsgError("Failed to resize medium!");
703 }
704 }
705
706 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
707}
708
709static const RTGETOPTDEF g_aCloneMediumOptions[] =
710{
711 { "disk", 'd', RTGETOPT_REQ_NOTHING },
712 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
713 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
714 { "--format", 'o', RTGETOPT_REQ_STRING },
715 { "-format", 'o', RTGETOPT_REQ_STRING },
716 { "--static", 'F', RTGETOPT_REQ_NOTHING },
717 { "-static", 'F', RTGETOPT_REQ_NOTHING },
718 { "--existing", 'E', RTGETOPT_REQ_NOTHING },
719 { "--variant", 'm', RTGETOPT_REQ_STRING },
720 { "-variant", 'm', RTGETOPT_REQ_STRING },
721};
722
723RTEXITCODE handleCloneMedium(HandlerArg *a)
724{
725 HRESULT rc;
726 int vrc;
727 enum {
728 CMD_NONE,
729 CMD_DISK,
730 CMD_DVD,
731 CMD_FLOPPY
732 } cmd = CMD_NONE;
733 const char *pszSrc = NULL;
734 const char *pszDst = NULL;
735 Bstr format;
736 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
737 bool fExisting = false;
738
739 int c;
740 RTGETOPTUNION ValueUnion;
741 RTGETOPTSTATE GetState;
742 // start at 0 because main() has hacked both the argc and argv given to us
743 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneMediumOptions, RT_ELEMENTS(g_aCloneMediumOptions),
744 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
745 while ((c = RTGetOpt(&GetState, &ValueUnion)))
746 {
747 switch (c)
748 {
749 case 'd': // disk
750 if (cmd != CMD_NONE)
751 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
752 cmd = CMD_DISK;
753 break;
754
755 case 'D': // DVD
756 if (cmd != CMD_NONE)
757 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
758 cmd = CMD_DVD;
759 break;
760
761 case 'f': // floppy
762 if (cmd != CMD_NONE)
763 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
764 cmd = CMD_FLOPPY;
765 break;
766
767 case 'o': // --format
768 format = ValueUnion.psz;
769 break;
770
771 case 'F': // --static
772 {
773 unsigned uMediumVariant = (unsigned)enmMediumVariant;
774 uMediumVariant |= MediumVariant_Fixed;
775 enmMediumVariant = (MediumVariant_T)uMediumVariant;
776 break;
777 }
778
779 case 'E': // --existing
780 fExisting = true;
781 break;
782
783 case 'm': // --variant
784 vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
785 if (RT_FAILURE(vrc))
786 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
787 break;
788
789 case VINF_GETOPT_NOT_OPTION:
790 if (!pszSrc)
791 pszSrc = ValueUnion.psz;
792 else if (!pszDst)
793 pszDst = ValueUnion.psz;
794 else
795 return errorSyntax(USAGE_CLONEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
796 break;
797
798 default:
799 if (c > 0)
800 {
801 if (RT_C_IS_GRAPH(c))
802 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: -%c", c);
803 else
804 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: %i", c);
805 }
806 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
807 return errorSyntax(USAGE_CLONEMEDIUM, "unknown option: %s", ValueUnion.psz);
808 else if (ValueUnion.pDef)
809 return errorSyntax(USAGE_CLONEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
810 else
811 return errorSyntax(USAGE_CLONEMEDIUM, "error: %Rrs", c);
812 }
813 }
814
815 if (cmd == CMD_NONE)
816 cmd = CMD_DISK;
817 if (!pszSrc)
818 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory UUID or input file parameter missing");
819 if (!pszDst)
820 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory output file parameter missing");
821 if (fExisting && (!format.isEmpty() || enmMediumVariant != MediumType_Normal))
822 return errorSyntax(USAGE_CLONEMEDIUM, "Specified options which cannot be used with --existing");
823
824 ComPtr<IMedium> pSrcMedium;
825 ComPtr<IMedium> pDstMedium;
826
827 if (cmd == CMD_DISK)
828 rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly, pSrcMedium,
829 false /* fForceNewUuidOnOpen */, false /* fSilent */);
830 else if (cmd == CMD_DVD)
831 rc = openMedium(a, pszSrc, DeviceType_DVD, AccessMode_ReadOnly, pSrcMedium,
832 false /* fForceNewUuidOnOpen */, false /* fSilent */);
833 else if (cmd == CMD_FLOPPY)
834 rc = openMedium(a, pszSrc, DeviceType_Floppy, AccessMode_ReadOnly, pSrcMedium,
835 false /* fForceNewUuidOnOpen */, false /* fSilent */);
836 else
837 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
838 if (FAILED(rc))
839 return RTEXITCODE_FAILURE;
840
841 do
842 {
843 /* open/create destination medium */
844 if (fExisting)
845 {
846 if (cmd == CMD_DISK)
847 rc = openMedium(a, pszDst, DeviceType_HardDisk, AccessMode_ReadWrite, pDstMedium,
848 false /* fForceNewUuidOnOpen */, false /* fSilent */);
849 else if (cmd == CMD_DVD)
850 rc = openMedium(a, pszDst, DeviceType_DVD, AccessMode_ReadOnly, pDstMedium,
851 false /* fForceNewUuidOnOpen */, false /* fSilent */);
852 else if (cmd == CMD_FLOPPY)
853 rc = openMedium(a, pszDst, DeviceType_Floppy, AccessMode_ReadWrite, pDstMedium,
854 false /* fForceNewUuidOnOpen */, false /* fSilent */);
855 if (FAILED(rc))
856 break;
857
858 /* Perform accessibility check now. */
859 MediumState_T state;
860 CHECK_ERROR_BREAK(pDstMedium, RefreshState(&state));
861 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Format)(format.asOutParam()));
862 }
863 else
864 {
865 /* use the format of the source medium if unspecified */
866 if (format.isEmpty())
867 CHECK_ERROR_BREAK(pSrcMedium, COMGETTER(Format)(format.asOutParam()));
868 Utf8Str strFormat(format);
869 if (cmd == CMD_DISK)
870 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_HardDisk,
871 AccessMode_ReadWrite, pDstMedium);
872 else if (cmd == CMD_DVD)
873 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_DVD,
874 AccessMode_ReadOnly, pDstMedium);
875 else if (cmd == CMD_FLOPPY)
876 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_Floppy,
877 AccessMode_ReadWrite, pDstMedium);
878 if (FAILED(rc))
879 break;
880 }
881
882 ComPtr<IProgress> pProgress;
883 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
884
885 for (ULONG i = 0; i < l_variants.size(); ++i)
886 {
887 ULONG temp = enmMediumVariant;
888 temp &= 1<<i;
889 l_variants [i] = (MediumVariant_T)temp;
890 }
891
892 CHECK_ERROR_BREAK(pSrcMedium, CloneTo(pDstMedium, ComSafeArrayAsInParam(l_variants), NULL, pProgress.asOutParam()));
893
894 rc = showProgress(pProgress);
895 CHECK_PROGRESS_ERROR_BREAK(pProgress, ("Failed to clone medium"));
896
897 Bstr uuid;
898 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Id)(uuid.asOutParam()));
899
900 RTPrintf("Clone medium created in format '%ls'. UUID: %s\n",
901 format.raw(), Utf8Str(uuid).c_str());
902 }
903 while (0);
904
905 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
906}
907
908static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
909{
910 { "--format", 'o', RTGETOPT_REQ_STRING },
911 { "-format", 'o', RTGETOPT_REQ_STRING },
912 { "--static", 'F', RTGETOPT_REQ_NOTHING },
913 { "-static", 'F', RTGETOPT_REQ_NOTHING },
914 { "--variant", 'm', RTGETOPT_REQ_STRING },
915 { "-variant", 'm', RTGETOPT_REQ_STRING },
916 { "--uuid", 'u', RTGETOPT_REQ_STRING },
917};
918
919RTEXITCODE handleConvertFromRaw(HandlerArg *a)
920{
921 int rc = VINF_SUCCESS;
922 bool fReadFromStdIn = false;
923 const char *format = "VDI";
924 const char *srcfilename = NULL;
925 const char *dstfilename = NULL;
926 const char *filesize = NULL;
927 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
928 void *pvBuf = NULL;
929 RTUUID uuid;
930 PCRTUUID pUuid = NULL;
931
932 int c;
933 RTGETOPTUNION ValueUnion;
934 RTGETOPTSTATE GetState;
935 // start at 0 because main() has hacked both the argc and argv given to us
936 RTGetOptInit(&GetState, a->argc, a->argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
937 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
938 while ((c = RTGetOpt(&GetState, &ValueUnion)))
939 {
940 switch (c)
941 {
942 case 'u': // --uuid
943 if (RT_FAILURE(RTUuidFromStr(&uuid, ValueUnion.psz)))
944 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid UUID '%s'", ValueUnion.psz);
945 pUuid = &uuid;
946 break;
947 case 'o': // --format
948 format = ValueUnion.psz;
949 break;
950
951 case 'm': // --variant
952 {
953 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
954 rc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
955 if (RT_FAILURE(rc))
956 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
957 /// @todo cleaner solution than assuming 1:1 mapping?
958 uImageFlags = (unsigned)enmMediumVariant;
959 break;
960 }
961 case VINF_GETOPT_NOT_OPTION:
962 if (!srcfilename)
963 {
964 srcfilename = ValueUnion.psz;
965 fReadFromStdIn = !strcmp(srcfilename, "stdin");
966 }
967 else if (!dstfilename)
968 dstfilename = ValueUnion.psz;
969 else if (fReadFromStdIn && !filesize)
970 filesize = ValueUnion.psz;
971 else
972 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
973 break;
974
975 default:
976 return errorGetOpt(USAGE_CONVERTFROMRAW, c, &ValueUnion);
977 }
978 }
979
980 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
981 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
982 RTStrmPrintf(g_pStdErr, "Converting from raw image file=\"%s\" to file=\"%s\"...\n",
983 srcfilename, dstfilename);
984
985 PVBOXHDD pDisk = NULL;
986
987 PVDINTERFACE pVDIfs = NULL;
988 VDINTERFACEERROR vdInterfaceError;
989 vdInterfaceError.pfnError = handleVDError;
990 vdInterfaceError.pfnMessage = NULL;
991
992 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
993 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
994 AssertRC(rc);
995
996 /* open raw image file. */
997 RTFILE File;
998 if (fReadFromStdIn)
999 rc = RTFileFromNative(&File, RTFILE_NATIVE_STDIN);
1000 else
1001 rc = RTFileOpen(&File, srcfilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1002 if (RT_FAILURE(rc))
1003 {
1004 RTMsgError("Cannot open file \"%s\": %Rrc", srcfilename, rc);
1005 goto out;
1006 }
1007
1008 uint64_t cbFile;
1009 /* get image size. */
1010 if (fReadFromStdIn)
1011 cbFile = RTStrToUInt64(filesize);
1012 else
1013 rc = RTFileGetSize(File, &cbFile);
1014 if (RT_FAILURE(rc))
1015 {
1016 RTMsgError("Cannot get image size for file \"%s\": %Rrc", srcfilename, rc);
1017 goto out;
1018 }
1019
1020 RTStrmPrintf(g_pStdErr, "Creating %s image with size %RU64 bytes (%RU64MB)...\n",
1021 (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
1022 char pszComment[256];
1023 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
1024 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1025 if (RT_FAILURE(rc))
1026 {
1027 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
1028 goto out;
1029 }
1030
1031 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
1032 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
1033 VDGEOMETRY PCHS, LCHS;
1034 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
1035 PCHS.cHeads = 16;
1036 PCHS.cSectors = 63;
1037 LCHS.cCylinders = 0;
1038 LCHS.cHeads = 0;
1039 LCHS.cSectors = 0;
1040 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
1041 uImageFlags, pszComment, &PCHS, &LCHS, pUuid,
1042 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1043 if (RT_FAILURE(rc))
1044 {
1045 RTMsgError("Cannot create the disk image \"%s\": %Rrc", dstfilename, rc);
1046 goto out;
1047 }
1048
1049 size_t cbBuffer;
1050 cbBuffer = _1M;
1051 pvBuf = RTMemAlloc(cbBuffer);
1052 if (!pvBuf)
1053 {
1054 rc = VERR_NO_MEMORY;
1055 RTMsgError("Out of memory allocating buffers for image \"%s\": %Rrc", dstfilename, rc);
1056 goto out;
1057 }
1058
1059 uint64_t offFile;
1060 offFile = 0;
1061 while (offFile < cbFile)
1062 {
1063 size_t cbRead;
1064 size_t cbToRead;
1065 cbRead = 0;
1066 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
1067 cbBuffer : (size_t)(cbFile - offFile);
1068 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
1069 if (RT_FAILURE(rc) || !cbRead)
1070 break;
1071 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
1072 if (RT_FAILURE(rc))
1073 {
1074 RTMsgError("Failed to write to disk image \"%s\": %Rrc", dstfilename, rc);
1075 goto out;
1076 }
1077 offFile += cbRead;
1078 }
1079
1080out:
1081 if (pvBuf)
1082 RTMemFree(pvBuf);
1083 if (pDisk)
1084 VDClose(pDisk, RT_FAILURE(rc));
1085 if (File != NIL_RTFILE)
1086 RTFileClose(File);
1087
1088 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1089}
1090
1091HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
1092 const ComPtr<IMedium> &pMedium,
1093 const char *pszParentUUID,
1094 bool fOptLong)
1095{
1096 HRESULT rc = S_OK;
1097 do
1098 {
1099 Bstr uuid;
1100 pMedium->COMGETTER(Id)(uuid.asOutParam());
1101 RTPrintf("UUID: %ls\n", uuid.raw());
1102 if (pszParentUUID)
1103 RTPrintf("Parent UUID: %s\n", pszParentUUID);
1104
1105 /* check for accessibility */
1106 MediumState_T enmState;
1107 CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
1108 pMedium->RefreshState(&enmState);
1109 const char *pszState = "unknown";
1110 switch (enmState)
1111 {
1112 case MediumState_NotCreated:
1113 pszState = "not created";
1114 break;
1115 case MediumState_Created:
1116 pszState = "created";
1117 break;
1118 case MediumState_LockedRead:
1119 pszState = "locked read";
1120 break;
1121 case MediumState_LockedWrite:
1122 pszState = "locked write";
1123 break;
1124 case MediumState_Inaccessible:
1125 pszState = "inaccessible";
1126 break;
1127 case MediumState_Creating:
1128 pszState = "creating";
1129 break;
1130 case MediumState_Deleting:
1131 pszState = "deleting";
1132 break;
1133 }
1134 RTPrintf("State: %s\n", pszState);
1135
1136 if (fOptLong && enmState == MediumState_Inaccessible)
1137 {
1138 Bstr err;
1139 CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
1140 RTPrintf("Access Error: %ls\n", err.raw());
1141 }
1142
1143 if (fOptLong)
1144 {
1145 Bstr description;
1146 pMedium->COMGETTER(Description)(description.asOutParam());
1147 if (!description.isEmpty())
1148 RTPrintf("Description: %ls\n", description.raw());
1149 }
1150
1151 MediumType_T type;
1152 pMedium->COMGETTER(Type)(&type);
1153 const char *typeStr = "unknown";
1154 switch (type)
1155 {
1156 case MediumType_Normal:
1157 if (pszParentUUID && Guid(pszParentUUID).isValid())
1158 typeStr = "normal (differencing)";
1159 else
1160 typeStr = "normal (base)";
1161 break;
1162 case MediumType_Immutable:
1163 typeStr = "immutable";
1164 break;
1165 case MediumType_Writethrough:
1166 typeStr = "writethrough";
1167 break;
1168 case MediumType_Shareable:
1169 typeStr = "shareable";
1170 break;
1171 case MediumType_Readonly:
1172 typeStr = "readonly";
1173 break;
1174 case MediumType_MultiAttach:
1175 typeStr = "multiattach";
1176 break;
1177 }
1178 RTPrintf("Type: %s\n", typeStr);
1179
1180 /* print out information specific for differencing media */
1181 if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
1182 {
1183 BOOL autoReset = FALSE;
1184 pMedium->COMGETTER(AutoReset)(&autoReset);
1185 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1186 }
1187
1188 Bstr loc;
1189 pMedium->COMGETTER(Location)(loc.asOutParam());
1190 RTPrintf("Location: %ls\n", loc.raw());
1191
1192 Bstr format;
1193 pMedium->COMGETTER(Format)(format.asOutParam());
1194 RTPrintf("Storage format: %ls\n", format.raw());
1195
1196 if (fOptLong)
1197 {
1198 com::SafeArray<MediumVariant_T> safeArray_variant;
1199
1200 pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
1201 ULONG variant=0;
1202 for (size_t i = 0; i < safeArray_variant.size(); i++)
1203 variant |= safeArray_variant[i];
1204
1205 const char *variantStr = "unknown";
1206 switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
1207 {
1208 case MediumVariant_VmdkSplit2G:
1209 variantStr = "split2G";
1210 break;
1211 case MediumVariant_VmdkStreamOptimized:
1212 variantStr = "streamOptimized";
1213 break;
1214 case MediumVariant_VmdkESX:
1215 variantStr = "ESX";
1216 break;
1217 case MediumVariant_Standard:
1218 variantStr = "default";
1219 break;
1220 }
1221 const char *variantTypeStr = "dynamic";
1222 if (variant & MediumVariant_Fixed)
1223 variantTypeStr = "fixed";
1224 else if (variant & MediumVariant_Diff)
1225 variantTypeStr = "differencing";
1226 RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
1227 }
1228
1229 LONG64 logicalSize;
1230 pMedium->COMGETTER(LogicalSize)(&logicalSize);
1231 RTPrintf("Capacity: %lld MBytes\n", logicalSize >> 20);
1232 if (fOptLong)
1233 {
1234 LONG64 actualSize;
1235 pMedium->COMGETTER(Size)(&actualSize);
1236 RTPrintf("Size on disk: %lld MBytes\n", actualSize >> 20);
1237 }
1238
1239 Bstr strCipher;
1240 Bstr strPasswordId;
1241 HRESULT rc2 = pMedium->GetEncryptionSettings(strCipher.asOutParam(), strPasswordId.asOutParam());
1242 if (SUCCEEDED(rc2))
1243 {
1244 RTPrintf("Encryption: enabled\n");
1245 if (fOptLong)
1246 {
1247 RTPrintf("Cipher: %ls\n", strCipher.raw());
1248 RTPrintf("Password ID: %ls\n", strPasswordId.raw());
1249 }
1250 }
1251 else
1252 RTPrintf("Encryption: disabled\n");
1253
1254 if (fOptLong)
1255 {
1256 com::SafeArray<BSTR> names;
1257 com::SafeArray<BSTR> values;
1258 pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
1259 size_t cNames = names.size();
1260 size_t cValues = values.size();
1261 bool fFirst = true;
1262 for (size_t i = 0; i < cNames; i++)
1263 {
1264 Bstr value;
1265 if (i < cValues)
1266 value = values[i];
1267 RTPrintf("%s%ls=%ls\n",
1268 fFirst ? "Property: " : " ",
1269 names[i], value.raw());
1270 }
1271 }
1272
1273 if (fOptLong)
1274 {
1275 bool fFirst = true;
1276 com::SafeArray<BSTR> machineIds;
1277 pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1278 for (size_t i = 0; i < machineIds.size(); i++)
1279 {
1280 ComPtr<IMachine> pMachine;
1281 CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], pMachine.asOutParam()));
1282 if (pMachine)
1283 {
1284 Bstr name;
1285 pMachine->COMGETTER(Name)(name.asOutParam());
1286 pMachine->COMGETTER(Id)(uuid.asOutParam());
1287 RTPrintf("%s%ls (UUID: %ls)",
1288 fFirst ? "In use by VMs: " : " ",
1289 name.raw(), machineIds[i]);
1290 fFirst = false;
1291 com::SafeArray<BSTR> snapshotIds;
1292 pMedium->GetSnapshotIds(machineIds[i],
1293 ComSafeArrayAsOutParam(snapshotIds));
1294 for (size_t j = 0; j < snapshotIds.size(); j++)
1295 {
1296 ComPtr<ISnapshot> pSnapshot;
1297 pMachine->FindSnapshot(snapshotIds[j], pSnapshot.asOutParam());
1298 if (pSnapshot)
1299 {
1300 Bstr snapshotName;
1301 pSnapshot->COMGETTER(Name)(snapshotName.asOutParam());
1302 RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
1303 }
1304 }
1305 RTPrintf("\n");
1306 }
1307 }
1308 }
1309
1310 if (fOptLong)
1311 {
1312 com::SafeIfaceArray<IMedium> children;
1313 pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
1314 bool fFirst = true;
1315 for (size_t i = 0; i < children.size(); i++)
1316 {
1317 ComPtr<IMedium> pChild(children[i]);
1318 if (pChild)
1319 {
1320 Bstr childUUID;
1321 pChild->COMGETTER(Id)(childUUID.asOutParam());
1322 RTPrintf("%s%ls\n",
1323 fFirst ? "Child UUIDs: " : " ",
1324 childUUID.raw());
1325 fFirst = false;
1326 }
1327 }
1328 }
1329 }
1330 while (0);
1331
1332 return rc;
1333}
1334
1335static const RTGETOPTDEF g_aShowMediumInfoOptions[] =
1336{
1337 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1338 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1339 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1340};
1341
1342RTEXITCODE handleShowMediumInfo(HandlerArg *a)
1343{
1344 HRESULT rc;
1345 enum {
1346 CMD_NONE,
1347 CMD_DISK,
1348 CMD_DVD,
1349 CMD_FLOPPY
1350 } cmd = CMD_NONE;
1351 const char *pszFilenameOrUuid = NULL;
1352
1353 int c;
1354 RTGETOPTUNION ValueUnion;
1355 RTGETOPTSTATE GetState;
1356 // start at 0 because main() has hacked both the argc and argv given to us
1357 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowMediumInfoOptions, RT_ELEMENTS(g_aShowMediumInfoOptions),
1358 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1359 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1360 {
1361 switch (c)
1362 {
1363 case 'd': // disk
1364 if (cmd != CMD_NONE)
1365 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1366 cmd = CMD_DISK;
1367 break;
1368
1369 case 'D': // DVD
1370 if (cmd != CMD_NONE)
1371 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1372 cmd = CMD_DVD;
1373 break;
1374
1375 case 'f': // floppy
1376 if (cmd != CMD_NONE)
1377 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1378 cmd = CMD_FLOPPY;
1379 break;
1380
1381 case VINF_GETOPT_NOT_OPTION:
1382 if (!pszFilenameOrUuid)
1383 pszFilenameOrUuid = ValueUnion.psz;
1384 else
1385 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid parameter '%s'", ValueUnion.psz);
1386 break;
1387
1388 default:
1389 if (c > 0)
1390 {
1391 if (RT_C_IS_PRINT(c))
1392 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option -%c", c);
1393 else
1394 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option case %i", c);
1395 }
1396 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1397 return errorSyntax(USAGE_SHOWMEDIUMINFO, "unknown option: %s\n", ValueUnion.psz);
1398 else if (ValueUnion.pDef)
1399 return errorSyntax(USAGE_SHOWMEDIUMINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1400 else
1401 return errorSyntax(USAGE_SHOWMEDIUMINFO, "error: %Rrs", c);
1402 }
1403 }
1404
1405 if (cmd == CMD_NONE)
1406 cmd = CMD_DISK;
1407
1408 /* check for required options */
1409 if (!pszFilenameOrUuid)
1410 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Medium name or UUID required");
1411
1412 ComPtr<IMedium> pMedium;
1413 if (cmd == CMD_DISK)
1414 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1415 AccessMode_ReadOnly, pMedium,
1416 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1417 else if (cmd == CMD_DVD)
1418 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1419 AccessMode_ReadOnly, pMedium,
1420 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1421 else if (cmd == CMD_FLOPPY)
1422 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1423 AccessMode_ReadOnly, pMedium,
1424 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1425 if (FAILED(rc))
1426 return RTEXITCODE_FAILURE;
1427
1428 Utf8Str strParentUUID("base");
1429 ComPtr<IMedium> pParent;
1430 pMedium->COMGETTER(Parent)(pParent.asOutParam());
1431 if (!pParent.isNull())
1432 {
1433 Bstr bstrParentUUID;
1434 pParent->COMGETTER(Id)(bstrParentUUID.asOutParam());
1435 strParentUUID = bstrParentUUID;
1436 }
1437
1438 rc = showMediumInfo(a->virtualBox, pMedium, strParentUUID.c_str(), true);
1439
1440 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1441}
1442
1443static const RTGETOPTDEF g_aCloseMediumOptions[] =
1444{
1445 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1446 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1447 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1448 { "--delete", 'r', RTGETOPT_REQ_NOTHING },
1449};
1450
1451RTEXITCODE handleCloseMedium(HandlerArg *a)
1452{
1453 HRESULT rc = S_OK;
1454 enum {
1455 CMD_NONE,
1456 CMD_DISK,
1457 CMD_DVD,
1458 CMD_FLOPPY
1459 } cmd = CMD_NONE;
1460 const char *pszFilenameOrUuid = NULL;
1461 bool fDelete = false;
1462
1463 int c;
1464 RTGETOPTUNION ValueUnion;
1465 RTGETOPTSTATE GetState;
1466 // start at 0 because main() has hacked both the argc and argv given to us
1467 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
1468 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1469 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1470 {
1471 switch (c)
1472 {
1473 case 'd': // disk
1474 if (cmd != CMD_NONE)
1475 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1476 cmd = CMD_DISK;
1477 break;
1478
1479 case 'D': // DVD
1480 if (cmd != CMD_NONE)
1481 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1482 cmd = CMD_DVD;
1483 break;
1484
1485 case 'f': // floppy
1486 if (cmd != CMD_NONE)
1487 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1488 cmd = CMD_FLOPPY;
1489 break;
1490
1491 case 'r': // --delete
1492 fDelete = true;
1493 break;
1494
1495 case VINF_GETOPT_NOT_OPTION:
1496 if (!pszFilenameOrUuid)
1497 pszFilenameOrUuid = ValueUnion.psz;
1498 else
1499 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1500 break;
1501
1502 default:
1503 if (c > 0)
1504 {
1505 if (RT_C_IS_PRINT(c))
1506 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option -%c", c);
1507 else
1508 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option case %i", c);
1509 }
1510 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1511 return errorSyntax(USAGE_CLOSEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1512 else if (ValueUnion.pDef)
1513 return errorSyntax(USAGE_CLOSEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1514 else
1515 return errorSyntax(USAGE_CLOSEMEDIUM, "error: %Rrs", c);
1516 }
1517 }
1518
1519 /* check for required options */
1520 if (cmd == CMD_NONE)
1521 cmd = CMD_DISK;
1522 if (!pszFilenameOrUuid)
1523 return errorSyntax(USAGE_CLOSEMEDIUM, "Medium name or UUID required");
1524
1525 ComPtr<IMedium> pMedium;
1526 if (cmd == CMD_DISK)
1527 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1528 AccessMode_ReadWrite, pMedium,
1529 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1530 else if (cmd == CMD_DVD)
1531 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1532 AccessMode_ReadOnly, pMedium,
1533 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1534 else if (cmd == CMD_FLOPPY)
1535 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1536 AccessMode_ReadWrite, pMedium,
1537 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1538
1539 if (SUCCEEDED(rc) && pMedium)
1540 {
1541 if (fDelete)
1542 {
1543 ComPtr<IProgress> pProgress;
1544 CHECK_ERROR(pMedium, DeleteStorage(pProgress.asOutParam()));
1545 if (SUCCEEDED(rc))
1546 {
1547 rc = showProgress(pProgress);
1548 CHECK_PROGRESS_ERROR(pProgress, ("Failed to delete medium"));
1549 }
1550 else
1551 RTMsgError("Failed to delete medium. Error code %Rrc", rc);
1552 }
1553 CHECK_ERROR(pMedium, Close());
1554 }
1555
1556 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1557}
1558
1559RTEXITCODE handleMediumProperty(HandlerArg *a)
1560{
1561 HRESULT rc = S_OK;
1562 const char *pszCmd = NULL;
1563 enum {
1564 CMD_NONE,
1565 CMD_DISK,
1566 CMD_DVD,
1567 CMD_FLOPPY
1568 } cmd = CMD_NONE;
1569 const char *pszAction = NULL;
1570 const char *pszFilenameOrUuid = NULL;
1571 const char *pszProperty = NULL;
1572 ComPtr<IMedium> pMedium;
1573
1574 pszCmd = (a->argc > 0) ? a->argv[0] : "";
1575 if ( !RTStrICmp(pszCmd, "disk")
1576 || !RTStrICmp(pszCmd, "dvd")
1577 || !RTStrICmp(pszCmd, "floppy"))
1578 {
1579 if (!RTStrICmp(pszCmd, "disk"))
1580 cmd = CMD_DISK;
1581 else if (!RTStrICmp(pszCmd, "dvd"))
1582 cmd = CMD_DVD;
1583 else if (!RTStrICmp(pszCmd, "floppy"))
1584 cmd = CMD_FLOPPY;
1585 else
1586 {
1587 AssertMsgFailed(("unexpected parameter %s\n", pszCmd));
1588 cmd = CMD_DISK;
1589 }
1590 a->argv++;
1591 a->argc--;
1592 }
1593 else
1594 {
1595 pszCmd = NULL;
1596 cmd = CMD_DISK;
1597 }
1598
1599 if (a->argc == 0)
1600 return errorSyntax(USAGE_MEDIUMPROPERTY, "Missing action");
1601
1602 pszAction = a->argv[0];
1603 if ( RTStrICmp(pszAction, "set")
1604 && RTStrICmp(pszAction, "get")
1605 && RTStrICmp(pszAction, "delete"))
1606 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid action given: %s", pszAction);
1607
1608 if ( ( !RTStrICmp(pszAction, "set")
1609 && a->argc != 4)
1610 || ( RTStrICmp(pszAction, "set")
1611 && a->argc != 3))
1612 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid number of arguments given for action: %s", pszAction);
1613
1614 pszFilenameOrUuid = a->argv[1];
1615 pszProperty = a->argv[2];
1616
1617 if (cmd == CMD_DISK)
1618 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1619 AccessMode_ReadWrite, pMedium,
1620 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1621 else if (cmd == CMD_DVD)
1622 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1623 AccessMode_ReadOnly, pMedium,
1624 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1625 else if (cmd == CMD_FLOPPY)
1626 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1627 AccessMode_ReadWrite, pMedium,
1628 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1629 if (SUCCEEDED(rc) && !pMedium.isNull())
1630 {
1631 if (!RTStrICmp(pszAction, "set"))
1632 {
1633 const char *pszValue = a->argv[3];
1634 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr(pszValue).raw()));
1635 }
1636 else if (!RTStrICmp(pszAction, "get"))
1637 {
1638 Bstr strVal;
1639 CHECK_ERROR(pMedium, GetProperty(Bstr(pszProperty).raw(), strVal.asOutParam()));
1640 if (SUCCEEDED(rc))
1641 RTPrintf("%s=%ls\n", pszProperty, strVal.raw());
1642 }
1643 else if (!RTStrICmp(pszAction, "delete"))
1644 {
1645 const char *pszValue = a->argv[3];
1646 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr().raw()));
1647 /** @todo */
1648 }
1649 }
1650
1651 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1652}
1653
1654static const RTGETOPTDEF g_aEncryptMediumOptions[] =
1655{
1656 { "--newpassword", 'n', RTGETOPT_REQ_STRING },
1657 { "--oldpassword", 'o', RTGETOPT_REQ_STRING },
1658 { "--cipher", 'c', RTGETOPT_REQ_STRING },
1659 { "--newpasswordid", 'i', RTGETOPT_REQ_STRING }
1660};
1661
1662RTEXITCODE handleEncryptMedium(HandlerArg *a)
1663{
1664 HRESULT rc;
1665 ComPtr<IMedium> hardDisk;
1666 const char *pszPasswordNew = NULL;
1667 const char *pszPasswordOld = NULL;
1668 const char *pszCipher = NULL;
1669 const char *pszFilenameOrUuid = NULL;
1670 const char *pszNewPasswordId = NULL;
1671 Utf8Str strPasswordNew;
1672 Utf8Str strPasswordOld;
1673
1674 int c;
1675 RTGETOPTUNION ValueUnion;
1676 RTGETOPTSTATE GetState;
1677 // start at 0 because main() has hacked both the argc and argv given to us
1678 RTGetOptInit(&GetState, a->argc, a->argv, g_aEncryptMediumOptions, RT_ELEMENTS(g_aEncryptMediumOptions),
1679 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1680 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1681 {
1682 switch (c)
1683 {
1684 case 'n': // --newpassword
1685 pszPasswordNew = ValueUnion.psz;
1686 break;
1687
1688 case 'o': // --oldpassword
1689 pszPasswordOld = ValueUnion.psz;
1690 break;
1691
1692 case 'c': // --cipher
1693 pszCipher = ValueUnion.psz;
1694 break;
1695
1696 case 'i': // --newpasswordid
1697 pszNewPasswordId = ValueUnion.psz;
1698 break;
1699
1700 case VINF_GETOPT_NOT_OPTION:
1701 if (!pszFilenameOrUuid)
1702 pszFilenameOrUuid = ValueUnion.psz;
1703 else
1704 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1705 break;
1706
1707 default:
1708 if (c > 0)
1709 {
1710 if (RT_C_IS_PRINT(c))
1711 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option -%c", c);
1712 else
1713 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option case %i", c);
1714 }
1715 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1716 return errorSyntax(USAGE_ENCRYPTMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1717 else if (ValueUnion.pDef)
1718 return errorSyntax(USAGE_ENCRYPTMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1719 else
1720 return errorSyntax(USAGE_ENCRYPTMEDIUM, "error: %Rrs", c);
1721 }
1722 }
1723
1724 if (!pszFilenameOrUuid)
1725 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Disk name or UUID required");
1726
1727 if (!pszPasswordNew && !pszPasswordOld)
1728 return errorSyntax(USAGE_ENCRYPTMEDIUM, "No password specified");
1729
1730 if ( (pszPasswordNew && !pszNewPasswordId)
1731 || (!pszPasswordNew && pszNewPasswordId))
1732 return errorSyntax(USAGE_ENCRYPTMEDIUM, "A new password must always have a valid identifier set at the same time");
1733
1734 if (pszPasswordNew)
1735 {
1736 if (!RTStrCmp(pszPasswordNew, "-"))
1737 {
1738 /* Get password from console. */
1739 RTEXITCODE rcExit = readPasswordFromConsole(&strPasswordNew, "Enter new password:");
1740 if (rcExit == RTEXITCODE_FAILURE)
1741 return rcExit;
1742 }
1743 else
1744 {
1745 RTEXITCODE rcExit = readPasswordFile(pszPasswordNew, &strPasswordNew);
1746 if (rcExit == RTEXITCODE_FAILURE)
1747 {
1748 RTMsgError("Failed to read new password from file");
1749 return rcExit;
1750 }
1751 }
1752 }
1753
1754 if (pszPasswordOld)
1755 {
1756 if (!RTStrCmp(pszPasswordOld, "-"))
1757 {
1758 /* Get password from console. */
1759 RTEXITCODE rcExit = readPasswordFromConsole(&strPasswordOld, "Enter old password:");
1760 if (rcExit == RTEXITCODE_FAILURE)
1761 return rcExit;
1762 }
1763 else
1764 {
1765 RTEXITCODE rcExit = readPasswordFile(pszPasswordOld, &strPasswordOld);
1766 if (rcExit == RTEXITCODE_FAILURE)
1767 {
1768 RTMsgError("Failed to read old password from file");
1769 return rcExit;
1770 }
1771 }
1772 }
1773
1774 /* Always open the medium if necessary, there is no other way. */
1775 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1776 AccessMode_ReadWrite, hardDisk,
1777 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1778 if (FAILED(rc))
1779 return RTEXITCODE_FAILURE;
1780 if (hardDisk.isNull())
1781 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid hard disk reference, avoiding crash");
1782
1783 ComPtr<IProgress> progress;
1784 CHECK_ERROR(hardDisk, ChangeEncryption(Bstr(strPasswordOld).raw(), Bstr(pszCipher).raw(),
1785 Bstr(strPasswordNew).raw(), Bstr(pszNewPasswordId).raw(),
1786 progress.asOutParam()));
1787 if (SUCCEEDED(rc))
1788 rc = showProgress(progress);
1789 if (FAILED(rc))
1790 {
1791 if (rc == E_NOTIMPL)
1792 RTMsgError("Encrypt hard disk operation is not implemented!");
1793 else if (rc == VBOX_E_NOT_SUPPORTED)
1794 RTMsgError("Encrypt hard disk operation for this cipher is not implemented yet!");
1795 else if (!progress.isNull())
1796 CHECK_PROGRESS_ERROR(progress, ("Failed to encrypt hard disk"));
1797 else
1798 RTMsgError("Failed to encrypt hard disk!");
1799 }
1800
1801 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1802}
1803
1804RTEXITCODE handleCheckMediumPassword(HandlerArg *a)
1805{
1806 HRESULT rc;
1807 ComPtr<IMedium> hardDisk;
1808 const char *pszFilenameOrUuid = NULL;
1809 Utf8Str strPassword;
1810
1811 if (a->argc != 2)
1812 return errorSyntax(USAGE_MEDIUMENCCHKPWD, "Invalid number of arguments: %d", a->argc);
1813
1814 pszFilenameOrUuid = a->argv[0];
1815
1816 if (!RTStrCmp(a->argv[1], "-"))
1817 {
1818 /* Get password from console. */
1819 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
1820 if (rcExit == RTEXITCODE_FAILURE)
1821 return rcExit;
1822 }
1823 else
1824 {
1825 RTEXITCODE rcExit = readPasswordFile(a->argv[1], &strPassword);
1826 if (rcExit == RTEXITCODE_FAILURE)
1827 {
1828 RTMsgError("Failed to read password from file");
1829 return rcExit;
1830 }
1831 }
1832
1833 /* Always open the medium if necessary, there is no other way. */
1834 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1835 AccessMode_ReadWrite, hardDisk,
1836 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1837 if (FAILED(rc))
1838 return RTEXITCODE_FAILURE;
1839 if (hardDisk.isNull())
1840 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid hard disk reference, avoiding crash");
1841
1842 CHECK_ERROR(hardDisk, CheckEncryptionPassword(Bstr(strPassword).raw()));
1843 if (SUCCEEDED(rc))
1844 RTPrintf("The given password is correct\n");
1845 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1846}
1847
1848#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette