vbox_tmpl.c 387.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/** @file vbox_tmpl.c
 * Template File to support multiple versions of VirtualBox
 * at runtime :).
 *
 * IMPORTANT:
 * Please dont include this file in the src/Makefile.am, it
 * is automatically include by other files.
 */

/*
11
 * Copyright (C) 2010-2014 Red Hat, Inc.
12 13 14 15 16
 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
 *
 * This file is part of a free software library; you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software
17
 * Foundation and shipped in the "COPYING.LESSER" file with this library.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 * The library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY of any kind.
 *
 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if
 * any license choice other than GPL or LGPL is available it will
 * apply instead, Sun elects to use only the Lesser General Public
 * License version 2.1 (LGPLv2) at this time for any software where
 * a choice of LGPL license versions is made available with the
 * language indicating that LGPLv2 or any later version may be used,
 * or where a choice of which version of the LGPL is applied is
 * otherwise unspecified.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 * additional information or have any questions.
 */

#include <config.h>

37
#include <unistd.h>
38 39 40
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
41 42 43 44

#include "internal.h"
#include "datatypes.h"
#include "domain_conf.h"
45
#include "snapshot_conf.h"
46
#include "vbox_snapshot_conf.h"
47
#include "network_conf.h"
48
#include "virerror.h"
49
#include "domain_event.h"
50
#include "storage_conf.h"
51
#include "virstoragefile.h"
52
#include "viruuid.h"
53
#include "viralloc.h"
54
#include "nodeinfo.h"
55
#include "virlog.h"
56
#include "vbox_driver.h"
57
#include "configmake.h"
E
Eric Blake 已提交
58
#include "virfile.h"
59
#include "fdstream.h"
M
Martin Kletzander 已提交
60
#include "viruri.h"
61
#include "virstring.h"
62 63
#include "virtime.h"
#include "virutil.h"
64 65

/* This one changes from version to version. */
66
#if VBOX_API_VERSION == 2002000
67
# include "vbox_CAPI_v2_2.h"
68
#elif VBOX_API_VERSION == 3000000
69
# include "vbox_CAPI_v3_0.h"
70
#elif VBOX_API_VERSION == 3001000
71
# include "vbox_CAPI_v3_1.h"
72
#elif VBOX_API_VERSION == 3002000
73
# include "vbox_CAPI_v3_2.h"
74
#elif VBOX_API_VERSION == 4000000
75
# include "vbox_CAPI_v4_0.h"
76
#elif VBOX_API_VERSION == 4001000
77
# include "vbox_CAPI_v4_1.h"
78
#elif VBOX_API_VERSION == 4002000
79
# include "vbox_CAPI_v4_2.h"
80 81 82
#elif VBOX_API_VERSION == 4002020
# include "vbox_CAPI_v4_2_20.h"
#elif VBOX_API_VERSION == 4003000
R
Ryota Ozaki 已提交
83
# include "vbox_CAPI_v4_3.h"
84 85
#elif VBOX_API_VERSION == 4003004
# include "vbox_CAPI_v4_3_4.h"
86 87
#else
# error "Unsupport VBOX_API_VERSION"
88 89
#endif

90
/* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
91
#include "vbox_glue.h"
T
Taowei 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104

#if VBOX_API_VERSION < 4000000
typedef IVRDPServer IVRDxServer;
#else /* VBOX_API_VERSION >= 4000000 */
typedef IVRDEServer IVRDxServer;
#endif /* VBOX_API_VERSION >= 4000000 */

#if VBOX_API_VERSION < 4003000
typedef IUSBController IUSBCommon;
#else /* VBOX_API_VERSION >= 4003000 */
typedef IUSBDeviceFilters IUSBCommon;
#endif /* VBOX_API_VERSION >= 4003000 */

T
Taowei 已提交
105
#include "vbox_uniformed_api.h"
106

107
#define VIR_FROM_THIS                   VIR_FROM_VBOX
108 109 110

VIR_LOG_INIT("vbox.vbox_tmpl");

T
Taowei 已提交
111 112 113
#define vboxUnsupported() \
    VIR_WARN("No %s in current vbox version %d.", __FUNCTION__, VBOX_API_VERSION);

J
John Ferlan 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#define VBOX_UTF16_FREE(arg)                                            \
    do {                                                                \
        if (arg) {                                                      \
            data->pFuncs->pfnUtf16Free(arg);                            \
            (arg) = NULL;                                               \
        }                                                               \
    } while (0)

#define VBOX_UTF8_FREE(arg)                                             \
    do {                                                                \
        if (arg) {                                                      \
            data->pFuncs->pfnUtf8Free(arg);                             \
            (arg) = NULL;                                               \
        }                                                               \
    } while (0)

#define VBOX_COM_UNALLOC_MEM(arg)                                       \
    do {                                                                \
        if (arg) {                                                      \
            data->pFuncs->pfnComUnallocMem(arg);                        \
            (arg) = NULL;                                               \
        }                                                               \
    } while (0)

138 139 140
#define VBOX_UTF16_TO_UTF8(arg1, arg2)  data->pFuncs->pfnUtf16ToUtf8(arg1, arg2)
#define VBOX_UTF8_TO_UTF16(arg1, arg2)  data->pFuncs->pfnUtf8ToUtf16(arg1, arg2)

141 142
#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))

143 144 145 146 147 148 149
#define VBOX_RELEASE(arg)                                                     \
    do {                                                                      \
        if (arg) {                                                            \
            (arg)->vtbl->nsisupports.Release((nsISupports *)(arg));           \
            (arg) = NULL;                                                     \
        }                                                                     \
    } while (0)
150 151 152 153

#define VBOX_OBJECT_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
154
if (!data->vboxObj) {\
155 156 157 158 159 160 161
    return ret;\
}

#define VBOX_OBJECT_HOST_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
IHost *host = NULL;\
162
if (!data->vboxObj) {\
163 164 165 166 167 168 169
    return ret;\
}\
data->vboxObj->vtbl->GetHost(data->vboxObj, &host);\
if (!host) {\
    return ret;\
}

170
#if VBOX_API_VERSION < 3001000
171

172
# define VBOX_MEDIUM_RELEASE(arg) \
173
if (arg)\
174
    (arg)->vtbl->imedium.nsisupports.Release((nsISupports *)(arg))
175
# define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
176
    (object)->vtbl->imedium.func((IMedium *)(object), arg1)
177
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
178 179
    (object)->vtbl->imedium.func((IMedium *)(object), arg1, arg2)

180
#else  /* VBOX_API_VERSION >= 3001000 */
181 182 183

typedef IMedium IHardDisk;
typedef IMediumAttachment IHardDiskAttachment;
184 185 186 187 188
# define MediaState_Inaccessible     MediumState_Inaccessible
# define HardDiskVariant_Standard    MediumVariant_Standard
# define HardDiskVariant_Fixed       MediumVariant_Fixed
# define VBOX_MEDIUM_RELEASE(arg) VBOX_RELEASE(arg)
# define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
189
    (object)->vtbl->func(object, arg1)
190
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
191 192
    (object)->vtbl->func(object, arg1, arg2)

193
#endif /* VBOX_API_VERSION >= 3001000 */
194

195 196 197 198 199 200
#define DEBUGPRUnichar(msg, strUtf16) \
if (strUtf16) {\
    char *strUtf8 = NULL;\
\
    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\
    if (strUtf8) {\
201
        VIR_DEBUG("%s: %s", msg, strUtf8);\
202 203 204 205 206 207
        g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\
    }\
}

#define DEBUGUUID(msg, iid) \
{\
T
Taowei 已提交
208
    VIR_DEBUG("%s: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", msg,\
209 210 211 212 213 214 215 216 217 218 219 220 221
          (unsigned)(iid)->m0,\
          (unsigned)(iid)->m1,\
          (unsigned)(iid)->m2,\
          (unsigned)(iid)->m3[0],\
          (unsigned)(iid)->m3[1],\
          (unsigned)(iid)->m3[2],\
          (unsigned)(iid)->m3[3],\
          (unsigned)(iid)->m3[4],\
          (unsigned)(iid)->m3[5],\
          (unsigned)(iid)->m3[6],\
          (unsigned)(iid)->m3[7]);\
}\

T
Taowei 已提交
222
#if VBOX_API_VERSION > 2002000
223

224 225 226 227 228 229 230 231 232 233
/* g_pVBoxGlobalData has to be global variable,
 * there is no other way to make the callbacks
 * work other then having g_pVBoxGlobalData as
 * global, because the functions namely AddRef,
 * Release, etc consider it as global and you
 * can't change the function definition as it
 * is XPCOM nsISupport::* function and it expects
 * them that way
 */

234
static vboxGlobalData *g_pVBoxGlobalData = NULL;
235

236
#endif /* !(VBOX_API_VERSION == 2002000) */
237

238
#if VBOX_API_VERSION < 4000000
239 240 241 242 243 244 245 246 247 248 249 250 251

# define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \
    data->vboxObj->vtbl->GetMachine(data->vboxObj, iid_value, machine)

# define VBOX_SESSION_OPEN(/* in */ iid_value, /* unused */ machine) \
    data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid_value)

# define VBOX_SESSION_OPEN_EXISTING(/* in */ iid_value, /* unused */ machine) \
    data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid_value)

# define VBOX_SESSION_CLOSE() \
    data->vboxSession->vtbl->Close(data->vboxSession)

252
#else /* VBOX_API_VERSION >= 4000000 */
253 254 255 256 257 258 259 260 261 262 263 264 265

# define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \
    data->vboxObj->vtbl->FindMachine(data->vboxObj, iid_value, machine)

# define VBOX_SESSION_OPEN(/* unused */ iid_value, /* in */ machine) \
    machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write)

# define VBOX_SESSION_OPEN_EXISTING(/* unused */ iid_value, /* in */ machine) \
    machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared)

# define VBOX_SESSION_CLOSE() \
    data->vboxSession->vtbl->UnlockMachine(data->vboxSession)

266
#endif /* VBOX_API_VERSION >= 4000000 */
267

268 269 270 271 272
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
/* Since vboxConnectGetCapabilities has been rewritten,
 * vboxDriverLock and vboxDriverUnlock only be used in code for
 * 3.x release. */

273 274
static void vboxDriverLock(vboxGlobalData *data)
{
275 276 277
    virMutexLock(&data->lock);
}

278 279
static void vboxDriverUnlock(vboxGlobalData *data)
{
280 281 282
    virMutexUnlock(&data->lock);
}

283 284
#endif

285
#if VBOX_API_VERSION == 2002000
286

287 288
static void nsIDtoChar(unsigned char *uuid, const nsID *iid)
{
289 290 291
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
292
    size_t i;
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

    memcpy(uuidinterim, iid, VIR_UUID_BUFLEN);
    virUUIDFormat(uuidinterim, uuidstrsrc);

    uuidstrdst[0]  = uuidstrsrc[6];
    uuidstrdst[1]  = uuidstrsrc[7];
    uuidstrdst[2]  = uuidstrsrc[4];
    uuidstrdst[3]  = uuidstrsrc[5];
    uuidstrdst[4]  = uuidstrsrc[2];
    uuidstrdst[5]  = uuidstrsrc[3];
    uuidstrdst[6]  = uuidstrsrc[0];
    uuidstrdst[7]  = uuidstrsrc[1];

    uuidstrdst[8]  = uuidstrsrc[8];

    uuidstrdst[9]  = uuidstrsrc[11];
    uuidstrdst[10] = uuidstrsrc[12];
    uuidstrdst[11] = uuidstrsrc[9];
    uuidstrdst[12] = uuidstrsrc[10];

    uuidstrdst[13] = uuidstrsrc[13];

    uuidstrdst[14] = uuidstrsrc[16];
    uuidstrdst[15] = uuidstrsrc[17];
    uuidstrdst[16] = uuidstrsrc[14];
    uuidstrdst[17] = uuidstrsrc[15];

320
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
321 322 323 324
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
325
    ignore_value(virUUIDParse(uuidstrdst, uuid));
326 327
}

328 329
static void nsIDFromChar(nsID *iid, const unsigned char *uuid)
{
330 331 332
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
333
    size_t i;
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359

    virUUIDFormat(uuid, uuidstrsrc);

    uuidstrdst[0]  = uuidstrsrc[6];
    uuidstrdst[1]  = uuidstrsrc[7];
    uuidstrdst[2]  = uuidstrsrc[4];
    uuidstrdst[3]  = uuidstrsrc[5];
    uuidstrdst[4]  = uuidstrsrc[2];
    uuidstrdst[5]  = uuidstrsrc[3];
    uuidstrdst[6]  = uuidstrsrc[0];
    uuidstrdst[7]  = uuidstrsrc[1];

    uuidstrdst[8]  = uuidstrsrc[8];

    uuidstrdst[9]  = uuidstrsrc[11];
    uuidstrdst[10] = uuidstrsrc[12];
    uuidstrdst[11] = uuidstrsrc[9];
    uuidstrdst[12] = uuidstrsrc[10];

    uuidstrdst[13] = uuidstrsrc[13];

    uuidstrdst[14] = uuidstrsrc[16];
    uuidstrdst[15] = uuidstrsrc[17];
    uuidstrdst[16] = uuidstrsrc[14];
    uuidstrdst[17] = uuidstrsrc[15];

360
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
361 362 363 364
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
365
    ignore_value(virUUIDParse(uuidstrdst, uuidinterim));
366 367 368
    memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}

369
# ifdef WIN32
370

371 372 373 374
typedef struct _vboxIID_v2_x_WIN32 vboxIID;
typedef struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32;

#  define VBOX_IID_INITIALIZER { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }
T
Taowei 已提交
375
#  define IID_MEMBER(name) (iidu->vboxIID_v2_x_WIN32.name)
376 377 378 379 380 381

static void
vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED,
                          vboxIID_v2_x_WIN32 *iid ATTRIBUTE_UNUSED)
{
    /* Nothing to free */
382
}
383

T
Taowei 已提交
384 385 386 387 388 389 390
static void
_vboxIIDUnalloc(vboxGlobalData *data ATTRIBUTE_UNUSED,
                vboxIIDUnion *iid ATTRIBUTE_UNUSED)
{
    /* Nothing to free */
}

391 392 393 394 395
static void
vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, (nsID *)&iid->value);
}
396

T
Taowei 已提交
397 398 399 400 401 402
static void
_vboxIIDToUUID(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu, unsigned char *uuid)
{
    vboxIIDToUUID_v2_x_WIN32(&iidu->vboxIID_v2_x_WIN32, uuid);
}

403 404 405 406 407
static void
vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                           const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x_WIN32(data, iid);
408

409
    nsIDFromChar((nsID *)&iid->value, uuid);
410 411
}

T
Taowei 已提交
412 413 414 415 416 417 418
static void
_vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
                 const unsigned char *uuid)
{
    vboxIIDFromUUID_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, uuid);
}

419 420 421
static bool
vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2)
{
422
    return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0;
423
}
424

T
Taowei 已提交
425 426 427 428 429 430
static bool
_vboxIIDIsEqual(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu1, vboxIIDUnion *iidu2)
{
    return vboxIIDIsEqual_v2_x_WIN32(&iidu1->vboxIID_v2_x_WIN32, &iidu2->vboxIID_v2_x_WIN32);
}

431 432 433 434 435 436 437 438
static void
vboxIIDFromArrayItem_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                                vboxArray *array, int idx)
{
    GUID *items = (GUID *)array->items;

    vboxIIDUnalloc_v2_x_WIN32(data, iid);

439
    memcpy(&iid->value, &items[idx], sizeof(GUID));
440 441
}

T
Taowei 已提交
442 443 444 445 446 447 448
static void
_vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu,
                      vboxArray *array, int idx)
{
    vboxIIDFromArrayItem_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, array, idx);
}

449 450 451 452 453 454 455 456 457 458 459 460 461 462
#  define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x_WIN32(data, iid)
#  define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x_WIN32(iid, uuid)
#  define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x_WIN32(data, iid, uuid)
#  define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x_WIN32(iid1, iid2)
#  define vboxIIDFromArrayItem(iid, array, idx) \
    vboxIIDFromArrayItem_v2_x_WIN32(data, iid, array, idx)
#  define DEBUGIID(msg, iid) DEBUGUUID(msg, (nsID *)&(iid))

# else /* !WIN32 */

typedef struct _vboxIID_v2_x vboxIID;
typedef struct _vboxIID_v2_x vboxIID_v2_x;

#  define VBOX_IID_INITIALIZER { NULL, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }
T
Taowei 已提交
463
#  define IID_MEMBER(name) (iidu->vboxIID_v2_x.name)
464 465 466 467 468

static void
vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid)
{
    if (iid->value == NULL) {
469 470 471
        return;
    }

472 473 474 475 476 477 478
    if (iid->value != &iid->backing) {
        data->pFuncs->pfnComUnallocMem(iid->value);
    }

    iid->value = NULL;
}

T
Taowei 已提交
479 480 481 482 483 484
static void
_vboxIIDUnalloc(vboxGlobalData *data, vboxIIDUnion *iidu)
{
    vboxIIDUnalloc_v2_x(data, &iidu->vboxIID_v2_x);
}

485 486 487 488 489 490
static void
vboxIIDToUUID_v2_x(vboxIID_v2_x *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, iid->value);
}

T
Taowei 已提交
491 492 493 494 495 496 497
static void
_vboxIIDToUUID(vboxGlobalData *data ATTRIBUTE_UNUSED,
               vboxIIDUnion *iidu, unsigned char *uuid)
{
    vboxIIDToUUID_v2_x(&iidu->vboxIID_v2_x, uuid);
}

498 499 500 501 502 503 504 505
static void
vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
                     const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x(data, iid);

    iid->value = &iid->backing;

506
    sa_assert(iid->value);
507
    nsIDFromChar(iid->value, uuid);
508 509
}

T
Taowei 已提交
510 511 512 513 514 515 516
static void
_vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
                 const unsigned char *uuid)
{
    vboxIIDFromUUID_v2_x(data, &iidu->vboxIID_v2_x, uuid);
}

517 518 519
static bool
vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2)
{
520
    return memcmp(iid1->value, iid2->value, sizeof(nsID)) == 0;
521 522
}

T
Taowei 已提交
523 524 525 526 527 528 529
static bool
_vboxIIDIsEqual(vboxGlobalData *data ATTRIBUTE_UNUSED,
                vboxIIDUnion *iidu1, vboxIIDUnion *iidu2)
{
    return vboxIIDIsEqual_v2_x(&iidu1->vboxIID_v2_x, &iidu2->vboxIID_v2_x);
}

530 531 532 533 534 535 536 537
static void
vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v2_x(data, iid);

    iid->value = &iid->backing;

538
    memcpy(iid->value, array->items[idx], sizeof(nsID));
539 540
}

T
Taowei 已提交
541 542 543 544 545 546 547
static void
_vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu,
                      vboxArray *array, int idx)
{
    vboxIIDFromArrayItem_v2_x(data, &iidu->vboxIID_v2_x, array, idx);
}

548 549 550 551 552 553 554 555 556 557
#  define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x(data, iid)
#  define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x(iid, uuid)
#  define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x(data, iid, uuid)
#  define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x(iid1, iid2)
#  define vboxIIDFromArrayItem(iid, array, idx) \
    vboxIIDFromArrayItem_v2_x(data, iid, array, idx)
#  define DEBUGIID(msg, iid) DEBUGUUID(msg, iid)

# endif /* !WIN32 */

558
#else /* VBOX_API_VERSION != 2002000 */
559

560 561 562 563
typedef struct _vboxIID_v3_x vboxIID;
typedef struct _vboxIID_v3_x vboxIID_v3_x;

# define VBOX_IID_INITIALIZER { NULL, true }
T
Taowei 已提交
564
# define IID_MEMBER(name) (iidu->vboxIID_v3_x.name)
565 566 567 568 569 570 571 572 573 574

static void
vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid)
{
    if (iid->value != NULL && iid->owner) {
        data->pFuncs->pfnUtf16Free(iid->value);
    }

    iid->value = NULL;
    iid->owner = true;
575 576
}

T
Taowei 已提交
577 578 579 580 581 582
static void
_vboxIIDUnalloc(vboxGlobalData *data, vboxIIDUnion *iidu)
{
    vboxIIDUnalloc_v3_x(data, &iidu->vboxIID_v3_x);
}

583 584 585 586 587 588 589 590
static void
vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                   unsigned char *uuid)
{
    char *utf8 = NULL;

    data->pFuncs->pfnUtf16ToUtf8(iid->value, &utf8);

591
    ignore_value(virUUIDParse(utf8, uuid));
592 593

    data->pFuncs->pfnUtf8Free(utf8);
594 595
}

T
Taowei 已提交
596 597 598 599 600 601 602
static void
_vboxIIDToUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
               unsigned char *uuid)
{
    vboxIIDToUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid);
}

603 604 605 606 607
static void
vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                     const unsigned char *uuid)
{
    char utf8[VIR_UUID_STRING_BUFLEN];
608

609
    vboxIIDUnalloc_v3_x(data, iid);
610

611
    virUUIDFormat(uuid, utf8);
612

613 614
    data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
}
615

T
Taowei 已提交
616 617 618 619 620 621 622
static void
_vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
                 const unsigned char *uuid)
{
    vboxIIDFromUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid);
}

623 624 625 626 627 628
static bool
vboxIIDIsEqual_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid1,
                    vboxIID_v3_x *iid2)
{
    unsigned char uuid1[VIR_UUID_BUFLEN];
    unsigned char uuid2[VIR_UUID_BUFLEN];
629 630

    /* Note: we can't directly compare the utf8 strings here
E
Eric Blake 已提交
631
     * cause the two UUID's may have separators as space or '-'
632 633
     * or mixture of both and we don't want to fail here by
     * using direct string comparison. Here virUUIDParse() takes
634 635 636
     * care of these cases. */
    vboxIIDToUUID_v3_x(data, iid1, uuid1);
    vboxIIDToUUID_v3_x(data, iid2, uuid2);
637

638 639
    return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
}
640

T
Taowei 已提交
641 642 643 644 645 646
static bool
_vboxIIDIsEqual(vboxGlobalData *data, vboxIIDUnion *iidu1,
                vboxIIDUnion *iidu2)
{
    return vboxIIDIsEqual_v3_x(data, &iidu1->vboxIID_v3_x, &iidu2->vboxIID_v3_x);
}
647

648 649 650 651 652
static void
vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v3_x(data, iid);
653

654 655
    iid->value = array->items[idx];
    iid->owner = false;
656 657
}

T
Taowei 已提交
658 659 660 661 662 663 664
static void
_vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu,
                      vboxArray *array, int idx)
{
    vboxIIDFromArrayItem_v3_x(data, &iidu->vboxIID_v3_x, array, idx);
}

665 666 667 668 669 670 671 672

# define vboxIIDUnalloc(iid) vboxIIDUnalloc_v3_x(data, iid)
# define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v3_x(data, iid, uuid)
# define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v3_x(data, iid, uuid)
# define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v3_x(data, iid1, iid2)
# define vboxIIDFromArrayItem(iid, array, idx) \
    vboxIIDFromArrayItem_v3_x(data, iid, array, idx)
# define DEBUGIID(msg, strUtf16) DEBUGPRUnichar(msg, strUtf16)
673

T
Taowei 已提交
674 675 676
#endif /* !(VBOX_API_VERSION == 2002000) */

#if VBOX_API_VERSION >= 3001000
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

/**
 * function to generate the name for medium,
 * for e.g: hda, sda, etc
 *
 * @returns     null terminated string with device name or NULL
 *              for failures
 * @param       conn            Input Connection Pointer
 * @param       storageBus      Input storage bus type
 * @param       deviceInst      Input device instance number
 * @param       devicePort      Input port number
 * @param       deviceSlot      Input slot number
 * @param       aMaxPortPerInst Input array of max port per device instance
 * @param       aMaxSlotPerPort Input array of max slot per device port
 *
 */
693
static char *vboxGenerateMediumName(PRUint32  storageBus,
694 695 696 697
                                    PRInt32   deviceInst,
                                    PRInt32   devicePort,
                                    PRInt32   deviceSlot,
                                    PRUint32 *aMaxPortPerInst,
698 699
                                    PRUint32 *aMaxSlotPerPort)
{
700
    const char *prefix = NULL;
701 702 703 704 705
    char *name  = NULL;
    int   total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

706 707
    if (!aMaxPortPerInst ||
        !aMaxSlotPerPort)
708 709
        return NULL;

710 711
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
712 713 714 715 716 717 718 719 720
        return NULL;

    maxPortPerInst = aMaxPortPerInst[storageBus];
    maxSlotPerPort = aMaxSlotPerPort[storageBus];
    total =   (deviceInst * maxPortPerInst * maxSlotPerPort)
            + (devicePort * maxSlotPerPort)
            + deviceSlot;

    if (storageBus == StorageBus_IDE) {
721
        prefix = "hd";
722 723
    } else if ((storageBus == StorageBus_SATA) ||
               (storageBus == StorageBus_SCSI)) {
724
        prefix = "sd";
725
    } else if (storageBus == StorageBus_Floppy) {
726
        prefix = "fd";
727 728
    }

729
    name = virIndexToDiskName(total, prefix);
730

731
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
732
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
733
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
          deviceSlot, maxPortPerInst, maxSlotPerPort);
    return name;
}

/**
 * function to get the StorageBus, Port number
 * and Device number for the given devicename
 * e.g: hda has StorageBus = IDE, port = 0,
 *      device = 0
 *
 * @returns     true on Success, false on failure.
 * @param       deviceName      Input device name
 * @param       aMaxPortPerInst Input array of max port per device instance
 * @param       aMaxSlotPerPort Input array of max slot per device port
 * @param       storageBus      Input storage bus type
 * @param       deviceInst      Output device instance number
 * @param       devicePort      Output port number
 * @param       deviceSlot      Output slot number
 *
 */
T
Taowei 已提交
754 755
# if VBOX_API_VERSION < 4000000
/* Only 3.x will use this function. */
756 757 758 759 760 761 762 763 764 765 766
static bool vboxGetDeviceDetails(const char *deviceName,
                                 PRUint32   *aMaxPortPerInst,
                                 PRUint32   *aMaxSlotPerPort,
                                 PRUint32    storageBus,
                                 PRInt32    *deviceInst,
                                 PRInt32    *devicePort,
                                 PRInt32    *deviceSlot) {
    int total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

767 768 769 770 771 772
    if (!deviceName ||
        !deviceInst ||
        !devicePort ||
        !deviceSlot ||
        !aMaxPortPerInst ||
        !aMaxSlotPerPort)
773 774
        return false;

775 776
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
777 778 779 780 781 782 783
        return false;

    total = virDiskNameToIndex(deviceName);

    maxPortPerInst = aMaxPortPerInst[storageBus];
    maxSlotPerPort = aMaxSlotPerPort[storageBus];

784 785 786
    if (!maxPortPerInst ||
        !maxSlotPerPort ||
        (total < 0))
787 788 789 790 791 792
        return false;

    *deviceInst = total / (maxPortPerInst * maxSlotPerPort);
    *devicePort = (total % (maxPortPerInst * maxSlotPerPort)) / maxSlotPerPort;
    *deviceSlot = (total % (maxPortPerInst * maxSlotPerPort)) % maxSlotPerPort;

793
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
794 795 796 797 798 799
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
          deviceName, total, storageBus, *deviceInst, *devicePort,
          *deviceSlot, maxPortPerInst, maxSlotPerPort);

    return true;
}
T
Taowei 已提交
800
# endif /* VBOX_API_VERSION < 4000000 */
801 802 803 804 805 806 807 808 809 810 811 812 813 814

/**
 * function to get the values for max port per
 * instance and max slots per port for the devices
 *
 * @returns     true on Success, false on failure.
 * @param       vbox            Input IVirtualBox pointer
 * @param       maxPortPerInst  Output array of max port per instance
 * @param       maxSlotPerPort  Output array of max slot per port
 *
 */

static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox,
                                     PRUint32 *maxPortPerInst,
815 816
                                     PRUint32 *maxSlotPerPort)
{
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
    ISystemProperties *sysProps = NULL;

    if (!vbox)
        return false;

    vbox->vtbl->GetSystemProperties(vbox, &sysProps);

    if (!sysProps)
        return false;

    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_IDE,
                                                 &maxPortPerInst[StorageBus_IDE]);
    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_SATA,
                                                 &maxPortPerInst[StorageBus_SATA]);
    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_SCSI,
                                                 &maxPortPerInst[StorageBus_SCSI]);
    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_Floppy,
                                                 &maxPortPerInst[StorageBus_Floppy]);

    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_IDE,
                                                      &maxSlotPerPort[StorageBus_IDE]);
    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_SATA,
                                                      &maxSlotPerPort[StorageBus_SATA]);
    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_SCSI,
                                                      &maxSlotPerPort[StorageBus_SCSI]);
    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_Floppy,
                                                      &maxSlotPerPort[StorageBus_Floppy]);

    VBOX_RELEASE(sysProps);

    return true;
}

/**
 * Converts Utf-16 string to int
 */
861 862
static int PRUnicharToInt(PRUnichar *strUtf16)
{
863 864 865 866 867 868 869 870 871 872
    char *strUtf8 = NULL;
    int ret = 0;

    if (!strUtf16)
        return -1;

    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);
    if (!strUtf8)
        return -1;

873 874 875
    if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0)
        ret = -1;

876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
    g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);

    return ret;
}

/**
 * Converts int to Utf-16 string
 */
static PRUnichar *PRUnicharFromInt(int n) {
    PRUnichar *strUtf16 = NULL;
    char s[24];

    snprintf(s, sizeof(s), "%d", n);

    g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(s, &strUtf16);

    return strUtf16;
}

T
Taowei 已提交
895
#endif /* VBOX_API_VERSION >= 3001000 */
896

897 898 899 900 901 902
static PRUnichar *
vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr)
{
    char *utf8 = NULL;
    PRUnichar *utf16 = NULL;

903
    utf8 = virSocketAddrFormat(addr);
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923

    if (utf8 == NULL) {
        return NULL;
    }

    VBOX_UTF8_TO_UTF16(utf8, &utf16);
    VIR_FREE(utf8);

    return utf16;
}

static int
vboxSocketParseAddrUtf16(vboxGlobalData *data, const PRUnichar *utf16,
                         virSocketAddrPtr addr)
{
    int result = -1;
    char *utf8 = NULL;

    VBOX_UTF16_TO_UTF8(utf16, &utf8);

924
    if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) {
925 926 927 928 929
        goto cleanup;
    }

    result = 0;

930
 cleanup:
931 932 933 934 935
    VBOX_UTF8_FREE(utf8);

    return result;
}

E
Eric Blake 已提交
936 937
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
{
938
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
939
    IMachine *machine    = NULL;
940
    vboxIID iid = VBOX_IID_INITIALIZER;
941 942
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
943 944
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
945

E
Eric Blake 已提交
946 947
    virCheckFlags(0, -1);

948
    vboxIIDFromUUID(&iid, dom->uuid);
949
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
950
    if (NS_FAILED(rc)) {
951 952
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
953 954
        goto cleanup;
    }
955

956 957
    if (!machine)
        goto cleanup;
958

959 960 961
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
962

963
        if (state == MachineState_Running) {
964
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
965 966 967 968 969
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Reset(console);
                VBOX_RELEASE(console);
                ret = 0;
970
            }
971
            VBOX_SESSION_CLOSE();
972
        } else {
973 974
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not running, so can't reboot it"));
975
            goto cleanup;
976 977 978
        }
    }

979
 cleanup:
980
    VBOX_RELEASE(machine);
981
    vboxIIDUnalloc(&iid);
982 983 984
    return ret;
}

985 986 987 988
static int
vboxDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
989
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
990
    IMachine *machine    = NULL;
991
    vboxIID iid = VBOX_IID_INITIALIZER;
992 993
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
994 995
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
996

997 998
    virCheckFlags(0, -1);

999
    vboxIIDFromUUID(&iid, dom->uuid);
1000
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1001
    if (NS_FAILED(rc)) {
1002 1003
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1004 1005
        goto cleanup;
    }
1006

1007 1008
    if (!machine)
        goto cleanup;
1009

1010 1011 1012
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1013

1014
        if (state == MachineState_PoweredOff) {
1015 1016
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1017 1018
            goto cleanup;
        }
1019

1020
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1021 1022
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
1023

1024
#if VBOX_API_VERSION == 2002000
1025
            console->vtbl->PowerDown(console);
1026
#else
1027
            IProgress *progress = NULL;
1028 1029 1030 1031
            console->vtbl->PowerDown(console, &progress);
            if (progress) {
                progress->vtbl->WaitForCompletion(progress, -1);
                VBOX_RELEASE(progress);
1032
            }
1033 1034
#endif
            VBOX_RELEASE(console);
1035
            dom->id = -1;
1036
            ret = 0;
1037
        }
1038
        VBOX_SESSION_CLOSE();
1039 1040
    }

1041
 cleanup:
1042
    VBOX_RELEASE(machine);
1043
    vboxIIDUnalloc(&iid);
1044 1045 1046
    return ret;
}

1047 1048 1049 1050 1051 1052
static int
vboxDomainDestroy(virDomainPtr dom)
{
    return vboxDomainDestroyFlags(dom, 0);
}

1053
static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1054 1055 1056 1057 1058
    /* Returning "hvm" always as suggested on list, cause
     * this functions seems to be badly named and it
     * is supposed to pass the ABI name and not the domain
     * operating system driver as I had imagined ;)
     */
1059
    char *osType;
1060

1061
    ignore_value(VIR_STRDUP(osType, "hvm"));
1062
    return osType;
1063 1064
}

1065 1066
static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
1067
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1068
    IMachine *machine    = NULL;
1069
    vboxIID iid = VBOX_IID_INITIALIZER;
1070
    PRUint32 state       = MachineState_Null;
1071 1072
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1073

1074
    vboxIIDFromUUID(&iid, dom->uuid);
1075
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1076
    if (NS_FAILED(rc)) {
1077 1078
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1079 1080
        goto cleanup;
    }
1081

1082 1083
    if (!machine)
        goto cleanup;
1084

1085 1086 1087
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1088

1089
        if (state != MachineState_PoweredOff) {
1090 1091
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("memory size can't be changed unless domain is powered down"));
1092 1093
            goto cleanup;
        }
1094

1095
        rc = VBOX_SESSION_OPEN(iid.value, machine);
1096 1097 1098
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
1099

1100 1101
                rc = machine->vtbl->SetMemorySize(machine,
                                                  VIR_DIV_UP(memory, 1024));
1102 1103 1104 1105
                if (NS_SUCCEEDED(rc)) {
                    machine->vtbl->SaveSettings(machine);
                    ret = 0;
                } else {
1106 1107 1108 1109
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("could not set the memory size of the "
                                     "domain to: %lu Kb, rc=%08x"),
                                   memory, (unsigned)rc);
1110 1111
                }
            }
1112
            VBOX_SESSION_CLOSE();
1113 1114 1115
        }
    }

1116
 cleanup:
1117
    VBOX_RELEASE(machine);
1118
    vboxIIDUnalloc(&iid);
1119 1120 1121
    return ret;
}

1122 1123
static virDomainState vboxConvertState(enum MachineState state)
{
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
    switch (state) {
        case MachineState_Running:
            return VIR_DOMAIN_RUNNING;
        case MachineState_Stuck:
            return VIR_DOMAIN_BLOCKED;
        case MachineState_Paused:
            return VIR_DOMAIN_PAUSED;
        case MachineState_Stopping:
            return VIR_DOMAIN_SHUTDOWN;
        case MachineState_PoweredOff:
R
Ryota Ozaki 已提交
1134
        case MachineState_Saved:
1135 1136 1137 1138 1139 1140 1141 1142 1143
            return VIR_DOMAIN_SHUTOFF;
        case MachineState_Aborted:
            return VIR_DOMAIN_CRASHED;
        case MachineState_Null:
        default:
            return VIR_DOMAIN_NOSTATE;
    }
}

1144 1145
static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
1146
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1147
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1148 1149
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1150
    nsresult rc;
1151
    size_t i = 0;
1152

1153
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1154
    if (NS_FAILED(rc)) {
1155 1156
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1157 1158
        goto cleanup;
    }
1159

1160
    info->nrVirtCpu = 0;
1161 1162
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1163
        PRBool isAccessible = PR_FALSE;
1164

1165 1166
        if (!machine)
            continue;
1167

1168 1169
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1170

1171 1172 1173 1174 1175 1176
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);

            if (STREQ(dom->name, machineName)) {
                /* Get the Machine State (also match it with
                * virDomainState). Get the Machine memory and
1177
                * for time being set max_balloon and cur_balloon to same
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
                * Also since there is no direct way of checking
                * the cputime required (one condition being the
                * VM is remote), return zero for cputime. Get the
                * number of CPU.
                */
                PRUint32 CPUCount   = 0;
                PRUint32 memorySize = 0;
                PRUint32 state      = MachineState_Null;
                PRUint32 maxMemorySize = 4 * 1024;
                ISystemProperties *systemProperties = NULL;

                data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
                if (systemProperties) {
                    systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                    VBOX_RELEASE(systemProperties);
                    systemProperties = NULL;
                }
1195 1196


1197 1198 1199 1200 1201 1202
                machine->vtbl->GetCPUCount(machine, &CPUCount);
                machine->vtbl->GetMemorySize(machine, &memorySize);
                machine->vtbl->GetState(machine, &state);

                info->cpuTime = 0;
                info->nrVirtCpu = CPUCount;
1203 1204
                info->memory = memorySize * 1024;
                info->maxMem = maxMemorySize * 1024;
1205
                info->state = vboxConvertState(state);
1206

1207
                ret = 0;
1208 1209
            }

