vbox_tmpl.c 423.4 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
#include "vbox_uniformed_api.h"
93

94
#define VIR_FROM_THIS                   VIR_FROM_VBOX
95 96 97

VIR_LOG_INIT("vbox.vbox_tmpl");

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

J
John Ferlan 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
#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)

125 126 127
#define VBOX_UTF16_TO_UTF8(arg1, arg2)  data->pFuncs->pfnUtf16ToUtf8(arg1, arg2)
#define VBOX_UTF8_TO_UTF16(arg1, arg2)  data->pFuncs->pfnUtf8ToUtf16(arg1, arg2)

128 129
#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))

130 131 132 133 134 135 136
#define VBOX_RELEASE(arg)                                                     \
    do {                                                                      \
        if (arg) {                                                            \
            (arg)->vtbl->nsisupports.Release((nsISupports *)(arg));           \
            (arg) = NULL;                                                     \
        }                                                                     \
    } while (0)
137 138 139 140

#define VBOX_OBJECT_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
141
if (!data->vboxObj) {\
142 143 144 145 146 147 148
    return ret;\
}

#define VBOX_OBJECT_HOST_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
IHost *host = NULL;\
149
if (!data->vboxObj) {\
150 151 152 153 154 155 156
    return ret;\
}\
data->vboxObj->vtbl->GetHost(data->vboxObj, &host);\
if (!host) {\
    return ret;\
}

157
#if VBOX_API_VERSION < 3001000
158

159
# define VBOX_MEDIUM_RELEASE(arg) \
160
if (arg)\
161
    (arg)->vtbl->imedium.nsisupports.Release((nsISupports *)(arg))
162
# define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
163
    (object)->vtbl->imedium.func((IMedium *)(object), arg1)
164
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
165 166
    (object)->vtbl->imedium.func((IMedium *)(object), arg1, arg2)

167
#else  /* VBOX_API_VERSION >= 3001000 */
168 169 170

typedef IMedium IHardDisk;
typedef IMediumAttachment IHardDiskAttachment;
171 172 173 174 175
# 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) \
176
    (object)->vtbl->func(object, arg1)
177
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
178 179
    (object)->vtbl->func(object, arg1, arg2)

180
#endif /* VBOX_API_VERSION >= 3001000 */
181

182 183 184 185 186 187
#define DEBUGPRUnichar(msg, strUtf16) \
if (strUtf16) {\
    char *strUtf8 = NULL;\
\
    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\
    if (strUtf8) {\
188
        VIR_DEBUG("%s: %s", msg, strUtf8);\
189 190 191 192 193 194
        g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\
    }\
}

#define DEBUGUUID(msg, iid) \
{\
T
Taowei 已提交
195
    VIR_DEBUG("%s: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", msg,\
196 197 198 199 200 201 202 203 204 205 206 207 208
          (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 已提交
209
#if VBOX_API_VERSION > 2002000
210

211 212 213 214 215 216 217 218 219 220
/* 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
 */

221
static vboxGlobalData *g_pVBoxGlobalData = NULL;
222

223
#endif /* !(VBOX_API_VERSION == 2002000) */
224

225
#if VBOX_API_VERSION < 4000000
226 227 228 229 230 231 232 233 234 235 236 237 238

# 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)

239
#else /* VBOX_API_VERSION >= 4000000 */
240 241 242 243 244 245 246 247 248 249 250 251 252

# 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)

253
#endif /* VBOX_API_VERSION >= 4000000 */
254

255 256
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);
257
static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags);
258

259 260 261 262 263
#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. */

264 265
static void vboxDriverLock(vboxGlobalData *data)
{
266 267 268
    virMutexLock(&data->lock);
}

269 270
static void vboxDriverUnlock(vboxGlobalData *data)
{
271 272 273
    virMutexUnlock(&data->lock);
}

274 275
#endif

276
#if VBOX_API_VERSION == 2002000
277

278 279
static void nsIDtoChar(unsigned char *uuid, const nsID *iid)
{
280 281 282
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
283
    size_t i;
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310

    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];

311
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
312 313 314 315
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
316
    ignore_value(virUUIDParse(uuidstrdst, uuid));
317 318
}

319 320
static void nsIDFromChar(nsID *iid, const unsigned char *uuid)
{
321 322 323
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
324
    size_t i;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350

    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];

351
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
352 353 354 355
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
356
    ignore_value(virUUIDParse(uuidstrdst, uuidinterim));
357 358 359
    memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}

360
# ifdef WIN32
361

362 363 364 365
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 已提交
366
#  define IID_MEMBER(name) (iidu->vboxIID_v2_x_WIN32.name)
367 368 369 370 371 372

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

T
Taowei 已提交
375 376 377 378 379 380 381
static void
_vboxIIDUnalloc(vboxGlobalData *data ATTRIBUTE_UNUSED,
                vboxIIDUnion *iid ATTRIBUTE_UNUSED)
{
    /* Nothing to free */
}

382 383 384 385 386
static void
vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, (nsID *)&iid->value);
}
387

T
Taowei 已提交
388 389 390 391 392 393
static void
_vboxIIDToUUID(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIIDUnion *iidu, unsigned char *uuid)
{
    vboxIIDToUUID_v2_x_WIN32(&iidu->vboxIID_v2_x_WIN32, uuid);
}

394 395 396 397 398
static void
vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                           const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x_WIN32(data, iid);
399

400
    nsIDFromChar((nsID *)&iid->value, uuid);
401 402
}

T
Taowei 已提交
403 404 405 406 407 408 409
static void
_vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
                 const unsigned char *uuid)
{
    vboxIIDFromUUID_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, uuid);
}

410 411 412
static bool
vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2)
{
413
    return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0;
414
}
415

T
Taowei 已提交
416 417 418 419 420 421
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);
}

422 423 424 425 426 427 428 429
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);

430
    memcpy(&iid->value, &items[idx], sizeof(GUID));
431 432
}

T
Taowei 已提交
433 434 435 436 437 438 439
static void
_vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu,
                      vboxArray *array, int idx)
{
    vboxIIDFromArrayItem_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, array, idx);
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453
#  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 已提交
454
#  define IID_MEMBER(name) (iidu->vboxIID_v2_x.name)
455 456 457 458 459

static void
vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid)
{
    if (iid->value == NULL) {
460 461 462
        return;
    }

463 464 465 466 467 468 469
    if (iid->value != &iid->backing) {
        data->pFuncs->pfnComUnallocMem(iid->value);
    }

    iid->value = NULL;
}

T
Taowei 已提交
470 471 472 473 474 475
static void
_vboxIIDUnalloc(vboxGlobalData *data, vboxIIDUnion *iidu)
{
    vboxIIDUnalloc_v2_x(data, &iidu->vboxIID_v2_x);
}

476 477 478 479 480 481
static void
vboxIIDToUUID_v2_x(vboxIID_v2_x *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, iid->value);
}

T
Taowei 已提交
482 483 484 485 486 487 488
static void
_vboxIIDToUUID(vboxGlobalData *data ATTRIBUTE_UNUSED,
               vboxIIDUnion *iidu, unsigned char *uuid)
{
    vboxIIDToUUID_v2_x(&iidu->vboxIID_v2_x, uuid);
}

489 490 491 492 493 494 495 496
static void
vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
                     const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x(data, iid);

    iid->value = &iid->backing;

497
    sa_assert(iid->value);
498
    nsIDFromChar(iid->value, uuid);
499 500
}

T
Taowei 已提交
501 502 503 504 505 506 507
static void
_vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
                 const unsigned char *uuid)
{
    vboxIIDFromUUID_v2_x(data, &iidu->vboxIID_v2_x, uuid);
}

508 509 510
static bool
vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2)
{
511
    return memcmp(iid1->value, iid2->value, sizeof(nsID)) == 0;
512 513
}

T
Taowei 已提交
514 515 516 517 518 519 520
static bool
_vboxIIDIsEqual(vboxGlobalData *data ATTRIBUTE_UNUSED,
                vboxIIDUnion *iidu1, vboxIIDUnion *iidu2)
{
    return vboxIIDIsEqual_v2_x(&iidu1->vboxIID_v2_x, &iidu2->vboxIID_v2_x);
}

521 522 523 524 525 526 527 528
static void
vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v2_x(data, iid);

    iid->value = &iid->backing;

529
    memcpy(iid->value, array->items[idx], sizeof(nsID));
530 531
}

T
Taowei 已提交
532 533 534 535 536 537 538
static void
_vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu,
                      vboxArray *array, int idx)
{
    vboxIIDFromArrayItem_v2_x(data, &iidu->vboxIID_v2_x, array, idx);
}

539 540 541 542 543 544 545 546 547 548
#  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 */

549
#else /* VBOX_API_VERSION != 2002000 */
550

551 552 553 554
typedef struct _vboxIID_v3_x vboxIID;
typedef struct _vboxIID_v3_x vboxIID_v3_x;

# define VBOX_IID_INITIALIZER { NULL, true }
T
Taowei 已提交
555
# define IID_MEMBER(name) (iidu->vboxIID_v3_x.name)
556 557 558 559 560 561 562 563 564 565

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;
566 567
}

T
Taowei 已提交
568 569 570 571 572 573
static void
_vboxIIDUnalloc(vboxGlobalData *data, vboxIIDUnion *iidu)
{
    vboxIIDUnalloc_v3_x(data, &iidu->vboxIID_v3_x);
}

574 575 576 577 578 579 580 581
static void
vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                   unsigned char *uuid)
{
    char *utf8 = NULL;

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

582
    ignore_value(virUUIDParse(utf8, uuid));
583 584

    data->pFuncs->pfnUtf8Free(utf8);
585 586
}

T
Taowei 已提交
587 588 589 590 591 592 593
static void
_vboxIIDToUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
               unsigned char *uuid)
{
    vboxIIDToUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid);
}

594 595 596 597 598
static void
vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                     const unsigned char *uuid)
{
    char utf8[VIR_UUID_STRING_BUFLEN];
599

600
    vboxIIDUnalloc_v3_x(data, iid);
601

602
    virUUIDFormat(uuid, utf8);
603

604 605
    data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
}
606

T
Taowei 已提交
607 608 609 610 611 612 613
static void
_vboxIIDFromUUID(vboxGlobalData *data, vboxIIDUnion *iidu,
                 const unsigned char *uuid)
{
    vboxIIDFromUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid);
}

614 615 616 617 618 619
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];
620 621

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

629 630
    return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
}
631

T
Taowei 已提交
632 633 634 635 636 637
static bool
_vboxIIDIsEqual(vboxGlobalData *data, vboxIIDUnion *iidu1,
                vboxIIDUnion *iidu2)
{
    return vboxIIDIsEqual_v3_x(data, &iidu1->vboxIID_v3_x, &iidu2->vboxIID_v3_x);
}
638

639 640 641 642 643
static void
vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v3_x(data, iid);
644

645 646
    iid->value = array->items[idx];
    iid->owner = false;
647 648
}

T
Taowei 已提交
649 650 651 652 653 654 655
static void
_vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu,
                      vboxArray *array, int idx)
{
    vboxIIDFromArrayItem_v3_x(data, &iidu->vboxIID_v3_x, array, idx);
}

656 657 658 659 660 661 662 663

# 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)
664

665
# if VBOX_API_VERSION >= 3001000
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

/**
 * 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
 *
 */
682
static char *vboxGenerateMediumName(PRUint32  storageBus,
683 684 685 686
                                    PRInt32   deviceInst,
                                    PRInt32   devicePort,
                                    PRInt32   deviceSlot,
                                    PRUint32 *aMaxPortPerInst,
687 688
                                    PRUint32 *aMaxSlotPerPort)
{
689
    const char *prefix = NULL;
690 691 692 693 694
    char *name  = NULL;
    int   total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

695 696
    if (!aMaxPortPerInst ||
        !aMaxSlotPerPort)
697 698
        return NULL;

699 700
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
701 702 703 704 705 706 707 708 709
        return NULL;

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

    if (storageBus == StorageBus_IDE) {
710
        prefix = "hd";
711 712
    } else if ((storageBus == StorageBus_SATA) ||
               (storageBus == StorageBus_SCSI)) {
713
        prefix = "sd";
714
    } else if (storageBus == StorageBus_Floppy) {
715
        prefix = "fd";
716 717
    }

718
    name = virIndexToDiskName(total, prefix);
719

720
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
721
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
722
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
723 724 725 726 727 728 729 730 731 732 733 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
 *
 */
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;

754 755 756 757 758 759
    if (!deviceName ||
        !deviceInst ||
        !devicePort ||
        !deviceSlot ||
        !aMaxPortPerInst ||
        !aMaxSlotPerPort)
760 761
        return false;

762 763
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
764 765 766 767 768 769 770
        return false;

    total = virDiskNameToIndex(deviceName);

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

771 772 773
    if (!maxPortPerInst ||
        !maxSlotPerPort ||
        (total < 0))
774 775 776 777 778 779
        return false;

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

780
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
          deviceName, total, storageBus, *deviceInst, *devicePort,
          *deviceSlot, maxPortPerInst, maxSlotPerPort);

    return true;
}

/**
 * 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,
801 802
                                     PRUint32 *maxSlotPerPort)
{
803 804 805 806 807 808 809 810 811 812 813 814 815 816 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
    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
 */
847 848
static int PRUnicharToInt(PRUnichar *strUtf16)
{
849 850 851 852 853 854 855 856 857 858
    char *strUtf8 = NULL;
    int ret = 0;

    if (!strUtf16)
        return -1;

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

859 860 861
    if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0)
        ret = -1;

862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
    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;
}

881
# endif /* VBOX_API_VERSION >= 3001000 */
882

883
#endif /* !(VBOX_API_VERSION == 2002000) */
884

885 886 887 888 889 890
static PRUnichar *
vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr)
{
    char *utf8 = NULL;
    PRUnichar *utf16 = NULL;

891
    utf8 = virSocketAddrFormat(addr);
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911

    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);

912
    if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) {
913 914 915 916 917
        goto cleanup;
    }

    result = 0;

918
 cleanup:
919 920 921 922 923
    VBOX_UTF8_FREE(utf8);

    return result;
}

924 925
static int vboxConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
926
    VBOX_OBJECT_CHECK(conn, int, -1);
927
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
928
    PRUint32 state;
929
    nsresult rc;
930
    size_t i, j;
931

932
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
933
    if (NS_FAILED(rc)) {
934
        virReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
935 936
                       _("Could not get list of Domains, rc=%08x"),
                       (unsigned)rc);
937 938
        goto cleanup;
    }
939

940 941 942
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < nids); ++i) {
        IMachine *machine = machines.items[i];
943 944 945 946 947 948

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
949 950
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline)) {
951 952
                    ret++;
                    ids[j++] = i + 1;
953 954 955 956 957
                }
            }
        }
    }

958
 cleanup:
959
    vboxArrayRelease(&machines);
960 961 962
    return ret;
}

963 964
static int vboxConnectNumOfDomains(virConnectPtr conn)
{
965
    VBOX_OBJECT_CHECK(conn, int, -1);
966
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
967
    PRUint32 state;
968
    nsresult rc;
969
    size_t i;
970

971
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
972
    if (NS_FAILED(rc)) {
973 974
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Domains, rc=%08x"), (unsigned)rc);
975 976
        goto cleanup;
    }
977

978 979 980
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
981 982 983 984 985 986

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
987 988
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
989
                    ret++;
990 991 992 993
            }
        }
    }

994
 cleanup:
995
    vboxArrayRelease(&machines);
996 997 998 999
    return ret;
}

static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
1000 1001
                                        unsigned int flags)
{
1002 1003 1004 1005 1006 1007 1008 1009
    /* VirtualBox currently doesn't have support for running
     * virtual machines without actually defining them and thus
     * for time being just define new machine and start it.
     *
     * TODO: After the appropriate API's are added in VirtualBox
     * change this behaviour to the expected one.
     */

1010 1011 1012 1013 1014
    virDomainPtr dom;

    virCheckFlags(0, NULL);

    dom = vboxDomainDefineXML(conn, xml);
1015 1016 1017 1018
    if (dom == NULL)
        return NULL;

    if (vboxDomainCreate(dom) < 0) {
1019
        vboxDomainUndefineFlags(dom, 0);
1020
        virObjectUnref(dom);
1021
        return NULL;
1022 1023 1024 1025 1026
    }

    return dom;
}

1027 1028
static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id)
{
1029
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1030
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1031 1032
    vboxIID iid = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
1033
    PRUint32 state;
1034
    nsresult rc;
1035

1036
    /* Internal vbox IDs start from 0, the public libvirt ID
1037
     * starts from 1, so refuse id == 0, and adjust the rest*/
1038
    if (id == 0) {
1039 1040
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1041 1042 1043 1044
        return NULL;
    }
    id = id - 1;

1045
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1046
    if (NS_FAILED(rc)) {
1047 1048
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1049 1050
        return NULL;
    }
1051

1052 1053 1054 1055
    if (id < machines.count) {
        IMachine *machine = machines.items[id];

        if (machine) {
1056
            PRBool isAccessible = PR_FALSE;
1057
            machine->vtbl->GetAccessible(machine, &isAccessible);
1058
            if (isAccessible) {
1059
                machine->vtbl->GetState(machine, &state);
1060 1061
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline)) {
1062 1063
                    PRUnichar *machineNameUtf16 = NULL;
                    char      *machineNameUtf8  = NULL;
1064

1065
                    machine->vtbl->GetName(machine, &machineNameUtf16);
1066
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1067

1068 1069 1070
                    machine->vtbl->GetId(machine, &iid.value);
                    vboxIIDToUUID(&iid, uuid);
                    vboxIIDUnalloc(&iid);
1071 1072 1073 1074 1075 1076 1077

                    /* get a new domain pointer from virGetDomain, if it fails
                     * then no need to assign the id, else assign the id, cause
                     * it is -1 by default. rest is taken care by virGetDomain
                     * itself, so need not worry.
                     */

1078
                    ret = virGetDomain(conn, machineNameUtf8, uuid);
1079 1080 1081 1082 1083 1084
                    if (ret)
                        ret->id = id + 1;

                    /* Cleanup all the XPCOM allocated stuff here */
                    VBOX_UTF8_FREE(machineNameUtf8);
                    VBOX_UTF16_FREE(machineNameUtf16);
1085 1086 1087 1088 1089
                }
            }
        }
    }

1090
    vboxArrayRelease(&machines);
1091 1092

    return ret;
1093 1094
}

1095 1096 1097
static virDomainPtr
vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
1098
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1099
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1100
    vboxIID iid = VBOX_IID_INITIALIZER;
1101
    char      *machineNameUtf8  = NULL;
1102
    PRUnichar *machineNameUtf16 = NULL;
1103
    unsigned char iid_as_uuid[VIR_UUID_BUFLEN];
1104 1105
    size_t i;
    int matched = 0;
1106
    nsresult rc;
1107

1108
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1109
    if (NS_FAILED(rc)) {
1110 1111
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1112 1113
        return NULL;
    }
1114

1115 1116
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1117
        PRBool isAccessible = PR_FALSE;
1118

1119 1120
        if (!machine)
            continue;
1121

1122 1123
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1124

1125 1126
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1127
                continue;
1128 1129
            vboxIIDToUUID(&iid, iid_as_uuid);
            vboxIIDUnalloc(&iid);
1130

1131
            if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
1132

1133
                PRUint32 state;
1134

1135
                matched = 1;
1136

1137 1138
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1139

1140
                machine->vtbl->GetState(machine, &state);
1141

1142 1143 1144 1145 1146
                /* get a new domain pointer from virGetDomain, if it fails
                 * then no need to assign the id, else assign the id, cause
                 * it is -1 by default. rest is taken care by virGetDomain
                 * itself, so need not worry.
                 */
1147

1148
                ret = virGetDomain(conn, machineNameUtf8, iid_as_uuid);
1149 1150 1151
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1152
                    ret->id = i + 1;
1153 1154
            }

1155 1156
            if (matched == 1)
                break;
1157 1158 1159
        }
    }

1160 1161 1162
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1163
    vboxArrayRelease(&machines);
1164 1165

    return ret;
1166 1167
}

1168 1169 1170
static virDomainPtr
vboxDomainLookupByName(virConnectPtr conn, const char *name)
{
1171
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1172
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1173
    vboxIID iid = VBOX_IID_INITIALIZER;
1174
    char      *machineNameUtf8  = NULL;
1175
    PRUnichar *machineNameUtf16 = NULL;
1176
    unsigned char uuid[VIR_UUID_BUFLEN];
1177 1178
    size_t i;
    int matched = 0;
1179
    nsresult rc;
1180

1181
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1182
    if (NS_FAILED(rc)) {
1183 1184
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1185 1186
        return NULL;
    }
1187

1188 1189
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1190
        PRBool isAccessible = PR_FALSE;
1191

1192 1193
        if (!machine)
            continue;
1194

1195 1196
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1197

1198 1199
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1200

1201
            if (STREQ(name, machineNameUtf8)) {
1202

1203
                PRUint32 state;
1204

1205
                matched = 1;
1206

1207 1208 1209
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);
1210

1211
                machine->vtbl->GetState(machine, &state);
1212

1213 1214 1215 1216 1217
                /* get a new domain pointer from virGetDomain, if it fails
                 * then no need to assign the id, else assign the id, cause
                 * it is -1 by default. rest is taken care by virGetDomain
                 * itself, so need not worry.
                 */
1218

1219
                ret = virGetDomain(conn, machineNameUtf8, uuid);
1220 1221 1222
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1223
                    ret->id = i + 1;
1224 1225
            }

J
John Ferlan 已提交
1226 1227
            VBOX_UTF8_FREE(machineNameUtf8);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1228 1229
            if (matched == 1)
                break;
1230 1231 1232
        }
    }

1233
    vboxArrayRelease(&machines);
1234 1235

    return ret;
1236 1237
}

1238

1239 1240
static int vboxDomainIsActive(virDomainPtr dom)
{
1241
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1242
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1243
    vboxIID iid = VBOX_IID_INITIALIZER;
1244 1245
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1246
    unsigned char uuid[VIR_UUID_BUFLEN];
1247 1248
    size_t i;
    int matched = 0;
1249
    nsresult rc;
1250

1251
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1252
    if (NS_FAILED(rc)) {
1253 1254
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1255 1256
        return ret;
    }
1257

1258 1259
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1260 1261 1262 1263 1264 1265 1266
        PRBool isAccessible = PR_FALSE;

        if (!machine)
            continue;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1267

1268 1269
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1270
                continue;
1271 1272
            vboxIIDToUUID(&iid, uuid);
            vboxIIDUnalloc(&iid);
1273

1274
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1275

1276
                PRUint32 state;
1277

1278
                matched = 1;
1279

1280 1281
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1282

1283
                machine->vtbl->GetState(machine, &state);
1284

1285 1286
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1287 1288 1289
                    ret = 1;
                else
                    ret = 0;
1290 1291
            }

1292 1293
            if (matched == 1)
                break;
1294 1295 1296
        }
    }

1297 1298 1299
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1300
    vboxArrayRelease(&machines);
1301

1302 1303 1304 1305
    return ret;
}


1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
static int vboxDomainIsPersistent(virDomainPtr dom ATTRIBUTE_UNUSED)
{
    /* All domains are persistent.  However, we do want to check for
     * existence. */
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1318 1319
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1320 1321 1322 1323 1324
        goto cleanup;
    }

    ret = 1;

1325
 cleanup:
1326 1327 1328
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1329 1330 1331
}


1332 1333
static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
    /* VBox domains never have a persistent state that differs from
     * current state.  However, we do want to check for existence.  */
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1344 1345
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1346 1347 1348 1349 1350
        goto cleanup;
    }

    ret = 0;

1351
 cleanup:
1352 1353 1354
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1355 1356
}

