summaryrefslogtreecommitdiffstats
path: root/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp')
-rw-r--r--src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp409
1 files changed, 409 insertions, 0 deletions
diff --git a/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp b/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp
new file mode 100644
index 00000000..bb49867c
--- /dev/null
+++ b/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp
@@ -0,0 +1,409 @@
+/* $Id: vboximgMedia.cpp $ */
+/** @file
+ * vboximgMedia.cpp - Disk Image Flattening FUSE Program.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <VirtualBox_XPCOM.h>
+#include <VBox/com/VirtualBox.h>
+#include <VBox/vd.h>
+#include <VBox/vd-ifs.h>
+#include <VBox/log.h>
+#include <iprt/errcore.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/NativeEventQueue.h>
+#include <VBox/com/com.h>
+#include <VBox/com/string.h>
+#include <VBox/com/Guid.h>
+#include <VBox/com/array.h>
+#include <VBox/com/errorprint.h>
+#include <VBox/vd-plugin.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/message.h>
+#include <iprt/critsect.h>
+#include <iprt/asm.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <iprt/types.h>
+#include <iprt/path.h>
+#include <iprt/utf16.h>
+#include <math.h>
+#include "vboximgOpts.h"
+
+using namespace com;
+
+extern VBOXIMGOPTS g_vboximgOpts;
+
+#define SAFENULL(strPtr) (strPtr ? strPtr : "") /** Makes null harmless to print */
+#define CSTR(arg) Utf8Str(arg).c_str() /** Converts XPCOM string type to C string type */
+#define MAX_UUID_LEN 256 /** Max length of a UUID */
+#define VM_MAX_NAME 32 /** Max length of VM name we handle */
+
+typedef struct MEDIUMINFO
+{
+ char *pszName;
+ char *pszUuid;
+ char *pszBaseUuid;
+ char *pszPath;
+ char *pszDescription;
+ char *pszState;
+ char *pszType;
+ char *pszFormat;
+ bool fSnapshot;
+ PRInt64 cbSize;
+ MediumType_T type;
+ MediumState_T state;
+ ~MEDIUMINFO()
+ {
+ RTMemFree(pszName);
+ RTMemFree(pszUuid);
+ RTMemFree(pszPath);
+ RTMemFree(pszDescription);
+ RTMemFree(pszFormat);
+ }
+} MEDIUMINFO;
+
+
+char *vboximgScaledSize(size_t size)
+{
+ uint64_t exp = 0;
+ if (size > 0)
+ exp = log2((double)size);
+ char scaledMagnitude = ((char []){ ' ', 'K', 'M', 'G', 'T', 'P' })[exp / 10];
+ /* This workaround is because IPRT RT*Printf* funcs don't handle floating point format specifiers */
+ double cbScaled = (double)size / pow(2, (double)(((uint64_t)(exp / 10)) * 10));
+ uint64_t intPart = cbScaled;
+ uint64_t fracPart = (cbScaled - (double)intPart) * 10;
+ char tmp[256];
+ RTStrPrintf(tmp, sizeof (tmp), "%d.%d%c", intPart, fracPart, scaledMagnitude);
+ return RTStrDup(tmp);
+}
+
+static int getMediumInfo(IMachine *pMachine, IMedium *pMedium, MEDIUMINFO **ppMediumInfo)
+{
+ RT_NOREF(pMachine);
+
+ MEDIUMINFO *info = new MEDIUMINFO();
+ *ppMediumInfo = info;
+
+ Bstr name;
+ Bstr uuid;
+ Bstr baseUuid;
+ Bstr path;
+ Bstr description;
+ Bstr format;
+ PRInt64 *pSize = &info->cbSize;
+ ComPtr<IMedium> pBase;
+ MediumType_T *pType = &info->type;
+ MediumState_T *pState = &info->state;
+
+ *pState = MediumState_NotCreated;
+
+ HRESULT hrc;
+
+ CHECK_ERROR(pMedium, RefreshState(pState));
+ CHECK_ERROR(pMedium, COMGETTER(Id)(uuid.asOutParam()));
+ CHECK_ERROR(pMedium, COMGETTER(Base)(pBase.asOutParam()));
+ CHECK_ERROR(pBase, COMGETTER(Id)(baseUuid.asOutParam()));
+
+ CHECK_ERROR(pMedium, COMGETTER(State)(pState));
+
+ CHECK_ERROR(pMedium, COMGETTER(Location)(path.asOutParam()));
+ CHECK_ERROR(pMedium, COMGETTER(Format)(format.asOutParam()));
+ CHECK_ERROR(pMedium, COMGETTER(Type)(pType));
+ CHECK_ERROR(pMedium, COMGETTER(Size)(pSize));
+
+ info->pszUuid = RTStrDup((char *)CSTR(uuid));
+ info->pszBaseUuid = RTStrDup((char *)CSTR(baseUuid));
+ info->pszPath = RTStrDup((char *)CSTR(path));
+ info->pszFormat = RTStrDup((char *)CSTR(format));
+ info->fSnapshot = RTStrCmp(CSTR(uuid), CSTR(baseUuid)) != 0;
+
+ if (info->fSnapshot)
+ {
+ /** @todo Determine the VM snapshot this and set name and description
+ * to the snapshot name/description
+ */
+ CHECK_ERROR(pMedium, COMGETTER(Name)(name.asOutParam()));
+ CHECK_ERROR(pMedium, COMGETTER(Description)(description.asOutParam()));
+ }
+ else
+ {
+ CHECK_ERROR(pMedium, COMGETTER(Name)(name.asOutParam()));
+ CHECK_ERROR(pMedium, COMGETTER(Description)(description.asOutParam()));
+ }
+
+ info->pszName = RTStrDup((char *)CSTR(name));
+ info->pszDescription = RTStrDup((char *)CSTR(description));
+
+ switch(*pType)
+ {
+ case MediumType_Normal:
+ info->pszType = (char *)"normal";
+ break;
+ case MediumType_Immutable:
+ info->pszType = (char *)"immutable";
+ break;
+ case MediumType_Writethrough:
+ info->pszType = (char *)"writethrough";
+ break;
+ case MediumType_Shareable:
+ info->pszType = (char *)"shareable";
+ break;
+ case MediumType_Readonly:
+ info->pszType = (char *)"readonly";
+ break;
+ case MediumType_MultiAttach:
+ info->pszType = (char *)"multiattach";
+ break;
+ default:
+ info->pszType = (char *)"?";
+ }
+
+ switch(*pState)
+ {
+ case MediumState_NotCreated:
+ info->pszState = (char *)"uncreated";
+ break;
+ case MediumState_Created:
+ info->pszState = (char *)"created";
+ break;
+ case MediumState_LockedRead:
+ info->pszState = (char *)"rlock";
+ break;
+ case MediumState_LockedWrite:
+ info->pszState = (char *)"wlock";
+ break;
+ case MediumState_Inaccessible:
+ info->pszState = (char *)"no access";
+ break;
+ case MediumState_Creating:
+ info->pszState = (char *)"creating";
+ break;
+ case MediumState_Deleting:
+ info->pszState = (char *)"deleting";
+ break;
+ default:
+ info->pszState = (char *)"?";
+ }
+ return VINF_SUCCESS;
+}
+
+static void displayMediumInfo(MEDIUMINFO *pInfo, int nestLevel, bool fLast)
+{
+ char *pszSzScaled = vboximgScaledSize(pInfo->cbSize);
+ int cPad = nestLevel * 2;
+ if (g_vboximgOpts.fWide && !g_vboximgOpts.fVerbose)
+ {
+ RTPrintf("%3s %-*s %7s %-9s %9s %-*s %s\n",
+ !fLast ? (pInfo->fSnapshot ? " | " : " +-") : (pInfo->fSnapshot ? " " : " +-"),
+ VM_MAX_NAME, pInfo->fSnapshot ? "+- <snapshot>" : pInfo->pszName,
+ pszSzScaled,
+ pInfo->pszFormat,
+ pInfo->pszState,
+ cPad, "", pInfo->pszUuid);
+ }
+ else
+ {
+ if (!pInfo->fSnapshot)
+ {
+ RTPrintf(" Image: %s\n", pInfo->pszName);
+ if (pInfo->pszDescription && RTStrNLen(pInfo->pszDescription, 256) > 0)
+ RTPrintf("Desc: %s\n", pInfo->pszDescription);
+ RTPrintf(" UUID: %s\n", pInfo->pszUuid);
+ if (g_vboximgOpts.fVerbose)
+ {
+ RTPrintf(" Path: %s\n", pInfo->pszPath);
+ RTPrintf(" Format: %s\n", pInfo->pszFormat);
+ RTPrintf(" Size: %s\n", pszSzScaled);
+ RTPrintf(" State: %s\n", pInfo->pszState);
+ RTPrintf(" Type: %s\n", pInfo->pszType);
+ }
+ RTPrintf("\n");
+ }
+ else
+ {
+ RTPrintf(" Snapshot: %s\n", pInfo->pszUuid);
+ if (g_vboximgOpts.fVerbose)
+ {
+ RTPrintf(" Name: %s\n", pInfo->pszName);
+ RTPrintf(" Desc: %s\n", pInfo->pszDescription);
+ }
+ RTPrintf(" Size: %s\n", pszSzScaled);
+ if (g_vboximgOpts.fVerbose)
+ RTPrintf(" Path: %s\n", pInfo->pszPath);
+ RTPrintf("\n");
+ }
+ }
+ RTMemFree(pszSzScaled);
+}
+
+static int vboximgListBranch(IMachine *pMachine, IMedium *pMedium, uint8_t nestLevel, bool fLast)
+{
+ MEDIUMINFO *pMediumInfo;
+ int vrc = getMediumInfo(pMachine, pMedium, &pMediumInfo);
+ if (RT_FAILURE(vrc))
+ return vrc;
+
+ displayMediumInfo(pMediumInfo, nestLevel, fLast);
+
+ HRESULT hrc;
+ com::SafeIfaceArray<IMedium> pChildren;
+ CHECK_ERROR_RET(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(pChildren)), VERR_NOT_FOUND); /** @todo r=andy Find a better rc. */
+
+ for (size_t i = 0; i < pChildren.size(); i++)
+ vboximgListBranch(pMachine, pChildren[i], nestLevel + 1, fLast);
+
+ delete pMediumInfo;
+
+ return VINF_SUCCESS;
+}
+
+static int listMedia(IVirtualBox *pVirtualBox, IMachine *pMachine, char *vmName, char *vmUuid)
+{
+ RT_NOREF(pVirtualBox);
+ RT_NOREF(vmName);
+ RT_NOREF(vmUuid);
+
+ int vrc = VINF_SUCCESS;
+
+ com::SafeIfaceArray<IMediumAttachment> pMediumAttachments;
+
+ HRESULT hrc;
+ CHECK_ERROR(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(pMediumAttachments)));
+
+ for (size_t i = 0; i < pMediumAttachments.size(); i++)
+ {
+ bool fLast = (i == pMediumAttachments.size() - 1);
+ DeviceType_T deviceType;
+
+ CHECK_ERROR(pMediumAttachments[i], COMGETTER(Type)(&deviceType));
+ if (deviceType != DeviceType_HardDisk)
+ continue;
+
+ ComPtr<IMedium> pMedium;
+ CHECK_ERROR(pMediumAttachments[i], COMGETTER(Medium)(pMedium.asOutParam()));
+
+ ComPtr<IMedium> pBase;
+ CHECK_ERROR(pMedium, COMGETTER(Base)(pBase.asOutParam()));
+ if (g_vboximgOpts.fWide && !g_vboximgOpts.fVerbose)
+ RTPrintf(" |\n");
+ else
+ RTPrintf("\n");
+
+ vrc = vboximgListBranch(pMachine, pBase, 0, fLast);
+ if (RT_FAILURE(vrc))
+ {
+ RTPrintf("vboximgListBranch failed with %Rrc\n", vrc);
+ break;
+ }
+ }
+
+ return vrc;
+}
+/**
+ * Display all registered VMs on the screen with some information about each
+ *
+ * @param virtualBox VirtualBox instance object.
+ */
+int vboximgListVMs(IVirtualBox *pVirtualBox)
+{
+ HRESULT hrc;
+ com::SafeIfaceArray<IMachine> pMachines;
+ CHECK_ERROR(pVirtualBox, COMGETTER(Machines)(ComSafeArrayAsOutParam(pMachines)));
+
+ if (g_vboximgOpts.fWide)
+ {
+ RTPrintf("\n");
+ RTPrintf("VM Image Size Type State UUID (hierarchy)\n");
+ }
+
+ int vrc = VINF_SUCCESS;
+
+ for (size_t i = 0; i < pMachines.size(); ++i)
+ {
+ ComPtr<IMachine> pMachine = pMachines[i];
+ if (pMachine)
+ {
+ BOOL fAccessible;
+ CHECK_ERROR(pMachines[i], COMGETTER(Accessible)(&fAccessible));
+ if (fAccessible)
+ {
+ Bstr machineName;
+ Bstr machineUuid;
+ Bstr description;
+ Bstr machineLocation;
+
+ CHECK_ERROR(pMachine, COMGETTER(Name)(machineName.asOutParam()));
+ CHECK_ERROR(pMachine, COMGETTER(Id)(machineUuid.asOutParam()));
+ CHECK_ERROR(pMachine, COMGETTER(Description)(description.asOutParam()));
+ CHECK_ERROR(pMachine, COMGETTER(SettingsFilePath)(machineLocation.asOutParam()));
+
+
+ if ( g_vboximgOpts.pszVm == NULL
+ || RTStrNCmp(CSTR(machineUuid), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0
+ || RTStrNCmp((const char *)machineName.raw(), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0)
+ {
+ if (g_vboximgOpts.fVerbose)
+ {
+ RTPrintf("-----------------------------------------------------------------\n");
+ RTPrintf("VM Name: \"%s\"\n", CSTR(machineName));
+ RTPrintf("UUID: %s\n", CSTR(machineUuid));
+ if (*description.raw() != '\0')
+ RTPrintf("Desc: %s\n", CSTR(description));
+ RTPrintf("Path: %s\n", CSTR(machineLocation));
+ }
+ else
+ {
+ if (g_vboximgOpts.fWide & !g_vboximgOpts.fVerbose)
+ {
+ RTPrintf("----------------------------------------------------------------- "
+ "------------------------------------\n");
+ RTPrintf("%-*s %*s %s\n", VM_MAX_NAME, CSTR(machineName), 33, "", CSTR(machineUuid));
+ }
+ else
+ {
+ RTPrintf("-----------------------------------------------------------------\n");
+ RTPrintf("VM: %s\n", CSTR(machineName));
+ RTPrintf("UUID: %s\n", CSTR(machineUuid));
+ }
+ }
+
+ int vrc2 = listMedia(pVirtualBox, pMachine,
+ RTStrDup(CSTR(machineName)), RTStrDup(CSTR(machineUuid)));
+ if (RT_SUCCESS(vrc))
+ vrc = vrc2;
+
+ RTPrintf("\n");
+ }
+ }
+ }
+ }
+
+ return vrc;
+}
+