J
John Ferlan 已提交
1210 1211
            VBOX_UTF8_FREE(machineName);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1212 1213
            if (info->nrVirtCpu)
                break;
1214 1215 1216 1217
        }

    }

1218
    vboxArrayRelease(&machines);
1219

1220
 cleanup:
1221 1222 1223
    return ret;
}

1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
static int
vboxDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID domiid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    PRUint32 mstate = MachineState_Null;
    nsresult rc;

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&domiid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
1241 1242
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1243 1244 1245 1246 1247
        goto cleanup;
    }

    machine->vtbl->GetState(machine, &mstate);

1248
    *state = vboxConvertState(mstate);
1249 1250 1251 1252 1253 1254

    if (reason)
        *reason = 0;

    ret = 0;

1255
 cleanup:
1256 1257 1258 1259
    vboxIIDUnalloc(&domiid);
    return ret;
}

1260 1261 1262 1263
static int
vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
{
1264
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1265
    IMachine *machine    = NULL;
1266
    vboxIID iid = VBOX_IID_INITIALIZER;
1267
    PRUint32  CPUCount   = nvcpus;
1268
    nsresult rc;
1269

1270
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
1271
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1272 1273 1274
        return -1;
    }

1275
    vboxIIDFromUUID(&iid, dom->uuid);
1276
#if VBOX_API_VERSION >= 4000000
1277 1278 1279
    /* Get machine for the call to VBOX_SESSION_OPEN */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1280 1281
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1282 1283 1284 1285 1286
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN(iid.value, machine);
1287 1288 1289 1290 1291 1292 1293
    if (NS_SUCCEEDED(rc)) {
        data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
        if (machine) {
            rc = machine->vtbl->SetCPUCount(machine, CPUCount);
            if (NS_SUCCEEDED(rc)) {
                machine->vtbl->SaveSettings(machine);
                ret = 0;
1294
            } else {
1295 1296 1297 1298
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not set the number of cpus of the domain "
                                 "to: %u, rc=%08x"),
                               CPUCount, (unsigned)rc);
1299
            }
1300
            VBOX_RELEASE(machine);
1301
        } else {
1302 1303
            virReportError(VIR_ERR_NO_DOMAIN,
                           _("no domain with matching id %d"), dom->id);
1304
        }
1305
    } else {
1306 1307
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("can't open session to the domain with id %d"), dom->id);
1308
    }
1309
    VBOX_SESSION_CLOSE();
1310

1311
    vboxIIDUnalloc(&iid);
1312 1313 1314
    return ret;
}

1315 1316 1317
static int
vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
1318
    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
1319 1320 1321 1322 1323
}

static int
vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
1324 1325
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    ISystemProperties *systemProperties = NULL;
1326 1327
    PRUint32 maxCPUCount = 0;

1328
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1329
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1330 1331 1332
        return -1;
    }

1333 1334 1335 1336 1337
    /* Currently every domain supports the same number of max cpus
     * as that supported by vbox and thus take it directly from
     * the systemproperties.
     */

1338 1339 1340 1341
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
1342 1343 1344 1345 1346 1347 1348 1349
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

1350 1351 1352
static int
vboxDomainGetMaxVcpus(virDomainPtr dom)
{
1353
    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
1354 1355 1356
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1357 1358
static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
{
1359
#if VBOX_API_VERSION < 4003000
1360 1361
    IUSBController *USBController = NULL;
    PRBool enabled = PR_FALSE;
R
Ryota Ozaki 已提交
1362 1363 1364
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
1365 1366 1367 1368 1369
    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
    size_t i;
    PRUint32 USBFilterCount = 0;

    def->nhostdevs = 0;
R
Ryota Ozaki 已提交
1370

1371
#if VBOX_API_VERSION < 4003000
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
    machine->vtbl->GetUSBController(machine, &USBController);

    if (!USBController)
        return;

    USBController->vtbl->GetEnabled(USBController, &enabled);
    if (!enabled)
        goto release_controller;

    vboxArrayGet(&deviceFilters, USBController,
                 USBController->vtbl->GetDeviceFilters);

R
Ryota Ozaki 已提交
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;

    vboxArrayGet(&deviceFilters, USBDeviceFilters,
                 USBDeviceFilters->vtbl->GetDeviceFilters);
#endif

1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
    if (deviceFilters.count <= 0)
        goto release_filters;

    /* check if the filters are active and then only
     * alloc mem and set def->nhostdevs
     */

    for (i = 0; i < deviceFilters.count; i++) {
        PRBool active = PR_FALSE;
        IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];

        deviceFilter->vtbl->GetActive(deviceFilter, &active);
        if (active) {
            def->nhostdevs++;
        }
    }

    if (def->nhostdevs == 0)
        goto release_filters;

    /* Alloc mem needed for the filters now */
    if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) < 0)
        goto release_filters;

1418 1419 1420 1421 1422 1423
    for (i = 0; i < def->nhostdevs; i++) {
        def->hostdevs[i] = virDomainHostdevDefAlloc();
        if (!def->hostdevs[i])
            goto release_hostdevs;
    }

1424
    for (i = 0; i < deviceFilters.count; i++) {
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
        PRBool active                  = PR_FALSE;
        IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
        PRUnichar *vendorIdUtf16       = NULL;
        char *vendorIdUtf8             = NULL;
        unsigned vendorId              = 0;
        PRUnichar *productIdUtf16      = NULL;
        char *productIdUtf8            = NULL;
        unsigned productId             = 0;
        char *endptr                   = NULL;

        deviceFilter->vtbl->GetActive(deviceFilter, &active);
        if (!active)
            continue;

        def->hostdevs[USBFilterCount]->mode =
            VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        def->hostdevs[USBFilterCount]->source.subsys.type =
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;

        deviceFilter->vtbl->GetVendorId(deviceFilter, &vendorIdUtf16);
        deviceFilter->vtbl->GetProductId(deviceFilter, &productIdUtf16);

        VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8);
        VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8);

1450 1451
        ignore_value(virStrToLong_ui(vendorIdUtf8, &endptr, 16, &vendorId));
        ignore_value(virStrToLong_ui(productIdUtf8, &endptr, 16, &productId));
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464

        def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor  = vendorId;
        def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId;

        VBOX_UTF16_FREE(vendorIdUtf16);
        VBOX_UTF8_FREE(vendorIdUtf8);

        VBOX_UTF16_FREE(productIdUtf16);
        VBOX_UTF8_FREE(productIdUtf8);

        USBFilterCount++;
    }

1465
 release_filters:
1466
    vboxArrayRelease(&deviceFilters);
1467
#if VBOX_API_VERSION < 4003000
1468
 release_controller:
1469
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
1470 1471 1472
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
1473 1474 1475

    return;

1476
 release_hostdevs:
1477 1478 1479 1480 1481
    for (i = 0; i < def->nhostdevs; i++)
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

    goto release_filters;
1482 1483
}

1484
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
1485
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
1486 1487
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
1488
    vboxIID iid = VBOX_IID_INITIALIZER;
1489
    int gotAllABoutDef   = -1;
1490
    nsresult rc;
1491

1492 1493
    /* Flags checked by virDomainDefFormat */

1494
    if (VIR_ALLOC(def) < 0)
1495 1496
        goto cleanup;

1497
    vboxIIDFromUUID(&iid, dom->uuid);
1498
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1499
    if (NS_SUCCEEDED(rc)) {
1500
        PRBool accessible = PR_FALSE;
1501

1502 1503
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
1504
            size_t i = 0;
1505 1506 1507
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
1508
            PRBool VRDxEnabled                  = PR_FALSE;
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
            PRUint32 CPUCount                   = 0;
            PRUint32 memorySize                 = 0;
            PRUint32 netAdpCnt                  = 0;
            PRUint32 netAdpIncCnt               = 0;
            PRUint32 maxMemorySize              = 4 * 1024;
            PRUint32 maxBootPosition            = 0;
            PRUint32 serialPortCount            = 0;
            PRUint32 serialPortIncCount         = 0;
            PRUint32 parallelPortCount          = 0;
            PRUint32 parallelPortIncCount       = 0;
            IBIOSSettings *bios                 = NULL;
1520
#if VBOX_API_VERSION < 3001000
1521 1522 1523 1524 1525 1526 1527 1528
            PRInt32       hddNum                = 0;
            IDVDDrive    *dvdDrive              = NULL;
            IHardDisk    *hardDiskPM            = NULL;
            IHardDisk    *hardDiskPS            = NULL;
            IHardDisk    *hardDiskSS            = NULL;
            const char   *hddBus                = "IDE";
            PRUnichar    *hddBusUtf16           = NULL;
            IFloppyDrive *floppyDrive           = NULL;
1529
#else  /* VBOX_API_VERSION >= 3001000 */
1530
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
1531 1532
#endif /* VBOX_API_VERSION >= 3001000 */
#if VBOX_API_VERSION < 4000000
1533
            IVRDPServer *VRDxServer             = NULL;
1534
#else  /* VBOX_API_VERSION >= 4000000 */
1535
            IVRDEServer *VRDxServer             = NULL;
1536
#endif /* VBOX_API_VERSION >= 4000000 */
1537
            IAudioAdapter *audioAdapter         = NULL;
1538
#if VBOX_API_VERSION >= 4001000
1539
            PRUint32 chipsetType                = ChipsetType_Null;
1540
#endif /* VBOX_API_VERSION >= 4001000 */
1541
            ISystemProperties *systemProperties = NULL;
1542 1543


1544 1545 1546
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
1547 1548
            if (VIR_STRDUP(def->name, dom->name) < 0)
                goto cleanup;
1549

1550
            machine->vtbl->GetMemorySize(machine, &memorySize);
1551
            def->mem.cur_balloon = memorySize * 1024;
1552

1553
#if VBOX_API_VERSION >= 4001000
1554
            machine->vtbl->GetChipsetType(machine, &chipsetType);
1555
#endif /* VBOX_API_VERSION >= 4001000 */
1556

1557 1558 1559 1560
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
1561
#if VBOX_API_VERSION < 4001000
1562
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
1563
#else  /* VBOX_API_VERSION >= 4000000 */
1564
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
1565
#endif /* VBOX_API_VERSION >= 4000000 */
1566 1567 1568 1569 1570 1571 1572 1573 1574
                systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
                systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
                VBOX_RELEASE(systemProperties);
                systemProperties = NULL;
            }
            /* Currently setting memory and maxMemory as same, cause
             * the notation here seems to be inconsistent while
             * reading and while dumping xml
             */
1575 1576
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
1577 1578

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
1579
            def->maxvcpus = def->vcpus = CPUCount;
1580 1581 1582

            /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */

1583 1584
            if (VIR_STRDUP(def->os.type, "hvm") < 0)
                goto cleanup;
1585

1586
            def->os.arch = virArchFromHost();
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609

            def->os.nBootDevs = 0;
            for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) {
                PRUint32 device = DeviceType_Null;

                machine->vtbl->GetBootOrder(machine, i+1, &device);

                if (device == DeviceType_Floppy) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_DVD) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_HardDisk) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_Network) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_USB) {
                    /* Not supported by libvirt yet */
                } else if (device == DeviceType_SharedFolder) {
                    /* Not supported by libvirt yet */
M
Matthias Bolte 已提交
1610
                    /* Can VirtualBox really boot from a shared folder? */
1611
                }
1612
            }
1613

1614
#if VBOX_API_VERSION < 3001000
1615
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
1616
#elif VBOX_API_VERSION == 3001000
1617
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
1618
#elif VBOX_API_VERSION >= 3002000
1619 1620
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
1621
            if (PAEEnabled)
J
Ján Tomko 已提交
1622
                def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
1623

1624 1625 1626
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
1627
                if (ACPIEnabled)
J
Ján Tomko 已提交
1628
                    def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
1629

1630
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
1631
                if (IOAPICEnabled)
J
Ján Tomko 已提交
1632
                    def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON;
1633

1634 1635 1636 1637 1638
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
1639
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
1640 1641 1642 1643 1644 1645 1646 1647

            /* dump video options vram/2d/3d/directx/etc. */
            {
                /* Currently supports only one graphics card */
                def->nvideos = 1;
                if (VIR_ALLOC_N(def->videos, def->nvideos) >= 0) {
                    if (VIR_ALLOC(def->videos[0]) >= 0) {
                        /* the default is: vram is 8MB, One monitor, 3dAccel Off */
1648
                        PRUint32 VRAMSize          = 8;
1649 1650 1651 1652 1653 1654 1655
                        PRUint32 monitorCount      = 1;
                        PRBool accelerate3DEnabled = PR_FALSE;
                        PRBool accelerate2DEnabled = PR_FALSE;

                        machine->vtbl->GetVRAMSize(machine, &VRAMSize);
                        machine->vtbl->GetMonitorCount(machine, &monitorCount);
                        machine->vtbl->GetAccelerate3DEnabled(machine, &accelerate3DEnabled);
1656
#if VBOX_API_VERSION >= 3001000
1657
                        machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
1658
#endif /* VBOX_API_VERSION >= 3001000 */
1659 1660

                        def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
1661
                        def->videos[0]->vram            = VRAMSize * 1024;
1662 1663 1664 1665
                        def->videos[0]->heads           = monitorCount;
                        if (VIR_ALLOC(def->videos[0]->accel) >= 0) {
                            def->videos[0]->accel->support3d = accelerate3DEnabled;
                            def->videos[0]->accel->support2d = accelerate2DEnabled;
1666 1667 1668
                        }
                    }
                }
1669
            }
1670

1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
            /* dump display options vrdp/gui/sdl */
            {
                int vrdpPresent           = 0;
                int sdlPresent            = 0;
                int guiPresent            = 0;
                int totalPresent          = 0;
                char *guiDisplay          = NULL;
                char *sdlDisplay          = NULL;
                PRUnichar *keyTypeUtf16   = NULL;
                PRUnichar *valueTypeUtf16 = NULL;
                char      *valueTypeUtf8  = NULL;
1682

1683
                def->ngraphics = 0;
1684

1685 1686 1687
                VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
                machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
                VBOX_UTF16_FREE(keyTypeUtf16);
1688

1689 1690 1691
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
1692

1693
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
1694 1695 1696
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
1697

1698 1699 1700
                        VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
                        machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16);
                        VBOX_UTF16_FREE(keyDislpayUtf16);
1701

1702 1703 1704
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
1705

J
John Ferlan 已提交
1706
                            if (strlen(valueDisplayUtf8) <= 0)
1707
                                VBOX_UTF8_FREE(valueDisplayUtf8);
1708
                        }
1709

1710 1711
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
1712
                            if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
1713 1714 1715 1716 1717 1718
                                /* just don't go to cleanup yet as it is ok to have
                                 * sdlDisplay as NULL and we check it below if it
                                 * exist and then only use it there
                                 */
                            }
                            totalPresent++;
1719
                        }
1720

1721 1722
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
1723
                            if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
1724
                                /* just don't go to cleanup yet as it is ok to have
1725 1726
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
1727
                                 */
1728
                            }
1729 1730
                            totalPresent++;
                        }
J
John Ferlan 已提交
1731
                        VBOX_UTF8_FREE(valueDisplayUtf8);
1732 1733
                    }

1734 1735
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
1736

1737 1738
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
1739

1740 1741 1742 1743 1744 1745 1746
                if ((totalPresent > 0) && (VIR_ALLOC_N(def->graphics, totalPresent) >= 0)) {
                    if ((guiPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
                        if (guiDisplay)
                            def->graphics[def->ngraphics]->data.desktop.display = guiDisplay;
                        def->ngraphics++;
                    }
1747

1748 1749 1750 1751 1752 1753 1754 1755
                    if ((sdlPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
                        if (sdlDisplay)
                            def->graphics[def->ngraphics]->data.sdl.display = sdlDisplay;
                        def->ngraphics++;
                    }
                } else if ((vrdpPresent != 1) && (totalPresent == 0) && (VIR_ALLOC_N(def->graphics, 1) >= 0)) {
                    if (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0) {
1756
                        const char *tmp;
1757
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
1758
                        tmp = virGetEnvBlockSUID("DISPLAY");
1759 1760 1761 1762
                        if (VIR_STRDUP(def->graphics[def->ngraphics]->data.desktop.display, tmp) < 0) {
                            /* just don't go to cleanup yet as it is ok to have
                             * display as NULL
                             */
1763 1764 1765 1766 1767
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
1768

1769
#if VBOX_API_VERSION < 4000000
1770
                machine->vtbl->GetVRDPServer(machine, &VRDxServer);
1771
#else  /* VBOX_API_VERSION >= 4000000 */
1772
                machine->vtbl->GetVRDEServer(machine, &VRDxServer);
1773
#endif /* VBOX_API_VERSION >= 4000000 */
1774 1775 1776
                if (VRDxServer) {
                    VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
                    if (VRDxEnabled) {
1777 1778 1779 1780 1781 1782 1783 1784 1785

                        totalPresent++;

                        if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) &&
                            (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                            PRUnichar *netAddressUtf16   = NULL;
                            char      *netAddressUtf8    = NULL;
                            PRBool allowMultiConnection  = PR_FALSE;
                            PRBool reuseSingleConnection = PR_FALSE;
1786
#if VBOX_API_VERSION < 3001000
1787
                            PRUint32 VRDPport = 0;
1788
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
1789 1790
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
1791 1792 1793
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
1794
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
1795
                            PRUnichar *VRDPport = NULL;
1796
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
1797 1798 1799 1800
                            if (VRDPport) {
                                /* even if vbox supports mutilpe ports, single port for now here */
                                def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDPport);
                                VBOX_UTF16_FREE(VRDPport);
1801 1802 1803
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
1804
#else /* VBOX_API_VERSION >= 4000000 */
1805 1806 1807 1808 1809 1810 1811 1812 1813
                            PRUnichar *VRDEPortsKey = NULL;
                            PRUnichar *VRDEPortsValue = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDEPortsKey, &VRDEPortsValue);
                            VBOX_UTF16_FREE(VRDEPortsKey);
                            if (VRDEPortsValue) {
                                /* even if vbox supports mutilpe ports, single port for now here */
                                def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDEPortsValue);
                                VBOX_UTF16_FREE(VRDEPortsValue);
1814
                            } else {
1815
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
1816
                            }
1817
#endif /* VBOX_API_VERSION >= 4000000 */
1818

1819
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
1820

1821
#if VBOX_API_VERSION >= 4000000
1822 1823 1824 1825
                            PRUnichar *VRDENetAddressKey = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
                            VBOX_UTF16_FREE(VRDENetAddressKey);
1826
#else /* VBOX_API_VERSION < 4000000 */
1827
                            VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
1828
#endif /* VBOX_API_VERSION < 4000000 */
1829 1830 1831
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
1832 1833
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
1834 1835 1836
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
1837

1838
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
1839
                            if (allowMultiConnection) {
1840
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
1841
                            }
1842

1843
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
1844
                            if (reuseSingleConnection) {
1845
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
1846
                            }
1847

1848
                            def->ngraphics++;
1849
                        } else
1850
                            virReportOOMError();
1851
                    }
1852
                    VBOX_RELEASE(VRDxServer);
1853
                }
1854
            }
1855

1856
#if VBOX_API_VERSION < 3001000
1857 1858
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
1859

1860 1861 1862 1863
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
1864

1865 1866 1867
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
1868

1869 1870 1871
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
1872

1873 1874 1875 1876
            VBOX_UTF16_FREE(hddBusUtf16);

            if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
                for (i = 0; i < def->ndisks; i++) {
1877
                    if ((def->disks[i] = virDomainDiskDefNew())) {
1878 1879
                        def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                        def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
1880
                        virDomainDiskSetType(def->disks[i],
E
Eric Blake 已提交
1881
                                             VIR_STORAGE_TYPE_FILE);
1882
                    }
1883
                }
1884
            }
1885

1886 1887 1888 1889
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
1890

1891 1892
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
1893

1894
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
1895

1896
                if (hddType == HardDiskType_Immutable)
1897
                    def->disks[hddNum]->src->readonly = true;
1898 1899
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
1900
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
1901
                hddNum++;
1902

1903 1904 1905 1906
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
1907

1908 1909 1910 1911
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
1912

1913 1914
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
1915

1916
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
1917

1918
                if (hddType == HardDiskType_Immutable)
1919
                    def->disks[hddNum]->src->readonly = true;
1920 1921
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
1922
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
1923
                hddNum++;
1924

1925 1926 1927 1928
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
1929

1930 1931 1932 1933
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
1934

1935 1936
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
1937

1938
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
1939

1940
                if (hddType == HardDiskType_Immutable)
1941
                    def->disks[hddNum]->src->readonly = true;
1942 1943
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
J
Ján Tomko 已提交
1944 1945
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
                hddNum++;
1946 1947 1948 1949 1950

                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskSS);
            }
1951
#else  /* VBOX_API_VERSION >= 3001000 */
1952 1953 1954 1955 1956 1957 1958
            /* dump IDE hdds if present */

            bool error = false;
            int diskCount = 0;
            PRUint32   maxPortPerInst[StorageBus_Floppy + 1] = {};
            PRUint32   maxSlotPerPort[StorageBus_Floppy + 1] = {};
            def->ndisks = 0;
1959
            vboxArrayGet(&mediumAttachments, machine, machine->vtbl->GetMediumAttachments);
1960 1961

            /* get the number of attachments */
1962 1963
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
1964 1965 1966 1967 1968 1969 1970
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
1971 1972
                    }
                }
1973
            }
1974

1975 1976 1977
            /* Allocate mem, if fails return error */
            if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) {
                for (i = 0; i < def->ndisks; i++) {
1978 1979
                    virDomainDiskDefPtr disk = virDomainDiskDefNew();
                    if (!disk) {
1980 1981
                        error = true;
                        break;
1982
                    }
1983
                    def->disks[i] = disk;
1984
                }
1985 1986 1987 1988 1989 1990 1991 1992
            } else {
                error = true;
            }

            if (!error)
                error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort);

            /* get the attachment details here */
1993 1994
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
                IStorageController *storageController = NULL;
                PRUnichar *storageControllerName = NULL;
                PRUint32   deviceType     = DeviceType_Null;
                PRUint32   storageBus     = StorageBus_Null;
                PRBool     readOnly       = PR_FALSE;
                IMedium   *medium         = NULL;
                PRUnichar *mediumLocUtf16 = NULL;
                char      *mediumLocUtf8  = NULL;
                PRUint32   deviceInst     = 0;
                PRInt32    devicePort     = 0;
                PRInt32    deviceSlot     = 0;

                if (!imediumattach)
                    continue;

                imediumattach->vtbl->GetMedium(imediumattach, &medium);
                if (!medium)
                    continue;

                imediumattach->vtbl->GetController(imediumattach, &storageControllerName);
                if (!storageControllerName) {
                    VBOX_RELEASE(medium);
                    continue;
                }

                machine->vtbl->GetStorageControllerByName(machine,
                                                          storageControllerName,
                                                          &storageController);
                VBOX_UTF16_FREE(storageControllerName);
                if (!storageController) {
                    VBOX_RELEASE(medium);
                    continue;
                }
2028

2029 2030 2031
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
2032 2033
                ignore_value(virDomainDiskSetSource(def->disks[diskCount],
                                                    mediumLocUtf8));
2034 2035
                VBOX_UTF8_FREE(mediumLocUtf8);

2036
                if (!virDomainDiskGetSource(def->disks[diskCount])) {
2037 2038 2039 2040 2041
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2042

2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
                storageController->vtbl->GetBus(storageController, &storageBus);
                if (storageBus == StorageBus_IDE) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                } else if (storageBus == StorageBus_SATA) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA;
                } else if (storageBus == StorageBus_SCSI) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI;
                } else if (storageBus == StorageBus_Floppy) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC;
                }
2053

2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
                imediumattach->vtbl->GetType(imediumattach, &deviceType);
                if (deviceType == DeviceType_HardDisk)
                    def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                else if (deviceType == DeviceType_Floppy)
                    def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                else if (deviceType == DeviceType_DVD)
                    def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;

                imediumattach->vtbl->GetPort(imediumattach, &devicePort);
                imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot);
2064
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2065 2066 2067 2068 2069 2070
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2071 2072 2073 2074
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2075 2076 2077 2078 2079
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2080

2081 2082
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2083
                    def->disks[diskCount]->src->readonly = true;
2084

2085
                virDomainDiskSetType(def->disks[diskCount],
E
Eric Blake 已提交
2086
                                     VIR_STORAGE_TYPE_FILE);
2087

2088 2089 2090 2091
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2092

2093
            vboxArrayRelease(&mediumAttachments);
2094

2095 2096 2097 2098 2099 2100 2101 2102
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2103

2104
#endif /* VBOX_API_VERSION >= 3001000 */
2105

M
Matthias Bolte 已提交
2106 2107 2108 2109 2110 2111 2112 2113 2114
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

            vboxArrayGet(&sharedFolders, machine,
                         machine->vtbl->GetSharedFolders);

            if (sharedFolders.count > 0) {
2115
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
M
Matthias Bolte 已提交
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125
                    goto sharedFoldersCleanup;

                for (i = 0; i < sharedFolders.count; i++) {
                    ISharedFolder *sharedFolder = sharedFolders.items[i];
                    PRUnichar *nameUtf16 = NULL;
                    char *name = NULL;
                    PRUnichar *hostPathUtf16 = NULL;
                    char *hostPath = NULL;
                    PRBool writable = PR_FALSE;

2126
                    if (VIR_ALLOC(def->fss[i]) < 0)
M
Matthias Bolte 已提交
2127 2128 2129 2130 2131 2132
                        goto sharedFoldersCleanup;

                    def->fss[i]->type = VIR_DOMAIN_FS_TYPE_MOUNT;

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
2133 2134 2135
                    if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
                        VBOX_UTF8_FREE(hostPath);
                        VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2136 2137
                        goto sharedFoldersCleanup;
                    }
2138 2139
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2140 2141 2142

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
2143 2144 2145
                    if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
                        VBOX_UTF8_FREE(name);
                        VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2146 2147
                        goto sharedFoldersCleanup;
                    }
2148 2149
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2150 2151 2152 2153 2154 2155 2156 2157

                    sharedFolder->vtbl->GetWritable(sharedFolder, &writable);
                    def->fss[i]->readonly = !writable;

                    ++def->nfss;
                }
            }

2158
 sharedFoldersCleanup:
M
Matthias Bolte 已提交
2159 2160
            vboxArrayRelease(&sharedFolders);

2161 2162 2163 2164 2165
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
2166

2167 2168 2169
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2170

2171 2172 2173 2174
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
2175

2176 2177 2178
                    VBOX_RELEASE(adapter);
                }
            }
2179

2180 2181 2182
            /* Allocate memory for the networkcards which are enabled */
            if ((def->nnets > 0) && (VIR_ALLOC_N(def->nets, def->nnets) >= 0)) {
                for (i = 0; i < def->nnets; i++) {
2183
                    ignore_value(VIR_ALLOC(def->nets[i]));
2184 2185
                }
            }
2186

2187
            /* Now get the details about the network cards here */
2188
            for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
2189
                INetworkAdapter *adapter = NULL;
2190

2191 2192 2193
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2194

2195 2196 2197 2198 2199 2200 2201
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        PRUint32 attachmentType    = NetworkAttachmentType_Null;
                        PRUint32 adapterType       = NetworkAdapterType_Null;
                        PRUnichar *MACAddressUtf16 = NULL;
                        char *MACAddress           = NULL;
                        char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
2202

2203 2204
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
2205

2206
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
2207

2208 2209 2210
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
2211

2212
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
2213

2214
#if VBOX_API_VERSION < 4001000
2215
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2216
#else /* VBOX_API_VERSION >= 4001000 */
2217
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
2218
#endif /* VBOX_API_VERSION >= 4001000 */
2219

2220
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
2221
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
2222

2223 2224
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
2225

2226 2227 2228
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
2229

2230 2231 2232 2233 2234
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

                            adapter->vtbl->GetInternalNetwork(adapter, &intNetUtf16);

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
2235
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
2236 2237 2238 2239 2240 2241 2242 2243 2244 2245

                            VBOX_UTF8_FREE(intNet);
                            VBOX_UTF16_FREE(intNetUtf16);

                        } else if (attachmentType == NetworkAttachmentType_HostOnly) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;

                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_NETWORK;

2246
#if VBOX_API_VERSION < 4001000
2247
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2248
#else /* VBOX_API_VERSION >= 4001000 */
2249
                            adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
2250
#endif /* VBOX_API_VERSION >= 4001000 */
2251 2252

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
2253
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266

                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);

                        } else {
                            /* default to user type i.e. NAT in VirtualBox if this
                             * dump is ever used to create a machine.
                             */
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
                        }

                        adapter->vtbl->GetAdapterType(adapter, &adapterType);
                        if (adapterType == NetworkAdapterType_Am79C970A) {
2267
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
2268
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
2269
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
2270
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
2271
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
2272
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
2273
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
2274
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
2275
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
2276
#if VBOX_API_VERSION >= 3001000
2277
                        } else if (adapterType == NetworkAdapterType_Virtio) {
2278
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
2279
#endif /* VBOX_API_VERSION >= 3001000 */
2280 2281
                        }

2282 2283 2284 2285 2286 2287 2288 2289 2290
                        adapter->vtbl->GetMACAddress(adapter, &MACAddressUtf16);
                        VBOX_UTF16_TO_UTF8(MACAddressUtf16, &MACAddress);
                        snprintf(macaddr, VIR_MAC_STRING_BUFLEN,
                                 "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
                                 MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3],
                                 MACAddress[4], MACAddress[5], MACAddress[6], MACAddress[7],
                                 MACAddress[8], MACAddress[9], MACAddress[10], MACAddress[11]);

                        /* XXX some real error handling here some day ... */
2291
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
2292 2293 2294 2295 2296 2297
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
2298
                    }
2299 2300

                    VBOX_RELEASE(adapter);
2301
                }
2302
            }
2303

2304
            /* dump sound card if active */
2305

2306 2307 2308
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
2309

2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336
            machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
            if (audioAdapter) {
                PRBool enabled = PR_FALSE;

                audioAdapter->vtbl->GetEnabled(audioAdapter, &enabled);
                if (enabled) {
                    PRUint32 audioController = AudioControllerType_AC97;

                    def->nsounds = 1;
                    if (VIR_ALLOC_N(def->sounds, def->nsounds) >= 0) {
                        if (VIR_ALLOC(def->sounds[0]) >= 0) {
                            audioAdapter->vtbl->GetAudioController(audioAdapter, &audioController);
                            if (audioController == AudioControllerType_SB16) {
                                def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16;
                            } else if (audioController == AudioControllerType_AC97) {
                                def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97;
                            }
                        } else {
                            VIR_FREE(def->sounds);
                            def->nsounds = 0;
                        }
                    } else {
                        def->nsounds = 0;
                    }
                }
                VBOX_RELEASE(audioAdapter);
            }
2337

2338
#if VBOX_API_VERSION < 3001000
2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
            /* dump CDROM/DVD if the drive is attached and has DVD/CD in it */
            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
            if (dvdDrive) {
                PRUint32 state = DriveState_Null;

                dvdDrive->vtbl->GetState(dvdDrive, &state);
                if (state == DriveState_ImageMounted) {
                    IDVDImage *dvdImage = NULL;

                    dvdDrive->vtbl->GetImage(dvdDrive, &dvdImage);
                    if (dvdImage) {
                        PRUnichar *locationUtf16 = NULL;
                        char *location           = NULL;

                        dvdImage->vtbl->imedium.GetLocation((IMedium *)dvdImage, &locationUtf16);
                        VBOX_UTF16_TO_UTF8(locationUtf16, &location);

                        def->ndisks++;
                        if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
2358
                            if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) {
2359 2360
                                def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
                                def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2361
                                virDomainDiskSetType(def->disks[def->ndisks - 1],
E
Eric Blake 已提交
2362
                                                     VIR_STORAGE_TYPE_FILE);
2363
                                def->disks[def->ndisks - 1]->src->readonly = true;
2364
                                ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
2365 2366
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
                                def->ndisks--;
2367
                            } else {
2368
                                def->ndisks--;
2369 2370
                            }
                        } else {
2371
                            def->ndisks--;
2372
                        }
2373 2374 2375 2376

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
2377 2378
                    }
                }
2379 2380
                VBOX_RELEASE(dvdDrive);
            }
2381

2382 2383 2384 2385 2386 2387 2388
            /* dump Floppy if the drive is attached and has floppy in it */
            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
            if (floppyDrive) {
                PRBool enabled = PR_FALSE;

                floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                if (enabled) {
2389 2390
                    PRUint32 state = DriveState_Null;

2391
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
2392
                    if (state == DriveState_ImageMounted) {
2393
                        IFloppyImage *floppyImage = NULL;
2394

2395 2396
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
2397 2398 2399
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

2400 2401
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
2402 2403 2404

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
2405
                                if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) {
2406 2407
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
2408
                                    virDomainDiskSetType(def->disks[def->ndisks - 1],
E
Eric Blake 已提交
2409
                                                         VIR_STORAGE_TYPE_FILE);
2410
                                    def->disks[def->ndisks - 1]->src->readonly = false;
2411
                                    ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
2412 2413
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
                                    def->ndisks--;
2414 2415 2416 2417 2418 2419 2420
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

2421 2422 2423
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
2424 2425 2426 2427
                        }
                    }
                }

2428 2429
                VBOX_RELEASE(floppyDrive);
            }
2430 2431
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
2432 2433 2434 2435 2436 2437 2438 2439 2440

            /* dump serial port if active */
            def->nserials = 0;
            /* Get which serial ports are enabled/active */
            for (i = 0; i < serialPortCount; i++) {
                ISerialPort *serialPort = NULL;

                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
2441 2442
                    PRBool enabled = PR_FALSE;

2443
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
2444
                    if (enabled) {
2445
                        def->nserials++;
2446 2447
                    }

2448
                    VBOX_RELEASE(serialPort);
2449
                }
2450
            }
2451

2452 2453 2454
            /* Allocate memory for the serial ports which are enabled */
            if ((def->nserials > 0) && (VIR_ALLOC_N(def->serials, def->nserials) >= 0)) {
                for (i = 0; i < def->nserials; i++) {
2455
                    ignore_value(VIR_ALLOC(def->serials[i]));
2456 2457
                }
            }
2458

2459
            /* Now get the details about the serial ports here */
2460 2461 2462
            for (i = 0;
                 serialPortIncCount < def->nserials && i < serialPortCount;
                 i++) {
2463
                ISerialPort *serialPort = NULL;
2464

2465 2466 2467
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
2468

2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
                    if (enabled) {
                        PRUint32 hostMode    = PortMode_Disconnected;
                        PRUint32 IOBase      = 0;
                        PRUint32 IRQ         = 0;
                        PRUnichar *pathUtf16 = NULL;
                        char *path           = NULL;

                        serialPort->vtbl->GetHostMode(serialPort, &hostMode);
                        if (hostMode == PortMode_HostPipe) {
2479
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
2480
                        } else if (hostMode == PortMode_HostDevice) {
2481
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
2482
#if VBOX_API_VERSION >= 3000000
2483
                        } else if (hostMode == PortMode_RawFile) {
2484
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
2485
#endif /* VBOX_API_VERSION >= 3000000 */
2486
                        } else {
2487
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
2488
                        }
2489

2490
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2491

2492 2493 2494 2495 2496 2497 2498
                        serialPort->vtbl->GetIRQ(serialPort, &IRQ);
                        serialPort->vtbl->GetIOBase(serialPort, &IOBase);
                        if ((IRQ == 4) && (IOBase == 1016)) {
                            def->serials[serialPortIncCount]->target.port = 0;
                        } else if ((IRQ == 3) && (IOBase == 760)) {
                            def->serials[serialPortIncCount]->target.port = 1;
                        }
2499

2500
                        serialPort->vtbl->GetPath(serialPort, &pathUtf16);
2501

2502 2503
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
2504
                            ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
2505 2506
                        }

2507 2508 2509 2510
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
2511 2512
                    }

2513 2514 2515
                    VBOX_RELEASE(serialPort);
                }
            }
2516

2517 2518 2519 2520 2521
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
2522

2523 2524 2525
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
2526

2527 2528 2529
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
2530
                    }
2531 2532

                    VBOX_RELEASE(parallelPort);
2533
                }
2534
            }
2535