1357 1358
static int vboxDomainSuspend(virDomainPtr dom)
{
1359
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1360
    IMachine *machine    = NULL;
1361
    vboxIID iid = VBOX_IID_INITIALIZER;
1362
    IConsole *console    = NULL;
1363
    PRBool isAccessible  = PR_FALSE;
1364
    PRUint32 state;
1365
    nsresult rc;
1366

1367
    vboxIIDFromUUID(&iid, dom->uuid);
1368
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1369
    if (NS_FAILED(rc)) {
1370 1371
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1372 1373
        goto cleanup;
    }
1374

1375 1376
    if (!machine)
        goto cleanup;
1377

1378 1379 1380
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1381

1382
        if (state == MachineState_Running) {
1383 1384
            /* set state pause */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1385 1386 1387 1388 1389
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Pause(console);
                VBOX_RELEASE(console);
                ret = 0;
1390
            } else {
1391 1392
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while suspending the domain"));
1393 1394
                goto cleanup;
            }
1395
            VBOX_SESSION_CLOSE();
1396
        } else {
1397 1398
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not in running state to suspend it"));
1399
            goto cleanup;
1400 1401 1402
        }
    }

1403
 cleanup:
1404
    VBOX_RELEASE(machine);
1405
    vboxIIDUnalloc(&iid);
1406 1407 1408
    return ret;
}

1409 1410
static int vboxDomainResume(virDomainPtr dom)
{
1411
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1412
    IMachine *machine    = NULL;
1413
    vboxIID iid = VBOX_IID_INITIALIZER;
1414 1415
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1416
    nsresult rc;
1417

1418
    PRBool isAccessible = PR_FALSE;
1419

1420
    vboxIIDFromUUID(&iid, dom->uuid);
1421
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1422
    if (NS_FAILED(rc)) {
1423 1424
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1425 1426
        goto cleanup;
    }
1427

1428 1429
    if (!machine)
        goto cleanup;
1430

1431 1432 1433 1434 1435
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);

        if (state == MachineState_Paused) {
1436 1437
            /* resume the machine here */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1438 1439 1440 1441 1442
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Resume(console);
                VBOX_RELEASE(console);
                ret = 0;
1443
            } else {
1444 1445
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while resuming the domain"));
1446 1447
                goto cleanup;
            }
1448
            VBOX_SESSION_CLOSE();
1449
        } else {
1450 1451
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not paused, so can't resume it"));
1452
            goto cleanup;
1453 1454 1455
        }
    }

1456
 cleanup:
1457
    VBOX_RELEASE(machine);
1458
    vboxIIDUnalloc(&iid);
1459 1460 1461
    return ret;
}

1462
static int vboxDomainShutdownFlags(virDomainPtr dom,
1463 1464
                                   unsigned int flags)
{
1465
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1466
    IMachine *machine    = NULL;
1467
    vboxIID iid = VBOX_IID_INITIALIZER;
1468 1469
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1470 1471
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1472

1473 1474
    virCheckFlags(0, -1);

1475
    vboxIIDFromUUID(&iid, dom->uuid);
1476
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1477
    if (NS_FAILED(rc)) {
1478 1479
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1480 1481
        goto cleanup;
    }
1482

1483 1484
    if (!machine)
        goto cleanup;
1485

1486 1487 1488
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1489

1490
        if (state == MachineState_Paused) {
1491 1492
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine paused, so can't power it down"));
1493 1494
            goto cleanup;
        } else if (state == MachineState_PoweredOff) {
1495 1496
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1497 1498
            goto cleanup;
        }
1499

1500
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1501 1502 1503 1504 1505
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
            console->vtbl->PowerButton(console);
            VBOX_RELEASE(console);
            ret = 0;
1506
        }
1507
        VBOX_SESSION_CLOSE();
1508 1509
    }

1510
 cleanup:
1511
    VBOX_RELEASE(machine);
1512
    vboxIIDUnalloc(&iid);
1513 1514 1515
    return ret;
}

1516 1517
static int vboxDomainShutdown(virDomainPtr dom)
{
1518 1519 1520 1521
    return vboxDomainShutdownFlags(dom, 0);
}


E
Eric Blake 已提交
1522 1523
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
{
1524
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1525
    IMachine *machine    = NULL;
1526
    vboxIID iid = VBOX_IID_INITIALIZER;
1527 1528
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1529 1530
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1531

E
Eric Blake 已提交
1532 1533
    virCheckFlags(0, -1);

1534
    vboxIIDFromUUID(&iid, dom->uuid);
1535
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1536
    if (NS_FAILED(rc)) {
1537 1538
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1539 1540
        goto cleanup;
    }
1541

1542 1543
    if (!machine)
        goto cleanup;
1544

1545 1546 1547
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1548

1549
        if (state == MachineState_Running) {
1550
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1551 1552 1553 1554 1555
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Reset(console);
                VBOX_RELEASE(console);
                ret = 0;
1556
            }
1557
            VBOX_SESSION_CLOSE();
1558
        } else {
1559 1560
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not running, so can't reboot it"));
1561
            goto cleanup;
1562 1563 1564
        }
    }

1565
 cleanup:
1566
    VBOX_RELEASE(machine);
1567
    vboxIIDUnalloc(&iid);
1568 1569 1570
    return ret;
}

1571 1572 1573 1574
static int
vboxDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1575
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1576
    IMachine *machine    = NULL;
1577
    vboxIID iid = VBOX_IID_INITIALIZER;
1578 1579
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1580 1581
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1582

1583 1584
    virCheckFlags(0, -1);

1585
    vboxIIDFromUUID(&iid, dom->uuid);
1586
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1587
    if (NS_FAILED(rc)) {
1588 1589
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1590 1591
        goto cleanup;
    }
1592

1593 1594
    if (!machine)
        goto cleanup;
1595

1596 1597 1598
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1599

1600
        if (state == MachineState_PoweredOff) {
1601 1602
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1603 1604
            goto cleanup;
        }
1605

1606
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1607 1608
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
1609

1610
#if VBOX_API_VERSION == 2002000
1611
            console->vtbl->PowerDown(console);
1612
#else
1613
            IProgress *progress = NULL;
1614 1615 1616 1617
            console->vtbl->PowerDown(console, &progress);
            if (progress) {
                progress->vtbl->WaitForCompletion(progress, -1);
                VBOX_RELEASE(progress);
1618
            }
1619 1620
#endif
            VBOX_RELEASE(console);
1621
            dom->id = -1;
1622
            ret = 0;
1623
        }
1624
        VBOX_SESSION_CLOSE();
1625 1626
    }

1627
 cleanup:
1628
    VBOX_RELEASE(machine);
1629
    vboxIIDUnalloc(&iid);
1630 1631 1632
    return ret;
}

1633 1634 1635 1636 1637 1638
static int
vboxDomainDestroy(virDomainPtr dom)
{
    return vboxDomainDestroyFlags(dom, 0);
}

1639
static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1640 1641 1642 1643 1644
    /* 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 ;)
     */
1645
    char *osType;
1646

1647
    ignore_value(VIR_STRDUP(osType, "hvm"));
1648
    return osType;
1649 1650
}

1651 1652
static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
1653
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1654
    IMachine *machine    = NULL;
1655
    vboxIID iid = VBOX_IID_INITIALIZER;
1656
    PRUint32 state       = MachineState_Null;
1657 1658
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1659

1660
    vboxIIDFromUUID(&iid, dom->uuid);
1661
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1662
    if (NS_FAILED(rc)) {
1663 1664
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1665 1666
        goto cleanup;
    }
1667

1668 1669
    if (!machine)
        goto cleanup;
1670

1671 1672 1673
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1674

1675
        if (state != MachineState_PoweredOff) {
1676 1677
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("memory size can't be changed unless domain is powered down"));
1678 1679
            goto cleanup;
        }
1680

1681
        rc = VBOX_SESSION_OPEN(iid.value, machine);
1682 1683 1684
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
1685

1686 1687
                rc = machine->vtbl->SetMemorySize(machine,
                                                  VIR_DIV_UP(memory, 1024));
1688 1689 1690 1691
                if (NS_SUCCEEDED(rc)) {
                    machine->vtbl->SaveSettings(machine);
                    ret = 0;
                } else {
1692 1693 1694 1695
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("could not set the memory size of the "
                                     "domain to: %lu Kb, rc=%08x"),
                                   memory, (unsigned)rc);
1696 1697
                }
            }
1698
            VBOX_SESSION_CLOSE();
1699 1700 1701
        }
    }

1702
 cleanup:
1703
    VBOX_RELEASE(machine);
1704
    vboxIIDUnalloc(&iid);
1705 1706 1707
    return ret;
}

1708 1709
static virDomainState vboxConvertState(enum MachineState state)
{
1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
    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 已提交
1720
        case MachineState_Saved:
1721 1722 1723 1724 1725 1726 1727 1728 1729
            return VIR_DOMAIN_SHUTOFF;
        case MachineState_Aborted:
            return VIR_DOMAIN_CRASHED;
        case MachineState_Null:
        default:
            return VIR_DOMAIN_NOSTATE;
    }
}

1730 1731
static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
1732
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1733
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1734 1735
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1736
    nsresult rc;
1737
    size_t i = 0;
1738

1739
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1740
    if (NS_FAILED(rc)) {
1741 1742
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1743 1744
        goto cleanup;
    }
1745

1746
    info->nrVirtCpu = 0;
1747 1748
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1749
        PRBool isAccessible = PR_FALSE;
1750

1751 1752
        if (!machine)
            continue;
1753

1754 1755
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1756

1757 1758 1759 1760 1761 1762
            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
1763
                * for time being set max_balloon and cur_balloon to same
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
                * 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;
                }
1781 1782


1783 1784 1785 1786 1787 1788
                machine->vtbl->GetCPUCount(machine, &CPUCount);
                machine->vtbl->GetMemorySize(machine, &memorySize);
                machine->vtbl->GetState(machine, &state);

                info->cpuTime = 0;
                info->nrVirtCpu = CPUCount;
1789 1790
                info->memory = memorySize * 1024;
                info->maxMem = maxMemorySize * 1024;
1791
                info->state = vboxConvertState(state);
1792

1793
                ret = 0;
1794 1795
            }

J
John Ferlan 已提交
1796 1797
            VBOX_UTF8_FREE(machineName);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1798 1799
            if (info->nrVirtCpu)
                break;
1800 1801 1802 1803
        }

    }

1804
    vboxArrayRelease(&machines);
1805

1806
 cleanup:
1807 1808 1809
    return ret;
}

1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
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)) {
1827 1828
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1829 1830 1831 1832 1833
        goto cleanup;
    }

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

1834
    *state = vboxConvertState(mstate);
1835 1836 1837 1838 1839 1840

    if (reason)
        *reason = 0;

    ret = 0;

1841
 cleanup:
1842 1843 1844 1845
    vboxIIDUnalloc(&domiid);
    return ret;
}

1846 1847 1848 1849
static int
vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
{
1850
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1851
    IMachine *machine    = NULL;
1852
    vboxIID iid = VBOX_IID_INITIALIZER;
1853
    PRUint32  CPUCount   = nvcpus;
1854
    nsresult rc;
1855

1856
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
1857
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1858 1859 1860
        return -1;
    }

1861
    vboxIIDFromUUID(&iid, dom->uuid);
1862
#if VBOX_API_VERSION >= 4000000
1863 1864 1865
    /* Get machine for the call to VBOX_SESSION_OPEN */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1866 1867
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1868 1869 1870 1871 1872
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN(iid.value, machine);
1873 1874 1875 1876 1877 1878 1879
    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;
1880
            } else {
1881 1882 1883 1884
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not set the number of cpus of the domain "
                                 "to: %u, rc=%08x"),
                               CPUCount, (unsigned)rc);
1885
            }
1886
            VBOX_RELEASE(machine);
1887
        } else {
1888 1889
            virReportError(VIR_ERR_NO_DOMAIN,
                           _("no domain with matching id %d"), dom->id);
1890
        }
1891
    } else {
1892 1893
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("can't open session to the domain with id %d"), dom->id);
1894
    }
1895
    VBOX_SESSION_CLOSE();
1896

1897
    vboxIIDUnalloc(&iid);
1898 1899 1900
    return ret;
}

1901 1902 1903
static int
vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
1904
    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
1905 1906 1907 1908 1909
}

static int
vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
1910 1911
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    ISystemProperties *systemProperties = NULL;
1912 1913
    PRUint32 maxCPUCount = 0;

1914
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1915
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1916 1917 1918
        return -1;
    }

1919 1920 1921 1922 1923
    /* Currently every domain supports the same number of max cpus
     * as that supported by vbox and thus take it directly from
     * the systemproperties.
     */

1924 1925 1926 1927
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
1928 1929 1930 1931 1932 1933 1934 1935
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

1936 1937 1938
static int
vboxDomainGetMaxVcpus(virDomainPtr dom)
{
1939
    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
1940 1941 1942
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1943 1944
static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
{
1945
#if VBOX_API_VERSION < 4003000
1946 1947
    IUSBController *USBController = NULL;
    PRBool enabled = PR_FALSE;
R
Ryota Ozaki 已提交
1948 1949 1950
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
1951 1952 1953 1954 1955
    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
    size_t i;
    PRUint32 USBFilterCount = 0;

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

1957
#if VBOX_API_VERSION < 4003000
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969
    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 已提交
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;

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

1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
    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;

2004 2005 2006 2007 2008 2009
    for (i = 0; i < def->nhostdevs; i++) {
        def->hostdevs[i] = virDomainHostdevDefAlloc();
        if (!def->hostdevs[i])
            goto release_hostdevs;
    }

2010
    for (i = 0; i < deviceFilters.count; i++) {
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035
        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);

2036 2037
        ignore_value(virStrToLong_ui(vendorIdUtf8, &endptr, 16, &vendorId));
        ignore_value(virStrToLong_ui(productIdUtf8, &endptr, 16, &productId));
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050

        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++;
    }

2051
 release_filters:
2052
    vboxArrayRelease(&deviceFilters);
2053
#if VBOX_API_VERSION < 4003000
2054
 release_controller:
2055
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
2056 2057 2058
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
2059 2060 2061

    return;

2062
 release_hostdevs:
2063 2064 2065 2066 2067
    for (i = 0; i < def->nhostdevs; i++)
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

    goto release_filters;
2068 2069
}

2070
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
2071
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
2072 2073
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
2074
    vboxIID iid = VBOX_IID_INITIALIZER;
2075
    int gotAllABoutDef   = -1;
2076
    nsresult rc;
2077

2078 2079
    /* Flags checked by virDomainDefFormat */

2080
    if (VIR_ALLOC(def) < 0)
2081 2082
        goto cleanup;

2083
    vboxIIDFromUUID(&iid, dom->uuid);
2084
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2085
    if (NS_SUCCEEDED(rc)) {
2086
        PRBool accessible = PR_FALSE;
2087

2088 2089
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
2090
            size_t i = 0;
2091 2092 2093
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
2094
            PRBool VRDxEnabled                  = PR_FALSE;
2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105
            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;
2106
#if VBOX_API_VERSION < 3001000
2107 2108 2109 2110 2111 2112 2113 2114
            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;
2115
#else  /* VBOX_API_VERSION >= 3001000 */
2116
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
2117 2118
#endif /* VBOX_API_VERSION >= 3001000 */
#if VBOX_API_VERSION < 4000000
2119
            IVRDPServer *VRDxServer             = NULL;
2120
#else  /* VBOX_API_VERSION >= 4000000 */
2121
            IVRDEServer *VRDxServer             = NULL;
2122
#endif /* VBOX_API_VERSION >= 4000000 */
2123
            IAudioAdapter *audioAdapter         = NULL;
2124
#if VBOX_API_VERSION >= 4001000
2125
            PRUint32 chipsetType                = ChipsetType_Null;
2126
#endif /* VBOX_API_VERSION >= 4001000 */
2127
            ISystemProperties *systemProperties = NULL;
2128 2129


2130 2131 2132
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
2133 2134
            if (VIR_STRDUP(def->name, dom->name) < 0)
                goto cleanup;
2135

2136
            machine->vtbl->GetMemorySize(machine, &memorySize);
2137
            def->mem.cur_balloon = memorySize * 1024;
2138

2139
#if VBOX_API_VERSION >= 4001000
2140
            machine->vtbl->GetChipsetType(machine, &chipsetType);
2141
#endif /* VBOX_API_VERSION >= 4001000 */
2142

2143 2144 2145 2146
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
2147
#if VBOX_API_VERSION < 4001000
2148
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
2149
#else  /* VBOX_API_VERSION >= 4000000 */
2150
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
2151
#endif /* VBOX_API_VERSION >= 4000000 */
2152 2153 2154 2155 2156 2157 2158 2159 2160
                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
             */
2161 2162
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
2163 2164

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
2165
            def->maxvcpus = def->vcpus = CPUCount;
2166 2167 2168

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

2169 2170
            if (VIR_STRDUP(def->os.type, "hvm") < 0)
                goto cleanup;
2171

2172
            def->os.arch = virArchFromHost();
2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195

            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 已提交
2196
                    /* Can VirtualBox really boot from a shared folder? */
2197
                }
2198
            }
2199

2200
#if VBOX_API_VERSION < 3001000
2201
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
2202
#elif VBOX_API_VERSION == 3001000
2203
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
2204
#elif VBOX_API_VERSION >= 3002000
2205 2206
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
2207
            if (PAEEnabled)
J
Ján Tomko 已提交
2208
                def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
2209

2210 2211 2212
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
2213
                if (ACPIEnabled)
J
Ján Tomko 已提交
2214
                    def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
2215

2216
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
2217
                if (IOAPICEnabled)
J
Ján Tomko 已提交
2218
                    def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON;
2219

2220 2221 2222 2223 2224
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
2225
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2226 2227 2228 2229 2230 2231 2232 2233

            /* 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 */
2234
                        PRUint32 VRAMSize          = 8;
2235 2236 2237 2238 2239 2240 2241
                        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);
2242
#if VBOX_API_VERSION >= 3001000
2243
                        machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
2244
#endif /* VBOX_API_VERSION >= 3001000 */
2245 2246

                        def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
2247
                        def->videos[0]->vram            = VRAMSize * 1024;
2248 2249 2250 2251
                        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;
2252 2253 2254
                        }
                    }
                }
2255
            }
2256

2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267
            /* 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;
2268

2269
                def->ngraphics = 0;
2270

2271 2272 2273
                VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
                machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
                VBOX_UTF16_FREE(keyTypeUtf16);
2274

2275 2276 2277
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
2278

2279
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2280 2281 2282
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
2283

2284 2285 2286
                        VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
                        machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16);
                        VBOX_UTF16_FREE(keyDislpayUtf16);
2287

2288 2289 2290
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
2291

J
John Ferlan 已提交
2292
                            if (strlen(valueDisplayUtf8) <= 0)
2293
                                VBOX_UTF8_FREE(valueDisplayUtf8);
2294
                        }
2295

2296 2297
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
2298
                            if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
2299 2300 2301 2302 2303 2304
                                /* 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++;
2305
                        }
2306

2307 2308
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
2309
                            if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
2310
                                /* just don't go to cleanup yet as it is ok to have
2311 2312
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
2313
                                 */
2314
                            }
2315 2316
                            totalPresent++;
                        }
J
John Ferlan 已提交
2317
                        VBOX_UTF8_FREE(valueDisplayUtf8);
2318 2319
                    }

2320 2321
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
2322

2323 2324
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2325

2326 2327 2328 2329 2330 2331 2332
                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++;
                    }
2333

2334 2335 2336 2337 2338 2339 2340 2341
                    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) {
2342
                        const char *tmp;
2343
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2344
                        tmp = virGetEnvBlockSUID("DISPLAY");
2345 2346 2347 2348
                        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
                             */
2349 2350 2351 2352 2353
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
2354

2355
#if VBOX_API_VERSION < 4000000
2356
                machine->vtbl->GetVRDPServer(machine, &VRDxServer);
2357
#else  /* VBOX_API_VERSION >= 4000000 */
2358
                machine->vtbl->GetVRDEServer(machine, &VRDxServer);
2359
#endif /* VBOX_API_VERSION >= 4000000 */
2360 2361 2362
                if (VRDxServer) {
                    VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
                    if (VRDxEnabled) {
2363 2364 2365 2366 2367 2368 2369 2370 2371

                        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;
2372
#if VBOX_API_VERSION < 3001000
2373
                            PRUint32 VRDPport = 0;
2374
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2375 2376
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2377 2378 2379
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
2380
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
2381
                            PRUnichar *VRDPport = NULL;
2382
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2383 2384 2385 2386
                            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);
2387 2388 2389
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
2390
#else /* VBOX_API_VERSION >= 4000000 */
2391 2392 2393 2394 2395 2396 2397 2398 2399
                            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);
2400
                            } else {
2401
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
2402
                            }
2403
#endif /* VBOX_API_VERSION >= 4000000 */
2404

2405
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2406

2407
#if VBOX_API_VERSION >= 4000000
2408 2409 2410 2411
                            PRUnichar *VRDENetAddressKey = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
                            VBOX_UTF16_FREE(VRDENetAddressKey);
2412
#else /* VBOX_API_VERSION < 4000000 */
2413
                            VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
2414
#endif /* VBOX_API_VERSION < 4000000 */
2415 2416 2417
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
2418 2419
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
2420 2421 2422
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
2423

2424
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2425
                            if (allowMultiConnection) {
2426
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2427
                            }
2428

2429
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2430
                            if (reuseSingleConnection) {
2431
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2432
                            }
2433

2434
                            def->ngraphics++;
2435
                        } else
2436
                            virReportOOMError();
2437
                    }
2438
                    VBOX_RELEASE(VRDxServer);
2439
                }
2440
            }
2441

2442
#if VBOX_API_VERSION < 3001000
2443 2444
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2445

2446 2447 2448 2449
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
2450

2451 2452 2453
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
2454

2455 2456 2457
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
2458

2459 2460 2461 2462
            VBOX_UTF16_FREE(hddBusUtf16);

            if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
                for (i = 0; i < def->ndisks; i++) {
2463
                    if ((def->disks[i] = virDomainDiskDefNew())) {
2464 2465
                        def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                        def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2466
                        virDomainDiskSetType(def->disks[i],
E
Eric Blake 已提交
2467
                                             VIR_STORAGE_TYPE_FILE);
2468
                    }
2469
                }
2470
            }
2471

2472 2473 2474 2475
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2476

2477 2478
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2479

2480
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2481

2482
                if (hddType == HardDiskType_Immutable)
2483
                    def->disks[hddNum]->src->readonly = true;
2484 2485
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
2486
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
2487
                hddNum++;
2488

2489 2490 2491 2492
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
2493

2494 2495 2496 2497
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2498

2499 2500
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2501

2502
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2503

2504
                if (hddType == HardDiskType_Immutable)
2505
                    def->disks[hddNum]->src->readonly = true;
2506 2507
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
2508
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
2509
                hddNum++;
2510

2511 2512 2513 2514
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
2515

2516 2517 2518 2519
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2520

2521 2522
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2523

2524
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2525

2526
                if (hddType == HardDiskType_Immutable)
2527
                    def->disks[hddNum]->src->readonly = true;
2528 2529
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
J
Ján Tomko 已提交
2530 2531
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
                hddNum++;
2532 2533 2534 2535 2536

                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskSS);
            }
2537
#else  /* VBOX_API_VERSION >= 3001000 */
2538 2539 2540 2541 2542 2543 2544
            /* dump IDE hdds if present */

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

            /* get the number of attachments */
2548 2549
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2550 2551 2552 2553 2554 2555 2556
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
2557 2558
                    }
                }
2559
            }
2560

2561 2562 2563
            /* Allocate mem, if fails return error */
            if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) {
                for (i = 0; i < def->ndisks; i++) {
2564 2565
                    virDomainDiskDefPtr disk = virDomainDiskDefNew();
                    if (!disk) {
2566 2567
                        error = true;
                        break;
2568
                    }
2569
                    def->disks[i] = disk;
2570
                }
2571 2572 2573 2574 2575 2576 2577 2578
            } else {
                error = true;
            }

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

            /* get the attachment details here */
2579 2580
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613
                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;
                }
2614

2615 2616 2617
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
2618 2619
                ignore_value(virDomainDiskSetSource(def->disks[diskCount],
                                                    mediumLocUtf8));
2620 2621
                VBOX_UTF8_FREE(mediumLocUtf8);

2622
                if (!virDomainDiskGetSource(def->disks[diskCount])) {
2623 2624 2625 2626 2627
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2628

2629 2630 2631 2632 2633 2634 2635 2636 2637 2638
                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;
                }
