[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] Added Storage Volume support to VIrtualBox



Hi All,

I have added support for Storage Volumes in VirtualBox, the patch for the same 
is attached here.

(needs the "little bit cleanup" patch previously posted)

Regards,
Pritesh
commit 4fc1ae881a8c45985c777605a012933c783f7d7c
Author: Pritesh Kothari <Pritesh Kothari Sun com>
Date:   Thu Sep 3 17:17:09 2009 +0200

    libvirt: New Storage API for vbox

diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c
index a863a66..450f306 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 2ff4610..dfc4df9 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,15 +251,38 @@ 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;
+}
 
-#else /* !(VBOX_API_VERSION == 2002) */
+static void vboxIIDtoUtf8(virConnectPtr conn, vboxIID *iid, char **uuidstr) {
+    unsigned char hddUUID[VIR_UUID_BUFLEN];
 
-typedef PRUnichar vboxIID;
+    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) */
 
 #define vboxIIDFromUUID(uuid, iid)\
 {\
@@ -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,
+};

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]