2536 2537 2538
            /* Allocate memory for the parallel ports which are enabled */
            if ((def->nparallels > 0) && (VIR_ALLOC_N(def->parallels, def->nparallels) >= 0)) {
                for (i = 0; i < def->nparallels; i++) {
2539
                    ignore_value(VIR_ALLOC(def->parallels[i]));
2540
                }
2541
            }
2542

2543
            /* Now get the details about the parallel ports here */
2544 2545 2546 2547
            for (i = 0;
                 parallelPortIncCount < def->nparallels &&
                     i < parallelPortCount;
                 i++) {
2548
                IParallelPort *parallelPort = NULL;
2549

2550 2551 2552
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
2553

2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        PRUint32 IOBase      = 0;
                        PRUint32 IRQ         = 0;
                        PRUnichar *pathUtf16 = NULL;
                        char *path           = NULL;

                        parallelPort->vtbl->GetIRQ(parallelPort, &IRQ);
                        parallelPort->vtbl->GetIOBase(parallelPort, &IOBase);
                        if ((IRQ == 7) && (IOBase == 888)) {
                            def->parallels[parallelPortIncCount]->target.port = 0;
                        } else if ((IRQ == 5) && (IOBase == 632)) {
                            def->parallels[parallelPortIncCount]->target.port = 1;
                        }
2568

2569
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
2570
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2571

2572
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
2573

2574
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
2575
                        ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
2576

2577 2578 2579 2580
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
2581
                    }
2582 2583

                    VBOX_RELEASE(parallelPort);
2584
                }
2585
            }
2586

2587
            /* dump USB devices/filters if active */
2588
            vboxHostDeviceGetXMLDesc(data, def, machine);
2589 2590 2591 2592 2593

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
2594
        }
2595 2596
        VBOX_RELEASE(machine);
        machine = NULL;
2597 2598 2599
    }

    if (gotAllABoutDef == 0)
2600
        ret = virDomainDefFormat(def, flags);
2601

2602
 cleanup:
2603
    vboxIIDUnalloc(&iid);
2604 2605 2606 2607
    virDomainDefFree(def);
    return ret;
}

2608
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
2609
    VBOX_OBJECT_CHECK(conn, int, -1);
2610
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
2611 2612 2613
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
2614
    nsresult rc;
2615
    size_t i, j;
2616

2617
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
2618
    if (NS_FAILED(rc)) {
2619 2620 2621
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Defined Domains, rc=%08x"),
                       (unsigned)rc);
2622 2623
        goto cleanup;
    }
2624

2625 2626
    memset(names, 0, sizeof(names[i]) * maxnames);

2627 2628 2629
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
2630 2631 2632 2633 2634 2635

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
2636 2637
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
2638 2639
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
2640 2641 2642
                    if (VIR_STRDUP(names[j], machineName) < 0) {
                        VBOX_UTF16_FREE(machineNameUtf16);
                        VBOX_UTF8_FREE(machineName);
2643
                        for (j = 0; j < maxnames; j++)
2644 2645 2646
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
2647
                    }
2648 2649
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
2650
                    j++;
2651
                    ret++;
2652 2653 2654 2655 2656
                }
            }
        }
    }

2657
 cleanup:
2658
    vboxArrayRelease(&machines);
2659 2660 2661
    return ret;
}

2662 2663
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn)
{
2664
    VBOX_OBJECT_CHECK(conn, int, -1);
2665
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
2666
    PRUint32 state       = MachineState_Null;
2667
    nsresult rc;
2668
    size_t i;
2669

2670
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
2671
    if (NS_FAILED(rc)) {
2672 2673 2674
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
2675 2676
        goto cleanup;
    }
2677

2678 2679 2680
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
2681 2682 2683 2684 2685 2686

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
2687 2688
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
2689
                    ret++;
2690 2691 2692 2693 2694
                }
            }
        }
    }

2695
 cleanup:
2696
    vboxArrayRelease(&machines);
2697 2698 2699
    return ret;
}

T
Taowei 已提交
2700
#if VBOX_API_VERSION < 3001000
2701

E
Eric Blake 已提交
2702
static void
T
Taowei 已提交
2703
_vboxAttachDrivesOld(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
E
Eric Blake 已提交
2704
{
2705
    size_t i;
E
Eric Blake 已提交
2706
    nsresult rc;
2707

E
Eric Blake 已提交
2708 2709 2710 2711
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
2712 2713 2714 2715 2716
        const char *src = virDomainDiskGetSource(def->disks[i]);
        int type = virDomainDiskGetType(def->disks[i]);
        int format = virDomainDiskGetFormat(def->disks[i]);

        VIR_DEBUG("disk(%zu) type:       %d", i, type);
2717 2718
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
2719
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
2720
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
2721 2722
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
2723
        VIR_DEBUG("disk(%zu) driverType: %s", i,
2724
                  virStorageFileFormatTypeToString(format));
2725
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
2726
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->src->readonly
E
Eric Blake 已提交
2727
                                             ? "True" : "False"));
2728
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->src->shared
E
Eric Blake 已提交
2729 2730 2731
                                             ? "True" : "False"));

        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
2732
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
2733 2734 2735 2736 2737 2738 2739
                IDVDDrive *dvdDrive = NULL;
                /* Currently CDROM/DVD Drive is always IDE
                 * Secondary Master so neglecting the following
                 * parameters:
                 *      def->disks[i]->bus
                 *      def->disks[i]->dst
                 */
2740

E
Eric Blake 已提交
2741 2742 2743 2744
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
2745 2746
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
2747

2748
                    VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
2749

E
Eric Blake 已提交
2750 2751 2752 2753 2754
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
2755
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
2756 2757 2758 2759
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
2760
                                                           &dvduuid.value);
E
Eric Blake 已提交
2761
                        if (NS_FAILED(rc)) {
2762 2763 2764
                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                           _("can't get the uuid of the file to "
                                             "be attached to cdrom: %s, rc=%08x"),
2765
                                           src, (unsigned)rc);
E
Eric Blake 已提交
2766
                        } else {
2767
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
2768
                            if (NS_FAILED(rc)) {
2769 2770
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
2771
                                               src, (unsigned)rc);
E
Eric Blake 已提交
2772
                            } else {
2773
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
2774
                            }
2775
                        }
E
Eric Blake 已提交
2776 2777

                        VBOX_MEDIUM_RELEASE(dvdImage);
2778
                    }
2779
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
2780 2781 2782
                    VBOX_UTF16_FREE(dvdfileUtf16);
                    VBOX_RELEASE(dvdDrive);
                }
E
Eric Blake 已提交
2783
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
E
Eric Blake 已提交
2784 2785
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
E
Eric Blake 已提交
2786
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
2787 2788
                IHardDisk *hardDisk     = NULL;
                PRUnichar *hddfileUtf16 = NULL;
2789
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
2790 2791 2792 2793 2794 2795
                PRUnichar *hddEmpty     = NULL;
                /* Current Limitation: Harddisk can't be connected to
                 * Secondary Master as Secondary Master is always used
                 * for CD/DVD Drive, so don't connect the harddisk if it
                 * is requested to be connected to Secondary master
                 */
2796

2797
                VBOX_UTF8_TO_UTF16(src, &hddfileUtf16);
E
Eric Blake 已提交
2798
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
2799

E
Eric Blake 已提交
2800 2801
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
2802

E
Eric Blake 已提交
2803
                if (!hardDisk) {
2804
# if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
2805 2806 2807 2808
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
2809
# else
E
Eric Blake 已提交
2810 2811 2812 2813 2814 2815 2816 2817
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
2818
# endif
E
Eric Blake 已提交
2819
                }
2820

E
Eric Blake 已提交
2821 2822
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
2823
                                                       &hdduuid.value);
E
Eric Blake 已提交
2824
                    if (NS_FAILED(rc)) {
2825 2826 2827
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("can't get the uuid of the file to be "
                                         "attached as harddisk: %s, rc=%08x"),
2828
                                       src, (unsigned)rc);
E
Eric Blake 已提交
2829
                    } else {
2830
                        if (def->disks[i]->src->readonly) {
E
Eric Blake 已提交
2831 2832
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
2833
                            VIR_DEBUG("setting harddisk to readonly");
2834
                        } else if (!def->disks[i]->src->readonly) {
E
Eric Blake 已提交
2835 2836
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
2837
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
2838 2839 2840
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
2841
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
2842
                                       " is taken by CD/DVD Drive");
2843
                            } else {
E
Eric Blake 已提交
2844 2845 2846 2847
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

2848 2849
                                char *hddcname;
                                ignore_value(VIR_STRDUP(hddcname, "IDE"));
E
Eric Blake 已提交
2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861
                                VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
                                VIR_FREE(hddcname);

                                if (STREQ(def->disks[i]->dst, "hda")) {
                                    channel = 0;
                                    device  = 0;
                                } else if (STREQ(def->disks[i]->dst, "hdb")) {
                                    channel = 0;
                                    device  = 1;
                                } else if (STREQ(def->disks[i]->dst, "hdd")) {
                                    channel = 1;
                                    device  = 1;
2862
                                }
E
Eric Blake 已提交
2863 2864

                                rc = machine->vtbl->AttachHardDisk(machine,
2865
                                                                   hdduuid.value,
E
Eric Blake 已提交
2866 2867 2868 2869 2870 2871
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
2872 2873 2874
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
2875
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
2876
                                } else {
2877
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
2878 2879 2880
                                }
                            }
                        }
2881
                    }
E
Eric Blake 已提交
2882 2883
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
2884
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
2885 2886
                VBOX_UTF16_FREE(hddEmpty);
                VBOX_UTF16_FREE(hddfileUtf16);
E
Eric Blake 已提交
2887
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
E
Eric Blake 已提交
2888 2889
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
2890
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
2891 2892 2893 2894 2895 2896 2897
                IFloppyDrive *floppyDrive;
                machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                if (floppyDrive) {
                    rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                    if (NS_SUCCEEDED(rc)) {
                        IFloppyImage *floppyImage   = NULL;
                        PRUnichar *fdfileUtf16      = NULL;
2898 2899
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
2900

2901
                        VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
E
Eric Blake 已提交
2902 2903 2904
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
2905

E
Eric Blake 已提交
2906 2907 2908
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
2909
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
2910 2911
                                                                 &floppyImage);
                        }
2912

E
Eric Blake 已提交
2913 2914
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
2915
                                                                  &fduuid.value);
E
Eric Blake 已提交
2916
                            if (NS_FAILED(rc)) {
2917 2918 2919
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
2920
                                               src, (unsigned)rc);
E
Eric Blake 已提交
2921 2922
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
2923
                                                                   fduuid.value);
E
Eric Blake 已提交
2924
                                if (NS_FAILED(rc)) {
2925 2926 2927
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
2928
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
2929
                                } else {
2930
                                    DEBUGIID("floppyImage UUID", fduuid.value);
2931 2932
                                }
                            }
E
Eric Blake 已提交
2933
                            VBOX_MEDIUM_RELEASE(floppyImage);
2934
                        }
2935
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
2936
                        VBOX_UTF16_FREE(fdfileUtf16);
2937
                    }
E
Eric Blake 已提交
2938
                    VBOX_RELEASE(floppyDrive);
2939
                }
E
Eric Blake 已提交
2940
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
2941
            }
2942
        }
E
Eric Blake 已提交
2943
    }
T
Taowei 已提交
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953
}

#elif VBOX_API_VERSION < 4000000

static void
_vboxAttachDrivesOld(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    size_t i;
    nsresult rc;

E
Eric Blake 已提交
2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965
    PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {};
    PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {};
    PRUnichar *storageCtlName = NULL;
    bool error = false;

    /* get the max port/slots/etc for the given storage bus */
    error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst,
                                      maxSlotPerPort);

    /* add a storage controller for the mediums to be attached */
    /* this needs to change when multiple controller are supported for
     * ver > 3.1 */
2966
    {
E
Eric Blake 已提交
2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001
        IStorageController *storageCtl = NULL;
        PRUnichar *sName = NULL;

        VBOX_UTF8_TO_UTF16("IDE Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_IDE,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);

        VBOX_UTF8_TO_UTF16("SATA Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_SATA,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);

        VBOX_UTF8_TO_UTF16("SCSI Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_SCSI,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);

        VBOX_UTF8_TO_UTF16("Floppy Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_Floppy,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);
    }
3002

E
Eric Blake 已提交
3003
    for (i = 0; i < def->ndisks && !error; i++) {
3004 3005 3006 3007 3008
        const char *src = virDomainDiskGetSource(def->disks[i]);
        int type = virDomainDiskGetType(def->disks[i]);
        int format = virDomainDiskGetFormat(def->disks[i]);

        VIR_DEBUG("disk(%zu) type:       %d", i, type);
3009 3010
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3011
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
3012
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3013 3014
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
3015
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3016
                  virStorageFileFormatTypeToString(format));
3017
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
3018
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->src->readonly
E
Eric Blake 已提交
3019
                                             ? "True" : "False"));
3020
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->src->shared
E
Eric Blake 已提交
3021 3022
                                             ? "True" : "False"));

E
Eric Blake 已提交
3023
        if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3024 3025 3026 3027 3028 3029 3030 3031 3032
            IMedium   *medium          = NULL;
            PRUnichar *mediumUUID      = NULL;
            PRUnichar *mediumFileUtf16 = NULL;
            PRUint32   storageBus      = StorageBus_Null;
            PRUint32   deviceType      = DeviceType_Null;
            PRInt32    deviceInst      = 0;
            PRInt32    devicePort      = 0;
            PRInt32    deviceSlot      = 0;

3033
            VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16);
E
Eric Blake 已提交
3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050

            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                deviceType = DeviceType_HardDisk;
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3051

E
Eric Blake 已提交
3052 3053
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
3054

E
Eric Blake 已提交
3055
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
3056 3057

                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3058 3059 3060 3061 3062 3063 3064 3065
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
3066 3067
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
3068 3069 3070 3071
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
3072 3073
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3074 3075 3076 3077 3078 3079
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
3080
                }
E
Eric Blake 已提交
3081 3082
                VBOX_UTF16_FREE(mediumEmpty);
            }
3083

E
Eric Blake 已提交
3084
            if (!medium) {
3085 3086 3087
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to attach the following disk/dvd/floppy "
                                 "to the machine: %s, rc=%08x"),
3088
                               src, (unsigned)rc);
E
Eric Blake 已提交
3089 3090 3091
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3092

E
Eric Blake 已提交
3093 3094
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
3095 3096 3097
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("can't get the uuid of the file to be attached "
                                 "as harddisk/dvd/floppy: %s, rc=%08x"),
3098
                               src, (unsigned)rc);
E
Eric Blake 已提交
3099 3100 3101 3102
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3103

E
Eric Blake 已提交
3104
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3105
                if (def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3106
                    medium->vtbl->SetType(medium, MediumType_Immutable);
3107
                    VIR_DEBUG("setting harddisk to immutable");
3108
                } else if (!def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3109
                    medium->vtbl->SetType(medium, MediumType_Normal);
3110
                    VIR_DEBUG("setting harddisk type to normal");
3111
                }
E
Eric Blake 已提交
3112
            }
3113

E
Eric Blake 已提交
3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126
            if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                VBOX_UTF8_TO_UTF16("IDE Controller", &storageCtlName);
                storageBus = StorageBus_IDE;
            } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SATA) {
                VBOX_UTF8_TO_UTF16("SATA Controller", &storageCtlName);
                storageBus = StorageBus_SATA;
            } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
                VBOX_UTF8_TO_UTF16("SCSI Controller", &storageCtlName);
                storageBus = StorageBus_SCSI;
            } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_FDC) {
                VBOX_UTF8_TO_UTF16("Floppy Controller", &storageCtlName);
                storageBus = StorageBus_Floppy;
            }
3127

E
Eric Blake 已提交
3128 3129 3130 3131 3132 3133 3134 3135
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
3136
                virReportError(VIR_ERR_INTERNAL_ERROR,
3137 3138 3139
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
3140
                               src, (unsigned)rc);
3141 3142 3143
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
                                             mediumUUID);

            if (NS_FAILED(rc)) {
3156
                virReportError(VIR_ERR_INTERNAL_ERROR,
3157 3158
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
3159
                               src, (unsigned)rc);
E
Eric Blake 已提交
3160 3161
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
3162
            }
E
Eric Blake 已提交
3163 3164 3165 3166 3167

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
3168 3169
        }
    }
E
Eric Blake 已提交
3170
}
3171

T
Taowei 已提交
3172
#else /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
3173 3174

static void
T
Taowei 已提交
3175 3176 3177
_vboxAttachDrivesOld(virDomainDefPtr def ATTRIBUTE_UNUSED,
                     vboxGlobalData *data ATTRIBUTE_UNUSED,
                     IMachine *machine ATTRIBUTE_UNUSED)
E
Eric Blake 已提交
3178
{
T
Taowei 已提交
3179 3180
    vboxUnsupported();
}
3181

3182
#endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
3183

T
Taowei 已提交
3184 3185
static int
vboxDomainUndefine(virDomainPtr dom)
E
Eric Blake 已提交
3186
{
T
Taowei 已提交
3187
    return vboxDomainUndefineFlags(dom, 0);
E
Eric Blake 已提交
3188
}
3189

T
Taowei 已提交
3190 3191 3192
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
                                      int mediaChangeOnly ATTRIBUTE_UNUSED)
E
Eric Blake 已提交
3193
{
T
Taowei 已提交
3194 3195 3196 3197 3198 3199 3200
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    IMachine *machine    = NULL;
    vboxIID iid = VBOX_IID_INITIALIZER;
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
    nsresult rc;
3201

T
Taowei 已提交
3202 3203
    if (VIR_ALLOC(def) < 0)
        return ret;
3204

T
Taowei 已提交
3205 3206
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
        goto cleanup;
E
Eric Blake 已提交
3207

T
Taowei 已提交
3208 3209 3210 3211
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;
E
Eric Blake 已提交
3212

T
Taowei 已提交
3213 3214 3215 3216 3217 3218
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
        goto cleanup;
E
Eric Blake 已提交
3219 3220
    }

T
Taowei 已提交
3221 3222 3223 3224 3225 3226
    if (machine) {
        machine->vtbl->GetState(machine, &state);

        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
E
Eric Blake 已提交
3227
        } else {
T
Taowei 已提交
3228
            rc = VBOX_SESSION_OPEN(iid.value, machine);
3229
        }
T
Taowei 已提交
3230 3231 3232 3233 3234 3235 3236
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
#if VBOX_API_VERSION < 3001000
                    const char *src = virDomainDiskGetSource(dev->data.disk);
                    int type = virDomainDiskGetType(dev->data.disk);
3237

T
Taowei 已提交
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
                            IDVDDrive *dvdDrive = NULL;
                            /* Currently CDROM/DVD Drive is always IDE
                             * Secondary Master so neglecting the following
                             * parameter dev->data.disk->bus
                             */
                            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                            if (dvdDrive) {
                                IDVDImage *dvdImage          = NULL;
                                PRUnichar *dvdfileUtf16      = NULL;
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3251

T
Taowei 已提交
3252
                                VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
3253

T
Taowei 已提交
3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
                                }
                                if (dvdImage) {
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
                                    if (NS_FAILED(rc)) {
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
                                                       src, (unsigned)rc);
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
                                        if (NS_FAILED(rc)) {
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
                                                           src, (unsigned)rc);
                                        } else {
                                            ret = 0;
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
                                        }
                                    }
3278

T
Taowei 已提交
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301
                                    VBOX_MEDIUM_RELEASE(dvdImage);
                                }
                                vboxIIDUnalloc(&dvduuid);
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
                            }
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                                if (NS_SUCCEEDED(rc)) {
                                    IFloppyImage *floppyImage   = NULL;
                                    PRUnichar *fdfileUtf16      = NULL;
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
                                    VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);
3302

T
Taowei 已提交
3303 3304 3305 3306 3307 3308
                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
                                                                             fdemptyuuid.value,
                                                                             &floppyImage);
                                    }
3309

T
Taowei 已提交
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
                                    if (floppyImage) {
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
                                        if (NS_FAILED(rc)) {
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
                                                           src, (unsigned)rc);
                                        } else {
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
                                            if (NS_FAILED(rc)) {
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
                                                               src, (unsigned)rc);
                                            } else {
                                                ret = 0;
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
                                            }
                                        }
                                        VBOX_MEDIUM_RELEASE(floppyImage);
                                    }
                                    vboxIIDUnalloc(&fduuid);
                                    VBOX_UTF16_FREE(fdfileUtf16);
                                }
                                VBOX_RELEASE(floppyDrive);
                            }
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
                        }
                    }
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
                } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                    if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
                        }
                    }
                } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
                           dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
                    PRUnichar *nameUtf16;
                    PRUnichar *hostPathUtf16;
                    PRBool writable;

                    VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
                    VBOX_UTF8_TO_UTF16(dev->data.fs->src, &hostPathUtf16);
                    writable = !dev->data.fs->readonly;
3355

3356
#if VBOX_API_VERSION < 4000000
T
Taowei 已提交
3357 3358
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable);
3359
#else /* VBOX_API_VERSION >= 4000000 */
T
Taowei 已提交
3360 3361
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable, PR_FALSE);
3362
#endif /* VBOX_API_VERSION >= 4000000 */
3363

T
Taowei 已提交
3364 3365 3366 3367 3368 3369 3370
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
                    } else {
                        ret = 0;
                    }
3371

T
Taowei 已提交
3372 3373 3374 3375 3376
                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
                }
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
3377
            }
T
Taowei 已提交
3378
            VBOX_SESSION_CLOSE();
3379
        }
E
Eric Blake 已提交
3380
    }
3381

T
Taowei 已提交
3382 3383 3384 3385 3386 3387
 cleanup:
    vboxIIDUnalloc(&iid);
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}
3388

T
Taowei 已提交
3389 3390 3391 3392
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}
3393

T
Taowei 已提交
3394 3395 3396 3397 3398
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
3399

T
Taowei 已提交
3400 3401 3402 3403 3404
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
        return -1;
    }
3405

T
Taowei 已提交
3406 3407
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}
3408

T
Taowei 已提交
3409 3410 3411 3412 3413 3414
static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
3415

T
Taowei 已提交
3416 3417 3418 3419
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
        return -1;
E
Eric Blake 已提交
3420
    }
3421

T
Taowei 已提交
3422
    return vboxDomainAttachDeviceImpl(dom, xml, 1);
E
Eric Blake 已提交
3423
}
3424

T
Taowei 已提交
3425
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
E
Eric Blake 已提交
3426
{
T
Taowei 已提交
3427 3428 3429 3430 3431 3432 3433
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    IMachine *machine    = NULL;
    vboxIID iid = VBOX_IID_INITIALIZER;
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
    nsresult rc;
E
Eric Blake 已提交
3434

T
Taowei 已提交
3435 3436
    if (VIR_ALLOC(def) < 0)
        return ret;
R
Ryota Ozaki 已提交
3437

T
Taowei 已提交
3438 3439
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
        goto cleanup;
R
Ryota Ozaki 已提交
3440

T
Taowei 已提交
3441 3442 3443 3444
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;
R
Ryota Ozaki 已提交
3445

T
Taowei 已提交
3446 3447 3448 3449 3450 3451
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
        goto cleanup;
E
Eric Blake 已提交
3452 3453
    }

T
Taowei 已提交
3454 3455
    if (machine) {
        machine->vtbl->GetState(machine, &state);
R
Ryota Ozaki 已提交
3456

T
Taowei 已提交
3457 3458 3459 3460 3461 3462
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
        } else {
            rc = VBOX_SESSION_OPEN(iid.value, machine);
        }
R
Ryota Ozaki 已提交
3463

T
Taowei 已提交
3464 3465 3466 3467 3468 3469
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
#if VBOX_API_VERSION < 3001000
                    int type = virDomainDiskGetType(dev->data.disk);
3470

T
Taowei 已提交
3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                        if (type == VIR_STORAGE_TYPE_FILE) {
                            IDVDDrive *dvdDrive = NULL;
                            /* Currently CDROM/DVD Drive is always IDE
                             * Secondary Master so neglecting the following
                             * parameter dev->data.disk->bus
                             */
                            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                            if (dvdDrive) {
                                rc = dvdDrive->vtbl->Unmount(dvdDrive);
                                if (NS_FAILED(rc)) {
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                        if (type == VIR_STORAGE_TYPE_FILE) {
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                PRBool enabled = PR_FALSE;
3498

T
Taowei 已提交
3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531
                                floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                                if (enabled) {
                                    rc = floppyDrive->vtbl->Unmount(floppyDrive);
                                    if (NS_FAILED(rc)) {
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
                                    } else {
                                        ret = 0;
                                    }
                                } else {
                                    /* If you are here means floppy drive is already unmounted
                                     * so don't flag error, just say everything is fine and quit
                                     */
                                    ret = 0;
                                }
                                VBOX_RELEASE(floppyDrive);
                            }
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
                        }
                    }
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
                } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                    if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
                        }
                    }
                } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
                           dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
                    PRUnichar *nameUtf16;
3532

T
Taowei 已提交
3533
                    VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
E
Eric Blake 已提交
3534

T
Taowei 已提交
3535
                    rc = machine->vtbl->RemoveSharedFolder(machine, nameUtf16);
R
Ryota Ozaki 已提交
3536

T
Taowei 已提交
3537 3538 3539 3540 3541 3542 3543
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
                    } else {
                        ret = 0;
                    }
R
Ryota Ozaki 已提交
3544

T
Taowei 已提交
3545 3546 3547 3548 3549 3550 3551
                    VBOX_UTF16_FREE(nameUtf16);
                }
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
            }
            VBOX_SESSION_CLOSE();
        }
E
Eric Blake 已提交
3552
    }
R
Ryota Ozaki 已提交
3553

T
Taowei 已提交
3554 3555 3556 3557 3558
 cleanup:
    vboxIIDUnalloc(&iid);
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
E
Eric Blake 已提交
3559 3560
}

T
Taowei 已提交
3561 3562 3563
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
M
Matthias Bolte 已提交
3564
{
T
Taowei 已提交
3565
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
M
Matthias Bolte 已提交
3566

T
Taowei 已提交
3567 3568 3569 3570
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
        return -1;
M
Matthias Bolte 已提交
3571
    }
T
Taowei 已提交
3572 3573

    return vboxDomainDetachDevice(dom, xml);
M
Matthias Bolte 已提交
3574 3575
}

T
Taowei 已提交
3576 3577 3578 3579
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
3580
{
T
Taowei 已提交
3581 3582 3583
    vboxIID empty = VBOX_IID_INITIALIZER;
    ISnapshot **list = NULL;
    PRUint32 count;
E
Eric Blake 已提交
3584
    nsresult rc;
T
Taowei 已提交
3585 3586
    unsigned int next;
    unsigned int top;
E
Eric Blake 已提交
3587

T
Taowei 已提交
3588
    rc = machine->vtbl->GetSnapshotCount(machine, &count);
E
Eric Blake 已提交
3589
    if (NS_FAILED(rc)) {
3590
        virReportError(VIR_ERR_INTERNAL_ERROR,
T
Taowei 已提交
3591 3592 3593
                       _("could not get snapshot count for domain %s"),
                       dom->name);
        goto error;
E
Eric Blake 已提交
3594 3595
    }

T
Taowei 已提交
3596 3597
    if (count == 0)
        goto out;
E
Eric Blake 已提交
3598

T
Taowei 已提交
3599 3600
    if (VIR_ALLOC_N(list, count) < 0)
        goto error;
E
Eric Blake 已提交
3601

T
Taowei 已提交
3602 3603 3604 3605 3606 3607
#if VBOX_API_VERSION < 4000000
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
#else /* VBOX_API_VERSION >= 4000000 */
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
#endif /* VBOX_API_VERSION >= 4000000 */
    if (NS_FAILED(rc) || !list[0]) {
3608
        virReportError(VIR_ERR_INTERNAL_ERROR,
T
Taowei 已提交
3609 3610 3611
                       _("could not get root snapshot for domain %s"),
                       dom->name);
        goto error;
E
Eric Blake 已提交
3612 3613
    }

T
Taowei 已提交
3614 3615 3616 3617 3618 3619 3620
    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
        vboxArray children = VBOX_ARRAY_INITIALIZER;
        size_t i;

        if (!list[next]) {
3621
            virReportError(VIR_ERR_INTERNAL_ERROR,
T
Taowei 已提交
3622 3623
                           _("unexpected number of snapshots < %u"), count);
            goto error;
E
Eric Blake 已提交
3624
        }
T
Taowei 已提交
3625 3626 3627

        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
E
Eric Blake 已提交
3628
        if (NS_FAILED(rc)) {
3629
            virReportError(VIR_ERR_INTERNAL_ERROR,
T
Taowei 已提交
3630 3631
                           "%s", _("could not get children snapshots"));
            goto error;
3632
        }
T
Taowei 已提交
3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
                continue;
            if (top == count) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
                vboxArrayRelease(&children);
                goto error;
            }
            VBOX_ADDREF(child);
            list[top++] = child;
        }
        vboxArrayRelease(&children);
E
Eric Blake 已提交
3647 3648
    }

T
Taowei 已提交
3649 3650 3651
 out:
    *snapshots = list;
    return count;
3652

T
Taowei 已提交
3653 3654 3655 3656 3657 3658
 error:
    if (list) {
        for (next = 0; next < count; next++)
            VBOX_RELEASE(list[next]);
    }
    VIR_FREE(list);
3659

T
Taowei 已提交
3660
    return -1;
3661 3662
}

T
Taowei 已提交
3663 3664 3665 3666 3667
static ISnapshot *
vboxDomainSnapshotGet(vboxGlobalData *data,
                      virDomainPtr dom,
                      IMachine *machine,
                      const char *name)
3668
{
T
Taowei 已提交
3669 3670 3671 3672 3673
    ISnapshot **snapshots = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;
    int count = 0;
    size_t i;
J
Jiri Denemark 已提交
3674 3675 3676 3677 3678 3679 3680 3681 3682 3683

    if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
        goto cleanup;

    for (i = 0; i < count; i++) {
        PRUnichar *nameUtf16;
        char *nameUtf8;

        rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16);
        if (NS_FAILED(rc) || !nameUtf16) {
3684 3685
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
        VBOX_UTF16_FREE(nameUtf16);
        if (STREQ(name, nameUtf8))
            snapshot = snapshots[i];
        VBOX_UTF8_FREE(nameUtf8);

        if (snapshot)
            break;
    }

    if (!snapshot) {
3699 3700 3701
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
3702 3703 3704
        goto cleanup;
    }

3705
 cleanup:
J
Jiri Denemark 已提交
3706 3707 3708 3709 3710 3711 3712 3713 3714 3715
    if (count > 0) {
        for (i = 0; i < count; i++) {
            if (snapshots[i] != snapshot)
                VBOX_RELEASE(snapshots[i]);
        }
    }
    VIR_FREE(snapshots);
    return snapshot;
}

3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966
#if VBOX_API_VERSION >= 4002000
static int vboxCloseDisksRecursively(virDomainPtr dom, char *location)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    nsresult rc;
    size_t i = 0;
    PRUnichar *locationUtf = NULL;
    IMedium *medium = NULL;
    IMedium **children = NULL;
    PRUint32 childrenSize = 0;
    VBOX_UTF8_TO_UTF16(location, &locationUtf);
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                         locationUtf,
                                         DeviceType_HardDisk,
                                         AccessMode_ReadWrite,
                                         false,
                                         &medium);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to open HardDisk, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }
    rc = medium->vtbl->GetChildren(medium, &childrenSize, &children);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
                       , _("Unable to get disk children"));
        goto cleanup;
    }
    for (i = 0; i < childrenSize; i++) {
        IMedium *childMedium = children[i];
        if (childMedium) {
            PRUnichar *childLocationUtf = NULL;
            char *childLocation = NULL;
            rc = childMedium->vtbl->GetLocation(childMedium, &childLocationUtf);
            VBOX_UTF16_TO_UTF8(childLocationUtf, &childLocation);
            VBOX_UTF16_FREE(childLocationUtf);
            if (vboxCloseDisksRecursively(dom, childLocation) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
                               , _("Unable to close disk children"));
                goto cleanup;
            }
            VIR_FREE(childLocation);
        }
    }
    rc = medium->vtbl->Close(medium);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to close HardDisk, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    VBOX_UTF16_FREE(locationUtf);
    return ret;
}

static int
vboxSnapshotRedefine(virDomainPtr dom,
                     virDomainSnapshotDefPtr def,
                     bool isCurrent)
{
    /*
     * If your snapshot has a parent,
     * it will only be redefined if you have already
     * redefined the parent.
     *
     * The general algorithm of this function is below :
     * First of all, we are going to create our vboxSnapshotXmlMachinePtr struct from
     * the machine settings path.
     * Then, if the machine current snapshot xml file is saved in the machine location,
     * it means that this snapshot was previously modified by us and has fake disks.
     * Fake disks are added when the flag VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT was not set
     * yet, in order to not corrupt read-only disks. The first thing to do is to remove those
     * disks and restore the read-write disks, if any, in the vboxSnapshotXmlMachinePtr struct.
     * We also delete the current snapshot xml file.
     *
     * After that, we are going to register the snapshot read-only disks that we want to redefine,
     * if they are not in the media registry struct.
     *
     * The next step is to unregister the machine and close all disks.
     *
     * Then, we check if the flag VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE has already been set.
     * If this flag was set, we just add read-write disks to the media registry
     * struct. Otherwise, we save the snapshot xml file into the machine location in order
     * to recover the read-write disks during the next redefine and we create differential disks
     * from the snapshot read-only disks and add them to the media registry struct.
     *
     * Finally, we register the machine with the new virtualbox description file.
     */
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID domiid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;
    PRUnichar *settingsFilePath = NULL;
    char *settingsFilePath_Utf8 = NULL;
    virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL;
    char *currentSnapshotXmlFilePath = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    char *machineName = NULL;
    char **realReadWriteDisksPath = NULL;
    int realReadWriteDisksPathSize = 0;
    char **realReadOnlyDisksPath = NULL;
    int realReadOnlyDisksPathSize = 0;
    virVBoxSnapshotConfSnapshotPtr newSnapshotPtr = NULL;
    unsigned char snapshotUuid[VIR_UUID_BUFLEN];
    int it = 0;
    int jt = 0;
    PRUint32 aMediaSize = 0;
    IMedium **aMedia = NULL;
    char *machineLocationPath = NULL;
    char *nameTmpUse = NULL;
    bool snapshotFileExists = false;
    bool needToChangeStorageController = false;

    vboxIIDFromUUID(&domiid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
        goto cleanup;
    }

    rc = machine->vtbl->SaveSettings(machine);
    /*It may failed when the machine is not mutable.*/
    rc = machine->vtbl->GetSettingsFilePath(machine, &settingsFilePath);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get settings file path"));
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(settingsFilePath, &settingsFilePath_Utf8);

    /*Getting the machine name to retrieve the machine location path.*/
    rc = machine->vtbl->GetName(machine, &machineNameUtf16);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get machine name"));
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);

    if (virAsprintf(&nameTmpUse, "%s.vbox", machineName) < 0)
        goto cleanup;
    machineLocationPath = virStringReplace(settingsFilePath_Utf8, nameTmpUse, "");
    if (machineLocationPath == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to get the machine location path"));
        goto cleanup;
    }

    /*We create the xml struct with the settings file path.*/
    snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilePath_Utf8, machineLocationPath);
    if (snapshotMachineDesc == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot create a vboxSnapshotXmlPtr"));
        goto cleanup;
    }
    if (snapshotMachineDesc->currentSnapshot != NULL) {
        if (virAsprintf(&currentSnapshotXmlFilePath, "%s%s.xml", machineLocationPath,
                       snapshotMachineDesc->currentSnapshot) < 0)
            goto cleanup;
        snapshotFileExists = virFileExists(currentSnapshotXmlFilePath);
    }

    if (snapshotFileExists) {
        /*
         * We have created fake disks, so we have to remove them and replace them with
         * the read-write disks if there are any. The fake disks will be closed during
         * the machine unregistration.
         */
        if (virVBoxSnapshotConfRemoveFakeDisks(snapshotMachineDesc) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to remove Fake Disks"));
            goto cleanup;
        }
        realReadWriteDisksPathSize = virVBoxSnapshotConfGetRWDisksPathsFromLibvirtXML(currentSnapshotXmlFilePath,
                                                             &realReadWriteDisksPath);
        realReadOnlyDisksPathSize = virVBoxSnapshotConfGetRODisksPathsFromLibvirtXML(currentSnapshotXmlFilePath,
                                                                         &realReadOnlyDisksPath);
        /*The read-only disk number is necessarily greater or equal to the
         *read-write disk number*/
        if (realReadOnlyDisksPathSize < realReadWriteDisksPathSize) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("The read only disk number must be greater or equal to the "
                           " read write disk number"));
            goto cleanup;
        }
        for (it = 0; it < realReadWriteDisksPathSize; it++) {
            virVBoxSnapshotConfHardDiskPtr readWriteDisk = NULL;
            PRUnichar *locationUtf = NULL;
            IMedium *readWriteMedium = NULL;
            PRUnichar *uuidUtf = NULL;
            char *uuid = NULL;
            PRUnichar *formatUtf = NULL;
            char *format = NULL;
            const char *parentUuid = NULL;

            VBOX_UTF8_TO_UTF16(realReadWriteDisksPath[it], &locationUtf);
            rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                 locationUtf,
                                                 DeviceType_HardDisk,
                                                 AccessMode_ReadWrite,
                                                 false,
                                                 &readWriteMedium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to open HardDisk, rc=%08x"),
                               (unsigned)rc);
                VBOX_UTF16_FREE(locationUtf);
                goto cleanup;
            }
            VBOX_UTF16_FREE(locationUtf);

            rc = readWriteMedium->vtbl->GetId(readWriteMedium, &uuidUtf);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get the read write medium id"));
                goto cleanup;
            }
            VBOX_UTF16_TO_UTF8(uuidUtf, &uuid);
            VBOX_UTF16_FREE(uuidUtf);

            rc = readWriteMedium->vtbl->GetFormat(readWriteMedium, &formatUtf);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get the read write medium format"));
                VIR_FREE(uuid);
                goto cleanup;
            }
            VBOX_UTF16_TO_UTF8(formatUtf, &format);
            VBOX_UTF16_FREE(formatUtf);

            if (VIR_ALLOC(readWriteDisk) < 0) {
                VIR_FREE(uuid);
                VIR_FREE(formatUtf);
                goto cleanup;
            }

            readWriteDisk->format = format;
            readWriteDisk->uuid = uuid;
            readWriteDisk->location = realReadWriteDisksPath[it];
            /*
             * We get the current snapshot's read-only disk uuid in order to add the
             * read-write disk to the media registry as it's child. The read-only disk
             * is already in the media registry because it is the fake disk's parent.
             */
            parentUuid = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
                                                      realReadOnlyDisksPath[it]);
