VirtualBox

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

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

Replace calls of findMedium with openMedium, remove findMedium references in idl and definitions/declarations

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