VirtualBox

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

Last change on this file since 61864 was 61483, checked in by vboxsync, 9 years ago

bugref:8344. First variant of "move" operation for medium. Standalone task "MoveTask". "setLocation" Medium API method was implemented.

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