VirtualBox

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

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

use openMedium instead of findMedium

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

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