From 6b50bbea0098e81e88ac40d60846fd1a5ace60f5 Mon Sep 17 00:00:00 2001 From: Pritesh Kothari Date: Fri, 4 Sep 2009 16:28:52 +0200 Subject: [PATCH] VBox add Storage Volume support * src/vbox/vbox_driver.c src/vbox/vbox_tmpl.c: adds the driver for storage volumes --- src/vbox/vbox_driver.c | 8 + src/vbox/vbox_tmpl.c | 932 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 933 insertions(+), 7 deletions(-) diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index a863a66e17..450f306aee 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -41,8 +41,10 @@ extern virDriver vbox22Driver; extern virNetworkDriver vbox22NetworkDriver; +extern virStorageDriver vbox22StorageDriver; extern virDriver vbox30Driver; extern virNetworkDriver vbox30NetworkDriver; +extern virStorageDriver vbox30StorageDriver; static virDriver vboxDriverDummy; @@ -55,6 +57,7 @@ static virDriver vboxDriverDummy; int vboxRegister(void) { virDriverPtr driver; virNetworkDriverPtr networkDriver; + virStorageDriverPtr storageDriver; uint32_t uVersion; /* @@ -65,6 +68,7 @@ int vboxRegister(void) { */ driver = &vboxDriverDummy; networkDriver = &vbox22NetworkDriver; + storageDriver = &vbox22StorageDriver; /* Init the glue and get the API version. */ if (VBoxCGlueInit() == 0) { @@ -83,10 +87,12 @@ int vboxRegister(void) { DEBUG0("VirtualBox API version: 2.2"); driver = &vbox22Driver; networkDriver = &vbox22NetworkDriver; + storageDriver = &vbox22StorageDriver; } else if (uVersion >= 2002051 && uVersion < 3000051) { DEBUG0("VirtualBox API version: 3.0"); driver = &vbox30Driver; networkDriver = &vbox30NetworkDriver; + storageDriver = &vbox30StorageDriver; } else { DEBUG0("Unsupport VirtualBox API version"); } @@ -99,6 +105,8 @@ int vboxRegister(void) { return -1; if (virRegisterNetworkDriver(networkDriver) < 0) return -1; + if (virRegisterStorageDriver(storageDriver) < 0) + return -1; return 0; } diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 2ff4610141..dfc4df925e 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -44,6 +44,7 @@ #include "network_conf.h" #include "virterror_internal.h" #include "domain_event.h" +#include "storage_conf.h" #include "uuid.h" #include "event.h" #include "memory.h" @@ -159,6 +160,15 @@ static void vboxDriverUnlock(vboxGlobalData *data) { } #if VBOX_API_VERSION == 2002 + +#define vboxIIDFromUUID(uuid, iid) nsIDFromChar((iid), (uuid)) +#define vboxIIDToUUID(uuid, iid) nsIDtoChar((uuid), (iid)) +#define vboxIIDUnalloc(iid) data->pFuncs->pfnComUnallocMem(iid) +#define vboxIIDFree(iid) VIR_FREE(iid) +#define vboxIIDUtf8Free(iid) VIR_FREE(iid) +#define vboxIIDUtf16Free(iid) VIR_FREE(iid) +#define DEBUGIID(msg, iid) DEBUGUUID(msg, iid) + static void nsIDtoChar(unsigned char *uuid, const nsID *iid) { char uuidstrsrc[VIR_UUID_STRING_BUFLEN]; char uuidstrdst[VIR_UUID_STRING_BUFLEN]; @@ -241,16 +251,39 @@ static void nsIDFromChar(nsID *iid, const unsigned char *uuid) { typedef nsID vboxIID; -#define vboxIIDFromUUID(uuid, iid) nsIDFromChar((iid), (uuid)) -#define vboxIIDToUUID(uuid, iid) nsIDtoChar((uuid), (iid)) -#define vboxIIDUnalloc(iid) data->pFuncs->pfnComUnallocMem(iid) -#define vboxIIDFree(iid) VIR_FREE(iid) -#define DEBUGIID(msg, iid) DEBUGUUID(msg, iid) +static bool vboxIIDEqual(vboxIID *firstIID, vboxIID *secondIID) { + if (memcmp(firstIID, secondIID, sizeof(firstIID)) == 0) + return true; + else + return false; +} + +static void vboxIIDtoUtf8(virConnectPtr conn, vboxIID *iid, char **uuidstr) { + unsigned char hddUUID[VIR_UUID_BUFLEN]; + + if (VIR_ALLOC_N(*uuidstr, VIR_UUID_STRING_BUFLEN) < 0) { + virReportOOMError(conn); + return; + } + + vboxIIDToUUID(hddUUID, iid); + virUUIDFormat(hddUUID, *uuidstr); +} + +static void vboxUtf8toIID(virConnectPtr conn, char *uuidstr, vboxIID **iid) { + unsigned char hddUUID[VIR_UUID_BUFLEN]; + + if (VIR_ALLOC(*iid) < 0) { + virReportOOMError(conn); + return; + } + + virUUIDParse(uuidstr, hddUUID); + vboxIIDFromUUID(hddUUID, *iid); +} #else /* !(VBOX_API_VERSION == 2002) */ -typedef PRUnichar vboxIID; - #define vboxIIDFromUUID(uuid, iid)\ {\ char vboxIIDUtf8[VIR_UUID_STRING_BUFLEN];\ @@ -268,9 +301,56 @@ typedef PRUnichar vboxIID; } #define vboxIIDFree(iid) data->pFuncs->pfnUtf16Free(iid) +#define vboxIIDUtf8Free(iid) data->pFuncs->pfnUtf8Free(iid) +#define vboxIIDUtf16Free(iid) data->pFuncs->pfnUtf16Free(iid) #define vboxIIDUnalloc(iid) data->pFuncs->pfnUtf16Free(iid) #define DEBUGIID(msg, strUtf16) DEBUGPRUnichar(msg, strUtf16) +typedef PRUnichar vboxIID; + +static bool vboxIIDEqual(vboxIID *firstIID, vboxIID *secondIID) { + unsigned char firstUUID[VIR_UUID_BUFLEN]; + unsigned char secondUUID[VIR_UUID_BUFLEN]; + char *firstIIDUtf8 = NULL; + char *secondIIDUtf8 = NULL; + + if (!g_pVBoxGlobalData) + return false; + + g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(firstIID, &firstIIDUtf8); + g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(secondIID, &secondIIDUtf8); + + /* Note: we can't directly compare the utf8 strings here + * cause the two UUID's may have seperators as space or '-' + * or mixture of both and we don't want to fail here by + * using direct string comparison. Here virUUIDParse() takes + * care of these cases. + */ + + virUUIDParse(firstIIDUtf8, firstUUID); + virUUIDParse(secondIIDUtf8, secondUUID); + + g_pVBoxGlobalData->pFuncs->pfnUtf8Free(firstIIDUtf8); + g_pVBoxGlobalData->pFuncs->pfnUtf8Free(secondIIDUtf8); + + if (memcmp(firstUUID, secondUUID, sizeof(firstIID)) == 0) + return true; + else + return false; +} + +static void vboxIIDtoUtf8(virConnectPtr conn, vboxIID *iid, char **uuidstr) { + g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(iid, uuidstr); + if (!(*uuidstr)) + virReportOOMError(conn); +} + +static void vboxUtf8toIID(virConnectPtr conn, char *uuidstr, vboxIID **iid) { + g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(uuidstr, iid); + if (!(*iid)) + virReportOOMError(conn); +} + #endif /* !(VBOX_API_VERSION == 2002) */ static virCapsPtr vboxCapsInit(void) { @@ -5475,6 +5555,806 @@ cleanup: return ret; } +/** + * The Storage Functions here on + */ + +static virDrvOpenStatus vboxStorageOpen (virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + vboxGlobalData *data = conn->privateData; + + if (STRNEQ(conn->driver->name, "VBOX")) + goto cleanup; + + if ((data->pFuncs == NULL) || + (data->vboxObj == NULL) || + (data->vboxSession == NULL)) + goto cleanup; + + DEBUG0("vbox storage intialized"); + /* conn->storagePrivateData = some storage specific data */ + return VIR_DRV_OPEN_SUCCESS; + +cleanup: + return VIR_DRV_OPEN_DECLINED; +} + +static int vboxStorageClose (virConnectPtr conn) { + DEBUG0("vbox storage unintialized"); + conn->storagePrivateData = NULL; + return 0; +} + +static int vboxStorageNumOfPools(virConnectPtr conn ATTRIBUTE_UNUSED) { + + /** Currently only one pool supported, the default one + * given by ISystemProperties::defaultHardDiskFolder() + */ + + return 1; +} + +static int vboxStorageListPools(virConnectPtr conn, char **const names, int nnames) { + int numActive = 0; + + if (nnames == 1) { + names[numActive] = strdup("default-pool"); + if (names[numActive] == NULL) { + virReportOOMError(conn); + } else { + numActive++; + } + } + return numActive; +} + +static virStoragePoolPtr vboxStoragePoolLookupByName(virConnectPtr conn, const char *name) { + virStoragePoolPtr ret = NULL; + + /** Current limitation of the function: since + * the default pool doesn't have UUID just assign + * one till vbox can handle pools + */ + if (STREQ("default-pool", name)) { + unsigned char uuid[VIR_UUID_BUFLEN]; + const char *uuidstr = "1deff1ff-1481-464f-967f-a50fe8936cc4"; + + virUUIDParse(uuidstr, uuid); + + ret = virGetStoragePool(conn, name, uuid); + } + + return ret; +} + +static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool) { + vboxGlobalData *data = pool->conn->privateData; + IHardDisk **hardDisks = NULL; + PRUint32 hardDiskCount = 0; + PRUint32 hardDiskAccessible = 0; + nsresult rc; + int i; + + if(data->vboxObj) { + rc = data->vboxObj->vtbl->GetHardDisks(data->vboxObj, &hardDiskCount, &hardDisks); + if (NS_SUCCEEDED(rc)) { + for (i = 0; i < hardDiskCount; ++i) { + IHardDisk *hardDisk = hardDisks[i]; + if (hardDisk) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) + hardDiskAccessible++; + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + } + hardDiskCount = 0; + } else { + hardDiskCount = -1; + vboxError(pool->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x", + "could not get number of volumes in the pool", + pool->name, (unsigned)rc); + } + } + + if (hardDiskAccessible) + return hardDiskAccessible; + else + return hardDiskCount; +} + +static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) { + vboxGlobalData *data = pool->conn->privateData; + IHardDisk **hardDisks = NULL; + PRUint32 hardDiskCount = 0; + PRUint32 numActive = 0; + nsresult rc; + int i; + + if(data->vboxObj) { + rc = data->vboxObj->vtbl->GetHardDisks(data->vboxObj, &hardDiskCount, &hardDisks); + if (NS_SUCCEEDED(rc)) { + for (i = 0; i < hardDiskCount && numActive < nnames; ++i) { + IHardDisk *hardDisk = hardDisks[i]; + + if (hardDisk) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + char *nameUtf8 = NULL; + PRUnichar *nameUtf16 = NULL; + + hardDisk->vtbl->imedium.GetName((IMedium *)hardDisk, &nameUtf16); + data->pFuncs->pfnUtf16ToUtf8(nameUtf16, &nameUtf8); + + if (nameUtf8) { + DEBUG("nnames[%d]: %s", numActive, nameUtf8); + names[numActive] = strdup(nameUtf8); + if (names[numActive] == NULL) { + virReportOOMError(pool->conn); + } else { + numActive++; + } + + data->pFuncs->pfnUtf8Free(nameUtf8); + } + data->pFuncs->pfnUtf16Free(nameUtf16); + } + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + } + hardDiskCount = 0; + } else { + hardDiskCount = -1; + vboxError(pool->conn, VIR_ERR_INTERNAL_ERROR,"%s:%s, rc=%08x", + "could not get the volume list in the pool", + pool->name, (unsigned)rc); + } + } + + if (numActive) + return numActive; + else + return hardDiskCount; +} + +static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) { + vboxGlobalData *data = pool->conn->privateData; + IHardDisk **hardDisks = NULL; + virStorageVolPtr ret = NULL; + PRUint32 hardDiskCount = 0; + nsresult rc; + int i; + + if(data->vboxObj && name) { + rc = data->vboxObj->vtbl->GetHardDisks(data->vboxObj, &hardDiskCount, &hardDisks); + if (NS_SUCCEEDED(rc)) { + for (i = 0; i < hardDiskCount; ++i) { + IHardDisk *hardDisk = hardDisks[i]; + + if (hardDisk) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + char *nameUtf8 = NULL; + PRUnichar *nameUtf16 = NULL; + + hardDisk->vtbl->imedium.GetName((IMedium *)hardDisk, &nameUtf16); + + if (nameUtf16) { + data->pFuncs->pfnUtf16ToUtf8(nameUtf16, &nameUtf8); + data->pFuncs->pfnUtf16Free(nameUtf16); + } + + if (nameUtf8 && STREQ(nameUtf8, name)) { + vboxIID *hddIID = NULL; + char *hddIIDUtf8 = NULL; + + hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk, &hddIID); + + if (hddIID) { + vboxIIDtoUtf8(pool->conn, hddIID, &hddIIDUtf8); + vboxIIDUnalloc(hddIID); + } + + if (hddIIDUtf8) { + + ret = virGetStorageVol(pool->conn, pool->name, name, hddIIDUtf8); + + DEBUG("virStorageVolPtr: %p", ret); + DEBUG("Storage Volume Name: %s", name); + DEBUG("Storage Volume key : %s", hddIIDUtf8); + DEBUG("Storage Volume Pool: %s", pool->name); + + vboxIIDUtf8Free(hddIIDUtf8); + } + + data->pFuncs->pfnUtf8Free(nameUtf8); + break; + } + + if (nameUtf8) + data->pFuncs->pfnUtf8Free(nameUtf8); + } + } + } + + for (i = 0; i < hardDiskCount; ++i) + if (hardDisks[i]) + hardDisks[i]->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisks[i]); + } + } + + return ret; +} + +static virStorageVolPtr vboxStorageVolLookupByKey(virConnectPtr conn, const char *key) { + vboxGlobalData *data = conn->privateData; + vboxIID *hddIID = NULL; + IHardDisk *hardDisk = NULL; + virStorageVolPtr ret = NULL; + nsresult rc; + +#if VBOX_API_VERSION == 2002 + if (VIR_ALLOC(hddIID) < 0) { + virReportOOMError(conn); + goto cleanup; + } + + if(data->vboxObj && key) { + unsigned char hddUUID[VIR_UUID_BUFLEN]; + + virUUIDParse(key, hddUUID); + vboxIIDFromUUID(hddUUID, hddIID); + { +#else /* VBOX_API_VERSION != 2002 */ + if(data->vboxObj && key) { + data->pFuncs->pfnUtf8ToUtf16(key, &hddIID); + if (hddIID) { +#endif /* VBOX_API_VERSION != 2002 */ + + rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID, &hardDisk); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + PRUnichar *hddNameUtf16 = NULL; + char *hddNameUtf8 = NULL; + + hardDisk->vtbl->imedium.GetName((IMedium *)hardDisk, &hddNameUtf16); + data->pFuncs->pfnUtf16ToUtf8(hddNameUtf16, &hddNameUtf8); + + if (hddNameUtf8) { + if (vboxStorageNumOfPools(conn) == 1) { + ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key); + DEBUG("Storage Volume Pool: %s", "default-pool"); + } else { + /* TODO: currently only one default pool and thus + * nothing here, change it when pools are supported + */ + } + + DEBUG("Storage Volume Name: %s", key); + DEBUG("Storage Volume key : %s", hddNameUtf8); + + data->pFuncs->pfnUtf8Free(hddNameUtf8); + data->pFuncs->pfnUtf16Free(hddNameUtf16); + } + } + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + } + } + +#if VBOX_API_VERSION == 2002 +cleanup: +#endif + vboxIIDFree(hddIID); + return ret; +} + +static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const char *path) { + vboxGlobalData *data = conn->privateData; + PRUnichar *hddPathUtf16 = NULL; + IHardDisk *hardDisk = NULL; + virStorageVolPtr ret = NULL; + nsresult rc; + + if(data->vboxObj && path) { + data->pFuncs->pfnUtf8ToUtf16(path, &hddPathUtf16); + + if (hddPathUtf16) { + rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + PRUnichar *hddNameUtf16 = NULL; + char *hddNameUtf8 = NULL; + vboxIID *hddIID = NULL; + char *hddIIDUtf8 = NULL; + + hardDisk->vtbl->imedium.GetName((IMedium *)hardDisk, &hddNameUtf16); + hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk, &hddIID); + + if (hddNameUtf16) { + data->pFuncs->pfnUtf16ToUtf8(hddNameUtf16, &hddNameUtf8); + data->pFuncs->pfnUtf16Free(hddNameUtf16); + } + + if (hddIID) { + vboxIIDtoUtf8(conn, hddIID, &hddIIDUtf8); + vboxIIDUnalloc(hddIID); + } + + if (hddIIDUtf8 && hddNameUtf8) { + + /* TODO: currently only one default pool and thus + * the check below, change it when pools are supported + */ + if (vboxStorageNumOfPools(conn) == 1) + ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, hddIIDUtf8); + + DEBUG("Storage Volume Pool: %s", "default-pool"); + DEBUG("Storage Volume Name: %s", hddNameUtf8); + DEBUG("Storage Volume key : %s", hddIIDUtf8); + + } + + if (hddNameUtf8) + data->pFuncs->pfnUtf8Free(hddNameUtf8); + + if (hddIIDUtf8) + vboxIIDUtf8Free(hddIIDUtf8); + } + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + + data->pFuncs->pfnUtf16Free(hddPathUtf16); + } + } + + return ret; +} + +static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool, + const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) { + vboxGlobalData *data = pool->conn->privateData; + virStorageVolPtr ret = NULL; + virStorageVolDefPtr def = NULL; + virStoragePoolDef poolDef; + nsresult rc; + + /* since there is currently one default pool now + * and virStorageVolDefFormat() just checks it type + * so just assign it for now, change the behaviour + * when vbox supports pools. + */ + memset(&poolDef, 0, sizeof(poolDef)); + poolDef.type = VIR_STORAGE_POOL_DIR; + + if ((def = virStorageVolDefParseString(pool->conn, &poolDef, xml)) == NULL) + goto cleanup; + + if ((data->vboxObj) && def->name && def->type == VIR_STORAGE_VOL_FILE) { + PRUnichar *hddFormatUtf16 = NULL; + PRUnichar *hddNameUtf16 = NULL; + + /* TODO: for now only the vmdk, vpc and vdi type harddisk + * variants can be created, also since there is no vdi + * type in enum virStorageVolFormatFileSystem {} the default + * will be to create vdi if nothing is specified in + * def->target.format + */ + + if (def->target.format == VIR_STORAGE_VOL_FILE_VMDK) { + data->pFuncs->pfnUtf8ToUtf16("VMDK", &hddFormatUtf16); + } else if (def->target.format == VIR_STORAGE_VOL_FILE_VPC) { + data->pFuncs->pfnUtf8ToUtf16("VHD", &hddFormatUtf16); + } else { + data->pFuncs->pfnUtf8ToUtf16("VDI", &hddFormatUtf16); + } + + data->pFuncs->pfnUtf8ToUtf16(def->name, &hddNameUtf16); + + if (hddFormatUtf16 && hddNameUtf16) { + IHardDisk *hardDisk = NULL; + + rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk); + if (NS_SUCCEEDED(rc)) { + IProgress *progress = NULL; + PRUint64 logicalSize = def->capacity / 1024 / 1024; + PRUint32 variant = HardDiskVariant_Standard; + + if (def->capacity == def->allocation) + variant = HardDiskVariant_Fixed; + + rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress); + if (NS_SUCCEEDED(rc) && progress) { + vboxIID *hddIID = NULL; +#if VBOX_API_VERSION == 2002 + nsresult resultCode; +#else + PRInt32 resultCode; +#endif + + progress->vtbl->WaitForCompletion(progress, -1); + progress->vtbl->GetResultCode(progress, &resultCode); + + if (NS_SUCCEEDED(resultCode)) { + + rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk, &hddIID); + if (NS_SUCCEEDED(rc)) { + char *hddKey = NULL; + + vboxIIDtoUtf8(pool->conn, hddIID, &hddKey); + + if (hddKey) + ret = virGetStorageVol(pool->conn, pool->name, def->name, hddKey); + + vboxIIDUtf8Free(hddKey); + vboxIIDUnalloc(hddIID); + } + } + + progress->vtbl->nsisupports.Release((nsISupports *)progress); + } + + } + } + + if (hddFormatUtf16) + data->pFuncs->pfnUtf16Free(hddFormatUtf16); + if (hddNameUtf16) + data->pFuncs->pfnUtf16Free(hddNameUtf16); + } + +cleanup: + virStorageVolDefFree(def); + return ret; +} + + +static int vboxStorageVolDelete(virStorageVolPtr vol, + unsigned int flags ATTRIBUTE_UNUSED) { + vboxGlobalData *data = vol->conn->privateData; + vboxIID *hddIID = NULL; + IHardDisk *hardDisk = NULL; + int ret = -1, i = 0, j = 0; + int deregister = 0; + nsresult rc; + + if(data->vboxObj && vol->key) { + + vboxUtf8toIID(vol->conn, vol->key, &hddIID); + if (hddIID) { + + rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID, &hardDisk); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + PRUint32 machineIdsSize = 0; + vboxIID **machineIds = NULL; + + hardDisk->vtbl->imedium.GetMachineIds((IMedium *)hardDisk, &machineIdsSize, &machineIds); + + for (i = 0; i < machineIdsSize; i++) { + IMachine *machine = NULL; + + rc = data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, machineIds[i]); + if (NS_SUCCEEDED(rc)) { + + rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddAttachSize = 0; + IHardDiskAttachment **hddAttachments = NULL; + + machine->vtbl->GetHardDiskAttachments(machine, &hddAttachSize, &hddAttachments); + for (j = 0; j < hddAttachSize; j++) { + IHardDiskAttachment *hddAttachment = hddAttachments[j]; + + if (hddAttachment) { + IHardDisk *hdd = NULL; + + rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd); + if (NS_SUCCEEDED(rc) && hdd) { + vboxIID *iid = NULL; + + hdd->vtbl->imedium.GetId((IMedium *)hdd, &iid); + if (iid) { + + DEBUGIID("HardDisk (to delete) UUID", hddIID); + DEBUGIID("HardDisk (currently processing) UUID", iid); + + if (vboxIIDEqual(hddIID, iid)) { + PRUnichar *controller = NULL; + PRInt32 port = 0; + PRInt32 device = 0; + + DEBUGIID("Found HardDisk to delete, UUID", hddIID); + + hddAttachment->vtbl->GetController(hddAttachment, &controller); + hddAttachment->vtbl->GetPort(hddAttachment, &port); + hddAttachment->vtbl->GetDevice(hddAttachment, &device); + + rc = machine->vtbl->DetachHardDisk(machine, controller, port, device); + if (NS_SUCCEEDED(rc)) { + rc = machine->vtbl->SaveSettings(machine); + DEBUG0("saving machine settings"); + } + + if (NS_SUCCEEDED(rc)) { + deregister++; + DEBUG("deregistering hdd:%d", deregister); + } + + if (controller) + data->pFuncs->pfnUtf16Free(controller); + } + vboxIIDUnalloc(iid); + } + hdd->vtbl->imedium.nsisupports.Release((nsISupports *)hdd); + } + hddAttachment->vtbl->nsisupports.Release((nsISupports *)hddAttachment); + } + } + machine->vtbl->nsisupports.Release((nsISupports *)machine); + } + data->vboxSession->vtbl->Close(data->vboxSession); + } + } + + for (i = 0; i < machineIdsSize; i++) + if (machineIds[i]) + vboxIIDUnalloc(machineIds[i]); + + if (machineIdsSize == 0 || machineIdsSize == deregister) { + IProgress *progress = NULL; + + rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress); + + if (NS_SUCCEEDED(rc) && progress) { + progress->vtbl->WaitForCompletion(progress, -1); + progress->vtbl->nsisupports.Release((nsISupports *)progress); + DEBUGIID("HardDisk deleted, UUID", hddIID); + ret = 0; + } + } + + } + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + + vboxIIDUtf16Free(hddIID); + } + } + + return ret; +} + +static int vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) { + vboxGlobalData *data = vol->conn->privateData; + IHardDisk *hardDisk = NULL; + vboxIID *hddIID = NULL; + int ret = -1; + nsresult rc; + + if(data->vboxObj && vol->key && info) { + + vboxUtf8toIID(vol->conn, vol->key, &hddIID); + if (hddIID) { + + rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID, &hardDisk); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + PRUint32 hddType; + PRUint64 hddLogicalSize; + PRUint64 hddActualSize; + + hardDisk->vtbl->GetType(hardDisk, &hddType); + if (hddType == HardDiskType_Writethrough) + info->type = VIR_STORAGE_VOL_BLOCK; + else + info->type = VIR_STORAGE_VOL_FILE; + + hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize); + info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */ + + hardDisk->vtbl->imedium.GetSize((IMedium *)hardDisk, &hddActualSize); + info->allocation = hddActualSize; + + ret = 0; + + DEBUG("Storage Volume Name: %s", vol->name); + DEBUG("Storage Volume Type: %s", info->type == VIR_STORAGE_VOL_BLOCK ? "Block" : "File"); + DEBUG("Storage Volume Capacity: %llu", info->capacity); + DEBUG("Storage Volume Allocation: %llu", info->allocation); + } + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + + vboxIIDUtf16Free(hddIID); + } + } + + return ret; +} + +static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags ATTRIBUTE_UNUSED) { + vboxGlobalData *data = vol->conn->privateData; + IHardDisk *hardDisk = NULL; + vboxIID *hddIID = NULL; + char *ret = NULL; + virStoragePoolDef pool; + virStorageVolDef def; + int defOk = 0; + nsresult rc; + + memset(&pool, 0, sizeof(pool)); + memset(&def, 0, sizeof(def)); + + if(data->vboxObj && vol->key) { + + vboxUtf8toIID(vol->conn, vol->key, &hddIID); + if (hddIID) { + + rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID, &hardDisk); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddstate; + + rc = hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) { + PRUnichar *hddFormatUtf16 = NULL; + PRUint64 hddLogicalSize; + PRUint64 hddActualSize; + PRUint32 hddType; + + /* since there is currently one default pool now + * and virStorageVolDefFormat() just checks it type + * so just assign it for now, change the behaviour + * when vbox supports pools. + */ + pool.type = VIR_STORAGE_POOL_DIR; + + rc = hardDisk->vtbl->GetType(hardDisk, &hddType); + if (NS_SUCCEEDED(rc)) { + if (hddType == HardDiskType_Writethrough) + def.type = VIR_STORAGE_VOL_BLOCK; + else + def.type = VIR_STORAGE_VOL_FILE; + defOk = 1; + } else { + defOk = 0; + } + + rc = hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize); + if (NS_SUCCEEDED(rc) && defOk) + def.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */ + else + defOk = 0; + + rc = hardDisk->vtbl->imedium.GetSize((IMedium *)hardDisk, &hddActualSize); + if (NS_SUCCEEDED(rc) && defOk) + def.allocation = hddActualSize; + else + defOk = 0; + + def.name = strdup(vol->name); + if (!(def.name && defOk)) + defOk = 0; + + def.key = strdup(vol->key); + if (!(def.key && defOk)) + defOk = 0; + + rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16); + if (NS_SUCCEEDED(rc) && defOk) { + char *hddFormatUtf8 = NULL; + + data->pFuncs->pfnUtf16ToUtf8(hddFormatUtf16, &hddFormatUtf8); + if (hddFormatUtf8) { + + DEBUG("Storage Volume Format: %s", hddFormatUtf8); + + if (STRCASEEQ("vmdk", hddFormatUtf8)) + def.target.format = VIR_STORAGE_VOL_FILE_VMDK; + else if (STRCASEEQ("vhd", hddFormatUtf8)) + def.target.format = VIR_STORAGE_VOL_FILE_VPC; + else + def.target.format = VIR_STORAGE_VOL_FILE_RAW; + + /* TODO: need to add vdi to enum virStorageVolFormatFileSystem {} + * and then add it here + */ + + data->pFuncs->pfnUtf8Free(hddFormatUtf8); + } + + data->pFuncs->pfnUtf16Free(hddFormatUtf16); + } else { + defOk = 0; + } + } + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + + vboxIIDUtf16Free(hddIID); + } + } + + if (defOk) + ret = virStorageVolDefFormat(vol->conn, &pool, &def); + + return ret; +} + +static char *vboxStorageVolGetPath(virStorageVolPtr vol) { + vboxGlobalData *data = vol->conn->privateData; + IHardDisk *hardDisk = NULL; + vboxIID *hddIID = NULL; + char *ret = NULL; + nsresult rc; + + if(data->vboxObj && vol->key) { + + vboxUtf8toIID(vol->conn, vol->key, &hddIID); + if (hddIID) { + + rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID, &hardDisk); + if (NS_SUCCEEDED(rc)) { + PRUint32 hddstate; + + hardDisk->vtbl->imedium.GetState((IMedium *)hardDisk, &hddstate); + if (hddstate != MediaState_Inaccessible) { + PRUnichar *hddLocationUtf16 = NULL; + char *hddLocationUtf8 = NULL; + + hardDisk->vtbl->imedium.GetLocation((IMedium *)hardDisk, &hddLocationUtf16); + + data->pFuncs->pfnUtf16ToUtf8(hddLocationUtf16, &hddLocationUtf8); + if (hddLocationUtf8) { + + ret = strdup(hddLocationUtf8); + if (!ret) + virReportOOMError(vol->conn); + + DEBUG("Storage Volume Name: %s", vol->name); + DEBUG("Storage Volume Path: %s", hddLocationUtf8); + DEBUG("Storage Volume Pool: %s", vol->pool); + + data->pFuncs->pfnUtf8Free(hddLocationUtf8); + } + + data->pFuncs->pfnUtf16Free(hddLocationUtf16); + } + + hardDisk->vtbl->imedium.nsisupports.Release((nsISupports *)hardDisk); + } + + vboxIIDUtf16Free(hddIID); + } + } + + return ret; +} /** * Function Tables @@ -5576,3 +6456,41 @@ virNetworkDriver NAME(NetworkDriver) = { .networkGetAutostart = NULL, .networkSetAutostart = NULL }; + +virStorageDriver NAME(StorageDriver) = { + .name = "VBOX", + .open = vboxStorageOpen, + .close = vboxStorageClose, + .numOfPools = vboxStorageNumOfPools, + .listPools = vboxStorageListPools, + .numOfDefinedPools = NULL, + .listDefinedPools = NULL, + .findPoolSources = NULL, + .poolLookupByName = vboxStoragePoolLookupByName, + .poolLookupByUUID = NULL, + .poolLookupByVolume = NULL, + .poolCreateXML = NULL, + .poolDefineXML = NULL, + .poolBuild = NULL, + .poolUndefine = NULL, + .poolCreate = NULL, + .poolDestroy = NULL, + .poolDelete = NULL, + .poolRefresh = NULL, + .poolGetInfo = NULL, + .poolGetXMLDesc = NULL, + .poolGetAutostart = NULL, + .poolSetAutostart = NULL, + .poolNumOfVolumes = vboxStoragePoolNumOfVolumes, + .poolListVolumes = vboxStoragePoolListVolumes, + + .volLookupByName = vboxStorageVolLookupByName, + .volLookupByKey = vboxStorageVolLookupByKey, + .volLookupByPath = vboxStorageVolLookupByPath, + .volCreateXML = vboxStorageVolCreateXML, + .volCreateXMLFrom = NULL, + .volDelete = vboxStorageVolDelete, + .volGetInfo = vboxStorageVolGetInfo, + .volGetXMLDesc = vboxStorageVolGetXMLDesc, + .volGetPath = vboxStorageVolGetPath, +};