2639

2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
                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);
2650
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2651 2652 2653 2654 2655 2656
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2657 2658 2659 2660
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2661 2662 2663 2664 2665
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2666

2667 2668
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2669
                    def->disks[diskCount]->src->readonly = true;
2670

2671
                virDomainDiskSetType(def->disks[diskCount],
E
Eric Blake 已提交
2672
                                     VIR_STORAGE_TYPE_FILE);
2673

2674 2675 2676 2677
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2678

2679
            vboxArrayRelease(&mediumAttachments);
2680

2681 2682 2683 2684 2685 2686 2687 2688
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2689

2690
#endif /* VBOX_API_VERSION >= 3001000 */
2691

M
Matthias Bolte 已提交
2692 2693 2694 2695 2696 2697 2698 2699 2700
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

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

            if (sharedFolders.count > 0) {
2701
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
M
Matthias Bolte 已提交
2702 2703 2704 2705 2706 2707 2708 2709 2710 2711
                    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;

2712
                    if (VIR_ALLOC(def->fss[i]) < 0)
M
Matthias Bolte 已提交
2713 2714 2715 2716 2717 2718
                        goto sharedFoldersCleanup;

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

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
2719 2720 2721
                    if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
                        VBOX_UTF8_FREE(hostPath);
                        VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2722 2723
                        goto sharedFoldersCleanup;
                    }
2724 2725
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2726 2727 2728

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
2729 2730 2731
                    if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
                        VBOX_UTF8_FREE(name);
                        VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2732 2733
                        goto sharedFoldersCleanup;
                    }
2734 2735
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2736 2737 2738 2739 2740 2741 2742 2743

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

                    ++def->nfss;
                }
            }

2744
 sharedFoldersCleanup:
M
Matthias Bolte 已提交
2745 2746
            vboxArrayRelease(&sharedFolders);

2747 2748 2749 2750 2751
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
2752

2753 2754 2755
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2756

2757 2758 2759 2760
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
2761

2762 2763 2764
                    VBOX_RELEASE(adapter);
                }
            }
2765

2766 2767 2768
            /* 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++) {
2769
                    ignore_value(VIR_ALLOC(def->nets[i]));
2770 2771
                }
            }
2772

2773
            /* Now get the details about the network cards here */
2774
            for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
2775
                INetworkAdapter *adapter = NULL;
2776

2777 2778 2779
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2780

2781 2782 2783 2784 2785 2786 2787
                    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};
2788

2789 2790
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
2791

2792
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
2793

2794 2795 2796
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
2797

2798
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
2799

2800
#if VBOX_API_VERSION < 4001000
2801
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2802
#else /* VBOX_API_VERSION >= 4001000 */
2803
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
2804
#endif /* VBOX_API_VERSION >= 4001000 */
2805

2806
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
2807
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
2808

2809 2810
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
2811

2812 2813 2814
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
2815

2816 2817 2818 2819 2820
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

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

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
2821
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
2822 2823 2824 2825 2826 2827 2828 2829 2830 2831

                            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;

2832
#if VBOX_API_VERSION < 4001000
2833
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2834
#else /* VBOX_API_VERSION >= 4001000 */
2835
                            adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
2836
#endif /* VBOX_API_VERSION >= 4001000 */
2837 2838

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
2839
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852

                            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) {
2853
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
2854
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
2855
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
2856
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
2857
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
2858
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
2859
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
2860
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
2861
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
2862
#if VBOX_API_VERSION >= 3001000
2863
                        } else if (adapterType == NetworkAdapterType_Virtio) {
2864
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
2865
#endif /* VBOX_API_VERSION >= 3001000 */
2866 2867
                        }

2868 2869 2870 2871 2872 2873 2874 2875 2876
                        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 ... */
2877
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
2878 2879 2880 2881 2882 2883
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
2884
                    }
2885 2886

                    VBOX_RELEASE(adapter);
2887
                }
2888
            }
2889

2890
            /* dump sound card if active */
2891

2892 2893 2894
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
2895

2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
            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);
            }
2923

2924
#if VBOX_API_VERSION < 3001000
2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943
            /* 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) {
2944
                            if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) {
2945 2946
                                def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
                                def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2947
                                virDomainDiskSetType(def->disks[def->ndisks - 1],
E
Eric Blake 已提交
2948
                                                     VIR_STORAGE_TYPE_FILE);
2949
                                def->disks[def->ndisks - 1]->src->readonly = true;
2950
                                ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
2951 2952
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
                                def->ndisks--;
2953
                            } else {
2954
                                def->ndisks--;
2955 2956
                            }
                        } else {
2957
                            def->ndisks--;
2958
                        }
2959 2960 2961 2962

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
2963 2964
                    }
                }
2965 2966
                VBOX_RELEASE(dvdDrive);
            }
2967

2968 2969 2970 2971 2972 2973 2974
            /* 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) {
2975 2976
                    PRUint32 state = DriveState_Null;

2977
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
2978
                    if (state == DriveState_ImageMounted) {
2979
                        IFloppyImage *floppyImage = NULL;
2980

2981 2982
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
2983 2984 2985
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

2986 2987
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
2988 2989 2990

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
2991
                                if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) {
2992 2993
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
2994
                                    virDomainDiskSetType(def->disks[def->ndisks - 1],
E
Eric Blake 已提交
2995
                                                         VIR_STORAGE_TYPE_FILE);
2996
                                    def->disks[def->ndisks - 1]->src->readonly = false;
2997
                                    ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
2998 2999
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
                                    def->ndisks--;
3000 3001 3002 3003 3004 3005 3006
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

3007 3008 3009
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
3010 3011 3012 3013
                        }
                    }
                }

3014 3015
                VBOX_RELEASE(floppyDrive);
            }
3016 3017
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
3018 3019 3020 3021 3022 3023 3024 3025 3026

            /* 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) {
3027 3028
                    PRBool enabled = PR_FALSE;

3029
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
3030
                    if (enabled) {
3031
                        def->nserials++;
3032 3033
                    }

3034
                    VBOX_RELEASE(serialPort);
3035
                }
3036
            }
3037

3038 3039 3040
            /* 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++) {
3041
                    ignore_value(VIR_ALLOC(def->serials[i]));
3042 3043
                }
            }
3044

3045
            /* Now get the details about the serial ports here */
3046 3047 3048
            for (i = 0;
                 serialPortIncCount < def->nserials && i < serialPortCount;
                 i++) {
3049
                ISerialPort *serialPort = NULL;
3050

3051 3052 3053
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
3054

3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
                    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) {
3065
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
3066
                        } else if (hostMode == PortMode_HostDevice) {
3067
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
3068
#if VBOX_API_VERSION >= 3000000
3069
                        } else if (hostMode == PortMode_RawFile) {
3070
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3071
#endif /* VBOX_API_VERSION >= 3000000 */
3072
                        } else {
3073
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
3074
                        }
3075

3076
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3077

3078 3079 3080 3081 3082 3083 3084
                        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;
                        }
3085

3086
                        serialPort->vtbl->GetPath(serialPort, &pathUtf16);
3087

3088 3089
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3090
                            ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
3091 3092
                        }

3093 3094 3095 3096
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3097 3098
                    }

3099 3100 3101
                    VBOX_RELEASE(serialPort);
                }
            }
3102

3103 3104 3105 3106 3107
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
3108

3109 3110 3111
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3112

3113 3114 3115
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
3116
                    }
3117 3118

                    VBOX_RELEASE(parallelPort);
3119
                }
3120
            }
3121

3122 3123 3124
            /* 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++) {
3125
                    ignore_value(VIR_ALLOC(def->parallels[i]));
3126
                }
3127
            }
3128

3129
            /* Now get the details about the parallel ports here */
3130 3131 3132 3133
            for (i = 0;
                 parallelPortIncCount < def->nparallels &&
                     i < parallelPortCount;
                 i++) {
3134
                IParallelPort *parallelPort = NULL;
3135

3136 3137 3138
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3139

3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
                    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;
                        }
3154

3155
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3156
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3157

3158
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
3159

3160
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3161
                        ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
3162

3163 3164 3165 3166
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3167
                    }
3168 3169

                    VBOX_RELEASE(parallelPort);
3170
                }
3171
            }
3172

3173
            /* dump USB devices/filters if active */
3174
            vboxHostDeviceGetXMLDesc(data, def, machine);
3175 3176 3177 3178 3179

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
3180
        }
3181 3182
        VBOX_RELEASE(machine);
        machine = NULL;
3183 3184 3185
    }

    if (gotAllABoutDef == 0)
3186
        ret = virDomainDefFormat(def, flags);
3187

3188
 cleanup:
3189
    vboxIIDUnalloc(&iid);
3190 3191 3192 3193
    virDomainDefFree(def);
    return ret;
}

3194
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
3195
    VBOX_OBJECT_CHECK(conn, int, -1);
3196
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3197 3198 3199
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
3200
    nsresult rc;
3201
    size_t i, j;
3202

3203
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3204
    if (NS_FAILED(rc)) {
3205 3206 3207
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3208 3209
        goto cleanup;
    }
3210

3211 3212
    memset(names, 0, sizeof(names[i]) * maxnames);

3213 3214 3215
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
3216 3217 3218 3219 3220 3221

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3222 3223
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3224 3225
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3226 3227 3228
                    if (VIR_STRDUP(names[j], machineName) < 0) {
                        VBOX_UTF16_FREE(machineNameUtf16);
                        VBOX_UTF8_FREE(machineName);
3229
                        for (j = 0; j < maxnames; j++)
3230 3231 3232
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
3233
                    }
3234 3235
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
3236
                    j++;
3237
                    ret++;
3238 3239 3240 3241 3242
                }
            }
        }
    }

3243
 cleanup:
3244
    vboxArrayRelease(&machines);
3245 3246 3247
    return ret;
}

3248 3249
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn)
{
3250
    VBOX_OBJECT_CHECK(conn, int, -1);
3251
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3252
    PRUint32 state       = MachineState_Null;
3253
    nsresult rc;
3254
    size_t i;
3255

3256
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3257
    if (NS_FAILED(rc)) {
3258 3259 3260
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3261 3262
        goto cleanup;
    }
3263

3264 3265 3266
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3267 3268 3269 3270 3271 3272

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3273 3274
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3275
                    ret++;
3276 3277 3278 3279 3280
                }
            }
        }
    }

3281
 cleanup:
3282
    vboxArrayRelease(&machines);
3283 3284 3285
    return ret;
}

E
Eric Blake 已提交
3286 3287

static int
3288
vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3289
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    int vrdpPresent              = 0;
    int sdlPresent               = 0;
    int guiPresent               = 0;
    char *guiDisplay             = NULL;
    char *sdlDisplay             = NULL;
    PRUnichar *keyTypeUtf16      = NULL;
    PRUnichar *valueTypeUtf16    = NULL;
    char      *valueTypeUtf8     = NULL;
    PRUnichar *keyDislpayUtf16   = NULL;
    PRUnichar *valueDisplayUtf16 = NULL;
    char      *valueDisplayUtf8  = NULL;
    IProgress *progress          = NULL;
    PRUnichar *env               = NULL;
    PRUnichar *sessionType       = NULL;
    nsresult rc;

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

    if (valueTypeUtf16) {
        VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
        VBOX_UTF16_FREE(valueTypeUtf16);

3316
        if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
E
Eric Blake 已提交
3317 3318 3319 3320 3321 3322 3323 3324 3325 3326

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

            if (valueDisplayUtf16) {
                VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                VBOX_UTF16_FREE(valueDisplayUtf16);

J
John Ferlan 已提交
3327
                if (strlen(valueDisplayUtf8) <= 0)
E
Eric Blake 已提交
3328 3329 3330 3331 3332
                    VBOX_UTF8_FREE(valueDisplayUtf8);
            }

            if (STREQ(valueTypeUtf8, "sdl")) {
                sdlPresent = 1;
3333 3334 3335 3336 3337
                if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
                    /* 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
                     */
E
Eric Blake 已提交
3338 3339 3340 3341 3342
                }
            }

            if (STREQ(valueTypeUtf8, "gui")) {
                guiPresent = 1;
3343 3344 3345 3346 3347
                if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
                    /* just don't go to cleanup yet as it is ok to have
                     * guiDisplay as NULL and we check it below if it
                     * exist and then only use it there
                     */
E
Eric Blake 已提交
3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367
                }
            }
        }

        if (STREQ(valueTypeUtf8, "vrdp")) {
            vrdpPresent = 1;
        }

        if (!vrdpPresent && !sdlPresent && !guiPresent) {
            /* if nothing is selected it means either the machine xml
             * file is really old or some values are missing so fallback
             */
            guiPresent = 1;
        }

        VBOX_UTF8_FREE(valueTypeUtf8);

    } else {
        guiPresent = 1;
    }
J
John Ferlan 已提交
3368
    VBOX_UTF8_FREE(valueDisplayUtf8);
E
Eric Blake 已提交
3369 3370 3371

    if (guiPresent) {
        if (guiDisplay) {
E
Eric Blake 已提交
3372
            char *displayutf8;
3373
            if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) >= 0) {
E
Eric Blake 已提交
3374 3375 3376
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3377 3378 3379 3380 3381 3382 3383 3384
            VIR_FREE(guiDisplay);
        }

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

    if (sdlPresent) {
        if (sdlDisplay) {
E
Eric Blake 已提交
3385
            char *displayutf8;
3386
            if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) >= 0) {
E
Eric Blake 已提交
3387 3388 3389
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3390 3391 3392 3393 3394 3395 3396 3397 3398 3399
            VIR_FREE(sdlDisplay);
        }

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

    if (vrdpPresent) {
        VBOX_UTF8_TO_UTF16("vrdp", &sessionType);
    }

3400
#if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3401 3402
    rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                data->vboxSession,
3403
                                                iid->value,
E
Eric Blake 已提交
3404 3405
                                                sessionType,
                                                env,
3406
                                                &progress);
3407
#else /* VBOX_API_VERSION >= 4000000 */
3408 3409
    rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                        sessionType, env, &progress);
3410
#endif /* VBOX_API_VERSION >= 4000000 */
3411

E
Eric Blake 已提交
3412
    if (NS_FAILED(rc)) {
3413 3414
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
E
Eric Blake 已提交
3415 3416 3417
        ret = -1;
    } else {
        PRBool completed = 0;
3418
#if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434
        nsresult resultCode;
#else
        PRInt32  resultCode;
#endif
        progress->vtbl->WaitForCompletion(progress, -1);
        rc = progress->vtbl->GetCompleted(progress, &completed);
        if (NS_FAILED(rc)) {
            /* error */
            ret = -1;
        }
        progress->vtbl->GetResultCode(progress, &resultCode);
        if (NS_FAILED(resultCode)) {
            /* error */
            ret = -1;
        } else {
            /* all ok set the domid */
3435
            dom->id = maxDomID + 1;
E
Eric Blake 已提交
3436 3437 3438 3439 3440 3441
            ret = 0;
        }
    }

    VBOX_RELEASE(progress);

3442
    VBOX_SESSION_CLOSE();
E
Eric Blake 已提交
3443 3444 3445 3446 3447 3448 3449

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

3450 3451
static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
3452
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
3453
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3454
    unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3455
    nsresult rc;
3456
    size_t i = 0;
3457

3458 3459
    virCheckFlags(0, -1);

3460
    if (!dom->name) {
3461 3462
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Error while reading the domain name"));
3463 3464 3465
        goto cleanup;
    }

3466
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3467
    if (NS_FAILED(rc)) {
3468 3469
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3470 3471
        goto cleanup;
    }
3472

3473 3474
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3475
        PRBool isAccessible = PR_FALSE;
3476

3477 3478
        if (!machine)
            continue;
3479

3480 3481
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
3482
            vboxIID iid = VBOX_IID_INITIALIZER;
3483

3484 3485
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
3486
                continue;
3487
            vboxIIDToUUID(&iid, uuid);
3488

3489
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3490 3491 3492
                PRUint32 state = MachineState_Null;
                machine->vtbl->GetState(machine, &state);

3493 3494 3495
                if ((state == MachineState_PoweredOff) ||
                    (state == MachineState_Saved) ||
                    (state == MachineState_Aborted)) {
3496
                    ret = vboxStartMachine(dom, i, machine, &iid);
3497
                } else {
3498
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3499 3500 3501
                                   _("machine is not in "
                                     "poweroff|saved|aborted state, so "
                                     "couldn't start it"));
3502
                    ret = -1;
3503 3504
                }
            }
3505
            vboxIIDUnalloc(&iid);
3506 3507
            if (ret != -1)
                break;
3508 3509 3510
        }
    }

3511
    /* Do the cleanup and take care you dont leak any memory */
3512
    vboxArrayRelease(&machines);
3513

3514
 cleanup:
3515 3516 3517
    return ret;
}

3518 3519
static int vboxDomainCreate(virDomainPtr dom)
{
3520 3521 3522
    return vboxDomainCreateWithFlags(dom, 0);
}

E
Eric Blake 已提交
3523 3524 3525 3526 3527 3528
static void
vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
                       IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 maxBootPosition            = 0;
3529
    size_t i = 0;
3530

3531
    VIR_DEBUG("def->os.type             %s", def->os.type);
3532
    VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3533
    VIR_DEBUG("def->os.machine          %s", def->os.machine);
3534
    VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546
    VIR_DEBUG("def->os.bootDevs[0]      %d", def->os.bootDevs[0]);
    VIR_DEBUG("def->os.bootDevs[1]      %d", def->os.bootDevs[1]);
    VIR_DEBUG("def->os.bootDevs[2]      %d", def->os.bootDevs[2]);
    VIR_DEBUG("def->os.bootDevs[3]      %d", def->os.bootDevs[3]);
    VIR_DEBUG("def->os.init             %s", def->os.init);
    VIR_DEBUG("def->os.kernel           %s", def->os.kernel);
    VIR_DEBUG("def->os.initrd           %s", def->os.initrd);
    VIR_DEBUG("def->os.cmdline          %s", def->os.cmdline);
    VIR_DEBUG("def->os.root             %s", def->os.root);
    VIR_DEBUG("def->os.loader           %s", def->os.loader);
    VIR_DEBUG("def->os.bootloader       %s", def->os.bootloader);
    VIR_DEBUG("def->os.bootloaderArgs   %s", def->os.bootloaderArgs);
3547

E
Eric Blake 已提交
3548 3549 3550 3551 3552 3553
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxBootPosition(systemProperties,
                                                   &maxBootPosition);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
3554
    }
3555

E
Eric Blake 已提交
3556 3557 3558
    /* Clear the defaults first */
    for (i = 0; i < maxBootPosition; i++) {
        machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3559
    }
3560

E
Eric Blake 已提交
3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571
    for (i = 0; (i < def->os.nBootDevs) && (i < maxBootPosition); i++) {
        PRUint32 device = DeviceType_Null;

        if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) {
            device = DeviceType_Floppy;
        } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) {
            device = DeviceType_DVD;
        } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_DISK) {
            device = DeviceType_HardDisk;
        } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
            device = DeviceType_Network;
3572
        }
E
Eric Blake 已提交
3573
        machine->vtbl->SetBootOrder(machine, i+1, device);
3574
    }
E
Eric Blake 已提交
3575
}
3576

E
Eric Blake 已提交
3577 3578 3579
static void
vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
3580
    size_t i;
E
Eric Blake 已提交
3581
    nsresult rc;
3582

3583
#if VBOX_API_VERSION < 3001000
E
Eric Blake 已提交
3584 3585 3586 3587
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
3588 3589 3590 3591 3592
        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);
3593 3594
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3595
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
3596
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3597 3598
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
3599
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3600
                  virStorageFileFormatTypeToString(format));
3601
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
3602
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->src->readonly
E
Eric Blake 已提交
3603
                                             ? "True" : "False"));
3604
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->src->shared
E
Eric Blake 已提交
3605 3606 3607
                                             ? "True" : "False"));

        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
3608
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3609 3610 3611 3612 3613 3614 3615
                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
                 */
3616

E
Eric Blake 已提交
3617 3618 3619 3620
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
3621 3622
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3623

3624
                    VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
3625

E
Eric Blake 已提交
3626 3627 3628 3629 3630
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
3631
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
3632 3633 3634 3635
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3636
                                                           &dvduuid.value);
E
Eric Blake 已提交
3637
                        if (NS_FAILED(rc)) {
3638 3639 3640
                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                           _("can't get the uuid of the file to "
                                             "be attached to cdrom: %s, rc=%08x"),
3641
                                           src, (unsigned)rc);
E
Eric Blake 已提交
3642
                        } else {
3643
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
3644
                            if (NS_FAILED(rc)) {
3645 3646
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
3647
                                               src, (unsigned)rc);
E
Eric Blake 已提交
3648
                            } else {
3649
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3650
                            }
3651
                        }
E
Eric Blake 已提交
3652 3653

                        VBOX_MEDIUM_RELEASE(dvdImage);
3654
                    }
3655
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
3656 3657 3658
                    VBOX_UTF16_FREE(dvdfileUtf16);
                    VBOX_RELEASE(dvdDrive);
                }
E
Eric Blake 已提交
3659
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
E
Eric Blake 已提交
3660 3661
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
E
Eric Blake 已提交
3662
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3663 3664
                IHardDisk *hardDisk     = NULL;
                PRUnichar *hddfileUtf16 = NULL;
3665
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
3666 3667 3668 3669 3670 3671
                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
                 */
3672

3673
                VBOX_UTF8_TO_UTF16(src, &hddfileUtf16);
E
Eric Blake 已提交
3674
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
3675

E
Eric Blake 已提交
3676 3677
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
3678

E
Eric Blake 已提交
3679
                if (!hardDisk) {
3680
# if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
3681 3682 3683 3684
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
3685
# else
E
Eric Blake 已提交
3686 3687 3688 3689 3690 3691 3692 3693
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
3694
# endif
E
Eric Blake 已提交
3695
                }
3696

E
Eric Blake 已提交
3697 3698
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
3699
                                                       &hdduuid.value);
E
Eric Blake 已提交
3700
                    if (NS_FAILED(rc)) {
3701 3702 3703
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("can't get the uuid of the file to be "
                                         "attached as harddisk: %s, rc=%08x"),
3704
                                       src, (unsigned)rc);
E
Eric Blake 已提交
3705
                    } else {
3706
                        if (def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3707 3708
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
3709
                            VIR_DEBUG("setting harddisk to readonly");
3710
                        } else if (!def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3711 3712
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
3713
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
3714 3715 3716
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
3717
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
3718
                                       " is taken by CD/DVD Drive");
3719
                            } else {
E
Eric Blake 已提交
3720 3721 3722 3723
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

3724 3725
                                char *hddcname;
                                ignore_value(VIR_STRDUP(hddcname, "IDE"));
E
Eric Blake 已提交
3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737
                                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;
3738
                                }
E
Eric Blake 已提交
3739 3740

                                rc = machine->vtbl->AttachHardDisk(machine,
3741
                                                                   hdduuid.value,
E
Eric Blake 已提交
3742 3743 3744 3745 3746 3747
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
3748 3749 3750
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
3751
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
3752
                                } else {
3753
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
3754 3755 3756
                                }
                            }
                        }
3757
                    }
E
Eric Blake 已提交
3758 3759
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
3760
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
3761 3762
                VBOX_UTF16_FREE(hddEmpty);
                VBOX_UTF16_FREE(hddfileUtf16);
E
Eric Blake 已提交
3763
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
E
Eric Blake 已提交
3764 3765
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
3766
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3767 3768 3769 3770 3771 3772 3773
                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;
3774 3775
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
3776

3777
                        VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
E
Eric Blake 已提交
3778 3779 3780
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
3781

E
Eric Blake 已提交
3782 3783 3784
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
3785
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
3786 3787
                                                                 &floppyImage);
                        }
3788

E
Eric Blake 已提交
3789 3790
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
3791
                                                                  &fduuid.value);
E
Eric Blake 已提交
3792
                            if (NS_FAILED(rc)) {
3793 3794 3795
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
3796
                                               src, (unsigned)rc);
E
Eric Blake 已提交
3797 3798
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
3799
                                                                   fduuid.value);