3967 3968 3969 3970 3971
            if (parentUuid == NULL) {
                VIR_FREE(readWriteDisk);
                goto cleanup;
            }

3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672
            if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readWriteDisk,
                                           snapshotMachineDesc->mediaRegistry,
                                           parentUuid) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to add hard disk to media Registry"));
                VIR_FREE(readWriteDisk);
                goto cleanup;
            }
            rc = readWriteMedium->vtbl->Close(readWriteMedium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to close HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
        }
        /*
         * Now we have done this swap, we remove the snapshot xml file from the
         * current machine location.
         */
        if (unlink(currentSnapshotXmlFilePath) < 0) {
            virReportSystemError(errno,
                                 _("Unable to delete file %s"), currentSnapshotXmlFilePath);
            goto cleanup;
        }
    }
    /*
     * Before unregistering the machine, while all disks are still open, ensure that all
     * read-only disks are in the redefined snapshot's media registry (the disks need to
     * be open to query their uuid).
     */
    for (it = 0; it < def->dom->ndisks; it++) {
        int diskInMediaRegistry = 0;
        IMedium *readOnlyMedium = NULL;
        PRUnichar *locationUtf = NULL;
        PRUnichar *uuidUtf = NULL;
        char *uuid = NULL;
        PRUnichar *formatUtf = NULL;
        char *format = NULL;
        PRUnichar *parentUuidUtf = NULL;
        char *parentUuid = NULL;
        virVBoxSnapshotConfHardDiskPtr readOnlyDisk = NULL;

        diskInMediaRegistry = virVBoxSnapshotConfDiskIsInMediaRegistry(snapshotMachineDesc,
                                                        def->dom->disks[it]->src->path);
        if (diskInMediaRegistry == -1) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to know if disk is in media registry"));
            goto cleanup;
        }
        if (diskInMediaRegistry == 1) /*Nothing to do.*/
            continue;
        /*The read only disk is not in the media registry*/

        VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src->path, &locationUtf);
        rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                             locationUtf,
                                             DeviceType_HardDisk,
                                             AccessMode_ReadWrite,
                                             false,
                                             &readOnlyMedium);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to open HardDisk, rc=%08x"),
                           (unsigned)rc);
            VBOX_UTF16_FREE(locationUtf);
            goto cleanup;
        }
        VBOX_UTF16_FREE(locationUtf);

        rc = readOnlyMedium->vtbl->GetId(readOnlyMedium, &uuidUtf);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to get hard disk id"));
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(uuidUtf, &uuid);
        VBOX_UTF16_FREE(uuidUtf);

        rc = readOnlyMedium->vtbl->GetFormat(readOnlyMedium, &formatUtf);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to get hard disk format"));
            VIR_FREE(uuid);
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(formatUtf, &format);
        VBOX_UTF16_FREE(formatUtf);

        /*This disk is already in the media registry*/
        IMedium *parentReadOnlyMedium = NULL;
        rc = readOnlyMedium->vtbl->GetParent(readOnlyMedium, &parentReadOnlyMedium);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to get parent hard disk"));
            VIR_FREE(uuid);
            goto cleanup;
        }

        rc = parentReadOnlyMedium->vtbl->GetId(parentReadOnlyMedium, &parentUuidUtf);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to get hard disk id, rc=%08x"),
                           (unsigned)rc);
            VIR_FREE(uuid);
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(parentUuidUtf, &parentUuid);
        VBOX_UTF16_FREE(parentUuidUtf);

        rc = readOnlyMedium->vtbl->Close(readOnlyMedium);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to close HardDisk, rc=%08x"),
                           (unsigned)rc);
            VIR_FREE(uuid);
            VIR_FREE(parentUuid);
            goto cleanup;
        }

        if (VIR_ALLOC(readOnlyDisk) < 0) {
            VIR_FREE(uuid);
            VIR_FREE(parentUuid);
            goto cleanup;
        }

        readOnlyDisk->format = format;
        readOnlyDisk->uuid = uuid;
        if (VIR_STRDUP(readOnlyDisk->location, def->dom->disks[it]->src->path) < 0) {
            VIR_FREE(readOnlyDisk);
            goto cleanup;
        }

        if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readOnlyDisk, snapshotMachineDesc->mediaRegistry,
                                       parentUuid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to add hard disk to media registry"));
            VIR_FREE(readOnlyDisk);
            goto cleanup;
        }
    }

    /*Now, we can unregister the machine*/
    rc = machine->vtbl->Unregister(machine,
                              CleanupMode_DetachAllReturnHardDisksOnly,
                              &aMediaSize,
                              &aMedia);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to unregister machine, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }
    VBOX_RELEASE(machine);

    /*
     * Unregister the machine, and then close all disks returned by the unregister method.
     * Some close operations will fail because some disks that need to be closed will not
     * be returned by virtualbox. We will close them just after. We have to use this
     * solution because it is the only way to delete fake disks.
     */
    for (it = 0; it < aMediaSize; it++) {
        IMedium *medium = aMedia[it];
        if (medium) {
            PRUnichar *locationUtf16 = NULL;
            char *locationUtf8 = NULL;
            rc = medium->vtbl->GetLocation(medium, &locationUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get medium location"));
                goto cleanup;
            }
            VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8);
            VBOX_UTF16_FREE(locationUtf16);
            if (strstr(locationUtf8, "fake") != NULL) {
                /*we delete the fake disk because we don't need it anymore*/
                IProgress *progress = NULL;
                PRInt32 resultCode = -1;
                rc = medium->vtbl->DeleteStorage(medium, &progress);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to delete medium, rc=%08x"),
                                   (unsigned)rc);
                    VIR_FREE(locationUtf8);
                    goto cleanup;
                }
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
                if (NS_FAILED(resultCode)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Error while closing medium, rc=%08x"),
                                   (unsigned)resultCode);
                    VIR_FREE(locationUtf8);
                    goto cleanup;
                }
                VBOX_RELEASE(progress);
            } else {
                /*
                 * This a comment from vboxmanage code in the handleUnregisterVM
                 * function in VBoxManageMisc.cpp :
                 * Note that the IMachine::Unregister method will return the medium
                 * reference in a sane order, which means that closing will normally
                 * succeed, unless there is still another machine which uses the
                 * medium. No harm done if we ignore the error.
                 */
                rc = medium->vtbl->Close(medium);
            }
            VBOX_UTF8_FREE(locationUtf8);
        }
    }
    /*Close all disks that failed to close normally.*/
    for (it = 0; it < snapshotMachineDesc->mediaRegistry->ndisks; it++) {
        if (vboxCloseDisksRecursively(dom, snapshotMachineDesc->mediaRegistry->disks[it]->location) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to close recursively all disks"));
            goto cleanup;
        }
    }
    /*Here, all disks are closed or deleted*/

    /*We are now going to create and fill the Snapshot xml struct*/
    if (VIR_ALLOC(newSnapshotPtr) < 0)
        goto cleanup;

    if (virUUIDGenerate(snapshotUuid) < 0)
        goto cleanup;

    char uuidtmp[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(snapshotUuid, uuidtmp);
    if (VIR_STRDUP(newSnapshotPtr->uuid, uuidtmp) < 0)
        goto cleanup;

    VIR_DEBUG("New snapshot UUID: %s", newSnapshotPtr->uuid);
    if (VIR_STRDUP(newSnapshotPtr->name, def->name) < 0)
        goto cleanup;

    newSnapshotPtr->timeStamp = virTimeStringThen(def->creationTime * 1000);

    if (VIR_STRDUP(newSnapshotPtr->description, def->description) < 0)
        goto cleanup;

    if (VIR_STRDUP(newSnapshotPtr->hardware, snapshotMachineDesc->hardware) < 0)
        goto cleanup;

    if (VIR_STRDUP(newSnapshotPtr->storageController, snapshotMachineDesc->storageController) < 0)
        goto cleanup;

    /*We get the parent disk uuid from the parent disk location to correctly fill the storage controller.*/
    for (it = 0; it < def->dom->ndisks; it++) {
        char *location = NULL;
        const char *uuidReplacing = NULL;
        char **searchResultTab = NULL;
        ssize_t resultSize = 0;
        char *tmp = NULL;

        location = def->dom->disks[it]->src->path;
        if (!location)
            goto cleanup;
        /*Replacing the uuid*/
        uuidReplacing = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, location);
        if (uuidReplacing == NULL)
            goto cleanup;

        resultSize = virStringSearch(newSnapshotPtr->storageController,
                                     VBOX_UUID_REGEX,
                                     it + 1,
                                     &searchResultTab);
        if (resultSize != it + 1)
            goto cleanup;

        tmp = virStringReplace(newSnapshotPtr->storageController,
                               searchResultTab[it],
                               uuidReplacing);
        virStringFreeList(searchResultTab);
        VIR_FREE(newSnapshotPtr->storageController);
        if (!tmp)
            goto cleanup;
        if (VIR_STRDUP(newSnapshotPtr->storageController, tmp) < 0)
            goto cleanup;

        VIR_FREE(tmp);
    }
    if (virVBoxSnapshotConfAddSnapshotToXmlMachine(newSnapshotPtr, snapshotMachineDesc, def->parent) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to add the snapshot to the machine description"));
        goto cleanup;
    }
    /*
     * We change the current snapshot only if there is no current snapshot or if the
     * snapshotFile exists, otherwise, it means that the correct current snapshot is
     * already set.
     */

    if (snapshotMachineDesc->currentSnapshot == NULL || snapshotFileExists) {
        snapshotMachineDesc->currentSnapshot = newSnapshotPtr->uuid;
        needToChangeStorageController = true;
    }

    /*
     * Open the snapshot's read-write disk's full ancestry to allow opening the
     * read-write disk itself.
     */
    for (it = 0; it < def->dom->ndisks; it++) {
        char *location = NULL;
        virVBoxSnapshotConfHardDiskPtr *hardDiskToOpen = NULL;
        size_t hardDiskToOpenSize = 0;

        location = def->dom->disks[it]->src->path;
        if (!location)
            goto cleanup;

        hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc,
                                                   &hardDiskToOpen, location);
        for (jt = hardDiskToOpenSize -1; jt >= 0; jt--) {
            IMedium *medium = NULL;
            PRUnichar *locationUtf16 = NULL;
            VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16);

            rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                 locationUtf16,
                                                 DeviceType_HardDisk,
                                                 AccessMode_ReadWrite,
                                                 false,
                                                 &medium);
            VBOX_UTF16_FREE(locationUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to open HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
        }
    }
    if (isCurrent || !needToChangeStorageController) {
        /* We don't create a differential hard disk because either the current snapshot
         * has already been defined or the snapshot to redefine is the current snapshot.
         * If the snapshot to redefine is the current snapshot, we add read-write disks in
         * the machine storage controllers.
         */
        for (it = 0; it < def->ndisks; it++) {
            IMedium *medium = NULL;
            PRUnichar *locationUtf16 = NULL;
            virVBoxSnapshotConfHardDiskPtr disk = NULL;
            PRUnichar *formatUtf16 = NULL;
            char *format = NULL;
            PRUnichar *uuidUtf16 = NULL;
            char *uuid = NULL;
            IMedium *parentDisk = NULL;
            PRUnichar *parentUuidUtf16 = NULL;
            char *parentUuid = NULL;

            VBOX_UTF8_TO_UTF16(def->disks[it].src->path, &locationUtf16);
            rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                 locationUtf16,
                                                 DeviceType_HardDisk,
                                                 AccessMode_ReadWrite,
                                                 false,
                                                 &medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to open HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
            VBOX_UTF16_FREE(locationUtf16);

            if (VIR_ALLOC(disk) < 0)
                goto cleanup;

            rc = medium->vtbl->GetFormat(medium, &formatUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get disk format"));
                VIR_FREE(disk);
                goto cleanup;
            }

            VBOX_UTF16_TO_UTF8(formatUtf16, &format);
            disk->format = format;
            VBOX_UTF16_FREE(formatUtf16);

            if (VIR_STRDUP(disk->location, def->disks[it].src->path) < 0) {
                VIR_FREE(disk);
                goto cleanup;
            }

            rc = medium->vtbl->GetId(medium, &uuidUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get disk uuid"));
                VIR_FREE(disk);
                goto cleanup;
            }
            VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
            disk->uuid  = uuid;
            VBOX_UTF16_FREE(uuidUtf16);

            rc = medium->vtbl->GetParent(medium, &parentDisk);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get disk parent"));
                VIR_FREE(disk);
                goto cleanup;
            }

            parentDisk->vtbl->GetId(parentDisk, &parentUuidUtf16);
            VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid);
            VBOX_UTF16_FREE(parentUuidUtf16);
            if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk,
                                           snapshotMachineDesc->mediaRegistry,
                                           parentUuid) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to add hard disk to the media registry"));
                VIR_FREE(disk);
                goto cleanup;
            }

            if (needToChangeStorageController) {
                /*We need to append this disk in the storage controller*/
                char **searchResultTab = NULL;
                ssize_t resultSize = 0;
                char *tmp = NULL;
                resultSize = virStringSearch(snapshotMachineDesc->storageController,
                                             VBOX_UUID_REGEX,
                                             it + 1,
                                             &searchResultTab);
                if (resultSize != it + 1) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to find UUID %s"), searchResultTab[it]);
                    goto cleanup;
                }

                tmp = virStringReplace(snapshotMachineDesc->storageController,
                                       searchResultTab[it],
                                       disk->uuid);
                virStringFreeList(searchResultTab);
                VIR_FREE(snapshotMachineDesc->storageController);
                if (!tmp)
                    goto cleanup;
                if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0)
                    goto cleanup;

                VIR_FREE(tmp);
            }
            /*Close disk*/
            rc = medium->vtbl->Close(medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to close HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
        }
    } else {
        /*Create a "fake" disk to avoid corrupting children snapshot disks.*/
        for (it = 0; it < def->dom->ndisks; it++) {
            IMedium *medium = NULL;
            PRUnichar *locationUtf16 = NULL;
            PRUnichar *parentUuidUtf16 = NULL;
            char *parentUuid = NULL;
            IMedium *newMedium = NULL;
            PRUnichar *formatUtf16 = NULL;
            PRUnichar *newLocation = NULL;
            char *newLocationUtf8 = NULL;
            PRInt32 resultCode = -1;
            virVBoxSnapshotConfHardDiskPtr disk = NULL;
            PRUnichar *uuidUtf16 = NULL;
            char *uuid = NULL;
            char *format = NULL;
            char **searchResultTab = NULL;
            ssize_t resultSize = 0;
            char *tmp = NULL;

            VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src->path, &locationUtf16);
            rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                 locationUtf16,
                                                 DeviceType_HardDisk,
                                                 AccessMode_ReadWrite,
                                                 false,
                                                 &medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to open HardDisk, rc=%08x"),
                               (unsigned)rc);
                VBOX_UTF16_FREE(locationUtf16);
                goto cleanup;
            }
            VBOX_UTF16_FREE(locationUtf16);

            rc = medium->vtbl->GetId(medium, &parentUuidUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to get hardDisk Id, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
            VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid);
            VBOX_UTF16_FREE(parentUuidUtf16);
            VBOX_UTF8_TO_UTF16("VDI", &formatUtf16);

            if (virAsprintf(&newLocationUtf8, "%sfakedisk-%d.vdi", machineLocationPath, it) < 0)
                goto cleanup;
            VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation);
            rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj,
                                                formatUtf16,
                                                newLocation,
                                                &newMedium);
            VBOX_UTF16_FREE(newLocation);
            VBOX_UTF16_FREE(formatUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to create HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }

            IProgress *progress = NULL;
# if VBOX_API_VERSION < 4003000
            medium->vtbl->CreateDiffStorage(medium, newMedium, MediumVariant_Diff, &progress);
# else
            PRUint32 tab[1];
            tab[0] =  MediumVariant_Diff;
            medium->vtbl->CreateDiffStorage(medium, newMedium, 1, tab, &progress);
# endif

            progress->vtbl->WaitForCompletion(progress, -1);
            progress->vtbl->GetResultCode(progress, &resultCode);
            if (NS_FAILED(resultCode)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Error while creating diff storage, rc=%08x"),
                               (unsigned)resultCode);
                goto cleanup;
            }
            VBOX_RELEASE(progress);
            /*
             * The differential disk is created, we add it to the media registry and the
             * machine storage controllers.
             */

            if (VIR_ALLOC(disk) < 0)
                goto cleanup;

            rc = newMedium->vtbl->GetId(newMedium, &uuidUtf16);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to get medium uuid, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
            VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
            disk->uuid = uuid;
            VBOX_UTF16_FREE(uuidUtf16);

            if (VIR_STRDUP(disk->location, newLocationUtf8) < 0)
                goto cleanup;

            rc = newMedium->vtbl->GetFormat(newMedium, &formatUtf16);
            VBOX_UTF16_TO_UTF8(formatUtf16, &format);
            disk->format = format;
            VBOX_UTF16_FREE(formatUtf16);

            if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk,
                                           snapshotMachineDesc->mediaRegistry,
                                           parentUuid) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to add hard disk to the media registry"));
                goto cleanup;
            }
            /*Adding the fake disk to the machine storage controllers*/

            resultSize = virStringSearch(snapshotMachineDesc->storageController,
                                         VBOX_UUID_REGEX,
                                         it + 1,
                                         &searchResultTab);
            if (resultSize != it + 1) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to find UUID %s"), searchResultTab[it]);
                goto cleanup;
            }

            tmp = virStringReplace(snapshotMachineDesc->storageController,
                                   searchResultTab[it],
                                   disk->uuid);
            virStringFreeList(searchResultTab);
            VIR_FREE(snapshotMachineDesc->storageController);
            if (!tmp)
                goto cleanup;
            if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0)
                goto cleanup;

            VIR_FREE(tmp);
            /*Closing the "fake" disk*/
            rc = newMedium->vtbl->Close(newMedium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to close the new medium, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
        }
        /*
         * We save the snapshot xml file to retrieve the real read-write disk during the
         * next define. This file is saved as "'machineLocation'/snapshot-'uuid'.xml"
         */
        VIR_FREE(currentSnapshotXmlFilePath);
        if (virAsprintf(&currentSnapshotXmlFilePath, "%s%s.xml", machineLocationPath, snapshotMachineDesc->currentSnapshot) < 0)
            goto cleanup;
        char *snapshotContent = virDomainSnapshotDefFormat(NULL, def, VIR_DOMAIN_XML_SECURE, 0);
        if (snapshotContent == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unable to get snapshot content"));
            goto cleanup;
        }
        if (virFileWriteStr(currentSnapshotXmlFilePath, snapshotContent, 0644) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Unable to save new snapshot xml file"));
            goto cleanup;
        }
        VIR_FREE(snapshotContent);
    }
    /*
     * All the snapshot structure manipulation is done, we close the disks we have
     * previously opened.
     */
    for (it = 0; it < def->dom->ndisks; it++) {
        char *location = def->dom->disks[it]->src->path;
        if (!location)
            goto cleanup;

        virVBoxSnapshotConfHardDiskPtr *hardDiskToOpen = NULL;
        size_t hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc,
                                                   &hardDiskToOpen, location);
        for (jt = 0; jt < hardDiskToOpenSize; jt++) {
            IMedium *medium = NULL;
            PRUnichar *locationUtf16 = NULL;
            VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16);
            rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                 locationUtf16,
                                                 DeviceType_HardDisk,
                                                 AccessMode_ReadWrite,
                                                 false,
                                                 &medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to open HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
            rc = medium->vtbl->Close(medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to close HardDisk, rc=%08x"),
                               (unsigned)rc);
                goto cleanup;
            }
            VBOX_UTF16_FREE(locationUtf16);
        }
    }

    /*Now, we rewrite the 'machineName'.vbox file to redefine the machine.*/
    if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilePath_Utf8) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to serialize the machine description"));
        goto cleanup;
    }
    rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj,
                                     settingsFilePath,
                                     &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to open Machine, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to register Machine, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    VBOX_RELEASE(machine);
    VBOX_UTF16_FREE(settingsFilePath);
    VBOX_UTF8_FREE(settingsFilePath_Utf8);
    VIR_FREE(snapshotMachineDesc);
    VIR_FREE(currentSnapshotXmlFilePath);
    VBOX_UTF16_FREE(machineNameUtf16);
    VBOX_UTF8_FREE(machineName);
    virStringFreeList(realReadOnlyDisksPath);
    virStringFreeList(realReadWriteDisksPath);
    VIR_FREE(newSnapshotPtr);
    VIR_FREE(machineLocationPath);
    VIR_FREE(nameTmpUse);
    return ret;
}
#endif

J
Jiri Denemark 已提交
4673 4674 4675
static virDomainSnapshotPtr
vboxDomainSnapshotCreateXML(virDomainPtr dom,
                            const char *xmlDesc,
4676
                            unsigned int flags)
J
Jiri Denemark 已提交
4677 4678 4679
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
4680
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
4681 4682 4683 4684 4685 4686 4687 4688
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
4689
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
4690 4691 4692 4693
    nsresult result;
#else
    PRInt32 result;
#endif
4694 4695 4696 4697
#if VBOX_API_VERSION >= 4002000
    bool isCurrent = false;
#endif

J
Jiri Denemark 已提交
4698

4699
    /* VBox has no snapshot metadata, so this flag is trivial.  */
4700 4701 4702
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
                  VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT, NULL);
4703

4704
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
4705 4706 4707
                                                data->xmlopt, -1,
                                                VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
                                                VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE)))
J
Jiri Denemark 已提交
4708 4709
        goto cleanup;

4710

4711
    vboxIIDFromUUID(&domiid, dom->uuid);
4712
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
4713
    if (NS_FAILED(rc)) {
4714 4715
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
4716 4717 4718
        goto cleanup;
    }

4719 4720 4721 4722 4723 4724 4725 4726 4727 4728
#if VBOX_API_VERSION >= 4002000
    isCurrent = flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT;
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        if (vboxSnapshotRedefine(dom, def, isCurrent) < 0)
            goto cleanup;
        ret = virGetDomainSnapshot(dom, def->name);
        goto cleanup;
    }
#endif

J
Jiri Denemark 已提交
4729 4730
    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
4731 4732
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
4733 4734 4735 4736 4737
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
4738
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
4739
    } else {
4740
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
4741
    }
4742

J
Jiri Denemark 已提交
4743 4744 4745
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
4746 4747 4748
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    if (def->description) {
        VBOX_UTF8_TO_UTF16(def->description, &description);
        if (!description) {
            virReportOOMError();
            goto cleanup;
        }
    }

    rc = console->vtbl->TakeSnapshot(console, name, description, &progress);
    if (NS_FAILED(rc) || !progress) {
4768 4769
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
4770 4771 4772 4773 4774 4775
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
4776 4777
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
4778 4779 4780 4781 4782
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
4783 4784
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
4785 4786 4787 4788 4789 4790
                  dom->name);
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, def->name);

4791
 cleanup:
J
Jiri Denemark 已提交
4792 4793 4794 4795
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
4796
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
4797
    VBOX_RELEASE(machine);
4798
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
4799 4800 4801 4802
    virDomainSnapshotDefFree(def);
    return ret;
}

4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874
#if VBOX_API_VERSION >=4002000
static
int vboxSnapshotGetReadWriteDisks(virDomainSnapshotDefPtr def,
                                    virDomainSnapshotPtr snapshot)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID domiid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IMachine *snapMachine = NULL;
    vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
    PRUint32   maxPortPerInst[StorageBus_Floppy + 1] = {};
    PRUint32   maxSlotPerPort[StorageBus_Floppy + 1] = {};
    int diskCount = 0;
    nsresult rc;
    vboxIID snapIid = VBOX_IID_INITIALIZER;
    char *snapshotUuidStr = NULL;
    size_t i = 0;

    vboxIIDFromUUID(&domiid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no domain with matching UUID"));
        goto cleanup;
    }
    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    rc = snap->vtbl->GetId(snap, &snapIid.value);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not get snapshot id"));
        goto cleanup;
    }

    VBOX_UTF16_TO_UTF8(snapIid.value, &snapshotUuidStr);
    rc = snap->vtbl->GetMachine(snap, &snapMachine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get machine"));
        goto cleanup;
    }
    def->ndisks = 0;
    rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no medium attachments"));
        goto cleanup;
    }
    /* get the number of attachments */
    for (i = 0; i < mediumAttachments.count; i++) {
        IMediumAttachment *imediumattach = mediumAttachments.items[i];
        if (imediumattach) {
            IMedium *medium = NULL;

            rc = imediumattach->vtbl->GetMedium(imediumattach, &medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cannot get medium"));
                goto cleanup;
            }
            if (medium) {
                def->ndisks++;
                VBOX_RELEASE(medium);
            }
        }
    }
    /* Allocate mem, if fails return error */
    if (VIR_ALLOC_N(def->disks, def->ndisks) < 0)
        goto cleanup;
4875 4876 4877 4878
    for (i = 0; i < def->ndisks; i++) {
        if (VIR_ALLOC(def->disks[i].src) < 0)
            goto cleanup;
    }
4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976

    if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort))
        goto cleanup;

    /* get the attachment details here */
    for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks; i++) {
        IStorageController *storageController = NULL;
        PRUnichar *storageControllerName = NULL;
        PRUint32   deviceType     = DeviceType_Null;
        PRUint32   storageBus     = StorageBus_Null;
        IMedium   *disk         = NULL;
        PRUnichar *childLocUtf16 = NULL;
        char      *childLocUtf8  = NULL;
        PRUint32   deviceInst     = 0;
        PRInt32    devicePort     = 0;
        PRInt32    deviceSlot     = 0;
        vboxArray children = VBOX_ARRAY_INITIALIZER;
        vboxArray snapshotIids = VBOX_ARRAY_INITIALIZER;
        IMediumAttachment *imediumattach = mediumAttachments.items[i];
        size_t j = 0;
        size_t k = 0;
        if (!imediumattach)
            continue;
        rc = imediumattach->vtbl->GetMedium(imediumattach, &disk);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get medium"));
            goto cleanup;
        }
        if (!disk)
            continue;
        rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get controller"));
            goto cleanup;
        }
        if (!storageControllerName) {
            VBOX_RELEASE(disk);
            continue;
        }
        rc = vboxArrayGet(&children, disk, disk->vtbl->GetChildren);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get children disk"));
            goto cleanup;
        }
        rc = vboxArrayGetWithPtrArg(&snapshotIids, disk, disk->vtbl->GetSnapshotIds, domiid.value);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get snapshot ids"));
            goto cleanup;
        }
        for (j = 0; j < children.count; ++j) {
            IMedium *child = children.items[j];
            for (k = 0; k < snapshotIids.count; ++k) {
                PRUnichar *diskSnapId = snapshotIids.items[k];
                char *diskSnapIdStr = NULL;
                VBOX_UTF16_TO_UTF8(diskSnapId, &diskSnapIdStr);
                if (STREQ(diskSnapIdStr, snapshotUuidStr)) {
                    rc = machine->vtbl->GetStorageControllerByName(machine,
                                                              storageControllerName,
                                                              &storageController);
                    VBOX_UTF16_FREE(storageControllerName);
                    if (!storageController) {
                        VBOX_RELEASE(child);
                        break;
                    }
                    rc = child->vtbl->GetLocation(child, &childLocUtf16);
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("cannot get disk location"));
                        goto cleanup;
                    }
                    VBOX_UTF16_TO_UTF8(childLocUtf16, &childLocUtf8);
                    VBOX_UTF16_FREE(childLocUtf16);
                    if (VIR_STRDUP(def->disks[diskCount].src->path, childLocUtf8) < 0) {
                        VBOX_RELEASE(child);
                        VBOX_RELEASE(storageController);
                        goto cleanup;
                    }
                    VBOX_UTF8_FREE(childLocUtf8);

                    rc = storageController->vtbl->GetBus(storageController, &storageBus);
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("cannot get storage controller bus"));
                        goto cleanup;
                    }
                    rc = imediumattach->vtbl->GetType(imediumattach, &deviceType);
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("cannot get medium attachment type"));
                        goto cleanup;
                    }
                    rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort);
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4977
                                       _("cannot get medium attachment type"));
4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005
                        goto cleanup;
                    }
                    rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot);
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("cannot get medium attachment device"));
                        goto cleanup;
                    }
                    def->disks[diskCount].src->type = VIR_STORAGE_TYPE_FILE;
                    def->disks[diskCount].name = vboxGenerateMediumName(storageBus,
                                                                        deviceInst,
                                                                        devicePort,
                                                                        deviceSlot,
                                                                        maxPortPerInst,
                                                                        maxSlotPerPort);
                }
                VBOX_UTF8_FREE(diskSnapIdStr);
            }
        }
        VBOX_RELEASE(storageController);
        VBOX_RELEASE(disk);
        diskCount++;
    }
    vboxArrayRelease(&mediumAttachments);

    ret = 0;
 cleanup:
    if (ret < 0) {
5006 5007 5008 5009 5010
        for (i = 0; i < def->ndisks; i++) {
            VIR_FREE(def->disks[i].src);
        }
        VIR_FREE(def->disks);
        def->ndisks = 0;
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083
    }
    VBOX_RELEASE(snap);
    return ret;
}

static
int vboxSnapshotGetReadOnlyDisks(virDomainSnapshotPtr snapshot,
                                    virDomainSnapshotDefPtr def)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID domiid = VBOX_IID_INITIALIZER;
    ISnapshot *snap = NULL;
    IMachine *machine = NULL;
    IMachine *snapMachine = NULL;
    IStorageController *storageController = NULL;
    IMedium   *disk         = NULL;
    nsresult rc;
    vboxIIDFromUUID(&domiid, dom->uuid);
    vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
    size_t i = 0;
    PRUint32   maxPortPerInst[StorageBus_Floppy + 1] = {};
    PRUint32   maxSlotPerPort[StorageBus_Floppy + 1] = {};
    int diskCount = 0;

    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    rc = snap->vtbl->GetMachine(snap, &snapMachine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get machine"));
        goto cleanup;
    }
    /*
     * Get READ ONLY disks
     * In the snapshot metadata, these are the disks written inside the <domain> node
    */
    rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get medium attachments"));
        goto cleanup;
    }
    /* get the number of attachments */
    for (i = 0; i < mediumAttachments.count; i++) {
        IMediumAttachment *imediumattach = mediumAttachments.items[i];
        if (imediumattach) {
            IMedium *medium = NULL;

            rc = imediumattach->vtbl->GetMedium(imediumattach, &medium);
            if (NS_FAILED(rc)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cannot get medium"));
                goto cleanup;
            }
            if (medium) {
                def->dom->ndisks++;
                VBOX_RELEASE(medium);
            }
        }
    }

    /* Allocate mem, if fails return error */
    if (VIR_ALLOC_N(def->dom->disks, def->dom->ndisks) >= 0) {
        for (i = 0; i < def->dom->ndisks; i++) {
5084 5085
            virDomainDiskDefPtr diskDef = virDomainDiskDefNew();
            if (!diskDef)
5086
                goto cleanup;
5087
            def->dom->disks[i] = diskDef;
5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197
        }
    } else {
        goto cleanup;
    }

    if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort))
        goto cleanup;

    /* get the attachment details here */
    for (i = 0; i < mediumAttachments.count && diskCount < def->dom->ndisks; i++) {
        PRUnichar *storageControllerName = NULL;
        PRUint32   deviceType     = DeviceType_Null;
        PRUint32   storageBus     = StorageBus_Null;
        PRBool     readOnly       = PR_FALSE;
        PRUnichar *mediumLocUtf16 = NULL;
        char      *mediumLocUtf8  = NULL;
        PRUint32   deviceInst     = 0;
        PRInt32    devicePort     = 0;
        PRInt32    deviceSlot     = 0;
        IMediumAttachment *imediumattach = mediumAttachments.items[i];
        if (!imediumattach)
            continue;
        rc = imediumattach->vtbl->GetMedium(imediumattach, &disk);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get medium"));
            goto cleanup;
        }
        if (!disk)
            continue;
        rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get storage controller name"));
            goto cleanup;
        }
        if (!storageControllerName)
            continue;
        rc = machine->vtbl->GetStorageControllerByName(machine,
                                                  storageControllerName,
                                                  &storageController);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get storage controller"));
            goto cleanup;
        }
        VBOX_UTF16_FREE(storageControllerName);
        if (!storageController)
            continue;
        rc = disk->vtbl->GetLocation(disk, &mediumLocUtf16);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get disk location"));
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
        VBOX_UTF16_FREE(mediumLocUtf16);
        if (VIR_STRDUP(def->dom->disks[diskCount]->src->path, mediumLocUtf8) < 0)
            goto cleanup;

        VBOX_UTF8_FREE(mediumLocUtf8);

        rc = storageController->vtbl->GetBus(storageController, &storageBus);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get storage controller bus"));
            goto cleanup;
        }
        if (storageBus == StorageBus_IDE) {
            def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE;
        } else if (storageBus == StorageBus_SATA) {
            def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA;
        } else if (storageBus == StorageBus_SCSI) {
            def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI;
        } else if (storageBus == StorageBus_Floppy) {
            def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC;
        }

        rc = imediumattach->vtbl->GetType(imediumattach, &deviceType);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get medium attachment type"));
            goto cleanup;
        }
        if (deviceType == DeviceType_HardDisk)
            def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
        else if (deviceType == DeviceType_Floppy)
            def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
        else if (deviceType == DeviceType_DVD)
            def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;

        rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get medium attachment port"));
            goto cleanup;
        }
        rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get device"));
            goto cleanup;
        }
        rc = disk->vtbl->GetReadOnly(disk, &readOnly);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot get read only attribute"));
            goto cleanup;
        }
        if (readOnly == PR_TRUE)
5198
            def->dom->disks[diskCount]->src->readonly = true;
5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221
        def->dom->disks[diskCount]->src->type = VIR_STORAGE_TYPE_FILE;
        def->dom->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
                                                                 deviceInst,
                                                                 devicePort,
                                                                 deviceSlot,
                                                                 maxPortPerInst,
                                                                 maxSlotPerPort);
        if (!def->dom->disks[diskCount]->dst) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not generate medium name for the disk "
                             "at: controller instance:%u, port:%d, slot:%d"),
                           deviceInst, devicePort, deviceSlot);
            ret = -1;
            goto cleanup;
        }
        diskCount ++;
    }
    /* cleanup on error */

    ret = 0;
 cleanup:
    if (ret < 0) {
        for (i = 0; i < def->dom->ndisks; i++)
5222
            virDomainDiskDefFree(def->dom->disks[i]);
5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233
        VIR_FREE(def->dom->disks);
        def->dom->ndisks = 0;
    }
    VBOX_RELEASE(disk);
    VBOX_RELEASE(storageController);
    vboxArrayRelease(&mediumAttachments);
    VBOX_RELEASE(snap);
    return ret;
}
#endif

J
Jiri Denemark 已提交
5234
static char *
5235 5236
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
5237 5238 5239
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
5240
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5241 5242 5243 5244 5245 5246 5247 5248 5249 5250
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    ISnapshot *parent = NULL;
    nsresult rc;
    virDomainSnapshotDefPtr def = NULL;
    PRUnichar *str16;
    char *str8;
    PRInt64 timestamp;
    PRBool online = PR_FALSE;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
5251 5252 5253 5254
#if VBOX_API_VERSION >=4002000
    PRUint32 memorySize                 = 0;
    PRUint32 CPUCount                 = 0;
