VirtualBox

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

Last change on this file since 41236 was 41236, checked in by vboxsync, 13 years ago

Small { formatting change for 6130

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