E
Eric Blake 已提交
3800
                                if (NS_FAILED(rc)) {
3801 3802 3803
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
3804
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
3805
                                } else {
3806
                                    DEBUGIID("floppyImage UUID", fduuid.value);
3807 3808
                                }
                            }
E
Eric Blake 已提交
3809
                            VBOX_MEDIUM_RELEASE(floppyImage);
3810
                        }
3811
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
3812
                        VBOX_UTF16_FREE(fdfileUtf16);
3813
                    }
E
Eric Blake 已提交
3814
                    VBOX_RELEASE(floppyDrive);
3815
                }
E
Eric Blake 已提交
3816
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3817
            }
3818
        }
E
Eric Blake 已提交
3819
    }
3820
#else  /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832
    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 */
3833
    {
E
Eric Blake 已提交
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
        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);
    }
3869

E
Eric Blake 已提交
3870
    for (i = 0; i < def->ndisks && !error; i++) {
3871 3872 3873 3874 3875
        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);
3876 3877
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3878
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
3879
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3880 3881
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
3882
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3883
                  virStorageFileFormatTypeToString(format));
3884
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
3885
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->src->readonly
E
Eric Blake 已提交
3886
                                             ? "True" : "False"));
3887
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->src->shared
E
Eric Blake 已提交
3888 3889
                                             ? "True" : "False"));

E
Eric Blake 已提交
3890
        if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3891 3892 3893 3894 3895
            IMedium   *medium          = NULL;
            PRUnichar *mediumUUID      = NULL;
            PRUnichar *mediumFileUtf16 = NULL;
            PRUint32   storageBus      = StorageBus_Null;
            PRUint32   deviceType      = DeviceType_Null;
3896
# if VBOX_API_VERSION >= 4000000
3897
            PRUint32   accessMode      = AccessMode_ReadOnly;
3898
# endif
E
Eric Blake 已提交
3899 3900 3901 3902
            PRInt32    deviceInst      = 0;
            PRInt32    devicePort      = 0;
            PRInt32    deviceSlot      = 0;

3903
            VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16);
E
Eric Blake 已提交
3904 3905 3906

            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                deviceType = DeviceType_HardDisk;
3907
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3908 3909
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
3910 3911
# else
                accessMode = AccessMode_ReadWrite;
3912
# endif
E
Eric Blake 已提交
3913 3914
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
3915
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3916 3917
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
3918 3919
# else
                accessMode = AccessMode_ReadOnly;
3920
# endif
E
Eric Blake 已提交
3921 3922
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
3923
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3924 3925
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
3926 3927
# else
                accessMode = AccessMode_ReadWrite;
3928
# endif
E
Eric Blake 已提交
3929 3930 3931 3932
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3933

3934
# if VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
3935 3936
            data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, &medium);
3937
# elif VBOX_API_VERSION >= 4002000
3938 3939
            data->vboxObj->vtbl->OpenMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, accessMode, PR_FALSE, &medium);
3940 3941
# endif

E
Eric Blake 已提交
3942 3943
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
3944

E
Eric Blake 已提交
3945
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
3946

3947
# if VBOX_API_VERSION < 4000000
3948
                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3949 3950 3951 3952 3953 3954 3955 3956
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
3957 3958
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
3959 3960 3961 3962
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
3963 3964
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3965 3966 3967 3968 3969 3970
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
3971
                }
3972
# elif VBOX_API_VERSION == 4000000
3973 3974 3975 3976
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     &medium);
3977
# elif VBOX_API_VERSION >= 4001000
3978 3979 3980 3981 3982
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     false,
                                                     &medium);
3983
# endif /* VBOX_API_VERSION >= 4001000 */
3984

E
Eric Blake 已提交
3985 3986
                VBOX_UTF16_FREE(mediumEmpty);
            }
3987

E
Eric Blake 已提交
3988
            if (!medium) {
3989 3990 3991
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to attach the following disk/dvd/floppy "
                                 "to the machine: %s, rc=%08x"),
3992
                               src, (unsigned)rc);
E
Eric Blake 已提交
3993 3994 3995
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3996

E
Eric Blake 已提交
3997 3998
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
3999 4000 4001
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("can't get the uuid of the file to be attached "
                                 "as harddisk/dvd/floppy: %s, rc=%08x"),
4002
                               src, (unsigned)rc);
E
Eric Blake 已提交
4003 4004 4005 4006
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4007

E
Eric Blake 已提交
4008
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4009
                if (def->disks[i]->src->readonly) {
E
Eric Blake 已提交
4010
                    medium->vtbl->SetType(medium, MediumType_Immutable);
4011
                    VIR_DEBUG("setting harddisk to immutable");
4012
                } else if (!def->disks[i]->src->readonly) {
E
Eric Blake 已提交
4013
                    medium->vtbl->SetType(medium, MediumType_Normal);
4014
                    VIR_DEBUG("setting harddisk type to normal");
4015
                }
E
Eric Blake 已提交
4016
            }
4017

E
Eric Blake 已提交
4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030
            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;
            }
4031

E
Eric Blake 已提交
4032 4033 4034 4035 4036 4037 4038 4039
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
4040
                virReportError(VIR_ERR_INTERNAL_ERROR,
4041 4042 4043
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
4044
                               src, (unsigned)rc);
4045 4046 4047
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
4048 4049 4050 4051 4052 4053 4054 4055 4056
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
4057
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
4058
                                             mediumUUID);
4059
# else /* VBOX_API_VERSION >= 4000000 */
4060
                                             medium);
4061
# endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
4062 4063

            if (NS_FAILED(rc)) {
4064
                virReportError(VIR_ERR_INTERNAL_ERROR,
4065 4066
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
4067
                               src, (unsigned)rc);
E
Eric Blake 已提交
4068 4069
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
4070
            }
E
Eric Blake 已提交
4071 4072 4073 4074 4075

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
4076 4077
        }
    }
4078
#endif /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
4079
}
4080

E
Eric Blake 已提交
4081 4082 4083 4084
static void
vboxAttachSound(virDomainDefPtr def, IMachine *machine)
{
    nsresult rc;
4085

E
Eric Blake 已提交
4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101
    /* Check if def->nsounds is one as VirtualBox currently supports
     * only one sound card
     */
    if (def->nsounds == 1) {
        IAudioAdapter *audioAdapter = NULL;

        machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
        if (audioAdapter) {
            rc = audioAdapter->vtbl->SetEnabled(audioAdapter, 1);
            if (NS_SUCCEEDED(rc)) {
                if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
                    audioAdapter->vtbl->SetAudioController(audioAdapter,
                                                           AudioControllerType_SB16);
                } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_AC97) {
                    audioAdapter->vtbl->SetAudioController(audioAdapter,
                                                           AudioControllerType_AC97);
4102
                }
4103
            }
E
Eric Blake 已提交
4104
            VBOX_RELEASE(audioAdapter);
4105
        }
E
Eric Blake 已提交
4106 4107 4108 4109 4110 4111 4112
    }
}

static void
vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
4113
#if VBOX_API_VERSION >= 4001000
4114
    PRUint32 chipsetType                = ChipsetType_Null;
4115
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4116
    PRUint32 networkAdapterCount        = 0;
4117
    size_t i = 0;
E
Eric Blake 已提交
4118

4119
#if VBOX_API_VERSION >= 4001000
4120
    machine->vtbl->GetChipsetType(machine, &chipsetType);
4121
#endif /* VBOX_API_VERSION >= 4001000 */
4122

E
Eric Blake 已提交
4123 4124
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
4125
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4126 4127
        systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                       &networkAdapterCount);
4128
#else  /* VBOX_API_VERSION >= 4000000 */
4129 4130
        systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
                                                      &networkAdapterCount);
4131
#endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
4132 4133 4134 4135
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }

4136
    VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
4137
    VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
E
Eric Blake 已提交
4138 4139 4140 4141 4142 4143 4144

    for (i = 0; (i < def->nnets) && (i < networkAdapterCount); i++) {
        INetworkAdapter *adapter = NULL;
        PRUint32 adapterType     = NetworkAdapterType_Null;
        char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
        char macaddrvbox[VIR_MAC_STRING_BUFLEN - 5] = {0};

4145
        virMacAddrFormat(&def->nets[i]->mac, macaddr);
E
Eric Blake 已提交
4146 4147
        snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                 "%02X%02X%02X%02X%02X%02X",
4148 4149 4150 4151 4152 4153
                 def->nets[i]->mac.addr[0],
                 def->nets[i]->mac.addr[1],
                 def->nets[i]->mac.addr[2],
                 def->nets[i]->mac.addr[3],
                 def->nets[i]->mac.addr[4],
                 def->nets[i]->mac.addr[5]);
E
Eric Blake 已提交
4154 4155
        macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

4156 4157 4158 4159
        VIR_DEBUG("NIC(%zu): Type:   %d", i, def->nets[i]->type);
        VIR_DEBUG("NIC(%zu): Model:  %s", i, def->nets[i]->model);
        VIR_DEBUG("NIC(%zu): Mac:    %s", i, macaddr);
        VIR_DEBUG("NIC(%zu): ifname: %s", i, def->nets[i]->ifname);
E
Eric Blake 已提交
4160
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4161
            VIR_DEBUG("NIC(%zu): name:    %s", i, def->nets[i]->data.network.name);
E
Eric Blake 已提交
4162
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4163
            VIR_DEBUG("NIC(%zu): name:   %s", i, def->nets[i]->data.internal.name);
E
Eric Blake 已提交
4164
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4165
            VIR_DEBUG("NIC(%zu): NAT.", i);
E
Eric Blake 已提交
4166
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4167 4168 4169
            VIR_DEBUG("NIC(%zu): brname: %s", i, def->nets[i]->data.bridge.brname);
            VIR_DEBUG("NIC(%zu): script: %s", i, def->nets[i]->script);
            VIR_DEBUG("NIC(%zu): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
4170 4171
        }

E
Eric Blake 已提交
4172 4173 4174 4175 4176
        machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
        if (adapter) {
            PRUnichar *MACAddress = NULL;

            adapter->vtbl->SetEnabled(adapter, 1);
4177

E
Eric Blake 已提交
4178
            if (def->nets[i]->model) {
E
Eric Blake 已提交
4179
                if (STRCASEEQ(def->nets[i]->model, "Am79C970A")) {
E
Eric Blake 已提交
4180
                    adapterType = NetworkAdapterType_Am79C970A;
E
Eric Blake 已提交
4181
                } else if (STRCASEEQ(def->nets[i]->model, "Am79C973")) {
E
Eric Blake 已提交
4182
                    adapterType = NetworkAdapterType_Am79C973;
E
Eric Blake 已提交
4183
                } else if (STRCASEEQ(def->nets[i]->model, "82540EM")) {
E
Eric Blake 已提交
4184
                    adapterType = NetworkAdapterType_I82540EM;
E
Eric Blake 已提交
4185
                } else if (STRCASEEQ(def->nets[i]->model, "82545EM")) {
E
Eric Blake 已提交
4186
                    adapterType = NetworkAdapterType_I82545EM;
E
Eric Blake 已提交
4187
                } else if (STRCASEEQ(def->nets[i]->model, "82543GC")) {
E
Eric Blake 已提交
4188
                    adapterType = NetworkAdapterType_I82543GC;
4189
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4190
                } else if (STRCASEEQ(def->nets[i]->model, "virtio")) {
E
Eric Blake 已提交
4191
                    adapterType = NetworkAdapterType_Virtio;
4192
#endif /* VBOX_API_VERSION >= 3001000 */
4193
                }
E
Eric Blake 已提交
4194 4195 4196
            } else {
                adapterType = NetworkAdapterType_Am79C973;
            }
4197

E
Eric Blake 已提交
4198
            adapter->vtbl->SetAdapterType(adapter, adapterType);
4199

E
Eric Blake 已提交
4200 4201 4202
            if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                PRUnichar *hostInterface = NULL;
                /* Bridged Network */
4203

4204
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4205
                adapter->vtbl->AttachToBridgedInterface(adapter);
4206
#else /* VBOX_API_VERSION >= 4001000 */
4207
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
4208
#endif /* VBOX_API_VERSION >= 4001000 */
4209

E
Eric Blake 已提交
4210 4211 4212
                if (def->nets[i]->data.bridge.brname) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
                                       &hostInterface);
4213
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4214
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4215
#else /* VBOX_API_VERSION >= 4001000 */
4216
                    adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
4217
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4218 4219 4220 4221 4222
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                PRUnichar *internalNetwork = NULL;
                /* Internal Network */
4223

4224
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4225
                adapter->vtbl->AttachToInternalNetwork(adapter);
4226
#else /* VBOX_API_VERSION >= 4001000 */
4227
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
4228
#endif /* VBOX_API_VERSION >= 4001000 */
4229

E
Eric Blake 已提交
4230 4231 4232 4233 4234
                if (def->nets[i]->data.internal.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.internal.name,
                                       &internalNetwork);
                    adapter->vtbl->SetInternalNetwork(adapter, internalNetwork);
                    VBOX_UTF16_FREE(internalNetwork);
4235
                }
E
Eric Blake 已提交
4236 4237 4238 4239 4240 4241
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
                PRUnichar *hostInterface = NULL;
                /* Host Only Networking (currently only vboxnet0 available
                 * on *nix and mac, on windows you can create and configure
                 * as many as you want)
                 */
4242
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4243
                adapter->vtbl->AttachToHostOnlyInterface(adapter);
4244
#else /* VBOX_API_VERSION >= 4001000 */
4245
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
4246
#endif /* VBOX_API_VERSION >= 4001000 */
4247

E
Eric Blake 已提交
4248 4249 4250
                if (def->nets[i]->data.network.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
                                       &hostInterface);
4251
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4252
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4253
#else /* VBOX_API_VERSION >= 4001000 */
4254
                    adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
4255
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4256 4257 4258 4259
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                /* NAT */
4260
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4261
                adapter->vtbl->AttachToNAT(adapter);
4262
#else /* VBOX_API_VERSION >= 4001000 */
4263
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4264
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4265 4266 4267 4268
            } else {
                /* else always default to NAT if we don't understand
                 * what option is been passed to us
                 */
4269
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4270
                adapter->vtbl->AttachToNAT(adapter);
4271
#else /* VBOX_API_VERSION >= 4001000 */
4272
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4273
#endif /* VBOX_API_VERSION >= 4001000 */
4274
            }
E
Eric Blake 已提交
4275 4276 4277 4278

            VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
            adapter->vtbl->SetMACAddress(adapter, MACAddress);
            VBOX_UTF16_FREE(MACAddress);
4279
        }
E
Eric Blake 已提交
4280 4281 4282 4283 4284 4285 4286 4287
    }
}

static void
vboxAttachSerial(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 serialPortCount            = 0;
4288
    size_t i = 0;
4289

E
Eric Blake 已提交
4290 4291 4292 4293 4294 4295 4296
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetSerialPortCount(systemProperties,
                                                   &serialPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4297

4298
    VIR_DEBUG("Number of Serial Ports to be connected: %zu", def->nserials);
4299
    VIR_DEBUG("Number of Serial Ports available: %d", serialPortCount);
E
Eric Blake 已提交
4300 4301
    for (i = 0; (i < def->nserials) && (i < serialPortCount); i++) {
        ISerialPort *serialPort = NULL;
4302

4303 4304
        VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source.type);
        VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4305
              def->serials[i]->target.port);
4306

E
Eric Blake 已提交
4307 4308 4309
        machine->vtbl->GetSerialPort(machine, i, &serialPort);
        if (serialPort) {
            PRUnichar *pathUtf16 = NULL;
4310

E
Eric Blake 已提交
4311
            serialPort->vtbl->SetEnabled(serialPort, 1);
4312

4313 4314 4315
            if (def->serials[i]->source.data.file.path) {
                VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
                                   &pathUtf16);
E
Eric Blake 已提交
4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330
                serialPort->vtbl->SetPath(serialPort, pathUtf16);
            }

            /* For now hard code the serial ports to COM1 and COM2,
             * COM1 (Base Addr: 0x3F8 (decimal: 1016), IRQ: 4)
             * COM2 (Base Addr: 0x2F8 (decimal:  760), IRQ: 3)
             * TODO: make this more flexible
             */
            /* TODO: to improve the libvirt XMl handling so
             * that def->serials[i]->target.port shows real port
             * and not always start at 0
             */
            if (def->serials[i]->target.port == 0) {
                serialPort->vtbl->SetIRQ(serialPort, 4);
                serialPort->vtbl->SetIOBase(serialPort, 1016);
4331
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4332
                      i, 4, 1016, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4333 4334 4335
            } else if (def->serials[i]->target.port == 1) {
                serialPort->vtbl->SetIRQ(serialPort, 3);
                serialPort->vtbl->SetIOBase(serialPort, 760);
4336
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4337
                      i, 3, 760, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4338
            }
4339

4340
            if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
E
Eric Blake 已提交
4341
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4342
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
E
Eric Blake 已提交
4343
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4344
#if VBOX_API_VERSION >= 3000000
4345
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
E
Eric Blake 已提交
4346
                serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4347
#endif /* VBOX_API_VERSION >= 3000000 */
E
Eric Blake 已提交
4348 4349 4350 4351
            } else {
                serialPort->vtbl->SetHostMode(serialPort,
                                              PortMode_Disconnected);
            }
4352

E
Eric Blake 已提交
4353
            VBOX_RELEASE(serialPort);
J
John Ferlan 已提交
4354
            VBOX_UTF16_FREE(pathUtf16);
4355
        }
E
Eric Blake 已提交
4356 4357
    }
}
4358

E
Eric Blake 已提交
4359 4360 4361 4362 4363
static void
vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 parallelPortCount          = 0;
4364
    size_t i = 0;
4365

E
Eric Blake 已提交
4366 4367 4368 4369 4370 4371 4372
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetParallelPortCount(systemProperties,
                                                     &parallelPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4373

4374
    VIR_DEBUG("Number of Parallel Ports to be connected: %zu", def->nparallels);
4375
    VIR_DEBUG("Number of Parallel Ports available: %d", parallelPortCount);
E
Eric Blake 已提交
4376 4377
    for (i = 0; (i < def->nparallels) && (i < parallelPortCount); i++) {
        IParallelPort *parallelPort = NULL;
4378

4379 4380
        VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source.type);
        VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4381
              def->parallels[i]->target.port);
4382

E
Eric Blake 已提交
4383 4384 4385
        machine->vtbl->GetParallelPort(machine, i, &parallelPort);
        if (parallelPort) {
            PRUnichar *pathUtf16 = NULL;
4386

4387
            VBOX_UTF8_TO_UTF16(def->parallels[i]->source.data.file.path, &pathUtf16);
4388

E
Eric Blake 已提交
4389 4390 4391 4392 4393
            /* For now hard code the parallel ports to
             * LPT1 (Base Addr: 0x378 (decimal: 888), IRQ: 7)
             * LPT2 (Base Addr: 0x278 (decimal: 632), IRQ: 5)
             * TODO: make this more flexible
             */
4394 4395 4396 4397
            if ((def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV)  ||
                (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)  ||
                (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) ||
                (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE)) {
E
Eric Blake 已提交
4398 4399 4400 4401
                parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                if (i == 0) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 7);
                    parallelPort->vtbl->SetIOBase(parallelPort, 888);
4402
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4403
                          i, 7, 888, def->parallels[i]->source.data.file.path);
E
Eric Blake 已提交
4404 4405 4406
                } else if (i == 1) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 5);
                    parallelPort->vtbl->SetIOBase(parallelPort, 632);
4407
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4408
                          i, 5, 632, def->parallels[i]->source.data.file.path);
4409 4410
                }
            }
E
Eric Blake 已提交
4411 4412 4413 4414 4415 4416 4417

            /* like serial port, parallel port can't be enabled unless
             * correct IRQ and IOBase values are specified.
             */
            parallelPort->vtbl->SetEnabled(parallelPort, 1);

            VBOX_RELEASE(parallelPort);
J
John Ferlan 已提交
4418
            VBOX_UTF16_FREE(pathUtf16);
4419
        }
E
Eric Blake 已提交
4420 4421 4422 4423 4424 4425 4426 4427
    }
}

static void
vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
{
    if ((def->nvideos == 1) &&
        (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4428 4429
        machine->vtbl->SetVRAMSize(machine,
                                   VIR_DIV_UP(def->videos[0]->vram, 1024));
E
Eric Blake 已提交
4430 4431 4432 4433
        machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
        if (def->videos[0]->accel) {
            machine->vtbl->SetAccelerate3DEnabled(machine,
                                                  def->videos[0]->accel->support3d);
4434
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4435 4436
            machine->vtbl->SetAccelerate2DVideoEnabled(machine,
                                                       def->videos[0]->accel->support2d);
4437
#endif /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
4438 4439
        } else {
            machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4440
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4441
            machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4442
#endif /* VBOX_API_VERSION >= 3001000 */
4443
        }
E
Eric Blake 已提交
4444 4445
    }
}
4446

E
Eric Blake 已提交
4447 4448 4449 4450 4451 4452 4453 4454
static void
vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int vrdpPresent  = 0;
    int sdlPresent   = 0;
    int guiPresent   = 0;
    char *guiDisplay = NULL;
    char *sdlDisplay = NULL;
4455
    size_t i = 0;
4456

E
Eric Blake 已提交
4457
    for (i = 0; i < def->ngraphics; i++) {
4458
#if VBOX_API_VERSION < 4000000
4459
        IVRDPServer *VRDxServer = NULL;
4460
#else /* VBOX_API_VERSION >= 4000000 */
4461
        IVRDEServer *VRDxServer = NULL;
4462
#endif /* VBOX_API_VERSION >= 4000000 */
4463

E
Eric Blake 已提交
4464 4465
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
            (vrdpPresent == 0)) {
4466

E
Eric Blake 已提交
4467
            vrdpPresent = 1;
4468
#if VBOX_API_VERSION < 4000000
4469
            machine->vtbl->GetVRDPServer(machine, &VRDxServer);
4470
#else /* VBOX_API_VERSION >= 4000000 */
4471
            machine->vtbl->GetVRDEServer(machine, &VRDxServer);
4472
#endif /* VBOX_API_VERSION >= 4000000 */
4473
            if (VRDxServer) {
4474 4475 4476
                const char *listenAddr
                    = virDomainGraphicsListenGetAddress(def->graphics[i], 0);

4477
                VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4478
                VIR_DEBUG("VRDP Support turned ON.");
4479

4480
#if VBOX_API_VERSION < 3001000
E
Eric Blake 已提交
4481
                if (def->graphics[i]->data.rdp.port) {
4482
                    VRDxServer->vtbl->SetPort(VRDxServer,
E
Eric Blake 已提交
4483
                                              def->graphics[i]->data.rdp.port);
4484
                    VIR_DEBUG("VRDP Port changed to: %d",
E
Eric Blake 已提交
4485 4486 4487 4488 4489
                          def->graphics[i]->data.rdp.port);
                } else if (def->graphics[i]->data.rdp.autoport) {
                    /* Setting the port to 0 will reset its value to
                     * the default one which is 3389 currently
                     */
4490
                    VRDxServer->vtbl->SetPort(VRDxServer, 0);
4491
                    VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
E
Eric Blake 已提交
4492
                }
4493
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
E
Eric Blake 已提交
4494 4495
                PRUnichar *portUtf16 = NULL;
                portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4496
                VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
E
Eric Blake 已提交
4497
                VBOX_UTF16_FREE(portUtf16);
4498
#else /* VBOX_API_VERSION >= 4000000 */
4499 4500 4501 4502 4503 4504 4505 4506
                PRUnichar *VRDEPortsKey = NULL;
                PRUnichar *VRDEPortsValue = NULL;
                VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
                VRDEPortsValue = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
                VRDxServer->vtbl->SetVRDEProperty(VRDxServer, VRDEPortsKey,
                                                  VRDEPortsValue);
                VBOX_UTF16_FREE(VRDEPortsKey);
                VBOX_UTF16_FREE(VRDEPortsValue);
4507
#endif /* VBOX_API_VERSION >= 4000000 */
4508

E
Eric Blake 已提交
4509
                if (def->graphics[i]->data.rdp.replaceUser) {
4510
                    VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
E
Eric Blake 已提交
4511
                                                               PR_TRUE);
4512
                    VIR_DEBUG("VRDP set to reuse single connection");
E
Eric Blake 已提交
4513
                }
4514

E
Eric Blake 已提交
4515
                if (def->graphics[i]->data.rdp.multiUser) {
4516
                    VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
E
Eric Blake 已提交
4517
                                                              PR_TRUE);
4518
                    VIR_DEBUG("VRDP set to allow multiple connection");
E
Eric Blake 已提交
4519
                }
4520

4521
                if (listenAddr) {
4522
#if VBOX_API_VERSION >= 4000000
4523 4524
                    PRUnichar *netAddressKey = NULL;
#endif
E
Eric Blake 已提交
4525
                    PRUnichar *netAddressUtf16 = NULL;
4526

4527
                    VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4528
#if VBOX_API_VERSION < 4000000
4529
                    VRDxServer->vtbl->SetNetAddress(VRDxServer,
E
Eric Blake 已提交
4530
                                                    netAddressUtf16);
4531
#else /* VBOX_API_VERSION >= 4000000 */
4532 4533 4534 4535
                    VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
                    VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
                                                      netAddressUtf16);
                    VBOX_UTF16_FREE(netAddressKey);
4536
#endif /* VBOX_API_VERSION >= 4000000 */
4537
                    VIR_DEBUG("VRDP listen address is set to: %s",
4538
                              listenAddr);
4539

E
Eric Blake 已提交
4540
                    VBOX_UTF16_FREE(netAddressUtf16);
4541
                }
