VirtualBox

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

Last change on this file since 72888 was 72883, checked in by vboxsync, 7 years ago

Main/Medium: add API flag for creating formatted floppy images
Frontends/VBoxManage: matching CLI code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.3 KB
Line 
1/* $Id: VBoxManageDisk.cpp 72883 2018-07-04 15:22:02Z vboxsync $ */
2/** @file
3 * VBoxManage - The disk/medium related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#include <VBox/com/com.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/asm.h>
31#include <iprt/file.h>
32#include <iprt/path.h>
33#include <iprt/param.h>
34#include <iprt/stream.h>
35#include <iprt/string.h>
36#include <iprt/ctype.h>
37#include <iprt/getopt.h>
38#include <VBox/log.h>
39#include <VBox/vd.h>
40
41#include "VBoxManage.h"
42using namespace com;
43
44
45// funcs
46///////////////////////////////////////////////////////////////////////////////
47
48
49static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
50{
51 RT_NOREF(pvUser);
52 RTMsgErrorV(pszFormat, va);
53 RTMsgError("Error code %Rrc at %s(%u) in function %s", rc, RT_SRC_POS_ARGS);
54}
55
56static int parseMediumVariant(const char *psz, MediumVariant_T *pMediumVariant)
57{
58 int rc = VINF_SUCCESS;
59 unsigned uMediumVariant = (unsigned)(*pMediumVariant);
60 while (psz && *psz && RT_SUCCESS(rc))
61 {
62 size_t len;
63 const char *pszComma = strchr(psz, ',');
64 if (pszComma)
65 len = pszComma - psz;
66 else
67 len = strlen(psz);
68 if (len > 0)
69 {
70 // Parsing is intentionally inconsistent: "standard" resets the
71 // variant, whereas the other flags are cumulative.
72 if (!RTStrNICmp(psz, "standard", len))
73 uMediumVariant = MediumVariant_Standard;
74 else if ( !RTStrNICmp(psz, "fixed", len)
75 || !RTStrNICmp(psz, "static", len))
76 uMediumVariant |= MediumVariant_Fixed;
77 else if (!RTStrNICmp(psz, "Diff", len))
78 uMediumVariant |= MediumVariant_Diff;
79 else if (!RTStrNICmp(psz, "split2g", len))
80 uMediumVariant |= MediumVariant_VmdkSplit2G;
81 else if ( !RTStrNICmp(psz, "stream", len)
82 || !RTStrNICmp(psz, "streamoptimized", len))
83 uMediumVariant |= MediumVariant_VmdkStreamOptimized;
84 else if (!RTStrNICmp(psz, "esx", len))
85 uMediumVariant |= MediumVariant_VmdkESX;
86 else if (!RTStrNICmp(psz, "formatted", len))
87 uMediumVariant |= MediumVariant_Formatted;
88 else
89 rc = VERR_PARSE_ERROR;
90 }
91 if (pszComma)
92 psz += len + 1;
93 else
94 psz += len;
95 }
96
97 if (RT_SUCCESS(rc))
98 *pMediumVariant = (MediumVariant_T)uMediumVariant;
99 return rc;
100}
101
102int parseMediumType(const char *psz, MediumType_T *penmMediumType)
103{
104 int rc = VINF_SUCCESS;
105 MediumType_T enmMediumType = MediumType_Normal;
106 if (!RTStrICmp(psz, "normal"))
107 enmMediumType = MediumType_Normal;
108 else if (!RTStrICmp(psz, "immutable"))
109 enmMediumType = MediumType_Immutable;
110 else if (!RTStrICmp(psz, "writethrough"))
111 enmMediumType = MediumType_Writethrough;
112 else if (!RTStrICmp(psz, "shareable"))
113 enmMediumType = MediumType_Shareable;
114 else if (!RTStrICmp(psz, "readonly"))
115 enmMediumType = MediumType_Readonly;
116 else if (!RTStrICmp(psz, "multiattach"))
117 enmMediumType = MediumType_MultiAttach;
118 else
119 rc = VERR_PARSE_ERROR;
120
121 if (RT_SUCCESS(rc))
122 *penmMediumType = enmMediumType;
123 return rc;
124}
125
126/** @todo move this into getopt, as getting bool values is generic */
127int parseBool(const char *psz, bool *pb)
128{
129 int rc = VINF_SUCCESS;
130 if ( !RTStrICmp(psz, "on")
131 || !RTStrICmp(psz, "yes")
132 || !RTStrICmp(psz, "true")
133 || !RTStrICmp(psz, "1")
134 || !RTStrICmp(psz, "enable")
135 || !RTStrICmp(psz, "enabled"))
136 {
137 *pb = true;
138 }
139 else if ( !RTStrICmp(psz, "off")
140 || !RTStrICmp(psz, "no")
141 || !RTStrICmp(psz, "false")
142 || !RTStrICmp(psz, "0")
143 || !RTStrICmp(psz, "disable")
144 || !RTStrICmp(psz, "disabled"))
145 {
146 *pb = false;
147 }
148 else
149 rc = VERR_PARSE_ERROR;
150
151 return rc;
152}
153
154HRESULT openMedium(HandlerArg *a, const char *pszFilenameOrUuid,
155 DeviceType_T enmDevType, AccessMode_T enmAccessMode,
156 ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
157 bool fSilent)
158{
159 HRESULT rc;
160 Guid id(pszFilenameOrUuid);
161 char szFilenameAbs[RTPATH_MAX] = "";
162
163 /* If it is no UUID, convert the filename to an absolute one. */
164 if (!id.isValid())
165 {
166 int irc = RTPathAbs(pszFilenameOrUuid, szFilenameAbs, sizeof(szFilenameAbs));
167 if (RT_FAILURE(irc))
168 {
169 if (!fSilent)
170 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilenameOrUuid);
171 return E_FAIL;
172 }
173 pszFilenameOrUuid = szFilenameAbs;
174 }
175
176 if (!fSilent)
177 CHECK_ERROR(a->virtualBox, OpenMedium(Bstr(pszFilenameOrUuid).raw(),
178 enmDevType,
179 enmAccessMode,
180 fForceNewUuidOnOpen,
181 pMedium.asOutParam()));
182 else
183 rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
184 enmDevType,
185 enmAccessMode,
186 fForceNewUuidOnOpen,
187 pMedium.asOutParam());
188
189 return rc;
190}
191
192static HRESULT createMedium(HandlerArg *a, const char *pszFormat,
193 const char *pszFilename, DeviceType_T enmDevType,
194 AccessMode_T enmAccessMode, ComPtr<IMedium> &pMedium)
195{
196 HRESULT rc;
197 char szFilenameAbs[RTPATH_MAX] = "";
198
199 /** @todo laziness shortcut. should really check the MediumFormatCapabilities */
200 if (RTStrICmp(pszFormat, "iSCSI"))
201 {
202 int irc = RTPathAbs(pszFilename, szFilenameAbs, sizeof(szFilenameAbs));
203 if (RT_FAILURE(irc))
204 {
205 RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilename);
206 return E_FAIL;
207 }
208 pszFilename = szFilenameAbs;
209 }
210
211 CHECK_ERROR(a->virtualBox, CreateMedium(Bstr(pszFormat).raw(),
212 Bstr(pszFilename).raw(),
213 enmAccessMode,
214 enmDevType,
215 pMedium.asOutParam()));
216 return rc;
217}
218
219static const RTGETOPTDEF g_aCreateMediumOptions[] =
220{
221 { "disk", 'H', RTGETOPT_REQ_NOTHING },
222 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
223 { "floppy", 'L', RTGETOPT_REQ_NOTHING },
224 { "--filename", 'f', RTGETOPT_REQ_STRING },
225 { "-filename", 'f', RTGETOPT_REQ_STRING }, // deprecated
226 { "--diffparent", 'd', RTGETOPT_REQ_STRING },
227 { "--size", 's', RTGETOPT_REQ_UINT64 },
228 { "-size", 's', RTGETOPT_REQ_UINT64 }, // deprecated
229 { "--sizebyte", 'S', RTGETOPT_REQ_UINT64 },
230 { "--format", 'o', RTGETOPT_REQ_STRING },
231 { "-format", 'o', RTGETOPT_REQ_STRING }, // deprecated
232 { "--static", 'F', RTGETOPT_REQ_NOTHING },
233 { "-static", 'F', RTGETOPT_REQ_NOTHING }, // deprecated
234 { "--variant", 'm', RTGETOPT_REQ_STRING },
235 { "-variant", 'm', RTGETOPT_REQ_STRING }, // deprecated
236};
237
238RTEXITCODE handleCreateMedium(HandlerArg *a)
239{
240 HRESULT rc;
241 int vrc;
242 const char *filename = NULL;
243 const char *diffparent = NULL;
244 uint64_t size = 0;
245 enum {
246 CMD_NONE,
247 CMD_DISK,
248 CMD_DVD,
249 CMD_FLOPPY
250 } cmd = CMD_NONE;
251 const char *format = NULL;
252 bool fBase = true;
253 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
254
255 int c;
256 RTGETOPTUNION ValueUnion;
257 RTGETOPTSTATE GetState;
258 // start at 0 because main() has hacked both the argc and argv given to us
259 RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateMediumOptions, RT_ELEMENTS(g_aCreateMediumOptions),
260 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
261 while ((c = RTGetOpt(&GetState, &ValueUnion)))
262 {
263 switch (c)
264 {
265 case 'H': // disk
266 if (cmd != CMD_NONE)
267 return errorSyntax(USAGE_CREATEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
268 cmd = CMD_DISK;
269 break;
270
271 case 'D': // DVD
272 if (cmd != CMD_NONE)
273 return errorSyntax(USAGE_CREATEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
274 cmd = CMD_DVD;
275 break;
276
277 case 'L': // floppy
278 if (cmd != CMD_NONE)
279 return errorSyntax(USAGE_CREATEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
280 cmd = CMD_FLOPPY;
281 break;
282
283 case 'f': // --filename
284 filename = ValueUnion.psz;
285 break;
286
287 case 'd': // --diffparent
288 diffparent = ValueUnion.psz;
289 fBase = false;
290 break;
291
292 case 's': // --size
293 size = ValueUnion.u64 * _1M;
294 break;
295
296 case 'S': // --sizebyte
297 size = ValueUnion.u64;
298 break;
299
300 case 'o': // --format
301 format = ValueUnion.psz;
302 break;
303
304 case 'F': // --static ("fixed"/"flat")
305 {
306 unsigned uMediumVariant = (unsigned)enmMediumVariant;
307 uMediumVariant |= MediumVariant_Fixed;
308 enmMediumVariant = (MediumVariant_T)uMediumVariant;
309 break;
310 }
311
312 case 'm': // --variant
313 vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
314 if (RT_FAILURE(vrc))
315 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
316 break;
317
318 case VINF_GETOPT_NOT_OPTION:
319 return errorSyntax(USAGE_CREATEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
320
321 default:
322 if (c > 0)
323 {
324 if (RT_C_IS_PRINT(c))
325 return errorSyntax(USAGE_CREATEMEDIUM, "Invalid option -%c", c);
326 else
327 return errorSyntax(USAGE_CREATEMEDIUM, "Invalid option case %i", c);
328 }
329 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
330 return errorSyntax(USAGE_CREATEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
331 else if (ValueUnion.pDef)
332 return errorSyntax(USAGE_CREATEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
333 else
334 return errorSyntax(USAGE_CREATEMEDIUM, "error: %Rrs", c);
335 }
336 }
337
338 /* check the outcome */
339 if (cmd == CMD_NONE)
340 cmd = CMD_DISK;
341 ComPtr<IMedium> pParentMedium;
342 if (fBase)
343 {
344 if ( !filename
345 || !*filename
346 || size == 0)
347 return errorSyntax(USAGE_CREATEMEDIUM, "Parameters --filename and --size are required");
348 if (!format || !*format)
349 {
350 if (cmd == CMD_DISK)
351 format = "VDI";
352 else if (cmd == CMD_DVD || cmd == CMD_FLOPPY)
353 {
354 format = "RAW";
355 unsigned uMediumVariant = (unsigned)enmMediumVariant;
356 uMediumVariant |= MediumVariant_Fixed;
357 enmMediumVariant = (MediumVariant_T)uMediumVariant;
358 }
359 }
360 }
361 else
362 {
363 if ( !filename
364 || !*filename)
365 return errorSyntax(USAGE_CREATEMEDIUM, "Parameters --filename is required");
366 size = 0;
367 if (cmd != CMD_DISK)
368 return errorSyntax(USAGE_CREATEMEDIUM, "Creating a differencing medium is only supported for hard disks");
369 enmMediumVariant = MediumVariant_Diff;
370 if (!format || !*format)
371 {
372 const char *pszExt = RTPathSuffix(filename);
373 /* Skip over . if there is an extension. */
374 if (pszExt)
375 pszExt++;
376 if (!pszExt || !*pszExt)
377 format = "VDI";
378 else
379 format = pszExt;
380 }
381 rc = openMedium(a, diffparent, DeviceType_HardDisk,
382 AccessMode_ReadWrite, pParentMedium,
383 false /* fForceNewUuidOnOpen */, false /* fSilent */);
384 if (FAILED(rc))
385 return RTEXITCODE_FAILURE;
386 if (pParentMedium.isNull())
387 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid parent hard disk reference, avoiding crash");
388 MediumState_T state;
389 CHECK_ERROR(pParentMedium, COMGETTER(State)(&state));
390 if (FAILED(rc))
391 return RTEXITCODE_FAILURE;
392 if (state == MediumState_Inaccessible)
393 {
394 CHECK_ERROR(pParentMedium, RefreshState(&state));
395 if (FAILED(rc))
396 return RTEXITCODE_FAILURE;
397 }
398 }
399 /* check for filename extension */
400 /** @todo use IMediumFormat to cover all extensions generically */
401 Utf8Str strName(filename);
402 if (!RTPathHasSuffix(strName.c_str()))
403 {
404 Utf8Str strFormat(format);
405 if (cmd == CMD_DISK)
406 {
407 if (strFormat.compare("vmdk", RTCString::CaseInsensitive) == 0)
408 strName.append(".vmdk");
409 else if (strFormat.compare("vhd", RTCString::CaseInsensitive) == 0)
410 strName.append(".vhd");
411 else
412 strName.append(".vdi");
413 } else if (cmd == CMD_DVD)
414 strName.append(".iso");
415 else if (cmd == CMD_FLOPPY)
416 strName.append(".img");
417 filename = strName.c_str();
418 }
419
420 ComPtr<IMedium> pMedium;
421 if (cmd == CMD_DISK)
422 rc = createMedium(a, format, filename, DeviceType_HardDisk,
423 AccessMode_ReadWrite, pMedium);
424 else if (cmd == CMD_DVD)
425 rc = createMedium(a, format, filename, DeviceType_DVD,
426 AccessMode_ReadOnly, pMedium);
427 else if (cmd == CMD_FLOPPY)
428 rc = createMedium(a, format, filename, DeviceType_Floppy,
429 AccessMode_ReadWrite, pMedium);
430 else
431 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
432
433 if (SUCCEEDED(rc) && pMedium)
434 {
435 ComPtr<IProgress> pProgress;
436 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
437
438 for (ULONG i = 0; i < l_variants.size(); ++i)
439 {
440 ULONG temp = enmMediumVariant;
441 temp &= 1<<i;
442 l_variants [i] = (MediumVariant_T)temp;
443 }
444
445 if (fBase)
446 CHECK_ERROR(pMedium, CreateBaseStorage(size, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
447 else
448 CHECK_ERROR(pParentMedium, CreateDiffStorage(pMedium, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
449 if (SUCCEEDED(rc) && pProgress)
450 {
451 rc = showProgress(pProgress);
452 CHECK_PROGRESS_ERROR(pProgress, ("Failed to create medium"));
453 }
454 }
455
456 if (SUCCEEDED(rc) && pMedium)
457 {
458 Bstr uuid;
459 CHECK_ERROR(pMedium, COMGETTER(Id)(uuid.asOutParam()));
460 RTPrintf("Medium created. UUID: %s\n", Utf8Str(uuid).c_str());
461
462 //CHECK_ERROR(pMedium, Close());
463 }
464 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
465}
466
467static const RTGETOPTDEF g_aModifyMediumOptions[] =
468{
469 { "disk", 'H', RTGETOPT_REQ_NOTHING },
470 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
471 { "floppy", 'L', RTGETOPT_REQ_NOTHING },
472 { "--type", 't', RTGETOPT_REQ_STRING },
473 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
474 { "settype", 't', RTGETOPT_REQ_STRING }, // deprecated
475 { "--autoreset", 'z', RTGETOPT_REQ_STRING },
476 { "-autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
477 { "autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
478 { "--property", 'p', RTGETOPT_REQ_STRING },
479 { "--compact", 'c', RTGETOPT_REQ_NOTHING },
480 { "-compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
481 { "compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
482 { "--resize", 'r', RTGETOPT_REQ_UINT64 },
483 { "--resizebyte", 'R', RTGETOPT_REQ_UINT64 },
484 { "--move", 'm', RTGETOPT_REQ_STRING },
485 { "--description", 'd', RTGETOPT_REQ_STRING }
486};
487
488RTEXITCODE handleModifyMedium(HandlerArg *a)
489{
490 HRESULT rc;
491 int vrc;
492 enum {
493 CMD_NONE,
494 CMD_DISK,
495 CMD_DVD,
496 CMD_FLOPPY
497 } cmd = CMD_NONE;
498 ComPtr<IMedium> pMedium;
499 MediumType_T enmMediumType = MediumType_Normal; /* Shut up MSC */
500 bool AutoReset = false;
501 SafeArray<BSTR> mediumPropNames;
502 SafeArray<BSTR> mediumPropValues;
503 bool fModifyMediumType = false;
504 bool fModifyAutoReset = false;
505 bool fModifyProperties = false;
506 bool fModifyCompact = false;
507 bool fModifyResize = false;
508 bool fModifyResizeMB = false;
509 bool fModifyLocation = false;
510 bool fModifyDescription = false;
511 uint64_t cbResize = 0;
512 const char *pszFilenameOrUuid = NULL;
513 char *pszNewLocation = NULL;
514
515 int c;
516 RTGETOPTUNION ValueUnion;
517 RTGETOPTSTATE GetState;
518 // start at 0 because main() has hacked both the argc and argv given to us
519 RTGetOptInit(&GetState, a->argc, a->argv, g_aModifyMediumOptions, RT_ELEMENTS(g_aModifyMediumOptions),
520 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
521 while ((c = RTGetOpt(&GetState, &ValueUnion)))
522 {
523 switch (c)
524 {
525 case 'H': // disk
526 if (cmd != CMD_NONE)
527 return errorSyntax(USAGE_MODIFYMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
528 cmd = CMD_DISK;
529 break;
530
531 case 'D': // DVD
532 if (cmd != CMD_NONE)
533 return errorSyntax(USAGE_MODIFYMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
534 cmd = CMD_DVD;
535 break;
536
537 case 'L': // floppy
538 if (cmd != CMD_NONE)
539 return errorSyntax(USAGE_MODIFYMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
540 cmd = CMD_FLOPPY;
541 break;
542
543 case 't': // --type
544 vrc = parseMediumType(ValueUnion.psz, &enmMediumType);
545 if (RT_FAILURE(vrc))
546 return errorArgument("Invalid medium type '%s'", ValueUnion.psz);
547 fModifyMediumType = true;
548 break;
549
550 case 'z': // --autoreset
551 vrc = parseBool(ValueUnion.psz, &AutoReset);
552 if (RT_FAILURE(vrc))
553 return errorArgument("Invalid autoreset parameter '%s'", ValueUnion.psz);
554 fModifyAutoReset = true;
555 break;
556
557 case 'p': // --property
558 {
559 /* Parse 'name=value' */
560 char *pszProperty = RTStrDup(ValueUnion.psz);
561 if (pszProperty)
562 {
563 char *pDelimiter = strchr(pszProperty, '=');
564 if (pDelimiter)
565 {
566 *pDelimiter = '\0';
567
568 Bstr bstrName(pszProperty);
569 Bstr bstrValue(&pDelimiter[1]);
570 bstrName.detachTo(mediumPropNames.appendedRaw());
571 bstrValue.detachTo(mediumPropValues.appendedRaw());
572 fModifyProperties = true;
573 }
574 else
575 {
576 errorArgument("Invalid --property argument '%s'", ValueUnion.psz);
577 rc = E_FAIL;
578 }
579 RTStrFree(pszProperty);
580 }
581 else
582 {
583 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for medium property '%s'\n", ValueUnion.psz);
584 rc = E_FAIL;
585 }
586 break;
587 }
588
589 case 'c': // --compact
590 fModifyCompact = true;
591 break;
592
593 case 'r': // --resize
594 cbResize = ValueUnion.u64 * _1M;
595 fModifyResize = true;
596 fModifyResizeMB = true; // do sanity check!
597 break;
598
599 case 'R': // --resizebyte
600 cbResize = ValueUnion.u64;
601 fModifyResize = true;
602 break;
603
604 case 'm': // --move
605 /* Get a new location */
606 pszNewLocation = RTPathAbsDup(ValueUnion.psz);
607 fModifyLocation = true;
608 break;
609
610 case 'd': // --description
611 /* Get a new description */
612 pszNewLocation = RTStrDup(ValueUnion.psz);
613 fModifyDescription = true;
614 break;
615
616 case VINF_GETOPT_NOT_OPTION:
617 if (!pszFilenameOrUuid)
618 pszFilenameOrUuid = ValueUnion.psz;
619 else
620 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
621 break;
622
623 default:
624 if (c > 0)
625 {
626 if (RT_C_IS_PRINT(c))
627 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid option -%c", c);
628 else
629 return errorSyntax(USAGE_MODIFYMEDIUM, "Invalid option case %i", c);
630 }
631 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
632 return errorSyntax(USAGE_MODIFYMEDIUM, "unknown option: %s\n", ValueUnion.psz);
633 else if (ValueUnion.pDef)
634 return errorSyntax(USAGE_MODIFYMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
635 else
636 return errorSyntax(USAGE_MODIFYMEDIUM, "error: %Rrs", c);
637 }
638 }
639
640 if (cmd == CMD_NONE)
641 cmd = CMD_DISK;
642
643 if (!pszFilenameOrUuid)
644 return errorSyntax(USAGE_MODIFYMEDIUM, "Medium name or UUID required");
645
646 if (!fModifyMediumType
647 && !fModifyAutoReset
648 && !fModifyProperties
649 && !fModifyCompact
650 && !fModifyResize
651 && !fModifyLocation
652 && !fModifyDescription)
653 return errorSyntax(USAGE_MODIFYMEDIUM, "No operation specified");
654
655 /* Always open the medium if necessary, there is no other way. */
656 if (cmd == CMD_DISK)
657 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
658 AccessMode_ReadWrite, pMedium,
659 false /* fForceNewUuidOnOpen */, false /* fSilent */);
660 else if (cmd == CMD_DVD)
661 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
662 AccessMode_ReadOnly, pMedium,
663 false /* fForceNewUuidOnOpen */, false /* fSilent */);
664 else if (cmd == CMD_FLOPPY)
665 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
666 AccessMode_ReadWrite, pMedium,
667 false /* fForceNewUuidOnOpen */, false /* fSilent */);
668 else
669 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
670 if (FAILED(rc))
671 return RTEXITCODE_FAILURE;
672 if (pMedium.isNull())
673 {
674 RTMsgError("Invalid medium reference, avoiding crash");
675 return RTEXITCODE_FAILURE;
676 }
677
678 if ( fModifyResize
679 && fModifyResizeMB)
680 {
681 // Sanity check
682 //
683 // In general users should know what they do but in this case users have no
684 // alternative to VBoxManage. If happens that one wants to resize the disk
685 // and uses --resize and does not consider that this parameter expects the
686 // new medium size in MB not Byte. If the operation is started and then
687 // aborted by the user, the result is most likely a medium which doesn't
688 // work anymore.
689 MediumState_T state;
690 pMedium->RefreshState(&state);
691 LONG64 logicalSize;
692 pMedium->COMGETTER(LogicalSize)(&logicalSize);
693 if (cbResize > (uint64_t)logicalSize * 1000)
694 {
695 RTMsgError("Error: Attempt to resize the medium from %RU64.%RU64 MB to %RU64.%RU64 MB. Use --resizebyte if this is intended!\n",
696 logicalSize / _1M, (logicalSize % _1M) / (_1M / 10), cbResize / _1M, (cbResize % _1M) / (_1M / 10));
697 return RTEXITCODE_FAILURE;
698 }
699 }
700
701 if (fModifyMediumType)
702 {
703 MediumType_T enmCurrMediumType;
704 CHECK_ERROR(pMedium, COMGETTER(Type)(&enmCurrMediumType));
705
706 if (enmCurrMediumType != enmMediumType)
707 CHECK_ERROR(pMedium, COMSETTER(Type)(enmMediumType));
708 }
709
710 if (fModifyAutoReset)
711 {
712 CHECK_ERROR(pMedium, COMSETTER(AutoReset)(AutoReset));
713 }
714
715 if (fModifyProperties)
716 {
717 CHECK_ERROR(pMedium, SetProperties(ComSafeArrayAsInParam(mediumPropNames), ComSafeArrayAsInParam(mediumPropValues)));
718 }
719
720 if (fModifyCompact)
721 {
722 ComPtr<IProgress> pProgress;
723 CHECK_ERROR(pMedium, Compact(pProgress.asOutParam()));
724 if (SUCCEEDED(rc))
725 rc = showProgress(pProgress);
726 if (FAILED(rc))
727 {
728 if (rc == E_NOTIMPL)
729 RTMsgError("Compact medium operation is not implemented!");
730 else if (rc == VBOX_E_NOT_SUPPORTED)
731 RTMsgError("Compact medium operation for this format is not implemented yet!");
732 else if (!pProgress.isNull())
733 CHECK_PROGRESS_ERROR(pProgress, ("Failed to compact medium"));
734 else
735 RTMsgError("Failed to compact medium!");
736 }
737 }
738
739 if (fModifyResize)
740 {
741 ComPtr<IProgress> pProgress;
742 CHECK_ERROR(pMedium, Resize(cbResize, pProgress.asOutParam()));
743 if (SUCCEEDED(rc))
744 rc = showProgress(pProgress);
745 if (FAILED(rc))
746 {
747 if (rc == E_NOTIMPL)
748 RTMsgError("Resize medium operation is not implemented!");
749 else if (rc == VBOX_E_NOT_SUPPORTED)
750 RTMsgError("Resize medium operation for this format is not implemented yet!");
751 else if (!pProgress.isNull())
752 CHECK_PROGRESS_ERROR(pProgress, ("Failed to resize medium"));
753 else
754 RTMsgError("Failed to resize medium!");
755 }
756 }
757
758 if (fModifyLocation)
759 {
760 do
761 {
762 ComPtr<IProgress> pProgress;
763 Utf8Str strLocation(pszNewLocation);
764 RTStrFree(pszNewLocation);
765 CHECK_ERROR(pMedium, SetLocation(Bstr(strLocation).raw(), pProgress.asOutParam()));
766
767 if (SUCCEEDED(rc) && !pProgress.isNull())
768 {
769 rc = showProgress(pProgress);
770 CHECK_PROGRESS_ERROR(pProgress, ("Failed to move medium"));
771 }
772
773 Bstr uuid;
774 CHECK_ERROR_BREAK(pMedium, COMGETTER(Id)(uuid.asOutParam()));
775
776 RTPrintf("Move medium with UUID %s finished \n", Utf8Str(uuid).c_str());
777 }
778 while (0);
779 }
780
781 if (fModifyDescription)
782 {
783 CHECK_ERROR(pMedium, COMSETTER(Description)(Bstr(pszNewLocation).raw()));
784
785 RTPrintf("Medium description has been changed. \n");
786 }
787
788 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
789}
790
791static const RTGETOPTDEF g_aCloneMediumOptions[] =
792{
793 { "disk", 'd', RTGETOPT_REQ_NOTHING },
794 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
795 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
796 { "--format", 'o', RTGETOPT_REQ_STRING },
797 { "-format", 'o', RTGETOPT_REQ_STRING },
798 { "--static", 'F', RTGETOPT_REQ_NOTHING },
799 { "-static", 'F', RTGETOPT_REQ_NOTHING },
800 { "--existing", 'E', RTGETOPT_REQ_NOTHING },
801 { "--variant", 'm', RTGETOPT_REQ_STRING },
802 { "-variant", 'm', RTGETOPT_REQ_STRING },
803};
804
805RTEXITCODE handleCloneMedium(HandlerArg *a)
806{
807 HRESULT rc;
808 int vrc;
809 enum {
810 CMD_NONE,
811 CMD_DISK,
812 CMD_DVD,
813 CMD_FLOPPY
814 } cmd = CMD_NONE;
815 const char *pszSrc = NULL;
816 const char *pszDst = NULL;
817 Bstr format;
818 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
819 bool fExisting = false;
820
821 int c;
822 RTGETOPTUNION ValueUnion;
823 RTGETOPTSTATE GetState;
824 // start at 0 because main() has hacked both the argc and argv given to us
825 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneMediumOptions, RT_ELEMENTS(g_aCloneMediumOptions),
826 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
827 while ((c = RTGetOpt(&GetState, &ValueUnion)))
828 {
829 switch (c)
830 {
831 case 'd': // disk
832 if (cmd != CMD_NONE)
833 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
834 cmd = CMD_DISK;
835 break;
836
837 case 'D': // DVD
838 if (cmd != CMD_NONE)
839 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
840 cmd = CMD_DVD;
841 break;
842
843 case 'f': // floppy
844 if (cmd != CMD_NONE)
845 return errorSyntax(USAGE_CLONEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
846 cmd = CMD_FLOPPY;
847 break;
848
849 case 'o': // --format
850 format = ValueUnion.psz;
851 break;
852
853 case 'F': // --static
854 {
855 unsigned uMediumVariant = (unsigned)enmMediumVariant;
856 uMediumVariant |= MediumVariant_Fixed;
857 enmMediumVariant = (MediumVariant_T)uMediumVariant;
858 break;
859 }
860
861 case 'E': // --existing
862 fExisting = true;
863 break;
864
865 case 'm': // --variant
866 vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
867 if (RT_FAILURE(vrc))
868 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
869 break;
870
871 case VINF_GETOPT_NOT_OPTION:
872 if (!pszSrc)
873 pszSrc = ValueUnion.psz;
874 else if (!pszDst)
875 pszDst = ValueUnion.psz;
876 else
877 return errorSyntax(USAGE_CLONEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
878 break;
879
880 default:
881 if (c > 0)
882 {
883 if (RT_C_IS_GRAPH(c))
884 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: -%c", c);
885 else
886 return errorSyntax(USAGE_CLONEMEDIUM, "unhandled option: %i", c);
887 }
888 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
889 return errorSyntax(USAGE_CLONEMEDIUM, "unknown option: %s", ValueUnion.psz);
890 else if (ValueUnion.pDef)
891 return errorSyntax(USAGE_CLONEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
892 else
893 return errorSyntax(USAGE_CLONEMEDIUM, "error: %Rrs", c);
894 }
895 }
896
897 if (cmd == CMD_NONE)
898 cmd = CMD_DISK;
899 if (!pszSrc)
900 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory UUID or input file parameter missing");
901 if (!pszDst)
902 return errorSyntax(USAGE_CLONEMEDIUM, "Mandatory output file parameter missing");
903 if (fExisting && (!format.isEmpty() || enmMediumVariant != MediumType_Normal))
904 return errorSyntax(USAGE_CLONEMEDIUM, "Specified options which cannot be used with --existing");
905
906 ComPtr<IMedium> pSrcMedium;
907 ComPtr<IMedium> pDstMedium;
908
909 if (cmd == CMD_DISK)
910 rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly, pSrcMedium,
911 false /* fForceNewUuidOnOpen */, false /* fSilent */);
912 else if (cmd == CMD_DVD)
913 rc = openMedium(a, pszSrc, DeviceType_DVD, AccessMode_ReadOnly, pSrcMedium,
914 false /* fForceNewUuidOnOpen */, false /* fSilent */);
915 else if (cmd == CMD_FLOPPY)
916 rc = openMedium(a, pszSrc, DeviceType_Floppy, AccessMode_ReadOnly, pSrcMedium,
917 false /* fForceNewUuidOnOpen */, false /* fSilent */);
918 else
919 rc = E_INVALIDARG; /* cannot happen but make gcc happy */
920 if (FAILED(rc))
921 return RTEXITCODE_FAILURE;
922
923 do
924 {
925 /* open/create destination medium */
926 if (fExisting)
927 {
928 if (cmd == CMD_DISK)
929 rc = openMedium(a, pszDst, DeviceType_HardDisk, AccessMode_ReadWrite, pDstMedium,
930 false /* fForceNewUuidOnOpen */, false /* fSilent */);
931 else if (cmd == CMD_DVD)
932 rc = openMedium(a, pszDst, DeviceType_DVD, AccessMode_ReadOnly, pDstMedium,
933 false /* fForceNewUuidOnOpen */, false /* fSilent */);
934 else if (cmd == CMD_FLOPPY)
935 rc = openMedium(a, pszDst, DeviceType_Floppy, AccessMode_ReadWrite, pDstMedium,
936 false /* fForceNewUuidOnOpen */, false /* fSilent */);
937 if (FAILED(rc))
938 break;
939
940 /* Perform accessibility check now. */
941 MediumState_T state;
942 CHECK_ERROR_BREAK(pDstMedium, RefreshState(&state));
943 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Format)(format.asOutParam()));
944 }
945 else
946 {
947 /*
948 * In case the format is unspecified check that the source medium supports
949 * image creation and use the same format for the destination image.
950 * Use the default image format if it is not supported.
951 */
952 if (format.isEmpty())
953 {
954 ComPtr<IMediumFormat> pMediumFmt;
955 com::SafeArray<MediumFormatCapabilities_T> l_caps;
956 CHECK_ERROR_BREAK(pSrcMedium, COMGETTER(MediumFormat)(pMediumFmt.asOutParam()));
957 CHECK_ERROR_BREAK(pMediumFmt, COMGETTER(Capabilities)(ComSafeArrayAsOutParam(l_caps)));
958 ULONG caps=0;
959 for (size_t i = 0; i < l_caps.size(); i++)
960 caps |= l_caps[i];
961 if (caps & ( MediumFormatCapabilities_CreateDynamic
962 | MediumFormatCapabilities_CreateFixed))
963 CHECK_ERROR_BREAK(pMediumFmt, COMGETTER(Id)(format.asOutParam()));
964 }
965 Utf8Str strFormat(format);
966 if (cmd == CMD_DISK)
967 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_HardDisk,
968 AccessMode_ReadWrite, pDstMedium);
969 else if (cmd == CMD_DVD)
970 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_DVD,
971 AccessMode_ReadOnly, pDstMedium);
972 else if (cmd == CMD_FLOPPY)
973 rc = createMedium(a, strFormat.c_str(), pszDst, DeviceType_Floppy,
974 AccessMode_ReadWrite, pDstMedium);
975 if (FAILED(rc))
976 break;
977 }
978
979 ComPtr<IProgress> pProgress;
980 com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
981
982 for (ULONG i = 0; i < l_variants.size(); ++i)
983 {
984 ULONG temp = enmMediumVariant;
985 temp &= 1<<i;
986 l_variants [i] = (MediumVariant_T)temp;
987 }
988
989 CHECK_ERROR_BREAK(pSrcMedium, CloneTo(pDstMedium, ComSafeArrayAsInParam(l_variants), NULL, pProgress.asOutParam()));
990
991 rc = showProgress(pProgress);
992 CHECK_PROGRESS_ERROR_BREAK(pProgress, ("Failed to clone medium"));
993
994 Bstr uuid;
995 CHECK_ERROR_BREAK(pDstMedium, COMGETTER(Id)(uuid.asOutParam()));
996
997 RTPrintf("Clone medium created in format '%ls'. UUID: %s\n",
998 format.raw(), Utf8Str(uuid).c_str());
999 }
1000 while (0);
1001
1002 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1003}
1004
1005static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
1006{
1007 { "--format", 'o', RTGETOPT_REQ_STRING },
1008 { "-format", 'o', RTGETOPT_REQ_STRING },
1009 { "--static", 'F', RTGETOPT_REQ_NOTHING },
1010 { "-static", 'F', RTGETOPT_REQ_NOTHING },
1011 { "--variant", 'm', RTGETOPT_REQ_STRING },
1012 { "-variant", 'm', RTGETOPT_REQ_STRING },
1013 { "--uuid", 'u', RTGETOPT_REQ_STRING },
1014};
1015
1016RTEXITCODE handleConvertFromRaw(HandlerArg *a)
1017{
1018 int rc = VINF_SUCCESS;
1019 bool fReadFromStdIn = false;
1020 const char *format = "VDI";
1021 const char *srcfilename = NULL;
1022 const char *dstfilename = NULL;
1023 const char *filesize = NULL;
1024 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
1025 void *pvBuf = NULL;
1026 RTUUID uuid;
1027 PCRTUUID pUuid = NULL;
1028
1029 int c;
1030 RTGETOPTUNION ValueUnion;
1031 RTGETOPTSTATE GetState;
1032 // start at 0 because main() has hacked both the argc and argv given to us
1033 RTGetOptInit(&GetState, a->argc, a->argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
1034 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1035 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1036 {
1037 switch (c)
1038 {
1039 case 'u': // --uuid
1040 if (RT_FAILURE(RTUuidFromStr(&uuid, ValueUnion.psz)))
1041 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid UUID '%s'", ValueUnion.psz);
1042 pUuid = &uuid;
1043 break;
1044 case 'o': // --format
1045 format = ValueUnion.psz;
1046 break;
1047
1048 case 'm': // --variant
1049 {
1050 MediumVariant_T enmMediumVariant = MediumVariant_Standard;
1051 rc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
1052 if (RT_FAILURE(rc))
1053 return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
1054 /// @todo cleaner solution than assuming 1:1 mapping?
1055 uImageFlags = (unsigned)enmMediumVariant;
1056 break;
1057 }
1058 case VINF_GETOPT_NOT_OPTION:
1059 if (!srcfilename)
1060 {
1061 srcfilename = ValueUnion.psz;
1062 fReadFromStdIn = !strcmp(srcfilename, "stdin");
1063 }
1064 else if (!dstfilename)
1065 dstfilename = ValueUnion.psz;
1066 else if (fReadFromStdIn && !filesize)
1067 filesize = ValueUnion.psz;
1068 else
1069 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
1070 break;
1071
1072 default:
1073 return errorGetOpt(USAGE_CONVERTFROMRAW, c, &ValueUnion);
1074 }
1075 }
1076
1077 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
1078 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
1079 RTStrmPrintf(g_pStdErr, "Converting from raw image file=\"%s\" to file=\"%s\"...\n",
1080 srcfilename, dstfilename);
1081
1082 PVDISK pDisk = NULL;
1083
1084 PVDINTERFACE pVDIfs = NULL;
1085 VDINTERFACEERROR vdInterfaceError;
1086 vdInterfaceError.pfnError = handleVDError;
1087 vdInterfaceError.pfnMessage = NULL;
1088
1089 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1090 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
1091 AssertRC(rc);
1092
1093 /* open raw image file. */
1094 RTFILE File;
1095 if (fReadFromStdIn)
1096 rc = RTFileFromNative(&File, RTFILE_NATIVE_STDIN);
1097 else
1098 rc = RTFileOpen(&File, srcfilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1099 if (RT_FAILURE(rc))
1100 {
1101 RTMsgError("Cannot open file \"%s\": %Rrc", srcfilename, rc);
1102 goto out;
1103 }
1104
1105 uint64_t cbFile;
1106 /* get image size. */
1107 if (fReadFromStdIn)
1108 cbFile = RTStrToUInt64(filesize);
1109 else
1110 rc = RTFileGetSize(File, &cbFile);
1111 if (RT_FAILURE(rc))
1112 {
1113 RTMsgError("Cannot get image size for file \"%s\": %Rrc", srcfilename, rc);
1114 goto out;
1115 }
1116
1117 RTStrmPrintf(g_pStdErr, "Creating %s image with size %RU64 bytes (%RU64MB)...\n",
1118 (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
1119 char pszComment[256];
1120 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
1121 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1122 if (RT_FAILURE(rc))
1123 {
1124 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
1125 goto out;
1126 }
1127
1128 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
1129 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
1130 VDGEOMETRY PCHS, LCHS;
1131 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
1132 PCHS.cHeads = 16;
1133 PCHS.cSectors = 63;
1134 LCHS.cCylinders = 0;
1135 LCHS.cHeads = 0;
1136 LCHS.cSectors = 0;
1137 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
1138 uImageFlags, pszComment, &PCHS, &LCHS, pUuid,
1139 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1140 if (RT_FAILURE(rc))
1141 {
1142 RTMsgError("Cannot create the disk image \"%s\": %Rrc", dstfilename, rc);
1143 goto out;
1144 }
1145
1146 size_t cbBuffer;
1147 cbBuffer = _1M;
1148 pvBuf = RTMemAlloc(cbBuffer);
1149 if (!pvBuf)
1150 {
1151 rc = VERR_NO_MEMORY;
1152 RTMsgError("Out of memory allocating buffers for image \"%s\": %Rrc", dstfilename, rc);
1153 goto out;
1154 }
1155
1156 uint64_t offFile;
1157 offFile = 0;
1158 while (offFile < cbFile)
1159 {
1160 size_t cbRead;
1161 size_t cbToRead;
1162 cbRead = 0;
1163 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
1164 cbBuffer : (size_t)(cbFile - offFile);
1165 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
1166 if (RT_FAILURE(rc) || !cbRead)
1167 break;
1168 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
1169 if (RT_FAILURE(rc))
1170 {
1171 RTMsgError("Failed to write to disk image \"%s\": %Rrc", dstfilename, rc);
1172 goto out;
1173 }
1174 offFile += cbRead;
1175 }
1176
1177out:
1178 if (pvBuf)
1179 RTMemFree(pvBuf);
1180 if (pDisk)
1181 VDClose(pDisk, RT_FAILURE(rc));
1182 if (File != NIL_RTFILE)
1183 RTFileClose(File);
1184
1185 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1186}
1187
1188HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
1189 const ComPtr<IMedium> &pMedium,
1190 const char *pszParentUUID,
1191 bool fOptLong)
1192{
1193 HRESULT rc = S_OK;
1194 do
1195 {
1196 Bstr uuid;
1197 pMedium->COMGETTER(Id)(uuid.asOutParam());
1198 RTPrintf("UUID: %ls\n", uuid.raw());
1199 if (pszParentUUID)
1200 RTPrintf("Parent UUID: %s\n", pszParentUUID);
1201
1202 /* check for accessibility */
1203 MediumState_T enmState;
1204 CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
1205 const char *pszState = "unknown";
1206 switch (enmState)
1207 {
1208 case MediumState_NotCreated:
1209 pszState = "not created";
1210 break;
1211 case MediumState_Created:
1212 pszState = "created";
1213 break;
1214 case MediumState_LockedRead:
1215 pszState = "locked read";
1216 break;
1217 case MediumState_LockedWrite:
1218 pszState = "locked write";
1219 break;
1220 case MediumState_Inaccessible:
1221 pszState = "inaccessible";
1222 break;
1223 case MediumState_Creating:
1224 pszState = "creating";
1225 break;
1226 case MediumState_Deleting:
1227 pszState = "deleting";
1228 break;
1229 }
1230 RTPrintf("State: %s\n", pszState);
1231
1232 if (fOptLong && enmState == MediumState_Inaccessible)
1233 {
1234 Bstr err;
1235 CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
1236 RTPrintf("Access Error: %ls\n", err.raw());
1237 }
1238
1239 if (fOptLong)
1240 {
1241 Bstr description;
1242 pMedium->COMGETTER(Description)(description.asOutParam());
1243 if (!description.isEmpty())
1244 RTPrintf("Description: %ls\n", description.raw());
1245 }
1246
1247 MediumType_T type;
1248 pMedium->COMGETTER(Type)(&type);
1249 const char *typeStr = "unknown";
1250 switch (type)
1251 {
1252 case MediumType_Normal:
1253 if (pszParentUUID && Guid(pszParentUUID).isValid())
1254 typeStr = "normal (differencing)";
1255 else
1256 typeStr = "normal (base)";
1257 break;
1258 case MediumType_Immutable:
1259 typeStr = "immutable";
1260 break;
1261 case MediumType_Writethrough:
1262 typeStr = "writethrough";
1263 break;
1264 case MediumType_Shareable:
1265 typeStr = "shareable";
1266 break;
1267 case MediumType_Readonly:
1268 typeStr = "readonly";
1269 break;
1270 case MediumType_MultiAttach:
1271 typeStr = "multiattach";
1272 break;
1273 }
1274 RTPrintf("Type: %s\n", typeStr);
1275
1276 /* print out information specific for differencing media */
1277 if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
1278 {
1279 BOOL autoReset = FALSE;
1280 pMedium->COMGETTER(AutoReset)(&autoReset);
1281 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1282 }
1283
1284 Bstr loc;
1285 pMedium->COMGETTER(Location)(loc.asOutParam());
1286 RTPrintf("Location: %ls\n", loc.raw());
1287
1288 Bstr format;
1289 pMedium->COMGETTER(Format)(format.asOutParam());
1290 RTPrintf("Storage format: %ls\n", format.raw());
1291
1292 if (fOptLong)
1293 {
1294 com::SafeArray<MediumVariant_T> safeArray_variant;
1295
1296 pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
1297 ULONG variant=0;
1298 for (size_t i = 0; i < safeArray_variant.size(); i++)
1299 variant |= safeArray_variant[i];
1300
1301 const char *variantStr = "unknown";
1302 switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
1303 {
1304 case MediumVariant_VmdkSplit2G:
1305 variantStr = "split2G";
1306 break;
1307 case MediumVariant_VmdkStreamOptimized:
1308 variantStr = "streamOptimized";
1309 break;
1310 case MediumVariant_VmdkESX:
1311 variantStr = "ESX";
1312 break;
1313 case MediumVariant_Standard:
1314 variantStr = "default";
1315 break;
1316 }
1317 const char *variantTypeStr = "dynamic";
1318 if (variant & MediumVariant_Fixed)
1319 variantTypeStr = "fixed";
1320 else if (variant & MediumVariant_Diff)
1321 variantTypeStr = "differencing";
1322 RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
1323 }
1324
1325 LONG64 logicalSize;
1326 pMedium->COMGETTER(LogicalSize)(&logicalSize);
1327 RTPrintf("Capacity: %lld MBytes\n", logicalSize >> 20);
1328 if (fOptLong)
1329 {
1330 LONG64 actualSize;
1331 pMedium->COMGETTER(Size)(&actualSize);
1332 RTPrintf("Size on disk: %lld MBytes\n", actualSize >> 20);
1333 }
1334
1335 Bstr strCipher;
1336 Bstr strPasswordId;
1337 HRESULT rc2 = pMedium->GetEncryptionSettings(strCipher.asOutParam(), strPasswordId.asOutParam());
1338 if (SUCCEEDED(rc2))
1339 {
1340 RTPrintf("Encryption: enabled\n");
1341 if (fOptLong)
1342 {
1343 RTPrintf("Cipher: %ls\n", strCipher.raw());
1344 RTPrintf("Password ID: %ls\n", strPasswordId.raw());
1345 }
1346 }
1347 else
1348 RTPrintf("Encryption: disabled\n");
1349
1350 if (fOptLong)
1351 {
1352 com::SafeArray<BSTR> names;
1353 com::SafeArray<BSTR> values;
1354 pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
1355 size_t cNames = names.size();
1356 size_t cValues = values.size();
1357 bool fFirst = true;
1358 for (size_t i = 0; i < cNames; i++)
1359 {
1360 Bstr value;
1361 if (i < cValues)
1362 value = values[i];
1363 RTPrintf("%s%ls=%ls\n",
1364 fFirst ? "Property: " : " ",
1365 names[i], value.raw());
1366 }
1367 }
1368
1369 if (fOptLong)
1370 {
1371 bool fFirst = true;
1372 com::SafeArray<BSTR> machineIds;
1373 pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1374 for (size_t i = 0; i < machineIds.size(); i++)
1375 {
1376 ComPtr<IMachine> pMachine;
1377 CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], pMachine.asOutParam()));
1378 if (pMachine)
1379 {
1380 Bstr name;
1381 pMachine->COMGETTER(Name)(name.asOutParam());
1382 pMachine->COMGETTER(Id)(uuid.asOutParam());
1383 RTPrintf("%s%ls (UUID: %ls)",
1384 fFirst ? "In use by VMs: " : " ",
1385 name.raw(), machineIds[i]);
1386 fFirst = false;
1387 com::SafeArray<BSTR> snapshotIds;
1388 pMedium->GetSnapshotIds(machineIds[i],
1389 ComSafeArrayAsOutParam(snapshotIds));
1390 for (size_t j = 0; j < snapshotIds.size(); j++)
1391 {
1392 ComPtr<ISnapshot> pSnapshot;
1393 pMachine->FindSnapshot(snapshotIds[j], pSnapshot.asOutParam());
1394 if (pSnapshot)
1395 {
1396 Bstr snapshotName;
1397 pSnapshot->COMGETTER(Name)(snapshotName.asOutParam());
1398 RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
1399 }
1400 }
1401 RTPrintf("\n");
1402 }
1403 }
1404 }
1405
1406 if (fOptLong)
1407 {
1408 com::SafeIfaceArray<IMedium> children;
1409 pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
1410 bool fFirst = true;
1411 for (size_t i = 0; i < children.size(); i++)
1412 {
1413 ComPtr<IMedium> pChild(children[i]);
1414 if (pChild)
1415 {
1416 Bstr childUUID;
1417 pChild->COMGETTER(Id)(childUUID.asOutParam());
1418 RTPrintf("%s%ls\n",
1419 fFirst ? "Child UUIDs: " : " ",
1420 childUUID.raw());
1421 fFirst = false;
1422 }
1423 }
1424 }
1425 }
1426 while (0);
1427
1428 return rc;
1429}
1430
1431static const RTGETOPTDEF g_aShowMediumInfoOptions[] =
1432{
1433 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1434 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1435 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1436};
1437
1438RTEXITCODE handleShowMediumInfo(HandlerArg *a)
1439{
1440 enum {
1441 CMD_NONE,
1442 CMD_DISK,
1443 CMD_DVD,
1444 CMD_FLOPPY
1445 } cmd = CMD_NONE;
1446 const char *pszFilenameOrUuid = NULL;
1447
1448 int c;
1449 RTGETOPTUNION ValueUnion;
1450 RTGETOPTSTATE GetState;
1451 // start at 0 because main() has hacked both the argc and argv given to us
1452 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowMediumInfoOptions, RT_ELEMENTS(g_aShowMediumInfoOptions),
1453 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1454 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1455 {
1456 switch (c)
1457 {
1458 case 'd': // disk
1459 if (cmd != CMD_NONE)
1460 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1461 cmd = CMD_DISK;
1462 break;
1463
1464 case 'D': // DVD
1465 if (cmd != CMD_NONE)
1466 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1467 cmd = CMD_DVD;
1468 break;
1469
1470 case 'f': // floppy
1471 if (cmd != CMD_NONE)
1472 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
1473 cmd = CMD_FLOPPY;
1474 break;
1475
1476 case VINF_GETOPT_NOT_OPTION:
1477 if (!pszFilenameOrUuid)
1478 pszFilenameOrUuid = ValueUnion.psz;
1479 else
1480 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid parameter '%s'", ValueUnion.psz);
1481 break;
1482
1483 default:
1484 if (c > 0)
1485 {
1486 if (RT_C_IS_PRINT(c))
1487 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option -%c", c);
1488 else
1489 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Invalid option case %i", c);
1490 }
1491 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1492 return errorSyntax(USAGE_SHOWMEDIUMINFO, "unknown option: %s\n", ValueUnion.psz);
1493 else if (ValueUnion.pDef)
1494 return errorSyntax(USAGE_SHOWMEDIUMINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1495 else
1496 return errorSyntax(USAGE_SHOWMEDIUMINFO, "error: %Rrs", c);
1497 }
1498 }
1499
1500 if (cmd == CMD_NONE)
1501 cmd = CMD_DISK;
1502
1503 /* check for required options */
1504 if (!pszFilenameOrUuid)
1505 return errorSyntax(USAGE_SHOWMEDIUMINFO, "Medium name or UUID required");
1506
1507 HRESULT rc = S_OK; /* Prevents warning. */
1508
1509 ComPtr<IMedium> pMedium;
1510 if (cmd == CMD_DISK)
1511 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1512 AccessMode_ReadOnly, pMedium,
1513 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1514 else if (cmd == CMD_DVD)
1515 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1516 AccessMode_ReadOnly, pMedium,
1517 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1518 else if (cmd == CMD_FLOPPY)
1519 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1520 AccessMode_ReadOnly, pMedium,
1521 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1522 if (FAILED(rc))
1523 return RTEXITCODE_FAILURE;
1524
1525 Utf8Str strParentUUID("base");
1526 ComPtr<IMedium> pParent;
1527 pMedium->COMGETTER(Parent)(pParent.asOutParam());
1528 if (!pParent.isNull())
1529 {
1530 Bstr bstrParentUUID;
1531 pParent->COMGETTER(Id)(bstrParentUUID.asOutParam());
1532 strParentUUID = bstrParentUUID;
1533 }
1534
1535 rc = showMediumInfo(a->virtualBox, pMedium, strParentUUID.c_str(), true);
1536
1537 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1538}
1539
1540static const RTGETOPTDEF g_aCloseMediumOptions[] =
1541{
1542 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1543 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1544 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1545 { "--delete", 'r', RTGETOPT_REQ_NOTHING },
1546};
1547
1548RTEXITCODE handleCloseMedium(HandlerArg *a)
1549{
1550 HRESULT rc = S_OK;
1551 enum {
1552 CMD_NONE,
1553 CMD_DISK,
1554 CMD_DVD,
1555 CMD_FLOPPY
1556 } cmd = CMD_NONE;
1557 const char *pszFilenameOrUuid = NULL;
1558 bool fDelete = false;
1559
1560 int c;
1561 RTGETOPTUNION ValueUnion;
1562 RTGETOPTSTATE GetState;
1563 // start at 0 because main() has hacked both the argc and argv given to us
1564 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
1565 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1566 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1567 {
1568 switch (c)
1569 {
1570 case 'd': // disk
1571 if (cmd != CMD_NONE)
1572 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1573 cmd = CMD_DISK;
1574 break;
1575
1576 case 'D': // DVD
1577 if (cmd != CMD_NONE)
1578 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1579 cmd = CMD_DVD;
1580 break;
1581
1582 case 'f': // floppy
1583 if (cmd != CMD_NONE)
1584 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1585 cmd = CMD_FLOPPY;
1586 break;
1587
1588 case 'r': // --delete
1589 fDelete = true;
1590 break;
1591
1592 case VINF_GETOPT_NOT_OPTION:
1593 if (!pszFilenameOrUuid)
1594 pszFilenameOrUuid = ValueUnion.psz;
1595 else
1596 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1597 break;
1598
1599 default:
1600 if (c > 0)
1601 {
1602 if (RT_C_IS_PRINT(c))
1603 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option -%c", c);
1604 else
1605 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option case %i", c);
1606 }
1607 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1608 return errorSyntax(USAGE_CLOSEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1609 else if (ValueUnion.pDef)
1610 return errorSyntax(USAGE_CLOSEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1611 else
1612 return errorSyntax(USAGE_CLOSEMEDIUM, "error: %Rrs", c);
1613 }
1614 }
1615
1616 /* check for required options */
1617 if (cmd == CMD_NONE)
1618 cmd = CMD_DISK;
1619 if (!pszFilenameOrUuid)
1620 return errorSyntax(USAGE_CLOSEMEDIUM, "Medium name or UUID required");
1621
1622 ComPtr<IMedium> pMedium;
1623 if (cmd == CMD_DISK)
1624 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1625 AccessMode_ReadWrite, pMedium,
1626 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1627 else if (cmd == CMD_DVD)
1628 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1629 AccessMode_ReadOnly, pMedium,
1630 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1631 else if (cmd == CMD_FLOPPY)
1632 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1633 AccessMode_ReadWrite, pMedium,
1634 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1635
1636 if (SUCCEEDED(rc) && pMedium)
1637 {
1638 if (fDelete)
1639 {
1640 ComPtr<IProgress> pProgress;
1641 CHECK_ERROR(pMedium, DeleteStorage(pProgress.asOutParam()));
1642 if (SUCCEEDED(rc))
1643 {
1644 rc = showProgress(pProgress);
1645 CHECK_PROGRESS_ERROR(pProgress, ("Failed to delete medium"));
1646 }
1647 else
1648 RTMsgError("Failed to delete medium. Error code %Rrc", rc);
1649 }
1650 CHECK_ERROR(pMedium, Close());
1651 }
1652
1653 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1654}
1655
1656RTEXITCODE handleMediumProperty(HandlerArg *a)
1657{
1658 HRESULT rc = S_OK;
1659 const char *pszCmd = NULL;
1660 enum {
1661 CMD_NONE,
1662 CMD_DISK,
1663 CMD_DVD,
1664 CMD_FLOPPY
1665 } cmd = CMD_NONE;
1666 const char *pszAction = NULL;
1667 const char *pszFilenameOrUuid = NULL;
1668 const char *pszProperty = NULL;
1669 ComPtr<IMedium> pMedium;
1670
1671 pszCmd = (a->argc > 0) ? a->argv[0] : "";
1672 if ( !RTStrICmp(pszCmd, "disk")
1673 || !RTStrICmp(pszCmd, "dvd")
1674 || !RTStrICmp(pszCmd, "floppy"))
1675 {
1676 if (!RTStrICmp(pszCmd, "disk"))
1677 cmd = CMD_DISK;
1678 else if (!RTStrICmp(pszCmd, "dvd"))
1679 cmd = CMD_DVD;
1680 else if (!RTStrICmp(pszCmd, "floppy"))
1681 cmd = CMD_FLOPPY;
1682 else
1683 {
1684 AssertMsgFailed(("unexpected parameter %s\n", pszCmd));
1685 cmd = CMD_DISK;
1686 }
1687 a->argv++;
1688 a->argc--;
1689 }
1690 else
1691 {
1692 pszCmd = NULL;
1693 cmd = CMD_DISK;
1694 }
1695
1696 if (a->argc == 0)
1697 return errorSyntax(USAGE_MEDIUMPROPERTY, "Missing action");
1698
1699 pszAction = a->argv[0];
1700 if ( RTStrICmp(pszAction, "set")
1701 && RTStrICmp(pszAction, "get")
1702 && RTStrICmp(pszAction, "delete"))
1703 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid action given: %s", pszAction);
1704
1705 if ( ( !RTStrICmp(pszAction, "set")
1706 && a->argc != 4)
1707 || ( RTStrICmp(pszAction, "set")
1708 && a->argc != 3))
1709 return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid number of arguments given for action: %s", pszAction);
1710
1711 pszFilenameOrUuid = a->argv[1];
1712 pszProperty = a->argv[2];
1713
1714 if (cmd == CMD_DISK)
1715 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1716 AccessMode_ReadWrite, pMedium,
1717 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1718 else if (cmd == CMD_DVD)
1719 rc = openMedium(a, pszFilenameOrUuid, DeviceType_DVD,
1720 AccessMode_ReadOnly, pMedium,
1721 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1722 else if (cmd == CMD_FLOPPY)
1723 rc = openMedium(a, pszFilenameOrUuid, DeviceType_Floppy,
1724 AccessMode_ReadWrite, pMedium,
1725 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1726 if (SUCCEEDED(rc) && !pMedium.isNull())
1727 {
1728 if (!RTStrICmp(pszAction, "set"))
1729 {
1730 const char *pszValue = a->argv[3];
1731 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr(pszValue).raw()));
1732 }
1733 else if (!RTStrICmp(pszAction, "get"))
1734 {
1735 Bstr strVal;
1736 CHECK_ERROR(pMedium, GetProperty(Bstr(pszProperty).raw(), strVal.asOutParam()));
1737 if (SUCCEEDED(rc))
1738 RTPrintf("%s=%ls\n", pszProperty, strVal.raw());
1739 }
1740 else if (!RTStrICmp(pszAction, "delete"))
1741 {
1742 CHECK_ERROR(pMedium, SetProperty(Bstr(pszProperty).raw(), Bstr().raw()));
1743 /** @todo */
1744 }
1745 }
1746
1747 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1748}
1749
1750static const RTGETOPTDEF g_aEncryptMediumOptions[] =
1751{
1752 { "--newpassword", 'n', RTGETOPT_REQ_STRING },
1753 { "--oldpassword", 'o', RTGETOPT_REQ_STRING },
1754 { "--cipher", 'c', RTGETOPT_REQ_STRING },
1755 { "--newpasswordid", 'i', RTGETOPT_REQ_STRING }
1756};
1757
1758RTEXITCODE handleEncryptMedium(HandlerArg *a)
1759{
1760 HRESULT rc;
1761 ComPtr<IMedium> hardDisk;
1762 const char *pszPasswordNew = NULL;
1763 const char *pszPasswordOld = NULL;
1764 const char *pszCipher = NULL;
1765 const char *pszFilenameOrUuid = NULL;
1766 const char *pszNewPasswordId = NULL;
1767 Utf8Str strPasswordNew;
1768 Utf8Str strPasswordOld;
1769
1770 int c;
1771 RTGETOPTUNION ValueUnion;
1772 RTGETOPTSTATE GetState;
1773 // start at 0 because main() has hacked both the argc and argv given to us
1774 RTGetOptInit(&GetState, a->argc, a->argv, g_aEncryptMediumOptions, RT_ELEMENTS(g_aEncryptMediumOptions),
1775 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1776 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1777 {
1778 switch (c)
1779 {
1780 case 'n': // --newpassword
1781 pszPasswordNew = ValueUnion.psz;
1782 break;
1783
1784 case 'o': // --oldpassword
1785 pszPasswordOld = ValueUnion.psz;
1786 break;
1787
1788 case 'c': // --cipher
1789 pszCipher = ValueUnion.psz;
1790 break;
1791
1792 case 'i': // --newpasswordid
1793 pszNewPasswordId = ValueUnion.psz;
1794 break;
1795
1796 case VINF_GETOPT_NOT_OPTION:
1797 if (!pszFilenameOrUuid)
1798 pszFilenameOrUuid = ValueUnion.psz;
1799 else
1800 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1801 break;
1802
1803 default:
1804 if (c > 0)
1805 {
1806 if (RT_C_IS_PRINT(c))
1807 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option -%c", c);
1808 else
1809 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Invalid option case %i", c);
1810 }
1811 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1812 return errorSyntax(USAGE_ENCRYPTMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1813 else if (ValueUnion.pDef)
1814 return errorSyntax(USAGE_ENCRYPTMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1815 else
1816 return errorSyntax(USAGE_ENCRYPTMEDIUM, "error: %Rrs", c);
1817 }
1818 }
1819
1820 if (!pszFilenameOrUuid)
1821 return errorSyntax(USAGE_ENCRYPTMEDIUM, "Disk name or UUID required");
1822
1823 if (!pszPasswordNew && !pszPasswordOld)
1824 return errorSyntax(USAGE_ENCRYPTMEDIUM, "No password specified");
1825
1826 if ( (pszPasswordNew && !pszNewPasswordId)
1827 || (!pszPasswordNew && pszNewPasswordId))
1828 return errorSyntax(USAGE_ENCRYPTMEDIUM, "A new password must always have a valid identifier set at the same time");
1829
1830 if (pszPasswordNew)
1831 {
1832 if (!RTStrCmp(pszPasswordNew, "-"))
1833 {
1834 /* Get password from console. */
1835 RTEXITCODE rcExit = readPasswordFromConsole(&strPasswordNew, "Enter new password:");
1836 if (rcExit == RTEXITCODE_FAILURE)
1837 return rcExit;
1838 }
1839 else
1840 {
1841 RTEXITCODE rcExit = readPasswordFile(pszPasswordNew, &strPasswordNew);
1842 if (rcExit == RTEXITCODE_FAILURE)
1843 {
1844 RTMsgError("Failed to read new password from file");
1845 return rcExit;
1846 }
1847 }
1848 }
1849
1850 if (pszPasswordOld)
1851 {
1852 if (!RTStrCmp(pszPasswordOld, "-"))
1853 {
1854 /* Get password from console. */
1855 RTEXITCODE rcExit = readPasswordFromConsole(&strPasswordOld, "Enter old password:");
1856 if (rcExit == RTEXITCODE_FAILURE)
1857 return rcExit;
1858 }
1859 else
1860 {
1861 RTEXITCODE rcExit = readPasswordFile(pszPasswordOld, &strPasswordOld);
1862 if (rcExit == RTEXITCODE_FAILURE)
1863 {
1864 RTMsgError("Failed to read old password from file");
1865 return rcExit;
1866 }
1867 }
1868 }
1869
1870 /* Always open the medium if necessary, there is no other way. */
1871 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1872 AccessMode_ReadWrite, hardDisk,
1873 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1874 if (FAILED(rc))
1875 return RTEXITCODE_FAILURE;
1876 if (hardDisk.isNull())
1877 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid hard disk reference, avoiding crash");
1878
1879 ComPtr<IProgress> progress;
1880 CHECK_ERROR(hardDisk, ChangeEncryption(Bstr(strPasswordOld).raw(), Bstr(pszCipher).raw(),
1881 Bstr(strPasswordNew).raw(), Bstr(pszNewPasswordId).raw(),
1882 progress.asOutParam()));
1883 if (SUCCEEDED(rc))
1884 rc = showProgress(progress);
1885 if (FAILED(rc))
1886 {
1887 if (rc == E_NOTIMPL)
1888 RTMsgError("Encrypt hard disk operation is not implemented!");
1889 else if (rc == VBOX_E_NOT_SUPPORTED)
1890 RTMsgError("Encrypt hard disk operation for this cipher is not implemented yet!");
1891 else if (!progress.isNull())
1892 CHECK_PROGRESS_ERROR(progress, ("Failed to encrypt hard disk"));
1893 else
1894 RTMsgError("Failed to encrypt hard disk!");
1895 }
1896
1897 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1898}
1899
1900RTEXITCODE handleCheckMediumPassword(HandlerArg *a)
1901{
1902 HRESULT rc;
1903 ComPtr<IMedium> hardDisk;
1904 const char *pszFilenameOrUuid = NULL;
1905 Utf8Str strPassword;
1906
1907 if (a->argc != 2)
1908 return errorSyntax(USAGE_MEDIUMENCCHKPWD, "Invalid number of arguments: %d", a->argc);
1909
1910 pszFilenameOrUuid = a->argv[0];
1911
1912 if (!RTStrCmp(a->argv[1], "-"))
1913 {
1914 /* Get password from console. */
1915 RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter password:");
1916 if (rcExit == RTEXITCODE_FAILURE)
1917 return rcExit;
1918 }
1919 else
1920 {
1921 RTEXITCODE rcExit = readPasswordFile(a->argv[1], &strPassword);
1922 if (rcExit == RTEXITCODE_FAILURE)
1923 {
1924 RTMsgError("Failed to read password from file");
1925 return rcExit;
1926 }
1927 }
1928
1929 /* Always open the medium if necessary, there is no other way. */
1930 rc = openMedium(a, pszFilenameOrUuid, DeviceType_HardDisk,
1931 AccessMode_ReadWrite, hardDisk,
1932 false /* fForceNewUuidOnOpen */, false /* fSilent */);
1933 if (FAILED(rc))
1934 return RTEXITCODE_FAILURE;
1935 if (hardDisk.isNull())
1936 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid hard disk reference, avoiding crash");
1937
1938 CHECK_ERROR(hardDisk, CheckEncryptionPassword(Bstr(strPassword).raw()));
1939 if (SUCCEEDED(rc))
1940 RTPrintf("The given password is correct\n");
1941 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1942}
1943
1944#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