VirtualBox

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

Last change on this file since 54652 was 54591, checked in by vboxsync, 10 years ago

Add support to supply passwords for disk encryption while the VM is running

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.9 KB
Line 
1/* $Id: VBoxManageDisk.cpp 54591 2015-03-02 19:55:29Z 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
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
235int 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 1;
383 if (pParentMedium.isNull())
384 {
385 RTMsgError("Invalid parent hard disk reference, avoiding crash");
386 return 1;
387 }
388 MediumState_T state;
389 CHECK_ERROR(pParentMedium, COMGETTER(State)(&state));
390 if (FAILED(rc))
391 return 1;
392 if (state == MediumState_Inaccessible)
393 {
394 CHECK_ERROR(pParentMedium, RefreshState(&state));
395 if (FAILED(rc))
396 return 1;
397 }
398 }
399 /* check for filename extension */
400 /** @todo use IMediumFormat to cover all extensions generically */
401 Utf8Str strName(filename);
402 if (!RTPathHasSuffix(strName.c_str()))
403 {
404 Utf8Str strFormat(format);
405 if (cmd == CMD_DISK)
406 {
407 if (strFormat.compare("vmdk", RTCString::CaseInsensitive) == 0)
408 strName.append(".vmdk");
409 else if (strFormat.compare("vhd", RTCString::CaseInsensitive) == 0)
410 strName.append(".vhd");
411 else
412 strName.append(".vdi");
413 } else if (cmd == CMD_DVD)
414 strName.append(".iso");
415 else if (cmd == CMD_FLOPPY)
416 strName.append(".img");
417 filename = strName.c_str();
418 }
419
420 ComPtr<IMedium> pMedium;
421 if (cmd == CMD_DISK)
422 rc = createMedium(a, format, filename, DeviceType_HardDisk,
423 AccessMode_ReadWrite, pMedium);
424 else if (cmd == CMD_DVD)
425 rc = createMedium(a, format, filename, DeviceType_DVD,
426 AccessMode_ReadOnly, pMedium);
427 else if (cmd == CMD_FLOPPY)
428 rc = createMedium(a, format, filename, DeviceType_Floppy,
429 AccessMode_ReadWrite, pMedium);
430 else
431 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
432
433 if (SUCCEEDED(rc) && pMedium)
434 {
435 ComPtr<IProgress> pProgress;
436 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
437
438 for (ULONG i = 0; i < l_variants.size(); ++i)
439 {
440 ULONG temp = enmMediumVariant;
441 temp &= 1<<i;
442 l_variants [i] = (MediumVariant_T)temp;
443 }
444
445 if (fBase)
446 CHECK_ERROR(pMedium, CreateBaseStorage(size, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
447 else
448 CHECK_ERROR(pParentMedium, CreateDiffStorage(pMedium, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
449 if (SUCCEEDED(rc) && pProgress)
450 {
451 rc = showProgress(pProgress);
452 CHECK_PROGRESS_ERROR(pProgress, ("Failed to create medium"));
453 }
454 }
455
456 if (SUCCEEDED(rc) && pMedium)
457 {
458 Bstr uuid;
459 CHECK_ERROR(pMedium, COMGETTER(Id)(uuid.asOutParam()));
460 RTPrintf("Medium created. UUID: %s\n", Utf8Str(uuid).c_str());
461
462 //CHECK_ERROR(pMedium, Close());
463 }
464 return SUCCEEDED(rc) ? 0 : 1;
465}
466
467static const RTGETOPTDEF g_aModifyMediumOptions[] =
468{
469 { "disk", 'H', RTGETOPT_REQ_NOTHING },
470 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
471 { "floppy", 'L', RTGETOPT_REQ_NOTHING },
472 { "--type", 't', RTGETOPT_REQ_STRING },
473 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
474 { "settype", 't', RTGETOPT_REQ_STRING }, // deprecated
475 { "--autoreset", 'z', RTGETOPT_REQ_STRING },
476 { "-autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
477 { "autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
478 { "--property", 'p', RTGETOPT_REQ_STRING },
479 { "--compact", 'c', RTGETOPT_REQ_NOTHING },
480 { "-compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
481 { "compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
482 { "--resize", 'r', RTGETOPT_REQ_UINT64 },
483 { "--resizebyte", 'R', RTGETOPT_REQ_UINT64 }
484};
485
486int handleModifyMedium(HandlerArg *a)
487{
488 HRESULT rc;
489 int vrc;
490 enum {
491 CMD_NONE,
492 CMD_DISK,
493 CMD_DVD,
494 CMD_FLOPPY
495 } cmd = CMD_NONE;
496 ComPtr<IMedium> pMedium;
497 MediumType_T enmMediumType;
498 bool AutoReset = false;
499 SafeArray<BSTR> mediumPropNames;
500 SafeArray<BSTR> mediumPropValues;
501 bool fModifyMediumType = false;
502 bool fModifyAutoReset = false;
503 bool fModifyProperties = false;
504 bool fModifyCompact = false;
505 bool fModifyResize = false;
506 uint64_t cbResize = 0;
507 const char *pszFilenameOrUuid = 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 VINF_GETOPT_NOT_OPTION:
598 if (!pszFilenameOrUuid)
599 pszFilenameOrUuid = ValueUnion.psz;
600 else
601 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
602 break;
603
604 default:
605 if (c > 0)
606 {
607 if (RT_C_IS_PRINT(c))
608 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid option -%c", c);
609 else
610 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid option case %i", c);
611 }
612 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
613 return errorSyntax(USAGE_MODIFYMEDIUM, "unknown option: %s\n", ValueUnion.psz);
614 else if (ValueUnion.pDef)
615 return errorSyntax(USAGE_MODIFYMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
616 else
617 return errorSyntax(USAGE_MODIFYMEDIUM, "error: %Rrs", c);
618 }
619 }
620
621 if (cmd == CMD_NONE)
622 cmd = CMD_DISK;
623
624 if (!pszFilenameOrUuid)
625 return errorSyntax(USAGE_MODIFYMEDIUM, "Medium name or UUID required");
626
627 if (!fModifyMediumType && !fModifyAutoReset && !fModifyProperties && !fModifyCompact && !fModifyResize)
628 return errorSyntax(USAGE_MODIFYMEDIUM, "No operation specified");
629
630 /* Always open the medium if necessary, there is no other way. */
631 if (cmd == CMD_DISK)
632 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
633 AccessMode_ReadWrite, pMedium,
634 false /* fForceNewUuidOnOpen */, false /* fSilent */);
635 else if (cmd == CMD_DVD)
636 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
637 AccessMode_ReadOnly, pMedium,
638 false /* fForceNewUuidOnOpen */, false /* fSilent */);
639 else if (cmd == CMD_FLOPPY)
640 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
641 AccessMode_ReadWrite, pMedium,
642 false /* fForceNewUuidOnOpen */, false /* fSilent */);
643 else
644 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
645 if (FAILED(rc))
646 return 1;
647 if (pMedium.isNull())
648 {
649 RTMsgError("Invalid medium reference, avoiding crash");
650 return 1;
651 }
652
653 if (fModifyMediumType)
654 {
655 MediumType_T enmCurrMediumType;
656 CHECK_ERROR(pMedium, COMGETTER(Type)(&enmCurrMediumType));
657
658 if (enmCurrMediumType != enmMediumType)
659 CHECK_ERROR(pMedium, COMSETTER(Type)(enmMediumType));
660 }
661
662 if (fModifyAutoReset)
663 {
664 CHECK_ERROR(pMedium, COMSETTER(AutoReset)(AutoReset));
665 }
666
667 if (fModifyProperties)
668 {
669 CHECK_ERROR(pMedium, SetProperties(ComSafeArrayAsInParam(mediumPropNames), ComSafeArrayAsInParam(mediumPropValues)));
670 }
671
672 if (fModifyCompact)
673 {
674 ComPtr<IProgress> pProgress;
675 CHECK_ERROR(pMedium, Compact(pProgress.asOutParam()));
676 if (SUCCEEDED(rc))
677 rc = showProgress(pProgress);
678 if (FAILED(rc))
679 {
680 if (rc == E_NOTIMPL)
681 RTMsgError("Compact medium operation is not implemented!");
682 else if (rc == VBOX_E_NOT_SUPPORTED)
683 RTMsgError("Compact medium operation for this format is not implemented yet!");
684 else if (!pProgress.isNull())
685 CHECK_PROGRESS_ERROR(pProgress, ("Failed to compact medium"));
686 else
687 RTMsgError("Failed to compact medium!");
688 }
689 }
690
691 if (fModifyResize)
692 {
693 ComPtr<IProgress> pProgress;
694 CHECK_ERROR(pMedium, Resize(cbResize, pProgress.asOutParam()));
695 if (SUCCEEDED(rc))
696 rc = showProgress(pProgress);
697 if (FAILED(rc))
698 {
699 if (rc == E_NOTIMPL)
700 RTMsgError("Resize medium operation is not implemented!");
701 else if (rc == VBOX_E_NOT_SUPPORTED)
702 RTMsgError("Resize medium operation for this format is not implemented yet!");
703 else
704 CHECK_PROGRESS_ERROR(pProgress, ("Failed to resize medium"));
705 }
706 }
707
708 return SUCCEEDED(rc) ? 0 : 1;
709}
710
711static const RTGETOPTDEF g_aCloneMediumOptions[] =
712{
713 { "disk", 'd', RTGETOPT_REQ_NOTHING },
714 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
715 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
716 { "--format", 'o', RTGETOPT_REQ_STRING },
717 { "-format", 'o', RTGETOPT_REQ_STRING },
718 { "--static", 'F', RTGETOPT_REQ_NOTHING },
719 { "-static", 'F', RTGETOPT_REQ_NOTHING },
720 { "--existing", 'E', RTGETOPT_REQ_NOTHING },
721 { "--variant", 'm', RTGETOPT_REQ_STRING },
722 { "-variant", 'm', RTGETOPT_REQ_STRING },
723};
724
725int handleCloneMedium(HandlerArg *a)
726{
727 HRESULT rc;
728 int vrc;
729 enum {
730 CMD_NONE,
731 CMD_DISK,
732 CMD_DVD,
733 CMD_FLOPPY
734 } cmd = CMD_NONE;
735 const char *pszSrc = NULL;
736 const char *pszDst = NULL;
737 Bstr format;
738 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
739 bool fExisting = false;
740
741 int c;
742 RTGETOPTUNION ValueUnion;
743 RTGETOPTSTATE GetState;
744 // start at 0 because main() has hacked both the argc and argv given to us
745 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneMediumOptions, RT_ELEMENTS(g_aCloneMediumOptions),
746 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
747 while ((c = RTGetOpt(&GetState, &ValueUnion)))
748 {
749 switch (c)
750 {
751 case 'd': // disk
752 if (cmd != CMD_NONE)
753 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
754 cmd = CMD_DISK;
755 break;
756
757 case 'D': // DVD
758 if (cmd != CMD_NONE)
759 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
760 cmd = CMD_DVD;
761 break;
762
763 case 'f': // floppy
764 if (cmd != CMD_NONE)
765 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
766 cmd = CMD_FLOPPY;
767 break;
768
769 case 'o': // --format
770 format = ValueUnion.psz;
771 break;
772
773 case 'F': // --static
774 {
775 unsigned uMediumVariant = (unsigned)enmMediumVariant;
776 uMediumVariant |= MediumVariant_Fixed;
777 enmMediumVariant = (MediumVariant_T)uMediumVariant;
778 break;
779 }
780
781 case 'E': // --existing
782 fExisting = true;
783 break;
784
785 case 'm': // --variant
786 vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
787 if (RT_FAILURE(vrc))
788 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
789 break;
790
791 case VINF_GETOPT_NOT_OPTION:
792 if (!pszSrc)
793 pszSrc = ValueUnion.psz;
794 else if (!pszDst)
795 pszDst = ValueUnion.psz;
796 else
797 return errorSyntax(USAGE_CLONEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
798 break;
799
800 default:
801 if (c > 0)
802 {
803 if (RT_C_IS_GRAPH(c))
804 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: -%c", c);
805 else
806 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: %i", c);
807 }
808 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
809 return errorSyntax(USAGE_CLONEMEDIUM, "unknown option: %s", ValueUnion.psz);
810 else if (ValueUnion.pDef)
811 return errorSyntax(USAGE_CLONEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
812 else
813 return errorSyntax(USAGE_CLONEMEDIUM, "error: %Rrs", c);
814 }
815 }
816
817 if (cmd == CMD_NONE)
818 cmd = CMD_DISK;
819 if (!pszSrc)
820 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory UUID or input file parameter missing");
821 if (!pszDst)
822 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory output file parameter missing");
823 if (fExisting && (!format.isEmpty() || enmMediumVariant != MediumType_Normal))
824 return errorSyntax(USAGE_CLONEMEDIUM, "Specified options which cannot be used with --existing");
825
826 ComPtr<IMedium> pSrcMedium;
827 ComPtr<IMedium> pDstMedium;
828
829 if (cmd == CMD_DISK)
830 rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly, pSrcMedium,
831 false /* fForceNewUuidOnOpen */, false /* fSilent */);
832 else if (cmd == CMD_DVD)
833 rc = openMedium(a, pszSrc, DeviceType_DVD, AccessMode_ReadOnly, pSrcMedium,
834 false /* fForceNewUuidOnOpen */, false /* fSilent */);
835 else if (cmd == CMD_FLOPPY)
836 rc = openMedium(a, pszSrc, DeviceType_Floppy, AccessMode_ReadOnly, pSrcMedium,
837 false /* fForceNewUuidOnOpen */, false /* fSilent */);
838 else
839 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
840 if (FAILED(rc))
841 return 1;
842
843 do
844 {
845 /* open/create destination medium */
846 if (fExisting)
847 {
848 if (cmd == CMD_DISK)
849 rc = openMedium(a, pszDst, DeviceType_HardDisk, AccessMode_ReadWrite, pDstMedium,
850 false /* fForceNewUuidOnOpen */, false /* fSilent */);
851 else if (cmd == CMD_DVD)
852 rc = openMedium(a, pszDst, DeviceType_DVD, AccessMode_ReadOnly, pDstMedium,
853 false /* fForceNewUuidOnOpen */, false /* fSilent */);
854 else if (cmd == CMD_FLOPPY)
855 rc = openMedium(a, pszDst, DeviceType_Floppy, AccessMode_ReadWrite, pDstMedium,
856 false /* fForceNewUuidOnOpen */, false /* fSilent */);
857 if (FAILED(rc))
858 break;
859
860 /* Perform accessibility check now. */
861 MediumState_T state;
862 CHECK_ERROR_BREAK(pDstMedium, RefreshState(&state));
863 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Format)(format.asOutParam()));
864 }
865 else
866 {
867 /* use the format of the source medium if unspecified */
868 if (format.isEmpty())
869 CHECK_ERROR_BREAK(pSrcMedium, COMGETTER(Format)(format.asOutParam()));
870 Utf8Str strFormat(format);
871 if (cmd == CMD_DISK)
872 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_HardDisk,
873 AccessMode_ReadWrite, pDstMedium);
874 else if (cmd == CMD_DVD)
875 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_DVD,
876 AccessMode_ReadOnly, pDstMedium);
877 else if (cmd == CMD_FLOPPY)
878 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_Floppy,
879 AccessMode_ReadWrite, pDstMedium);
880 if (FAILED(rc))
881 break;
882 }
883
884 ComPtr<IProgress> pProgress;
885 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
886
887 for (ULONG i = 0; i < l_variants.size(); ++i)
888 {
889 ULONG temp = enmMediumVariant;
890 temp &= 1<<i;
891 l_variants [i] = (MediumVariant_T)temp;
892 }
893
894 CHECK_ERROR_BREAK(pSrcMedium, CloneTo(pDstMedium, ComSafeArrayAsInParam(l_variants), NULL, pProgress.asOutParam()));
895
896 rc = showProgress(pProgress);
897 CHECK_PROGRESS_ERROR_BREAK(pProgress, ("Failed to clone medium"));
898
899 Bstr uuid;
900 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Id)(uuid.asOutParam()));
901
902 RTPrintf("Clone medium created in format '%ls'. UUID: %s\n",
903 format.raw(), Utf8Str(uuid).c_str());
904 }
905 while (0);
906
907 return SUCCEEDED(rc) ? 0 : 1;
908}
909
910static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
911{
912 { "--format", 'o', RTGETOPT_REQ_STRING },
913 { "-format", 'o', RTGETOPT_REQ_STRING },
914 { "--static", 'F', RTGETOPT_REQ_NOTHING },
915 { "-static", 'F', RTGETOPT_REQ_NOTHING },
916 { "--variant", 'm', RTGETOPT_REQ_STRING },
917 { "-variant", 'm', RTGETOPT_REQ_STRING },
918 { "--uuid", 'u', RTGETOPT_REQ_STRING },
919};
920
921RTEXITCODE handleConvertFromRaw(int argc, char *argv[])
922{
923 int rc = VINF_SUCCESS;
924 bool fReadFromStdIn = false;
925 const char *format = "VDI";
926 const char *srcfilename = NULL;
927 const char *dstfilename = NULL;
928 const char *filesize = NULL;
929 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
930 void *pvBuf = NULL;
931 RTUUID uuid;
932 PCRTUUID pUuid = NULL;
933
934 int c;
935 RTGETOPTUNION ValueUnion;
936 RTGETOPTSTATE GetState;
937 // start at 0 because main() has hacked both the argc and argv given to us
938 RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
939 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
940 while ((c = RTGetOpt(&GetState, &ValueUnion)))
941 {
942 switch (c)
943 {
944 case 'u': // --uuid
945 if (RT_FAILURE(RTUuidFromStr(&uuid, ValueUnion.psz)))
946 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid UUID '%s'", ValueUnion.psz);
947 pUuid = &uuid;
948 break;
949 case 'o': // --format
950 format = ValueUnion.psz;
951 break;
952
953 case 'm': // --variant
954 {
955 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
956 rc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
957 if (RT_FAILURE(rc))
958 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
959 /// @todo cleaner solution than assuming 1:1 mapping?
960 uImageFlags = (unsigned)enmMediumVariant;
961 break;
962 }
963 case VINF_GETOPT_NOT_OPTION:
964 if (!srcfilename)
965 {
966 srcfilename = ValueUnion.psz;
967 fReadFromStdIn = !strcmp(srcfilename, "stdin");
968 }
969 else if (!dstfilename)
970 dstfilename = ValueUnion.psz;
971 else if (fReadFromStdIn && !filesize)
972 filesize = ValueUnion.psz;
973 else
974 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
975 break;
976
977 default:
978 return errorGetOpt(USAGE_CONVERTFROMRAW, c, &ValueUnion);
979 }
980 }
981
982 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
983 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
984 RTStrmPrintf(g_pStdErr, "Converting from raw image file=\"%s\" to file=\"%s\"...\n",
985 srcfilename, dstfilename);
986
987 PVBOXHDD pDisk = NULL;
988
989 PVDINTERFACE pVDIfs = NULL;
990 VDINTERFACEERROR vdInterfaceError;
991 vdInterfaceError.pfnError = handleVDError;
992 vdInterfaceError.pfnMessage = NULL;
993
994 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
995 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
996 AssertRC(rc);
997
998 /* open raw image file. */
999 RTFILE File;
1000 if (fReadFromStdIn)
1001 rc = RTFileFromNative(&File, RTFILE_NATIVE_STDIN);
1002 else
1003 rc = RTFileOpen(&File, srcfilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1004 if (RT_FAILURE(rc))
1005 {
1006 RTMsgError("Cannot open file \"%s\": %Rrc", srcfilename, rc);
1007 goto out;
1008 }
1009
1010 uint64_t cbFile;
1011 /* get image size. */
1012 if (fReadFromStdIn)
1013 cbFile = RTStrToUInt64(filesize);
1014 else
1015 rc = RTFileGetSize(File, &cbFile);
1016 if (RT_FAILURE(rc))
1017 {
1018 RTMsgError("Cannot get image size for file \"%s\": %Rrc", srcfilename, rc);
1019 goto out;
1020 }
1021
1022 RTStrmPrintf(g_pStdErr, "Creating %s image with size %RU64 bytes (%RU64MB)...\n",
1023 (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
1024 char pszComment[256];
1025 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
1026 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1027 if (RT_FAILURE(rc))
1028 {
1029 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
1030 goto out;
1031 }
1032
1033 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
1034 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
1035 VDGEOMETRY PCHS, LCHS;
1036 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
1037 PCHS.cHeads = 16;
1038 PCHS.cSectors = 63;
1039 LCHS.cCylinders = 0;
1040 LCHS.cHeads = 0;
1041 LCHS.cSectors = 0;
1042 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
1043 uImageFlags, pszComment, &PCHS, &LCHS, pUuid,
1044 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1045 if (RT_FAILURE(rc))
1046 {
1047 RTMsgError("Cannot create the disk image \"%s\": %Rrc", dstfilename, rc);
1048 goto out;
1049 }
1050
1051 size_t cbBuffer;
1052 cbBuffer = _1M;
1053 pvBuf = RTMemAlloc(cbBuffer);
1054 if (!pvBuf)
1055 {
1056 rc = VERR_NO_MEMORY;
1057 RTMsgError("Out of memory allocating buffers for image \"%s\": %Rrc", dstfilename, rc);
1058 goto out;
1059 }
1060
1061 uint64_t offFile;
1062 offFile = 0;
1063 while (offFile < cbFile)
1064 {
1065 size_t cbRead;
1066 size_t cbToRead;
1067 cbRead = 0;
1068 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
1069 cbBuffer : (size_t)(cbFile - offFile);
1070 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
1071 if (RT_FAILURE(rc) || !cbRead)
1072 break;
1073 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
1074 if (RT_FAILURE(rc))
1075 {
1076 RTMsgError("Failed to write to disk image \"%s\": %Rrc", dstfilename, rc);
1077 goto out;
1078 }
1079 offFile += cbRead;
1080 }
1081
1082out:
1083 if (pvBuf)
1084 RTMemFree(pvBuf);
1085 if (pDisk)
1086 VDClose(pDisk, RT_FAILURE(rc));
1087 if (File != NIL_RTFILE)
1088 RTFileClose(File);
1089
1090 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1091}
1092
1093HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
1094 const ComPtr<IMedium> &pMedium,
1095 const char *pszParentUUID,
1096 bool fOptLong)
1097{
1098 HRESULT rc = S_OK;
1099 do
1100 {
1101 Bstr uuid;
1102 pMedium->COMGETTER(Id)(uuid.asOutParam());
1103 RTPrintf("UUID: %ls\n", uuid.raw());
1104 if (pszParentUUID)
1105 RTPrintf("Parent UUID: %s\n", pszParentUUID);
1106
1107 /* check for accessibility */
1108 MediumState_T enmState;
1109 CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
1110 pMedium->RefreshState(&enmState);
1111 const char *pszState = "unknown";
1112 switch (enmState)
1113 {
1114 case MediumState_NotCreated:
1115 pszState = "not created";
1116 break;
1117 case MediumState_Created:
1118 pszState = "created";
1119 break;
1120 case MediumState_LockedRead:
1121 pszState = "locked read";
1122 break;
1123 case MediumState_LockedWrite:
1124 pszState = "locked write";
1125 break;
1126 case MediumState_Inaccessible:
1127 pszState = "inaccessible";
1128 break;
1129 case MediumState_Creating:
1130 pszState = "creating";
1131 break;
1132 case MediumState_Deleting:
1133 pszState = "deleting";
1134 break;
1135 }
1136 RTPrintf("State: %s\n", pszState);
1137
1138 if (fOptLong && enmState == MediumState_Inaccessible)
1139 {
1140 Bstr err;
1141 CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
1142 RTPrintf("Access Error: %ls\n", err.raw());
1143 }
1144
1145 if (fOptLong)
1146 {
1147 Bstr description;
1148 pMedium->COMGETTER(Description)(description.asOutParam());
1149 if (!description.isEmpty())
1150 RTPrintf("Description: %ls\n", description.raw());
1151 }
1152
1153 MediumType_T type;
1154 pMedium->COMGETTER(Type)(&type);
1155 const char *typeStr = "unknown";
1156 switch (type)
1157 {
1158 case MediumType_Normal:
1159 if (pszParentUUID && Guid(pszParentUUID).isValid())
1160 typeStr = "normal (differencing)";
1161 else
1162 typeStr = "normal (base)";
1163 break;
1164 case MediumType_Immutable:
1165 typeStr = "immutable";
1166 break;
1167 case MediumType_Writethrough:
1168 typeStr = "writethrough";
1169 break;
1170 case MediumType_Shareable:
1171 typeStr = "shareable";
1172 break;
1173 case MediumType_Readonly:
1174 typeStr = "readonly";
1175 break;
1176 case MediumType_MultiAttach:
1177 typeStr = "multiattach";
1178 break;
1179 }
1180 RTPrintf("Type: %s\n", typeStr);
1181
1182 /* print out information specific for differencing media */
1183 if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
1184 {
1185 BOOL autoReset = FALSE;
1186 pMedium->COMGETTER(AutoReset)(&autoReset);
1187 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1188 }
1189
1190 Bstr loc;
1191 pMedium->COMGETTER(Location)(loc.asOutParam());
1192 RTPrintf("Location: %ls\n", loc.raw());
1193
1194 Bstr format;
1195 pMedium->COMGETTER(Format)(format.asOutParam());
1196 RTPrintf("Storage format: %ls\n", format.raw());
1197
1198 if (fOptLong)
1199 {
1200 com::SafeArray<MediumVariant_T> safeArray_variant;
1201
1202 pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
1203 ULONG variant=0;
1204 for (size_t i = 0; i < safeArray_variant.size(); i++)
1205 variant |= safeArray_variant[i];
1206
1207 const char *variantStr = "unknown";
1208 switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
1209 {
1210 case MediumVariant_VmdkSplit2G:
1211 variantStr = "split2G";
1212 break;
1213 case MediumVariant_VmdkStreamOptimized:
1214 variantStr = "streamOptimized";
1215 break;
1216 case MediumVariant_VmdkESX:
1217 variantStr = "ESX";
1218 break;
1219 case MediumVariant_Standard:
1220 variantStr = "default";
1221 break;
1222 }
1223 const char *variantTypeStr = "dynamic";
1224 if (variant & MediumVariant_Fixed)
1225 variantTypeStr = "fixed";
1226 else if (variant & MediumVariant_Diff)
1227 variantTypeStr = "differencing";
1228 RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
1229 }
1230
1231 LONG64 logicalSize;
1232 pMedium->COMGETTER(LogicalSize)(&logicalSize);
1233 RTPrintf("Capacity: %lld MBytes\n", logicalSize >> 20);
1234 if (fOptLong)
1235 {
1236 LONG64 actualSize;
1237 pMedium->COMGETTER(Size)(&actualSize);
1238 RTPrintf("Size on disk: %lld MBytes\n", actualSize >> 20);
1239 }
1240
1241 if (fOptLong)
1242 {
1243 com::SafeArray<BSTR> names;
1244 com::SafeArray<BSTR> values;
1245 pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
1246 size_t cNames = names.size();
1247 size_t cValues = values.size();
1248 bool fFirst = true;
1249 for (size_t i = 0; i < cNames; i++)
1250 {
1251 Bstr value;
1252 if (i < cValues)
1253 value = values[i];
1254 RTPrintf("%s%ls=%ls\n",
1255 fFirst ? "Property: " : " ",
1256 names[i], value.raw());
1257 }
1258 }
1259
1260 if (fOptLong)
1261 {
1262 bool fFirst = true;
1263 com::SafeArray<BSTR> machineIds;
1264 pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1265 for (size_t i = 0; i < machineIds.size(); i++)
1266 {
1267 ComPtr<IMachine> pMachine;
1268 CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], pMachine.asOutParam()));
1269 if (pMachine)
1270 {
1271 Bstr name;
1272 pMachine->COMGETTER(Name)(name.asOutParam());
1273 pMachine->COMGETTER(Id)(uuid.asOutParam());
1274 RTPrintf("%s%ls (UUID: %ls)",
1275 fFirst ? "In use by VMs: " : " ",
1276 name.raw(), machineIds[i]);
1277 fFirst = false;
1278 com::SafeArray<BSTR> snapshotIds;
1279 pMedium->GetSnapshotIds(machineIds[i],
1280 ComSafeArrayAsOutParam(snapshotIds));
1281 for (size_t j = 0; j < snapshotIds.size(); j++)
1282 {
1283 ComPtr<ISnapshot> pSnapshot;
1284 pMachine->FindSnapshot(snapshotIds[j], pSnapshot.asOutParam());
1285 if (pSnapshot)
1286 {
1287 Bstr snapshotName;
1288 pSnapshot->COMGETTER(Name)(snapshotName.asOutParam());
1289 RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
1290 }
1291 }
1292 RTPrintf("\n");
1293 }
1294 }
1295 }
1296
1297 if (fOptLong)
1298 {
1299 com::SafeIfaceArray<IMedium> children;
1300 pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
1301 bool fFirst = true;
1302 for (size_t i = 0; i < children.size(); i++)
1303 {
1304 ComPtr<IMedium> pChild(children[i]);
1305 if (pChild)
1306 {
1307 Bstr childUUID;
1308 pChild->COMGETTER(Id)(childUUID.asOutParam());
1309 RTPrintf("%s%ls\n",
1310 fFirst ? "Child UUIDs: " : " ",
1311 childUUID.raw());
1312 fFirst = false;
1313 }
1314 }
1315 }
1316 }
1317 while (0);
1318
1319 return rc;
1320}
1321
1322static const RTGETOPTDEF g_aShowMediumInfoOptions[] =
1323{
1324 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1325 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1326 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1327};
1328
1329int handleShowMediumInfo(HandlerArg *a)
1330{
1331 HRESULT rc;
1332 enum {
1333 CMD_NONE,
1334 CMD_DISK,
1335 CMD_DVD,
1336 CMD_FLOPPY
1337 } cmd = CMD_NONE;
1338 const char *pszFilenameOrUuid = NULL;
1339
1340 int c;
1341 RTGETOPTUNION ValueUnion;
1342 RTGETOPTSTATE GetState;
1343 // start at 0 because main() has hacked both the argc and argv given to us
1344 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowMediumInfoOptions, RT_ELEMENTS(g_aShowMediumInfoOptions),
1345 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1346 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1347 {
1348 switch (c)
1349 {
1350 case 'd': // disk
1351 if (cmd != CMD_NONE)
1352 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1353 cmd = CMD_DISK;
1354 break;
1355
1356 case 'D': // DVD
1357 if (cmd != CMD_NONE)
1358 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1359 cmd = CMD_DVD;
1360 break;
1361
1362 case 'f': // floppy
1363 if (cmd != CMD_NONE)
1364 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1365 cmd = CMD_FLOPPY;
1366 break;
1367
1368 case VINF_GETOPT_NOT_OPTION:
1369 if (!pszFilenameOrUuid)
1370 pszFilenameOrUuid = ValueUnion.psz;
1371 else
1372 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid parameter '%s'", ValueUnion.psz);
1373 break;
1374
1375 default:
1376 if (c > 0)
1377 {
1378 if (RT_C_IS_PRINT(c))
1379 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option -%c", c);
1380 else
1381 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option case %i", c);
1382 }
1383 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1384 return errorSyntax(USAGE_SHOWMEDIUMINFO, "unknown option: %s\n", ValueUnion.psz);
1385 else if (ValueUnion.pDef)
1386 return errorSyntax(USAGE_SHOWMEDIUMINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1387 else
1388 return errorSyntax(USAGE_SHOWMEDIUMINFO, "error: %Rrs", c);
1389 }
1390 }
1391
1392 if (cmd == CMD_NONE)
1393 cmd = CMD_DISK;
1394
1395 /* check for required options */
1396 if (!pszFilenameOrUuid)
1397 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Medium name or UUID required");
1398
1399 ComPtr<IMedium> pMedium;
1400 if (cmd == CMD_DISK)
1401 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1402 AccessMode_ReadOnly, pMedium,
1403 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1404 else if (cmd == CMD_DVD)
1405 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1406 AccessMode_ReadOnly, pMedium,
1407 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1408 else if (cmd == CMD_FLOPPY)
1409 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1410 AccessMode_ReadOnly, pMedium,
1411 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1412 if (FAILED(rc))
1413 return 1;
1414
1415 Utf8Str strParentUUID("base");
1416 ComPtr<IMedium> pParent;
1417 pMedium->COMGETTER(Parent)(pParent.asOutParam());
1418 if (!pParent.isNull())
1419 {
1420 Bstr bstrParentUUID;
1421 pParent->COMGETTER(Id)(bstrParentUUID.asOutParam());
1422 strParentUUID = bstrParentUUID;
1423 }
1424
1425 rc = showMediumInfo(a->virtualBox, pMedium, strParentUUID.c_str(), true);
1426
1427 return SUCCEEDED(rc) ? 0 : 1;
1428}
1429
1430static const RTGETOPTDEF g_aCloseMediumOptions[] =
1431{
1432 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1433 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1434 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1435 { "--delete", 'r', RTGETOPT_REQ_NOTHING },
1436};
1437
1438int handleCloseMedium(HandlerArg *a)
1439{
1440 HRESULT rc = S_OK;
1441 enum {
1442 CMD_NONE,
1443 CMD_DISK,
1444 CMD_DVD,
1445 CMD_FLOPPY
1446 } cmd = CMD_NONE;
1447 const char *pszFilenameOrUuid = NULL;
1448 bool fDelete = false;
1449
1450 int c;
1451 RTGETOPTUNION ValueUnion;
1452 RTGETOPTSTATE GetState;
1453 // start at 0 because main() has hacked both the argc and argv given to us
1454 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
1455 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1456 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1457 {
1458 switch (c)
1459 {
1460 case 'd': // disk
1461 if (cmd != CMD_NONE)
1462 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1463 cmd = CMD_DISK;
1464 break;
1465
1466 case 'D': // DVD
1467 if (cmd != CMD_NONE)
1468 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1469 cmd = CMD_DVD;
1470 break;
1471
1472 case 'f': // floppy
1473 if (cmd != CMD_NONE)
1474 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1475 cmd = CMD_FLOPPY;
1476 break;
1477
1478 case 'r': // --delete
1479 fDelete = true;
1480 break;
1481
1482 case VINF_GETOPT_NOT_OPTION:
1483 if (!pszFilenameOrUuid)
1484 pszFilenameOrUuid = ValueUnion.psz;
1485 else
1486 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1487 break;
1488
1489 default:
1490 if (c > 0)
1491 {
1492 if (RT_C_IS_PRINT(c))
1493 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option -%c", c);
1494 else
1495 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option case %i", c);
1496 }
1497 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1498 return errorSyntax(USAGE_CLOSEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1499 else if (ValueUnion.pDef)
1500 return errorSyntax(USAGE_CLOSEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1501 else
1502 return errorSyntax(USAGE_CLOSEMEDIUM, "error: %Rrs", c);
1503 }
1504 }
1505
1506 /* check for required options */
1507 if (cmd == CMD_NONE)
1508 cmd = CMD_DISK;
1509 if (!pszFilenameOrUuid)
1510 return errorSyntax(USAGE_CLOSEMEDIUM, "Medium name or UUID required");
1511
1512 ComPtr<IMedium> pMedium;
1513 if (cmd == CMD_DISK)
1514 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1515 AccessMode_ReadWrite, pMedium,
1516 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1517 else if (cmd == CMD_DVD)
1518 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1519 AccessMode_ReadOnly, pMedium,
1520 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1521 else if (cmd == CMD_FLOPPY)
1522 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1523 AccessMode_ReadWrite, pMedium,
1524 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1525
1526 if (SUCCEEDED(rc) && pMedium)
1527 {
1528 if (fDelete)
1529 {
1530 ComPtr<IProgress> pProgress;
1531 CHECK_ERROR(pMedium, DeleteStorage(pProgress.asOutParam()));
1532 if (SUCCEEDED(rc))
1533 {
1534 rc = showProgress(pProgress);
1535 CHECK_PROGRESS_ERROR(pProgress, ("Failed to delete medium"));
1536 }
1537 else
1538 RTMsgError("Failed to delete medium. Error code %Rrc", rc);
1539 }
1540 CHECK_ERROR(pMedium, Close());
1541 }
1542
1543 return SUCCEEDED(rc) ? 0 : 1;
1544}
1545
1546int handleMediumProperty(HandlerArg *a)
1547{
1548 HRESULT rc = S_OK;
1549 const char *pszCmd = NULL;
1550 enum {
1551 CMD_NONE,
1552 CMD_DISK,
1553 CMD_DVD,
1554 CMD_FLOPPY
1555 } cmd = CMD_NONE;
1556 const char *pszAction = NULL;
1557 const char *pszFilenameOrUuid = NULL;
1558 const char *pszProperty = NULL;
1559 ComPtr<IMedium> pMedium;
1560
1561 pszCmd = (a->argc > 0) ? a->argv[0] : "";
1562 if ( !RTStrICmp(pszCmd, "disk")
1563 || !RTStrICmp(pszCmd, "dvd")
1564 || !RTStrICmp(pszCmd, "floppy"))
1565 {
1566 if (!RTStrICmp(pszCmd, "disk"))
1567 cmd = CMD_DISK;
1568 else if (!RTStrICmp(pszCmd, "dvd"))
1569 cmd = CMD_DVD;
1570 else if (!RTStrICmp(pszCmd, "floppy"))
1571 cmd = CMD_FLOPPY;
1572 else
1573 {
1574 AssertMsgFailed(("unexpected parameter %s\n", pszCmd));
1575 cmd = CMD_DISK;
1576 }
1577 a->argv++;
1578 a->argc--;
1579 }
1580 else
1581 {
1582 pszCmd = NULL;
1583 cmd = CMD_DISK;
1584 }
1585
1586 if (a->argc == 0)
1587 return errorSyntax(USAGE_MEDIUMPROPERTY, "Missing action");
1588
1589 pszAction = a->argv[0];
1590 if ( RTStrICmp(pszAction, "set")
1591 && RTStrICmp(pszAction, "get")
1592 && RTStrICmp(pszAction, "delete"))
1593 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid action given: %s", pszAction);
1594
1595 if ( ( !RTStrICmp(pszAction, "set")
1596 && a->argc != 4)
1597 || ( RTStrICmp(pszAction, "set")
1598 && a->argc != 3))
1599 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid number of arguments given for action: %s", pszAction);
1600
1601 pszFilenameOrUuid = a->argv[1];
1602 pszProperty = a->argv[2];
1603
1604 if (cmd == CMD_DISK)
1605 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1606 AccessMode_ReadWrite, pMedium,
1607 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1608 else if (cmd == CMD_DVD)
1609 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1610 AccessMode_ReadOnly, pMedium,
1611 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1612 else if (cmd == CMD_FLOPPY)
1613 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1614 AccessMode_ReadWrite, pMedium,
1615 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1616 if (SUCCEEDED(rc) && !pMedium.isNull())
1617 {
1618 if (!RTStrICmp(pszAction, "set"))
1619 {
1620 const char *pszValue = a->argv[3];
1621 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr(pszValue).raw()));
1622 }
1623 else if (!RTStrICmp(pszAction, "get"))
1624 {
1625 Bstr strVal;
1626 CHECK_ERROR(pMedium, GetProperty(Bstr(pszProperty).raw(), strVal.asOutParam()));
1627 if (SUCCEEDED(rc))
1628 RTPrintf("%s=%ls\n", pszProperty, strVal.raw());
1629 }
1630 else if (!RTStrICmp(pszAction, "delete"))
1631 {
1632 const char *pszValue = a->argv[3];
1633 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr().raw()));
1634 /** @todo */
1635 }
1636 }
1637
1638 return SUCCEEDED(rc) ? 0 : 1;
1639}
1640
1641static const RTGETOPTDEF g_aEncryptMediumOptions[] =
1642{
1643 { "--newpassword", 'n', RTGETOPT_REQ_STRING },
1644 { "--oldpassword", 'o', RTGETOPT_REQ_STRING },
1645 { "--cipher", 'c', RTGETOPT_REQ_STRING },
1646 { "--newpasswordid", 'i', RTGETOPT_REQ_STRING }
1647};
1648
1649int handleEncryptMedium(HandlerArg *a)
1650{
1651 HRESULT rc;
1652 int vrc;
1653 ComPtr<IMedium> hardDisk;
1654 const char *pszPasswordNew = NULL;
1655 const char *pszPasswordOld = NULL;
1656 const char *pszCipher = NULL;
1657 const char *pszFilenameOrUuid = NULL;
1658 const char *pszNewPasswordId = NULL;
1659
1660 int c;
1661 RTGETOPTUNION ValueUnion;
1662 RTGETOPTSTATE GetState;
1663 // start at 0 because main() has hacked both the argc and argv given to us
1664 RTGetOptInit(&GetState, a->argc, a->argv, g_aEncryptMediumOptions, RT_ELEMENTS(g_aEncryptMediumOptions),
1665 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1666 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1667 {
1668 switch (c)
1669 {
1670 case 'n': // --newpassword
1671 pszPasswordNew = ValueUnion.psz;
1672 break;
1673
1674 case 'o': // --oldpassword
1675 pszPasswordOld = ValueUnion.psz;
1676 break;
1677
1678 case 'c': // --cipher
1679 pszCipher = ValueUnion.psz;
1680 break;
1681
1682 case 'i': // --newpasswordid
1683 pszNewPasswordId = ValueUnion.psz;
1684 break;
1685
1686 case VINF_GETOPT_NOT_OPTION:
1687 if (!pszFilenameOrUuid)
1688 pszFilenameOrUuid = ValueUnion.psz;
1689 else
1690 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1691 break;
1692
1693 default:
1694 if (c > 0)
1695 {
1696 if (RT_C_IS_PRINT(c))
1697 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option -%c", c);
1698 else
1699 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option case %i", c);
1700 }
1701 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1702 return errorSyntax(USAGE_ENCRYPTMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1703 else if (ValueUnion.pDef)
1704 return errorSyntax(USAGE_ENCRYPTMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1705 else
1706 return errorSyntax(USAGE_ENCRYPTMEDIUM, "error: %Rrs", c);
1707 }
1708 }
1709
1710 if (!pszFilenameOrUuid)
1711 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Disk name or UUID required");
1712
1713 if (!pszPasswordNew && !pszPasswordOld)
1714 return errorSyntax(USAGE_ENCRYPTMEDIUM, "No password specified");
1715
1716 if ( (pszPasswordNew && !pszNewPasswordId)
1717 || (!pszPasswordNew && pszNewPasswordId))
1718 return errorSyntax(USAGE_ENCRYPTMEDIUM, "A new password must always have a valid identifier set at the same time");
1719
1720 /* Always open the medium if necessary, there is no other way. */
1721 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1722 AccessMode_ReadWrite, hardDisk,
1723 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1724 if (FAILED(rc))
1725 return 1;
1726 if (hardDisk.isNull())
1727 {
1728 RTMsgError("Invalid hard disk reference, avoiding crash");
1729 return 1;
1730 }
1731
1732 ComPtr<IProgress> progress;
1733 CHECK_ERROR(hardDisk, ChangeEncryption(Bstr(pszPasswordNew).raw(), Bstr(pszPasswordOld).raw(),
1734 Bstr(pszCipher).raw(), Bstr(pszNewPasswordId).raw(),
1735 progress.asOutParam()));
1736 if (SUCCEEDED(rc))
1737 rc = showProgress(progress);
1738 if (FAILED(rc))
1739 {
1740 if (rc == E_NOTIMPL)
1741 RTMsgError("Encrypt hard disk operation is not implemented!");
1742 else if (rc == VBOX_E_NOT_SUPPORTED)
1743 RTMsgError("Encrypt hard disk operation for this cipher is not implemented yet!");
1744 else if (!progress.isNull())
1745 CHECK_PROGRESS_ERROR(progress, ("Failed to encrypt hard disk"));
1746 else
1747 RTMsgError("Failed to encrypt hard disk!");
1748 }
1749
1750 return SUCCEEDED(rc) ? 0 : 1;
1751}
1752
1753#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

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