E
Eric Blake 已提交
4542

4543
                VBOX_RELEASE(VRDxServer);
4544
            }
E
Eric Blake 已提交
4545
        }
4546

E
Eric Blake 已提交
4547 4548 4549
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
            (guiPresent == 0)) {
            guiPresent = 1;
4550 4551 4552 4553 4554
            if (VIR_STRDUP(guiDisplay, def->graphics[i]->data.desktop.display) < 0) {
                /* just don't go to cleanup yet as it is ok to have
                 * guiDisplay as NULL and we check it below if it
                 * exist and then only use it there
                 */
4555
            }
E
Eric Blake 已提交
4556
        }
4557

E
Eric Blake 已提交
4558 4559 4560
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
            (sdlPresent == 0)) {
            sdlPresent = 1;
4561 4562 4563 4564 4565
            if (VIR_STRDUP(sdlDisplay, def->graphics[i]->data.sdl.display) < 0) {
                /* 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
                 */
4566
            }
4567
        }
E
Eric Blake 已提交
4568
    }
4569

E
Eric Blake 已提交
4570 4571 4572 4573
    if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
        /* store extradata key that frontend is set to vrdp */
        PRUnichar *keyTypeUtf16   = NULL;
        PRUnichar *valueTypeUtf16 = NULL;
4574

E
Eric Blake 已提交
4575 4576
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4577

E
Eric Blake 已提交
4578
        machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4579

E
Eric Blake 已提交
4580 4581
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4582

E
Eric Blake 已提交
4583 4584 4585 4586 4587 4588
    } else if ((guiPresent == 0) && (sdlPresent == 1)) {
        /* store extradata key that frontend is set to sdl */
        PRUnichar *keyTypeUtf16      = NULL;
        PRUnichar *valueTypeUtf16    = NULL;
        PRUnichar *keyDislpayUtf16   = NULL;
        PRUnichar *valueDisplayUtf16 = NULL;
4589

E
Eric Blake 已提交
4590 4591
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4592

E
Eric Blake 已提交
4593
        machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4594

E
Eric Blake 已提交
4595 4596
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4597

E
Eric Blake 已提交
4598 4599 4600
        if (sdlDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4601

E
Eric Blake 已提交
4602 4603
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4604

E
Eric Blake 已提交
4605 4606 4607
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
        }
4608

E
Eric Blake 已提交
4609 4610 4611 4612 4613 4614
    } else {
        /* if all are set then default is gui, with vrdp turned on */
        PRUnichar *keyTypeUtf16      = NULL;
        PRUnichar *valueTypeUtf16    = NULL;
        PRUnichar *keyDislpayUtf16   = NULL;
        PRUnichar *valueDisplayUtf16 = NULL;
4615

E
Eric Blake 已提交
4616 4617
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
4618

E
Eric Blake 已提交
4619
        machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4620

E
Eric Blake 已提交
4621 4622
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4623

E
Eric Blake 已提交
4624 4625 4626
        if (guiDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4627

E
Eric Blake 已提交
4628 4629
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4630

E
Eric Blake 已提交
4631 4632
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
4633
        }
E
Eric Blake 已提交
4634
    }
4635

E
Eric Blake 已提交
4636 4637 4638
    VIR_FREE(guiDisplay);
    VIR_FREE(sdlDisplay);
}
4639

E
Eric Blake 已提交
4640 4641 4642
static void
vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
4643
#if VBOX_API_VERSION < 4003000
E
Eric Blake 已提交
4644
    IUSBController *USBController = NULL;
R
Ryota Ozaki 已提交
4645 4646 4647
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
4648
    size_t i = 0;
E
Eric Blake 已提交
4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659
    bool isUSB = false;

    if (def->nhostdevs == 0)
        return;

    /* Loop through the devices first and see if you
     * have a USB Device, only if you have one then
     * start the USB controller else just proceed as
     * usual
     */
    for (i = 0; i < def->nhostdevs; i++) {
R
Ryota Ozaki 已提交
4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675
        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;

        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;

        if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
            !def->hostdevs[i]->source.subsys.u.usb.product)
            continue;

        VIR_DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
                  def->hostdevs[i]->source.subsys.u.usb.vendor,
                  def->hostdevs[i]->source.subsys.u.usb.product);
        isUSB = true;
        break;
E
Eric Blake 已提交
4676 4677
    }

R
Ryota Ozaki 已提交
4678 4679 4680
    if (!isUSB)
        return;

4681
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4682 4683 4684 4685 4686 4687 4688 4689 4690
    /* First Start the USB Controller and then loop
     * to attach USB Devices to it
     */
    machine->vtbl->GetUSBController(machine, &USBController);

    if (!USBController)
        return;

    USBController->vtbl->SetEnabled(USBController, 1);
4691
# if VBOX_API_VERSION < 4002000
R
Ryota Ozaki 已提交
4692
    USBController->vtbl->SetEnabledEhci(USBController, 1);
R
Ryota Ozaki 已提交
4693
# else
R
Ryota Ozaki 已提交
4694
    USBController->vtbl->SetEnabledEHCI(USBController, 1);
R
Ryota Ozaki 已提交
4695 4696 4697 4698 4699 4700
# endif
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;
4701
#endif
4702

R
Ryota Ozaki 已提交
4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713
    for (i = 0; i < def->nhostdevs; i++) {
        char *filtername           = NULL;
        PRUnichar *filternameUtf16 = NULL;
        IUSBDeviceFilter *filter   = NULL;
        PRUnichar *vendorIdUtf16  = NULL;
        char vendorId[40]         = {0};
        PRUnichar *productIdUtf16 = NULL;
        char productId[40]        = {0};

        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
4714

R
Ryota Ozaki 已提交
4715 4716 4717
        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;
4718

R
Ryota Ozaki 已提交
4719 4720 4721 4722 4723 4724
        /* Zero pad for nice alignment when fewer than 9999
         * devices.
         */
        if (virAsprintf(&filtername, "filter%04zu", i) >= 0) {
            VBOX_UTF8_TO_UTF16(filtername, &filternameUtf16);
            VIR_FREE(filtername);
4725
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4726 4727 4728
            USBController->vtbl->CreateDeviceFilter(USBController,
                                                    filternameUtf16,
                                                    &filter);
R
Ryota Ozaki 已提交
4729 4730 4731 4732 4733
#else
            USBDeviceFilters->vtbl->CreateDeviceFilter(USBDeviceFilters,
                                                       filternameUtf16,
                                                       &filter);
#endif
R
Ryota Ozaki 已提交
4734 4735
        }
        VBOX_UTF16_FREE(filternameUtf16);
E
Eric Blake 已提交
4736

R
Ryota Ozaki 已提交
4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757
        if (!filter)
            continue;

        if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
            !def->hostdevs[i]->source.subsys.u.usb.product)
            continue;

        if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
            snprintf(vendorId, sizeof(vendorId), "%x",
                     def->hostdevs[i]->source.subsys.u.usb.vendor);
            VBOX_UTF8_TO_UTF16(vendorId, &vendorIdUtf16);
            filter->vtbl->SetVendorId(filter, vendorIdUtf16);
            VBOX_UTF16_FREE(vendorIdUtf16);
        }
        if (def->hostdevs[i]->source.subsys.u.usb.product) {
            snprintf(productId, sizeof(productId), "%x",
                     def->hostdevs[i]->source.subsys.u.usb.product);
            VBOX_UTF8_TO_UTF16(productId, &productIdUtf16);
            filter->vtbl->SetProductId(filter,
                                       productIdUtf16);
            VBOX_UTF16_FREE(productIdUtf16);
E
Eric Blake 已提交
4758
        }
R
Ryota Ozaki 已提交
4759
        filter->vtbl->SetActive(filter, 1);
4760
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4761 4762 4763
        USBController->vtbl->InsertDeviceFilter(USBController,
                                                i,
                                                filter);
R
Ryota Ozaki 已提交
4764 4765 4766 4767 4768
#else
        USBDeviceFilters->vtbl->InsertDeviceFilter(USBDeviceFilters,
                                                   i,
                                                   filter);
#endif
R
Ryota Ozaki 已提交
4769
        VBOX_RELEASE(filter);
E
Eric Blake 已提交
4770
    }
R
Ryota Ozaki 已提交
4771

4772
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4773
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
4774 4775 4776
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
E
Eric Blake 已提交
4777 4778
}

M
Matthias Bolte 已提交
4779 4780 4781
static void
vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
4782
    size_t i;
M
Matthias Bolte 已提交
4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797
    PRUnichar *nameUtf16;
    PRUnichar *hostPathUtf16;
    PRBool writable;

    if (def->nfss == 0)
        return;

    for (i = 0; i < def->nfss; i++) {
        if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
            continue;

        VBOX_UTF8_TO_UTF16(def->fss[i]->dst, &nameUtf16);
        VBOX_UTF8_TO_UTF16(def->fss[i]->src, &hostPathUtf16);
        writable = !def->fss[i]->readonly;

4798
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
4799 4800
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable);
4801
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
4802 4803
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable, PR_FALSE);
4804
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
4805 4806 4807 4808 4809 4810

        VBOX_UTF16_FREE(nameUtf16);
        VBOX_UTF16_FREE(hostPathUtf16);
    }
}

4811 4812
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml)
{
E
Eric Blake 已提交
4813 4814 4815
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
4816 4817
    vboxIID iid = VBOX_IID_INITIALIZER;
    vboxIID mchiid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
4818 4819
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;
4820
#if VBOX_API_VERSION >= 3002000 && VBOX_API_VERSION < 4002000
E
Eric Blake 已提交
4821 4822 4823
    PRBool override             = PR_FALSE;
#endif
    nsresult rc;
4824
    char uuidstr[VIR_UUID_STRING_BUFLEN];
4825
#if VBOX_API_VERSION >= 4002000
4826 4827 4828 4829 4830 4831
    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;
#endif
E
Eric Blake 已提交
4832

4833 4834
    if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_VBOX,
E
Eric Blake 已提交
4835 4836 4837 4838 4839
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
4840
    vboxIIDFromUUID(&iid, def->uuid);
4841 4842
    virUUIDFormat(def->uuid, uuidstr);

4843
#if VBOX_API_VERSION < 3002000
E
Eric Blake 已提交
4844 4845 4846 4847
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
4848
                                            iid.value,
E
Eric Blake 已提交
4849
                                            &machine);
4850
#elif VBOX_API_VERSION < 4000000 /* 3002000 <= VBOX_API_VERSION < 4000000 */
E
Eric Blake 已提交
4851 4852 4853 4854
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
4855
                                            iid.value,
E
Eric Blake 已提交
4856 4857
                                            override,
                                            &machine);
4858
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
4859 4860 4861 4862 4863 4864 4865
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            NULL,
                                            iid.value,
                                            override,
                                            &machine);
4866
#else /* VBOX_API_VERSION >= 4002000 */
4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881
    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);
4882
#endif /* VBOX_API_VERSION >= 4002000 */
E
Eric Blake 已提交
4883 4884 4885
    VBOX_UTF16_FREE(machineNameUtf16);

    if (NS_FAILED(rc)) {
4886 4887
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
4888 4889 4890
        goto cleanup;
    }

4891 4892
    rc = machine->vtbl->SetMemorySize(machine,
                                      VIR_DIV_UP(def->mem.cur_balloon, 1024));
E
Eric Blake 已提交
4893
    if (NS_FAILED(rc)) {
4894 4895 4896 4897
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the memory size of the domain to: %llu Kb, "
                         "rc=%08x"),
                       def->mem.cur_balloon, (unsigned)rc);
E
Eric Blake 已提交
4898 4899
    }

E
Eric Blake 已提交
4900
    if (def->vcpus != def->maxvcpus) {
4901 4902
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
4903 4904
    }
    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
E
Eric Blake 已提交
4905
    if (NS_FAILED(rc)) {
4906 4907 4908
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the number of virtual CPUs to: %u, rc=%08x"),
                       def->maxvcpus, (unsigned)rc);
E
Eric Blake 已提交
4909 4910
    }

4911
#if VBOX_API_VERSION < 3001000
4912 4913
    rc = machine->vtbl->SetPAEEnabled(machine,
                                      def->features[VIR_DOMAIN_FEATURE_PAE] ==
J
Ján Tomko 已提交
4914
                                      VIR_TRISTATE_SWITCH_ON);
4915
#elif VBOX_API_VERSION == 3001000
E
Eric Blake 已提交
4916
    rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
4917
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
J
Ján Tomko 已提交
4918
                                       VIR_TRISTATE_SWITCH_ON);
4919
#elif VBOX_API_VERSION >= 3002000
E
Eric Blake 已提交
4920
    rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
4921
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
J
Ján Tomko 已提交
4922
                                       VIR_TRISTATE_SWITCH_ON);
E
Eric Blake 已提交
4923 4924
#endif
    if (NS_FAILED(rc)) {
4925 4926
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not change PAE status to: %s, rc=%08x"),
J
Ján Tomko 已提交
4927
                       (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_TRISTATE_SWITCH_ON)
4928
                       ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
4929 4930 4931 4932
    }

    machine->vtbl->GetBIOSSettings(machine, &bios);
    if (bios) {
4933 4934
        rc = bios->vtbl->SetACPIEnabled(bios,
                                        def->features[VIR_DOMAIN_FEATURE_ACPI] ==
J
Ján Tomko 已提交
4935
                                        VIR_TRISTATE_SWITCH_ON);
E
Eric Blake 已提交
4936
        if (NS_FAILED(rc)) {
4937 4938
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change ACPI status to: %s, rc=%08x"),
J
Ján Tomko 已提交
4939
                           (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_TRISTATE_SWITCH_ON)
4940
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
4941
        }
4942 4943
        rc = bios->vtbl->SetIOAPICEnabled(bios,
                                          def->features[VIR_DOMAIN_FEATURE_APIC] ==
J
Ján Tomko 已提交
4944
                                          VIR_TRISTATE_SWITCH_ON);
E
Eric Blake 已提交
4945
        if (NS_FAILED(rc)) {
4946 4947
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change APIC status to: %s, rc=%08x"),
J
Ján Tomko 已提交
4948
                           (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_TRISTATE_SWITCH_ON)
4949
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
4950
        }
E
Eric Blake 已提交
4951 4952 4953 4954 4955 4956
        VBOX_RELEASE(bios);
    }

    /* Register the machine before attaching other devices to it */
    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
4957 4958
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
4959 4960 4961 4962 4963 4964 4965
        goto cleanup;
    }

    /* Get the uuid of the machine, currently it is immutable
     * object so open a session to it and get it back, so that
     * you can make changes to the machine setting
     */
4966
    machine->vtbl->GetId(machine, &mchiid.value);
4967
    VBOX_SESSION_OPEN(mchiid.value, machine);
E
Eric Blake 已提交
4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978
    data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);

    vboxSetBootDeviceOrder(def, data, machine);
    vboxAttachDrives(def, data, machine);
    vboxAttachSound(def, machine);
    vboxAttachNetwork(def, data, machine);
    vboxAttachSerial(def, data, machine);
    vboxAttachParallel(def, data, machine);
    vboxAttachVideo(def, machine);
    vboxAttachDisplay(def, data, machine);
    vboxAttachUSB(def, data, machine);
M
Matthias Bolte 已提交
4979
    vboxAttachSharedFolder(def, data, machine);
4980

4981 4982 4983 4984
    /* Save the machine settings made till now and close the
     * session. also free up the mchiid variable used.
     */
    rc = machine->vtbl->SaveSettings(machine);
4985
    VBOX_SESSION_CLOSE();
4986
    vboxIIDUnalloc(&mchiid);
4987

4988 4989
    ret = virGetDomain(conn, def->name, def->uuid);
    VBOX_RELEASE(machine);
4990

4991
    vboxIIDUnalloc(&iid);
4992 4993
    virDomainDefFree(def);

4994
    return ret;
4995

4996
 cleanup:
4997
    VBOX_RELEASE(machine);
4998
    vboxIIDUnalloc(&iid);
4999 5000 5001 5002
    virDomainDefFree(def);
    return NULL;
}

5003
static int
5004
vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
5005
{
5006
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5007
    IMachine *machine    = NULL;
5008
    vboxIID iid = VBOX_IID_INITIALIZER;
5009
    nsresult rc;
5010
#if VBOX_API_VERSION >= 4000000
5011 5012
    vboxArray media = VBOX_ARRAY_INITIALIZER;
#endif
5013 5014 5015 5016
    /* No managed save, so we explicitly reject
     * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE.  No snapshot metadata for
     * VBox, so we can trivially ignore that flag.  */
    virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5017

5018
    vboxIIDFromUUID(&iid, dom->uuid);
5019

5020
#if VBOX_API_VERSION < 4000000
5021 5022 5023
    /* Block for checking if HDD's are attched to VM.
     * considering just IDE bus for now. Also skipped
     * chanel=1 and device=0 (Secondary Master) as currenlty
5024 5025 5026 5027
     * it is allocated to CD/DVD Drive by default.
     *
     * Only do this for VirtualBox 3.x and before. Since
     * VirtualBox 4.0 the Unregister method can do this for use.
5028 5029 5030
     */
    {
        PRUnichar *hddcnameUtf16 = NULL;
5031

5032 5033
        char *hddcname;
        ignore_value(VIR_STRDUP(hddcname, "IDE"));
5034 5035
        VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
        VIR_FREE(hddcname);
5036

5037
        /* Open a Session for the machine */
5038
        rc = VBOX_SESSION_OPEN(iid.value, machine);
5039 5040 5041 5042
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {

5043
# if VBOX_API_VERSION < 3001000
5044 5045 5046 5047
                /* 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);
5048
# else  /* VBOX_API_VERSION >= 3001000 */
5049 5050 5051
                /* get all the controller first, then the attachments and
                 * remove them all so that the machine can be undefined
                 */
5052
                vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
5053
                size_t i = 0, j = 0;
5054

5055 5056
                vboxArrayGet(&storageControllers, machine,
                             machine->vtbl->GetStorageControllers);
5057

5058 5059
                for (i = 0; i < storageControllers.count; i++) {
                    IStorageController *strCtl = storageControllers.items[i];
5060
                    PRUnichar *strCtlName = NULL;
5061
                    vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5062 5063 5064 5065 5066

                    if (!strCtl)
                        continue;

                    strCtl->vtbl->GetName(strCtl, &strCtlName);
5067 5068 5069
                    vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                                           machine->vtbl->GetMediumAttachmentsOfController,
                                           strCtlName);
5070

5071 5072
                    for (j = 0; j < mediumAttachments.count; j++) {
                        IMediumAttachment *medAtt = mediumAttachments.items[j];
5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088
                        PRInt32 port = ~0U;
                        PRInt32 device = ~0U;

                        if (!medAtt)
                            continue;

                        medAtt->vtbl->GetPort(medAtt, &port);
                        medAtt->vtbl->GetDevice(medAtt, &device);

                        if ((port != ~0U) && (device != ~0U)) {
                            machine->vtbl->DetachDevice(machine,
                                                        strCtlName,
                                                        port,
                                                        device);
                        }
                    }
5089

5090 5091
                    vboxArrayRelease(&storageControllers);

5092 5093
                    machine->vtbl->RemoveStorageController(machine, strCtlName);
                    VBOX_UTF16_FREE(strCtlName);
5094
                }
5095 5096

                vboxArrayRelease(&storageControllers);
5097
# endif /* VBOX_API_VERSION >= 3001000 */
5098 5099

                machine->vtbl->SaveSettings(machine);
5100
            }
5101
            VBOX_SESSION_CLOSE();
5102
        }
5103 5104
        VBOX_UTF16_FREE(hddcnameUtf16);
    }
5105
#endif
5106

5107
#if VBOX_API_VERSION < 4000000
5108
    rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
5109
#else /* VBOX_API_VERSION >= 4000000 */
5110 5111
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5112 5113
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5114 5115 5116 5117 5118 5119 5120 5121 5122
        return -1;
    }

    /* 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);
5123
#endif /* VBOX_API_VERSION >= 4000000 */
5124
    DEBUGIID("UUID of machine being undefined", iid.value);
5125

5126
    if (NS_SUCCEEDED(rc)) {
5127
#if VBOX_API_VERSION < 4000000
5128
        machine->vtbl->DeleteSettings(machine);
5129
#else /* VBOX_API_VERSION >= 4000000 */
5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142
        IProgress *progress = NULL;

        /* 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);

5143
#  if VBOX_API_VERSION < 4003000
5144
        ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
R
Ryota Ozaki 已提交
5145 5146 5147
#  else
        ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
#  endif
5148
# else
5149 5150 5151
        /* 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 };
5152
#  if VBOX_API_VERSION < 4003000
5153
        machine->vtbl->Delete(machine, 0, array, &progress);
R
Ryota Ozaki 已提交
5154 5155 5156
#  else
        machine->vtbl->DeleteConfig(machine, 0, array, &progress);
#  endif
5157 5158 5159 5160 5161
# endif
        if (progress != NULL) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
5162
#endif /* VBOX_API_VERSION >= 4000000 */
5163 5164
        ret = 0;
    } else {
5165 5166
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not delete the domain, rc=%08x"), (unsigned)rc);
5167 5168
    }

5169
#if VBOX_API_VERSION >= 4000000
5170 5171
    vboxArrayUnalloc(&media);
#endif
5172
    vboxIIDUnalloc(&iid);
5173
    VBOX_RELEASE(machine);
5174 5175 5176 5177

    return ret;
}

5178 5179 5180 5181 5182 5183
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

5184 5185
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
5186 5187
                                      int mediaChangeOnly ATTRIBUTE_UNUSED)
{
5188
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5189
    IMachine *machine    = NULL;
5190
    vboxIID iid = VBOX_IID_INITIALIZER;
5191 5192 5193
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5194
    nsresult rc;
5195

5196
    if (VIR_ALLOC(def) < 0)
5197 5198
        return ret;

5199
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5200 5201
        goto cleanup;

5202 5203
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5204
    if (dev == NULL)
5205 5206
        goto cleanup;

5207
    vboxIIDFromUUID(&iid, dom->uuid);
5208
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5209
    if (NS_FAILED(rc)) {
5210 5211
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5212 5213
        goto cleanup;
    }
5214

5215 5216
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5217

5218 5219
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5220
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5221
        } else {
5222
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5223 5224 5225 5226 5227
        }
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5228
#if VBOX_API_VERSION < 3001000
5229 5230 5231
                    const char *src = virDomainDiskGetSource(dev->data.disk);
                    int type = virDomainDiskGetType(dev->data.disk);

5232
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
5233
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
5234 5235 5236 5237 5238 5239 5240 5241 5242
                            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;
5243 5244
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5245

5246
                                VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
5247