#endif
J
Jiri Denemark 已提交
5255

5256 5257
    virCheckFlags(0, NULL);

5258
    vboxIIDFromUUID(&domiid, dom->uuid);
5259
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
5260
    if (NS_FAILED(rc)) {
5261 5262
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5263 5264 5265 5266 5267 5268
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

5269
    if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0)
5270
        goto cleanup;
5271 5272
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
5273

5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303
#if VBOX_API_VERSION >=4002000
    /* Register def->dom properties for them to be saved inside the snapshot XMl
     * Otherwise, there is a problem while parsing the xml
     */
    def->dom->virtType = VIR_DOMAIN_VIRT_VBOX;
    def->dom->id = dom->id;
    memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN);
    if (VIR_STRDUP(def->dom->name, dom->name) < 0)
        goto cleanup;
    machine->vtbl->GetMemorySize(machine, &memorySize);
    def->dom->mem.cur_balloon = memorySize * 1024;
    /* Currently setting memory and maxMemory as same, cause
     * the notation here seems to be inconsistent while
     * reading and while dumping xml
     */
    def->dom->mem.max_balloon = memorySize * 1024;
    if (VIR_STRDUP(def->dom->os.type, "hvm") < 0)
        goto cleanup;
    def->dom->os.arch = virArchFromHost();
    machine->vtbl->GetCPUCount(machine, &CPUCount);
    def->dom->maxvcpus = def->dom->vcpus = CPUCount;
    if (vboxSnapshotGetReadWriteDisks(def, snapshot) < 0) {
        VIR_DEBUG("Could not get read write disks for snapshot");
    }

    if (vboxSnapshotGetReadOnlyDisks(snapshot, def) < 0) {
        VIR_DEBUG("Could not get Readonly disks for snapshot");
    }
#endif /* VBOX_API_VERSION >= 4002000 */

J
Jiri Denemark 已提交
5304 5305
    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
5306 5307 5308
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
5309 5310 5311 5312 5313
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
5314 5315 5316 5317
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
5318 5319 5320 5321 5322
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
5323 5324 5325
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
5326 5327 5328 5329 5330 5331 5332
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
5333 5334 5335
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
5336 5337 5338 5339 5340
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
5341 5342 5343
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
5344 5345 5346 5347
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
5348 5349
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
5350
            goto cleanup;
5351 5352
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
5353 5354 5355 5356
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
5357 5358 5359
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
5360 5361 5362 5363 5364 5365 5366 5367
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

    virUUIDFormat(dom->uuid, uuidstr);
5368
    memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN);
5369
    ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
J
Jiri Denemark 已提交
5370

5371
 cleanup:
J
Jiri Denemark 已提交
5372 5373 5374 5375
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
5376
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
5377 5378 5379 5380 5381
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
5382
                      unsigned int flags)
J
Jiri Denemark 已提交
5383 5384
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5385
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5386 5387 5388 5389
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

5390 5391
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
5392

5393
    vboxIIDFromUUID(&iid, dom->uuid);
5394
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
5395
    if (NS_FAILED(rc)) {
5396 5397
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5398 5399 5400
        goto cleanup;
    }

5401 5402 5403 5404 5405 5406
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
5407 5408
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
5409 5410 5411
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5412 5413 5414
        goto cleanup;
    }

5415 5416 5417 5418 5419
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
5420

5421
 cleanup:
J
Jiri Denemark 已提交
5422
    VBOX_RELEASE(machine);
5423
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
5424 5425 5426 5427 5428 5429 5430
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
5431
                            unsigned int flags)
J
Jiri Denemark 已提交
5432 5433
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5434
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5435 5436 5437 5438
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
5439
    size_t i;
J
Jiri Denemark 已提交
5440

5441 5442
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
5443

5444
    vboxIIDFromUUID(&iid, dom->uuid);
5445
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
5446
    if (NS_FAILED(rc)) {
5447 5448
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5449 5450 5451
        goto cleanup;
    }

5452 5453 5454 5455 5456
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

5457 5458 5459
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

5460
        if (VIR_ALLOC_N(snapshots, 1) < 0)
5461
            goto cleanup;
5462
#if VBOX_API_VERSION < 4000000
5463
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
5464
#else /* VBOX_API_VERSION >= 4000000 */
5465
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
5466
#endif /* VBOX_API_VERSION >= 4000000 */
5467
        if (NS_FAILED(rc) || !snapshots[0]) {
5468 5469 5470
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
5471 5472 5473 5474 5475 5476 5477
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
5478 5479 5480 5481 5482 5483 5484 5485 5486 5487

    for (i = 0; i < nameslen; i++) {
        PRUnichar *nameUtf16;
        char *name;

        if (i >= count)
            break;

        rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16);
        if (NS_FAILED(rc) || !nameUtf16) {
5488 5489
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5490 5491 5492 5493
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
5494 5495
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
5496 5497
            goto cleanup;
        }
5498
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
5499 5500 5501 5502 5503 5504 5505
    }

    if (count <= nameslen)
        ret = count;
    else
        ret = nameslen;

5506
 cleanup:
J
Jiri Denemark 已提交
5507 5508 5509 5510 5511 5512
    if (count > 0) {
        for (i = 0; i < count; i++)
            VBOX_RELEASE(snapshots[i]);
    }
    VIR_FREE(snapshots);
    VBOX_RELEASE(machine);
5513
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
5514 5515 5516 5517 5518 5519
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
5520
                               unsigned int flags)
J
Jiri Denemark 已提交
5521 5522
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
5523
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5524 5525 5526 5527
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

5528 5529
    virCheckFlags(0, NULL);

5530
    vboxIIDFromUUID(&iid, dom->uuid);
5531
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
5532
    if (NS_FAILED(rc)) {
5533 5534
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5535 5536 5537 5538 5539 5540 5541 5542
        goto cleanup;
    }

    if (!(snapshot = vboxDomainSnapshotGet(data, dom, machine, name)))
        goto cleanup;

    ret = virGetDomainSnapshot(dom, name);

5543
 cleanup:
J
Jiri Denemark 已提交
5544 5545
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
5546
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
5547 5548 5549 5550 5551
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
5552
                             unsigned int flags)
J
Jiri Denemark 已提交
5553 5554
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5555
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5556 5557 5558 5559
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

5560 5561
    virCheckFlags(0, -1);

5562
    vboxIIDFromUUID(&iid, dom->uuid);
5563
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5564
    if (NS_FAILED(rc)) {
5565 5566
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5567 5568 5569 5570 5571
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
5572 5573
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
5574 5575 5576 5577 5578 5579 5580 5581
        goto cleanup;
    }

    if (snapshot)
        ret = 1;
    else
        ret = 0;

5582
 cleanup:
J
Jiri Denemark 已提交
5583
    VBOX_RELEASE(machine);
5584
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
5585 5586 5587
    return ret;
}

5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606
static virDomainSnapshotPtr
vboxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    ISnapshot *parent = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

    virCheckFlags(0, NULL);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5607 5608
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
5609 5610 5611 5612 5613 5614 5615 5616
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
5617 5618 5619
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
5620 5621 5622
        goto cleanup;
    }
    if (!parent) {
5623 5624 5625
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
5626 5627 5628 5629 5630
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
5631 5632 5633
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
5634 5635 5636 5637 5638 5639 5640 5641 5642 5643
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

5644
 cleanup:
5645 5646 5647 5648 5649 5650 5651 5652 5653
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

J
Jiri Denemark 已提交
5654 5655
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
5656
                          unsigned int flags)
J
Jiri Denemark 已提交
5657 5658
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
5659
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5660 5661 5662 5663 5664 5665
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

5666 5667
    virCheckFlags(0, NULL);

5668
    vboxIIDFromUUID(&iid, dom->uuid);
5669
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5670
    if (NS_FAILED(rc)) {
5671 5672
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5673 5674 5675 5676 5677
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
5678 5679
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
5680 5681 5682 5683
        goto cleanup;
    }

    if (!snapshot) {
5684 5685
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
5686 5687 5688 5689 5690
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
5691 5692
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703
        goto cleanup;
    }

    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

5704
 cleanup:
J
Jiri Denemark 已提交
5705 5706 5707 5708
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
5709
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
5710 5711 5712
    return ret;
}

5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731
static int
vboxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    ISnapshot *current = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5732 5733
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
5734 5735 5736 5737 5738 5739 5740 5741
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
5742 5743
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
5744 5745 5746 5747 5748 5749 5750 5751 5752
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
5753 5754
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765
        goto cleanup;
    }

    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = STREQ(snapshot->name, name);

5766
 cleanup:
5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(current);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

static int
vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    nsresult rc;

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5792 5793
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
5794 5795 5796 5797 5798 5799 5800 5801 5802
        goto cleanup;
    }

    /* Check that snapshot exists.  If so, there is no metadata.  */
    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    ret = 0;

5803
 cleanup:
5804 5805 5806 5807 5808 5809
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

5810
#if VBOX_API_VERSION < 3001000
J
Jiri Denemark 已提交
5811 5812 5813 5814 5815 5816
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5817
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5818 5819
    nsresult rc;

5820 5821
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
5822 5823
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
5824 5825 5826
        goto cleanup;
    }

5827
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
5828
    if (NS_FAILED(rc)) {
5829 5830
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
5831 5832 5833 5834 5835
        goto cleanup;
    }

    ret = 0;

5836
 cleanup:
5837
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851
    return ret;
}
#else
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    IConsole *console = NULL;
    IProgress *progress = NULL;
    PRUint32 state;
    nsresult rc;
    PRInt32 result;
5852
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5853

5854 5855
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
5856 5857
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
5858 5859 5860 5861 5862
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
5863 5864
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
5865 5866 5867 5868 5869
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
5870 5871
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
5872 5873 5874
        goto cleanup;
    }

5875
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
5876 5877 5878
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
5879 5880 5881
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5882 5883 5884 5885 5886 5887
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
5888 5889
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
5890
        } else {
5891 5892 5893
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
5894 5895 5896 5897 5898 5899 5900
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
5901 5902
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
5903 5904 5905 5906 5907
        goto cleanup;
    }

    ret = 0;

5908
 cleanup:
J
Jiri Denemark 已提交
5909 5910
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
5911
    VBOX_SESSION_CLOSE();
5912
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
5913 5914 5915 5916 5917 5918
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
5919
                           unsigned int flags)
J
Jiri Denemark 已提交
5920 5921 5922
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5923
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5924 5925 5926 5927 5928 5929 5930
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

5931 5932
    virCheckFlags(0, -1);

5933
    vboxIIDFromUUID(&domiid, dom->uuid);
5934
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
5935
    if (NS_FAILED(rc)) {
5936 5937
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5938 5939 5940 5941 5942 5943 5944 5945 5946
        goto cleanup;
    }

    newSnapshot = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
    if (!newSnapshot)
        goto cleanup;

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
5947 5948 5949
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
5950 5951 5952 5953 5954
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
5955 5956 5957
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5958 5959 5960 5961 5962
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
5963 5964
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
5965 5966 5967 5968 5969
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
5970 5971
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984
        goto cleanup;
    }

    if (vboxDomainSnapshotRestore(dom, machine, newSnapshot))
        goto cleanup;

    if (online) {
        ret = vboxDomainCreate(dom);
        if (!ret)
            vboxDomainSnapshotRestore(dom, machine, prevSnapshot);
    } else
        ret = 0;

5985
 cleanup:
J
Jiri Denemark 已提交
5986 5987
    VBOX_RELEASE(prevSnapshot);
    VBOX_RELEASE(newSnapshot);
5988
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
5989 5990 5991 5992 5993 5994 5995 5996 5997
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
5998
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5999 6000
    int ret = -1;
    nsresult rc;
6001
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
6002 6003 6004 6005 6006
    nsresult result;
#else
    PRInt32 result;
#endif

6007 6008
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6009 6010
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6011 6012 6013
        goto cleanup;
    }

6014
#if VBOX_API_VERSION < 3001000
6015
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6016
#else
6017
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6018 6019 6020
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6021 6022
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
6023
        } else {
6024 6025
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
6026 6027 6028 6029 6030 6031 6032
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6033 6034
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
6035 6036 6037 6038 6039
        goto cleanup;
    }

    ret = 0;

6040
 cleanup:
J
Jiri Denemark 已提交
6041
    VBOX_RELEASE(progress);
6042
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6043 6044 6045 6046 6047 6048 6049 6050
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
6051
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
6052 6053
    int ret = -1;
    nsresult rc;
6054
    size_t i;
J
Jiri Denemark 已提交
6055

6056
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
6057
    if (NS_FAILED(rc)) {
6058 6059
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
6060 6061 6062
        goto cleanup;
    }

6063 6064 6065
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
6066 6067 6068 6069
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

6070
 cleanup:
6071
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
6072 6073 6074
    return ret;
}

6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094
#if VBOX_API_VERSION >= 4002000
static int
vboxDomainSnapshotDeleteMetadataOnly(virDomainSnapshotPtr snapshot)
{
    /*
     * This function will remove the node in the vbox xml corresponding to the snapshot.
     * It is usually called by vboxDomainSnapshotDelete() with the flag
     * VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY.
     * If you want to use it anywhere else, be careful, if the snapshot you want to delete
     * has children, the result is not granted, they will probably will be deleted in the
     * xml, but you may have a problem with hard drives.
     *
     * If the snapshot which is being deleted is the current one, we will set the current
     * snapshot of the machine to the parent of this snapshot. Before writing the modified
     * xml file, we undefine the machine from vbox. After writing the file, we redefine
     * the machine with the new file.
     */

    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6095
    virDomainSnapshotDefPtr def = NULL;
6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110
    char *defXml = NULL;
    vboxIID domiid = VBOX_IID_INITIALIZER;
    nsresult rc;
    IMachine *machine = NULL;
    PRUnichar *settingsFilePathUtf16 = NULL;
    char *settingsFilepath = NULL;
    virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL;
    int isCurrent = -1;
    int it = 0;
    PRUnichar *machineNameUtf16 = NULL;
    char *machineName = NULL;
    char *nameTmpUse = NULL;
    char *machineLocationPath = NULL;
    PRUint32 aMediaSize = 0;
    IMedium **aMedia = NULL;
6111

6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286
    defXml = vboxDomainSnapshotGetXMLDesc(snapshot, 0);
    if (!defXml) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to get XML Desc of snapshot"));
        goto cleanup;
    }
    def = virDomainSnapshotDefParseString(defXml,
                                          data->caps,
                                          data->xmlopt,
                                          -1,
                                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
                                          VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
    if (!def) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to get a virDomainSnapshotDefPtr"));
        goto cleanup;
    }

    vboxIIDFromUUID(&domiid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
        goto cleanup;
    }
    rc = machine->vtbl->GetSettingsFilePath(machine, &settingsFilePathUtf16);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get settings file path"));
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(settingsFilePathUtf16, &settingsFilepath);

    /*Getting the machine name to retrieve the machine location path.*/
    rc = machine->vtbl->GetName(machine, &machineNameUtf16);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get machine name"));
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
    if (virAsprintf(&nameTmpUse, "%s.vbox", machineName) < 0)
        goto cleanup;
    machineLocationPath = virStringReplace(settingsFilepath, nameTmpUse, "");
    if (machineLocationPath == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to get the machine location path"));
        goto cleanup;
    }
    snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilepath, machineLocationPath);
    if (!snapshotMachineDesc) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot create a vboxSnapshotXmlPtr"));
        goto cleanup;
    }

    isCurrent = virVBoxSnapshotConfIsCurrentSnapshot(snapshotMachineDesc, def->name);
    if (isCurrent < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to know if the snapshot is the current snapshot"));
        goto cleanup;
    }
    if (isCurrent) {
        /*
         * If the snapshot is the current snapshot, it means that the machine has read-write
         * disks. The first thing to do is to manipulate VirtualBox API to create
         * differential read-write disks if the parent snapshot is not null.
         */
        if (def->parent != NULL) {
            for (it = 0; it < def->dom->ndisks; it++) {
                virVBoxSnapshotConfHardDiskPtr readOnly = NULL;
                IMedium *medium = NULL;
                PRUnichar *locationUtf16 = NULL;
                PRUnichar *parentUuidUtf16 = NULL;
                char *parentUuid = NULL;
                IMedium *newMedium = NULL;
                PRUnichar *formatUtf16 = NULL;
                PRUnichar *newLocation = NULL;
                char *newLocationUtf8 = NULL;
                IProgress *progress = NULL;
                PRInt32 resultCode = -1;
                virVBoxSnapshotConfHardDiskPtr disk = NULL;
                PRUnichar *uuidUtf16 = NULL;
                char *uuid = NULL;
                char *format = NULL;
                char **searchResultTab = NULL;
                ssize_t resultSize = 0;
                char *tmp = NULL;

                readOnly = virVBoxSnapshotConfHardDiskPtrByLocation(snapshotMachineDesc,
                                                 def->dom->disks[it]->src->path);
                if (!readOnly) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("Cannot get hard disk by location"));
                    goto cleanup;
                }
                if (readOnly->parent == NULL) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("The read only disk has no parent"));
                    goto cleanup;
                }

                VBOX_UTF8_TO_UTF16(readOnly->parent->location, &locationUtf16);
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     locationUtf16,
                                                     DeviceType_HardDisk,
                                                     AccessMode_ReadWrite,
                                                     false,
                                                     &medium);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to open HardDisk, rc=%08x"),
                                   (unsigned)rc);
                    goto cleanup;
                }

                rc = medium->vtbl->GetId(medium, &parentUuidUtf16);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to get hardDisk Id, rc=%08x"),
                                   (unsigned)rc);
                    goto cleanup;
                }
                VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid);
                VBOX_UTF16_FREE(parentUuidUtf16);
                VBOX_UTF16_FREE(locationUtf16);
                VBOX_UTF8_TO_UTF16("VDI", &formatUtf16);

                if (virAsprintf(&newLocationUtf8, "%sfakedisk-%s-%d.vdi",
                                machineLocationPath, def->parent, it) < 0)
                    goto cleanup;
                VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation);
                rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj,
                                                         formatUtf16,
                                                         newLocation,
                                                         &newMedium);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to create HardDisk, rc=%08x"),
                                   (unsigned)rc);
                    goto cleanup;
                }
                VBOX_UTF16_FREE(formatUtf16);
                VBOX_UTF16_FREE(newLocation);

# if VBOX_API_VERSION < 4003000
                medium->vtbl->CreateDiffStorage(medium, newMedium, MediumVariant_Diff, &progress);
# else
                PRUint32 tab[1];
                tab[0] =  MediumVariant_Diff;
                medium->vtbl->CreateDiffStorage(medium, newMedium, 1, tab, &progress);
# endif

                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
                if (NS_FAILED(resultCode)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Error while creating diff storage, rc=%08x"),
                                   (unsigned)resultCode);
                    goto cleanup;
                }
                VBOX_RELEASE(progress);
                /*
                 * The differential disk is created, we add it to the media registry and
                 * the machine storage controller.
                 */

                if (VIR_ALLOC(disk) < 0)
                    goto cleanup;

                rc = newMedium->vtbl->GetId(newMedium, &uuidUtf16);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to get medium uuid, rc=%08x"),
                                   (unsigned)rc);
6287
                    VIR_FREE(disk);
6288 6289 6290 6291 6292 6293
                    goto cleanup;
                }
                VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
                disk->uuid = uuid;
                VBOX_UTF16_FREE(uuidUtf16);

6294 6295
                if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) {
                    VIR_FREE(disk);
6296
                    goto cleanup;
6297
                }
6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529

                rc = newMedium->vtbl->GetFormat(newMedium, &formatUtf16);
                VBOX_UTF16_TO_UTF8(formatUtf16, &format);
                disk->format = format;
                VBOX_UTF16_FREE(formatUtf16);

                if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk,
                                               snapshotMachineDesc->mediaRegistry,
                                               parentUuid) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("Unable to add hard disk to the media registry"));
                    goto cleanup;
                }
                /*Adding fake disks to the machine storage controllers*/

                resultSize = virStringSearch(snapshotMachineDesc->storageController,
                                             VBOX_UUID_REGEX,
                                             it + 1,
                                             &searchResultTab);
                if (resultSize != it + 1) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to find UUID %s"), searchResultTab[it]);
                    goto cleanup;
                }

                tmp = virStringReplace(snapshotMachineDesc->storageController,
                                       searchResultTab[it],
                                       disk->uuid);
                virStringFreeList(searchResultTab);
                VIR_FREE(snapshotMachineDesc->storageController);
                if (!tmp)
                    goto cleanup;
                if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0)
                    goto cleanup;

                VIR_FREE(tmp);
                /*Closing the "fake" disk*/
                rc = newMedium->vtbl->Close(newMedium);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to close the new medium, rc=%08x"),
                                   (unsigned)rc);
                    goto cleanup;
                }
            }
        } else {
            for (it = 0; it < def->dom->ndisks; it++) {
                const char *uuidRO = NULL;
                char **searchResultTab = NULL;
                ssize_t resultSize = 0;
                char *tmp = NULL;
                uuidRO = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
                                                      def->dom->disks[it]->src->path);
                if (!uuidRO) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("No such disk in media registry %s"),
                                   def->dom->disks[it]->src->path);
                    goto cleanup;
                }

                resultSize = virStringSearch(snapshotMachineDesc->storageController,
                                             VBOX_UUID_REGEX,
                                             it + 1,
                                             &searchResultTab);
                if (resultSize != it + 1) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to find UUID %s"),
                                   searchResultTab[it]);
                    goto cleanup;
                }

                tmp = virStringReplace(snapshotMachineDesc->storageController,
                                       searchResultTab[it],
                                       uuidRO);
                virStringFreeList(searchResultTab);
                VIR_FREE(snapshotMachineDesc->storageController);
                if (!tmp)
                    goto cleanup;
                if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0)
                    goto cleanup;

                VIR_FREE(tmp);
            }
        }
    }
    /*We remove the read write disks from the media registry*/
    for (it = 0; it < def->ndisks; it++) {
        const char *uuidRW =
            virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
                                                      def->disks[it].src->path);
        if (!uuidRW) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find UUID for location %s"), def->disks[it].src->path);
            goto cleanup;
        }
        if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRW) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to remove disk from media registry. uuid = %s"), uuidRW);
            goto cleanup;
        }
    }
    /*If the parent snapshot is not NULL, we remove the-read only disks from the media registry*/
    if (def->parent != NULL) {
        for (it = 0; it < def->dom->ndisks; it++) {
            const char *uuidRO =
                virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
                                                          def->dom->disks[it]->src->path);
            if (!uuidRO) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to find UUID for location %s"), def->dom->disks[it]->src->path);
                goto cleanup;
            }
            if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRO) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to remove disk from media registry. uuid = %s"), uuidRO);
                goto cleanup;
            }
        }
    }
    rc = machine->vtbl->Unregister(machine,
                              CleanupMode_DetachAllReturnHardDisksOnly,
                              &aMediaSize,
                              &aMedia);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to unregister machine, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }
    VBOX_RELEASE(machine);
    for (it = 0; it < aMediaSize; it++) {
        IMedium *medium = aMedia[it];
        if (medium) {
            PRUnichar *locationUtf16 = NULL;
            char *locationUtf8 = NULL;
            rc = medium->vtbl->GetLocation(medium, &locationUtf16);
            VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8);
            if (isCurrent && strstr(locationUtf8, "fake") != NULL) {
                /*we delete the fake disk because we don't need it anymore*/
                IProgress *progress = NULL;
                PRInt32 resultCode = -1;
                rc = medium->vtbl->DeleteStorage(medium, &progress);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to delete medium, rc=%08x"),
                                   (unsigned)rc);
                    goto cleanup;
                }
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
                if (NS_FAILED(resultCode)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Error while closing medium, rc=%08x"),
                                   (unsigned)resultCode);
                    goto cleanup;
                }
                VBOX_RELEASE(progress);
            } else {
                /* This a comment from vboxmanage code in the handleUnregisterVM
                 * function in VBoxManageMisc.cpp :
                 * Note that the IMachine::Unregister method will return the medium
                 * reference in a sane order, which means that closing will normally
                 * succeed, unless there is still another machine which uses the
                 * medium. No harm done if we ignore the error. */
                rc = medium->vtbl->Close(medium);
            }
            VBOX_UTF16_FREE(locationUtf16);
            VBOX_UTF8_FREE(locationUtf8);
        }
    }

    /*removing the snapshot*/
    if (virVBoxSnapshotConfRemoveSnapshot(snapshotMachineDesc, def->name) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to remove snapshot %s"), def->name);
        goto cleanup;
    }

    if (isCurrent) {
        VIR_FREE(snapshotMachineDesc->currentSnapshot);
        if (def->parent != NULL) {
            virVBoxSnapshotConfSnapshotPtr snap = virVBoxSnapshotConfSnapshotByName(snapshotMachineDesc->snapshot, def->parent);
            if (!snap) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to get the snapshot to remove"));
                goto cleanup;
            }
            if (VIR_STRDUP(snapshotMachineDesc->currentSnapshot, snap->uuid) < 0)
                goto cleanup;
        }
    }

    /*Registering the machine*/
    if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilepath) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to serialize the machine description"));
        goto cleanup;
    }
    rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj,
                                     settingsFilePathUtf16,
                                     &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to open Machine, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to register Machine, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    VIR_FREE(def);
    VIR_FREE(defXml);
    VBOX_RELEASE(machine);
    VBOX_UTF16_FREE(settingsFilePathUtf16);
    VBOX_UTF8_FREE(settingsFilepath);
    VIR_FREE(snapshotMachineDesc);
    VBOX_UTF16_FREE(machineNameUtf16);
    VBOX_UTF8_FREE(machineName);
    VIR_FREE(machineLocationPath);
    VIR_FREE(nameTmpUse);

    return ret;
}
#endif
6530

J
Jiri Denemark 已提交
6531 6532 6533 6534 6535 6536
static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6537
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6538 6539 6540 6541 6542
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;
6543
    vboxArray snapChildren = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
6544

6545 6546
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
6547

6548
    vboxIIDFromUUID(&domiid, dom->uuid);
6549
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6550
    if (NS_FAILED(rc)) {
6551 6552
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6553 6554 6555 6556 6557 6558 6559 6560 6561
        goto cleanup;
    }

    snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
    if (!snap)
        goto cleanup;

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6562 6563
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6564 6565 6566
        goto cleanup;
    }

6567 6568 6569
    /* In case we just want to delete the metadata, we will edit the vbox file in order
     *to remove the node concerning the snapshot
    */
6570
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585
        rc = vboxArrayGet(&snapChildren, snap, snap->vtbl->GetChildren);
        if (NS_FAILED(rc)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not get snapshot children"));
            goto cleanup;
        }
        if (snapChildren.count != 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot delete metadata of a snapshot with children"));
            goto cleanup;
        } else {
#if VBOX_API_VERSION >= 4002000
            ret = vboxDomainSnapshotDeleteMetadataOnly(snapshot);
#endif
        }
6586 6587 6588
        goto cleanup;
    }

J
Jiri Denemark 已提交
6589 6590
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6591 6592
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
6593 6594 6595
        goto cleanup;
    }

6596
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6597 6598 6599
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6600 6601 6602
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6603 6604 6605 6606 6607 6608 6609 6610
        goto cleanup;
    }

    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
        ret = vboxDomainSnapshotDeleteTree(data, console, snap);
    else
        ret = vboxDomainSnapshotDeleteSingle(data, console, snap);

6611
 cleanup:
J
Jiri Denemark 已提交
6612 6613
    VBOX_RELEASE(console);
    VBOX_RELEASE(snap);
6614
    vboxIIDUnalloc(&domiid);
6615
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6616 6617 6618
    return ret;
}

6619
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
6620
    /* No Callback support for VirtualBox 2.2.* series */
6621
    /* No Callback support for VirtualBox 4.* series */
6622
#else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
6623 6624

/* Functions needed for Callbacks */
6625
static nsresult PR_COM_METHOD
6626
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6627 6628
                                 PRUnichar *machineId, PRUint32 state)
{
6629 6630 6631 6632 6633 6634
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

6635
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
6636 6637 6638 6639 6640 6641 6642
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
6643
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
6644 6645 6646

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
6647
            virObjectEventPtr ev;
6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677

            if (state == MachineState_Starting) {
                event  = VIR_DOMAIN_EVENT_STARTED;
                detail = VIR_DOMAIN_EVENT_STARTED_BOOTED;
            } else if (state == MachineState_Restoring) {
                event  = VIR_DOMAIN_EVENT_STARTED;
                detail = VIR_DOMAIN_EVENT_STARTED_RESTORED;
            } else if (state == MachineState_Paused) {
                event  = VIR_DOMAIN_EVENT_SUSPENDED;
                detail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
            } else if (state == MachineState_Running) {
                event  = VIR_DOMAIN_EVENT_RESUMED;
                detail = VIR_DOMAIN_EVENT_RESUMED_UNPAUSED;
            } else if (state == MachineState_PoweredOff) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
            } else if (state == MachineState_Stopping) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_DESTROYED;
            } else if (state == MachineState_Aborted) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_CRASHED;
            } else if (state == MachineState_Saving) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SAVED;
            } else {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
            }

6678
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
6679

6680
            if (ev)
6681
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
6682 6683 6684 6685 6686 6687 6688 6689
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

6690
static nsresult PR_COM_METHOD
6691
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6692 6693
                                PRUnichar *machineId)
{
6694
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6695 6696 6697 6698 6699
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

6700
static nsresult PR_COM_METHOD
6701
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6702 6703 6704
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
6705
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
6706
{
6707
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
6708 6709 6710 6711 6712 6713 6714
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

6715
static nsresult PR_COM_METHOD
6716 6717
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
6718 6719
                              PRUnichar *key, PRUnichar *value)
{
6720
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6721 6722 6723 6724 6725 6726 6727
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

6728
# if VBOX_API_VERSION < 3001000
6729
static nsresult PR_COM_METHOD
6730 6731 6732 6733
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
6734
{
6735 6736
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
6737 6738 6739 6740
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
6741 6742
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
6743

6744
static nsresult PR_COM_METHOD
6745
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6746 6747
                                PRUnichar *machineId, PRBool registered)
{
6748 6749 6750 6751 6752 6753
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

6754
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
6755 6756 6757 6758 6759 6760 6761
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
6762
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
6763 6764 6765

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
6766
            virObjectEventPtr ev;
6767 6768

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
6769
             * event because the when the machine is de-registered the call
6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781
             * to vboxDomainLookupByUUID fails and thus we don't get any
             * dom pointer which is necessary (null dom pointer doesn't work)
             * to show the VIR_DOMAIN_EVENT_UNDEFINED event
             */
            if (registered) {
                event  = VIR_DOMAIN_EVENT_DEFINED;
                detail = VIR_DOMAIN_EVENT_DEFINED_ADDED;
            } else {
                event  = VIR_DOMAIN_EVENT_UNDEFINED;
                detail = VIR_DOMAIN_EVENT_UNDEFINED_REMOVED;
            }

6782
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
6783

6784
            if (ev)
6785
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
6786 6787 6788 6789 6790 6791 6792 6793
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

6794
static nsresult PR_COM_METHOD
6795 6796 6797
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
6798
{
6799
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
6800 6801 6802 6803 6804
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

6805
static nsresult PR_COM_METHOD
6806 6807
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
6808 6809
                            PRUnichar *snapshotId)
{
6810
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6811 6812 6813 6814 6815 6816
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

6817
static nsresult PR_COM_METHOD
6818 6819
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
6820 6821
                                PRUnichar *snapshotId)
{
6822
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6823 6824 6825 6826 6827 6828
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

6829
static nsresult PR_COM_METHOD
6830 6831
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
6832 6833
                             PRUnichar *snapshotId)
{
6834
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6835 6836 6837 6838 6839 6840
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

6841
static nsresult PR_COM_METHOD
6842
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6843 6844 6845
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
6846
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6847 6848 6849 6850 6851 6852 6853 6854
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

6855
static nsresult PR_COM_METHOD
6856
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
6857
{
6858 6859 6860 6861
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

6862
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
6863 6864 6865 6866

    return c;
}

6867 6868 6869
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
6870 6871 6872 6873 6874 6875 6876 6877 6878
    nsresult c;

    c = --g_pVBoxGlobalData->vboxCallBackRefCount;
    if (c == 0) {
        /* delete object */
        VIR_FREE(pThis->vtbl);
        VIR_FREE(pThis);
    }

6879
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
6880 6881 6882 6883

    return c;
}

6884 6885 6886
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
6887 6888 6889 6890 6891
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
6892 6893
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
6894 6895 6896
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

6897
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
6898 6899 6900 6901 6902

        return NS_OK;
    }


6903
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
6904 6905 6906 6907 6908 6909
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


6910
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
6911 6912
    IVirtualBoxCallback *vboxCallback = NULL;

6913
    /* Allocate, Initialize and return a valid
6914 6915 6916
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
6917
        VIR_FREE(vboxCallback);
6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928
        return NULL;
    }

    {
        vboxCallback->vtbl->nsisupports.AddRef          = &vboxCallbackAddRef;
        vboxCallback->vtbl->nsisupports.Release         = &vboxCallbackRelease;
        vboxCallback->vtbl->nsisupports.QueryInterface  = &vboxCallbackQueryInterface;
        vboxCallback->vtbl->OnMachineStateChange        = &vboxCallbackOnMachineStateChange;
        vboxCallback->vtbl->OnMachineDataChange         = &vboxCallbackOnMachineDataChange;
        vboxCallback->vtbl->OnExtraDataCanChange        = &vboxCallbackOnExtraDataCanChange;
        vboxCallback->vtbl->OnExtraDataChange           = &vboxCallbackOnExtraDataChange;
6929
# if VBOX_API_VERSION < 3001000
6930
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
6931 6932
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
6933 6934 6935
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
6936
# if VBOX_API_VERSION < 3002000
6937
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
6938
# else /* VBOX_API_VERSION >= 3002000 */
6939
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
6940
# endif /* VBOX_API_VERSION >= 3002000 */
6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952
        vboxCallback->vtbl->OnSnapshotChange            = &vboxCallbackOnSnapshotChange;
        vboxCallback->vtbl->OnGuestPropertyChange       = &vboxCallbackOnGuestPropertyChange;
        g_pVBoxGlobalData->vboxCallBackRefCount = 1;

    }

    return vboxCallback;
}

static void vboxReadCallback(int watch ATTRIBUTE_UNUSED,
                             int fd,
                             int events ATTRIBUTE_UNUSED,
6953 6954
                             void *opaque ATTRIBUTE_UNUSED)
{
6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966
    if (fd >= 0) {
        g_pVBoxGlobalData->vboxQueue->vtbl->ProcessPendingEvents(g_pVBoxGlobalData->vboxQueue);
    } else {
        nsresult rc;
        PLEvent *pEvent = NULL;

        rc = g_pVBoxGlobalData->vboxQueue->vtbl->WaitForEvent(g_pVBoxGlobalData->vboxQueue, &pEvent);
        if (NS_SUCCEEDED(rc))
            g_pVBoxGlobalData->vboxQueue->vtbl->HandleEvent(g_pVBoxGlobalData->vboxQueue, pEvent);
    }
}

6967 6968 6969 6970 6971 6972
static int
vboxConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
{
6973
    VBOX_OBJECT_CHECK(conn, int, -1);
6974
    int vboxRet          = -1;
6975
    nsresult rc;
6976 6977 6978 6979 6980 6981

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

6982
    if (data->vboxCallback == NULL) {
6983
        data->vboxCallback = vboxAllocCallbackObj();
6984 6985 6986 6987
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
6988 6989
            }
        }
6990 6991 6992
    } else {
        vboxRet = 0;
    }
6993

6994 6995 6996 6997 6998 6999 7000
    /* Get the vbox file handle and add a event handle to it
     * so that the events can be passed down to the user
     */
    if (vboxRet == 0) {
        if (data->fdWatch < 0) {
            PRInt32 vboxFileHandle;
            vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);
7001

7002 7003
            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }
7004

7005 7006 7007 7008 7009
        if (data->fdWatch >= 0) {
            /* Once a callback is registered with virtualbox, use a list
             * to store the callbacks registered with libvirt so that
             * later you can iterate over them
             */
7010

7011
            ret = virDomainEventStateRegister(conn, data->domainEvents,
7012
                                              callback, opaque, freecb);
7013
            VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
7014
                      "callback: %p, opaque: %p, "
7015
                      "freecb: %p)", ret, conn, callback,
7016
                      opaque, freecb);
7017 7018 7019 7020 7021 7022
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
7023
        return 0;
7024 7025 7026 7027 7028 7029 7030 7031
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7032 7033 7034 7035
static int
vboxConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
{
7036
    VBOX_OBJECT_CHECK(conn, int, -1);
7037
    int cnt;
7038 7039 7040 7041 7042 7043

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7044 7045
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
7046

7047 7048 7049
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7050

7051 7052 7053
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7054 7055 7056 7057
    }

    vboxDriverUnlock(data);

7058 7059 7060
    if (cnt >= 0)
        ret = 0;

7061 7062 7063
    return ret;
}

