VirtualBox

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

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

Frontends/VBoxManage/VBoxManageDisk.cpp: fix COM incompatibility (variable name was the same as the COM type)

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