5248 5249
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
5250
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5251 5252
                                }
                                if (dvdImage) {
5253
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5254
                                    if (NS_FAILED(rc)) {
5255 5256 5257
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
5258
                                                       src, (unsigned)rc);
5259 5260 5261
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
5262
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5263
                                        if (NS_FAILED(rc)) {
5264 5265
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
5266
                                                           src, (unsigned)rc);
5267
                                        } else {
5268
                                            ret = 0;
5269
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5270 5271
                                        }
                                    }
5272 5273

                                    VBOX_MEDIUM_RELEASE(dvdImage);
5274
                                }
5275
                                vboxIIDUnalloc(&dvduuid);
5276 5277
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
5278
                            }
E
Eric Blake 已提交
5279
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5280 5281
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
5282
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
5283 5284 5285 5286 5287 5288 5289
                            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;
5290 5291
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5292
                                    VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
5293 5294 5295 5296 5297 5298 5299
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
5300
                                                                             fdemptyuuid.value,
5301 5302
                                                                             &floppyImage);
                                    }
5303

5304
                                    if (floppyImage) {
5305
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5306
                                        if (NS_FAILED(rc)) {
5307 5308 5309
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
5310
                                                           src, (unsigned)rc);
5311
                                        } else {
5312
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5313
                                            if (NS_FAILED(rc)) {
5314 5315
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
5316
                                                               src, (unsigned)rc);
5317
                                            } else {
5318
                                                ret = 0;
5319
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
5320 5321
                                            }
                                        }
5322
                                        VBOX_MEDIUM_RELEASE(floppyImage);
5323
                                    }
5324
                                    vboxIIDUnalloc(&fduuid);
5325
                                    VBOX_UTF16_FREE(fdfileUtf16);
5326
                                }
5327
                                VBOX_RELEASE(floppyDrive);
5328
                            }
E
Eric Blake 已提交
5329
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5330
                        }
5331
                    }
5332 5333
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5334 5335 5336 5337
                } 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) {
5338 5339
                        }
                    }
M
Matthias Bolte 已提交
5340 5341 5342 5343 5344 5345 5346 5347 5348 5349
                } 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;

5350
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
5351 5352
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable);
5353
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5354 5355
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable, PR_FALSE);
5356
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5357 5358

                    if (NS_FAILED(rc)) {
5359 5360 5361
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5362 5363 5364 5365 5366 5367
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
5368
                }
5369 5370
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5371
            }
5372
            VBOX_SESSION_CLOSE();
5373 5374 5375
        }
    }

5376
 cleanup:
5377
    vboxIIDUnalloc(&iid);
5378 5379 5380 5381 5382
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5383 5384
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
{
5385 5386 5387
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

5388 5389 5390 5391 5392 5393
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5394
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5395 5396
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5397 5398 5399
        return -1;
    }

5400 5401 5402 5403
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
5404 5405
                                       unsigned int flags)
{
5406 5407 5408
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5409

5410
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5411 5412
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5413 5414 5415 5416
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5417 5418
}

5419 5420
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
{
5421
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5422
    IMachine *machine    = NULL;
5423
    vboxIID iid = VBOX_IID_INITIALIZER;
5424 5425 5426
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5427
    nsresult rc;
5428

5429
    if (VIR_ALLOC(def) < 0)
5430 5431
        return ret;

5432
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5433 5434
        goto cleanup;

5435 5436
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5437
    if (dev == NULL)
5438 5439
        goto cleanup;

5440
    vboxIIDFromUUID(&iid, dom->uuid);
5441
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5442
    if (NS_FAILED(rc)) {
5443 5444
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5445 5446
        goto cleanup;
    }
5447

5448 5449
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5450

5451 5452
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5453
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5454
        } else {
5455
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5456
        }
5457

5458 5459 5460 5461
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5462
#if VBOX_API_VERSION < 3001000
5463 5464
                    int type = virDomainDiskGetType(dev->data.disk);

5465
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
5466
                        if (type == VIR_STORAGE_TYPE_FILE) {
5467 5468 5469 5470 5471 5472 5473 5474 5475
                            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)) {
5476 5477 5478
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5479 5480 5481 5482 5483
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
E
Eric Blake 已提交
5484
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5485 5486
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
5487
                        if (type == VIR_STORAGE_TYPE_FILE) {
5488 5489 5490 5491 5492 5493 5494 5495
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                PRBool enabled = PR_FALSE;

                                floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                                if (enabled) {
                                    rc = floppyDrive->vtbl->Unmount(floppyDrive);
5496
                                    if (NS_FAILED(rc)) {
5497 5498 5499 5500
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5501 5502 5503
                                    } else {
                                        ret = 0;
                                    }
5504 5505 5506 5507 5508
                                } 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;
5509
                                }
5510
                                VBOX_RELEASE(floppyDrive);
5511
                            }
E
Eric Blake 已提交
5512
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5513
                        }
5514
                    }
5515 5516
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5517 5518 5519 5520
                } 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) {
5521 5522
                        }
                    }
M
Matthias Bolte 已提交
5523 5524 5525 5526 5527 5528 5529 5530 5531
                } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
                           dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
                    PRUnichar *nameUtf16;

                    VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);

                    rc = machine->vtbl->RemoveSharedFolder(machine, nameUtf16);

                    if (NS_FAILED(rc)) {
5532 5533 5534
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5535 5536 5537 5538 5539
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5540
                }
5541 5542
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5543
            }
5544
            VBOX_SESSION_CLOSE();
5545 5546 5547
        }
    }

5548
 cleanup:
5549
    vboxIIDUnalloc(&iid);
5550 5551 5552 5553 5554
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5555 5556 5557 5558 5559 5560
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5561
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5562 5563
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5564 5565 5566 5567 5568 5569
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5570 5571 5572 5573 5574
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5575
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5576 5577 5578 5579 5580 5581 5582 5583
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5584 5585 5586
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5587 5588 5589 5590 5591 5592
        goto error;
    }

    if (count == 0)
        goto out;

5593
    if (VIR_ALLOC_N(list, count) < 0)
J
Jiri Denemark 已提交
5594 5595
        goto error;

5596
#if VBOX_API_VERSION < 4000000
5597
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5598
#else /* VBOX_API_VERSION >= 4000000 */
5599
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
5600
#endif /* VBOX_API_VERSION >= 4000000 */
J
Jiri Denemark 已提交
5601
    if (NS_FAILED(rc) || !list[0]) {
5602 5603 5604
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5605 5606 5607 5608 5609 5610
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5611
        vboxArray children = VBOX_ARRAY_INITIALIZER;
5612
        size_t i;
J
Jiri Denemark 已提交
5613 5614

        if (!list[next]) {
5615 5616
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5617 5618 5619
            goto error;
        }

5620 5621
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5622
        if (NS_FAILED(rc)) {
5623 5624
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5625 5626
            goto error;
        }
5627 5628 5629
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5630 5631
                continue;
            if (top == count) {
5632 5633
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5634
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5635 5636
                goto error;
            }
5637 5638
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5639
        }
5640
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5641 5642
    }

5643
 out:
J
Jiri Denemark 已提交
5644 5645 5646
    *snapshots = list;
    return count;

5647
 error:
J
Jiri Denemark 已提交
5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666
    if (list) {
        for (next = 0; next < count; next++)
            VBOX_RELEASE(list[next]);
    }
    VIR_FREE(list);

    return -1;
}

static ISnapshot *
vboxDomainSnapshotGet(vboxGlobalData *data,
                      virDomainPtr dom,
                      IMachine *machine,
                      const char *name)
{
    ISnapshot **snapshots = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;
    int count = 0;
5667
    size_t i;
J
Jiri Denemark 已提交
5668 5669 5670 5671 5672 5673 5674 5675 5676 5677

    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) {
5678 5679
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692
            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) {
5693 5694 5695
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
5696 5697 5698
        goto cleanup;
    }

5699
 cleanup:
J
Jiri Denemark 已提交
5700 5701 5702 5703 5704 5705 5706 5707 5708 5709
    if (count > 0) {
        for (i = 0; i < count; i++) {
            if (snapshots[i] != snapshot)
                VBOX_RELEASE(snapshots[i]);
        }
    }
    VIR_FREE(snapshots);
    return snapshot;
}

5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 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 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960
#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]);
5961 5962 5963 5964 5965
            if (parentUuid == NULL) {
                VIR_FREE(readWriteDisk);
                goto cleanup;
            }

5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 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 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 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 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666
            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 已提交
6667 6668 6669
static virDomainSnapshotPtr
vboxDomainSnapshotCreateXML(virDomainPtr dom,
                            const char *xmlDesc,
6670
                            unsigned int flags)
J
Jiri Denemark 已提交
6671 6672 6673
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
6674
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6675 6676 6677 6678 6679 6680 6681 6682
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
6683
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
6684 6685 6686 6687
    nsresult result;
#else
    PRInt32 result;
#endif
6688 6689 6690 6691
#if VBOX_API_VERSION >= 4002000
    bool isCurrent = false;
#endif

J
Jiri Denemark 已提交
6692

6693
    /* VBox has no snapshot metadata, so this flag is trivial.  */
6694 6695 6696
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
                  VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT, NULL);
6697

6698
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
6699 6700 6701
                                                data->xmlopt, -1,
                                                VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
                                                VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE)))
J
Jiri Denemark 已提交
6702 6703
        goto cleanup;

6704

6705
    vboxIIDFromUUID(&domiid, dom->uuid);
6706
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6707
    if (NS_FAILED(rc)) {
6708 6709
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6710 6711 6712
        goto cleanup;
    }

6713 6714 6715 6716 6717 6718 6719 6720 6721 6722
#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 已提交
6723 6724
    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6725 6726
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6727 6728 6729 6730 6731
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
6732
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
6733
    } else {
6734
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6735
    }
6736

J
Jiri Denemark 已提交
6737 6738 6739
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6740 6741 6742
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761
        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) {
6762 6763
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6764 6765 6766 6767 6768 6769
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6770 6771
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6772 6773 6774 6775 6776
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6777 6778
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
6779 6780 6781 6782 6783 6784
                  dom->name);
        goto cleanup;
    }

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

6785
 cleanup:
J
Jiri Denemark 已提交
6786 6787 6788 6789
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
6790
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6791
    VBOX_RELEASE(machine);
6792
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6793 6794 6795 6796
    virDomainSnapshotDefFree(def);
    return ret;
}

6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868
#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;
6869 6870 6871 6872
    for (i = 0; i < def->ndisks; i++) {
        if (VIR_ALLOC(def->disks[i].src) < 0)
            goto cleanup;
    }
6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970

    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",
6971
                                       _("cannot get medium attachment type"));
6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999
                        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) {
7000 7001 7002 7003 7004
        for (i = 0; i < def->ndisks; i++) {
            VIR_FREE(def->disks[i].src);
        }
        VIR_FREE(def->disks);
        def->ndisks = 0;
7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077
    }
    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++) {
7078 7079
            virDomainDiskDefPtr diskDef = virDomainDiskDefNew();
            if (!diskDef)
7080
                goto cleanup;
7081
            def->dom->disks[i] = diskDef;
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 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191
        }
    } 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)
7192
            def->dom->disks[diskCount]->src->readonly = true;
7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215
        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++)
7216
            virDomainDiskDefFree(def->dom->disks[i]);
7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227
        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 已提交
7228
static char *
7229 7230
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
7231 7232 7233
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
7234
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7235 7236 7237 7238 7239 7240 7241 7242 7243 7244
    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];
7245 7246 7247 7248
#if VBOX_API_VERSION >=4002000
    PRUint32 memorySize                 = 0;
    PRUint32 CPUCount                 = 0;
#endif
J
Jiri Denemark 已提交
7249

7250 7251
    virCheckFlags(0, NULL);

7252
    vboxIIDFromUUID(&domiid, dom->uuid);
7253
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
7254
    if (NS_FAILED(rc)) {
7255 7256
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7257 7258 7259 7260 7261 7262
        goto cleanup;
    }

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

7263
    if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0)
7264
        goto cleanup;
7265 7266
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
7267

7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297
#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 已提交
7298 7299
    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
7300 7301 7302
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7303 7304 7305 7306 7307
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
7308 7309 7310 7311
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
7312 7313 7314 7315 7316
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
7317 7318 7319
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7320 7321 7322 7323 7324 7325 7326
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
7327 7328 7329
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7330 7331 7332 7333 7334
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
7335 7336 7337
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
7338 7339 7340 7341
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
7342 7343
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
7344
            goto cleanup;
7345 7346
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
7347 7348 7349 7350
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
7351 7352 7353
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7354 7355 7356 7357 7358 7359 7360 7361
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

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

7365
 cleanup:
J
Jiri Denemark 已提交
7366 7367 7368 7369
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
7370
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7371 7372 7373 7374 7375
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
7376
                      unsigned int flags)
J
Jiri Denemark 已提交
7377 7378
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7379
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7380 7381 7382 7383
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

7384 7385
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
7386

7387
    vboxIIDFromUUID(&iid, dom->uuid);
7388
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7389
    if (NS_FAILED(rc)) {
7390 7391
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7392 7393 7394
        goto cleanup;
    }

7395 7396 7397 7398 7399 7400
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
7401 7402
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
7403 7404 7405
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7406 7407 7408
        goto cleanup;
    }

7409 7410 7411 7412 7413
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
7414

7415
 cleanup:
J
Jiri Denemark 已提交
7416
    VBOX_RELEASE(machine);
7417
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7418 7419 7420 7421 7422 7423 7424
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
7425
                            unsigned int flags)
J
Jiri Denemark 已提交
7426 7427
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7428
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7429 7430 7431 7432
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
7433
    size_t i;
J
Jiri Denemark 已提交
7434

7435 7436
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
7437

7438
    vboxIIDFromUUID(&iid, dom->uuid);
7439
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7440
    if (NS_FAILED(rc)) {
7441 7442
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7443 7444 7445
        goto cleanup;
    }

7446 7447 7448 7449 7450
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

7451 7452 7453
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

7454
        if (VIR_ALLOC_N(snapshots, 1) < 0)
7455
            goto cleanup;
7456
#if VBOX_API_VERSION < 4000000
7457
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
7458
#else /* VBOX_API_VERSION >= 4000000 */
7459
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
7460
#endif /* VBOX_API_VERSION >= 4000000 */
7461
        if (NS_FAILED(rc) || !snapshots[0]) {
7462 7463 7464
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
7465 7466 7467 7468 7469 7470 7471
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
7472 7473 7474 7475 7476 7477 7478 7479 7480 7481

    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) {
7482 7483
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
7484 7485 7486 7487
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
7488 7489
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
7490 7491
            goto cleanup;
        }
7492
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
7493 7494 7495 7496 7497 7498 7499
    }

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

7500
 cleanup:
J
Jiri Denemark 已提交
7501 7502 7503 7504 7505 7506
    if (count > 0) {
        for (i = 0; i < count; i++)
            VBOX_RELEASE(snapshots[i]);
    }
    VIR_FREE(snapshots);
    VBOX_RELEASE(machine);
7507
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7508 7509 7510 7511 7512 7513
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
7514
                               unsigned int flags)
J
Jiri Denemark 已提交
7515 7516
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
7517
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7518 7519 7520 7521
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

7522 7523
    virCheckFlags(0, NULL);

7524
    vboxIIDFromUUID(&iid, dom->uuid);
7525
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7526
    if (NS_FAILED(rc)) {
7527 7528
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7529 7530 7531 7532 7533 7534 7535 7536
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

7537
 cleanup:
J
Jiri Denemark 已提交
7538 7539
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
7540
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7541 7542 7543 7544 7545
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
7546
                             unsigned int flags)
J
Jiri Denemark 已提交
7547 7548
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7549
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7550 7551 7552 7553
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

7554 7555
    virCheckFlags(0, -1);

7556
    vboxIIDFromUUID(&iid, dom->uuid);
7557
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
7558
    if (NS_FAILED(rc)) {
7559 7560
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7561 7562 7563 7564 7565
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
7566 7567
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
7568 7569 7570 7571 7572 7573 7574 7575
        goto cleanup;
    }

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

7576
 cleanup:
J
Jiri Denemark 已提交
7577
    VBOX_RELEASE(machine);
7578
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7579 7580 7581
    return ret;
}

7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600
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)) {
7601 7602
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7603 7604 7605 7606 7607 7608 7609 7610
        goto cleanup;
    }

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

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
7611 7612 7613
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
7614 7615 7616
        goto cleanup;
    }
    if (!parent) {
7617 7618 7619
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
7620 7621 7622 7623 7624
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7625 7626 7627
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
7628 7629 7630 7631 7632 7633 7634 7635 7636 7637
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

7638
 cleanup:
7639 7640 7641 7642 7643 7644 7645 7646 7647
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

J
Jiri Denemark 已提交
7648 7649
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
7650
                          unsigned int flags)
J
Jiri Denemark 已提交
7651 7652
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
7653
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7654 7655 7656 7657 7658 7659
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

7660 7661
    virCheckFlags(0, NULL);

7662
    vboxIIDFromUUID(&iid, dom->uuid);
7663
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
7664
    if (NS_FAILED(rc)) {
7665 7666
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7667 7668 7669 7670 7671
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
7672 7673
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
7674 7675 7676 7677
        goto cleanup;
    }

    if (!snapshot) {
7678 7679
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
7680 7681 7682 7683 7684
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7685 7686
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

7698
 cleanup:
J
Jiri Denemark 已提交
7699 7700 7701 7702
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
7703
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7704 7705 7706
    return ret;
}

7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725
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)) {
7726 7727
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7728 7729 7730 7731 7732 7733 7734 7735
        goto cleanup;
    }

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
7736 7737
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
7738 7739 7740 7741 7742 7743 7744 7745 7746
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7747 7748
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759
        goto cleanup;
    }

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

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

7760
 cleanup:
7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785
    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)) {
7786 7787
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7788 7789 7790 7791 7792 7793 7794 7795 7796
        goto cleanup;
    }

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

    ret = 0;

7797
 cleanup:
7798 7799 7800 7801 7802 7803
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

7804
#if VBOX_API_VERSION < 3001000
J
Jiri Denemark 已提交
7805 7806 7807 7808 7809 7810
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7811
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7812 7813
    nsresult rc;

7814 7815
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
7816 7817
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
7818 7819 7820
        goto cleanup;
    }

7821
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
7822
    if (NS_FAILED(rc)) {
7823 7824
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
7825 7826 7827 7828 7829
        goto cleanup;
    }

    ret = 0;

7830
 cleanup:
7831
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845
    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;
7846
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7847

7848 7849
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
7850 7851
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
7852 7853 7854 7855 7856
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
7857 7858
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
7859 7860 7861 7862 7863
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
7864 7865
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
7866 7867 7868
        goto cleanup;
    }

7869
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
7870 7871 7872
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
7873 7874 7875
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7876 7877 7878 7879 7880 7881
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
7882 7883
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
7884
        } else {
7885 7886 7887
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
7888 7889 7890 7891 7892 7893 7894
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
7895 7896
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
7897 7898 7899 7900 7901
        goto cleanup;
    }

    ret = 0;

7902
 cleanup:
J
Jiri Denemark 已提交
7903 7904
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
7905
    VBOX_SESSION_CLOSE();
7906
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7907 7908 7909 7910 7911 7912
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
7913
                           unsigned int flags)
J
Jiri Denemark 已提交
7914 7915 7916
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7917
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7918 7919 7920 7921 7922 7923 7924
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

7925 7926
    virCheckFlags(0, -1);

7927
    vboxIIDFromUUID(&domiid, dom->uuid);
7928
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
7929
    if (NS_FAILED(rc)) {
7930 7931
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7932 7933 7934 7935 7936 7937 7938 7939 7940
        goto cleanup;
    }

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

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
7941 7942 7943
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7944 7945 7946 7947 7948
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
7949 7950 7951
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7952 7953 7954 7955 7956
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
7957 7958
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
7959 7960 7961 7962 7963
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
7964 7965
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978
        goto cleanup;
    }

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

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

7979
 cleanup:
J
Jiri Denemark 已提交
7980 7981
    VBOX_RELEASE(prevSnapshot);
    VBOX_RELEASE(newSnapshot);
7982
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7983 7984 7985 7986 7987 7988 7989 7990 7991
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
7992
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7993 7994
    int ret = -1;
    nsresult rc;
7995
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
7996 7997 7998 7999 8000
    nsresult result;
#else
    PRInt32 result;
#endif

8001 8002
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
8003 8004
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
8005 8006 8007
        goto cleanup;
    }

8008
#if VBOX_API_VERSION < 3001000
8009
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
8010
#else
8011
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
8012 8013 8014
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
8015 8016
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
8017
        } else {
8018 8019
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
8020 8021 8022 8023 8024 8025 8026
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
8027 8028
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
8029 8030 8031 8032 8033
        goto cleanup;
    }

    ret = 0;

8034
 cleanup:
J
Jiri Denemark 已提交
8035
    VBOX_RELEASE(progress);
8036
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
8037 8038 8039 8040 8041 8042 8043 8044
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
8045
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
8046 8047
    int ret = -1;
    nsresult rc;
8048
    size_t i;
J
Jiri Denemark 已提交
8049

8050
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
8051
    if (NS_FAILED(rc)) {
8052 8053
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
8054 8055 8056
        goto cleanup;
    }

8057 8058 8059
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
8060 8061 8062 8063
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

8064
 cleanup:
8065
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
8066 8067 8068
    return ret;
}

8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088
#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);
8089
    virDomainSnapshotDefPtr def = NULL;
8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104
    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;
8105

8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 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
    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);
8281
                    VIR_FREE(disk);
8282 8283 8284 8285 8286 8287
                    goto cleanup;
                }
                VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
                disk->uuid = uuid;
                VBOX_UTF16_FREE(uuidUtf16);

8288 8289
                if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) {
                    VIR_FREE(disk);
8290
                    goto cleanup;
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 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 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 8515 8516 8517 8518 8519 8520 8521 8522 8523

                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
8524

J
Jiri Denemark 已提交
8525 8526 8527 8528 8529 8530
static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
8531
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
8532 8533 8534 8535 8536
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;
8537
    vboxArray snapChildren = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
8538

8539 8540
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
8541

8542
    vboxIIDFromUUID(&domiid, dom->uuid);
8543
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
8544
    if (NS_FAILED(rc)) {
8545 8546
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
8547 8548 8549 8550 8551 8552 8553 8554 8555
        goto cleanup;
    }

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

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
8556 8557
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
8558 8559 8560
        goto cleanup;
    }

8561 8562 8563
    /* In case we just want to delete the metadata, we will edit the vbox file in order
     *to remove the node concerning the snapshot
    */
8564
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579
        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
        }
8580 8581 8582
        goto cleanup;
    }

J
Jiri Denemark 已提交
8583 8584
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
8585 8586
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
8587 8588 8589
        goto cleanup;
    }

8590
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
8591 8592 8593
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
8594 8595 8596
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
8597 8598 8599 8600 8601 8602 8603 8604
        goto cleanup;
    }

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

8605
 cleanup:
J
Jiri Denemark 已提交
8606 8607
    VBOX_RELEASE(console);
    VBOX_RELEASE(snap);
8608
    vboxIIDUnalloc(&domiid);
8609
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
8610 8611 8612
    return ret;
}

8613
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
8614
    /* No Callback support for VirtualBox 2.2.* series */
8615
    /* No Callback support for VirtualBox 4.* series */
8616
#else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
8617 8618

/* Functions needed for Callbacks */
8619
static nsresult PR_COM_METHOD
8620
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8621 8622
                                 PRUnichar *machineId, PRUint32 state)
{
8623 8624 8625 8626 8627 8628
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

8629
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
8630 8631 8632 8633 8634 8635 8636
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
8637
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
8638 8639 8640

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
8641
            virObjectEventPtr ev;
8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671

            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;
            }

8672
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
8673

8674
            if (ev)
8675
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
8676 8677 8678 8679 8680 8681 8682 8683
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