7064 7065 7066 7067 7068
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
7069 7070
                                             virFreeCallback freecb)
{
7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108
    VBOX_OBJECT_CHECK(conn, int, -1);
    int vboxRet          = -1;
    nsresult rc;

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

    if (data->vboxCallback == NULL) {
        data->vboxCallback = vboxAllocCallbackObj();
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
            }
        }
    } else {
        vboxRet = 0;
    }

    /* Get the vbox file handle and add a event handle to it
     * so that the events can be passed down to the user
     */
    if (vboxRet == 0) {
        if (data->fdWatch < 0) {
            PRInt32 vboxFileHandle;
            vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);

            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }

        if (data->fdWatch >= 0) {
            /* Once a callback is registered with virtualbox, use a list
             * to store the callbacks registered with libvirt so that
             * later you can iterate over them
             */

7109
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
7110 7111
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
7112
                ret = -1;
7113
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
7114
                      "callback: %p, opaque: %p, "
7115
                      "freecb: %p)", ret, conn, callback,
7116
                      opaque, freecb);
7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7132 7133 7134 7135
static int
vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
{
7136
    VBOX_OBJECT_CHECK(conn, int, -1);
7137
    int cnt;
7138 7139 7140 7141 7142 7143

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7144
    cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
7145
                                          callbackID);
7146

7147 7148 7149
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7150

7151 7152 7153
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7154 7155 7156 7157
    }

    vboxDriverUnlock(data);

7158 7159 7160
    if (cnt >= 0)
        ret = 0;

7161 7162 7163
    return ret;
}

7164
#endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
7165

7166 7167 7168 7169 7170
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
7171 7172
                                        unsigned int flags)
{
7173 7174
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
7175 7176
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

7177 7178 7179 7180 7181 7182 7183 7184
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

7185
    VIR_DEBUG("network initialized");
7186 7187 7188
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

7189
 cleanup:
7190 7191 7192
    return VIR_DRV_OPEN_DECLINED;
}

7193 7194
static int vboxNetworkClose(virConnectPtr conn)
{
7195
    VIR_DEBUG("network uninitialized");
7196 7197 7198 7199
    conn->networkPrivateData = NULL;
    return 0;
}

7200 7201
static int vboxConnectNumOfNetworks(virConnectPtr conn)
{
7202
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7203
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7204
    size_t i = 0;
7205

7206
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7207

7208 7209 7210 7211
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7212
            PRUint32 interfaceType = 0;
7213

7214
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7215 7216
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7217

7218
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7219

7220 7221
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
7222 7223 7224 7225
            }
        }
    }

7226 7227
    vboxArrayRelease(&networkInterfaces);

7228 7229
    VBOX_RELEASE(host);

7230
    VIR_DEBUG("numActive: %d", ret);
7231
    return ret;
7232 7233
}

7234
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
7235
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7236
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7237
    size_t i = 0;
7238

7239 7240 7241 7242
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7243

7244
        if (networkInterface) {
7245
            PRUint32 interfaceType = 0;
7246

7247
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7248

7249 7250
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7251

7252
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7253

7254 7255 7256
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7257

7258
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7259
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7260

7261
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7262
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7263
                        ret++;
7264

7265 7266
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7267 7268 7269 7270 7271
                }
            }
        }
    }

7272
    vboxArrayRelease(&networkInterfaces);
7273

7274
    VBOX_RELEASE(host);
7275

7276 7277
    return ret;
}
7278

7279 7280
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn)
{
7281
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7282
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7283
    size_t i = 0;
7284

7285
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7286

7287 7288 7289 7290
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7291
            PRUint32 interfaceType = 0;
7292

7293
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7294 7295
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7296

7297
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7298

7299 7300
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
7301 7302 7303 7304
            }
        }
    }

7305 7306
    vboxArrayRelease(&networkInterfaces);

7307 7308
    VBOX_RELEASE(host);

7309
    VIR_DEBUG("numActive: %d", ret);
7310
    return ret;
7311 7312
}

7313
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
7314
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7315
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7316
    size_t i = 0;
7317

7318 7319 7320 7321
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7322

7323
        if (networkInterface) {
7324
            PRUint32 interfaceType = 0;
7325

7326
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7327

7328 7329
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7330

7331
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7332

7333 7334 7335
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7336

7337
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7338
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7339

7340
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7341
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7342
                        ret++;
7343

7344 7345
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7346 7347 7348 7349 7350
                }
            }
        }
    }

7351
    vboxArrayRelease(&networkInterfaces);
7352 7353 7354 7355

    VBOX_RELEASE(host);

    return ret;
7356 7357
}

7358 7359 7360
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
7361
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7362
    vboxIID iid = VBOX_IID_INITIALIZER;
7363

7364
    vboxIIDFromUUID(&iid, uuid);
7365

7366 7367 7368
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
7369
    IHostNetworkInterface *networkInterface = NULL;
7370

7371
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
7372 7373
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7374

7375
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7376

7377 7378 7379
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
7380

7381 7382
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7383

7384
            ret = virGetNetwork(conn, nameUtf8, uuid);
7385

7386
            VIR_DEBUG("Network Name: %s", nameUtf8);
7387
            DEBUGIID("Network UUID", iid.value);
7388

7389 7390
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
7391
        }
7392 7393

        VBOX_RELEASE(networkInterface);
7394 7395
    }

7396 7397
    VBOX_RELEASE(host);

7398
    vboxIIDUnalloc(&iid);
7399 7400 7401
    return ret;
}

7402 7403 7404
static virNetworkPtr
vboxNetworkLookupByName(virConnectPtr conn, const char *name)
{
7405 7406 7407
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7408

7409
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
7410

7411
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
7412

7413 7414
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7415

7416
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7417

7418 7419
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
7420
            vboxIID iid = VBOX_IID_INITIALIZER;
7421

7422 7423
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
7424
            ret = virGetNetwork(conn, name, uuid);
7425
            VIR_DEBUG("Network Name: %s", name);
7426

7427 7428
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
7429
        }
7430 7431

        VBOX_RELEASE(networkInterface);
7432 7433
    }

7434 7435 7436
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

7437 7438 7439
    return ret;
}

7440 7441 7442
static virNetworkPtr
vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
{
7443 7444 7445 7446
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7447
    nsresult rc;
7448

7449
    virNetworkDefPtr def = virNetworkDefParseString(xml);
7450 7451
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
7452

7453
    if ((!def) ||
7454
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
7455
        (def->nips == 0 || !def->ips))
7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466
        goto cleanup;

    /* Look for the first IPv4 IP address definition and use that.
     * If there weren't any IPv4 addresses, ignore the network (since it's
     * required below to have an IPv4 address)
    */
    ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
    if (!ipdef)
        goto cleanup;

    if (virNetworkIpDefNetmask(ipdef, &netmask) < 0)
7467
        goto cleanup;
7468

7469 7470 7471 7472 7473 7474
    /* the current limitation of hostonly network is that you can't
     * assign a name to it and it defaults to vboxnet*, for e.g:
     * vboxnet0, vboxnet1, etc. Also the UUID is assigned to it
     * automatically depending on the mac address and thus both
     * these paramters are ignored here for now.
     */
7475

7476
#if VBOX_API_VERSION == 2002000
7477
    if (STREQ(def->name, "vboxnet0")) {
7478
        PRUint32 interfaceType = 0;
7479

7480 7481
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7482

7483 7484 7485 7486 7487 7488
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
7489
#else /* VBOX_API_VERSION != 2002000 */
7490 7491 7492 7493
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
7494

7495 7496 7497 7498
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
7499
    }
7500
#endif /* VBOX_API_VERSION != 2002000 */
7501

7502 7503 7504 7505
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
7506
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517

        networkInterface->vtbl->GetName(networkInterface, &networkInterfaceNameUtf16);
        if (networkInterfaceNameUtf16) {
            VBOX_UTF16_TO_UTF8(networkInterfaceNameUtf16, &networkInterfaceNameUtf8);

            if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", networkInterfaceNameUtf8) < 0) {
                VBOX_RELEASE(host);
                VBOX_RELEASE(networkInterface);
                goto cleanup;
            }
        }
7518

E
Eric Blake 已提交
7519
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7520

7521 7522 7523
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
7524
        if ((ipdef->nranges >= 1) &&
7525 7526
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
7527 7528 7529 7530 7531 7532 7533 7534 7535 7536
            IDHCPServer *dhcpServer = NULL;

            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (!dhcpServer) {
                /* create a dhcp server */
                data->vboxObj->vtbl->CreateDHCPServer(data->vboxObj,
                                                      networkNameUtf16,
                                                      &dhcpServer);
7537
                VIR_DEBUG("couldn't find dhcp server so creating one");
7538 7539 7540 7541 7542 7543 7544 7545
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

7546 7547 7548 7549
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
7550 7551 7552 7553 7554 7555 7556 7557 7558 7559

                if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
                    fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
                    VBOX_UTF16_FREE(ipAddressUtf16);
                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(fromIPAddressUtf16);
                    VBOX_UTF16_FREE(toIPAddressUtf16);
                    VBOX_RELEASE(dhcpServer);
                    goto cleanup;
                }
7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584

                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);

                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);

                dhcpServer->vtbl->SetConfiguration(dhcpServer,
                                                   ipAddressUtf16,
                                                   networkMaskUtf16,
                                                   fromIPAddressUtf16,
                                                   toIPAddressUtf16);

                if (start)
                    dhcpServer->vtbl->Start(dhcpServer,
                                            networkNameUtf16,
                                            networkInterfaceNameUtf16,
                                            trunkTypeUtf16);

                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                VBOX_UTF16_FREE(fromIPAddressUtf16);
                VBOX_UTF16_FREE(toIPAddressUtf16);
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
            }
        }
7585

7586
        if ((ipdef->nhosts >= 1) &&
7587
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
7588 7589
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
7590

7591 7592
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7593 7594 7595 7596 7597 7598

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
7599

7600 7601 7602 7603
            /* Current drawback is that since EnableStaticIpConfig() sets
             * IP and enables the interface so even if the dhcpserver is not
             * started the interface is still up and running
             */
7604
#if VBOX_API_VERSION < 4002000
7605 7606 7607
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
7608 7609 7610 7611 7612
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
7613

7614 7615 7616
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
7617
#if VBOX_API_VERSION < 4002000
7618 7619
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
7620 7621 7622 7623
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
7624
        }
7625

7626 7627 7628 7629 7630
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
7631
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
7632
        }
7633 7634 7635 7636

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
7637 7638
    }

7639 7640 7641 7642
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7643
 cleanup:
7644 7645 7646 7647
    virNetworkDefFree(def);
    return ret;
}

7648 7649
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml)
{
7650 7651 7652
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

7653 7654
static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml)
{
7655 7656 7657
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

7658 7659 7660
static int
vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface)
{
7661
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
7662
    char *networkNameUtf8 = NULL;
7663 7664
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7665 7666 7667 7668 7669 7670 7671 7672 7673

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that you can't delete the default hostonly adaptor namely:
     * vboxnet0 and thus all this functions does is remove the
     * dhcp server configuration, but the network can still be used
     * by giving the machine static IP and also it will still
     * show up in the net-list in virsh
     */

7674
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
7675 7676
        goto cleanup;

7677
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7678

7679
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7680

7681 7682
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7683

7684
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7685

7686 7687 7688
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
7689

7690
#if VBOX_API_VERSION != 2002000
7691 7692 7693
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
7694

7695
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
7696

7697
                if (iidUtf16) {
7698
# if VBOX_API_VERSION == 3000000
7699 7700 7701
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
7702
# else  /* VBOX_API_VERSION > 3000000 */
7703
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
7704
# endif /* VBOX_API_VERSION > 3000000 */
7705 7706
                    VBOX_UTF16_FREE(iidUtf16);
                }
7707

7708 7709 7710 7711 7712
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
7713
#endif /* VBOX_API_VERSION != 2002000 */
7714

E
Eric Blake 已提交
7715
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7716 7717 7718 7719 7720 7721 7722 7723 7724 7725

            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_FALSE);
                dhcpServer->vtbl->Stop(dhcpServer);
                if (removeinterface)
                    data->vboxObj->vtbl->RemoveDHCPServer(data->vboxObj, dhcpServer);
                VBOX_RELEASE(dhcpServer);
7726 7727
            }

7728 7729
            VBOX_UTF16_FREE(networkNameUtf16);

7730
        }
7731
        VBOX_RELEASE(networkInterface);
7732 7733
    }

7734 7735 7736
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7737 7738
    ret = 0;

7739
 cleanup:
7740 7741 7742 7743
    VIR_FREE(networkNameUtf8);
    return ret;
}

7744 7745
static int vboxNetworkUndefine(virNetworkPtr network)
{
7746 7747 7748
    return vboxNetworkUndefineDestroy(network, true);
}

7749 7750
static int vboxNetworkCreate(virNetworkPtr network)
{
7751
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
7752
    char *networkNameUtf8 = NULL;
7753 7754
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7755 7756 7757 7758 7759 7760 7761 7762

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that the default hostonly network "vboxnet0" is always active
     * and thus all this functions does is start the dhcp server,
     * but the network can still be used without starting the dhcp
     * server by giving the machine static IP
     */

7763
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
7764 7765
        goto cleanup;

7766
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7767

7768
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7769

7770 7771
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7772

7773
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7774

7775 7776 7777
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
7778 7779


E
Eric Blake 已提交
7780
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7781

7782 7783 7784 7785 7786
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
7787

7788
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
7789

7790
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
7791

7792 7793 7794 7795
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
7796

7797 7798
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
7799 7800
            }

7801
            VBOX_UTF16_FREE(networkNameUtf16);
7802
        }
7803 7804

        VBOX_RELEASE(networkInterface);
7805 7806
    }

7807 7808 7809
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7810 7811
    ret = 0;

7812
 cleanup:
7813 7814 7815 7816
    VIR_FREE(networkNameUtf8);
    return ret;
}

7817 7818
static int vboxNetworkDestroy(virNetworkPtr network)
{
7819
    return vboxNetworkUndefineDestroy(network, false);
7820 7821
}

7822
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
7823 7824
                                   unsigned int flags)
{
7825
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
7826
    virNetworkDefPtr def  = NULL;
7827
    virNetworkIpDefPtr ipdef = NULL;
7828
    char *networkNameUtf8 = NULL;
7829 7830
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7831

E
Eric Blake 已提交
7832 7833
    virCheckFlags(0, NULL);

7834
    if (VIR_ALLOC(def) < 0)
7835
        goto cleanup;
7836
    if (VIR_ALLOC(ipdef) < 0)
7837 7838 7839
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
7840

7841
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
7842 7843
        goto cleanup;

7844
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7845

7846
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7847

7848 7849
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7850

7851
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7852

7853
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
7854
            if (VIR_STRDUP(def->name, network->name) >= 0) {
7855 7856
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
7857
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
7858

7859 7860
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
7861

E
Eric Blake 已提交
7862
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7863

7864
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
7865

7866 7867 7868 7869
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
7870
                    ipdef->nranges = 1;
7871
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >= 0) {
7872 7873 7874 7875
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
7876
                        bool errorOccurred = false;
7877

7878 7879 7880 7881 7882 7883 7884
                        dhcpServer->vtbl->GetIPAddress(dhcpServer, &ipAddressUtf16);
                        dhcpServer->vtbl->GetNetworkMask(dhcpServer, &networkMaskUtf16);
                        dhcpServer->vtbl->GetLowerIP(dhcpServer, &fromIPAddressUtf16);
                        dhcpServer->vtbl->GetUpperIP(dhcpServer, &toIPAddressUtf16);
                        /* Currently virtualbox supports only one dhcp server per network
                         * with contigious address space from start to end
                         */
7885
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
7886
                                                     &ipdef->address) < 0 ||
7887
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
7888
                                                     &ipdef->netmask) < 0 ||
7889
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
7890
                                                     &ipdef->ranges[0].start) < 0 ||
7891
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
7892
                                                     &ipdef->ranges[0].end) < 0) {
7893 7894
                            errorOccurred = true;
                        }
7895 7896 7897 7898 7899

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
7900 7901 7902 7903

                        if (errorOccurred) {
                            goto cleanup;
                        }
7904
                    } else {
7905
                        ipdef->nranges = 0;
7906
                    }
7907

7908
                    ipdef->nhosts = 1;
7909
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >= 0) {
7910
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
7911 7912
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
7913
                        } else {
7914 7915
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
7916
                            bool errorOccurred = false;
7917

7918
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
7919 7920
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

7921
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
7922 7923

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
7924
                                                         &ipdef->hosts[0].ip) < 0) {
7925 7926
                                errorOccurred = true;
                            }
7927

7928 7929
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
7930 7931 7932 7933

                            if (errorOccurred) {
                                goto cleanup;
                            }
7934 7935
                        }
                    } else {
7936
                        ipdef->nhosts = 0;
7937
                    }
7938 7939 7940 7941 7942

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
7943
                    bool errorOccurred = false;
7944 7945 7946 7947

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

7948
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
7949
                                                 &ipdef->netmask) < 0 ||
7950
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
7951
                                                 &ipdef->address) < 0) {
7952 7953
                        errorOccurred = true;
                    }
7954 7955 7956

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
7957 7958 7959 7960

                    if (errorOccurred) {
                        goto cleanup;
                    }
7961 7962
                }

7963 7964
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
7965
                VBOX_UTF16_FREE(networkNameUtf16);
7966 7967
            }
        }
7968 7969

        VBOX_RELEASE(networkInterface);
7970 7971
    }

7972 7973 7974
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7975
    ret = virNetworkDefFormat(def, 0);
7976

7977
 cleanup:
7978
    virNetworkDefFree(def);
7979 7980 7981 7982
    VIR_FREE(networkNameUtf8);
    return ret;
}

7983 7984 7985 7986
/**
 * The Storage Functions here on
 */

7987 7988 7989
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
7990
{
7991 7992
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
7993 7994
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

7995
    if (STRNEQ(conn->driver->name, "VBOX"))
7996
        return VIR_DRV_OPEN_DECLINED;
7997 7998 7999 8000

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
8001
        return VIR_DRV_OPEN_ERROR;
8002

8003
    VIR_DEBUG("vbox storage initialized");
8004 8005 8006 8007
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

8008 8009
static int vboxStorageClose(virConnectPtr conn)
{
8010
    VIR_DEBUG("vbox storage uninitialized");
8011 8012 8013 8014
    conn->storagePrivateData = NULL;
    return 0;
}

8015 8016
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
8017 8018 8019 8020 8021 8022 8023 8024

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

8025 8026
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
8027 8028
    int numActive = 0;

8029 8030 8031
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
8032 8033 8034
    return numActive;
}

8035 8036 8037
static virStoragePoolPtr
vboxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
8038 8039 8040 8041 8042 8043 8044 8045 8046 8047
    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";

8048
        ignore_value(virUUIDParse(uuidstr, uuid));
8049

8050
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
8051 8052 8053 8054 8055
    }

    return ret;
}

8056 8057
static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
8058
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8059
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8060 8061
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
8062
    size_t i;
8063

8064
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8065
    if (NS_SUCCEEDED(rc)) {
8066 8067
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8068 8069
            if (hardDisk) {
                PRUint32 hddstate;
8070

8071 8072 8073
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
8074 8075
            }
        }
8076 8077 8078 8079

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
8080
    } else {
8081
        ret = -1;
8082 8083 8084
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8085 8086
    }

8087
    return ret;
8088 8089 8090
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
8091
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8092
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8093 8094
    PRUint32 numActive     = 0;
    nsresult rc;
8095
    size_t i;
8096

8097
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8098
    if (NS_SUCCEEDED(rc)) {
8099 8100
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8101

8102 8103 8104 8105
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8106

8107 8108 8109
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8110

8111 8112
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8113

8114
                    if (nameUtf8) {
8115
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
8116
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
8117 8118 8119
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
8120 8121 8122 8123
                    }
                }
            }
        }
8124 8125 8126 8127

        vboxArrayRelease(&hardDisks);

        ret = numActive;
8128
    } else {
8129
        ret = -1;
8130 8131 8132
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8133 8134
    }

8135
    return ret;
8136 8137
}

8138 8139 8140
static virStorageVolPtr
vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
{
8141
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8142
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8143
    nsresult rc;
8144
    size_t i;
8145

8146
    if (!name)
8147
        return ret;
8148

8149
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8150
    if (NS_SUCCEEDED(rc)) {
8151 8152
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8153

8154 8155 8156 8157
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8158

8159 8160 8161
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8162

8163 8164 8165 8166
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
8167

8168
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
8169 8170 8171
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
8172

8173 8174 8175 8176
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
8177

8178 8179
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
8180

8181 8182 8183 8184
                            VIR_DEBUG("virStorageVolPtr: %p", ret);
                            VIR_DEBUG("Storage Volume Name: %s", name);
                            VIR_DEBUG("Storage Volume key : %s", key);
                            VIR_DEBUG("Storage Volume Pool: %s", pool->name);
8185 8186
                        }

8187
                        vboxIIDUnalloc(&hddIID);
8188 8189
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
8190
                    }
8191

J
John Ferlan 已提交
8192
                    VBOX_UTF8_FREE(nameUtf8);
8193 8194 8195
                }
            }
        }
8196

8197
        vboxArrayRelease(&hardDisks);
8198 8199 8200 8201 8202
    }

    return ret;
}

T
Taowei 已提交
8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445
static virStorageVolPtr
vboxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

    if (!key)
        return ret;

    if (virUUIDParse(key, uuid) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
        return NULL;
    }

    vboxIIDFromUUID(&hddIID, uuid);
#if VBOX_API_VERSION < 4000000
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000000 */
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;

            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);

            if (hddNameUtf8) {
                if (vboxConnectNumOfStoragePools(conn) == 1) {
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
                }

                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
        }

        VBOX_MEDIUM_RELEASE(hardDisk);
    }

    vboxIIDUnalloc(&hddIID);
    return ret;
}

static virStorageVolPtr
vboxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

    if (!path)
        return ret;

    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);

    if (!hddPathUtf16)
        return ret;

#if VBOX_API_VERSION < 4000000
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000000 */
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;

            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);

            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }

            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";

                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);

                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
                    if (vboxConnectNumOfStoragePools(conn) == 1)
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);

                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
                }

                vboxIIDUnalloc(&hddIID);
            }

            VBOX_UTF8_FREE(hddNameUtf8);
        }

        VBOX_MEDIUM_RELEASE(hardDisk);
    }

    VBOX_UTF16_FREE(hddPathUtf16);

    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
                                                unsigned int flags)
{
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
    virStorageVolDefPtr  def  = NULL;
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
    virStoragePoolDef poolDef;
    nsresult rc;

    virCheckFlags(0, NULL);

    /* 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(&poolDef, xml)) == NULL)
        goto cleanup;

    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
        goto cleanup;

    /* For now only the vmdk, vpc and vdi type harddisk
     * variants can be created.  For historical reason, we default to vdi */
    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
        VBOX_UTF8_TO_UTF16("VMDK", &hddFormatUtf16);
    } else if (def->target.format == VIR_STORAGE_FILE_VPC) {
        VBOX_UTF8_TO_UTF16("VHD", &hddFormatUtf16);
    } else {
        VBOX_UTF8_TO_UTF16("VDI", &hddFormatUtf16);
    }

    VBOX_UTF8_TO_UTF16(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 = VIR_DIV_UP(def->target.capacity,
                                                1024 * 1024);
            PRUint32   variant     = HardDiskVariant_Standard;

            if (def->target.capacity == def->target.allocation)
                variant = HardDiskVariant_Fixed;

#if VBOX_API_VERSION < 4003000
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
#else
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
#endif
            if (NS_SUCCEEDED(rc) && progress) {
#if VBOX_API_VERSION == 2002000
                nsresult resultCode;
#else
                PRInt32  resultCode;
#endif

                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);

                if (NS_SUCCEEDED(resultCode)) {
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";

                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                    if (NS_SUCCEEDED(rc)) {
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);

                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
                    }

                    vboxIIDUnalloc(&hddIID);
                }

                VBOX_RELEASE(progress);
            }
        }
    }

    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

 cleanup:
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
                                unsigned int flags)
8446
{
T
Taowei 已提交
8447
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8448 8449
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8450
    IHardDisk *hardDisk  = NULL;
T
Taowei 已提交
8451
    int deregister = 0;
8452
    nsresult rc;
T
Taowei 已提交
8453 8454
    size_t i = 0;
    size_t j = 0;
8455

T
Taowei 已提交
8456
    virCheckFlags(0, -1);
8457

T
Taowei 已提交
8458
    if (virUUIDParse(vol->key, uuid) < 0) {
8459
        virReportError(VIR_ERR_INVALID_ARG,
T
Taowei 已提交
8460 8461
                       _("Could not parse UUID from '%s'"), vol->key);
        return -1;
8462 8463
    }

8464
    vboxIIDFromUUID(&hddIID, uuid);
8465
#if VBOX_API_VERSION < 4000000
8466
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8467
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8468 8469
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8470 8471 8472 8473
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8474
#endif /* VBOX_API_VERSION >= 4000000 */
8475 8476
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8477

8478 8479
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
T
Taowei 已提交
8480 8481
            PRUint32  machineIdsSize = 0;
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;
8482

T
Taowei 已提交
8483 8484 8485 8486 8487
#if VBOX_API_VERSION < 3001000
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
#else  /* VBOX_API_VERSION >= 3001000 */
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
#endif /* VBOX_API_VERSION >= 3001000 */
8488

T
Taowei 已提交
8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514
#if VBOX_API_VERSION == 2002000 && defined WIN32
            /* VirtualBox 2.2 on Windows represents IIDs as GUIDs and the
             * machineIds array contains direct instances of the GUID struct
             * instead of pointers to the actual struct instances. But there
             * is no 128bit width simple item type for a SafeArray to fit a
             * GUID in. The largest simple type it 64bit width and VirtualBox
             * uses two of this 64bit items to represents one GUID. Therefore,
             * we divide the size of the SafeArray by two, to compensate for
             * this workaround in VirtualBox */
            machineIds.count /= 2;
#endif /* VBOX_API_VERSION >= 2002000 */

            machineIdsSize = machineIds.count;

            for (i = 0; i < machineIds.count; i++) {
                IMachine *machine = NULL;
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);

#if VBOX_API_VERSION >= 4000000
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
                    break;
8515
                }
T
Taowei 已提交
8516
#endif
8517

T
Taowei 已提交
8518
                rc = VBOX_SESSION_OPEN(machineId.value, machine);
8519

T
Taowei 已提交
8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607
                if (NS_SUCCEEDED(rc)) {

                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;

#if VBOX_API_VERSION < 3001000
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
#else  /* VBOX_API_VERSION >= 3001000 */
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
#endif /* VBOX_API_VERSION >= 3001000 */
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

#if VBOX_API_VERSION < 3001000
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
#else  /* VBOX_API_VERSION >= 3001000 */
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
#endif /* VBOX_API_VERSION >= 3001000 */
                                if (NS_SUCCEEDED(rc) && hdd) {
                                    vboxIID iid = VBOX_IID_INITIALIZER;

                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {

                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);

                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

#if VBOX_API_VERSION < 3001000
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
#else  /* VBOX_API_VERSION >= 3001000 */
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
#endif /* VBOX_API_VERSION >= 3001000 */
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
                                                VIR_DEBUG("saving machine settings");
                                            }

                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
                                            }

                                            VBOX_UTF16_FREE(controller);
                                        }
                                        vboxIIDUnalloc(&iid);
                                    }
                                    VBOX_MEDIUM_RELEASE(hdd);
                                }
                            }
                        }
                        vboxArrayRelease(&hddAttachments);
                        VBOX_RELEASE(machine);
                    }
                    VBOX_SESSION_CLOSE();
                }

                vboxIIDUnalloc(&machineId);
            }

            vboxArrayUnalloc(&machineIds);

            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);

                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
                    ret = 0;
                }
8608 8609
            }
        }
8610 8611

        VBOX_MEDIUM_RELEASE(hardDisk);
8612 8613
    }

8614
    vboxIIDUnalloc(&hddIID);
T
Taowei 已提交
8615

8616 8617 8618
    return ret;
}

T
Taowei 已提交
8619 8620
static int
vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
8621
{
T
Taowei 已提交
8622 8623 8624 8625
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
    IHardDisk *hardDisk  = NULL;
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8626 8627
    nsresult rc;

T
Taowei 已提交
8628
    if (!info)
8629
        return ret;
8630

T
Taowei 已提交
8631 8632 8633
    if (virUUIDParse(vol->key, uuid) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8634
        return ret;
T
Taowei 已提交
8635
    }
8636

T
Taowei 已提交
8637
    vboxIIDFromUUID(&hddIID, uuid);
8638
#if VBOX_API_VERSION < 4000000
T
Taowei 已提交
8639
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8640
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
T
Taowei 已提交
8641
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
8642
                                         DeviceType_HardDisk, &hardDisk);
8643
#else
T
Taowei 已提交
8644
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
8645 8646
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8647
#endif /* VBOX_API_VERSION >= 4000000 */
8648 8649
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8650

8651 8652
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
T
Taowei 已提交
8653 8654 8655 8656 8657 8658 8659
#if VBOX_API_VERSION < 4000000
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
#else /* VBOX_API_VERSION >= 4000000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000000 */
8660

T
Taowei 已提交
8661
            info->type = VIR_STORAGE_VOL_FILE;
8662

T
Taowei 已提交
8663 8664 8665 8666 8667 8668
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
#if VBOX_API_VERSION < 4000000
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
#else /* VBOX_API_VERSION >= 4000000 */
            info->capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000000 */
8669

T
Taowei 已提交
8670 8671
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
8672

T
Taowei 已提交
8673
            ret = 0;
8674

T
Taowei 已提交
8675 8676 8677 8678
            VIR_DEBUG("Storage Volume Name: %s", vol->name);
            VIR_DEBUG("Storage Volume Type: %s", info->type == VIR_STORAGE_VOL_BLOCK ? "Block" : "File");
            VIR_DEBUG("Storage Volume Capacity: %llu", info->capacity);
            VIR_DEBUG("Storage Volume Allocation: %llu", info->allocation);
8679
        }
8680 8681

        VBOX_MEDIUM_RELEASE(hardDisk);
8682 8683
    }

T
Taowei 已提交
8684
    vboxIIDUnalloc(&hddIID);
8685

8686 8687 8688
    return ret;
}

T
Taowei 已提交
8689
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
E
Eric Blake 已提交
8690
{
T
Taowei 已提交
8691 8692 8693 8694 8695 8696 8697
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
    IHardDisk *hardDisk  = NULL;
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
8698 8699
    nsresult rc;

E
Eric Blake 已提交
8700 8701
    virCheckFlags(0, NULL);

T
Taowei 已提交
8702 8703
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));
8704

T
Taowei 已提交
8705 8706 8707 8708 8709
    if (virUUIDParse(vol->key, uuid) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
        return ret;
    }
8710

T
Taowei 已提交
8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723
    vboxIIDFromUUID(&hddIID, uuid);
#if VBOX_API_VERSION < 4000000
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000000 */
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8724

T
Taowei 已提交
8725 8726 8727 8728 8729 8730 8731 8732 8733 8734
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
#if VBOX_API_VERSION < 4000000
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
#else /* VBOX_API_VERSION >= 4000000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000000 */
8735

T
Taowei 已提交
8736 8737 8738 8739 8740 8741 8742 8743
            /* 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;
            def.type = VIR_STORAGE_VOL_FILE;
            defOk = 1;
8744

T
Taowei 已提交
8745 8746 8747 8748 8749 8750 8751 8752 8753
            rc = hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
            if (NS_SUCCEEDED(rc) && defOk) {
#if VBOX_API_VERSION < 4000000
                def.target.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
#else /* VBOX_API_VERSION >= 4000000 */
                def.target.capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000000 */
            } else
                defOk = 0;
8754

T
Taowei 已提交
8755 8756 8757 8758 8759
            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
                def.target.allocation = hddActualSize;
            else
                defOk = 0;
8760

T
Taowei 已提交
8761 8762
            if (VIR_STRDUP(def.name, vol->name) < 0)
                defOk = 0;
8763

T
Taowei 已提交
8764 8765
            if (VIR_STRDUP(def.key, vol->key) < 0)
                defOk = 0;
8766

T
Taowei 已提交
8767 8768 8769
            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;
8770

T
Taowei 已提交
8771 8772
                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {
8773

T
Taowei 已提交
8774
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
8775

T
Taowei 已提交
8776 8777 8778 8779 8780 8781 8782 8783
                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
                    else if (STRCASEEQ("vdi", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VDI;
                    else
                        def.target.format = VIR_STORAGE_FILE_RAW;
8784

T
Taowei 已提交
8785
                    VBOX_UTF8_FREE(hddFormatUtf8);
8786 8787
                }

T
Taowei 已提交
8788 8789 8790
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
8791
            }
8792
        }
T
Taowei 已提交
8793 8794

        VBOX_MEDIUM_RELEASE(hardDisk);
8795 8796
    }

T
Taowei 已提交
8797 8798 8799 8800
    vboxIIDUnalloc(&hddIID);

    if (defOk)
        ret = virStorageVolDefFormat(&pool, &def);
8801

8802 8803 8804
    return ret;
}

T
Taowei 已提交
8805 8806
static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
8807
    IHardDisk *hardDisk  = NULL;
T
Taowei 已提交
8808 8809
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8810
    nsresult rc;
E
Eric Blake 已提交
8811

8812
    if (virUUIDParse(vol->key, uuid) < 0) {
8813 8814
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
T
Taowei 已提交
8815
        return ret;
8816
    }
8817

8818
    vboxIIDFromUUID(&hddIID, uuid);
8819
#if VBOX_API_VERSION < 4000000
8820
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8821
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8822 8823
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8824 8825 8826 8827
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8828
#endif /* VBOX_API_VERSION >= 4000000 */
8829 8830
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8831

8832 8833
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
T
Taowei 已提交
8834 8835
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
8836

T
Taowei 已提交
8837
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
8838

T
Taowei 已提交
8839 8840
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
8841

T
Taowei 已提交
8842
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
8843

T
Taowei 已提交
8844 8845 8846
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
8847

T
Taowei 已提交
8848 8849
                VBOX_UTF8_FREE(hddLocationUtf8);
            }
8850

T
Taowei 已提交
8851 8852
            VBOX_UTF16_FREE(hddLocationUtf16);
        }
8853

T
Taowei 已提交
8854 8855
        VBOX_MEDIUM_RELEASE(hardDisk);
    }
8856

T
Taowei 已提交
8857
    vboxIIDUnalloc(&hddIID);
8858

T
Taowei 已提交
8859 8860
    return ret;
}
8861

T
Taowei 已提交
8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894
#if VBOX_API_VERSION >= 4000000
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
                     unsigned int flags)
{
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
    IConsole *console = NULL;
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;
    char *tmp;
    int tmp_fd = -1;
    unsigned int max_screen;

    virCheckFlags(0, NULL);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
        VBOX_RELEASE(machine);
        return NULL;
    }
8895

T
Taowei 已提交
8896 8897 8898 8899 8900 8901 8902
    if (screen >= max_screen) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
        VBOX_RELEASE(machine);
        return NULL;
    }
8903

T
Taowei 已提交
8904 8905 8906 8907
    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }
8908

T
Taowei 已提交
8909 8910 8911 8912 8913 8914
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
        VIR_FREE(tmp);
        VBOX_RELEASE(machine);
        return NULL;
    }
8915 8916


T
Taowei 已提交
8917 8918 8919 8920 8921
    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
    if (NS_SUCCEEDED(rc)) {
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (NS_SUCCEEDED(rc) && console) {
            IDisplay *display = NULL;
8922

T
Taowei 已提交
8923
            console->vtbl->GetDisplay(console, &display);
8924

T
Taowei 已提交
8925 8926 8927 8928 8929 8930 8931
            if (display) {
                PRUint32 width, height, bitsPerPixel;
                PRUint32 screenDataSize;
                PRUint8 *screenData;
# if VBOX_API_VERSION >= 4003000
                PRInt32 xOrigin, yOrigin;
# endif
8932

T
Taowei 已提交
8933 8934 8935 8936 8937 8938 8939 8940
                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
# if VBOX_API_VERSION < 4003000
                                                        &bitsPerPixel);
# else
                                                        &bitsPerPixel,
                                                        &xOrigin, &yOrigin);
# endif
8941

T
Taowei 已提交
8942 8943 8944 8945 8946
                if (NS_FAILED(rc) || !width || !height) {
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
                    goto endjob;
                }
8947

T
Taowei 已提交
8948 8949 8950 8951 8952 8953 8954 8955
                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
                    goto endjob;
8956
                }
8957

T
Taowei 已提交
8958 8959 8960 8961 8962 8963
                if (safewrite(tmp_fd, (char *) screenData,
                              screenDataSize) < 0) {
                    virReportSystemError(errno, _("unable to write data "
                                                  "to '%s'"), tmp);
                    goto endjob;
                }
8964

T
Taowei 已提交
8965 8966 8967 8968
                if (VIR_CLOSE(tmp_fd) < 0) {
                    virReportSystemError(errno, _("unable to close %s"), tmp);
                    goto endjob;
                }
