VirtualBox

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

Last change on this file since 56158 was 56118, checked in by vboxsync, 10 years ago

VBoxManage: A quick command handler return-code cleanup that turned out to be rather tedious.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.4 KB
Line 
1/* $Id: VBoxManageDisk.cpp 56118 2015-05-27 19:49:50Z 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
700 CHECK_PROGRESS_ERROR(pProgress, ("Failed to resize medium"));
701 }
702 }
703
704 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
705}
706
707static const RTGETOPTDEF g_aCloneMediumOptions[] =
708{
709 { "disk", 'd', RTGETOPT_REQ_NOTHING },
710 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
711 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
712 { "--format", 'o', RTGETOPT_REQ_STRING },
713 { "-format", 'o', RTGETOPT_REQ_STRING },
714 { "--static", 'F', RTGETOPT_REQ_NOTHING },
715 { "-static", 'F', RTGETOPT_REQ_NOTHING },
716 { "--existing", 'E', RTGETOPT_REQ_NOTHING },
717 { "--variant", 'm', RTGETOPT_REQ_STRING },
718 { "-variant", 'm', RTGETOPT_REQ_STRING },
719};
720
721RTEXITCODE handleCloneMedium(HandlerArg *a)
722{
723 HRESULT rc;
724 int vrc;
725 enum {
726 CMD_NONE,
727 CMD_DISK,
728 CMD_DVD,
729 CMD_FLOPPY
730 } cmd = CMD_NONE;
731 const char *pszSrc = NULL;
732 const char *pszDst = NULL;
733 Bstr format;
734 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
735 bool fExisting = false;
736
737 int c;
738 RTGETOPTUNION ValueUnion;
739 RTGETOPTSTATE GetState;
740 // start at 0 because main() has hacked both the argc and argv given to us
741 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneMediumOptions, RT_ELEMENTS(g_aCloneMediumOptions),
742 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
743 while ((c = RTGetOpt(&GetState, &ValueUnion)))
744 {
745 switch (c)
746 {
747 case 'd': // disk
748 if (cmd != CMD_NONE)
749 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
750 cmd = CMD_DISK;
751 break;
752
753 case 'D': // DVD
754 if (cmd != CMD_NONE)
755 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
756 cmd = CMD_DVD;
757 break;
758
759 case 'f': // floppy
760 if (cmd != CMD_NONE)
761 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
762 cmd = CMD_FLOPPY;
763 break;
764
765 case 'o': // --format
766 format = ValueUnion.psz;
767 break;
768
769 case 'F': // --static
770 {
771 unsigned uMediumVariant = (unsigned)enmMediumVariant;
772 uMediumVariant |= MediumVariant_Fixed;
773 enmMediumVariant = (MediumVariant_T)uMediumVariant;
774 break;
775 }
776
777 case 'E': // --existing
778 fExisting = true;
779 break;
780
781 case 'm': // --variant
782 vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
783 if (RT_FAILURE(vrc))
784 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
785 break;
786
787 case VINF_GETOPT_NOT_OPTION:
788 if (!pszSrc)
789 pszSrc = ValueUnion.psz;
790 else if (!pszDst)
791 pszDst = ValueUnion.psz;
792 else
793 return errorSyntax(USAGE_CLONEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
794 break;
795
796 default:
797 if (c > 0)
798 {
799 if (RT_C_IS_GRAPH(c))
800 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: -%c", c);
801 else
802 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: %i", c);
803 }
804 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
805 return errorSyntax(USAGE_CLONEMEDIUM, "unknown option: %s", ValueUnion.psz);
806 else if (ValueUnion.pDef)
807 return errorSyntax(USAGE_CLONEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
808 else
809 return errorSyntax(USAGE_CLONEMEDIUM, "error: %Rrs", c);
810 }
811 }
812
813 if (cmd == CMD_NONE)
814 cmd = CMD_DISK;
815 if (!pszSrc)
816 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory UUID or input file parameter missing");
817 if (!pszDst)
818 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory output file parameter missing");
819 if (fExisting && (!format.isEmpty() || enmMediumVariant != MediumType_Normal))
820 return errorSyntax(USAGE_CLONEMEDIUM, "Specified options which cannot be used with --existing");
821
822 ComPtr<IMedium> pSrcMedium;
823 ComPtr<IMedium> pDstMedium;
824
825 if (cmd == CMD_DISK)
826 rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly, pSrcMedium,
827 false /* fForceNewUuidOnOpen */, false /* fSilent */);
828 else if (cmd == CMD_DVD)
829 rc = openMedium(a, pszSrc, DeviceType_DVD, AccessMode_ReadOnly, pSrcMedium,
830 false /* fForceNewUuidOnOpen */, false /* fSilent */);
831 else if (cmd == CMD_FLOPPY)
832 rc = openMedium(a, pszSrc, DeviceType_Floppy, AccessMode_ReadOnly, pSrcMedium,
833 false /* fForceNewUuidOnOpen */, false /* fSilent */);
834 else
835 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
836 if (FAILED(rc))
837 return RTEXITCODE_FAILURE;
838
839 do
840 {
841 /* open/create destination medium */
842 if (fExisting)
843 {
844 if (cmd == CMD_DISK)
845 rc = openMedium(a, pszDst, DeviceType_HardDisk, AccessMode_ReadWrite, pDstMedium,
846 false /* fForceNewUuidOnOpen */, false /* fSilent */);
847 else if (cmd == CMD_DVD)
848 rc = openMedium(a, pszDst, DeviceType_DVD, AccessMode_ReadOnly, pDstMedium,
849 false /* fForceNewUuidOnOpen */, false /* fSilent */);
850 else if (cmd == CMD_FLOPPY)
851 rc = openMedium(a, pszDst, DeviceType_Floppy, AccessMode_ReadWrite, pDstMedium,
852 false /* fForceNewUuidOnOpen */, false /* fSilent */);
853 if (FAILED(rc))
854 break;
855
856 /* Perform accessibility check now. */
857 MediumState_T state;
858 CHECK_ERROR_BREAK(pDstMedium, RefreshState(&state));
859 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Format)(format.asOutParam()));
860 }
861 else
862 {
863 /* use the format of the source medium if unspecified */
864 if (format.isEmpty())
865 CHECK_ERROR_BREAK(pSrcMedium, COMGETTER(Format)(format.asOutParam()));
866 Utf8Str strFormat(format);
867 if (cmd == CMD_DISK)
868 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_HardDisk,
869 AccessMode_ReadWrite, pDstMedium);
870 else if (cmd == CMD_DVD)
871 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_DVD,
872 AccessMode_ReadOnly, pDstMedium);
873 else if (cmd == CMD_FLOPPY)
874 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_Floppy,
875 AccessMode_ReadWrite, pDstMedium);
876 if (FAILED(rc))
877 break;
878 }
879
880 ComPtr<IProgress> pProgress;
881 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
882
883 for (ULONG i = 0; i < l_variants.size(); ++i)
884 {
885 ULONG temp = enmMediumVariant;
886 temp &= 1<<i;
887 l_variants [i] = (MediumVariant_T)temp;
888 }
889
890 CHECK_ERROR_BREAK(pSrcMedium, CloneTo(pDstMedium, ComSafeArrayAsInParam(l_variants), NULL, pProgress.asOutParam()));
891
892 rc = showProgress(pProgress);
893 CHECK_PROGRESS_ERROR_BREAK(pProgress, ("Failed to clone medium"));
894
895 Bstr uuid;
896 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Id)(uuid.asOutParam()));
897
898 RTPrintf("Clone medium created in format '%ls'. UUID: %s\n",
899 format.raw(), Utf8Str(uuid).c_str());
900 }
901 while (0);
902
903 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
904}
905
906static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
907{
908 { "--format", 'o', RTGETOPT_REQ_STRING },
909 { "-format", 'o', RTGETOPT_REQ_STRING },
910 { "--static", 'F', RTGETOPT_REQ_NOTHING },
911 { "-static", 'F', RTGETOPT_REQ_NOTHING },
912 { "--variant", 'm', RTGETOPT_REQ_STRING },
913 { "-variant", 'm', RTGETOPT_REQ_STRING },
914 { "--uuid", 'u', RTGETOPT_REQ_STRING },
915};
916
917RTEXITCODE handleConvertFromRaw(HandlerArg *a)
918{
919 int rc = VINF_SUCCESS;
920 bool fReadFromStdIn = false;
921 const char *format = "VDI";
922 const char *srcfilename = NULL;
923 const char *dstfilename = NULL;
924 const char *filesize = NULL;
925 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
926 void *pvBuf = NULL;
927 RTUUID uuid;
928 PCRTUUID pUuid = NULL;
929
930 int c;
931 RTGETOPTUNION ValueUnion;
932 RTGETOPTSTATE GetState;
933 // start at 0 because main() has hacked both the argc and argv given to us
934 RTGetOptInit(&GetState, a->argc, a->argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
935 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
936 while ((c = RTGetOpt(&GetState, &ValueUnion)))
937 {
938 switch (c)
939 {
940 case 'u': // --uuid
941 if (RT_FAILURE(RTUuidFromStr(&uuid, ValueUnion.psz)))
942 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid UUID '%s'", ValueUnion.psz);
943 pUuid = &uuid;
944 break;
945 case 'o': // --format
946 format = ValueUnion.psz;
947 break;
948
949 case 'm': // --variant
950 {
951 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
952 rc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
953 if (RT_FAILURE(rc))
954 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
955 /// @todo cleaner solution than assuming 1:1 mapping?
956 uImageFlags = (unsigned)enmMediumVariant;
957 break;
958 }
959 case VINF_GETOPT_NOT_OPTION:
960 if (!srcfilename)
961 {
962 srcfilename = ValueUnion.psz;
963 fReadFromStdIn = !strcmp(srcfilename, "stdin");
964 }
965 else if (!dstfilename)
966 dstfilename = ValueUnion.psz;
967 else if (fReadFromStdIn && !filesize)
968 filesize = ValueUnion.psz;
969 else
970 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
971 break;
972
973 default:
974 return errorGetOpt(USAGE_CONVERTFROMRAW, c, &ValueUnion);
975 }
976 }
977
978 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
979 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
980 RTStrmPrintf(g_pStdErr, "Converting from raw image file=\"%s\" to file=\"%s\"...\n",
981 srcfilename, dstfilename);
982
983 PVBOXHDD pDisk = NULL;
984
985 PVDINTERFACE pVDIfs = NULL;
986 VDINTERFACEERROR vdInterfaceError;
987 vdInterfaceError.pfnError = handleVDError;
988 vdInterfaceError.pfnMessage = NULL;
989
990 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
991 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
992 AssertRC(rc);
993
994 /* open raw image file. */
995 RTFILE File;
996 if (fReadFromStdIn)
997 rc = RTFileFromNative(&File, RTFILE_NATIVE_STDIN);
998 else
999 rc = RTFileOpen(&File, srcfilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1000 if (RT_FAILURE(rc))
1001 {
1002 RTMsgError("Cannot open file \"%s\": %Rrc", srcfilename, rc);
1003 goto out;
1004 }
1005
1006 uint64_t cbFile;
1007 /* get image size. */
1008 if (fReadFromStdIn)
1009 cbFile = RTStrToUInt64(filesize);
1010 else
1011 rc = RTFileGetSize(File, &cbFile);
1012 if (RT_FAILURE(rc))
1013 {
1014 RTMsgError("Cannot get image size for file \"%s\": %Rrc", srcfilename, rc);
1015 goto out;
1016 }
1017
1018 RTStrmPrintf(g_pStdErr, "Creating %s image with size %RU64 bytes (%RU64MB)...\n",
1019 (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
1020 char pszComment[256];
1021 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
1022 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1023 if (RT_FAILURE(rc))
1024 {
1025 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
1026 goto out;
1027 }
1028
1029 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
1030 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
1031 VDGEOMETRY PCHS, LCHS;
1032 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
1033 PCHS.cHeads = 16;
1034 PCHS.cSectors = 63;
1035 LCHS.cCylinders = 0;
1036 LCHS.cHeads = 0;
1037 LCHS.cSectors = 0;
1038 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
1039 uImageFlags, pszComment, &PCHS, &LCHS, pUuid,
1040 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1041 if (RT_FAILURE(rc))
1042 {
1043 RTMsgError("Cannot create the disk image \"%s\": %Rrc", dstfilename, rc);
1044 goto out;
1045 }
1046
1047 size_t cbBuffer;
1048 cbBuffer = _1M;
1049 pvBuf = RTMemAlloc(cbBuffer);
1050 if (!pvBuf)
1051 {
1052 rc = VERR_NO_MEMORY;
1053 RTMsgError("Out of memory allocating buffers for image \"%s\": %Rrc", dstfilename, rc);
1054 goto out;
1055 }
1056
1057 uint64_t offFile;
1058 offFile = 0;
1059 while (offFile < cbFile)
1060 {
1061 size_t cbRead;
1062 size_t cbToRead;
1063 cbRead = 0;
1064 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
1065 cbBuffer : (size_t)(cbFile - offFile);
1066 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
1067 if (RT_FAILURE(rc) || !cbRead)
1068 break;
1069 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
1070 if (RT_FAILURE(rc))
1071 {
1072 RTMsgError("Failed to write to disk image \"%s\": %Rrc", dstfilename, rc);
1073 goto out;
1074 }
1075 offFile += cbRead;
1076 }
1077
1078out:
1079 if (pvBuf)
1080 RTMemFree(pvBuf);
1081 if (pDisk)
1082 VDClose(pDisk, RT_FAILURE(rc));
1083 if (File != NIL_RTFILE)
1084 RTFileClose(File);
1085
1086 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1087}
1088
1089HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
1090 const ComPtr<IMedium> &pMedium,
1091 const char *pszParentUUID,
1092 bool fOptLong)
1093{
1094 HRESULT rc = S_OK;
1095 do
1096 {
1097 Bstr uuid;
1098 pMedium->COMGETTER(Id)(uuid.asOutParam());
1099 RTPrintf("UUID: %ls\n", uuid.raw());
1100 if (pszParentUUID)
1101 RTPrintf("Parent UUID: %s\n", pszParentUUID);
1102
1103 /* check for accessibility */
1104 MediumState_T enmState;
1105 CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
1106 pMedium->RefreshState(&enmState);
1107 const char *pszState = "unknown";
1108 switch (enmState)
1109 {
1110 case MediumState_NotCreated:
1111 pszState = "not created";
1112 break;
1113 case MediumState_Created:
1114 pszState = "created";
1115 break;
1116 case MediumState_LockedRead:
1117 pszState = "locked read";
1118 break;
1119 case MediumState_LockedWrite:
1120 pszState = "locked write";
1121 break;
1122 case MediumState_Inaccessible:
1123 pszState = "inaccessible";
1124 break;
1125 case MediumState_Creating:
1126 pszState = "creating";
1127 break;
1128 case MediumState_Deleting:
1129 pszState = "deleting";
1130 break;
1131 }
1132 RTPrintf("State: %s\n", pszState);
1133
1134 if (fOptLong && enmState == MediumState_Inaccessible)
1135 {
1136 Bstr err;
1137 CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
1138 RTPrintf("Access Error: %ls\n", err.raw());
1139 }
1140
1141 if (fOptLong)
1142 {
1143 Bstr description;
1144 pMedium->COMGETTER(Description)(description.asOutParam());
1145 if (!description.isEmpty())
1146 RTPrintf("Description: %ls\n", description.raw());
1147 }
1148
1149 MediumType_T type;
1150 pMedium->COMGETTER(Type)(&type);
1151 const char *typeStr = "unknown";
1152 switch (type)
1153 {
1154 case MediumType_Normal:
1155 if (pszParentUUID && Guid(pszParentUUID).isValid())
1156 typeStr = "normal (differencing)";
1157 else
1158 typeStr = "normal (base)";
1159 break;
1160 case MediumType_Immutable:
1161 typeStr = "immutable";
1162 break;
1163 case MediumType_Writethrough:
1164 typeStr = "writethrough";
1165 break;
1166 case MediumType_Shareable:
1167 typeStr = "shareable";
1168 break;
1169 case MediumType_Readonly:
1170 typeStr = "readonly";
1171 break;
1172 case MediumType_MultiAttach:
1173 typeStr = "multiattach";
1174 break;
1175 }
1176 RTPrintf("Type: %s\n", typeStr);
1177
1178 /* print out information specific for differencing media */
1179 if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
1180 {
1181 BOOL autoReset = FALSE;
1182 pMedium->COMGETTER(AutoReset)(&autoReset);
1183 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1184 }
1185
1186 Bstr loc;
1187 pMedium->COMGETTER(Location)(loc.asOutParam());
1188 RTPrintf("Location: %ls\n", loc.raw());
1189
1190 Bstr format;
1191 pMedium->COMGETTER(Format)(format.asOutParam());
1192 RTPrintf("Storage format: %ls\n", format.raw());
1193
1194 if (fOptLong)
1195 {
1196 com::SafeArray<MediumVariant_T> safeArray_variant;
1197
1198 pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
1199 ULONG variant=0;
1200 for (size_t i = 0; i < safeArray_variant.size(); i++)
1201 variant |= safeArray_variant[i];
1202
1203 const char *variantStr = "unknown";
1204 switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
1205 {
1206 case MediumVariant_VmdkSplit2G:
1207 variantStr = "split2G";
1208 break;
1209 case MediumVariant_VmdkStreamOptimized:
1210 variantStr = "streamOptimized";
1211 break;
1212 case MediumVariant_VmdkESX:
1213 variantStr = "ESX";
1214 break;
1215 case MediumVariant_Standard:
1216 variantStr = "default";
1217 break;
1218 }
1219 const char *variantTypeStr = "dynamic";
1220 if (variant & MediumVariant_Fixed)
1221 variantTypeStr = "fixed";
1222 else if (variant & MediumVariant_Diff)
1223 variantTypeStr = "differencing";
1224 RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
1225 }
1226
1227 LONG64 logicalSize;
1228 pMedium->COMGETTER(LogicalSize)(&logicalSize);
1229 RTPrintf("Capacity: %lld MBytes\n", logicalSize >> 20);
1230 if (fOptLong)
1231 {
1232 LONG64 actualSize;
1233 pMedium->COMGETTER(Size)(&actualSize);
1234 RTPrintf("Size on disk: %lld MBytes\n", actualSize >> 20);
1235 }
1236
1237 Bstr strCipher;
1238 Bstr strPasswordId;
1239 HRESULT rc2 = pMedium->GetEncryptionSettings(strCipher.asOutParam(), strPasswordId.asOutParam());
1240 if (SUCCEEDED(rc2))
1241 {
1242 RTPrintf("Encryption: enabled\n");
1243 if (fOptLong)
1244 {
1245 RTPrintf("Cipher: %ls\n", strCipher.raw());
1246 RTPrintf("Password ID: %ls\n", strPasswordId.raw());
1247 }
1248 }
1249 else
1250 RTPrintf("Encryption: disabled\n");
1251
1252 if (fOptLong)
1253 {
1254 com::SafeArray<BSTR> names;
1255 com::SafeArray<BSTR> values;
1256 pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
1257 size_t cNames = names.size();
1258 size_t cValues = values.size();
1259 bool fFirst = true;
1260 for (size_t i = 0; i < cNames; i++)
1261 {
1262 Bstr value;
1263 if (i < cValues)
1264 value = values[i];
1265 RTPrintf("%s%ls=%ls\n",
1266 fFirst ? "Property: " : " ",
1267 names[i], value.raw());
1268 }
1269 }
1270
1271 if (fOptLong)
1272 {
1273 bool fFirst = true;
1274 com::SafeArray<BSTR> machineIds;
1275 pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1276 for (size_t i = 0; i < machineIds.size(); i++)
1277 {
1278 ComPtr<IMachine> pMachine;
1279 CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], pMachine.asOutParam()));
1280 if (pMachine)
1281 {
1282 Bstr name;
1283 pMachine->COMGETTER(Name)(name.asOutParam());
1284 pMachine->COMGETTER(Id)(uuid.asOutParam());
1285 RTPrintf("%s%ls (UUID: %ls)",
1286 fFirst ? "In use by VMs: " : " ",
1287 name.raw(), machineIds[i]);
1288 fFirst = false;
1289 com::SafeArray<BSTR> snapshotIds;
1290 pMedium->GetSnapshotIds(machineIds[i],
1291 ComSafeArrayAsOutParam(snapshotIds));
1292 for (size_t j = 0; j < snapshotIds.size(); j++)
1293 {
1294 ComPtr<ISnapshot> pSnapshot;
1295 pMachine->FindSnapshot(snapshotIds[j], pSnapshot.asOutParam());
1296 if (pSnapshot)
1297 {
1298 Bstr snapshotName;
1299 pSnapshot->COMGETTER(Name)(snapshotName.asOutParam());
1300 RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
1301 }
1302 }
1303 RTPrintf("\n");
1304 }
1305 }
1306 }
1307
1308 if (fOptLong)
1309 {
1310 com::SafeIfaceArray<IMedium> children;
1311 pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
1312 bool fFirst = true;
1313 for (size_t i = 0; i < children.size(); i++)
1314 {
1315 ComPtr<IMedium> pChild(children[i]);
1316 if (pChild)
1317 {
1318 Bstr childUUID;
1319 pChild->COMGETTER(Id)(childUUID.asOutParam());
1320 RTPrintf("%s%ls\n",
1321 fFirst ? "Child UUIDs: " : " ",
1322 childUUID.raw());
1323 fFirst = false;
1324 }
1325 }
1326 }
1327 }
1328 while (0);
1329
1330 return rc;
1331}
1332
1333static const RTGETOPTDEF g_aShowMediumInfoOptions[] =
1334{
1335 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1336 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1337 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1338};
1339
1340RTEXITCODE handleShowMediumInfo(HandlerArg *a)
1341{
1342 HRESULT rc;
1343 enum {
1344 CMD_NONE,
1345 CMD_DISK,
1346 CMD_DVD,
1347 CMD_FLOPPY
1348 } cmd = CMD_NONE;
1349 const char *pszFilenameOrUuid = NULL;
1350
1351 int c;
1352 RTGETOPTUNION ValueUnion;
1353 RTGETOPTSTATE GetState;
1354 // start at 0 because main() has hacked both the argc and argv given to us
1355 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowMediumInfoOptions, RT_ELEMENTS(g_aShowMediumInfoOptions),
1356 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1357 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1358 {
1359 switch (c)
1360 {
1361 case 'd': // disk
1362 if (cmd != CMD_NONE)
1363 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1364 cmd = CMD_DISK;
1365 break;
1366
1367 case 'D': // DVD
1368 if (cmd != CMD_NONE)
1369 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1370 cmd = CMD_DVD;
1371 break;
1372
1373 case 'f': // floppy
1374 if (cmd != CMD_NONE)
1375 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1376 cmd = CMD_FLOPPY;
1377 break;
1378
1379 case VINF_GETOPT_NOT_OPTION:
1380 if (!pszFilenameOrUuid)
1381 pszFilenameOrUuid = ValueUnion.psz;
1382 else
1383 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid parameter '%s'", ValueUnion.psz);
1384 break;
1385
1386 default:
1387 if (c > 0)
1388 {
1389 if (RT_C_IS_PRINT(c))
1390 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option -%c", c);
1391 else
1392 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option case %i", c);
1393 }
1394 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1395 return errorSyntax(USAGE_SHOWMEDIUMINFO, "unknown option: %s\n", ValueUnion.psz);
1396 else if (ValueUnion.pDef)
1397 return errorSyntax(USAGE_SHOWMEDIUMINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1398 else
1399 return errorSyntax(USAGE_SHOWMEDIUMINFO, "error: %Rrs", c);
1400 }
1401 }
1402
1403 if (cmd == CMD_NONE)
1404 cmd = CMD_DISK;
1405
1406 /* check for required options */
1407 if (!pszFilenameOrUuid)
1408 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Medium name or UUID required");
1409
1410 ComPtr<IMedium> pMedium;
1411 if (cmd == CMD_DISK)
1412 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1413 AccessMode_ReadOnly, pMedium,
1414 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1415 else if (cmd == CMD_DVD)
1416 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1417 AccessMode_ReadOnly, pMedium,
1418 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1419 else if (cmd == CMD_FLOPPY)
1420 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1421 AccessMode_ReadOnly, pMedium,
1422 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1423 if (FAILED(rc))
1424 return RTEXITCODE_FAILURE;
1425
1426 Utf8Str strParentUUID("base");
1427 ComPtr<IMedium> pParent;
1428 pMedium->COMGETTER(Parent)(pParent.asOutParam());
1429 if (!pParent.isNull())
1430 {
1431 Bstr bstrParentUUID;
1432 pParent->COMGETTER(Id)(bstrParentUUID.asOutParam());
1433 strParentUUID = bstrParentUUID;
1434 }
1435
1436 rc = showMediumInfo(a->virtualBox, pMedium, strParentUUID.c_str(), true);
1437
1438 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1439}
1440
1441static const RTGETOPTDEF g_aCloseMediumOptions[] =
1442{
1443 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1444 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1445 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1446 { "--delete", 'r', RTGETOPT_REQ_NOTHING },
1447};
1448
1449RTEXITCODE handleCloseMedium(HandlerArg *a)
1450{
1451 HRESULT rc = S_OK;
1452 enum {
1453 CMD_NONE,
1454 CMD_DISK,
1455 CMD_DVD,
1456 CMD_FLOPPY
1457 } cmd = CMD_NONE;
1458 const char *pszFilenameOrUuid = NULL;
1459 bool fDelete = false;
1460
1461 int c;
1462 RTGETOPTUNION ValueUnion;
1463 RTGETOPTSTATE GetState;
1464 // start at 0 because main() has hacked both the argc and argv given to us
1465 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
1466 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1467 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1468 {
1469 switch (c)
1470 {
1471 case 'd': // disk
1472 if (cmd != CMD_NONE)
1473 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1474 cmd = CMD_DISK;
1475 break;
1476
1477 case 'D': // DVD
1478 if (cmd != CMD_NONE)
1479 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1480 cmd = CMD_DVD;
1481 break;
1482
1483 case 'f': // floppy
1484 if (cmd != CMD_NONE)
1485 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1486 cmd = CMD_FLOPPY;
1487 break;
1488
1489 case 'r': // --delete
1490 fDelete = true;
1491 break;
1492
1493 case VINF_GETOPT_NOT_OPTION:
1494 if (!pszFilenameOrUuid)
1495 pszFilenameOrUuid = ValueUnion.psz;
1496 else
1497 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1498 break;
1499
1500 default:
1501 if (c > 0)
1502 {
1503 if (RT_C_IS_PRINT(c))
1504 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option -%c", c);
1505 else
1506 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option case %i", c);
1507 }
1508 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1509 return errorSyntax(USAGE_CLOSEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1510 else if (ValueUnion.pDef)
1511 return errorSyntax(USAGE_CLOSEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1512 else
1513 return errorSyntax(USAGE_CLOSEMEDIUM, "error: %Rrs", c);
1514 }
1515 }
1516
1517 /* check for required options */
1518 if (cmd == CMD_NONE)
1519 cmd = CMD_DISK;
1520 if (!pszFilenameOrUuid)
1521 return errorSyntax(USAGE_CLOSEMEDIUM, "Medium name or UUID required");
1522
1523 ComPtr<IMedium> pMedium;
1524 if (cmd == CMD_DISK)
1525 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1526 AccessMode_ReadWrite, pMedium,
1527 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1528 else if (cmd == CMD_DVD)
1529 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1530 AccessMode_ReadOnly, pMedium,
1531 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1532 else if (cmd == CMD_FLOPPY)
1533 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1534 AccessMode_ReadWrite, pMedium,
1535 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1536
1537 if (SUCCEEDED(rc) && pMedium)
1538 {
1539 if (fDelete)
1540 {
1541 ComPtr<IProgress> pProgress;
1542 CHECK_ERROR(pMedium, DeleteStorage(pProgress.asOutParam()));
1543 if (SUCCEEDED(rc))
1544 {
1545 rc = showProgress(pProgress);
1546 CHECK_PROGRESS_ERROR(pProgress, ("Failed to delete medium"));
1547 }
1548 else
1549 RTMsgError("Failed to delete medium. Error code %Rrc", rc);
1550 }
1551 CHECK_ERROR(pMedium, Close());
1552 }
1553
1554 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1555}
1556
1557RTEXITCODE handleMediumProperty(HandlerArg *a)
1558{
1559 HRESULT rc = S_OK;
1560 const char *pszCmd = NULL;
1561 enum {
1562 CMD_NONE,
1563 CMD_DISK,
1564 CMD_DVD,
1565 CMD_FLOPPY
1566 } cmd = CMD_NONE;
1567 const char *pszAction = NULL;
1568 const char *pszFilenameOrUuid = NULL;
1569 const char *pszProperty = NULL;
1570 ComPtr<IMedium> pMedium;
1571
1572 pszCmd = (a->argc > 0) ? a->argv[0] : "";
1573 if ( !RTStrICmp(pszCmd, "disk")
1574 || !RTStrICmp(pszCmd, "dvd")
1575 || !RTStrICmp(pszCmd, "floppy"))
1576 {
1577 if (!RTStrICmp(pszCmd, "disk"))
1578 cmd = CMD_DISK;
1579 else if (!RTStrICmp(pszCmd, "dvd"))
1580 cmd = CMD_DVD;
1581 else if (!RTStrICmp(pszCmd, "floppy"))
1582 cmd = CMD_FLOPPY;
1583 else
1584 {
1585 AssertMsgFailed(("unexpected parameter %s\n", pszCmd));
1586 cmd = CMD_DISK;
1587 }
1588 a->argv++;
1589 a->argc--;
1590 }
1591 else
1592 {
1593 pszCmd = NULL;
1594 cmd = CMD_DISK;
1595 }
1596
1597 if (a->argc == 0)
1598 return errorSyntax(USAGE_MEDIUMPROPERTY, "Missing action");
1599
1600 pszAction = a->argv[0];
1601 if ( RTStrICmp(pszAction, "set")
1602 && RTStrICmp(pszAction, "get")
1603 && RTStrICmp(pszAction, "delete"))
1604 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid action given: %s", pszAction);
1605
1606 if ( ( !RTStrICmp(pszAction, "set")
1607 && a->argc != 4)
1608 || ( RTStrICmp(pszAction, "set")
1609 && a->argc != 3))
1610 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid number of arguments given for action: %s", pszAction);
1611
1612 pszFilenameOrUuid = a->argv[1];
1613 pszProperty = a->argv[2];
1614
1615 if (cmd == CMD_DISK)
1616 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1617 AccessMode_ReadWrite, pMedium,
1618 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1619 else if (cmd == CMD_DVD)
1620 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1621 AccessMode_ReadOnly, pMedium,
1622 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1623 else if (cmd == CMD_FLOPPY)
1624 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1625 AccessMode_ReadWrite, pMedium,
1626 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1627 if (SUCCEEDED(rc) && !pMedium.isNull())
1628 {
1629 if (!RTStrICmp(pszAction, "set"))
1630 {
1631 const char *pszValue = a->argv[3];
1632 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr(pszValue).raw()));
1633 }
1634 else if (!RTStrICmp(pszAction, "get"))
1635 {
1636 Bstr strVal;
1637 CHECK_ERROR(pMedium, GetProperty(Bstr(pszProperty).raw(), strVal.asOutParam()));
1638 if (SUCCEEDED(rc))
1639 RTPrintf("%s=%ls\n", pszProperty, strVal.raw());
1640 }
1641 else if (!RTStrICmp(pszAction, "delete"))
1642 {
1643 const char *pszValue = a->argv[3];
1644 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr().raw()));
1645 /** @todo */
1646 }
1647 }
1648
1649 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1650}
1651
1652static const RTGETOPTDEF g_aEncryptMediumOptions[] =
1653{
1654 { "--newpassword", 'n', RTGETOPT_REQ_STRING },
1655 { "--oldpassword", 'o', RTGETOPT_REQ_STRING },
1656 { "--cipher", 'c', RTGETOPT_REQ_STRING },
1657 { "--newpasswordid", 'i', RTGETOPT_REQ_STRING }
1658};
1659
1660RTEXITCODE handleEncryptMedium(HandlerArg *a)
1661{
1662 HRESULT rc;
1663 ComPtr<IMedium> hardDisk;
1664 const char *pszPasswordNew = NULL;
1665 const char *pszPasswordOld = NULL;
1666 const char *pszCipher = NULL;
1667 const char *pszFilenameOrUuid = NULL;
1668 const char *pszNewPasswordId = NULL;
1669 Utf8Str strPasswordNew;
1670 Utf8Str strPasswordOld;
1671
1672 int c;
1673 RTGETOPTUNION ValueUnion;
1674 RTGETOPTSTATE GetState;
1675 // start at 0 because main() has hacked both the argc and argv given to us
1676 RTGetOptInit(&GetState, a->argc, a->argv, g_aEncryptMediumOptions, RT_ELEMENTS(g_aEncryptMediumOptions),
1677 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1678 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1679 {
1680 switch (c)
1681 {
1682 case 'n': // --newpassword
1683 pszPasswordNew = ValueUnion.psz;
1684 break;
1685
1686 case 'o': // --oldpassword
1687 pszPasswordOld = ValueUnion.psz;
1688 break;
1689
1690 case 'c': // --cipher
1691 pszCipher = ValueUnion.psz;
1692 break;
1693
1694 case 'i': // --newpasswordid
1695 pszNewPasswordId = ValueUnion.psz;
1696 break;
1697
1698 case VINF_GETOPT_NOT_OPTION:
1699 if (!pszFilenameOrUuid)
1700 pszFilenameOrUuid = ValueUnion.psz;
1701 else
1702 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1703 break;
1704
1705 default:
1706 if (c > 0)
1707 {
1708 if (RT_C_IS_PRINT(c))
1709 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option -%c", c);
1710 else
1711 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option case %i", c);
1712 }
1713 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1714 return errorSyntax(USAGE_ENCRYPTMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1715 else if (ValueUnion.pDef)
1716 return errorSyntax(USAGE_ENCRYPTMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1717 else
1718 return errorSyntax(USAGE_ENCRYPTMEDIUM, "error: %Rrs", c);
1719 }
1720 }
1721
1722 if (!pszFilenameOrUuid)
1723 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Disk name or UUID required");
1724
1725 if (!pszPasswordNew && !pszPasswordOld)
1726 return errorSyntax(USAGE_ENCRYPTMEDIUM, "No password specified");
1727
1728 if ( (pszPasswordNew && !pszNewPasswordId)
1729 || (!pszPasswordNew && pszNewPasswordId))
1730 return errorSyntax(USAGE_ENCRYPTMEDIUM, "A new password must always have a valid identifier set at the same time");
1731
1732 if (pszPasswordNew)
1733 {
1734 if (!RTStrCmp(pszPasswordNew, "-"))
1735 {
1736 /* Get password from console. */
1737 RTEXITCODE rcExit = readPasswordFromConsole(&strPasswordNew, "Enter new password:");
1738 if (rcExit == RTEXITCODE_FAILURE)
1739 return rcExit;
1740 }
1741 else
1742 {
1743 RTEXITCODE rcExit = readPasswordFile(pszPasswordNew, &strPasswordNew);
1744 if (rcExit == RTEXITCODE_FAILURE)
1745 {
1746 RTMsgError("Failed to read new password from file");
1747 return rcExit;
1748 }
1749 }
1750 }
1751
1752 if (pszPasswordOld)
1753 {
1754 if (!RTStrCmp(pszPasswordOld, "-"))
1755 {
1756 /* Get password from console. */
1757 RTEXITCODE rcExit = readPasswordFromConsole(&strPasswordOld, "Enter old password:");
1758 if (rcExit == RTEXITCODE_FAILURE)
1759 return rcExit;
1760 }
1761 else
1762 {
1763 RTEXITCODE rcExit = readPasswordFile(pszPasswordOld, &strPasswordOld);
1764 if (rcExit == RTEXITCODE_FAILURE)
1765 {
1766 RTMsgError("Failed to read old password from file");
1767 return rcExit;
1768 }
1769 }
1770 }
1771
1772 /* Always open the medium if necessary, there is no other way. */
1773 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1774 AccessMode_ReadWrite, hardDisk,
1775 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1776 if (FAILED(rc))
1777 return RTEXITCODE_FAILURE;
1778 if (hardDisk.isNull())
1779 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid hard disk reference, avoiding crash");
1780
1781 ComPtr<IProgress> progress;
1782 CHECK_ERROR(hardDisk, ChangeEncryption(Bstr(strPasswordOld).raw(), Bstr(pszCipher).raw(),
1783 Bstr(strPasswordNew).raw(), Bstr(pszNewPasswordId).raw(),
1784 progress.asOutParam()));
1785 if (SUCCEEDED(rc))
1786 rc = showProgress(progress);
1787 if (FAILED(rc))
1788 {
1789 if (rc == E_NOTIMPL)
1790 RTMsgError("Encrypt hard disk operation is not implemented!");
1791 else if (rc == VBOX_E_NOT_SUPPORTED)
1792 RTMsgError("Encrypt hard disk operation for this cipher is not implemented yet!");
1793 else if (!progress.isNull())
1794 CHECK_PROGRESS_ERROR(progress, ("Failed to encrypt hard disk"));
1795 else
1796 RTMsgError("Failed to encrypt hard disk!");
1797 }
1798
1799 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1800}
1801
1802RTEXITCODE handleCheckMediumPassword(HandlerArg *a)
1803{
1804 HRESULT rc;
1805 ComPtr<IMedium> hardDisk;
1806 const char *pszFilenameOrUuid = NULL;
1807 Utf8Str strPassword;
1808
1809 if (a->argc != 2)
1810 return errorSyntax(USAGE_MEDIUMENCCHKPWD, "Invalid number of arguments: %d", a->argc);
1811
1812 pszFilenameOrUuid = a->argv[0];
1813
1814 if (!RTStrCmp(a->argv[1], "-"))
1815 {
1816 /* Get password from console. */
1817 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
1818 if (rcExit == RTEXITCODE_FAILURE)
1819 return rcExit;
1820 }
1821 else
1822 {
1823 RTEXITCODE rcExit = readPasswordFile(a->argv[1], &strPassword);
1824 if (rcExit == RTEXITCODE_FAILURE)
1825 {
1826 RTMsgError("Failed to read password from file");
1827 return rcExit;
1828 }
1829 }
1830
1831 /* Always open the medium if necessary, there is no other way. */
1832 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1833 AccessMode_ReadWrite, hardDisk,
1834 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1835 if (FAILED(rc))
1836 return RTEXITCODE_FAILURE;
1837 if (hardDisk.isNull())
1838 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid hard disk reference, avoiding crash");
1839
1840 CHECK_ERROR(hardDisk, CheckEncryptionPassword(Bstr(strPassword).raw()));
1841 if (SUCCEEDED(rc))
1842 RTPrintf("The given password is correct\n");
1843 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1844}
1845
1846#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