8684
static nsresult PR_COM_METHOD
8685
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8686 8687
                                PRUnichar *machineId)
{
8688
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8689 8690 8691 8692 8693
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

8694
static nsresult PR_COM_METHOD
8695
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8696 8697 8698
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
8699
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
8700
{
8701
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
8702 8703 8704 8705 8706 8707 8708
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

8709
static nsresult PR_COM_METHOD
8710 8711
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
8712 8713
                              PRUnichar *key, PRUnichar *value)
{
8714
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8715 8716 8717 8718 8719 8720 8721
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

8722
# if VBOX_API_VERSION < 3001000
8723
static nsresult PR_COM_METHOD
8724 8725 8726 8727
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
8728
{
8729 8730
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
8731 8732 8733 8734
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
8735 8736
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
8737

8738
static nsresult PR_COM_METHOD
8739
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8740 8741
                                PRUnichar *machineId, PRBool registered)
{
8742 8743 8744 8745 8746 8747
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

8748
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
8749 8750 8751 8752 8753 8754 8755
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
8756
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
8757 8758 8759

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
8760
            virObjectEventPtr ev;
8761 8762

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
8763
             * event because the when the machine is de-registered the call
8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775
             * 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;
            }

8776
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
8777

8778
            if (ev)
8779
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
8780 8781 8782 8783 8784 8785 8786 8787
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

8788
static nsresult PR_COM_METHOD
8789 8790 8791
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
8792
{
8793
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
8794 8795 8796 8797 8798
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

8799
static nsresult PR_COM_METHOD
8800 8801
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
8802 8803
                            PRUnichar *snapshotId)
{
8804
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8805 8806 8807 8808 8809 8810
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8811
static nsresult PR_COM_METHOD
8812 8813
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
8814 8815
                                PRUnichar *snapshotId)
{
8816
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8817 8818 8819 8820 8821 8822
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8823
static nsresult PR_COM_METHOD
8824 8825
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
8826 8827
                             PRUnichar *snapshotId)
{
8828
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8829 8830 8831 8832 8833 8834
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8835
static nsresult PR_COM_METHOD
8836
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8837 8838 8839
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
8840
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8841 8842 8843 8844 8845 8846 8847 8848
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

8849
static nsresult PR_COM_METHOD
8850
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
8851
{
8852 8853 8854 8855
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

8856
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
8857 8858 8859 8860

    return c;
}

8861 8862 8863
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
8864 8865 8866 8867 8868 8869 8870 8871 8872
    nsresult c;

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

8873
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
8874 8875 8876 8877

    return c;
}

8878 8879 8880
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
8881 8882 8883 8884 8885
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
8886 8887
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
8888 8889 8890
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

8891
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
8892 8893 8894 8895 8896

        return NS_OK;
    }


8897
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
8898 8899 8900 8901 8902 8903
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


8904
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
8905 8906
    IVirtualBoxCallback *vboxCallback = NULL;

8907
    /* Allocate, Initialize and return a valid
8908 8909 8910
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
8911
        VIR_FREE(vboxCallback);
8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922
        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;
8923
# if VBOX_API_VERSION < 3001000
8924
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
8925 8926
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
8927 8928 8929
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
8930
# if VBOX_API_VERSION < 3002000
8931
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
8932
# else /* VBOX_API_VERSION >= 3002000 */
8933
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
8934
# endif /* VBOX_API_VERSION >= 3002000 */
8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946
        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,
8947 8948
                             void *opaque ATTRIBUTE_UNUSED)
{
8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960
    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);
    }
}

8961 8962 8963 8964 8965 8966
static int
vboxConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
{
8967
    VBOX_OBJECT_CHECK(conn, int, -1);
8968
    int vboxRet          = -1;
8969
    nsresult rc;
8970 8971 8972 8973 8974 8975

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

8976
    if (data->vboxCallback == NULL) {
8977
        data->vboxCallback = vboxAllocCallbackObj();
8978 8979 8980 8981
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
8982 8983
            }
        }
8984 8985 8986
    } else {
        vboxRet = 0;
    }
8987

8988 8989 8990 8991 8992 8993 8994
    /* 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);
8995

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

8999 9000 9001 9002 9003
        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
             */
9004

9005
            ret = virDomainEventStateRegister(conn, data->domainEvents,
9006
                                              callback, opaque, freecb);
9007
            VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
9008
                      "callback: %p, opaque: %p, "
9009
                      "freecb: %p)", ret, conn, callback,
9010
                      opaque, freecb);
9011 9012 9013 9014 9015 9016
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
9017
        return 0;
9018 9019 9020 9021 9022 9023 9024 9025
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

9026 9027 9028 9029
static int
vboxConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
{
9030
    VBOX_OBJECT_CHECK(conn, int, -1);
9031
    int cnt;
9032 9033 9034 9035 9036 9037

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

9038 9039
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
9040

9041 9042 9043
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
9044

9045 9046 9047
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
9048 9049 9050 9051
    }

    vboxDriverUnlock(data);

9052 9053 9054
    if (cnt >= 0)
        ret = 0;

9055 9056 9057
    return ret;
}

9058 9059 9060 9061 9062
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
9063 9064
                                             virFreeCallback freecb)
{
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 9099 9100 9101 9102
    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
             */

9103
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
9104 9105
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
9106
                ret = -1;
9107
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
9108
                      "callback: %p, opaque: %p, "
9109
                      "freecb: %p)", ret, conn, callback,
9110
                      opaque, freecb);
9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

9126 9127 9128 9129
static int
vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
{
9130
    VBOX_OBJECT_CHECK(conn, int, -1);
9131
    int cnt;
9132 9133 9134 9135 9136 9137

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

9138
    cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
9139
                                          callbackID);
9140

9141 9142 9143
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
9144

9145 9146 9147
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
9148 9149 9150 9151
    }

    vboxDriverUnlock(data);

9152 9153 9154
    if (cnt >= 0)
        ret = 0;

9155 9156 9157
    return ret;
}

9158
#endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
9159

9160 9161 9162 9163 9164
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
9165 9166
                                        unsigned int flags)
{
9167 9168
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
9169 9170
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

9171 9172 9173 9174 9175 9176 9177 9178
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

9179
    VIR_DEBUG("network initialized");
9180 9181 9182
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

9183
 cleanup:
9184 9185 9186
    return VIR_DRV_OPEN_DECLINED;
}

9187 9188
static int vboxNetworkClose(virConnectPtr conn)
{
9189
    VIR_DEBUG("network uninitialized");
9190 9191 9192 9193
    conn->networkPrivateData = NULL;
    return 0;
}

9194 9195
static int vboxConnectNumOfNetworks(virConnectPtr conn)
{
9196
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9197
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9198
    size_t i = 0;
9199

9200
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
9201

9202 9203 9204 9205
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
9206
            PRUint32 interfaceType = 0;
9207

9208
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9209 9210
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9211

9212
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9213

9214 9215
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
9216 9217 9218 9219
            }
        }
    }

9220 9221
    vboxArrayRelease(&networkInterfaces);

9222 9223
    VBOX_RELEASE(host);

9224
    VIR_DEBUG("numActive: %d", ret);
9225
    return ret;
9226 9227
}

9228
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
9229
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9230
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9231
    size_t i = 0;
9232

9233 9234 9235 9236
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
9237

9238
        if (networkInterface) {
9239
            PRUint32 interfaceType = 0;
9240

9241
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9242

9243 9244
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9245

9246
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9247

9248 9249 9250
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
9251

9252
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
9253
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
9254

9255
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
9256
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
9257
                        ret++;
9258

9259 9260
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
9261 9262 9263 9264 9265
                }
            }
        }
    }

9266
    vboxArrayRelease(&networkInterfaces);
9267

9268
    VBOX_RELEASE(host);
9269

9270 9271
    return ret;
}
9272

9273 9274
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn)
{
9275
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9276
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9277
    size_t i = 0;
9278

9279
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
9280

9281 9282 9283 9284
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
9285
            PRUint32 interfaceType = 0;
9286

9287
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9288 9289
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9290

9291
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9292

9293 9294
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
9295 9296 9297 9298
            }
        }
    }

9299 9300
    vboxArrayRelease(&networkInterfaces);

9301 9302
    VBOX_RELEASE(host);

9303
    VIR_DEBUG("numActive: %d", ret);
9304
    return ret;
9305 9306
}

9307
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
9308
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9309
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9310
    size_t i = 0;
9311

9312 9313 9314 9315
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
9316

9317
        if (networkInterface) {
9318
            PRUint32 interfaceType = 0;
9319

9320
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9321

9322 9323
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9324

9325
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9326

9327 9328 9329
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
9330

9331
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
9332
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
9333

9334
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
9335
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
9336
                        ret++;
9337

9338 9339
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
9340 9341 9342 9343 9344
                }
            }
        }
    }

9345
    vboxArrayRelease(&networkInterfaces);
9346 9347 9348 9349

    VBOX_RELEASE(host);

    return ret;
9350 9351
}

9352 9353 9354
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
9355
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
9356
    vboxIID iid = VBOX_IID_INITIALIZER;
9357

9358
    vboxIIDFromUUID(&iid, uuid);
9359

9360 9361 9362
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
9363
    IHostNetworkInterface *networkInterface = NULL;
9364

9365
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
9366 9367
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9368

9369
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9370

9371 9372 9373
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
9374

9375 9376
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
9377

9378
            ret = virGetNetwork(conn, nameUtf8, uuid);
9379

9380
            VIR_DEBUG("Network Name: %s", nameUtf8);
9381
            DEBUGIID("Network UUID", iid.value);
9382

9383 9384
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
9385
        }
9386 9387

        VBOX_RELEASE(networkInterface);
9388 9389
    }

9390 9391
    VBOX_RELEASE(host);

9392
    vboxIIDUnalloc(&iid);
9393 9394 9395
    return ret;
}

9396 9397 9398
static virNetworkPtr
vboxNetworkLookupByName(virConnectPtr conn, const char *name)
{
9399 9400 9401
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9402

9403
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
9404

9405
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
9406

9407 9408
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9409

9410
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9411

9412 9413
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
9414
            vboxIID iid = VBOX_IID_INITIALIZER;
9415

9416 9417
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
9418
            ret = virGetNetwork(conn, name, uuid);
9419
            VIR_DEBUG("Network Name: %s", name);
9420

9421 9422
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
9423
        }
9424 9425

        VBOX_RELEASE(networkInterface);
9426 9427
    }

9428 9429 9430
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

9431 9432 9433
    return ret;
}

9434 9435 9436
static virNetworkPtr
vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
{
9437 9438 9439 9440
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9441
    nsresult rc;
9442

9443
    virNetworkDefPtr def = virNetworkDefParseString(xml);
9444 9445
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
9446

9447
    if ((!def) ||
9448
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
9449
        (def->nips == 0 || !def->ips))
9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460
        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)
9461
        goto cleanup;
9462

9463 9464 9465 9466 9467 9468
    /* 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.
     */
9469

9470
#if VBOX_API_VERSION == 2002000
9471
    if (STREQ(def->name, "vboxnet0")) {
9472
        PRUint32 interfaceType = 0;
9473

9474 9475
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9476

9477 9478 9479 9480 9481 9482
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
9483
#else /* VBOX_API_VERSION != 2002000 */
9484 9485 9486 9487
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
9488

9489 9490 9491 9492
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
9493
    }
9494
#endif /* VBOX_API_VERSION != 2002000 */
9495

9496 9497 9498 9499
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
9500
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511

        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;
            }
        }
9512

E
Eric Blake 已提交
9513
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9514

9515 9516 9517
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
9518
        if ((ipdef->nranges >= 1) &&
9519 9520
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
9521 9522 9523 9524 9525 9526 9527 9528 9529 9530
            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);
9531
                VIR_DEBUG("couldn't find dhcp server so creating one");
9532 9533 9534 9535 9536 9537 9538 9539
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

9540 9541 9542 9543
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
9544 9545 9546 9547 9548 9549 9550 9551 9552 9553

                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;
                }
9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578

                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);
            }
        }
9579

9580
        if ((ipdef->nhosts >= 1) &&
9581
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
9582 9583
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
9584

9585 9586
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
9587 9588 9589 9590 9591 9592

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
9593

9594 9595 9596 9597
            /* 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
             */
9598
#if VBOX_API_VERSION < 4002000
9599 9600 9601
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
9602 9603 9604 9605 9606
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
9607

9608 9609 9610
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
9611
#if VBOX_API_VERSION < 4002000
9612 9613
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
9614 9615 9616 9617
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
9618
        }
9619

9620 9621 9622 9623 9624
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
9625
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
9626
        }
9627 9628 9629 9630

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
9631 9632
    }

9633 9634 9635 9636
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9637
 cleanup:
9638 9639 9640 9641
    virNetworkDefFree(def);
    return ret;
}

9642 9643
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml)
{
9644 9645 9646
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

9647 9648
static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml)
{
9649 9650 9651
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

9652 9653 9654
static int
vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface)
{
9655
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
9656
    char *networkNameUtf8 = NULL;
9657 9658
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9659 9660 9661 9662 9663 9664 9665 9666 9667

    /* 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
     */

9668
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9669 9670
        goto cleanup;

9671
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9672

9673
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9674

9675 9676
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9677

9678
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9679

9680 9681 9682
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
9683

9684
#if VBOX_API_VERSION != 2002000
9685 9686 9687
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
9688

9689
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
9690

9691
                if (iidUtf16) {
9692
# if VBOX_API_VERSION == 3000000
9693 9694 9695
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
9696
# else  /* VBOX_API_VERSION > 3000000 */
9697
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
9698
# endif /* VBOX_API_VERSION > 3000000 */
9699 9700
                    VBOX_UTF16_FREE(iidUtf16);
                }
9701

9702 9703 9704 9705 9706
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
9707
#endif /* VBOX_API_VERSION != 2002000 */
9708

E
Eric Blake 已提交
9709
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9710 9711 9712 9713 9714 9715 9716 9717 9718 9719

            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);
9720 9721
            }

9722 9723
            VBOX_UTF16_FREE(networkNameUtf16);

9724
        }
9725
        VBOX_RELEASE(networkInterface);
9726 9727
    }

9728 9729 9730
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9731 9732
    ret = 0;

9733
 cleanup:
9734 9735 9736 9737
    VIR_FREE(networkNameUtf8);
    return ret;
}

9738 9739
static int vboxNetworkUndefine(virNetworkPtr network)
{
9740 9741 9742
    return vboxNetworkUndefineDestroy(network, true);
}

9743 9744
static int vboxNetworkCreate(virNetworkPtr network)
{
9745
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
9746
    char *networkNameUtf8 = NULL;
9747 9748
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9749 9750 9751 9752 9753 9754 9755 9756

    /* 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
     */

9757
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9758 9759
        goto cleanup;

9760
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9761

9762
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9763

9764 9765
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9766

9767
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9768

9769 9770 9771
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
9772 9773


E
Eric Blake 已提交
9774
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9775

9776 9777 9778 9779 9780
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
9781

9782
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
9783

9784
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
9785

9786 9787 9788 9789
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
9790

9791 9792
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
9793 9794
            }

9795
            VBOX_UTF16_FREE(networkNameUtf16);
9796
        }
9797 9798

        VBOX_RELEASE(networkInterface);
9799 9800
    }

9801 9802 9803
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9804 9805
    ret = 0;

9806
 cleanup:
9807 9808 9809 9810
    VIR_FREE(networkNameUtf8);
    return ret;
}

9811 9812
static int vboxNetworkDestroy(virNetworkPtr network)
{
9813
    return vboxNetworkUndefineDestroy(network, false);
9814 9815
}

9816
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
9817 9818
                                   unsigned int flags)
{
9819
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
9820
    virNetworkDefPtr def  = NULL;
9821
    virNetworkIpDefPtr ipdef = NULL;
9822
    char *networkNameUtf8 = NULL;
9823 9824
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9825

E
Eric Blake 已提交
9826 9827
    virCheckFlags(0, NULL);

9828
    if (VIR_ALLOC(def) < 0)
9829
        goto cleanup;
9830
    if (VIR_ALLOC(ipdef) < 0)
9831 9832 9833
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
9834

9835
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9836 9837
        goto cleanup;

9838
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9839

9840
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9841

9842 9843
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9844

9845
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9846

9847
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
9848
            if (VIR_STRDUP(def->name, network->name) >= 0) {
9849 9850
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
9851
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
9852

9853 9854
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
9855

E
Eric Blake 已提交
9856
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9857

9858
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
9859

9860 9861 9862 9863
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
9864
                    ipdef->nranges = 1;
9865
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >= 0) {
9866 9867 9868 9869
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
9870
                        bool errorOccurred = false;
9871

9872 9873 9874 9875 9876 9877 9878
                        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
                         */
9879
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9880
                                                     &ipdef->address) < 0 ||
9881
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
9882
                                                     &ipdef->netmask) < 0 ||
9883
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
9884
                                                     &ipdef->ranges[0].start) < 0 ||
9885
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
9886
                                                     &ipdef->ranges[0].end) < 0) {
9887 9888
                            errorOccurred = true;
                        }
9889 9890 9891 9892 9893

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
9894 9895 9896 9897

                        if (errorOccurred) {
                            goto cleanup;
                        }
9898
                    } else {
9899
                        ipdef->nranges = 0;
9900
                    }
9901

9902
                    ipdef->nhosts = 1;
9903
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >= 0) {
9904
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
9905 9906
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
9907
                        } else {
9908 9909
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
9910
                            bool errorOccurred = false;
9911

9912
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
9913 9914
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

9915
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
9916 9917

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9918
                                                         &ipdef->hosts[0].ip) < 0) {
9919 9920
                                errorOccurred = true;
                            }
9921

9922 9923
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
9924 9925 9926 9927

                            if (errorOccurred) {
                                goto cleanup;
                            }
9928 9929
                        }
                    } else {
9930
                        ipdef->nhosts = 0;
9931
                    }
9932 9933 9934 9935 9936

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
9937
                    bool errorOccurred = false;
9938 9939 9940 9941

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

9942
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
9943
                                                 &ipdef->netmask) < 0 ||
9944
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9945
                                                 &ipdef->address) < 0) {
9946 9947
                        errorOccurred = true;
                    }
9948 9949 9950

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
9951 9952 9953 9954

                    if (errorOccurred) {
                        goto cleanup;
                    }
9955 9956
                }

9957 9958
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
9959
                VBOX_UTF16_FREE(networkNameUtf16);
9960 9961
            }
        }
9962 9963

        VBOX_RELEASE(networkInterface);
9964 9965
    }

9966 9967 9968
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9969
    ret = virNetworkDefFormat(def, 0);
9970

9971
 cleanup:
9972
    virNetworkDefFree(def);
9973 9974 9975 9976
    VIR_FREE(networkNameUtf8);
    return ret;
}

9977 9978 9979 9980
/**
 * The Storage Functions here on
 */

9981 9982 9983
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
9984
{
9985 9986
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
9987 9988
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

9989
    if (STRNEQ(conn->driver->name, "VBOX"))
9990
        return VIR_DRV_OPEN_DECLINED;
9991 9992 9993 9994

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
9995
        return VIR_DRV_OPEN_ERROR;
9996

9997
    VIR_DEBUG("vbox storage initialized");
9998 9999 10000 10001
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

10002 10003
static int vboxStorageClose(virConnectPtr conn)
{
10004
    VIR_DEBUG("vbox storage uninitialized");
10005 10006 10007 10008
    conn->storagePrivateData = NULL;
    return 0;
}

10009 10010
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
10011 10012 10013 10014 10015 10016 10017 10018

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

10019 10020
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
10021 10022
    int numActive = 0;

10023 10024 10025
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
10026 10027 10028
    return numActive;
}

10029 10030 10031
static virStoragePoolPtr
vboxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
10032 10033 10034 10035 10036 10037 10038 10039 10040 10041
    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";

10042
        ignore_value(virUUIDParse(uuidstr, uuid));
10043

10044
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
10045 10046 10047 10048 10049
    }

    return ret;
}

10050 10051
static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
10052
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
10053
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
10054 10055
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
10056
    size_t i;
10057

10058
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
10059
    if (NS_SUCCEEDED(rc)) {
10060 10061
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
10062 10063
            if (hardDisk) {
                PRUint32 hddstate;
10064

10065 10066 10067
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
10068 10069
            }
        }
10070 10071 10072 10073

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
10074
    } else {
10075
        ret = -1;
10076 10077 10078
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
10079 10080
    }

10081
    return ret;
10082 10083 10084
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
10085
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
10086
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
10087 10088
    PRUint32 numActive     = 0;
    nsresult rc;
10089
    size_t i;
10090

10091
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
10092
    if (NS_SUCCEEDED(rc)) {
10093 10094
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
10095

10096 10097 10098 10099
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
10100

10101 10102 10103
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
10104

10105 10106
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
10107

10108
                    if (nameUtf8) {
10109
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
10110
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
10111 10112 10113
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
10114 10115 10116 10117
                    }
                }
            }
        }
10118 10119 10120 10121

        vboxArrayRelease(&hardDisks);

        ret = numActive;
10122
    } else {
10123
        ret = -1;
10124 10125 10126
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
10127 10128
    }

10129
    return ret;
10130 10131
}

10132 10133 10134
static virStorageVolPtr
vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
{
10135
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
10136
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
10137
    nsresult rc;
10138
    size_t i;
10139

10140
    if (!name)
10141
        return ret;
10142

10143
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
10144
    if (NS_SUCCEEDED(rc)) {
10145 10146
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
10147

10148 10149 10150 10151
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
10152

10153 10154 10155
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
10156

10157 10158 10159 10160
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
10161

10162
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
10163 10164 10165
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
10166

10167 10168 10169 10170
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
10171

10172 10173
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
10174

10175 10176 10177 10178
                            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);
10179 10180
                        }

10181
                        vboxIIDUnalloc(&hddIID);
10182 10183
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
10184
                    }
10185

J
John Ferlan 已提交
10186
                    VBOX_UTF8_FREE(nameUtf8);
10187 10188 10189
                }
            }
        }
10190

10191
        vboxArrayRelease(&hardDisks);
10192 10193 10194 10195 10196
    }

    return ret;
}

10197 10198 10199
static virStorageVolPtr
vboxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
10200
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
10201 10202
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
10203 10204 10205
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

10206 10207 10208
    if (!key)
        return ret;

10209
    if (virUUIDParse(key, uuid) < 0) {
10210 10211
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
10212
        return NULL;
10213 10214
    }

10215
    vboxIIDFromUUID(&hddIID, uuid);
10216
#if VBOX_API_VERSION < 4000000
10217
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10218
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10219 10220
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10221 10222 10223 10224
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10225
#endif /* VBOX_API_VERSION >= 4000000 */
10226 10227
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10228

10229 10230 10231 10232
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
10233

10234 10235
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
10236

10237
            if (hddNameUtf8) {
10238
                if (vboxConnectNumOfStoragePools(conn) == 1) {
10239 10240
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
10241
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
10242 10243 10244 10245
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
10246 10247
                }

10248 10249
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
10250 10251 10252

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
10253 10254
            }
        }
10255 10256

        VBOX_MEDIUM_RELEASE(hardDisk);
10257 10258
    }

10259
    vboxIIDUnalloc(&hddIID);
10260 10261 10262
    return ret;
}

10263 10264 10265
static virStorageVolPtr
vboxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
10266
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
10267 10268 10269 10270
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

10271 10272
    if (!path)
        return ret;
10273

10274
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
10275

10276 10277
    if (!hddPathUtf16)
        return ret;
10278

10279
#if VBOX_API_VERSION < 4000000
10280
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
10281
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10282 10283
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
10284 10285 10286 10287
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10288
#endif /* VBOX_API_VERSION >= 4000000 */
10289 10290
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10291

10292 10293 10294 10295
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
10296

10297
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
10298

10299 10300 10301 10302
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
10303

10304 10305 10306 10307
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
10308

10309 10310 10311 10312
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
10313

10314 10315 10316
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
10317
                    if (vboxConnectNumOfStoragePools(conn) == 1)
10318 10319
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
10320

10321 10322 10323
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
10324
                }
10325

10326
                vboxIIDUnalloc(&hddIID);
10327 10328
            }

J
John Ferlan 已提交
10329
            VBOX_UTF8_FREE(hddNameUtf8);
10330
        }
10331 10332

        VBOX_MEDIUM_RELEASE(hardDisk);
10333 10334
    }

10335 10336
    VBOX_UTF16_FREE(hddPathUtf16);