8969

T
Taowei 已提交
8970 8971
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;
8972

T
Taowei 已提交
8973 8974 8975 8976
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
                    VIR_FREE(ret);
8977
                }
T
Taowei 已提交
8978 8979 8980
 endjob:
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
8981
            }
T
Taowei 已提交
8982
            VBOX_RELEASE(console);
8983
        }
T
Taowei 已提交
8984
        VBOX_SESSION_CLOSE();
8985 8986
    }

T
Taowei 已提交
8987 8988 8989 8990 8991
    VIR_FORCE_CLOSE(tmp_fd);
    unlink(tmp);
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
8992 8993
    return ret;
}
T
Taowei 已提交
8994
#endif /* VBOX_API_VERSION >= 4000000 */
8995

T
Taowei 已提交
8996 8997

#define MATCH(FLAG) (flags & (FLAG))
8998
static int
T
Taowei 已提交
8999 9000 9001
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
9002
{
T
Taowei 已提交
9003 9004 9005 9006
    VBOX_OBJECT_CHECK(conn, int, -1);
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
9007
    unsigned char uuid[VIR_UUID_BUFLEN];
T
Taowei 已提交
9008 9009
    vboxIID iid = VBOX_IID_INITIALIZER;
    PRUint32 state;
9010
    nsresult rc;
T
Taowei 已提交
9011 9012 9013 9014 9015 9016
    size_t i;
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;
9017

T
Taowei 已提交
9018
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
9019

T
Taowei 已提交
9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036
    /* filter out flag options that will produce 0 results in vbox driver:
     * - managed save: vbox guests don't have managed save images
     * - autostart: vbox doesn't support autostarting guests
     * - persistance: vbox doesn't support transient guests
     */
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
        (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) ||
        (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
        if (domains &&
            VIR_ALLOC_N(*domains, 1) < 0)
            goto cleanup;

        ret = 0;
        goto cleanup;
9037
    }
9038

T
Taowei 已提交
9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
        goto cleanup;

    for (i = 0; i < machines.count; i++) {
        IMachine *machine = machines.items[i];

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);

                if (state >= MachineState_FirstOnline &&
                    state <= MachineState_LastOnline)
                    active = true;
                else
                    active = false;

                /* filter by active state */
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("could not get snapshot count for listed domains"));
                        goto cleanup;
                    }
                    if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
                           snapshotCount > 0) ||
                          (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
                           snapshotCount == 0)))
                        continue;
                }

                /* filter by machine state */
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
                       state == MachineState_Running) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
                       state == MachineState_Paused) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
                       state == MachineState_PoweredOff) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
                       (state != MachineState_Running &&
                        state != MachineState_Paused &&
                        state != MachineState_PoweredOff))))
                    continue;
9099

T
Taowei 已提交
9100 9101 9102 9103 9104
                /* just count the machines */
                if (!doms) {
                    count++;
                    continue;
                }
9105

T
Taowei 已提交
9106 9107 9108 9109 9110
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);
9111

T
Taowei 已提交
9112
                dom = virGetDomain(conn, machineNameUtf8, uuid);
9113

T
Taowei 已提交
9114 9115
                VBOX_UTF8_FREE(machineNameUtf8);
                VBOX_UTF16_FREE(machineNameUtf16);
9116

T
Taowei 已提交
9117 9118
                if (!dom)
                    goto cleanup;
9119

T
Taowei 已提交
9120 9121 9122 9123 9124
                if (active)
                    dom->id = i + 1;

                doms[count++] = dom;
            }
9125
        }
T
Taowei 已提交
9126
    }
9127

T
Taowei 已提交
9128 9129 9130 9131 9132 9133
    if (doms) {
        /* safe to ignore, new size will be equal or less than
         * previous allocation*/
        ignore_value(VIR_REALLOC_N(doms, count + 1));
        *domains = doms;
        doms = NULL;
9134 9135
    }

T
Taowei 已提交
9136 9137 9138 9139 9140 9141 9142 9143 9144 9145
    ret = count;

 cleanup:
    if (doms) {
        for (i = 0; i < count; i++) {
            if (doms[i])
                virDomainFree(doms[i]);
        }
    }
    VIR_FREE(doms);
9146

T
Taowei 已提交
9147
    vboxArrayRelease(&machines);
9148 9149
    return ret;
}
T
Taowei 已提交
9150
#undef MATCH
9151

E
Eric Blake 已提交
9152

T
Taowei 已提交
9153 9154 9155 9156 9157 9158
static int
vboxNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
                virNodeInfoPtr nodeinfo)
{
    return nodeGetInfo(nodeinfo);
}
9159 9160


T
Taowei 已提交
9161 9162 9163 9164 9165 9166 9167 9168
static int
vboxNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
                           unsigned long long *freeMems,
                           int startCell,
                           int maxCells)
{
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}
9169 9170


T
Taowei 已提交
9171 9172 9173 9174 9175 9176 9177 9178
static unsigned long long
vboxNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    unsigned long long freeMem;
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;
    return freeMem;
}
9179 9180


T
Taowei 已提交
9181 9182 9183 9184 9185 9186 9187 9188 9189 9190
static int
vboxNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
                     unsigned int npages,
                     unsigned int *pages,
                     int startCell,
                     unsigned int cellCount,
                     unsigned long long *counts,
                     unsigned int flags)
{
    virCheckFlags(0, -1);
9191

T
Taowei 已提交
9192 9193
    return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
}
9194

T
Taowei 已提交
9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206
static int _pfnInitialize(vboxGlobalData *data)
{
    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);
    if (data->pFuncs == NULL)
        return -1;
#if VBOX_XPCOMC_VERSION == 0x00010000U
    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj, ISESSION_IID_STR, &data->vboxSession);
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
    return 0;
}
9207

T
Taowei 已提交
9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225
static int
_initializeDomainEvent(vboxGlobalData *data ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
    /* No event queue functionality in 2.2.* and 4.* as of now */
    vboxUnsupported();
#else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
    /* Initialize the fWatch needed for Event Callbacks */
    data->fdWatch = -1;
    data->pFuncs->pfnGetEventQueue(&data->vboxQueue);
    if (data->vboxQueue == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("nsIEventQueue object is null"));
        return -1;
    }
#endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
    return 0;
}
9226

T
Taowei 已提交
9227 9228 9229 9230 9231 9232 9233 9234 9235
static
void _registerGlobalData(vboxGlobalData *data ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION == 2002000
    vboxUnsupported();
#else /* VBOX_API_VERSION != 2002000 */
    g_pVBoxGlobalData = data;
#endif /* VBOX_API_VERSION != 2002000 */
}
9236

T
Taowei 已提交
9237
#if VBOX_API_VERSION < 4000000
9238

T
Taowei 已提交
9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258
# if VBOX_API_VERSION < 3001000
static void
_detachDevices(vboxGlobalData *data ATTRIBUTE_UNUSED,
               IMachine *machine, PRUnichar *hddcnameUtf16)
{
    /* Disconnect all the drives if present */
    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 0);
    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 1);
    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 1, 1);
}
# else  /* VBOX_API_VERSION >= 3001000 */
static void
_detachDevices(vboxGlobalData *data, IMachine *machine,
               PRUnichar *hddcnameUtf16 ATTRIBUTE_UNUSED)
{
    /* get all the controller first, then the attachments and
    * remove them all so that the machine can be undefined
    */
   vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
   size_t i = 0, j = 0;
9259

T
Taowei 已提交
9260 9261
   vboxArrayGet(&storageControllers, machine,
                machine->vtbl->GetStorageControllers);
9262

T
Taowei 已提交
9263 9264 9265 9266
   for (i = 0; i < storageControllers.count; i++) {
       IStorageController *strCtl = storageControllers.items[i];
       PRUnichar *strCtlName = NULL;
       vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
9267

T
Taowei 已提交
9268 9269
       if (!strCtl)
           continue;
9270

T
Taowei 已提交
9271 9272 9273 9274
       strCtl->vtbl->GetName(strCtl, &strCtlName);
       vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                              machine->vtbl->GetMediumAttachmentsOfController,
                              strCtlName);
9275

T
Taowei 已提交
9276 9277 9278 9279
       for (j = 0; j < mediumAttachments.count; j++) {
           IMediumAttachment *medAtt = mediumAttachments.items[j];
           PRInt32 port = ~0U;
           PRInt32 device = ~0U;
9280

T
Taowei 已提交
9281 9282
           if (!medAtt)
               continue;
9283

T
Taowei 已提交
9284 9285
           medAtt->vtbl->GetPort(medAtt, &port);
           medAtt->vtbl->GetDevice(medAtt, &device);
9286

T
Taowei 已提交
9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300
           if ((port != ~0U) && (device != ~0U)) {
               machine->vtbl->DetachDevice(machine,
                                           strCtlName,
                                           port,
                                           device);
           }
       }
       vboxArrayRelease(&storageControllers);
       machine->vtbl->RemoveStorageController(machine, strCtlName);
       VBOX_UTF16_FREE(strCtlName);
   }
   vboxArrayRelease(&storageControllers);
}
# endif /* VBOX_API_VERSION >= 3001000 */
9301

T
Taowei 已提交
9302 9303 9304 9305 9306
static nsresult
_unregisterMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine)
{
    return data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, IID_MEMBER(value), machine);
}
9307

T
Taowei 已提交
9308 9309 9310 9311 9312
static void
_deleteConfig(IMachine *machine)
{
    machine->vtbl->DeleteSettings(machine);
}
9313

T
Taowei 已提交
9314
#else /* VBOX_API_VERSION >= 4000000 */
9315

T
Taowei 已提交
9316 9317 9318 9319 9320 9321 9322
static void
_detachDevices(vboxGlobalData *data ATTRIBUTE_UNUSED,
               IMachine *machine ATTRIBUTE_UNUSED,
               PRUnichar *hddcnameUtf16 ATTRIBUTE_UNUSED)
{
    vboxUnsupported();
}
9323

T
Taowei 已提交
9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334
static nsresult
_unregisterMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine)
{
    nsresult rc;
    vboxArray media = VBOX_ARRAY_INITIALIZER;
    rc = VBOX_OBJECT_GET_MACHINE(IID_MEMBER(value), machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
        return rc;
    }
9335

T
Taowei 已提交
9336 9337 9338 9339 9340 9341 9342 9343 9344
    /* We're not interested in the array returned by the Unregister method,
     * but in the side effect of unregistering the virtual machine. In order
     * to call the Unregister method correctly we need to use the vboxArray
     * wrapper here. */
    rc = vboxArrayGetWithUintArg(&media, *machine, (*machine)->vtbl->Unregister,
                                 CleanupMode_DetachAllReturnNone);
    vboxArrayUnalloc(&media);
    return rc;
}
9345

T
Taowei 已提交
9346 9347 9348 9349
static void
_deleteConfig(IMachine *machine)
{
    IProgress *progress = NULL;
9350

T
Taowei 已提交
9351 9352 9353 9354 9355 9356 9357 9358 9359 9360
    /* The IMachine Delete method takes an array of IMedium items to be
     * deleted along with the virtual machine. We just want to pass an
     * empty array. But instead of adding a full vboxArraySetWithReturn to
     * the glue layer (in order to handle the required signature of the
     * Delete method) we use a local solution here. */
# ifdef WIN32
    SAFEARRAY *safeArray = NULL;
    typedef HRESULT __stdcall (*IMachine_Delete)(IMachine *self,
                                                 SAFEARRAY **media,
                                                 IProgress **progress);
9361

T
Taowei 已提交
9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379
#  if VBOX_API_VERSION < 4003000
    ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
#  else
    ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
#  endif
# else
    /* XPCOM doesn't like NULL as an array, even when the array size is 0.
     * Instead pass it a dummy array to avoid passing NULL. */
    IMedium *array[] = { NULL };
#  if VBOX_API_VERSION < 4003000
    machine->vtbl->Delete(machine, 0, array, &progress);
#  else
    machine->vtbl->DeleteConfig(machine, 0, array, &progress);
#  endif
# endif
    if (progress != NULL) {
        progress->vtbl->WaitForCompletion(progress, -1);
        VBOX_RELEASE(progress);
9380
    }
T
Taowei 已提交
9381
}
9382

T
Taowei 已提交
9383
#endif /* VBOX_API_VERSION >= 4000000 */
9384

T
Taowei 已提交
9385 9386 9387 9388
static void _pfnUninitialize(vboxGlobalData *data)
{
    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();
9389
}
9390

T
Taowei 已提交
9391
static void _pfnComUnallocMem(PCVBOXXPCOM pFuncs, void *pv)
9392
{
T
Taowei 已提交
9393 9394
    pFuncs->pfnComUnallocMem(pv);
}
9395

T
Taowei 已提交
9396 9397 9398 9399
static void _pfnUtf16Free(PCVBOXXPCOM pFuncs, PRUnichar *pwszString)
{
    pFuncs->pfnUtf16Free(pwszString);
}
E
Eric Blake 已提交
9400

T
Taowei 已提交
9401 9402 9403 9404
static void _pfnUtf8Free(PCVBOXXPCOM pFuncs, char *pszString)
{
    pFuncs->pfnUtf8Free(pszString);
}
9405

T
Taowei 已提交
9406 9407 9408 9409
static int _pfnUtf16ToUtf8(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString)
{
    return pFuncs->pfnUtf16ToUtf8(pwszString, ppszString);
}
9410

T
Taowei 已提交
9411 9412 9413 9414
static int _pfnUtf8ToUtf16(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString)
{
    return pFuncs->pfnUtf8ToUtf16(pszString, ppwszString);
}
9415

T
Taowei 已提交
9416
#if VBOX_API_VERSION == 2002000
9417

T
Taowei 已提交
9418 9419 9420 9421
static void _vboxIIDInitialize(vboxIIDUnion *iidu)
{
    memset(iidu, 0, sizeof(vboxIIDUnion));
}
9422

T
Taowei 已提交
9423 9424 9425 9426 9427 9428 9429 9430
static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu)
{
# ifdef WIN32
    DEBUGUUID(msg, (nsID *)&IID_MEMBER(value));
# else /* !WIN32 */
    DEBUGUUID(msg, IID_MEMBER(value));
# endif /* !WIN32 */
}
9431

T
Taowei 已提交
9432
#else /* VBOX_API_VERSION != 2002000 */
9433

T
Taowei 已提交
9434 9435 9436 9437 9438
static void _vboxIIDInitialize(vboxIIDUnion *iidu)
{
    memset(iidu, 0, sizeof(vboxIIDUnion));
    IID_MEMBER(owner) = true;
}
9439

T
Taowei 已提交
9440 9441 9442 9443
static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu)
{
    DEBUGPRUnichar(msg, IID_MEMBER(value));
}
9444

T
Taowei 已提交
9445
#endif /* VBOX_API_VERSION != 2002000 */
9446

T
Taowei 已提交
9447 9448 9449 9450
static void* _handleGetMachines(IVirtualBox *vboxObj)
{
    return vboxObj->vtbl->GetMachines;
}
9451

T
Taowei 已提交
9452 9453 9454 9455
static nsresult _nsisupportsRelease(nsISupports *nsi)
{
    return nsi->vtbl->Release(nsi);
}
9456

T
Taowei 已提交
9457 9458 9459 9460 9461
static nsresult
_virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16)
{
    return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16);
}
9462

T
Taowei 已提交
9463
#if VBOX_API_VERSION < 4000000
9464

T
Taowei 已提交
9465 9466 9467 9468 9469
static nsresult
_virtualboxGetMachine(IVirtualBox *vboxObj, vboxIIDUnion *iidu, IMachine **machine)
{
    return vboxObj->vtbl->GetMachine(vboxObj, IID_MEMBER(value), machine);
}
9470

T
Taowei 已提交
9471
#else /* VBOX_API_VERSION >= 4000000 */
9472

T
Taowei 已提交
9473 9474 9475 9476
static nsresult
_virtualboxGetMachine(IVirtualBox *vboxObj, vboxIIDUnion *iidu, IMachine **machine)
{
    return vboxObj->vtbl->FindMachine(vboxObj, IID_MEMBER(value), machine);
9477
}
T
Taowei 已提交
9478

9479
#endif /* VBOX_API_VERSION >= 4000000 */
9480

T
Taowei 已提交
9481 9482 9483 9484 9485
static nsresult
_virtualboxGetSystemProperties(IVirtualBox *vboxObj, ISystemProperties **systemProperties)
{
    return vboxObj->vtbl->GetSystemProperties(vboxObj, systemProperties);
}
9486

T
Taowei 已提交
9487 9488
static nsresult
_virtualboxCreateMachine(vboxGlobalData *data, virDomainDefPtr def, IMachine **machine, char *uuidstr ATTRIBUTE_UNUSED)
9489 9490
{
    vboxIID iid = VBOX_IID_INITIALIZER;
T
Taowei 已提交
9491
    PRUnichar *machineNameUtf16 = NULL;
9492 9493
    nsresult rc;

T
Taowei 已提交
9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544
    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
    vboxIIDFromUUID(&iid, def->uuid);
    {
#if VBOX_API_VERSION < 3002000
        rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                                    machineNameUtf16,
                                                    NULL,
                                                    NULL,
                                                    iid.value,
                                                    machine);
#elif VBOX_API_VERSION < 4000000 /* 3002000 <= VBOX_API_VERSION < 4000000 */
        PRBool override             = PR_FALSE;
        rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                                machineNameUtf16,
                                                NULL,
                                                NULL,
                                                iid.value,
                                                override,
                                                machine);
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
        PRBool override             = PR_FALSE;
        rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                                NULL,
                                                machineNameUtf16,
                                                NULL,
                                                iid.value,
                                                override,
                                                machine);
#else /* VBOX_API_VERSION >= 4002000 */
        const char *flagsUUIDPrefix = "UUID=";
        const char *flagsForceOverwrite = "forceOverwrite=0";
        const char *flagsSeparator = ",";
        char createFlags[strlen(flagsUUIDPrefix) + VIR_UUID_STRING_BUFLEN + strlen(flagsSeparator) + strlen(flagsForceOverwrite) + 1];
        PRUnichar *createFlagsUtf16 = NULL;

        snprintf(createFlags, sizeof(createFlags), "%s%s%s%s",
                 flagsUUIDPrefix,
                 uuidstr,
                 flagsSeparator,
                 flagsForceOverwrite
                );
        VBOX_UTF8_TO_UTF16(createFlags, &createFlagsUtf16);
        rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                                NULL,
                                                machineNameUtf16,
                                                0,
                                                nsnull,
                                                nsnull,
                                                createFlagsUtf16,
                                                machine);
#endif /* VBOX_API_VERSION >= 4002000 */
9545
    }
T
Taowei 已提交
9546 9547 9548 9549
    VBOX_UTF16_FREE(machineNameUtf16);
    vboxIIDUnalloc(&iid);
    return rc;
}
9550

T
Taowei 已提交
9551 9552 9553 9554 9555
static nsresult
_virtualboxRegisterMachine(IVirtualBox *vboxObj, IMachine *machine)
{
    return vboxObj->vtbl->RegisterMachine(vboxObj, machine);
}
9556

T
Taowei 已提交
9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574
static nsresult
_virtualboxFindMedium(IVirtualBox *vboxObj ATTRIBUTE_UNUSED,
                      PRUnichar *location ATTRIBUTE_UNUSED,
                      PRUint32 deviceType ATTRIBUTE_UNUSED,
                      PRUint32 accessMode ATTRIBUTE_UNUSED,
                      IMedium **medium ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
    return vboxObj->vtbl->FindMedium(vboxObj, location,
                                     deviceType, medium);
#elif VBOX_API_VERSION >= 4002000
    return vboxObj->vtbl->OpenMedium(vboxObj, location,
                                     deviceType, accessMode, PR_FALSE, medium);
#else
    vboxUnsupported();
    return 0;
#endif
}
9575

T
Taowei 已提交
9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598
static nsresult
_virtualboxOpenMedium(IVirtualBox *vboxObj ATTRIBUTE_UNUSED,
                      PRUnichar *location ATTRIBUTE_UNUSED,
                      PRUint32 deviceType ATTRIBUTE_UNUSED,
                      PRUint32 accessMode ATTRIBUTE_UNUSED,
                      IMedium **medium ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION == 4000000
    return vboxObj->vtbl->OpenMedium(vboxObj,
                                     location,
                                     deviceType, accessMode,
                                     medium);
#elif VBOX_API_VERSION >= 4001000
    return vboxObj->vtbl->OpenMedium(vboxObj,
                                     location,
                                     deviceType, accessMode,
                                     false,
                                     medium);
#else
    vboxUnsupported();
    return 0;
#endif
}
9599

T
Taowei 已提交
9600 9601 9602 9603 9604 9605 9606 9607
static nsresult
_machineAddStorageController(IMachine *machine, PRUnichar *name,
                             PRUint32 connectionType,
                             IStorageController **controller)
{
    return machine->vtbl->AddStorageController(machine, name, connectionType,
                                               controller);
}
9608

T
Taowei 已提交
9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624
static nsresult
_machineAttachDevice(IMachine *machine ATTRIBUTE_UNUSED,
                     PRUnichar *name ATTRIBUTE_UNUSED,
                     PRInt32 controllerPort ATTRIBUTE_UNUSED,
                     PRInt32 device ATTRIBUTE_UNUSED,
                     PRUint32 type ATTRIBUTE_UNUSED,
                     IMedium * medium ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION >= 4000000
    return machine->vtbl->AttachDevice(machine, name, controllerPort,
                                       device, type, medium);
#else /* VBOX_API_VERSION < 4000000 */
    vboxUnsupported();
    return 0;
#endif /* VBOX_API_VERSION < 4000000 */
}
9625

T
Taowei 已提交
9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638
static nsresult
_machineCreateSharedFolder(IMachine *machine, PRUnichar *name,
                           PRUnichar *hostPath, PRBool writable,
                           PRBool automount ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION < 4000000
    return machine->vtbl->CreateSharedFolder(machine, name, hostPath,
                                             writable);
#else /* VBOX_API_VERSION >= 4000000 */
    return machine->vtbl->CreateSharedFolder(machine, name, hostPath,
                                             writable, automount);
#endif /* VBOX_API_VERSION >= 4000000 */
}
9639

T
Taowei 已提交
9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658
static nsresult
_machineLaunchVMProcess(vboxGlobalData *data,
                        IMachine *machine ATTRIBUTE_UNUSED,
                        vboxIIDUnion *iidu ATTRIBUTE_UNUSED,
                        PRUnichar *sessionType, PRUnichar *env,
                        IProgress **progress)
{
#if VBOX_API_VERSION < 4000000
    return data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                  data->vboxSession,
                                                  IID_MEMBER(value),
                                                  sessionType,
                                                  env,
                                                  progress);
#else /* VBOX_API_VERSION >= 4000000 */
    return machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                          sessionType, env, progress);
#endif /* VBOX_API_VERSION >= 4000000 */
}
9659

T
Taowei 已提交
9660 9661 9662 9663 9664
static nsresult
_machineGetAccessible(IMachine *machine, PRBool *isAccessible)
{
    return machine->vtbl->GetAccessible(machine, isAccessible);
}
9665

T
Taowei 已提交
9666 9667 9668 9669 9670
static nsresult
_machineGetState(IMachine *machine, PRUint32 *state)
{
    return machine->vtbl->GetState(machine, state);
}
9671

T
Taowei 已提交
9672 9673 9674 9675 9676
static nsresult
_machineGetName(IMachine *machine, PRUnichar **name)
{
    return machine->vtbl->GetName(machine, name);
}
9677

T
Taowei 已提交
9678 9679 9680 9681 9682
static nsresult
_machineGetId(IMachine *machine, vboxIIDUnion *iidu)
{
    return machine->vtbl->GetId(machine, &IID_MEMBER(value));
}
9683

T
Taowei 已提交
9684 9685 9686 9687 9688
static nsresult
_machineGetBIOSSettings(IMachine *machine, IBIOSSettings **bios)
{
    return machine->vtbl->GetBIOSSettings(machine, bios);
}
9689

T
Taowei 已提交
9690 9691 9692 9693 9694
static nsresult
_machineGetAudioAdapter(IMachine *machine, IAudioAdapter **audioadapter)
{
    return machine->vtbl->GetAudioAdapter(machine, audioadapter);
}
9695

T
Taowei 已提交
9696 9697 9698 9699 9700
static nsresult
_machineGetNetworkAdapter(IMachine *machine, PRUint32 slot, INetworkAdapter **adapter)
{
    return machine->vtbl->GetNetworkAdapter(machine, slot, adapter);
}
9701

T
Taowei 已提交
9702 9703 9704 9705 9706 9707 9708 9709 9710 9711
static nsresult
_machineGetChipsetType(IMachine *machine ATTRIBUTE_UNUSED, PRUint32 *chipsetType ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION >= 4001000
    return machine->vtbl->GetChipsetType(machine, chipsetType);
#else /* VBOX_API_VERSION < 4001000 */
    vboxUnsupported();
    return 0;
#endif /* VBOX_API_VERSION < 4001000 */
}
9712

T
Taowei 已提交
9713 9714 9715 9716
static nsresult
_machineGetSerialPort(IMachine *machine, PRUint32 slot, ISerialPort **port)
{
    return machine->vtbl->GetSerialPort(machine, slot, port);
9717 9718
}

T
Taowei 已提交
9719 9720 9721 9722 9723
static nsresult
_machineGetParallelPort(IMachine *machine, PRUint32 slot, IParallelPort **port)
{
    return machine->vtbl->GetParallelPort(machine, slot, port);
}
9724

T
Taowei 已提交
9725 9726
static nsresult
_machineGetVRDxServer(IMachine *machine, IVRDxServer **VRDxServer)
9727
{
T
Taowei 已提交
9728 9729 9730 9731 9732
#if VBOX_API_VERSION < 4000000
    return machine->vtbl->GetVRDPServer(machine, VRDxServer);
#else /* VBOX_API_VERSION >= 4000000 */
    return machine->vtbl->GetVRDEServer(machine, VRDxServer);
#endif /* VBOX_API_VERSION >= 4000000 */
9733 9734
}

T
Taowei 已提交
9735 9736 9737 9738 9739 9740 9741 9742 9743
static nsresult
_machineGetUSBCommon(IMachine *machine, IUSBCommon **USBCommon)
{
#if VBOX_API_VERSION < 4003000
    return machine->vtbl->GetUSBController(machine, USBCommon);
#else
    return machine->vtbl->GetUSBDeviceFilters(machine, USBCommon);
#endif
}
9744

T
Taowei 已提交
9745 9746
static nsresult
_machineSetCPUCount(IMachine *machine, PRUint32 CPUCount)
9747
{
T
Taowei 已提交
9748
    return machine->vtbl->SetCPUCount(machine, CPUCount);
9749 9750
}

T
Taowei 已提交
9751 9752 9753 9754 9755
static nsresult
_machineSetMemorySize(IMachine *machine, PRUint32 memorySize)
{
    return machine->vtbl->SetMemorySize(machine, memorySize);
}
9756

T
Taowei 已提交
9757 9758
static nsresult
_machineSetCPUProperty(IMachine *machine, PRUint32 property ATTRIBUTE_UNUSED, PRBool value)
9759
{
T
Taowei 已提交
9760 9761 9762 9763 9764 9765 9766
#if VBOX_API_VERSION < 3001000
    return machine->vtbl->SetPAEEnabled(machine, value);
#elif VBOX_API_VERSION == 3001000
    return machine->vtbl->SetCpuProperty(machine, property, value);
#elif VBOX_API_VERSION >= 3002000
    return machine->vtbl->SetCPUProperty(machine, property, value);
#endif
9767 9768
}

T
Taowei 已提交
9769 9770 9771 9772 9773
static nsresult
_machineSetBootOrder(IMachine *machine, PRUint32 position, PRUint32 device)
{
    return machine->vtbl->SetBootOrder(machine, position, device);
}
9774

T
Taowei 已提交
9775 9776
static nsresult
_machineSetVRAMSize(IMachine *machine, PRUint32 VRAMSize)
9777
{
T
Taowei 已提交
9778 9779
    return machine->vtbl->SetVRAMSize(machine, VRAMSize);
}
9780

T
Taowei 已提交
9781 9782 9783 9784
static nsresult
_machineSetMonitorCount(IMachine *machine, PRUint32 monitorCount)
{
    return machine->vtbl->SetMonitorCount(machine, monitorCount);
9785 9786
}

T
Taowei 已提交
9787 9788
static nsresult
_machineSetAccelerate3DEnabled(IMachine *machine, PRBool accelerate3DEnabled)
T
Taowei 已提交
9789
{
T
Taowei 已提交
9790
    return machine->vtbl->SetAccelerate3DEnabled(machine, accelerate3DEnabled);
T
Taowei 已提交
9791 9792
}

T
Taowei 已提交
9793 9794 9795
static nsresult
_machineSetAccelerate2DVideoEnabled(IMachine *machine ATTRIBUTE_UNUSED,
                                    PRBool accelerate2DVideoEnabled ATTRIBUTE_UNUSED)
T
Taowei 已提交
9796
{
T
Taowei 已提交
9797 9798 9799
#if VBOX_API_VERSION >= 3001000
    return machine->vtbl->SetAccelerate2DVideoEnabled(machine, accelerate2DVideoEnabled);
#else /* VBOX_API_VERSION < 3001000 */
T
Taowei 已提交
9800 9801
    vboxUnsupported();
    return 0;
T
Taowei 已提交
9802
#endif /* VBOX_API_VERSION < 3001000 */
T
Taowei 已提交
9803 9804
}

T
Taowei 已提交
9805 9806 9807 9808 9809 9810
static nsresult
_machineGetExtraData(IMachine *machine, PRUnichar *key, PRUnichar **value)
{
    return machine->vtbl->GetExtraData(machine, key, value);
}

T
Taowei 已提交
9811 9812
static nsresult
_machineSetExtraData(IMachine *machine, PRUnichar *key, PRUnichar *value)
T
Taowei 已提交
9813
{
T
Taowei 已提交
9814 9815 9816 9817 9818 9819 9820
    return machine->vtbl->SetExtraData(machine, key, value);
}

static nsresult
_machineSaveSettings(IMachine *machine)
{
    return machine->vtbl->SaveSettings(machine);
T
Taowei 已提交
9821 9822
}

T
Taowei 已提交
9823 9824
#if VBOX_API_VERSION < 4000000

T
Taowei 已提交
9825 9826
static nsresult
_sessionOpen(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED)
T
Taowei 已提交
9827
{
T
Taowei 已提交
9828
    return data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, IID_MEMBER(value));
T
Taowei 已提交
9829
}
T
Taowei 已提交
9830 9831 9832

static nsresult
_sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED)
T
Taowei 已提交
9833
{
T
Taowei 已提交
9834 9835
    return data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, IID_MEMBER(value));
}
T
Taowei 已提交
9836

T
Taowei 已提交
9837 9838 9839 9840 9841
static nsresult
_sessionClose(ISession *session)
{
    return session->vtbl->Close(session);
}
T
Taowei 已提交
9842

T
Taowei 已提交
9843
#else /* VBOX_API_VERSION >= 4000000 */
T
Taowei 已提交
9844

T
Taowei 已提交
9845 9846 9847 9848 9849
static nsresult
_sessionOpen(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine)
{
    return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write);
}
T
Taowei 已提交
9850

T
Taowei 已提交
9851 9852 9853 9854 9855
static nsresult
_sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine)
{
    return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared);
}
T
Taowei 已提交
9856

T
Taowei 已提交
9857 9858 9859 9860 9861
static nsresult
_sessionClose(ISession *session)
{
    return session->vtbl->UnlockMachine(session);
}
T
Taowei 已提交
9862

T
Taowei 已提交
9863
#endif /* VBOX_API_VERSION >= 4000000 */
T
Taowei 已提交
9864

T
Taowei 已提交
9865 9866 9867 9868 9869
static nsresult
_sessionGetConsole(ISession *session, IConsole **console)
{
    return session->vtbl->GetConsole(session, console);
}
T
Taowei 已提交
9870

T
Taowei 已提交
9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882
static nsresult
_sessionGetMachine(ISession *session, IMachine **machine)
{
    return session->vtbl->GetMachine(session, machine);
}

static nsresult
_consoleSaveState(IConsole *console, IProgress **progress)
{
    return console->vtbl->SaveState(console, progress);
}

T
Taowei 已提交
9883 9884 9885 9886 9887 9888
static nsresult
_consolePause(IConsole *console)
{
    return console->vtbl->Pause(console);
}

T
Taowei 已提交
9889 9890 9891 9892 9893 9894
static nsresult
_consoleResume(IConsole *console)
{
    return console->vtbl->Resume(console);
}

T
Taowei 已提交
9895 9896 9897 9898 9899 9900
static nsresult
_consolePowerButton(IConsole *console)
{
    return console->vtbl->PowerButton(console);
}

T
Taowei 已提交
9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916
static nsresult
_progressWaitForCompletion(IProgress *progress, PRInt32 timeout)
{
    return progress->vtbl->WaitForCompletion(progress, timeout);
}

static nsresult
_progressGetResultCode(IProgress *progress, resultCodeUnion *resultCode)
{
#if VBOX_API_VERSION == 2002000
    return progress->vtbl->GetResultCode(progress, &resultCode->uResultCode);
#else /* VBOX_API_VERSION != 2002000 */
    return progress->vtbl->GetResultCode(progress, &resultCode->resultCode);
#endif /* VBOX_API_VERSION != 2002000 */
}

T
Taowei 已提交
9917 9918 9919 9920 9921 9922
static nsresult
_progressGetCompleted(IProgress *progress, PRBool *completed)
{
    return progress->vtbl->GetCompleted(progress, completed);
}

T
Taowei 已提交
9923 9924 9925 9926
static nsresult
_systemPropertiesGetMaxGuestCPUCount(ISystemProperties *systemProperties, PRUint32 *maxCPUCount)
{
    return systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, maxCPUCount);
T
Taowei 已提交
9927 9928 9929
}

static nsresult
T
Taowei 已提交
9930
_systemPropertiesGetMaxBootPosition(ISystemProperties *systemProperties, PRUint32 *maxBootPosition)
T
Taowei 已提交
9931
{
T
Taowei 已提交
9932
    return systemProperties->vtbl->GetMaxBootPosition(systemProperties, maxBootPosition);
T
Taowei 已提交
9933 9934
}

T
Taowei 已提交
9935 9936 9937
static nsresult
_systemPropertiesGetMaxNetworkAdapters(ISystemProperties *systemProperties, PRUint32 chipset ATTRIBUTE_UNUSED,
                                       PRUint32 *maxNetworkAdapters)
T
Taowei 已提交
9938
{
T
Taowei 已提交
9939 9940 9941 9942 9943 9944 9945
#if VBOX_API_VERSION < 4001000
        return systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                              maxNetworkAdapters);
#else  /* VBOX_API_VERSION >= 4000000 */
        return systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipset,
                                                             maxNetworkAdapters);
#endif /* VBOX_API_VERSION >= 4000000 */
T
Taowei 已提交
9946 9947
}

T
Taowei 已提交
9948 9949
static nsresult
_systemPropertiesGetSerialPortCount(ISystemProperties *systemProperties, PRUint32 *SerialPortCount)
T
Taowei 已提交
9950
{
T
Taowei 已提交
9951
    return systemProperties->vtbl->GetSerialPortCount(systemProperties, SerialPortCount);
T
Taowei 已提交
9952 9953 9954
}

static nsresult
T
Taowei 已提交
9955
_systemPropertiesGetParallelPortCount(ISystemProperties *systemProperties, PRUint32 *ParallelPortCount)
T
Taowei 已提交
9956
{
T
Taowei 已提交
9957 9958
    return systemProperties->vtbl->GetParallelPortCount(systemProperties, ParallelPortCount);
}
T
Taowei 已提交
9959

T
Taowei 已提交
9960 9961 9962 9963 9964 9965
#if VBOX_API_VERSION >= 3001000
static nsresult
_systemPropertiesGetMaxPortCountForStorageBus(ISystemProperties *systemProperties, PRUint32 bus,
                                              PRUint32 *maxPortCount)
{
    return systemProperties->vtbl->GetMaxPortCountForStorageBus(systemProperties, bus, maxPortCount);
T
Taowei 已提交
9966 9967
}

T
Taowei 已提交
9968 9969 9970
static nsresult
_systemPropertiesGetMaxDevicesPerPortForStorageBus(ISystemProperties *systemProperties,
                                                   PRUint32 bus, PRUint32 *maxDevicesPerPort)
T
Taowei 已提交
9971
{
T
Taowei 已提交
9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983
    return systemProperties->vtbl->GetMaxDevicesPerPortForStorageBus(systemProperties,
                                                                     bus, maxDevicesPerPort);
}
#else /* VBOX_API_VERSION < 3001000 */
static nsresult
_systemPropertiesGetMaxPortCountForStorageBus(ISystemProperties *systemProperties ATTRIBUTE_UNUSED,
                                              PRUint32 bus ATTRIBUTE_UNUSED,
                                              PRUint32 *maxPortCount ATTRIBUTE_UNUSED)
{
    vboxUnsupported();
    return 0;
}
T
Taowei 已提交
9984

