VirtualBox

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

最後變更 在這個檔案從35037是 35037,由 vboxsync 提交於 14 年 前

Frontends/VBoxManage: remove no longer reliable options from clonehd (as done earlier with createhd)

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

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