10337 10338 10339 10340 10341
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
10342 10343
                                                unsigned int flags)
{
10344
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
10345
    virStorageVolDefPtr  def  = NULL;
10346 10347
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
10348 10349 10350
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
10351 10352
    virCheckFlags(0, NULL);

10353 10354 10355 10356 10357 10358 10359 10360
    /* 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;

10361
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
10362 10363
        goto cleanup;

10364 10365
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
10366
        goto cleanup;
10367

10368 10369
    /* For now only the vmdk, vpc and vdi type harddisk
     * variants can be created.  For historical reason, we default to vdi */
10370 10371 10372 10373 10374 10375 10376
    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);
    }
10377

10378
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
10379

10380 10381
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
10382

10383 10384 10385
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
10386 10387
            PRUint64   logicalSize = VIR_DIV_UP(def->target.capacity,
                                                1024 * 1024);
10388
            PRUint32   variant     = HardDiskVariant_Standard;
10389

10390
            if (def->target.capacity == def->target.allocation)
10391
                variant = HardDiskVariant_Fixed;
10392

10393
#if VBOX_API_VERSION < 4003000
10394
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
R
Ryota Ozaki 已提交
10395 10396 10397
#else
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
#endif
10398
            if (NS_SUCCEEDED(rc) && progress) {
10399
#if VBOX_API_VERSION == 2002000
10400
                nsresult resultCode;
10401
#else
10402
                PRInt32  resultCode;
10403 10404
#endif

10405 10406
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
10407

10408
                if (NS_SUCCEEDED(resultCode)) {
10409 10410 10411
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
10412

10413
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
10414
                    if (NS_SUCCEEDED(rc)) {
10415 10416
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
10417

10418 10419
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
10420
                    }
10421 10422

                    vboxIIDUnalloc(&hddIID);
10423 10424
                }

10425
                VBOX_RELEASE(progress);
10426
            }
10427
        }
10428 10429
    }

10430 10431 10432
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

10433
 cleanup:
10434 10435 10436 10437 10438
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
10439 10440
                                unsigned int flags)
{
10441
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
10442 10443
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
10444 10445 10446
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
10447 10448
    size_t i = 0;
    size_t j = 0;
10449

E
Eric Blake 已提交
10450 10451
    virCheckFlags(0, -1);

10452
    if (virUUIDParse(vol->key, uuid) < 0) {
10453 10454
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10455 10456
        return -1;
    }
10457

10458
    vboxIIDFromUUID(&hddIID, uuid);
10459
#if VBOX_API_VERSION < 4000000
10460
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10461
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10462 10463
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10464 10465 10466 10467
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10468
#endif /* VBOX_API_VERSION >= 4000000 */
10469 10470
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10471

10472 10473 10474
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
10475 10476
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;

10477
#if VBOX_API_VERSION < 3001000
10478
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
10479
#else  /* VBOX_API_VERSION >= 3001000 */
10480
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
10481
#endif /* VBOX_API_VERSION >= 3001000 */
10482

10483
#if VBOX_API_VERSION == 2002000 && defined WIN32
10484 10485 10486 10487 10488 10489
            /* 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,
J
Ján Tomko 已提交
10490
             * we divide the size of the SafeArray by two, to compensate for
10491 10492
             * this workaround in VirtualBox */
            machineIds.count /= 2;
10493
#endif /* VBOX_API_VERSION >= 2002000 */
10494

10495
            machineIdsSize = machineIds.count;
10496

10497
            for (i = 0; i < machineIds.count; i++) {
10498
                IMachine *machine = NULL;
10499 10500 10501
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
10502

10503
#if VBOX_API_VERSION >= 4000000
10504 10505
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
10506 10507
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
10508 10509 10510 10511 10512 10513
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

10514
                if (NS_SUCCEEDED(rc)) {
10515

10516 10517
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
10518
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
10519

10520
#if VBOX_API_VERSION < 3001000
10521 10522
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
10523
#else  /* VBOX_API_VERSION >= 3001000 */
10524 10525
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
10526
#endif /* VBOX_API_VERSION >= 3001000 */
10527 10528
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
10529 10530 10531 10532

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

10533
#if VBOX_API_VERSION < 3001000
10534
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
10535
#else  /* VBOX_API_VERSION >= 3001000 */
10536
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
10537
#endif /* VBOX_API_VERSION >= 3001000 */
10538
                                if (NS_SUCCEEDED(rc) && hdd) {
10539
                                    vboxIID iid = VBOX_IID_INITIALIZER;
10540

10541 10542
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
10543

10544 10545
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
10546

10547
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
10548 10549 10550 10551
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

10552
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
10553 10554 10555 10556 10557

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

10558
#if VBOX_API_VERSION < 3001000
10559
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
10560
#else  /* VBOX_API_VERSION >= 3001000 */
10561
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
10562
#endif /* VBOX_API_VERSION >= 3001000 */
10563 10564
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
10565
                                                VIR_DEBUG("saving machine settings");
10566
                                            }
10567

10568 10569
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
10570
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
10571
                                            }
10572

J
John Ferlan 已提交
10573
                                            VBOX_UTF16_FREE(controller);
10574
                                        }
10575
                                        vboxIIDUnalloc(&iid);
10576
                                    }
10577
                                    VBOX_MEDIUM_RELEASE(hdd);
10578 10579 10580
                                }
                            }
                        }
10581
                        vboxArrayRelease(&hddAttachments);
10582
                        VBOX_RELEASE(machine);
10583
                    }
10584
                    VBOX_SESSION_CLOSE();
10585
                }
10586 10587

                vboxIIDUnalloc(&machineId);
10588
            }
10589

10590
            vboxArrayUnalloc(&machineIds);
10591

10592 10593 10594
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
10595

10596 10597 10598
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
10599
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
10600
                    ret = 0;
10601 10602 10603
                }
            }
        }
10604 10605

        VBOX_MEDIUM_RELEASE(hardDisk);
10606 10607
    }

10608
    vboxIIDUnalloc(&hddIID);
10609

10610 10611 10612
    return ret;
}

10613 10614 10615
static int
vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
{
10616
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
10617
    IHardDisk *hardDisk  = NULL;
10618 10619
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10620 10621
    nsresult rc;

10622
    if (!info)
10623
        return ret;
10624

10625
    if (virUUIDParse(vol->key, uuid) < 0) {
10626 10627
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10628
        return ret;
10629
    }
10630

10631
    vboxIIDFromUUID(&hddIID, uuid);
10632
#if VBOX_API_VERSION < 4000000
10633
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10634
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10635 10636
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10637 10638 10639 10640
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10641
#endif /* VBOX_API_VERSION >= 4000000 */
10642 10643
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10644

10645 10646
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
10647
#if VBOX_API_VERSION < 4000000
10648 10649
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
10650
#else /* VBOX_API_VERSION >= 4000000 */
10651 10652
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
10653
#endif /* VBOX_API_VERSION >= 4000000 */
10654

10655
            info->type = VIR_STORAGE_VOL_FILE;
10656

10657
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
10658
#if VBOX_API_VERSION < 4000000
10659
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
10660
#else /* VBOX_API_VERSION >= 4000000 */
10661
            info->capacity = hddLogicalSize;
10662
#endif /* VBOX_API_VERSION >= 4000000 */
10663

10664 10665
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
10666

10667
            ret = 0;
10668

10669 10670 10671 10672
            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);
10673
        }
10674 10675

        VBOX_MEDIUM_RELEASE(hardDisk);
10676 10677
    }

10678
    vboxIIDUnalloc(&hddIID);
10679

10680 10681 10682
    return ret;
}

E
Eric Blake 已提交
10683 10684
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
10685
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
10686
    IHardDisk *hardDisk  = NULL;
10687 10688
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10689 10690 10691 10692 10693
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
10694 10695
    virCheckFlags(0, NULL);

10696 10697 10698
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

10699
    if (virUUIDParse(vol->key, uuid) < 0) {
10700 10701
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10702
        return ret;
10703
    }
10704

10705
    vboxIIDFromUUID(&hddIID, uuid);
10706
#if VBOX_API_VERSION < 4000000
10707
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10708
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10709 10710
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10711 10712 10713 10714
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10715
#endif /* VBOX_API_VERSION >= 4000000 */
10716 10717 10718 10719 10720 10721
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
10722
#if VBOX_API_VERSION < 4000000
10723 10724
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
10725
#else /* VBOX_API_VERSION >= 4000000 */
10726 10727
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
10728
#endif /* VBOX_API_VERSION >= 4000000 */
10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739

            /* 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;

            rc = hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
10740
            if (NS_SUCCEEDED(rc) && defOk) {
10741
#if VBOX_API_VERSION < 4000000
10742
                def.target.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
10743
#else /* VBOX_API_VERSION >= 4000000 */
10744
                def.target.capacity = hddLogicalSize;
10745
#endif /* VBOX_API_VERSION >= 4000000 */
10746
            } else
10747 10748 10749 10750
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
10751
                def.target.allocation = hddActualSize;
10752 10753 10754
            else
                defOk = 0;

10755
            if (VIR_STRDUP(def.name, vol->name) < 0)
10756 10757
                defOk = 0;

10758
            if (VIR_STRDUP(def.key, vol->key) < 0)
10759 10760 10761 10762 10763 10764 10765 10766 10767
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

10768
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
10769 10770 10771 10772 10773

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
10774 10775
                    else if (STRCASEEQ("vdi", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VDI;
10776
                    else
10777
                        def.target.format = VIR_STORAGE_FILE_RAW;
10778

10779
                    VBOX_UTF8_FREE(hddFormatUtf8);
10780 10781
                }

10782 10783 10784
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
10785 10786
            }
        }
10787 10788

        VBOX_MEDIUM_RELEASE(hardDisk);
10789 10790
    }

10791
    vboxIIDUnalloc(&hddIID);
10792

10793
    if (defOk)
10794
        ret = virStorageVolDefFormat(&pool, &def);
10795 10796 10797 10798 10799

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
10800
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
10801
    IHardDisk *hardDisk  = NULL;
10802 10803
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10804 10805
    nsresult rc;

10806
    if (virUUIDParse(vol->key, uuid) < 0) {
10807 10808
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10809
        return ret;
10810
    }
10811

10812
    vboxIIDFromUUID(&hddIID, uuid);
10813
#if VBOX_API_VERSION < 4000000
10814
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10815
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10816 10817
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10818 10819 10820 10821
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10822
#endif /* VBOX_API_VERSION >= 4000000 */
10823 10824
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10825

10826 10827 10828 10829
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
10830

10831
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
10832

10833 10834
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
10835

10836
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
10837

10838 10839 10840
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
10841

10842
                VBOX_UTF8_FREE(hddLocationUtf8);
10843 10844
            }

10845
            VBOX_UTF16_FREE(hddLocationUtf16);
10846
        }
10847 10848

        VBOX_MEDIUM_RELEASE(hardDisk);
10849 10850
    }

10851
    vboxIIDUnalloc(&hddIID);
10852

10853 10854
    return ret;
}
10855

10856
#if VBOX_API_VERSION >= 4000000
10857 10858 10859 10860
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
10861
                     unsigned int flags)
10862 10863 10864 10865 10866 10867 10868 10869 10870 10871
{
    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;

E
Eric Blake 已提交
10872 10873
    virCheckFlags(0, NULL);

10874 10875 10876
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
10877 10878
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
10879 10880 10881 10882 10883
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
10884 10885
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
10886 10887 10888 10889 10890
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
10891 10892 10893
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
10894 10895 10896 10897 10898 10899 10900 10901 10902
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }

10903 10904
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922
        VIR_FREE(tmp);
        VBOX_RELEASE(machine);
        return NULL;
    }


    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;

            console->vtbl->GetDisplay(console, &display);

            if (display) {
                PRUint32 width, height, bitsPerPixel;
                PRUint32 screenDataSize;
                PRUint8 *screenData;
10923
# if VBOX_API_VERSION >= 4003000
R
Ryota Ozaki 已提交
10924 10925
                PRInt32 xOrigin, yOrigin;
# endif
10926 10927 10928

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
10929
# if VBOX_API_VERSION < 4003000
10930
                                                        &bitsPerPixel);
R
Ryota Ozaki 已提交
10931 10932 10933 10934
# else
                                                        &bitsPerPixel,
                                                        &xOrigin, &yOrigin);
# endif
10935 10936

                if (NS_FAILED(rc) || !width || !height) {
10937 10938
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
10939 10940 10941 10942 10943 10944 10945 10946
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
10947 10948
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963
                    goto endjob;
                }

                if (safewrite(tmp_fd, (char *) screenData,
                              screenDataSize) < 0) {
                    virReportSystemError(errno, _("unable to write data "
                                                  "to '%s'"), tmp);
                    goto endjob;
                }

                if (VIR_CLOSE(tmp_fd) < 0) {
                    virReportSystemError(errno, _("unable to close %s"), tmp);
                    goto endjob;
                }

10964 10965 10966
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;

E
Eric Blake 已提交
10967
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
10968 10969
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
10970
                    VIR_FREE(ret);
10971
                }
10972
 endjob:
10973 10974 10975 10976 10977 10978 10979 10980 10981
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
10982
    unlink(tmp);
10983 10984 10985 10986 10987
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
10988
#endif /* VBOX_API_VERSION >= 4000000 */
10989

10990 10991 10992

#define MATCH(FLAG) (flags & (FLAG))
static int
10993 10994 10995
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
10996 10997 10998 10999 11000 11001 11002 11003 11004
{
    VBOX_OBJECT_CHECK(conn, int, -1);
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID iid = VBOX_IID_INITIALIZER;
    PRUint32 state;
    nsresult rc;
11005
    size_t i;
11006 11007 11008 11009 11010 11011
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
11012
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026

    /* 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)
11027
            goto cleanup;
11028 11029 11030 11031 11032 11033 11034

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
11035 11036
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
11037 11038 11039 11040 11041
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
11042
        goto cleanup;
11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059

    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 */
O
Osier Yang 已提交
11060
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
11061 11062 11063 11064 11065
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
11066
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
11067 11068
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
11069
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
11070
                                       _("could not get snapshot count for listed domains"));
11071 11072 11073 11074 11075 11076 11077 11078 11079 11080
                        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 */
O
Osier Yang 已提交
11081
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131
                    !((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;

                /* just count the machines */
                if (!doms) {
                    count++;
                    continue;
                }

                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);

                dom = virGetDomain(conn, machineNameUtf8, uuid);

                VBOX_UTF8_FREE(machineNameUtf8);
                VBOX_UTF16_FREE(machineNameUtf16);

                if (!dom)
                    goto cleanup;

                if (active)
                    dom->id = i + 1;

                doms[count++] = dom;
            }
        }
    }

    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;
    }

    ret = count;

11132
 cleanup:
11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146
    if (doms) {
        for (i = 0; i < count; i++) {
            if (doms[i])
                virDomainFree(doms[i]);
        }
    }
    VIR_FREE(doms);

    vboxArrayRelease(&machines);
    return ret;
}
#undef MATCH


11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167
static int
vboxNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
                virNodeInfoPtr nodeinfo)
{
    return nodeGetInfo(nodeinfo);
}


static int
vboxNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
                           unsigned long long *freeMems,
                           int startCell,
                           int maxCells)
{
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
vboxNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
11168 11169 11170 11171
    unsigned long long freeMem;
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;
    return freeMem;
11172 11173
}

11174

11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188
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);

    return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
}

T
Taowei 已提交
11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261
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;
}

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;
}

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 */
}

static void _pfnUninitialize(vboxGlobalData *data)
{
    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();
}

static void _pfnComUnallocMem(PCVBOXXPCOM pFuncs, void *pv)
{
    pFuncs->pfnComUnallocMem(pv);
}

static void _pfnUtf16Free(PCVBOXXPCOM pFuncs, PRUnichar *pwszString)
{
    pFuncs->pfnUtf16Free(pwszString);
}

static void _pfnUtf8Free(PCVBOXXPCOM pFuncs, char *pszString)
{
    pFuncs->pfnUtf8Free(pszString);
}

static int _pfnUtf16ToUtf8(PCVBOXXPCOM pFuncs, const PRUnichar *pwszString, char **ppszString)
{
    return pFuncs->pfnUtf16ToUtf8(pwszString, ppszString);
}

static int _pfnUtf8ToUtf16(PCVBOXXPCOM pFuncs, const char *pszString, PRUnichar **ppwszString)
{
    return pFuncs->pfnUtf8ToUtf16(pszString, ppwszString);
}

T
Taowei 已提交
11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297
#if VBOX_API_VERSION == 2002000

static void _vboxIIDInitialize(vboxIIDUnion *iidu)
{
    memset(iidu, 0, sizeof(vboxIIDUnion));
}

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 */
}

#else /* VBOX_API_VERSION != 2002000 */

static void _vboxIIDInitialize(vboxIIDUnion *iidu)
{
    memset(iidu, 0, sizeof(vboxIIDUnion));
    IID_MEMBER(owner) = true;
}

static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu)
{
    DEBUGPRUnichar(msg, IID_MEMBER(value));
}

#endif /* VBOX_API_VERSION != 2002000 */

static nsresult _nsisupportsRelease(nsISupports *nsi)
{
    return nsi->vtbl->Release(nsi);
}

T
Taowei 已提交
11298 11299 11300 11301 11302 11303
static nsresult
_virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16)
{
    return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16);
}

T
Taowei 已提交
11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321
#if VBOX_API_VERSION < 4000000

static nsresult
_virtualboxGetMachine(IVirtualBox *vboxObj, vboxIIDUnion *iidu, IMachine **machine)
{
    return vboxObj->vtbl->GetMachine(vboxObj, IID_MEMBER(value), machine);
}

#else /* VBOX_API_VERSION >= 4000000 */

static nsresult
_virtualboxGetMachine(IVirtualBox *vboxObj, vboxIIDUnion *iidu, IMachine **machine)
{
    return vboxObj->vtbl->FindMachine(vboxObj, IID_MEMBER(value), machine);
}

#endif /* VBOX_API_VERSION >= 4000000 */

T
Taowei 已提交
11322 11323 11324 11325 11326 11327
static nsresult
_virtualboxGetSystemProperties(IVirtualBox *vboxObj, ISystemProperties **systemProperties)
{
    return vboxObj->vtbl->GetSystemProperties(vboxObj, systemProperties);
}

T
Taowei 已提交
11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385
#if VBOX_API_VERSION < 4000000

static nsresult
_sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED)
{
    return data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, IID_MEMBER(value));
}

static nsresult
_sessionClose(ISession *session)
{
    return session->vtbl->Close(session);
}

#else /* VBOX_API_VERSION >= 4000000 */

static nsresult
_sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine)
{
    return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared);
}

static nsresult
_sessionClose(ISession *session)
{
    return session->vtbl->UnlockMachine(session);
}

#endif /* VBOX_API_VERSION >= 4000000 */

static nsresult
_sessionGetConsole(ISession *session, IConsole **console)
{
    return session->vtbl->GetConsole(session, console);
}

static nsresult
_consoleSaveState(IConsole *console, IProgress **progress)
{
    return console->vtbl->SaveState(console, progress);
}

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 已提交
11386 11387 11388 11389 11390 11391
static nsresult
_systemPropertiesGetMaxGuestCPUCount(ISystemProperties *systemProperties, PRUint32 *maxCPUCount)
{
    return systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, maxCPUCount);
}

T
Taowei 已提交
11392 11393 11394 11395 11396 11397 11398 11399 11400 11401
static vboxUniformedPFN _UPFN = {
    .Initialize = _pfnInitialize,
    .Uninitialize = _pfnUninitialize,
    .ComUnallocMem = _pfnComUnallocMem,
    .Utf16Free = _pfnUtf16Free,
    .Utf8Free = _pfnUtf8Free,
    .Utf16ToUtf8 = _pfnUtf16ToUtf8,
    .Utf8ToUtf16 = _pfnUtf8ToUtf16,
};

T
Taowei 已提交
11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415
static vboxUniformedIID _UIID = {
    .vboxIIDInitialize = _vboxIIDInitialize,
    .vboxIIDUnalloc = _vboxIIDUnalloc,
    .vboxIIDToUUID = _vboxIIDToUUID,
    .vboxIIDFromUUID = _vboxIIDFromUUID,
    .vboxIIDIsEqual = _vboxIIDIsEqual,
    .vboxIIDFromArrayItem = _vboxIIDFromArrayItem,
    .DEBUGIID = _DEBUGIID,
};

static vboxUniformednsISupports _nsUISupports = {
    .Release = _nsisupportsRelease,
};

T
Taowei 已提交
11416 11417
static vboxUniformedIVirtualBox _UIVirtualBox = {
    .GetVersion = _virtualboxGetVersion,
T
Taowei 已提交
11418
    .GetMachine = _virtualboxGetMachine,
T
Taowei 已提交
11419
    .GetSystemProperties = _virtualboxGetSystemProperties,
T
Taowei 已提交
11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434
};

static vboxUniformedISession _UISession = {
    .OpenExisting = _sessionOpenExisting,
    .GetConsole = _sessionGetConsole,
    .Close = _sessionClose,
};

static vboxUniformedIConsole _UIConsole = {
    .SaveState = _consoleSaveState,
};

static vboxUniformedIProgress _UIProgress = {
    .WaitForCompletion = _progressWaitForCompletion,
    .GetResultCode = _progressGetResultCode,
T
Taowei 已提交
11435 11436
};

T
Taowei 已提交
11437 11438 11439 11440
static vboxUniformedISystemProperties _UISystemProperties = {
    .GetMaxGuestCPUCount = _systemPropertiesGetMaxGuestCPUCount,
};

T
Taowei 已提交
11441 11442 11443 11444 11445 11446 11447
void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
{
    pVBoxAPI->APIVersion = VBOX_API_VERSION;
    pVBoxAPI->XPCOMCVersion = VBOX_XPCOMC_VERSION;
    pVBoxAPI->initializeDomainEvent = _initializeDomainEvent;
    pVBoxAPI->registerGlobalData = _registerGlobalData;
    pVBoxAPI->UPFN = _UPFN;
T
Taowei 已提交
11448 11449
    pVBoxAPI->UIID = _UIID;
    pVBoxAPI->nsUISupports = _nsUISupports;
T
Taowei 已提交
11450
    pVBoxAPI->UIVirtualBox = _UIVirtualBox;
T
Taowei 已提交
11451 11452 11453
    pVBoxAPI->UISession = _UISession;
    pVBoxAPI->UIConsole = _UIConsole;
    pVBoxAPI->UIProgress = _UIProgress;
T
Taowei 已提交
11454
    pVBoxAPI->UISystemProperties = _UISystemProperties;
T
Taowei 已提交
11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467

#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 已提交
11468 11469 11470 11471 11472 11473
#if VBOX_API_VERSION >= 4000000
    /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
    pVBoxAPI->getMachineForSession = 1;
#else /* VBOX_API_VERSION < 4000000 */
    pVBoxAPI->getMachineForSession = 0;
#endif /* VBOX_API_VERSION < 4000000 */
T
Taowei 已提交
11474
}
11475

11476 11477 11478 11479
/**
 * Function Tables
 */

11480
virDriver NAME(Driver) = {
11481 11482
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
11483 11484 11485
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
11486
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
11487
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
11488
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
11489 11490 11491 11492
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
11493 11494 11495 11496 11497 11498 11499
    .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 */
11500
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
11501 11502
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
11503
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
11504 11505 11506 11507 11508 11509 11510 11511 11512 11513
    .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 */
11514 11515
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
11516 11517 11518 11519
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
11520
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
11521 11522 11523 11524 11525
    .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 */
11526 11527
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
11528
#if VBOX_API_VERSION >= 4000000
11529
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
11530
#endif
11531
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
11532 11533
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
11534
#endif
11535 11536
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
11537 11538 11539
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
11540
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
11541 11542
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
11543
#endif
11544 11545 11546 11547 11548 11549
    .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 */
11550
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
11551
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
11552 11553
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
11554 11555
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
11556
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
11557
    .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */
11558
};
11559 11560 11561

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
11562 11563
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
11564 11565 11566 11567
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
11568 11569 11570 11571 11572 11573 11574 11575
    .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 */
11576
};
11577 11578 11579

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
11580 11581
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
11582 11583
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595
    .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 */
11596
};