VirtualBox

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

Last change on this file since 42739 was 42248, checked in by vboxsync, 12 years ago

API change for SetVideoModeHint to be able to disable guest screens and to set the origin of guest screens

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.6 KB
Line 
1/* $Id: VBoxManageDisk.cpp 42248 2012-07-20 08:39:45Z vboxsync $ */
2/** @file
3 * VBoxManage - The disk related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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 RTMsgError(pszFormat, va);
51 RTMsgError("Error code %Rrc at %s(%u) in function %s", rc, RT_SRC_POS_ARGS);
52}
53
54
55static int parseDiskVariant(const char *psz, MediumVariant_T *pDiskVariant)
56{
57 int rc = VINF_SUCCESS;
58 unsigned DiskVariant = (unsigned)(*pDiskVariant);
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 DiskVariant = MediumVariant_Standard;
73 else if ( !RTStrNICmp(psz, "fixed", len)
74 || !RTStrNICmp(psz, "static", len))
75 DiskVariant |= MediumVariant_Fixed;
76 else if (!RTStrNICmp(psz, "Diff", len))
77 DiskVariant |= MediumVariant_Diff;
78 else if (!RTStrNICmp(psz, "split2g", len))
79 DiskVariant |= MediumVariant_VmdkSplit2G;
80 else if ( !RTStrNICmp(psz, "stream", len)
81 || !RTStrNICmp(psz, "streamoptimized", len))
82 DiskVariant |= MediumVariant_VmdkStreamOptimized;
83 else if (!RTStrNICmp(psz, "esx", len))
84 DiskVariant |= 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 *pDiskVariant = (MediumVariant_T)DiskVariant;
96 return rc;
97}
98
99int parseDiskType(const char *psz, MediumType_T *pDiskType)
100{
101 int rc = VINF_SUCCESS;
102 MediumType_T DiskType = MediumType_Normal;
103 if (!RTStrICmp(psz, "normal"))
104 DiskType = MediumType_Normal;
105 else if (!RTStrICmp(psz, "immutable"))
106 DiskType = MediumType_Immutable;
107 else if (!RTStrICmp(psz, "writethrough"))
108 DiskType = MediumType_Writethrough;
109 else if (!RTStrICmp(psz, "shareable"))
110 DiskType = MediumType_Shareable;
111 else if (!RTStrICmp(psz, "readonly"))
112 DiskType = MediumType_Readonly;
113 else if (!RTStrICmp(psz, "multiattach"))
114 DiskType = MediumType_MultiAttach;
115 else
116 rc = VERR_PARSE_ERROR;
117
118 if (RT_SUCCESS(rc))
119 *pDiskType = DiskType;
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 findMedium(HandlerArg *a, const char *pszFilenameOrUuid,
152 DeviceType_T enmDevType, bool fSilent,
153 ComPtr<IMedium> &pMedium)
154{
155 HRESULT rc;
156 Guid id(pszFilenameOrUuid);
157 char szFilenameAbs[RTPATH_MAX] = "";
158
159 /* If it is no UUID, convert the filename to an absolute one. */
160 if (id.isEmpty())
161 {
162 int irc = RTPathAbs(pszFilenameOrUuid, szFilenameAbs, sizeof(szFilenameAbs));
163 if (RT_FAILURE(irc))
164 {
165 if (!fSilent)
166 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilenameOrUuid);
167 return E_FAIL;
168 }
169 pszFilenameOrUuid = szFilenameAbs;
170 }
171
172 if (!fSilent)
173 CHECK_ERROR(a->virtualBox, OpenMedium(Bstr(pszFilenameOrUuid).raw(),
174 enmDevType,
175 AccessMode_ReadWrite,
176 /*fForceNewUidOnOpen */ false,
177 pMedium.asOutParam()));
178 else
179 rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
180 enmDevType,
181 AccessMode_ReadWrite,
182 /*fForceNewUidOnOpen */ false,
183 pMedium.asOutParam());
184 return rc;
185}
186
187HRESULT findOrOpenMedium(HandlerArg *a, const char *pszFilenameOrUuid,
188 DeviceType_T enmDevType, AccessMode_T enmAccessMode,
189 ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
190 bool *pfWasUnknown)
191{
192 HRESULT rc;
193 bool fWasUnknown = false;
194 Guid id(pszFilenameOrUuid);
195 char szFilenameAbs[RTPATH_MAX] = "";
196
197 /* If it is no UUID, convert the filename to an absolute one. */
198 if (id.isEmpty())
199 {
200 int irc = RTPathAbs(pszFilenameOrUuid, szFilenameAbs, sizeof(szFilenameAbs));
201 if (RT_FAILURE(irc))
202 {
203 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilenameOrUuid);
204 return E_FAIL;
205 }
206 pszFilenameOrUuid = szFilenameAbs;
207 }
208
209 rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
210 enmDevType,
211 enmAccessMode,
212 /*fForceNewUidOnOpen */ false,
213 pMedium.asOutParam());
214 /* If the medium is unknown try to open it. */
215 if (!pMedium)
216 {
217 CHECK_ERROR(a->virtualBox, OpenMedium(Bstr(pszFilenameOrUuid).raw(),
218 enmDevType, enmAccessMode,
219 fForceNewUuidOnOpen,
220 pMedium.asOutParam()));
221 if (SUCCEEDED(rc))
222 fWasUnknown = true;
223 }
224 if (RT_VALID_PTR(pfWasUnknown))
225 *pfWasUnknown = fWasUnknown;
226 return rc;
227}
228
229static HRESULT createHardDisk(HandlerArg *a, const char *pszFormat,
230 const char *pszFilename, ComPtr<IMedium> &pMedium)
231{
232 HRESULT rc;
233 char szFilenameAbs[RTPATH_MAX] = "";
234
235 /** @todo laziness shortcut. should really check the MediumFormatCapabilities */
236 if (RTStrICmp(pszFormat, "iSCSI"))
237 {
238 int irc = RTPathAbs(pszFilename, szFilenameAbs, sizeof(szFilenameAbs));
239 if (RT_FAILURE(irc))
240 {
241 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilename);
242 return E_FAIL;
243 }
244 pszFilename = szFilenameAbs;
245 }
246
247 CHECK_ERROR(a->virtualBox, CreateHardDisk(Bstr(pszFormat).raw(),
248 Bstr(pszFilename).raw(),
249 pMedium.asOutParam()));
250 return rc;
251}
252
253static const RTGETOPTDEF g_aCreateHardDiskOptions[] =
254{
255 { "--filename", 'f', RTGETOPT_REQ_STRING },
256 { "-filename", 'f', RTGETOPT_REQ_STRING }, // deprecated
257 { "--diffparent", 'd', RTGETOPT_REQ_STRING },
258 { "--size", 's', RTGETOPT_REQ_UINT64 },
259 { "-size", 's', RTGETOPT_REQ_UINT64 }, // deprecated
260 { "--sizebyte", 'S', RTGETOPT_REQ_UINT64 },
261 { "--format", 'o', RTGETOPT_REQ_STRING },
262 { "-format", 'o', RTGETOPT_REQ_STRING }, // deprecated
263 { "--static", 'F', RTGETOPT_REQ_NOTHING },
264 { "-static", 'F', RTGETOPT_REQ_NOTHING }, // deprecated
265 { "--variant", 'm', RTGETOPT_REQ_STRING },
266 { "-variant", 'm', RTGETOPT_REQ_STRING }, // deprecated
267};
268
269int handleCreateHardDisk(HandlerArg *a)
270{
271 HRESULT rc;
272 int vrc;
273 const char *filename = NULL;
274 const char *diffparent = NULL;
275 uint64_t size = 0;
276 const char *format = NULL;
277 bool fBase = true;
278 MediumVariant_T DiskVariant = MediumVariant_Standard;
279
280 int c;
281 RTGETOPTUNION ValueUnion;
282 RTGETOPTSTATE GetState;
283 // start at 0 because main() has hacked both the argc and argv given to us
284 RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateHardDiskOptions, RT_ELEMENTS(g_aCreateHardDiskOptions),
285 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
286 while ((c = RTGetOpt(&GetState, &ValueUnion)))
287 {
288 switch (c)
289 {
290 case 'f': // --filename
291 filename = ValueUnion.psz;
292 break;
293
294 case 'd': // --diffparent
295 diffparent = ValueUnion.psz;
296 fBase = false;
297 break;
298
299 case 's': // --size
300 size = ValueUnion.u64 * _1M;
301 break;
302
303 case 'S': // --sizebyte
304 size = ValueUnion.u64;
305 break;
306
307 case 'o': // --format
308 format = ValueUnion.psz;
309 break;
310
311 case 'F': // --static ("fixed"/"flat")
312 {
313 unsigned uDiskVariant = (unsigned)DiskVariant;
314 uDiskVariant |= MediumVariant_Fixed;
315 DiskVariant = (MediumVariant_T)uDiskVariant;
316 break;
317 }
318
319 case 'm': // --variant
320 vrc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
321 if (RT_FAILURE(vrc))
322 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
323 break;
324
325 case VINF_GETOPT_NOT_OPTION:
326 return errorSyntax(USAGE_CREATEHD, "Invalid parameter '%s'", ValueUnion.psz);
327
328 default:
329 if (c > 0)
330 {
331 if (RT_C_IS_PRINT(c))
332 return errorSyntax(USAGE_CREATEHD, "Invalid option -%c", c);
333 else
334 return errorSyntax(USAGE_CREATEHD, "Invalid option case %i", c);
335 }
336 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
337 return errorSyntax(USAGE_CREATEHD, "unknown option: %s\n", ValueUnion.psz);
338 else if (ValueUnion.pDef)
339 return errorSyntax(USAGE_CREATEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
340 else
341 return errorSyntax(USAGE_CREATEHD, "error: %Rrs", c);
342 }
343 }
344
345 /* check the outcome */
346 bool fUnknownParent = false;
347 ComPtr<IMedium> parentHardDisk;
348 if (fBase)
349 {
350 if ( !filename
351 || !*filename
352 || size == 0)
353 return errorSyntax(USAGE_CREATEHD, "Parameters --filename and --size are required");
354 if (!format || !*format)
355 format = "VDI";
356 }
357 else
358 {
359 if ( !filename
360 || !*filename)
361 return errorSyntax(USAGE_CREATEHD, "Parameters --filename is required");
362 size = 0;
363 DiskVariant = MediumVariant_Diff;
364 if (!format || !*format)
365 {
366 const char *pszExt = RTPathExt(filename);
367 /* Skip over . if there is an extension. */
368 if (pszExt)
369 pszExt++;
370 if (!pszExt || !*pszExt)
371 format = "VDI";
372 else
373 format = pszExt;
374 }
375 rc = findOrOpenMedium(a, diffparent, DeviceType_HardDisk, AccessMode_ReadWrite,
376 parentHardDisk, false /* fForceNewUuidOnOpen */,
377 &fUnknownParent);
378 if (FAILED(rc))
379 return 1;
380 if (parentHardDisk.isNull())
381 {
382 RTMsgError("Invalid parent hard disk reference, avoiding crash");
383 return 1;
384 }
385 MediumState_T state;
386 CHECK_ERROR(parentHardDisk, COMGETTER(State)(&state));
387 if (FAILED(rc))
388 return 1;
389 if (state == MediumState_Inaccessible)
390 {
391 CHECK_ERROR(parentHardDisk, RefreshState(&state));
392 if (FAILED(rc))
393 return 1;
394 }
395 }
396 /* check for filename extension */
397 /** @todo use IMediumFormat to cover all extensions generically */
398 Utf8Str strName(filename);
399 if (!RTPathHaveExt(strName.c_str()))
400 {
401 Utf8Str strFormat(format);
402 if (strFormat.compare("vmdk", RTCString::CaseInsensitive) == 0)
403 strName.append(".vmdk");
404 else if (strFormat.compare("vhd", RTCString::CaseInsensitive) == 0)
405 strName.append(".vhd");
406 else
407 strName.append(".vdi");
408 filename = strName.c_str();
409 }
410
411 ComPtr<IMedium> hardDisk;
412 rc = createHardDisk(a, format, filename, hardDisk);
413 if (SUCCEEDED(rc) && hardDisk)
414 {
415 ComPtr<IProgress> progress;
416 if (fBase)
417 CHECK_ERROR(hardDisk, CreateBaseStorage(size, DiskVariant, progress.asOutParam()));
418 else
419 CHECK_ERROR(parentHardDisk, CreateDiffStorage(hardDisk, DiskVariant, progress.asOutParam()));
420 if (SUCCEEDED(rc) && progress)
421 {
422 rc = showProgress(progress);
423 CHECK_PROGRESS_ERROR(progress, ("Failed to create hard disk"));
424 if (SUCCEEDED(rc))
425 {
426 Bstr uuid;
427 CHECK_ERROR(hardDisk, COMGETTER(Id)(uuid.asOutParam()));
428 RTPrintf("Disk image created. UUID: %s\n", Utf8Str(uuid).c_str());
429 }
430 }
431
432 CHECK_ERROR(hardDisk, Close());
433 if (!fBase && fUnknownParent)
434 CHECK_ERROR(parentHardDisk, Close());
435 }
436 return SUCCEEDED(rc) ? 0 : 1;
437}
438
439static const RTGETOPTDEF g_aModifyHardDiskOptions[] =
440{
441 { "--type", 't', RTGETOPT_REQ_STRING },
442 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
443 { "settype", 't', RTGETOPT_REQ_STRING }, // deprecated
444 { "--autoreset", 'z', RTGETOPT_REQ_STRING },
445 { "-autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
446 { "autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
447 { "--compact", 'c', RTGETOPT_REQ_NOTHING },
448 { "-compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
449 { "compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
450 { "--resize", 'r', RTGETOPT_REQ_UINT64 },
451 { "--resizebyte", 'R', RTGETOPT_REQ_UINT64 }
452};
453
454int handleModifyHardDisk(HandlerArg *a)
455{
456 HRESULT rc;
457 int vrc;
458 ComPtr<IMedium> hardDisk;
459 MediumType_T DiskType;
460 bool AutoReset = false;
461 bool fModifyDiskType = false, fModifyAutoReset = false, fModifyCompact = false;
462 bool fModifyResize = false;
463 uint64_t cbResize = 0;
464 const char *FilenameOrUuid = NULL;
465 bool unknown = false;
466
467 int c;
468 RTGETOPTUNION ValueUnion;
469 RTGETOPTSTATE GetState;
470 // start at 0 because main() has hacked both the argc and argv given to us
471 RTGetOptInit(&GetState, a->argc, a->argv, g_aModifyHardDiskOptions, RT_ELEMENTS(g_aModifyHardDiskOptions),
472 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
473 while ((c = RTGetOpt(&GetState, &ValueUnion)))
474 {
475 switch (c)
476 {
477 case 't': // --type
478 vrc = parseDiskType(ValueUnion.psz, &DiskType);
479 if (RT_FAILURE(vrc))
480 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
481 fModifyDiskType = true;
482 break;
483
484 case 'z': // --autoreset
485 vrc = parseBool(ValueUnion.psz, &AutoReset);
486 if (RT_FAILURE(vrc))
487 return errorArgument("Invalid autoreset parameter '%s'", ValueUnion.psz);
488 fModifyAutoReset = true;
489 break;
490
491 case 'c': // --compact
492 fModifyCompact = true;
493 break;
494
495 case 'r': // --resize
496 cbResize = ValueUnion.u64 * _1M;
497 fModifyResize = true;
498 break;
499
500 case 'R': // --resizebyte
501 cbResize = ValueUnion.u64;
502 fModifyResize = true;
503 break;
504
505 case VINF_GETOPT_NOT_OPTION:
506 if (!FilenameOrUuid)
507 FilenameOrUuid = ValueUnion.psz;
508 else
509 return errorSyntax(USAGE_MODIFYHD, "Invalid parameter '%s'", ValueUnion.psz);
510 break;
511
512 default:
513 if (c > 0)
514 {
515 if (RT_C_IS_PRINT(c))
516 return errorSyntax(USAGE_MODIFYHD, "Invalid option -%c", c);
517 else
518 return errorSyntax(USAGE_MODIFYHD, "Invalid option case %i", c);
519 }
520 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
521 return errorSyntax(USAGE_MODIFYHD, "unknown option: %s\n", ValueUnion.psz);
522 else if (ValueUnion.pDef)
523 return errorSyntax(USAGE_MODIFYHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
524 else
525 return errorSyntax(USAGE_MODIFYHD, "error: %Rrs", c);
526 }
527 }
528
529 if (!FilenameOrUuid)
530 return errorSyntax(USAGE_MODIFYHD, "Disk name or UUID required");
531
532 if (!fModifyDiskType && !fModifyAutoReset && !fModifyCompact && !fModifyResize)
533 return errorSyntax(USAGE_MODIFYHD, "No operation specified");
534
535 /* Depending on the operation the medium must be in the registry or
536 * may be opened on demand. */
537 if (fModifyDiskType || fModifyAutoReset)
538 rc = findMedium(a, FilenameOrUuid, DeviceType_HardDisk, false /* fSilent */, hardDisk);
539 else
540 rc = findOrOpenMedium(a, FilenameOrUuid, DeviceType_HardDisk, AccessMode_ReadWrite,
541 hardDisk, false /* fForceNewUuidOnOpen */, &unknown);
542 if (FAILED(rc))
543 return 1;
544 if (hardDisk.isNull())
545 {
546 RTMsgError("Invalid hard disk reference, avoiding crash");
547 return 1;
548 }
549
550 if (fModifyDiskType)
551 {
552 MediumType_T hddType;
553 CHECK_ERROR(hardDisk, COMGETTER(Type)(&hddType));
554
555 if (hddType != DiskType)
556 CHECK_ERROR(hardDisk, COMSETTER(Type)(DiskType));
557 }
558
559 if (fModifyAutoReset)
560 {
561 CHECK_ERROR(hardDisk, COMSETTER(AutoReset)(AutoReset));
562 }
563
564 if (fModifyCompact)
565 {
566 ComPtr<IProgress> progress;
567 CHECK_ERROR(hardDisk, Compact(progress.asOutParam()));
568 if (SUCCEEDED(rc))
569 rc = showProgress(progress);
570 if (FAILED(rc))
571 {
572 if (rc == E_NOTIMPL)
573 RTMsgError("Compact hard disk operation is not implemented!");
574 else if (rc == VBOX_E_NOT_SUPPORTED)
575 RTMsgError("Compact hard disk operation for this format is not implemented yet!");
576 else if (!progress.isNull())
577 CHECK_PROGRESS_ERROR(progress, ("Failed to compact hard disk"));
578 else
579 RTMsgError("Failed to compact hard disk!");
580 }
581 }
582
583 if (fModifyResize)
584 {
585 ComPtr<IProgress> progress;
586 CHECK_ERROR(hardDisk, Resize(cbResize, progress.asOutParam()));
587 if (SUCCEEDED(rc))
588 rc = showProgress(progress);
589 if (FAILED(rc))
590 {
591 if (rc == E_NOTIMPL)
592 RTMsgError("Resize hard disk operation is not implemented!");
593 else if (rc == VBOX_E_NOT_SUPPORTED)
594 RTMsgError("Resize hard disk operation for this format is not implemented yet!");
595 else
596 CHECK_PROGRESS_ERROR(progress, ("Failed to resize hard disk"));
597 }
598 }
599
600 if (unknown)
601 hardDisk->Close();
602
603 return SUCCEEDED(rc) ? 0 : 1;
604}
605
606static const RTGETOPTDEF g_aCloneHardDiskOptions[] =
607{
608 { "--format", 'o', RTGETOPT_REQ_STRING },
609 { "-format", 'o', RTGETOPT_REQ_STRING },
610 { "--static", 'F', RTGETOPT_REQ_NOTHING },
611 { "-static", 'F', RTGETOPT_REQ_NOTHING },
612 { "--existing", 'E', RTGETOPT_REQ_NOTHING },
613 { "--variant", 'm', RTGETOPT_REQ_STRING },
614 { "-variant", 'm', RTGETOPT_REQ_STRING },
615};
616
617int handleCloneHardDisk(HandlerArg *a)
618{
619 HRESULT rc;
620 int vrc;
621 const char *pszSrc = NULL;
622 const char *pszDst = NULL;
623 Bstr format;
624 MediumVariant_T DiskVariant = MediumVariant_Standard;
625 bool fExisting = false;
626
627 int c;
628 RTGETOPTUNION ValueUnion;
629 RTGETOPTSTATE GetState;
630 // start at 0 because main() has hacked both the argc and argv given to us
631 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneHardDiskOptions, RT_ELEMENTS(g_aCloneHardDiskOptions),
632 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
633 while ((c = RTGetOpt(&GetState, &ValueUnion)))
634 {
635 switch (c)
636 {
637 case 'o': // --format
638 format = ValueUnion.psz;
639 break;
640
641 case 'F': // --static
642 {
643 unsigned uDiskVariant = (unsigned)DiskVariant;
644 uDiskVariant |= MediumVariant_Fixed;
645 DiskVariant = (MediumVariant_T)uDiskVariant;
646 break;
647 }
648
649 case 'E': // --existing
650 fExisting = true;
651 break;
652
653 case 'm': // --variant
654 vrc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
655 if (RT_FAILURE(vrc))
656 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
657 break;
658
659 case VINF_GETOPT_NOT_OPTION:
660 if (!pszSrc)
661 pszSrc = ValueUnion.psz;
662 else if (!pszDst)
663 pszDst = ValueUnion.psz;
664 else
665 return errorSyntax(USAGE_CLONEHD, "Invalid parameter '%s'", ValueUnion.psz);
666 break;
667
668 default:
669 if (c > 0)
670 {
671 if (RT_C_IS_GRAPH(c))
672 return errorSyntax(USAGE_CLONEHD, "unhandled option: -%c", c);
673 else
674 return errorSyntax(USAGE_CLONEHD, "unhandled option: %i", c);
675 }
676 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
677 return errorSyntax(USAGE_CLONEHD, "unknown option: %s", ValueUnion.psz);
678 else if (ValueUnion.pDef)
679 return errorSyntax(USAGE_CLONEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
680 else
681 return errorSyntax(USAGE_CLONEHD, "error: %Rrs", c);
682 }
683 }
684
685 if (!pszSrc)
686 return errorSyntax(USAGE_CLONEHD, "Mandatory UUID or input file parameter missing");
687 if (!pszDst)
688 return errorSyntax(USAGE_CLONEHD, "Mandatory output file parameter missing");
689 if (fExisting && (!format.isEmpty() || DiskVariant != MediumType_Normal))
690 return errorSyntax(USAGE_CLONEHD, "Specified options which cannot be used with --existing");
691
692 ComPtr<IMedium> srcDisk;
693 ComPtr<IMedium> dstDisk;
694 bool fSrcUnknown = false;
695 bool fDstUnknown = false;
696
697 rc = findOrOpenMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly,
698 srcDisk, false /* fForceNewUuidOnOpen */, &fSrcUnknown);
699 if (FAILED(rc))
700 return 1;
701
702 do
703 {
704 /* open/create destination hard disk */
705 if (fExisting)
706 {
707 rc = findOrOpenMedium(a, pszDst, DeviceType_HardDisk, AccessMode_ReadWrite,
708 dstDisk, false /* fForceNewUuidOnOpen */, &fDstUnknown);
709 if (FAILED(rc))
710 break;
711
712 /* Perform accessibility check now. */
713 MediumState_T state;
714 CHECK_ERROR_BREAK(dstDisk, RefreshState(&state));
715 CHECK_ERROR_BREAK(dstDisk, COMGETTER(Format)(format.asOutParam()));
716 }
717 else
718 {
719 /* use the format of the source hard disk if unspecified */
720 if (format.isEmpty())
721 CHECK_ERROR_BREAK(srcDisk, COMGETTER(Format)(format.asOutParam()));
722 rc = createHardDisk(a, Utf8Str(format).c_str(), pszDst, dstDisk);
723 if (FAILED(rc))
724 break;
725 fDstUnknown = true;
726 }
727
728 ComPtr<IProgress> progress;
729 CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, DiskVariant, NULL, progress.asOutParam()));
730
731 rc = showProgress(progress);
732 CHECK_PROGRESS_ERROR_BREAK(progress, ("Failed to clone hard disk"));
733
734 Bstr uuid;
735 CHECK_ERROR_BREAK(dstDisk, COMGETTER(Id)(uuid.asOutParam()));
736
737 RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
738 format.raw(), Utf8Str(uuid).c_str());
739 }
740 while (0);
741
742 if (fDstUnknown && !dstDisk.isNull())
743 {
744 /* forget the created clone */
745 dstDisk->Close();
746 }
747 if (fSrcUnknown)
748 {
749 /* close the unknown hard disk to forget it again */
750 srcDisk->Close();
751 }
752
753 return SUCCEEDED(rc) ? 0 : 1;
754}
755
756static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
757{
758 { "--format", 'o', RTGETOPT_REQ_STRING },
759 { "-format", 'o', RTGETOPT_REQ_STRING },
760 { "--static", 'F', RTGETOPT_REQ_NOTHING },
761 { "-static", 'F', RTGETOPT_REQ_NOTHING },
762 { "--variant", 'm', RTGETOPT_REQ_STRING },
763 { "-variant", 'm', RTGETOPT_REQ_STRING },
764 { "--uuid", 'u', RTGETOPT_REQ_STRING },
765};
766
767RTEXITCODE handleConvertFromRaw(int argc, char *argv[])
768{
769 int rc = VINF_SUCCESS;
770 bool fReadFromStdIn = false;
771 const char *format = "VDI";
772 const char *srcfilename = NULL;
773 const char *dstfilename = NULL;
774 const char *filesize = NULL;
775 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
776 void *pvBuf = NULL;
777 RTUUID uuid;
778 PCRTUUID pUuid = NULL;
779
780 int c;
781 RTGETOPTUNION ValueUnion;
782 RTGETOPTSTATE GetState;
783 // start at 0 because main() has hacked both the argc and argv given to us
784 RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
785 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
786 while ((c = RTGetOpt(&GetState, &ValueUnion)))
787 {
788 switch (c)
789 {
790 case 'u': // --uuid
791 if (RT_FAILURE(RTUuidFromStr(&uuid, ValueUnion.psz)))
792 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid UUID '%s'", ValueUnion.psz);
793 pUuid = &uuid;
794 break;
795 case 'o': // --format
796 format = ValueUnion.psz;
797 break;
798
799 case 'm': // --variant
800 MediumVariant_T DiskVariant;
801 rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
802 if (RT_FAILURE(rc))
803 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
804 /// @todo cleaner solution than assuming 1:1 mapping?
805 uImageFlags = (unsigned)DiskVariant;
806 break;
807
808 case VINF_GETOPT_NOT_OPTION:
809 if (!srcfilename)
810 {
811 srcfilename = ValueUnion.psz;
812 fReadFromStdIn = !strcmp(srcfilename, "stdin");
813 }
814 else if (!dstfilename)
815 dstfilename = ValueUnion.psz;
816 else if (fReadFromStdIn && !filesize)
817 filesize = ValueUnion.psz;
818 else
819 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
820 break;
821
822 default:
823 return errorGetOpt(USAGE_CONVERTFROMRAW, c, &ValueUnion);
824 }
825 }
826
827 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
828 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
829 RTStrmPrintf(g_pStdErr, "Converting from raw image file=\"%s\" to file=\"%s\"...\n",
830 srcfilename, dstfilename);
831
832 PVBOXHDD pDisk = NULL;
833
834 PVDINTERFACE pVDIfs = NULL;
835 VDINTERFACEERROR vdInterfaceError;
836 vdInterfaceError.pfnError = handleVDError;
837 vdInterfaceError.pfnMessage = NULL;
838
839 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
840 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
841 AssertRC(rc);
842
843 /* open raw image file. */
844 RTFILE File;
845 if (fReadFromStdIn)
846 rc = RTFileFromNative(&File, RTFILE_NATIVE_STDIN);
847 else
848 rc = RTFileOpen(&File, srcfilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
849 if (RT_FAILURE(rc))
850 {
851 RTMsgError("Cannot open file \"%s\": %Rrc", srcfilename, rc);
852 goto out;
853 }
854
855 uint64_t cbFile;
856 /* get image size. */
857 if (fReadFromStdIn)
858 cbFile = RTStrToUInt64(filesize);
859 else
860 rc = RTFileGetSize(File, &cbFile);
861 if (RT_FAILURE(rc))
862 {
863 RTMsgError("Cannot get image size for file \"%s\": %Rrc", srcfilename, rc);
864 goto out;
865 }
866
867 RTStrmPrintf(g_pStdErr, "Creating %s image with size %RU64 bytes (%RU64MB)...\n",
868 (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
869 char pszComment[256];
870 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
871 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
872 if (RT_FAILURE(rc))
873 {
874 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
875 goto out;
876 }
877
878 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
879 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
880 VDGEOMETRY PCHS, LCHS;
881 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
882 PCHS.cHeads = 16;
883 PCHS.cSectors = 63;
884 LCHS.cCylinders = 0;
885 LCHS.cHeads = 0;
886 LCHS.cSectors = 0;
887 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
888 uImageFlags, pszComment, &PCHS, &LCHS, pUuid,
889 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
890 if (RT_FAILURE(rc))
891 {
892 RTMsgError("Cannot create the disk image \"%s\": %Rrc", dstfilename, rc);
893 goto out;
894 }
895
896 size_t cbBuffer;
897 cbBuffer = _1M;
898 pvBuf = RTMemAlloc(cbBuffer);
899 if (!pvBuf)
900 {
901 rc = VERR_NO_MEMORY;
902 RTMsgError("Out of memory allocating buffers for image \"%s\": %Rrc", dstfilename, rc);
903 goto out;
904 }
905
906 uint64_t offFile;
907 offFile = 0;
908 while (offFile < cbFile)
909 {
910 size_t cbRead;
911 size_t cbToRead;
912 cbRead = 0;
913 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
914 cbBuffer : (size_t)(cbFile - offFile);
915 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
916 if (RT_FAILURE(rc) || !cbRead)
917 break;
918 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
919 if (RT_FAILURE(rc))
920 {
921 RTMsgError("Failed to write to disk image \"%s\": %Rrc", dstfilename, rc);
922 goto out;
923 }
924 offFile += cbRead;
925 }
926
927out:
928 if (pvBuf)
929 RTMemFree(pvBuf);
930 if (pDisk)
931 VDClose(pDisk, RT_FAILURE(rc));
932 if (File != NIL_RTFILE)
933 RTFileClose(File);
934
935 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
936}
937
938static const RTGETOPTDEF g_aShowHardDiskInfoOptions[] =
939{
940 { "--dummy", 256, RTGETOPT_REQ_NOTHING }, // placeholder for C++
941};
942
943int handleShowHardDiskInfo(HandlerArg *a)
944{
945 HRESULT rc;
946 const char *FilenameOrUuid = NULL;
947
948 int c;
949 RTGETOPTUNION ValueUnion;
950 RTGETOPTSTATE GetState;
951 // start at 0 because main() has hacked both the argc and argv given to us
952 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowHardDiskInfoOptions, RT_ELEMENTS(g_aShowHardDiskInfoOptions),
953 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
954 while ((c = RTGetOpt(&GetState, &ValueUnion)))
955 {
956 switch (c)
957 {
958 case VINF_GETOPT_NOT_OPTION:
959 if (!FilenameOrUuid)
960 FilenameOrUuid = ValueUnion.psz;
961 else
962 return errorSyntax(USAGE_SHOWHDINFO, "Invalid parameter '%s'", ValueUnion.psz);
963 break;
964
965 default:
966 if (c > 0)
967 {
968 if (RT_C_IS_PRINT(c))
969 return errorSyntax(USAGE_SHOWHDINFO, "Invalid option -%c", c);
970 else
971 return errorSyntax(USAGE_SHOWHDINFO, "Invalid option case %i", c);
972 }
973 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
974 return errorSyntax(USAGE_SHOWHDINFO, "unknown option: %s\n", ValueUnion.psz);
975 else if (ValueUnion.pDef)
976 return errorSyntax(USAGE_SHOWHDINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
977 else
978 return errorSyntax(USAGE_SHOWHDINFO, "error: %Rrs", c);
979 }
980 }
981
982 /* check for required options */
983 if (!FilenameOrUuid)
984 return errorSyntax(USAGE_SHOWHDINFO, "Disk name or UUID required");
985
986 ComPtr<IMedium> hardDisk;
987 bool unknown = false;
988
989 rc = findOrOpenMedium(a, FilenameOrUuid, DeviceType_HardDisk, AccessMode_ReadOnly,
990 hardDisk, false /* fForceNewUuidOnOpen */, &unknown);
991 if (FAILED(rc))
992 return 1;
993
994 do
995 {
996 Bstr uuid;
997 hardDisk->COMGETTER(Id)(uuid.asOutParam());
998 RTPrintf("UUID: %s\n", Utf8Str(uuid).c_str());
999
1000 /* check for accessibility */
1001 /// @todo NEWMEDIA check accessibility of all parents
1002 /// @todo NEWMEDIA print the full state value
1003 MediumState_T state;
1004 CHECK_ERROR_BREAK(hardDisk, RefreshState(&state));
1005 RTPrintf("Accessible: %s\n", state != MediumState_Inaccessible ? "yes" : "no");
1006
1007 if (state == MediumState_Inaccessible)
1008 {
1009 Bstr err;
1010 CHECK_ERROR_BREAK(hardDisk, COMGETTER(LastAccessError)(err.asOutParam()));
1011 RTPrintf("Access Error: %ls\n", err.raw());
1012 }
1013
1014 Bstr description;
1015 hardDisk->COMGETTER(Description)(description.asOutParam());
1016 if (!description.isEmpty())
1017 {
1018 RTPrintf("Description: %ls\n", description.raw());
1019 }
1020
1021 LONG64 logicalSize;
1022 hardDisk->COMGETTER(LogicalSize)(&logicalSize);
1023 RTPrintf("Logical size: %lld MBytes\n", logicalSize >> 20);
1024 LONG64 actualSize;
1025 hardDisk->COMGETTER(Size)(&actualSize);
1026 RTPrintf("Current size on disk: %lld MBytes\n", actualSize >> 20);
1027
1028 ComPtr <IMedium> parent;
1029 hardDisk->COMGETTER(Parent)(parent.asOutParam());
1030
1031 MediumType_T type;
1032 hardDisk->COMGETTER(Type)(&type);
1033 const char *typeStr = "unknown";
1034 switch (type)
1035 {
1036 case MediumType_Normal:
1037 if (!parent.isNull())
1038 typeStr = "normal (differencing)";
1039 else
1040 typeStr = "normal (base)";
1041 break;
1042 case MediumType_Immutable:
1043 typeStr = "immutable";
1044 break;
1045 case MediumType_Writethrough:
1046 typeStr = "writethrough";
1047 break;
1048 case MediumType_Shareable:
1049 typeStr = "shareable";
1050 break;
1051 case MediumType_Readonly:
1052 typeStr = "readonly";
1053 break;
1054 case MediumType_MultiAttach:
1055 typeStr = "multiattach";
1056 break;
1057 }
1058 RTPrintf("Type: %s\n", typeStr);
1059
1060 Bstr format;
1061 hardDisk->COMGETTER(Format)(format.asOutParam());
1062 RTPrintf("Storage format: %ls\n", format.raw());
1063 ULONG variant;
1064 hardDisk->COMGETTER(Variant)(&variant);
1065 const char *variantStr = "unknown";
1066 switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
1067 {
1068 case MediumVariant_VmdkSplit2G:
1069 variantStr = "split2G";
1070 break;
1071 case MediumVariant_VmdkStreamOptimized:
1072 variantStr = "streamOptimized";
1073 break;
1074 case MediumVariant_VmdkESX:
1075 variantStr = "ESX";
1076 break;
1077 case MediumVariant_Standard:
1078 variantStr = "default";
1079 break;
1080 }
1081 const char *variantTypeStr = "dynamic";
1082 if (variant & MediumVariant_Fixed)
1083 variantTypeStr = "fixed";
1084 else if (variant & MediumVariant_Diff)
1085 variantTypeStr = "differencing";
1086 RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
1087
1088 /// @todo also dump config parameters (iSCSI)
1089
1090 if (!unknown)
1091 {
1092 com::SafeArray<BSTR> machineIds;
1093 hardDisk->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1094 for (size_t j = 0; j < machineIds.size(); ++ j)
1095 {
1096 ComPtr<IMachine> machine;
1097 CHECK_ERROR(a->virtualBox, FindMachine(machineIds[j], machine.asOutParam()));
1098 ASSERT(machine);
1099 Bstr name;
1100 machine->COMGETTER(Name)(name.asOutParam());
1101 machine->COMGETTER(Id)(uuid.asOutParam());
1102 RTPrintf("%s%ls (UUID: %ls)\n",
1103 j == 0 ? "In use by VMs: " : " ",
1104 name.raw(), machineIds[j]);
1105 }
1106 /// @todo NEWMEDIA check usage in snapshots too
1107 /// @todo NEWMEDIA also list children
1108 }
1109
1110 Bstr loc;
1111 hardDisk->COMGETTER(Location)(loc.asOutParam());
1112 RTPrintf("Location: %ls\n", loc.raw());
1113
1114 /* print out information specific for differencing hard disks */
1115 if (!parent.isNull())
1116 {
1117 BOOL autoReset = FALSE;
1118 hardDisk->COMGETTER(AutoReset)(&autoReset);
1119 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1120 }
1121 }
1122 while (0);
1123
1124 if (unknown)
1125 {
1126 /* close the unknown hard disk to forget it again */
1127 hardDisk->Close();
1128 }
1129
1130 return SUCCEEDED(rc) ? 0 : 1;
1131}
1132
1133static const RTGETOPTDEF g_aCloseMediumOptions[] =
1134{
1135 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1136 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1137 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1138 { "--delete", 'r', RTGETOPT_REQ_NOTHING },
1139};
1140
1141int handleCloseMedium(HandlerArg *a)
1142{
1143 HRESULT rc = S_OK;
1144 enum {
1145 CMD_NONE,
1146 CMD_DISK,
1147 CMD_DVD,
1148 CMD_FLOPPY
1149 } cmd = CMD_NONE;
1150 const char *FilenameOrUuid = NULL;
1151 bool fDelete = false;
1152
1153 int c;
1154 RTGETOPTUNION ValueUnion;
1155 RTGETOPTSTATE GetState;
1156 // start at 0 because main() has hacked both the argc and argv given to us
1157 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
1158 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1159 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1160 {
1161 switch (c)
1162 {
1163 case 'd': // disk
1164 if (cmd != CMD_NONE)
1165 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1166 cmd = CMD_DISK;
1167 break;
1168
1169 case 'D': // DVD
1170 if (cmd != CMD_NONE)
1171 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1172 cmd = CMD_DVD;
1173 break;
1174
1175 case 'f': // floppy
1176 if (cmd != CMD_NONE)
1177 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1178 cmd = CMD_FLOPPY;
1179 break;
1180
1181 case 'r': // --delete
1182 fDelete = true;
1183 break;
1184
1185 case VINF_GETOPT_NOT_OPTION:
1186 if (!FilenameOrUuid)
1187 FilenameOrUuid = ValueUnion.psz;
1188 else
1189 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1190 break;
1191
1192 default:
1193 if (c > 0)
1194 {
1195 if (RT_C_IS_PRINT(c))
1196 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option -%c", c);
1197 else
1198 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option case %i", c);
1199 }
1200 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1201 return errorSyntax(USAGE_CLOSEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1202 else if (ValueUnion.pDef)
1203 return errorSyntax(USAGE_CLOSEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1204 else
1205 return errorSyntax(USAGE_CLOSEMEDIUM, "error: %Rrs", c);
1206 }
1207 }
1208
1209 /* check for required options */
1210 if (cmd == CMD_NONE)
1211 return errorSyntax(USAGE_CLOSEMEDIUM, "Command variant disk/dvd/floppy required");
1212 if (!FilenameOrUuid)
1213 return errorSyntax(USAGE_CLOSEMEDIUM, "Disk name or UUID required");
1214
1215 ComPtr<IMedium> medium;
1216
1217 if (cmd == CMD_DISK)
1218 rc = findMedium(a, FilenameOrUuid, DeviceType_HardDisk, false /* fSilent */, medium);
1219 else if (cmd == CMD_DVD)
1220 rc = findMedium(a, FilenameOrUuid, DeviceType_DVD, false /* fSilent */, medium);
1221 else if (cmd == CMD_FLOPPY)
1222 rc = findMedium(a, FilenameOrUuid, DeviceType_Floppy, false /* fSilent */, medium);
1223
1224 if (SUCCEEDED(rc) && medium)
1225 {
1226 if (fDelete)
1227 {
1228 ComPtr<IProgress> progress;
1229 CHECK_ERROR(medium, DeleteStorage(progress.asOutParam()));
1230 if (SUCCEEDED(rc))
1231 {
1232 rc = showProgress(progress);
1233 CHECK_PROGRESS_ERROR(progress, ("Failed to delete medium"));
1234 }
1235 else
1236 RTMsgError("Failed to delete medium. Error code %Rrc", rc);
1237 }
1238 CHECK_ERROR(medium, Close());
1239 }
1240
1241 return SUCCEEDED(rc) ? 0 : 1;
1242}
1243#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

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