T
Taowei 已提交
9985 9986 9987 9988 9989 9990 9991 9992 9993
static nsresult
_systemPropertiesGetMaxDevicesPerPortForStorageBus(ISystemProperties *systemProperties ATTRIBUTE_UNUSED,
                                                   PRUint32 bus ATTRIBUTE_UNUSED,
                                                   PRUint32 *maxDevicesPerPort ATTRIBUTE_UNUSED)
{
    vboxUnsupported();
    return 0;
}
#endif
T
Taowei 已提交
9994

T
Taowei 已提交
9995 9996 9997 9998
static nsresult
_biosSettingsSetACPIEnabled(IBIOSSettings *bios, PRBool ACPIEnabled)
{
    return bios->vtbl->SetACPIEnabled(bios, ACPIEnabled);
T
Taowei 已提交
9999 10000
}

T
Taowei 已提交
10001 10002 10003 10004 10005
static nsresult
_biosSettingsSetIOAPICEnabled(IBIOSSettings *bios, PRBool IOAPICEnabled)
{
    return bios->vtbl->SetIOAPICEnabled(bios, IOAPICEnabled);
}
T
Taowei 已提交
10006

T
Taowei 已提交
10007 10008
static nsresult
_audioAdapterSetEnabled(IAudioAdapter *audioAdapter, PRBool enabled)
T
Taowei 已提交
10009
{
T
Taowei 已提交
10010
    return audioAdapter->vtbl->SetEnabled(audioAdapter, enabled);
T
Taowei 已提交
10011 10012
}

T
Taowei 已提交
10013 10014
static nsresult
_audioAdapterSetAudioController(IAudioAdapter *audioAdapter, PRUint32 audioController)
T
Taowei 已提交
10015
{
T
Taowei 已提交
10016
    return audioAdapter->vtbl->SetAudioController(audioAdapter, audioController);
T
Taowei 已提交
10017 10018
}

T
Taowei 已提交
10019 10020
static nsresult
_networkAdapterSetEnabled(INetworkAdapter *adapter, PRBool enabled)
T
Taowei 已提交
10021
{
T
Taowei 已提交
10022
    return adapter->vtbl->SetEnabled(adapter, enabled);
T
Taowei 已提交
10023 10024
}

T
Taowei 已提交
10025 10026
static nsresult
_networkAdapterSetAdapterType(INetworkAdapter *adapter, PRUint32 adapterType)
T
Taowei 已提交
10027
{
T
Taowei 已提交
10028
    return adapter->vtbl->SetAdapterType(adapter, adapterType);
T
Taowei 已提交
10029 10030
}

T
Taowei 已提交
10031 10032
static nsresult
_networkAdapterSetInternalNetwork(INetworkAdapter *adapter, PRUnichar *internalNetwork)
T
Taowei 已提交
10033
{
T
Taowei 已提交
10034
    return adapter->vtbl->SetInternalNetwork(adapter, internalNetwork);
T
Taowei 已提交
10035 10036
}

T
Taowei 已提交
10037 10038
static nsresult
_networkAdapterSetMACAddress(INetworkAdapter *adapter, PRUnichar *MACAddress)
T
Taowei 已提交
10039
{
T
Taowei 已提交
10040
    return adapter->vtbl->SetMACAddress(adapter, MACAddress);
T
Taowei 已提交
10041 10042
}

T
Taowei 已提交
10043
#if VBOX_API_VERSION < 4001000
T
Taowei 已提交
10044

T
Taowei 已提交
10045 10046
static nsresult
_networkAdapterSetBridgedInterface(INetworkAdapter *adapter, PRUnichar *hostInterface)
T
Taowei 已提交
10047
{
T
Taowei 已提交
10048
    return adapter->vtbl->SetHostInterface(adapter, hostInterface);
T
Taowei 已提交
10049 10050
}

T
Taowei 已提交
10051 10052
static nsresult
_networkAdapterSetHostOnlyInterface(INetworkAdapter *adapter, PRUnichar *hostOnlyInterface)
T
Taowei 已提交
10053
{
T
Taowei 已提交
10054
    return adapter->vtbl->SetHostInterface(adapter, hostOnlyInterface);
T
Taowei 已提交
10055 10056
}

T
Taowei 已提交
10057 10058
static nsresult
_networkAdapterAttachToBridgedInterface(INetworkAdapter *adapter)
T
Taowei 已提交
10059
{
T
Taowei 已提交
10060
    return adapter->vtbl->AttachToBridgedInterface(adapter);
T
Taowei 已提交
10061 10062
}

T
Taowei 已提交
10063 10064
static nsresult
_networkAdapterAttachToInternalNetwork(INetworkAdapter *adapter)
T
Taowei 已提交
10065
{
T
Taowei 已提交
10066
    return adapter->vtbl->AttachToInternalNetwork(adapter);
T
Taowei 已提交
10067 10068
}

T
Taowei 已提交
10069 10070 10071 10072 10073
static nsresult
_networkAdapterAttachToHostOnlyInterface(INetworkAdapter *adapter)
{
    return adapter->vtbl->AttachToHostOnlyInterface(adapter);
}
T
Taowei 已提交
10074

T
Taowei 已提交
10075 10076
static nsresult
_networkAdapterAttachToNAT(INetworkAdapter *adapter)
T
Taowei 已提交
10077
{
T
Taowei 已提交
10078
    return adapter->vtbl->AttachToNAT(adapter);
T
Taowei 已提交
10079 10080
}

T
Taowei 已提交
10081 10082 10083 10084
#else /* VBOX_API_VERSION >= 4001000 */

static nsresult
_networkAdapterSetBridgedInterface(INetworkAdapter *adapter, PRUnichar *bridgedInterface)
T
Taowei 已提交
10085
{
T
Taowei 已提交
10086
    return adapter->vtbl->SetBridgedInterface(adapter, bridgedInterface);
T
Taowei 已提交
10087 10088
}

T
Taowei 已提交
10089
static nsresult
T
Taowei 已提交
10090
_networkAdapterSetHostOnlyInterface(INetworkAdapter *adapter, PRUnichar *hostOnlyInterface)
T
Taowei 已提交
10091
{
T
Taowei 已提交
10092
    return adapter->vtbl->SetHostOnlyInterface(adapter, hostOnlyInterface);
T
Taowei 已提交
10093 10094
}

T
Taowei 已提交
10095 10096 10097 10098 10099
static nsresult
_networkAdapterAttachToBridgedInterface(INetworkAdapter *adapter)
{
    return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
}
T
Taowei 已提交
10100 10101

static nsresult
T
Taowei 已提交
10102
_networkAdapterAttachToInternalNetwork(INetworkAdapter *adapter)
T
Taowei 已提交
10103
{
T
Taowei 已提交
10104
    return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
T
Taowei 已提交
10105 10106
}

T
Taowei 已提交
10107 10108 10109 10110 10111
static nsresult
_networkAdapterAttachToHostOnlyInterface(INetworkAdapter *adapter)
{
    return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
}
T
Taowei 已提交
10112 10113

static nsresult
T
Taowei 已提交
10114
_networkAdapterAttachToNAT(INetworkAdapter *adapter)
T
Taowei 已提交
10115
{
T
Taowei 已提交
10116
    return adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
T
Taowei 已提交
10117 10118
}

T
Taowei 已提交
10119
#endif /* VBOX_API_VERSION >= 4001000 */
T
Taowei 已提交
10120

T
Taowei 已提交
10121
static nsresult
T
Taowei 已提交
10122
_serialPortSetEnabled(ISerialPort *port, PRBool enabled)
T
Taowei 已提交
10123
{
T
Taowei 已提交
10124
    return port->vtbl->SetEnabled(port, enabled);
T
Taowei 已提交
10125 10126
}

T
Taowei 已提交
10127
static nsresult
T
Taowei 已提交
10128
_serialPortSetPath(ISerialPort *port, PRUnichar *path)
T
Taowei 已提交
10129
{
T
Taowei 已提交
10130
    return port->vtbl->SetPath(port, path);
T
Taowei 已提交
10131 10132 10133
}

static nsresult
T
Taowei 已提交
10134
_serialPortSetIRQ(ISerialPort *port, PRUint32 IRQ)
T
Taowei 已提交
10135
{
T
Taowei 已提交
10136
    return port->vtbl->SetIRQ(port, IRQ);
T
Taowei 已提交
10137 10138
}

T
Taowei 已提交
10139
static nsresult
T
Taowei 已提交
10140
_serialPortSetIOBase(ISerialPort *port, PRUint32 IOBase)
T
Taowei 已提交
10141
{
T
Taowei 已提交
10142
    return port->vtbl->SetIOBase(port, IOBase);
T
Taowei 已提交
10143 10144 10145
}

static nsresult
T
Taowei 已提交
10146
_serialPortSetHostMode(ISerialPort *port, PRUint32 hostMode)
T
Taowei 已提交
10147
{
T
Taowei 已提交
10148
    return port->vtbl->SetHostMode(port, hostMode);
T
Taowei 已提交
10149 10150
}

T
Taowei 已提交
10151
static nsresult
T
Taowei 已提交
10152
_parallelPortSetEnabled(IParallelPort *port, PRBool enabled)
T
Taowei 已提交
10153
{
T
Taowei 已提交
10154
    return port->vtbl->SetEnabled(port, enabled);
T
Taowei 已提交
10155 10156 10157
}

static nsresult
T
Taowei 已提交
10158
_parallelPortSetPath(IParallelPort *port, PRUnichar *path)
T
Taowei 已提交
10159
{
T
Taowei 已提交
10160
    return port->vtbl->SetPath(port, path);
T
Taowei 已提交
10161 10162
}

T
Taowei 已提交
10163
static nsresult
T
Taowei 已提交
10164
_parallelPortSetIRQ(IParallelPort *port, PRUint32 IRQ)
T
Taowei 已提交
10165
{
T
Taowei 已提交
10166
    return port->vtbl->SetIRQ(port, IRQ);
T
Taowei 已提交
10167 10168 10169
}

static nsresult
T
Taowei 已提交
10170
_parallelPortSetIOBase(IParallelPort *port, PRUint32 IOBase)
T
Taowei 已提交
10171
{
T
Taowei 已提交
10172
    return port->vtbl->SetIOBase(port, IOBase);
T
Taowei 已提交
10173 10174
}

T
Taowei 已提交
10175 10176 10177 10178 10179
static nsresult
_vrdxServerSetEnabled(IVRDxServer *VRDxServer, PRBool enabled)
{
    return VRDxServer->vtbl->SetEnabled(VRDxServer, enabled);
}
T
Taowei 已提交
10180

T
Taowei 已提交
10181
static nsresult
T
Taowei 已提交
10182 10183
_vrdxServerSetPorts(vboxGlobalData *data ATTRIBUTE_UNUSED,
                    IVRDxServer *VRDxServer, virDomainGraphicsDefPtr graphics)
T
Taowei 已提交
10184
{
T
Taowei 已提交
10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214
    nsresult rc = 0;
#if VBOX_API_VERSION < 3001000
    if (graphics->data.rdp.port) {
        rc = VRDxServer->vtbl->SetPort(VRDxServer,
                                       graphics->data.rdp.port);
        VIR_DEBUG("VRDP Port changed to: %d",
                  graphics->data.rdp.port);
    } else if (graphics->data.rdp.autoport) {
        /* Setting the port to 0 will reset its value to
         * the default one which is 3389 currently
         */
        rc = VRDxServer->vtbl->SetPort(VRDxServer, 0);
        VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
    }
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
    PRUnichar *portUtf16 = NULL;
    portUtf16 = PRUnicharFromInt(graphics->data.rdp.port);
    rc = VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
    VBOX_UTF16_FREE(portUtf16);
#else /* VBOX_API_VERSION >= 4000000 */
    PRUnichar *VRDEPortsKey = NULL;
    PRUnichar *VRDEPortsValue = NULL;
    VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
    VRDEPortsValue = PRUnicharFromInt(graphics->data.rdp.port);
    rc = VRDxServer->vtbl->SetVRDEProperty(VRDxServer, VRDEPortsKey,
                                           VRDEPortsValue);
    VBOX_UTF16_FREE(VRDEPortsKey);
    VBOX_UTF16_FREE(VRDEPortsValue);
#endif /* VBOX_API_VERSION >= 4000000 */
    return rc;
T
Taowei 已提交
10215 10216
}

T
Taowei 已提交
10217
static nsresult
T
Taowei 已提交
10218
_vrdxServerSetReuseSingleConnection(IVRDxServer *VRDxServer, PRBool enabled)
T
Taowei 已提交
10219
{
T
Taowei 已提交
10220
    return VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer, enabled);
T
Taowei 已提交
10221 10222 10223
}

static nsresult
T
Taowei 已提交
10224
_vrdxServerSetAllowMultiConnection(IVRDxServer *VRDxServer, PRBool enabled)
T
Taowei 已提交
10225
{
T
Taowei 已提交
10226
    return VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer, enabled);
T
Taowei 已提交
10227 10228
}

T
Taowei 已提交
10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243
static nsresult
_vrdxServerSetNetAddress(vboxGlobalData *data ATTRIBUTE_UNUSED,
                         IVRDxServer *VRDxServer, PRUnichar *netAddress)
{
#if VBOX_API_VERSION < 4000000
    return VRDxServer->vtbl->SetNetAddress(VRDxServer,
                                           netAddress);
#else /* VBOX_API_VERSION >= 4000000 */
    PRUnichar *netAddressKey = NULL;
    nsresult rc;
    VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
    rc = VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
                                           netAddress);
    VBOX_UTF16_FREE(netAddressKey);
    return rc;
T
Taowei 已提交
10244
#endif /* VBOX_API_VERSION >= 4000000 */
T
Taowei 已提交
10245
}
T
Taowei 已提交
10246 10247

static nsresult
T
Taowei 已提交
10248
_usbCommonEnable(IUSBCommon *USBCommon ATTRIBUTE_UNUSED)
T
Taowei 已提交
10249
{
T
Taowei 已提交
10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260
    nsresult rc = 0;
#if VBOX_API_VERSION < 4003000
    USBCommon->vtbl->SetEnabled(USBCommon, 1);
# if VBOX_API_VERSION < 4002000
    rc = USBCommon->vtbl->SetEnabledEhci(USBCommon, 1);
# else /* VBOX_API_VERSION >= 4002000 */
    rc = USBCommon->vtbl->SetEnabledEHCI(USBCommon, 1);
# endif /* VBOX_API_VERSION >= 4002000 */
#endif /* VBOX_API_VERSION >= 4003000 */
    /* We don't need to set usb enabled for vbox 4.3 and later */
    return rc;
T
Taowei 已提交
10261 10262
}

T
Taowei 已提交
10263
static nsresult
T
Taowei 已提交
10264 10265
_usbCommonCreateDeviceFilter(IUSBCommon *USBCommon, PRUnichar *name,
                             IUSBDeviceFilter **filter)
T
Taowei 已提交
10266
{
T
Taowei 已提交
10267
    return USBCommon->vtbl->CreateDeviceFilter(USBCommon, name, filter);
T
Taowei 已提交
10268 10269
}

T
Taowei 已提交
10270
static nsresult
T
Taowei 已提交
10271 10272
_usbCommonInsertDeviceFilter(IUSBCommon *USBCommon, PRUint32 position,
                             IUSBDeviceFilter *filter)
T
Taowei 已提交
10273
{
T
Taowei 已提交
10274
    return USBCommon->vtbl->InsertDeviceFilter(USBCommon, position, filter);
T
Taowei 已提交
10275 10276 10277
}

static nsresult
T
Taowei 已提交
10278
_usbDeviceFilterSetProductId(IUSBDeviceFilter *USBDeviceFilter, PRUnichar *productId)
T
Taowei 已提交
10279
{
T
Taowei 已提交
10280
    return USBDeviceFilter->vtbl->SetProductId(USBDeviceFilter, productId);
T
Taowei 已提交
10281 10282 10283
}

static nsresult
T
Taowei 已提交
10284
_usbDeviceFilterSetActive(IUSBDeviceFilter *USBDeviceFilter, PRBool active)
T
Taowei 已提交
10285
{
T
Taowei 已提交
10286
    return USBDeviceFilter->vtbl->SetActive(USBDeviceFilter, active);
T
Taowei 已提交
10287 10288
}

T
Taowei 已提交
10289
static nsresult
T
Taowei 已提交
10290
_usbDeviceFilterSetVendorId(IUSBDeviceFilter *USBDeviceFilter, PRUnichar *vendorId)
T
Taowei 已提交
10291
{
T
Taowei 已提交
10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313
    return USBDeviceFilter->vtbl->SetVendorId(USBDeviceFilter, vendorId);
}

static nsresult _mediumGetId(IMedium *medium, vboxIIDUnion *iidu)
{
    return medium->vtbl->GetId(medium, &IID_MEMBER(value));
}

static nsresult _mediumRelease(IMedium *medium)
{
    return medium->vtbl->nsisupports.Release((nsISupports *)medium);
}

static nsresult _mediumSetType(IMedium *medium ATTRIBUTE_UNUSED,
                               PRUint32 type ATTRIBUTE_UNUSED)
{
#if VBOX_API_VERSION > 3000000
    return medium->vtbl->SetType(medium, type);
#else
    vboxUnsupported();
    return 0;
#endif
T
Taowei 已提交
10314 10315
}

T
Taowei 已提交
10316 10317 10318 10319 10320 10321
static bool _machineStateOnline(PRUint32 state)
{
    return ((state >= MachineState_FirstOnline) &&
            (state <= MachineState_LastOnline));
}

T
Taowei 已提交
10322 10323 10324 10325 10326 10327 10328
static bool _machineStateNotStart(PRUint32 state)
{
    return ((state == MachineState_PoweredOff) ||
            (state == MachineState_Saved) ||
            (state == MachineState_Aborted));
}

T
Taowei 已提交
10329 10330 10331 10332 10333
static bool _machineStateRunning(PRUint32 state)
{
    return state == MachineState_Running;
}

T
Taowei 已提交
10334 10335 10336 10337 10338
static bool _machineStatePaused(PRUint32 state)
{
    return state == MachineState_Paused;
}

T
Taowei 已提交
10339 10340 10341 10342 10343
static bool _machineStatePoweredOff(PRUint32 state)
{
    return state == MachineState_PoweredOff;
}

T
Taowei 已提交
10344 10345 10346 10347 10348 10349 10350 10351 10352 10353
static vboxUniformedPFN _UPFN = {
    .Initialize = _pfnInitialize,
    .Uninitialize = _pfnUninitialize,
    .ComUnallocMem = _pfnComUnallocMem,
    .Utf16Free = _pfnUtf16Free,
    .Utf8Free = _pfnUtf8Free,
    .Utf16ToUtf8 = _pfnUtf16ToUtf8,
    .Utf8ToUtf16 = _pfnUtf8ToUtf16,
};

T
Taowei 已提交
10354 10355 10356 10357 10358 10359 10360 10361 10362 10363
static vboxUniformedIID _UIID = {
    .vboxIIDInitialize = _vboxIIDInitialize,
    .vboxIIDUnalloc = _vboxIIDUnalloc,
    .vboxIIDToUUID = _vboxIIDToUUID,
    .vboxIIDFromUUID = _vboxIIDFromUUID,
    .vboxIIDIsEqual = _vboxIIDIsEqual,
    .vboxIIDFromArrayItem = _vboxIIDFromArrayItem,
    .DEBUGIID = _DEBUGIID,
};

T
Taowei 已提交
10364 10365 10366 10367 10368 10369
static vboxUniformedArray _UArray = {
    .vboxArrayGet = vboxArrayGet,
    .vboxArrayRelease = vboxArrayRelease,
    .handleGetMachines = _handleGetMachines,
};

T
Taowei 已提交
10370 10371 10372 10373
static vboxUniformednsISupports _nsUISupports = {
    .Release = _nsisupportsRelease,
};

T
Taowei 已提交
10374 10375
static vboxUniformedIVirtualBox _UIVirtualBox = {
    .GetVersion = _virtualboxGetVersion,
T
Taowei 已提交
10376
    .GetMachine = _virtualboxGetMachine,
T
Taowei 已提交
10377
    .GetSystemProperties = _virtualboxGetSystemProperties,
T
Taowei 已提交
10378 10379 10380 10381
    .CreateMachine = _virtualboxCreateMachine,
    .RegisterMachine = _virtualboxRegisterMachine,
    .FindMedium = _virtualboxFindMedium,
    .OpenMedium = _virtualboxOpenMedium,
T
Taowei 已提交
10382 10383
};

T
Taowei 已提交
10384
static vboxUniformedIMachine _UIMachine = {
T
Taowei 已提交
10385 10386 10387
    .AddStorageController = _machineAddStorageController,
    .AttachDevice = _machineAttachDevice,
    .CreateSharedFolder = _machineCreateSharedFolder,
T
Taowei 已提交
10388
    .LaunchVMProcess = _machineLaunchVMProcess,
T
Taowei 已提交
10389 10390
    .GetAccessible = _machineGetAccessible,
    .GetState = _machineGetState,
T
Taowei 已提交
10391 10392
    .GetName = _machineGetName,
    .GetId = _machineGetId,
T
Taowei 已提交
10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408
    .GetBIOSSettings = _machineGetBIOSSettings,
    .GetAudioAdapter = _machineGetAudioAdapter,
    .GetNetworkAdapter = _machineGetNetworkAdapter,
    .GetChipsetType = _machineGetChipsetType,
    .GetSerialPort = _machineGetSerialPort,
    .GetParallelPort = _machineGetParallelPort,
    .GetVRDxServer = _machineGetVRDxServer,
    .GetUSBCommon = _machineGetUSBCommon,
    .SetCPUCount = _machineSetCPUCount,
    .SetMemorySize = _machineSetMemorySize,
    .SetCPUProperty = _machineSetCPUProperty,
    .SetBootOrder = _machineSetBootOrder,
    .SetVRAMSize = _machineSetVRAMSize,
    .SetMonitorCount = _machineSetMonitorCount,
    .SetAccelerate3DEnabled = _machineSetAccelerate3DEnabled,
    .SetAccelerate2DVideoEnabled = _machineSetAccelerate2DVideoEnabled,
T
Taowei 已提交
10409
    .GetExtraData = _machineGetExtraData,
T
Taowei 已提交
10410
    .SetExtraData = _machineSetExtraData,
T
Taowei 已提交
10411
    .SaveSettings = _machineSaveSettings,
T
Taowei 已提交
10412 10413
};

T
Taowei 已提交
10414
static vboxUniformedISession _UISession = {
T
Taowei 已提交
10415
    .Open = _sessionOpen,
T
Taowei 已提交
10416 10417
    .OpenExisting = _sessionOpenExisting,
    .GetConsole = _sessionGetConsole,
T
Taowei 已提交
10418
    .GetMachine = _sessionGetMachine,
T
Taowei 已提交
10419 10420 10421 10422 10423
    .Close = _sessionClose,
};

static vboxUniformedIConsole _UIConsole = {
    .SaveState = _consoleSaveState,
T
Taowei 已提交
10424
    .Pause = _consolePause,
T
Taowei 已提交
10425
    .Resume = _consoleResume,
T
Taowei 已提交
10426
    .PowerButton = _consolePowerButton,
T
Taowei 已提交
10427 10428 10429 10430 10431
};

static vboxUniformedIProgress _UIProgress = {
    .WaitForCompletion = _progressWaitForCompletion,
    .GetResultCode = _progressGetResultCode,
T
Taowei 已提交
10432
    .GetCompleted = _progressGetCompleted,
T
Taowei 已提交
10433 10434
};

T
Taowei 已提交
10435 10436
static vboxUniformedISystemProperties _UISystemProperties = {
    .GetMaxGuestCPUCount = _systemPropertiesGetMaxGuestCPUCount,
T
Taowei 已提交
10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506
    .GetMaxBootPosition = _systemPropertiesGetMaxBootPosition,
    .GetMaxNetworkAdapters = _systemPropertiesGetMaxNetworkAdapters,
    .GetSerialPortCount = _systemPropertiesGetSerialPortCount,
    .GetParallelPortCount = _systemPropertiesGetParallelPortCount,
    .GetMaxPortCountForStorageBus = _systemPropertiesGetMaxPortCountForStorageBus,
    .GetMaxDevicesPerPortForStorageBus = _systemPropertiesGetMaxDevicesPerPortForStorageBus,
};

static vboxUniformedIBIOSSettings _UIBIOSSettings = {
    .SetACPIEnabled = _biosSettingsSetACPIEnabled,
    .SetIOAPICEnabled = _biosSettingsSetIOAPICEnabled,
};

static vboxUniformedIAudioAdapter _UIAudioAdapter = {
    .SetEnabled = _audioAdapterSetEnabled,
    .SetAudioController = _audioAdapterSetAudioController,
};

static vboxUniformedINetworkAdapter _UINetworkAdapter = {
    .SetEnabled = _networkAdapterSetEnabled,
    .SetAdapterType = _networkAdapterSetAdapterType,
    .SetBridgedInterface = _networkAdapterSetBridgedInterface,
    .SetInternalNetwork = _networkAdapterSetInternalNetwork,
    .SetHostOnlyInterface = _networkAdapterSetHostOnlyInterface,
    .SetMACAddress = _networkAdapterSetMACAddress,
    .AttachToBridgedInterface = _networkAdapterAttachToBridgedInterface,
    .AttachToInternalNetwork = _networkAdapterAttachToInternalNetwork,
    .AttachToHostOnlyInterface = _networkAdapterAttachToHostOnlyInterface,
    .AttachToNAT = _networkAdapterAttachToNAT,
};

static vboxUniformedISerialPort _UISerialPort = {
    .SetEnabled = _serialPortSetEnabled,
    .SetPath = _serialPortSetPath,
    .SetIRQ = _serialPortSetIRQ,
    .SetIOBase = _serialPortSetIOBase,
    .SetHostMode = _serialPortSetHostMode,
};

static vboxUniformedIParallelPort _UIParallelPort = {
    .SetEnabled = _parallelPortSetEnabled,
    .SetPath = _parallelPortSetPath,
    .SetIRQ = _parallelPortSetIRQ,
    .SetIOBase = _parallelPortSetIOBase,
};

static vboxUniformedIVRDxServer _UIVRDxServer = {
    .SetEnabled = _vrdxServerSetEnabled,
    .SetPorts = _vrdxServerSetPorts,
    .SetReuseSingleConnection = _vrdxServerSetReuseSingleConnection,
    .SetAllowMultiConnection = _vrdxServerSetAllowMultiConnection,
    .SetNetAddress = _vrdxServerSetNetAddress,
};

static vboxUniformedIUSBCommon _UIUSBCommon = {
    .Enable = _usbCommonEnable,
    .CreateDeviceFilter = _usbCommonCreateDeviceFilter,
    .InsertDeviceFilter = _usbCommonInsertDeviceFilter,
};

static vboxUniformedIUSBDeviceFilter _UIUSBDeviceFilter = {
    .SetProductId = _usbDeviceFilterSetProductId,
    .SetActive = _usbDeviceFilterSetActive,
    .SetVendorId = _usbDeviceFilterSetVendorId,
};

static vboxUniformedIMedium _UIMedium = {
    .GetId = _mediumGetId,
    .Release = _mediumRelease,
    .SetType = _mediumSetType,
T
Taowei 已提交
10507 10508
};

T
Taowei 已提交
10509 10510
static uniformedMachineStateChecker _machineStateChecker = {
    .Online = _machineStateOnline,
T
Taowei 已提交
10511
    .NotStart = _machineStateNotStart,
T
Taowei 已提交
10512
    .Running = _machineStateRunning,
T
Taowei 已提交
10513
    .Paused = _machineStatePaused,
T
Taowei 已提交
10514
    .PoweredOff = _machineStatePoweredOff,
T
Taowei 已提交
10515 10516
};

T
Taowei 已提交
10517 10518 10519 10520 10521 10522
void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
{
    pVBoxAPI->APIVersion = VBOX_API_VERSION;
    pVBoxAPI->XPCOMCVersion = VBOX_XPCOMC_VERSION;
    pVBoxAPI->initializeDomainEvent = _initializeDomainEvent;
    pVBoxAPI->registerGlobalData = _registerGlobalData;
T
Taowei 已提交
10523 10524 10525
    pVBoxAPI->detachDevices = _detachDevices;
    pVBoxAPI->unregisterMachine = _unregisterMachine;
    pVBoxAPI->deleteConfig = _deleteConfig;
T
Taowei 已提交
10526
    pVBoxAPI->vboxAttachDrivesOld = _vboxAttachDrivesOld;
T
Taowei 已提交
10527
    pVBoxAPI->UPFN = _UPFN;
T
Taowei 已提交
10528
    pVBoxAPI->UIID = _UIID;
T
Taowei 已提交
10529
    pVBoxAPI->UArray = _UArray;
T
Taowei 已提交
10530
    pVBoxAPI->nsUISupports = _nsUISupports;
T
Taowei 已提交
10531
    pVBoxAPI->UIVirtualBox = _UIVirtualBox;
T
Taowei 已提交
10532
    pVBoxAPI->UIMachine = _UIMachine;
T
Taowei 已提交
10533 10534 10535
    pVBoxAPI->UISession = _UISession;
    pVBoxAPI->UIConsole = _UIConsole;
    pVBoxAPI->UIProgress = _UIProgress;
T
Taowei 已提交
10536
    pVBoxAPI->UISystemProperties = _UISystemProperties;
T
Taowei 已提交
10537 10538 10539 10540 10541 10542 10543 10544 10545
    pVBoxAPI->UIBIOSSettings = _UIBIOSSettings;
    pVBoxAPI->UIAudioAdapter = _UIAudioAdapter;
    pVBoxAPI->UINetworkAdapter = _UINetworkAdapter;
    pVBoxAPI->UISerialPort = _UISerialPort;
    pVBoxAPI->UIParallelPort = _UIParallelPort;
    pVBoxAPI->UIVRDxServer = _UIVRDxServer;
    pVBoxAPI->UIUSBCommon = _UIUSBCommon;
    pVBoxAPI->UIUSBDeviceFilter = _UIUSBDeviceFilter;
    pVBoxAPI->UIMedium = _UIMedium;
T
Taowei 已提交
10546
    pVBoxAPI->machineStateChecker = _machineStateChecker;
T
Taowei 已提交
10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559

#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
    pVBoxAPI->domainEventCallbacks = 0;
#else /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */
    pVBoxAPI->domainEventCallbacks = 1;
#endif /* VBOX_API_VERSION > 2002000 || VBOX_API_VERSION < 4000000 */

#if VBOX_API_VERSION == 2002000
    pVBoxAPI->hasStaticGlobalData = 0;
#else /* VBOX_API_VERSION > 2002000 */
    pVBoxAPI->hasStaticGlobalData = 1;
#endif /* VBOX_API_VERSION > 2002000 */

T
Taowei 已提交
10560 10561 10562
#if VBOX_API_VERSION >= 4000000
    /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
    pVBoxAPI->getMachineForSession = 1;
T
Taowei 已提交
10563
    pVBoxAPI->detachDevicesExplicitly = 0;
T
Taowei 已提交
10564
    pVBoxAPI->vboxAttachDrivesUseOld = 0;
T
Taowei 已提交
10565 10566
#else /* VBOX_API_VERSION < 4000000 */
    pVBoxAPI->getMachineForSession = 0;
T
Taowei 已提交
10567
    pVBoxAPI->detachDevicesExplicitly = 1;
T
Taowei 已提交
10568
    pVBoxAPI->vboxAttachDrivesUseOld = 1;
T
Taowei 已提交
10569
#endif /* VBOX_API_VERSION < 4000000 */
T
Taowei 已提交
10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581

#if VBOX_API_VERSION >= 4001000
    pVBoxAPI->chipsetType = 1;
#else /* VBOX_API_VERSION < 4001000 */
    pVBoxAPI->chipsetType = 0;
#endif /* VBOX_API_VERSION < 4001000 */

#if VBOX_API_VERSION >= 3001000
    pVBoxAPI->accelerate2DVideo = 1;
#else /* VBOX_API_VERSION < 3001000 */
    pVBoxAPI->accelerate2DVideo = 0;
#endif /* VBOX_API_VERSION < 3001000 */
T
Taowei 已提交
10582
}
10583

10584 10585 10586 10587
/**
 * Function Tables
 */

10588
virDriver NAME(Driver) = {
10589 10590
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
10591 10592 10593
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
10594
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
10595
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
10596
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
10597 10598 10599 10600
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
10601 10602 10603 10604 10605 10606 10607
    .domainCreateXML = vboxDomainCreateXML, /* 0.6.3 */
    .domainLookupByID = vboxDomainLookupByID, /* 0.6.3 */
    .domainLookupByUUID = vboxDomainLookupByUUID, /* 0.6.3 */
    .domainLookupByName = vboxDomainLookupByName, /* 0.6.3 */
    .domainSuspend = vboxDomainSuspend, /* 0.6.3 */
    .domainResume = vboxDomainResume, /* 0.6.3 */
    .domainShutdown = vboxDomainShutdown, /* 0.6.3 */
10608
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
10609 10610
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
10611
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
10612 10613 10614 10615 10616 10617 10618 10619 10620 10621
    .domainGetOSType = vboxDomainGetOSType, /* 0.6.3 */
    .domainSetMemory = vboxDomainSetMemory, /* 0.6.3 */
    .domainGetInfo = vboxDomainGetInfo, /* 0.6.3 */
    .domainGetState = vboxDomainGetState, /* 0.9.2 */
    .domainSave = vboxDomainSave, /* 0.6.3 */
    .domainSetVcpus = vboxDomainSetVcpus, /* 0.7.1 */
    .domainSetVcpusFlags = vboxDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = vboxDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = vboxDomainGetMaxVcpus, /* 0.7.1 */
    .domainGetXMLDesc = vboxDomainGetXMLDesc, /* 0.6.3 */
10622 10623
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
10624 10625 10626 10627
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
10628
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
10629 10630 10631 10632 10633
    .domainAttachDevice = vboxDomainAttachDevice, /* 0.6.3 */
    .domainAttachDeviceFlags = vboxDomainAttachDeviceFlags, /* 0.7.7 */
    .domainDetachDevice = vboxDomainDetachDevice, /* 0.6.3 */
    .domainDetachDeviceFlags = vboxDomainDetachDeviceFlags, /* 0.7.7 */
    .domainUpdateDeviceFlags = vboxDomainUpdateDeviceFlags, /* 0.8.0 */
10634 10635
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
10636
#if VBOX_API_VERSION >= 4000000
10637
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
10638
#endif
10639
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
10640 10641
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
10642
#endif
10643 10644
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
10645 10646 10647
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
10648
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
10649 10650
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
10651
#endif
10652 10653 10654 10655 10656 10657
    .domainSnapshotCreateXML = vboxDomainSnapshotCreateXML, /* 0.8.0 */
    .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */
    .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */
    .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */
    .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */
10658
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
10659
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
10660 10661
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
10662 10663
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
10664
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
10665
    .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */
10666
};
10667 10668 10669

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
10670 10671
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
10672 10673 10674 10675
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
10676 10677 10678 10679 10680 10681 10682 10683
    .networkLookupByUUID = vboxNetworkLookupByUUID, /* 0.6.4 */
    .networkLookupByName = vboxNetworkLookupByName, /* 0.6.4 */
    .networkCreateXML = vboxNetworkCreateXML, /* 0.6.4 */
    .networkDefineXML = vboxNetworkDefineXML, /* 0.6.4 */
    .networkUndefine = vboxNetworkUndefine, /* 0.6.4 */
    .networkCreate = vboxNetworkCreate, /* 0.6.4 */
    .networkDestroy = vboxNetworkDestroy, /* 0.6.4 */
    .networkGetXMLDesc = vboxNetworkGetXMLDesc, /* 0.6.4 */
10684
};
10685 10686 10687

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
10688 10689
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
10690 10691
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703
    .storagePoolLookupByName = vboxStoragePoolLookupByName, /* 0.7.1 */
    .storagePoolNumOfVolumes = vboxStoragePoolNumOfVolumes, /* 0.7.1 */
    .storagePoolListVolumes = vboxStoragePoolListVolumes, /* 0.7.1 */

    .storageVolLookupByName = vboxStorageVolLookupByName, /* 0.7.1 */
    .storageVolLookupByKey = vboxStorageVolLookupByKey, /* 0.7.1 */
    .storageVolLookupByPath = vboxStorageVolLookupByPath, /* 0.7.1 */
    .storageVolCreateXML = vboxStorageVolCreateXML, /* 0.7.1 */
    .storageVolDelete = vboxStorageVolDelete, /* 0.7.1 */
    .storageVolGetInfo = vboxStorageVolGetInfo, /* 0.7.1 */
    .storageVolGetXMLDesc = vboxStorageVolGetXMLDesc, /* 0.7.1 */
    .storageVolGetPath = vboxStorageVolGetPath /* 0.7.1 */
10704
};