VirtualBox

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

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

Small changes for 6130

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