vbox_tmpl.c 418.0 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
static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
925 926
                                        unsigned int flags)
{
927 928 929 930 931 932 933 934
    /* 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.
     */

935 936 937 938 939
    virDomainPtr dom;

    virCheckFlags(0, NULL);

    dom = vboxDomainDefineXML(conn, xml);
940 941 942 943
    if (dom == NULL)
        return NULL;

    if (vboxDomainCreate(dom) < 0) {
944
        vboxDomainUndefineFlags(dom, 0);
945
        virObjectUnref(dom);
946
        return NULL;
947 948 949 950 951
    }

    return dom;
}

952 953 954
static virDomainPtr
vboxDomainLookupByName(virConnectPtr conn, const char *name)
{
955
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
956
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
957
    vboxIID iid = VBOX_IID_INITIALIZER;
958
    char      *machineNameUtf8  = NULL;
959
    PRUnichar *machineNameUtf16 = NULL;
960
    unsigned char uuid[VIR_UUID_BUFLEN];
961 962
    size_t i;
    int matched = 0;
963
    nsresult rc;
964

965
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
966
    if (NS_FAILED(rc)) {
967 968
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
969 970
        return NULL;
    }
971

972 973
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
974
        PRBool isAccessible = PR_FALSE;
975

976 977
        if (!machine)
            continue;
978

979 980
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
981

982 983
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
984

985
            if (STREQ(name, machineNameUtf8)) {
986

987
                PRUint32 state;
988

989
                matched = 1;
990

991 992 993
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);
994

995
                machine->vtbl->GetState(machine, &state);
996

997 998 999 1000 1001
                /* 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.
                 */
1002

1003
                ret = virGetDomain(conn, machineNameUtf8, uuid);
1004 1005 1006
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1007
                    ret->id = i + 1;
1008 1009
            }

J
John Ferlan 已提交
1010 1011
            VBOX_UTF8_FREE(machineNameUtf8);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1012 1013
            if (matched == 1)
                break;
1014 1015 1016
        }
    }

1017
    vboxArrayRelease(&machines);
1018 1019

    return ret;
1020 1021
}

1022

1023 1024
static int vboxDomainIsActive(virDomainPtr dom)
{
1025
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1026
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1027
    vboxIID iid = VBOX_IID_INITIALIZER;
1028 1029
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1030
    unsigned char uuid[VIR_UUID_BUFLEN];
1031 1032
    size_t i;
    int matched = 0;
1033
    nsresult rc;
1034

1035
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1036
    if (NS_FAILED(rc)) {
1037 1038
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1039 1040
        return ret;
    }
1041

1042 1043
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1044 1045 1046 1047 1048 1049 1050
        PRBool isAccessible = PR_FALSE;

        if (!machine)
            continue;

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

1052 1053
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1054
                continue;
1055 1056
            vboxIIDToUUID(&iid, uuid);
            vboxIIDUnalloc(&iid);
1057

1058
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1059

1060
                PRUint32 state;
1061

1062
                matched = 1;
1063

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

1067
                machine->vtbl->GetState(machine, &state);
1068

1069 1070
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1071 1072 1073
                    ret = 1;
                else
                    ret = 0;
1074 1075
            }

1076 1077
            if (matched == 1)
                break;
1078 1079 1080
        }
    }

1081 1082 1083
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1084
    vboxArrayRelease(&machines);
1085

1086 1087 1088 1089
    return ret;
}


1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
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)) {
1102 1103
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1104 1105 1106 1107 1108
        goto cleanup;
    }

    ret = 1;

1109
 cleanup:
1110 1111 1112
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1113 1114 1115
}


1116 1117
static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
    /* 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)) {
1128 1129
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1130 1131 1132 1133 1134
        goto cleanup;
    }

    ret = 0;

1135
 cleanup:
1136 1137 1138
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1139 1140
}

1141 1142
static int vboxDomainSuspend(virDomainPtr dom)
{
1143
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1144
    IMachine *machine    = NULL;
1145
    vboxIID iid = VBOX_IID_INITIALIZER;
1146
    IConsole *console    = NULL;
1147
    PRBool isAccessible  = PR_FALSE;
1148
    PRUint32 state;
1149
    nsresult rc;
1150

1151
    vboxIIDFromUUID(&iid, dom->uuid);
1152
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1153
    if (NS_FAILED(rc)) {
1154 1155
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1156 1157
        goto cleanup;
    }
1158

1159 1160
    if (!machine)
        goto cleanup;
1161

1162 1163 1164
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1165

1166
        if (state == MachineState_Running) {
1167 1168
            /* set state pause */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1169 1170 1171 1172 1173
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Pause(console);
                VBOX_RELEASE(console);
                ret = 0;
1174
            } else {
1175 1176
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while suspending the domain"));
1177 1178
                goto cleanup;
            }
1179
            VBOX_SESSION_CLOSE();
1180
        } else {
1181 1182
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not in running state to suspend it"));
1183
            goto cleanup;
1184 1185 1186
        }
    }

1187
 cleanup:
1188
    VBOX_RELEASE(machine);
1189
    vboxIIDUnalloc(&iid);
1190 1191 1192
    return ret;
}

1193 1194
static int vboxDomainResume(virDomainPtr dom)
{
1195
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1196
    IMachine *machine    = NULL;
1197
    vboxIID iid = VBOX_IID_INITIALIZER;
1198 1199
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1200
    nsresult rc;
1201

1202
    PRBool isAccessible = PR_FALSE;
1203

1204
    vboxIIDFromUUID(&iid, dom->uuid);
1205
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1206
    if (NS_FAILED(rc)) {
1207 1208
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1209 1210
        goto cleanup;
    }
1211

1212 1213
    if (!machine)
        goto cleanup;
1214

1215 1216 1217 1218 1219
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);

        if (state == MachineState_Paused) {
1220 1221
            /* resume the machine here */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1222 1223 1224 1225 1226
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Resume(console);
                VBOX_RELEASE(console);
                ret = 0;
1227
            } else {
1228 1229
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while resuming the domain"));
1230 1231
                goto cleanup;
            }
1232
            VBOX_SESSION_CLOSE();
1233
        } else {
1234 1235
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not paused, so can't resume it"));
1236
            goto cleanup;
1237 1238 1239
        }
    }

1240
 cleanup:
1241
    VBOX_RELEASE(machine);
1242
    vboxIIDUnalloc(&iid);
1243 1244 1245
    return ret;
}

1246
static int vboxDomainShutdownFlags(virDomainPtr dom,
1247 1248
                                   unsigned int flags)
{
1249
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1250
    IMachine *machine    = NULL;
1251
    vboxIID iid = VBOX_IID_INITIALIZER;
1252 1253
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1254 1255
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1256

1257 1258
    virCheckFlags(0, -1);

1259
    vboxIIDFromUUID(&iid, dom->uuid);
1260
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1261
    if (NS_FAILED(rc)) {
1262 1263
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1264 1265
        goto cleanup;
    }
1266

1267 1268
    if (!machine)
        goto cleanup;
1269

1270 1271 1272
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1273

1274
        if (state == MachineState_Paused) {
1275 1276
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine paused, so can't power it down"));
1277 1278
            goto cleanup;
        } else if (state == MachineState_PoweredOff) {
1279 1280
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1281 1282
            goto cleanup;
        }
1283

1284
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1285 1286 1287 1288 1289
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
            console->vtbl->PowerButton(console);
            VBOX_RELEASE(console);
            ret = 0;
1290
        }
1291
        VBOX_SESSION_CLOSE();
1292 1293
    }

1294
 cleanup:
1295
    VBOX_RELEASE(machine);
1296
    vboxIIDUnalloc(&iid);
1297 1298 1299
    return ret;
}

1300 1301
static int vboxDomainShutdown(virDomainPtr dom)
{
1302 1303 1304 1305
    return vboxDomainShutdownFlags(dom, 0);
}


E
Eric Blake 已提交
1306 1307
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
{
1308
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1309
    IMachine *machine    = NULL;
1310
    vboxIID iid = VBOX_IID_INITIALIZER;
1311 1312
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1313 1314
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1315

E
Eric Blake 已提交
1316 1317
    virCheckFlags(0, -1);

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

1326 1327
    if (!machine)
        goto cleanup;
1328

1329 1330 1331
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1332

1333
        if (state == MachineState_Running) {
1334
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1335 1336 1337 1338 1339
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Reset(console);
                VBOX_RELEASE(console);
                ret = 0;
1340
            }
1341
            VBOX_SESSION_CLOSE();
1342
        } else {
1343 1344
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not running, so can't reboot it"));
1345
            goto cleanup;
1346 1347 1348
        }
    }

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

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

1367 1368
    virCheckFlags(0, -1);

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

1377 1378
    if (!machine)
        goto cleanup;
1379

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

1384
        if (state == MachineState_PoweredOff) {
1385 1386
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1387 1388
            goto cleanup;
        }
1389

1390
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1391 1392
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
1393

1394
#if VBOX_API_VERSION == 2002000
1395
            console->vtbl->PowerDown(console);
1396
#else
1397
            IProgress *progress = NULL;
1398 1399 1400 1401
            console->vtbl->PowerDown(console, &progress);
            if (progress) {
                progress->vtbl->WaitForCompletion(progress, -1);
                VBOX_RELEASE(progress);
1402
            }
1403 1404
#endif
            VBOX_RELEASE(console);
1405
            dom->id = -1;
1406
            ret = 0;
1407
        }
1408
        VBOX_SESSION_CLOSE();
1409 1410
    }

1411
 cleanup:
1412
    VBOX_RELEASE(machine);
1413
    vboxIIDUnalloc(&iid);
1414 1415 1416
    return ret;
}

1417 1418 1419 1420 1421 1422
static int
vboxDomainDestroy(virDomainPtr dom)
{
    return vboxDomainDestroyFlags(dom, 0);
}

1423
static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1424 1425 1426 1427 1428
    /* 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 ;)
     */
1429
    char *osType;
1430

1431
    ignore_value(VIR_STRDUP(osType, "hvm"));
1432
    return osType;
1433 1434
}

1435 1436
static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
1437
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1438
    IMachine *machine    = NULL;
1439
    vboxIID iid = VBOX_IID_INITIALIZER;
1440
    PRUint32 state       = MachineState_Null;
1441 1442
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1443

1444
    vboxIIDFromUUID(&iid, dom->uuid);
1445
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1446
    if (NS_FAILED(rc)) {
1447 1448
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1449 1450
        goto cleanup;
    }
1451

1452 1453
    if (!machine)
        goto cleanup;
1454

1455 1456 1457
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1458

1459
        if (state != MachineState_PoweredOff) {
1460 1461
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("memory size can't be changed unless domain is powered down"));
1462 1463
            goto cleanup;
        }
1464

1465
        rc = VBOX_SESSION_OPEN(iid.value, machine);
1466 1467 1468
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
1469

1470 1471
                rc = machine->vtbl->SetMemorySize(machine,
                                                  VIR_DIV_UP(memory, 1024));
1472 1473 1474 1475
                if (NS_SUCCEEDED(rc)) {
                    machine->vtbl->SaveSettings(machine);
                    ret = 0;
                } else {
1476 1477 1478 1479
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("could not set the memory size of the "
                                     "domain to: %lu Kb, rc=%08x"),
                                   memory, (unsigned)rc);
1480 1481
                }
            }
1482
            VBOX_SESSION_CLOSE();
1483 1484 1485
        }
    }

1486
 cleanup:
1487
    VBOX_RELEASE(machine);
1488
    vboxIIDUnalloc(&iid);
1489 1490 1491
    return ret;
}

1492 1493
static virDomainState vboxConvertState(enum MachineState state)
{
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
    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 已提交
1504
        case MachineState_Saved:
1505 1506 1507 1508 1509 1510 1511 1512 1513
            return VIR_DOMAIN_SHUTOFF;
        case MachineState_Aborted:
            return VIR_DOMAIN_CRASHED;
        case MachineState_Null:
        default:
            return VIR_DOMAIN_NOSTATE;
    }
}

1514 1515
static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
1516
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1517
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1518 1519
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1520
    nsresult rc;
1521
    size_t i = 0;
1522

1523
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1524
    if (NS_FAILED(rc)) {
1525 1526
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1527 1528
        goto cleanup;
    }
1529

1530
    info->nrVirtCpu = 0;
1531 1532
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1533
        PRBool isAccessible = PR_FALSE;
1534

1535 1536
        if (!machine)
            continue;
1537

1538 1539
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1540

1541 1542 1543 1544 1545 1546
            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
1547
                * for time being set max_balloon and cur_balloon to same
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
                * 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;
                }
1565 1566


1567 1568 1569 1570 1571 1572
                machine->vtbl->GetCPUCount(machine, &CPUCount);
                machine->vtbl->GetMemorySize(machine, &memorySize);
                machine->vtbl->GetState(machine, &state);

                info->cpuTime = 0;
                info->nrVirtCpu = CPUCount;
1573 1574
                info->memory = memorySize * 1024;
                info->maxMem = maxMemorySize * 1024;
1575
                info->state = vboxConvertState(state);
1576

1577
                ret = 0;
1578 1579
            }

J
John Ferlan 已提交
1580 1581
            VBOX_UTF8_FREE(machineName);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1582 1583
            if (info->nrVirtCpu)
                break;
1584 1585 1586 1587
        }

    }

1588
    vboxArrayRelease(&machines);
1589

1590
 cleanup:
1591 1592 1593
    return ret;
}

1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
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)) {
1611 1612
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1613 1614 1615 1616 1617
        goto cleanup;
    }

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

1618
    *state = vboxConvertState(mstate);
1619 1620 1621 1622 1623 1624

    if (reason)
        *reason = 0;

    ret = 0;

1625
 cleanup:
1626 1627 1628 1629
    vboxIIDUnalloc(&domiid);
    return ret;
}

1630 1631 1632 1633
static int
vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
{
1634
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1635
    IMachine *machine    = NULL;
1636
    vboxIID iid = VBOX_IID_INITIALIZER;
1637
    PRUint32  CPUCount   = nvcpus;
1638
    nsresult rc;
1639

1640
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
1641
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1642 1643 1644
        return -1;
    }

1645
    vboxIIDFromUUID(&iid, dom->uuid);
1646
#if VBOX_API_VERSION >= 4000000
1647 1648 1649
    /* Get machine for the call to VBOX_SESSION_OPEN */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1650 1651
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1652 1653 1654 1655 1656
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN(iid.value, machine);
1657 1658 1659 1660 1661 1662 1663
    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;
1664
            } else {
1665 1666 1667 1668
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not set the number of cpus of the domain "
                                 "to: %u, rc=%08x"),
                               CPUCount, (unsigned)rc);
1669
            }
1670
            VBOX_RELEASE(machine);
1671
        } else {
1672 1673
            virReportError(VIR_ERR_NO_DOMAIN,
                           _("no domain with matching id %d"), dom->id);
1674
        }
1675
    } else {
1676 1677
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("can't open session to the domain with id %d"), dom->id);
1678
    }
1679
    VBOX_SESSION_CLOSE();
1680

1681
    vboxIIDUnalloc(&iid);
1682 1683 1684
    return ret;
}

1685 1686 1687
static int
vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
1688
    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
1689 1690 1691 1692 1693
}

static int
vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
1694 1695
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    ISystemProperties *systemProperties = NULL;
1696 1697
    PRUint32 maxCPUCount = 0;

1698
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1699
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1700 1701 1702
        return -1;
    }

1703 1704 1705 1706 1707
    /* Currently every domain supports the same number of max cpus
     * as that supported by vbox and thus take it directly from
     * the systemproperties.
     */

1708 1709 1710 1711
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
1712 1713 1714 1715 1716 1717 1718 1719
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

1720 1721 1722
static int
vboxDomainGetMaxVcpus(virDomainPtr dom)
{
1723
    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
1724 1725 1726
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1727 1728
static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
{
1729
#if VBOX_API_VERSION < 4003000
1730 1731
    IUSBController *USBController = NULL;
    PRBool enabled = PR_FALSE;
R
Ryota Ozaki 已提交
1732 1733 1734
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
1735 1736 1737 1738 1739
    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
    size_t i;
    PRUint32 USBFilterCount = 0;

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

1741
#if VBOX_API_VERSION < 4003000
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
    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 已提交
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;

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

1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
    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;

1788 1789 1790 1791 1792 1793
    for (i = 0; i < def->nhostdevs; i++) {
        def->hostdevs[i] = virDomainHostdevDefAlloc();
        if (!def->hostdevs[i])
            goto release_hostdevs;
    }

1794
    for (i = 0; i < deviceFilters.count; i++) {
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819
        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);

1820 1821
        ignore_value(virStrToLong_ui(vendorIdUtf8, &endptr, 16, &vendorId));
        ignore_value(virStrToLong_ui(productIdUtf8, &endptr, 16, &productId));
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834

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

1835
 release_filters:
1836
    vboxArrayRelease(&deviceFilters);
1837
#if VBOX_API_VERSION < 4003000
1838
 release_controller:
1839
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
1840 1841 1842
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
1843 1844 1845

    return;

1846
 release_hostdevs:
1847 1848 1849 1850 1851
    for (i = 0; i < def->nhostdevs; i++)
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

    goto release_filters;
1852 1853
}

1854
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
1855
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
1856 1857
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
1858
    vboxIID iid = VBOX_IID_INITIALIZER;
1859
    int gotAllABoutDef   = -1;
1860
    nsresult rc;
1861

1862 1863
    /* Flags checked by virDomainDefFormat */

1864
    if (VIR_ALLOC(def) < 0)
1865 1866
        goto cleanup;

1867
    vboxIIDFromUUID(&iid, dom->uuid);
1868
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1869
    if (NS_SUCCEEDED(rc)) {
1870
        PRBool accessible = PR_FALSE;
1871

1872 1873
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
1874
            size_t i = 0;
1875 1876 1877
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
1878
            PRBool VRDxEnabled                  = PR_FALSE;
1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889
            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;
1890
#if VBOX_API_VERSION < 3001000
1891 1892 1893 1894 1895 1896 1897 1898
            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;
1899
#else  /* VBOX_API_VERSION >= 3001000 */
1900
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
1901 1902
#endif /* VBOX_API_VERSION >= 3001000 */
#if VBOX_API_VERSION < 4000000
1903
            IVRDPServer *VRDxServer             = NULL;
1904
#else  /* VBOX_API_VERSION >= 4000000 */
1905
            IVRDEServer *VRDxServer             = NULL;
1906
#endif /* VBOX_API_VERSION >= 4000000 */
1907
            IAudioAdapter *audioAdapter         = NULL;
1908
#if VBOX_API_VERSION >= 4001000
1909
            PRUint32 chipsetType                = ChipsetType_Null;
1910
#endif /* VBOX_API_VERSION >= 4001000 */
1911
            ISystemProperties *systemProperties = NULL;
1912 1913


1914 1915 1916
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
1917 1918
            if (VIR_STRDUP(def->name, dom->name) < 0)
                goto cleanup;
1919

1920
            machine->vtbl->GetMemorySize(machine, &memorySize);
1921
            def->mem.cur_balloon = memorySize * 1024;
1922

1923
#if VBOX_API_VERSION >= 4001000
1924
            machine->vtbl->GetChipsetType(machine, &chipsetType);
1925
#endif /* VBOX_API_VERSION >= 4001000 */
1926

1927 1928 1929 1930
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
1931
#if VBOX_API_VERSION < 4001000
1932
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
1933
#else  /* VBOX_API_VERSION >= 4000000 */
1934
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
1935
#endif /* VBOX_API_VERSION >= 4000000 */
1936 1937 1938 1939 1940 1941 1942 1943 1944
                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
             */
1945 1946
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
1947 1948

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
1949
            def->maxvcpus = def->vcpus = CPUCount;
1950 1951 1952

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

1953 1954
            if (VIR_STRDUP(def->os.type, "hvm") < 0)
                goto cleanup;
1955

1956
            def->os.arch = virArchFromHost();
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979

            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 已提交
1980
                    /* Can VirtualBox really boot from a shared folder? */
1981
                }
1982
            }
1983

1984
#if VBOX_API_VERSION < 3001000
1985
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
1986
#elif VBOX_API_VERSION == 3001000
1987
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
1988
#elif VBOX_API_VERSION >= 3002000
1989 1990
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
1991
            if (PAEEnabled)
J
Ján Tomko 已提交
1992
                def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
1993

1994 1995 1996
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
1997
                if (ACPIEnabled)
J
Ján Tomko 已提交
1998
                    def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
1999

2000
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
2001
                if (IOAPICEnabled)
J
Ján Tomko 已提交
2002
                    def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON;
2003

2004 2005 2006 2007 2008
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
2009
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2010 2011 2012 2013 2014 2015 2016 2017

            /* 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 */
2018
                        PRUint32 VRAMSize          = 8;
2019 2020 2021 2022 2023 2024 2025
                        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);
2026
#if VBOX_API_VERSION >= 3001000
2027
                        machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
2028
#endif /* VBOX_API_VERSION >= 3001000 */
2029 2030

                        def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
2031
                        def->videos[0]->vram            = VRAMSize * 1024;
2032 2033 2034 2035
                        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;
2036 2037 2038
                        }
                    }
                }
2039
            }
2040

2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
            /* 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;
2052

2053
                def->ngraphics = 0;
2054

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

2059 2060 2061
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
2062

2063
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2064 2065 2066
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
2067

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

2072 2073 2074
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
2075

J
John Ferlan 已提交
2076
                            if (strlen(valueDisplayUtf8) <= 0)
2077
                                VBOX_UTF8_FREE(valueDisplayUtf8);
2078
                        }
2079

2080 2081
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
2082
                            if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
2083 2084 2085 2086 2087 2088
                                /* 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++;
2089
                        }
2090

2091 2092
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
2093
                            if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
2094
                                /* just don't go to cleanup yet as it is ok to have
2095 2096
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
2097
                                 */
2098
                            }
2099 2100
                            totalPresent++;
                        }
J
John Ferlan 已提交
2101
                        VBOX_UTF8_FREE(valueDisplayUtf8);
2102 2103
                    }

2104 2105
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
2106

2107 2108
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2109

2110 2111 2112 2113 2114 2115 2116
                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++;
                    }
2117

2118 2119 2120 2121 2122 2123 2124 2125
                    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) {
2126
                        const char *tmp;
2127
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2128
                        tmp = virGetEnvBlockSUID("DISPLAY");
2129 2130 2131 2132
                        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
                             */
2133 2134 2135 2136 2137
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
2138

2139
#if VBOX_API_VERSION < 4000000
2140
                machine->vtbl->GetVRDPServer(machine, &VRDxServer);
2141
#else  /* VBOX_API_VERSION >= 4000000 */
2142
                machine->vtbl->GetVRDEServer(machine, &VRDxServer);
2143
#endif /* VBOX_API_VERSION >= 4000000 */
2144 2145 2146
                if (VRDxServer) {
                    VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
                    if (VRDxEnabled) {
2147 2148 2149 2150 2151 2152 2153 2154 2155

                        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;
2156
#if VBOX_API_VERSION < 3001000
2157
                            PRUint32 VRDPport = 0;
2158
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2159 2160
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2161 2162 2163
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
2164
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
2165
                            PRUnichar *VRDPport = NULL;
2166
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2167 2168 2169 2170
                            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);
2171 2172 2173
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
2174
#else /* VBOX_API_VERSION >= 4000000 */
2175 2176 2177 2178 2179 2180 2181 2182 2183
                            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);
2184
                            } else {
2185
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
2186
                            }
2187
#endif /* VBOX_API_VERSION >= 4000000 */
2188

2189
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2190

2191
#if VBOX_API_VERSION >= 4000000
2192 2193 2194 2195
                            PRUnichar *VRDENetAddressKey = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
                            VBOX_UTF16_FREE(VRDENetAddressKey);
2196
#else /* VBOX_API_VERSION < 4000000 */
2197
                            VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
2198
#endif /* VBOX_API_VERSION < 4000000 */
2199 2200 2201
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
2202 2203
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
2204 2205 2206
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
2207

2208
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2209
                            if (allowMultiConnection) {
2210
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2211
                            }
2212

2213
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2214
                            if (reuseSingleConnection) {
2215
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2216
                            }
2217

2218
                            def->ngraphics++;
2219
                        } else
2220
                            virReportOOMError();
2221
                    }
2222
                    VBOX_RELEASE(VRDxServer);
2223
                }
2224
            }
2225

2226
#if VBOX_API_VERSION < 3001000
2227 2228
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2229

2230 2231 2232 2233
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
2234

2235 2236 2237
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
2238

2239 2240 2241
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
2242

2243 2244 2245 2246
            VBOX_UTF16_FREE(hddBusUtf16);

            if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
                for (i = 0; i < def->ndisks; i++) {
2247
                    if ((def->disks[i] = virDomainDiskDefNew())) {
2248 2249
                        def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                        def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2250
                        virDomainDiskSetType(def->disks[i],
E
Eric Blake 已提交
2251
                                             VIR_STORAGE_TYPE_FILE);
2252
                    }
2253
                }
2254
            }
2255

2256 2257 2258 2259
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2260

2261 2262
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2263

2264
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2265

2266
                if (hddType == HardDiskType_Immutable)
2267
                    def->disks[hddNum]->src->readonly = true;
2268 2269
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
2270
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
2271
                hddNum++;
2272

2273 2274 2275 2276
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
2277

2278 2279 2280 2281
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2282

2283 2284
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2285

2286
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2287

2288
                if (hddType == HardDiskType_Immutable)
2289
                    def->disks[hddNum]->src->readonly = true;
2290 2291
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
2292
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
2293
                hddNum++;
2294

2295 2296 2297 2298
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
2299

2300 2301 2302 2303
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2304

2305 2306
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2307

2308
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2309

2310
                if (hddType == HardDiskType_Immutable)
2311
                    def->disks[hddNum]->src->readonly = true;
2312 2313
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
J
Ján Tomko 已提交
2314 2315
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
                hddNum++;
2316 2317 2318 2319 2320

                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskSS);
            }
2321
#else  /* VBOX_API_VERSION >= 3001000 */
2322 2323 2324 2325 2326 2327 2328
            /* dump IDE hdds if present */

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

            /* get the number of attachments */
2332 2333
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2334 2335 2336 2337 2338 2339 2340
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
2341 2342
                    }
                }
2343
            }
2344

2345 2346 2347
            /* Allocate mem, if fails return error */
            if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) {
                for (i = 0; i < def->ndisks; i++) {
2348 2349
                    virDomainDiskDefPtr disk = virDomainDiskDefNew();
                    if (!disk) {
2350 2351
                        error = true;
                        break;
2352
                    }
2353
                    def->disks[i] = disk;
2354
                }
2355 2356 2357 2358 2359 2360 2361 2362
            } else {
                error = true;
            }

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

            /* get the attachment details here */
2363 2364
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397
                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;
                }
2398

2399 2400 2401
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
2402 2403
                ignore_value(virDomainDiskSetSource(def->disks[diskCount],
                                                    mediumLocUtf8));
2404 2405
                VBOX_UTF8_FREE(mediumLocUtf8);

2406
                if (!virDomainDiskGetSource(def->disks[diskCount])) {
2407 2408 2409 2410 2411
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2412

2413 2414 2415 2416 2417 2418 2419 2420 2421 2422
                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;
                }
2423

2424 2425 2426 2427 2428 2429 2430 2431 2432 2433
                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);
2434
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2435 2436 2437 2438 2439 2440
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2441 2442 2443 2444
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2445 2446 2447 2448 2449
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2450

2451 2452
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2453
                    def->disks[diskCount]->src->readonly = true;
2454

2455
                virDomainDiskSetType(def->disks[diskCount],
E
Eric Blake 已提交
2456
                                     VIR_STORAGE_TYPE_FILE);
2457

2458 2459 2460 2461
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2462

2463
            vboxArrayRelease(&mediumAttachments);
2464

2465 2466 2467 2468 2469 2470 2471 2472
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2473

2474
#endif /* VBOX_API_VERSION >= 3001000 */
2475

M
Matthias Bolte 已提交
2476 2477 2478 2479 2480 2481 2482 2483 2484
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

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

            if (sharedFolders.count > 0) {
2485
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
M
Matthias Bolte 已提交
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495
                    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;

2496
                    if (VIR_ALLOC(def->fss[i]) < 0)
M
Matthias Bolte 已提交
2497 2498 2499 2500 2501 2502
                        goto sharedFoldersCleanup;

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

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
2503 2504 2505
                    if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
                        VBOX_UTF8_FREE(hostPath);
                        VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2506 2507
                        goto sharedFoldersCleanup;
                    }
2508 2509
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2510 2511 2512

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
2513 2514 2515
                    if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
                        VBOX_UTF8_FREE(name);
                        VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2516 2517
                        goto sharedFoldersCleanup;
                    }
2518 2519
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2520 2521 2522 2523 2524 2525 2526 2527

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

                    ++def->nfss;
                }
            }

2528
 sharedFoldersCleanup:
M
Matthias Bolte 已提交
2529 2530
            vboxArrayRelease(&sharedFolders);

2531 2532 2533 2534 2535
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
2536

2537 2538 2539
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2540

2541 2542 2543 2544
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
2545

2546 2547 2548
                    VBOX_RELEASE(adapter);
                }
            }
2549

2550 2551 2552
            /* 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++) {
2553
                    ignore_value(VIR_ALLOC(def->nets[i]));
2554 2555
                }
            }
2556

2557
            /* Now get the details about the network cards here */
2558
            for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
2559
                INetworkAdapter *adapter = NULL;
2560

2561 2562 2563
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2564

2565 2566 2567 2568 2569 2570 2571
                    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};
2572

2573 2574
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
2575

2576
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
2577

2578 2579 2580
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
2581

2582
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
2583

2584
#if VBOX_API_VERSION < 4001000
2585
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2586
#else /* VBOX_API_VERSION >= 4001000 */
2587
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
2588
#endif /* VBOX_API_VERSION >= 4001000 */
2589

2590
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
2591
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
2592

2593 2594
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
2595

2596 2597 2598
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
2599

2600 2601 2602 2603 2604
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

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

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
2605
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
2606 2607 2608 2609 2610 2611 2612 2613 2614 2615

                            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;

2616
#if VBOX_API_VERSION < 4001000
2617
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2618
#else /* VBOX_API_VERSION >= 4001000 */
2619
                            adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
2620
#endif /* VBOX_API_VERSION >= 4001000 */
2621 2622

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
2623
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636

                            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) {
2637
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
2638
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
2639
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
2640
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
2641
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
2642
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
2643
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
2644
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
2645
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
2646
#if VBOX_API_VERSION >= 3001000
2647
                        } else if (adapterType == NetworkAdapterType_Virtio) {
2648
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
2649
#endif /* VBOX_API_VERSION >= 3001000 */
2650 2651
                        }

2652 2653 2654 2655 2656 2657 2658 2659 2660
                        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 ... */
2661
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
2662 2663 2664 2665 2666 2667
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
2668
                    }
2669 2670

                    VBOX_RELEASE(adapter);
2671
                }
2672
            }
2673

2674
            /* dump sound card if active */
2675

2676 2677 2678
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
2679

2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706
            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);
            }
2707

2708
#if VBOX_API_VERSION < 3001000
2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727
            /* 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) {
2728
                            if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) {
2729 2730
                                def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
                                def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2731
                                virDomainDiskSetType(def->disks[def->ndisks - 1],
E
Eric Blake 已提交
2732
                                                     VIR_STORAGE_TYPE_FILE);
2733
                                def->disks[def->ndisks - 1]->src->readonly = true;
2734
                                ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
2735 2736
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
                                def->ndisks--;
2737
                            } else {
2738
                                def->ndisks--;
2739 2740
                            }
                        } else {
2741
                            def->ndisks--;
2742
                        }
2743 2744 2745 2746

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
2747 2748
                    }
                }
2749 2750
                VBOX_RELEASE(dvdDrive);
            }
2751

2752 2753 2754 2755 2756 2757 2758
            /* 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) {
2759 2760
                    PRUint32 state = DriveState_Null;

2761
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
2762
                    if (state == DriveState_ImageMounted) {
2763
                        IFloppyImage *floppyImage = NULL;
2764

2765 2766
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
2767 2768 2769
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

2770 2771
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
2772 2773 2774

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
2775
                                if ((def->disks[def->ndisks - 1] = virDomainDiskDefNew())) {
2776 2777
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
2778
                                    virDomainDiskSetType(def->disks[def->ndisks - 1],
E
Eric Blake 已提交
2779
                                                         VIR_STORAGE_TYPE_FILE);
2780
                                    def->disks[def->ndisks - 1]->src->readonly = false;
2781
                                    ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
2782 2783
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
                                    def->ndisks--;
2784 2785 2786 2787 2788 2789 2790
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

2791 2792 2793
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
2794 2795 2796 2797
                        }
                    }
                }

2798 2799
                VBOX_RELEASE(floppyDrive);
            }
2800 2801
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
2802 2803 2804 2805 2806 2807 2808 2809 2810

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

2813
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
2814
                    if (enabled) {
2815
                        def->nserials++;
2816 2817
                    }

2818
                    VBOX_RELEASE(serialPort);
2819
                }
2820
            }
2821

2822 2823 2824
            /* 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++) {
2825
                    ignore_value(VIR_ALLOC(def->serials[i]));
2826 2827
                }
            }
2828

2829
            /* Now get the details about the serial ports here */
2830 2831 2832
            for (i = 0;
                 serialPortIncCount < def->nserials && i < serialPortCount;
                 i++) {
2833
                ISerialPort *serialPort = NULL;
2834

2835 2836 2837
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
2838

2839 2840 2841 2842 2843 2844 2845 2846 2847 2848
                    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) {
2849
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
2850
                        } else if (hostMode == PortMode_HostDevice) {
2851
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
2852
#if VBOX_API_VERSION >= 3000000
2853
                        } else if (hostMode == PortMode_RawFile) {
2854
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
2855
#endif /* VBOX_API_VERSION >= 3000000 */
2856
                        } else {
2857
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
2858
                        }
2859

2860
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2861

2862 2863 2864 2865 2866 2867 2868
                        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;
                        }
2869

2870
                        serialPort->vtbl->GetPath(serialPort, &pathUtf16);
2871

2872 2873
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
2874
                            ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
2875 2876
                        }

2877 2878 2879 2880
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
2881 2882
                    }

2883 2884 2885
                    VBOX_RELEASE(serialPort);
                }
            }
2886

2887 2888 2889 2890 2891
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
2892

2893 2894 2895
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
2896

2897 2898 2899
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
2900
                    }
2901 2902

                    VBOX_RELEASE(parallelPort);
2903
                }
2904
            }
2905

2906 2907 2908
            /* 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++) {
2909
                    ignore_value(VIR_ALLOC(def->parallels[i]));
2910
                }
2911
            }
2912

2913
            /* Now get the details about the parallel ports here */
2914 2915 2916 2917
            for (i = 0;
                 parallelPortIncCount < def->nparallels &&
                     i < parallelPortCount;
                 i++) {
2918
                IParallelPort *parallelPort = NULL;
2919

2920 2921 2922
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
2923

2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937
                    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;
                        }
2938

2939
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
2940
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2941

2942
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
2943

2944
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
2945
                        ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
2946

2947 2948 2949 2950
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
2951
                    }
2952 2953

                    VBOX_RELEASE(parallelPort);
2954
                }
2955
            }
2956

2957
            /* dump USB devices/filters if active */
2958
            vboxHostDeviceGetXMLDesc(data, def, machine);
2959 2960 2961 2962 2963

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
2964
        }
2965 2966
        VBOX_RELEASE(machine);
        machine = NULL;
2967 2968 2969
    }

    if (gotAllABoutDef == 0)
2970
        ret = virDomainDefFormat(def, flags);
2971

2972
 cleanup:
2973
    vboxIIDUnalloc(&iid);
2974 2975 2976 2977
    virDomainDefFree(def);
    return ret;
}

2978
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
2979
    VBOX_OBJECT_CHECK(conn, int, -1);
2980
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
2981 2982 2983
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
2984
    nsresult rc;
2985
    size_t i, j;
2986

2987
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
2988
    if (NS_FAILED(rc)) {
2989 2990 2991
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Defined Domains, rc=%08x"),
                       (unsigned)rc);
2992 2993
        goto cleanup;
    }
2994

2995 2996
    memset(names, 0, sizeof(names[i]) * maxnames);

2997 2998 2999
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
3000 3001 3002 3003 3004 3005

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3006 3007
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3008 3009
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3010 3011 3012
                    if (VIR_STRDUP(names[j], machineName) < 0) {
                        VBOX_UTF16_FREE(machineNameUtf16);
                        VBOX_UTF8_FREE(machineName);
3013
                        for (j = 0; j < maxnames; j++)
3014 3015 3016
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
3017
                    }
3018 3019
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
3020
                    j++;
3021
                    ret++;
3022 3023 3024 3025 3026
                }
            }
        }
    }

3027
 cleanup:
3028
    vboxArrayRelease(&machines);
3029 3030 3031
    return ret;
}

3032 3033
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn)
{
3034
    VBOX_OBJECT_CHECK(conn, int, -1);
3035
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3036
    PRUint32 state       = MachineState_Null;
3037
    nsresult rc;
3038
    size_t i;
3039

3040
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3041
    if (NS_FAILED(rc)) {
3042 3043 3044
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3045 3046
        goto cleanup;
    }
3047

3048 3049 3050
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3051 3052 3053 3054 3055 3056

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3057 3058
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3059
                    ret++;
3060 3061 3062 3063 3064
                }
            }
        }
    }

3065
 cleanup:
3066
    vboxArrayRelease(&machines);
3067 3068 3069
    return ret;
}

E
Eric Blake 已提交
3070 3071

static int
3072
vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3073
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099
{
    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);

3100
        if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
E
Eric Blake 已提交
3101 3102 3103 3104 3105 3106 3107 3108 3109 3110

            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 已提交
3111
                if (strlen(valueDisplayUtf8) <= 0)
E
Eric Blake 已提交
3112 3113 3114 3115 3116
                    VBOX_UTF8_FREE(valueDisplayUtf8);
            }

            if (STREQ(valueTypeUtf8, "sdl")) {
                sdlPresent = 1;
3117 3118 3119 3120 3121
                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 已提交
3122 3123 3124 3125 3126
                }
            }

            if (STREQ(valueTypeUtf8, "gui")) {
                guiPresent = 1;
3127 3128 3129 3130 3131
                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 已提交
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151
                }
            }
        }

        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 已提交
3152
    VBOX_UTF8_FREE(valueDisplayUtf8);
E
Eric Blake 已提交
3153 3154 3155

    if (guiPresent) {
        if (guiDisplay) {
E
Eric Blake 已提交
3156
            char *displayutf8;
3157
            if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) >= 0) {
E
Eric Blake 已提交
3158 3159 3160
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3161 3162 3163 3164 3165 3166 3167 3168
            VIR_FREE(guiDisplay);
        }

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

    if (sdlPresent) {
        if (sdlDisplay) {
E
Eric Blake 已提交
3169
            char *displayutf8;
3170
            if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) >= 0) {
E
Eric Blake 已提交
3171 3172 3173
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3174 3175 3176 3177 3178 3179 3180 3181 3182 3183
            VIR_FREE(sdlDisplay);
        }

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

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

3184
#if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3185 3186
    rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                data->vboxSession,
3187
                                                iid->value,
E
Eric Blake 已提交
3188 3189
                                                sessionType,
                                                env,
3190
                                                &progress);
3191
#else /* VBOX_API_VERSION >= 4000000 */
3192 3193
    rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                        sessionType, env, &progress);
3194
#endif /* VBOX_API_VERSION >= 4000000 */
3195

E
Eric Blake 已提交
3196
    if (NS_FAILED(rc)) {
3197 3198
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
E
Eric Blake 已提交
3199 3200 3201
        ret = -1;
    } else {
        PRBool completed = 0;
3202
#if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218
        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 */
3219
            dom->id = maxDomID + 1;
E
Eric Blake 已提交
3220 3221 3222 3223 3224 3225
            ret = 0;
        }
    }

    VBOX_RELEASE(progress);

3226
    VBOX_SESSION_CLOSE();
E
Eric Blake 已提交
3227 3228 3229 3230 3231 3232 3233

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

3234 3235
static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
3236
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
3237
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3238
    unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3239
    nsresult rc;
3240
    size_t i = 0;
3241

3242 3243
    virCheckFlags(0, -1);

3244
    if (!dom->name) {
3245 3246
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Error while reading the domain name"));
3247 3248 3249
        goto cleanup;
    }

3250
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3251
    if (NS_FAILED(rc)) {
3252 3253
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3254 3255
        goto cleanup;
    }
3256

3257 3258
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3259
        PRBool isAccessible = PR_FALSE;
3260

3261 3262
        if (!machine)
            continue;
3263

3264 3265
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
3266
            vboxIID iid = VBOX_IID_INITIALIZER;
3267

3268 3269
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
3270
                continue;
3271
            vboxIIDToUUID(&iid, uuid);
3272

3273
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3274 3275 3276
                PRUint32 state = MachineState_Null;
                machine->vtbl->GetState(machine, &state);

3277 3278 3279
                if ((state == MachineState_PoweredOff) ||
                    (state == MachineState_Saved) ||
                    (state == MachineState_Aborted)) {
3280
                    ret = vboxStartMachine(dom, i, machine, &iid);
3281
                } else {
3282
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3283 3284 3285
                                   _("machine is not in "
                                     "poweroff|saved|aborted state, so "
                                     "couldn't start it"));
3286
                    ret = -1;
3287 3288
                }
            }
3289
            vboxIIDUnalloc(&iid);
3290 3291
            if (ret != -1)
                break;
3292 3293 3294
        }
    }

3295
    /* Do the cleanup and take care you dont leak any memory */
3296
    vboxArrayRelease(&machines);
3297

3298
 cleanup:
3299 3300 3301
    return ret;
}

3302 3303
static int vboxDomainCreate(virDomainPtr dom)
{
3304 3305 3306
    return vboxDomainCreateWithFlags(dom, 0);
}

E
Eric Blake 已提交
3307 3308 3309 3310 3311 3312
static void
vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
                       IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 maxBootPosition            = 0;
3313
    size_t i = 0;
3314

3315
    VIR_DEBUG("def->os.type             %s", def->os.type);
3316
    VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3317
    VIR_DEBUG("def->os.machine          %s", def->os.machine);
3318
    VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330
    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);
3331

E
Eric Blake 已提交
3332 3333 3334 3335 3336 3337
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxBootPosition(systemProperties,
                                                   &maxBootPosition);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
3338
    }
3339

E
Eric Blake 已提交
3340 3341 3342
    /* Clear the defaults first */
    for (i = 0; i < maxBootPosition; i++) {
        machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3343
    }
3344

E
Eric Blake 已提交
3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355
    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;
3356
        }
E
Eric Blake 已提交
3357
        machine->vtbl->SetBootOrder(machine, i+1, device);
3358
    }
E
Eric Blake 已提交
3359
}
3360

E
Eric Blake 已提交
3361 3362 3363
static void
vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
3364
    size_t i;
E
Eric Blake 已提交
3365
    nsresult rc;
3366

3367
#if VBOX_API_VERSION < 3001000
E
Eric Blake 已提交
3368 3369 3370 3371
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
3372 3373 3374 3375 3376
        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);
3377 3378
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3379
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
3380
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3381 3382
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
3383
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3384
                  virStorageFileFormatTypeToString(format));
3385
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
3386
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->src->readonly
E
Eric Blake 已提交
3387
                                             ? "True" : "False"));
3388
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->src->shared
E
Eric Blake 已提交
3389 3390 3391
                                             ? "True" : "False"));

        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
3392
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3393 3394 3395 3396 3397 3398 3399
                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
                 */
3400

E
Eric Blake 已提交
3401 3402 3403 3404
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
3405 3406
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3407

3408
                    VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
3409

E
Eric Blake 已提交
3410 3411 3412 3413 3414
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
3415
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
3416 3417 3418 3419
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3420
                                                           &dvduuid.value);
E
Eric Blake 已提交
3421
                        if (NS_FAILED(rc)) {
3422 3423 3424
                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                           _("can't get the uuid of the file to "
                                             "be attached to cdrom: %s, rc=%08x"),
3425
                                           src, (unsigned)rc);
E
Eric Blake 已提交
3426
                        } else {
3427
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
3428
                            if (NS_FAILED(rc)) {
3429 3430
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
3431
                                               src, (unsigned)rc);
E
Eric Blake 已提交
3432
                            } else {
3433
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3434
                            }
3435
                        }
E
Eric Blake 已提交
3436 3437

                        VBOX_MEDIUM_RELEASE(dvdImage);
3438
                    }
3439
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
3440 3441 3442
                    VBOX_UTF16_FREE(dvdfileUtf16);
                    VBOX_RELEASE(dvdDrive);
                }
E
Eric Blake 已提交
3443
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
E
Eric Blake 已提交
3444 3445
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
E
Eric Blake 已提交
3446
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3447 3448
                IHardDisk *hardDisk     = NULL;
                PRUnichar *hddfileUtf16 = NULL;
3449
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
3450 3451 3452 3453 3454 3455
                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
                 */
3456

3457
                VBOX_UTF8_TO_UTF16(src, &hddfileUtf16);
E
Eric Blake 已提交
3458
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
3459

E
Eric Blake 已提交
3460 3461
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
3462

E
Eric Blake 已提交
3463
                if (!hardDisk) {
3464
# if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
3465 3466 3467 3468
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
3469
# else
E
Eric Blake 已提交
3470 3471 3472 3473 3474 3475 3476 3477
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
3478
# endif
E
Eric Blake 已提交
3479
                }
3480

E
Eric Blake 已提交
3481 3482
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
3483
                                                       &hdduuid.value);
E
Eric Blake 已提交
3484
                    if (NS_FAILED(rc)) {
3485 3486 3487
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("can't get the uuid of the file to be "
                                         "attached as harddisk: %s, rc=%08x"),
3488
                                       src, (unsigned)rc);
E
Eric Blake 已提交
3489
                    } else {
3490
                        if (def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3491 3492
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
3493
                            VIR_DEBUG("setting harddisk to readonly");
3494
                        } else if (!def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3495 3496
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
3497
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
3498 3499 3500
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
3501
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
3502
                                       " is taken by CD/DVD Drive");
3503
                            } else {
E
Eric Blake 已提交
3504 3505 3506 3507
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

3508 3509
                                char *hddcname;
                                ignore_value(VIR_STRDUP(hddcname, "IDE"));
E
Eric Blake 已提交
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521
                                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;
3522
                                }
E
Eric Blake 已提交
3523 3524

                                rc = machine->vtbl->AttachHardDisk(machine,
3525
                                                                   hdduuid.value,
E
Eric Blake 已提交
3526 3527 3528 3529 3530 3531
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
3532 3533 3534
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
3535
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
3536
                                } else {
3537
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
3538 3539 3540
                                }
                            }
                        }
3541
                    }
E
Eric Blake 已提交
3542 3543
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
3544
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
3545 3546
                VBOX_UTF16_FREE(hddEmpty);
                VBOX_UTF16_FREE(hddfileUtf16);
E
Eric Blake 已提交
3547
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
E
Eric Blake 已提交
3548 3549
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
3550
            if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3551 3552 3553 3554 3555 3556 3557
                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;
3558 3559
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
3560

3561
                        VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
E
Eric Blake 已提交
3562 3563 3564
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
3565

E
Eric Blake 已提交
3566 3567 3568
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
3569
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
3570 3571
                                                                 &floppyImage);
                        }
3572

E
Eric Blake 已提交
3573 3574
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
3575
                                                                  &fduuid.value);
E
Eric Blake 已提交
3576
                            if (NS_FAILED(rc)) {
3577 3578 3579
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
3580
                                               src, (unsigned)rc);
E
Eric Blake 已提交
3581 3582
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
3583
                                                                   fduuid.value);
E
Eric Blake 已提交
3584
                                if (NS_FAILED(rc)) {
3585 3586 3587
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
3588
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
3589
                                } else {
3590
                                    DEBUGIID("floppyImage UUID", fduuid.value);
3591 3592
                                }
                            }
E
Eric Blake 已提交
3593
                            VBOX_MEDIUM_RELEASE(floppyImage);
3594
                        }
3595
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
3596
                        VBOX_UTF16_FREE(fdfileUtf16);
3597
                    }
E
Eric Blake 已提交
3598
                    VBOX_RELEASE(floppyDrive);
3599
                }
E
Eric Blake 已提交
3600
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3601
            }
3602
        }
E
Eric Blake 已提交
3603
    }
3604
#else  /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616
    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 */
3617
    {
E
Eric Blake 已提交
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652
        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);
    }
3653

E
Eric Blake 已提交
3654
    for (i = 0; i < def->ndisks && !error; i++) {
3655 3656 3657 3658 3659
        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);
3660 3661
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3662
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
3663
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3664 3665
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
3666
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3667
                  virStorageFileFormatTypeToString(format));
3668
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
3669
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->src->readonly
E
Eric Blake 已提交
3670
                                             ? "True" : "False"));
3671
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->src->shared
E
Eric Blake 已提交
3672 3673
                                             ? "True" : "False"));

E
Eric Blake 已提交
3674
        if (type == VIR_STORAGE_TYPE_FILE && src) {
E
Eric Blake 已提交
3675 3676 3677 3678 3679
            IMedium   *medium          = NULL;
            PRUnichar *mediumUUID      = NULL;
            PRUnichar *mediumFileUtf16 = NULL;
            PRUint32   storageBus      = StorageBus_Null;
            PRUint32   deviceType      = DeviceType_Null;
3680
# if VBOX_API_VERSION >= 4000000
3681
            PRUint32   accessMode      = AccessMode_ReadOnly;
3682
# endif
E
Eric Blake 已提交
3683 3684 3685 3686
            PRInt32    deviceInst      = 0;
            PRInt32    devicePort      = 0;
            PRInt32    deviceSlot      = 0;

3687
            VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16);
E
Eric Blake 已提交
3688 3689 3690

            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                deviceType = DeviceType_HardDisk;
3691
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3692 3693
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
3694 3695
# else
                accessMode = AccessMode_ReadWrite;
3696
# endif
E
Eric Blake 已提交
3697 3698
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
3699
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3700 3701
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
3702 3703
# else
                accessMode = AccessMode_ReadOnly;
3704
# endif
E
Eric Blake 已提交
3705 3706
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
3707
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3708 3709
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
3710 3711
# else
                accessMode = AccessMode_ReadWrite;
3712
# endif
E
Eric Blake 已提交
3713 3714 3715 3716
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3717

3718
# if VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
3719 3720
            data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, &medium);
3721
# elif VBOX_API_VERSION >= 4002000
3722 3723
            data->vboxObj->vtbl->OpenMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, accessMode, PR_FALSE, &medium);
3724 3725
# endif

E
Eric Blake 已提交
3726 3727
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
3728

E
Eric Blake 已提交
3729
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
3730

3731
# if VBOX_API_VERSION < 4000000
3732
                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3733 3734 3735 3736 3737 3738 3739 3740
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
3741 3742
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
3743 3744 3745 3746
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
3747 3748
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3749 3750 3751 3752 3753 3754
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
3755
                }
3756
# elif VBOX_API_VERSION == 4000000
3757 3758 3759 3760
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     &medium);
3761
# elif VBOX_API_VERSION >= 4001000
3762 3763 3764 3765 3766
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     false,
                                                     &medium);
3767
# endif /* VBOX_API_VERSION >= 4001000 */
3768

E
Eric Blake 已提交
3769 3770
                VBOX_UTF16_FREE(mediumEmpty);
            }
3771

E
Eric Blake 已提交
3772
            if (!medium) {
3773 3774 3775
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to attach the following disk/dvd/floppy "
                                 "to the machine: %s, rc=%08x"),
3776
                               src, (unsigned)rc);
E
Eric Blake 已提交
3777 3778 3779
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3780

E
Eric Blake 已提交
3781 3782
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
3783 3784 3785
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("can't get the uuid of the file to be attached "
                                 "as harddisk/dvd/floppy: %s, rc=%08x"),
3786
                               src, (unsigned)rc);
E
Eric Blake 已提交
3787 3788 3789 3790
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
3791

E
Eric Blake 已提交
3792
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3793
                if (def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3794
                    medium->vtbl->SetType(medium, MediumType_Immutable);
3795
                    VIR_DEBUG("setting harddisk to immutable");
3796
                } else if (!def->disks[i]->src->readonly) {
E
Eric Blake 已提交
3797
                    medium->vtbl->SetType(medium, MediumType_Normal);
3798
                    VIR_DEBUG("setting harddisk type to normal");
3799
                }
E
Eric Blake 已提交
3800
            }
3801

E
Eric Blake 已提交
3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814
            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;
            }
3815

E
Eric Blake 已提交
3816 3817 3818 3819 3820 3821 3822 3823
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
3824
                virReportError(VIR_ERR_INTERNAL_ERROR,
3825 3826 3827
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
3828
                               src, (unsigned)rc);
3829 3830 3831
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
3832 3833 3834 3835 3836 3837 3838 3839 3840
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
3841
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3842
                                             mediumUUID);
3843
# else /* VBOX_API_VERSION >= 4000000 */
3844
                                             medium);
3845
# endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
3846 3847

            if (NS_FAILED(rc)) {
3848
                virReportError(VIR_ERR_INTERNAL_ERROR,
3849 3850
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
3851
                               src, (unsigned)rc);
E
Eric Blake 已提交
3852 3853
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
3854
            }
E
Eric Blake 已提交
3855 3856 3857 3858 3859

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
3860 3861
        }
    }
3862
#endif /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
3863
}
3864

E
Eric Blake 已提交
3865 3866 3867 3868
static void
vboxAttachSound(virDomainDefPtr def, IMachine *machine)
{
    nsresult rc;
3869

E
Eric Blake 已提交
3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885
    /* 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);
3886
                }
3887
            }
E
Eric Blake 已提交
3888
            VBOX_RELEASE(audioAdapter);
3889
        }
E
Eric Blake 已提交
3890 3891 3892 3893 3894 3895 3896
    }
}

static void
vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
3897
#if VBOX_API_VERSION >= 4001000
3898
    PRUint32 chipsetType                = ChipsetType_Null;
3899
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
3900
    PRUint32 networkAdapterCount        = 0;
3901
    size_t i = 0;
E
Eric Blake 已提交
3902

3903
#if VBOX_API_VERSION >= 4001000
3904
    machine->vtbl->GetChipsetType(machine, &chipsetType);
3905
#endif /* VBOX_API_VERSION >= 4001000 */
3906

E
Eric Blake 已提交
3907 3908
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
3909
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
3910 3911
        systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                       &networkAdapterCount);
3912
#else  /* VBOX_API_VERSION >= 4000000 */
3913 3914
        systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
                                                      &networkAdapterCount);
3915
#endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
3916 3917 3918 3919
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }

3920
    VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
3921
    VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
E
Eric Blake 已提交
3922 3923 3924 3925 3926 3927 3928

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

3929
        virMacAddrFormat(&def->nets[i]->mac, macaddr);
E
Eric Blake 已提交
3930 3931
        snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                 "%02X%02X%02X%02X%02X%02X",
3932 3933 3934 3935 3936 3937
                 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 已提交
3938 3939
        macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

3940 3941 3942 3943
        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 已提交
3944
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
3945
            VIR_DEBUG("NIC(%zu): name:    %s", i, def->nets[i]->data.network.name);
E
Eric Blake 已提交
3946
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
3947
            VIR_DEBUG("NIC(%zu): name:   %s", i, def->nets[i]->data.internal.name);
E
Eric Blake 已提交
3948
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
3949
            VIR_DEBUG("NIC(%zu): NAT.", i);
E
Eric Blake 已提交
3950
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
3951 3952 3953
            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);
3954 3955
        }

E
Eric Blake 已提交
3956 3957 3958 3959 3960
        machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
        if (adapter) {
            PRUnichar *MACAddress = NULL;

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

E
Eric Blake 已提交
3962
            if (def->nets[i]->model) {
E
Eric Blake 已提交
3963
                if (STRCASEEQ(def->nets[i]->model, "Am79C970A")) {
E
Eric Blake 已提交
3964
                    adapterType = NetworkAdapterType_Am79C970A;
E
Eric Blake 已提交
3965
                } else if (STRCASEEQ(def->nets[i]->model, "Am79C973")) {
E
Eric Blake 已提交
3966
                    adapterType = NetworkAdapterType_Am79C973;
E
Eric Blake 已提交
3967
                } else if (STRCASEEQ(def->nets[i]->model, "82540EM")) {
E
Eric Blake 已提交
3968
                    adapterType = NetworkAdapterType_I82540EM;
E
Eric Blake 已提交
3969
                } else if (STRCASEEQ(def->nets[i]->model, "82545EM")) {
E
Eric Blake 已提交
3970
                    adapterType = NetworkAdapterType_I82545EM;
E
Eric Blake 已提交
3971
                } else if (STRCASEEQ(def->nets[i]->model, "82543GC")) {
E
Eric Blake 已提交
3972
                    adapterType = NetworkAdapterType_I82543GC;
3973
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
3974
                } else if (STRCASEEQ(def->nets[i]->model, "virtio")) {
E
Eric Blake 已提交
3975
                    adapterType = NetworkAdapterType_Virtio;
3976
#endif /* VBOX_API_VERSION >= 3001000 */
3977
                }
E
Eric Blake 已提交
3978 3979 3980
            } else {
                adapterType = NetworkAdapterType_Am79C973;
            }
3981

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

E
Eric Blake 已提交
3984 3985 3986
            if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                PRUnichar *hostInterface = NULL;
                /* Bridged Network */
3987

3988
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
3989
                adapter->vtbl->AttachToBridgedInterface(adapter);
3990
#else /* VBOX_API_VERSION >= 4001000 */
3991
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
3992
#endif /* VBOX_API_VERSION >= 4001000 */
3993

E
Eric Blake 已提交
3994 3995 3996
                if (def->nets[i]->data.bridge.brname) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
                                       &hostInterface);
3997
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
3998
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
3999
#else /* VBOX_API_VERSION >= 4001000 */
4000
                    adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
4001
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4002 4003 4004 4005 4006
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                PRUnichar *internalNetwork = NULL;
                /* Internal Network */
4007

4008
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4009
                adapter->vtbl->AttachToInternalNetwork(adapter);
4010
#else /* VBOX_API_VERSION >= 4001000 */
4011
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
4012
#endif /* VBOX_API_VERSION >= 4001000 */
4013

E
Eric Blake 已提交
4014 4015 4016 4017 4018
                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);
4019
                }
E
Eric Blake 已提交
4020 4021 4022 4023 4024 4025
            } 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)
                 */
4026
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4027
                adapter->vtbl->AttachToHostOnlyInterface(adapter);
4028
#else /* VBOX_API_VERSION >= 4001000 */
4029
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
4030
#endif /* VBOX_API_VERSION >= 4001000 */
4031

E
Eric Blake 已提交
4032 4033 4034
                if (def->nets[i]->data.network.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
                                       &hostInterface);
4035
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4036
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4037
#else /* VBOX_API_VERSION >= 4001000 */
4038
                    adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
4039
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4040 4041 4042 4043
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                /* NAT */
4044
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4045
                adapter->vtbl->AttachToNAT(adapter);
4046
#else /* VBOX_API_VERSION >= 4001000 */
4047
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4048
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4049 4050 4051 4052
            } else {
                /* else always default to NAT if we don't understand
                 * what option is been passed to us
                 */
4053
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4054
                adapter->vtbl->AttachToNAT(adapter);
4055
#else /* VBOX_API_VERSION >= 4001000 */
4056
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4057
#endif /* VBOX_API_VERSION >= 4001000 */
4058
            }
E
Eric Blake 已提交
4059 4060 4061 4062

            VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
            adapter->vtbl->SetMACAddress(adapter, MACAddress);
            VBOX_UTF16_FREE(MACAddress);
4063
        }
E
Eric Blake 已提交
4064 4065 4066 4067 4068 4069 4070 4071
    }
}

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

E
Eric Blake 已提交
4074 4075 4076 4077 4078 4079 4080
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetSerialPortCount(systemProperties,
                                                   &serialPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4081

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

4087 4088
        VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source.type);
        VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4089
              def->serials[i]->target.port);
4090

E
Eric Blake 已提交
4091 4092 4093
        machine->vtbl->GetSerialPort(machine, i, &serialPort);
        if (serialPort) {
            PRUnichar *pathUtf16 = NULL;
4094

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

4097 4098 4099
            if (def->serials[i]->source.data.file.path) {
                VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
                                   &pathUtf16);
E
Eric Blake 已提交
4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114
                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);
4115
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4116
                      i, 4, 1016, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4117 4118 4119
            } else if (def->serials[i]->target.port == 1) {
                serialPort->vtbl->SetIRQ(serialPort, 3);
                serialPort->vtbl->SetIOBase(serialPort, 760);
4120
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4121
                      i, 3, 760, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4122
            }
4123

4124
            if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
E
Eric Blake 已提交
4125
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4126
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
E
Eric Blake 已提交
4127
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4128
#if VBOX_API_VERSION >= 3000000
4129
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
E
Eric Blake 已提交
4130
                serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4131
#endif /* VBOX_API_VERSION >= 3000000 */
E
Eric Blake 已提交
4132 4133 4134 4135
            } else {
                serialPort->vtbl->SetHostMode(serialPort,
                                              PortMode_Disconnected);
            }
4136

E
Eric Blake 已提交
4137
            VBOX_RELEASE(serialPort);
J
John Ferlan 已提交
4138
            VBOX_UTF16_FREE(pathUtf16);
4139
        }
E
Eric Blake 已提交
4140 4141
    }
}
4142

E
Eric Blake 已提交
4143 4144 4145 4146 4147
static void
vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 parallelPortCount          = 0;
4148
    size_t i = 0;
4149

E
Eric Blake 已提交
4150 4151 4152 4153 4154 4155 4156
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetParallelPortCount(systemProperties,
                                                     &parallelPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4157

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

4163 4164
        VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source.type);
        VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4165
              def->parallels[i]->target.port);
4166

E
Eric Blake 已提交
4167 4168 4169
        machine->vtbl->GetParallelPort(machine, i, &parallelPort);
        if (parallelPort) {
            PRUnichar *pathUtf16 = NULL;
4170

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

E
Eric Blake 已提交
4173 4174 4175 4176 4177
            /* 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
             */
4178 4179 4180 4181
            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 已提交
4182 4183 4184 4185
                parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                if (i == 0) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 7);
                    parallelPort->vtbl->SetIOBase(parallelPort, 888);
4186
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4187
                          i, 7, 888, def->parallels[i]->source.data.file.path);
E
Eric Blake 已提交
4188 4189 4190
                } else if (i == 1) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 5);
                    parallelPort->vtbl->SetIOBase(parallelPort, 632);
4191
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4192
                          i, 5, 632, def->parallels[i]->source.data.file.path);
4193 4194
                }
            }
E
Eric Blake 已提交
4195 4196 4197 4198 4199 4200 4201

            /* 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 已提交
4202
            VBOX_UTF16_FREE(pathUtf16);
4203
        }
E
Eric Blake 已提交
4204 4205 4206 4207 4208 4209 4210 4211
    }
}

static void
vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
{
    if ((def->nvideos == 1) &&
        (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4212 4213
        machine->vtbl->SetVRAMSize(machine,
                                   VIR_DIV_UP(def->videos[0]->vram, 1024));
E
Eric Blake 已提交
4214 4215 4216 4217
        machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
        if (def->videos[0]->accel) {
            machine->vtbl->SetAccelerate3DEnabled(machine,
                                                  def->videos[0]->accel->support3d);
4218
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4219 4220
            machine->vtbl->SetAccelerate2DVideoEnabled(machine,
                                                       def->videos[0]->accel->support2d);
4221
#endif /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
4222 4223
        } else {
            machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4224
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4225
            machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4226
#endif /* VBOX_API_VERSION >= 3001000 */
4227
        }
E
Eric Blake 已提交
4228 4229
    }
}
4230

E
Eric Blake 已提交
4231 4232 4233 4234 4235 4236 4237 4238
static void
vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int vrdpPresent  = 0;
    int sdlPresent   = 0;
    int guiPresent   = 0;
    char *guiDisplay = NULL;
    char *sdlDisplay = NULL;
4239
    size_t i = 0;
4240

E
Eric Blake 已提交
4241
    for (i = 0; i < def->ngraphics; i++) {
4242
#if VBOX_API_VERSION < 4000000
4243
        IVRDPServer *VRDxServer = NULL;
4244
#else /* VBOX_API_VERSION >= 4000000 */
4245
        IVRDEServer *VRDxServer = NULL;
4246
#endif /* VBOX_API_VERSION >= 4000000 */
4247

E
Eric Blake 已提交
4248 4249
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
            (vrdpPresent == 0)) {
4250

E
Eric Blake 已提交
4251
            vrdpPresent = 1;
4252
#if VBOX_API_VERSION < 4000000
4253
            machine->vtbl->GetVRDPServer(machine, &VRDxServer);
4254
#else /* VBOX_API_VERSION >= 4000000 */
4255
            machine->vtbl->GetVRDEServer(machine, &VRDxServer);
4256
#endif /* VBOX_API_VERSION >= 4000000 */
4257
            if (VRDxServer) {
4258 4259 4260
                const char *listenAddr
                    = virDomainGraphicsListenGetAddress(def->graphics[i], 0);

4261
                VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4262
                VIR_DEBUG("VRDP Support turned ON.");
4263

4264
#if VBOX_API_VERSION < 3001000
E
Eric Blake 已提交
4265
                if (def->graphics[i]->data.rdp.port) {
4266
                    VRDxServer->vtbl->SetPort(VRDxServer,
E
Eric Blake 已提交
4267
                                              def->graphics[i]->data.rdp.port);
4268
                    VIR_DEBUG("VRDP Port changed to: %d",
E
Eric Blake 已提交
4269 4270 4271 4272 4273
                          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
                     */
4274
                    VRDxServer->vtbl->SetPort(VRDxServer, 0);
4275
                    VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
E
Eric Blake 已提交
4276
                }
4277
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
E
Eric Blake 已提交
4278 4279
                PRUnichar *portUtf16 = NULL;
                portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4280
                VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
E
Eric Blake 已提交
4281
                VBOX_UTF16_FREE(portUtf16);
4282
#else /* VBOX_API_VERSION >= 4000000 */
4283 4284 4285 4286 4287 4288 4289 4290
                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);
4291
#endif /* VBOX_API_VERSION >= 4000000 */
4292

E
Eric Blake 已提交
4293
                if (def->graphics[i]->data.rdp.replaceUser) {
4294
                    VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
E
Eric Blake 已提交
4295
                                                               PR_TRUE);
4296
                    VIR_DEBUG("VRDP set to reuse single connection");
E
Eric Blake 已提交
4297
                }
4298

E
Eric Blake 已提交
4299
                if (def->graphics[i]->data.rdp.multiUser) {
4300
                    VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
E
Eric Blake 已提交
4301
                                                              PR_TRUE);
4302
                    VIR_DEBUG("VRDP set to allow multiple connection");
E
Eric Blake 已提交
4303
                }
4304

4305
                if (listenAddr) {
4306
#if VBOX_API_VERSION >= 4000000
4307 4308
                    PRUnichar *netAddressKey = NULL;
#endif
E
Eric Blake 已提交
4309
                    PRUnichar *netAddressUtf16 = NULL;
4310

4311
                    VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4312
#if VBOX_API_VERSION < 4000000
4313
                    VRDxServer->vtbl->SetNetAddress(VRDxServer,
E
Eric Blake 已提交
4314
                                                    netAddressUtf16);
4315
#else /* VBOX_API_VERSION >= 4000000 */
4316 4317 4318 4319
                    VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
                    VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
                                                      netAddressUtf16);
                    VBOX_UTF16_FREE(netAddressKey);
4320
#endif /* VBOX_API_VERSION >= 4000000 */
4321
                    VIR_DEBUG("VRDP listen address is set to: %s",
4322
                              listenAddr);
4323

E
Eric Blake 已提交
4324
                    VBOX_UTF16_FREE(netAddressUtf16);
4325
                }
E
Eric Blake 已提交
4326

4327
                VBOX_RELEASE(VRDxServer);
4328
            }
E
Eric Blake 已提交
4329
        }
4330

E
Eric Blake 已提交
4331 4332 4333
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
            (guiPresent == 0)) {
            guiPresent = 1;
4334 4335 4336 4337 4338
            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
                 */
4339
            }
E
Eric Blake 已提交
4340
        }
4341

E
Eric Blake 已提交
4342 4343 4344
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
            (sdlPresent == 0)) {
            sdlPresent = 1;
4345 4346 4347 4348 4349
            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
                 */
4350
            }
4351
        }
E
Eric Blake 已提交
4352
    }
4353

E
Eric Blake 已提交
4354 4355 4356 4357
    if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
        /* store extradata key that frontend is set to vrdp */
        PRUnichar *keyTypeUtf16   = NULL;
        PRUnichar *valueTypeUtf16 = NULL;
4358

E
Eric Blake 已提交
4359 4360
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4361

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

E
Eric Blake 已提交
4364 4365
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4366

E
Eric Blake 已提交
4367 4368 4369 4370 4371 4372
    } 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;
4373

E
Eric Blake 已提交
4374 4375
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4376

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

E
Eric Blake 已提交
4379 4380
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4381

E
Eric Blake 已提交
4382 4383 4384
        if (sdlDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4385

E
Eric Blake 已提交
4386 4387
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4388

E
Eric Blake 已提交
4389 4390 4391
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
        }
4392

E
Eric Blake 已提交
4393 4394 4395 4396 4397 4398
    } 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;
4399

E
Eric Blake 已提交
4400 4401
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
4402

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

E
Eric Blake 已提交
4405 4406
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4407

E
Eric Blake 已提交
4408 4409 4410
        if (guiDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4411

E
Eric Blake 已提交
4412 4413
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4414

E
Eric Blake 已提交
4415 4416
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
4417
        }
E
Eric Blake 已提交
4418
    }
4419

E
Eric Blake 已提交
4420 4421 4422
    VIR_FREE(guiDisplay);
    VIR_FREE(sdlDisplay);
}
4423

E
Eric Blake 已提交
4424 4425 4426
static void
vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
4427
#if VBOX_API_VERSION < 4003000
E
Eric Blake 已提交
4428
    IUSBController *USBController = NULL;
R
Ryota Ozaki 已提交
4429 4430 4431
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
4432
    size_t i = 0;
E
Eric Blake 已提交
4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443
    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 已提交
4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459
        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 已提交
4460 4461
    }

R
Ryota Ozaki 已提交
4462 4463 4464
    if (!isUSB)
        return;

4465
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4466 4467 4468 4469 4470 4471 4472 4473 4474
    /* 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);
4475
# if VBOX_API_VERSION < 4002000
R
Ryota Ozaki 已提交
4476
    USBController->vtbl->SetEnabledEhci(USBController, 1);
R
Ryota Ozaki 已提交
4477
# else
R
Ryota Ozaki 已提交
4478
    USBController->vtbl->SetEnabledEHCI(USBController, 1);
R
Ryota Ozaki 已提交
4479 4480 4481 4482 4483 4484
# endif
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;
4485
#endif
4486

R
Ryota Ozaki 已提交
4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497
    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;
4498

R
Ryota Ozaki 已提交
4499 4500 4501
        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;
4502

R
Ryota Ozaki 已提交
4503 4504 4505 4506 4507 4508
        /* 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);
4509
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4510 4511 4512
            USBController->vtbl->CreateDeviceFilter(USBController,
                                                    filternameUtf16,
                                                    &filter);
R
Ryota Ozaki 已提交
4513 4514 4515 4516 4517
#else
            USBDeviceFilters->vtbl->CreateDeviceFilter(USBDeviceFilters,
                                                       filternameUtf16,
                                                       &filter);
#endif
R
Ryota Ozaki 已提交
4518 4519
        }
        VBOX_UTF16_FREE(filternameUtf16);
E
Eric Blake 已提交
4520

R
Ryota Ozaki 已提交
4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541
        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 已提交
4542
        }
R
Ryota Ozaki 已提交
4543
        filter->vtbl->SetActive(filter, 1);
4544
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4545 4546 4547
        USBController->vtbl->InsertDeviceFilter(USBController,
                                                i,
                                                filter);
R
Ryota Ozaki 已提交
4548 4549 4550 4551 4552
#else
        USBDeviceFilters->vtbl->InsertDeviceFilter(USBDeviceFilters,
                                                   i,
                                                   filter);
#endif
R
Ryota Ozaki 已提交
4553
        VBOX_RELEASE(filter);
E
Eric Blake 已提交
4554
    }
R
Ryota Ozaki 已提交
4555

4556
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4557
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
4558 4559 4560
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
E
Eric Blake 已提交
4561 4562
}

M
Matthias Bolte 已提交
4563 4564 4565
static void
vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
4566
    size_t i;
M
Matthias Bolte 已提交
4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581
    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;

4582
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
4583 4584
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable);
4585
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
4586 4587
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable, PR_FALSE);
4588
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
4589 4590 4591 4592 4593 4594

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

4595 4596
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml)
{
E
Eric Blake 已提交
4597 4598 4599
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
4600 4601
    vboxIID iid = VBOX_IID_INITIALIZER;
    vboxIID mchiid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
4602 4603
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;
4604
#if VBOX_API_VERSION >= 3002000 && VBOX_API_VERSION < 4002000
E
Eric Blake 已提交
4605 4606 4607
    PRBool override             = PR_FALSE;
#endif
    nsresult rc;
4608
    char uuidstr[VIR_UUID_STRING_BUFLEN];
4609
#if VBOX_API_VERSION >= 4002000
4610 4611 4612 4613 4614 4615
    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 已提交
4616

4617 4618
    if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_VBOX,
E
Eric Blake 已提交
4619 4620 4621 4622 4623
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
4624
    vboxIIDFromUUID(&iid, def->uuid);
4625 4626
    virUUIDFormat(def->uuid, uuidstr);

4627
#if VBOX_API_VERSION < 3002000
E
Eric Blake 已提交
4628 4629 4630 4631
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
4632
                                            iid.value,
E
Eric Blake 已提交
4633
                                            &machine);
4634
#elif VBOX_API_VERSION < 4000000 /* 3002000 <= VBOX_API_VERSION < 4000000 */
E
Eric Blake 已提交
4635 4636 4637 4638
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
4639
                                            iid.value,
E
Eric Blake 已提交
4640 4641
                                            override,
                                            &machine);
4642
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
4643 4644 4645 4646 4647 4648 4649
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            NULL,
                                            iid.value,
                                            override,
                                            &machine);
4650
#else /* VBOX_API_VERSION >= 4002000 */
4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665
    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);
4666
#endif /* VBOX_API_VERSION >= 4002000 */
E
Eric Blake 已提交
4667 4668 4669
    VBOX_UTF16_FREE(machineNameUtf16);

    if (NS_FAILED(rc)) {
4670 4671
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
4672 4673 4674
        goto cleanup;
    }

4675 4676
    rc = machine->vtbl->SetMemorySize(machine,
                                      VIR_DIV_UP(def->mem.cur_balloon, 1024));
E
Eric Blake 已提交
4677
    if (NS_FAILED(rc)) {
4678 4679 4680 4681
        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 已提交
4682 4683
    }

E
Eric Blake 已提交
4684
    if (def->vcpus != def->maxvcpus) {
4685 4686
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
4687 4688
    }
    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
E
Eric Blake 已提交
4689
    if (NS_FAILED(rc)) {
4690 4691 4692
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the number of virtual CPUs to: %u, rc=%08x"),
                       def->maxvcpus, (unsigned)rc);
E
Eric Blake 已提交
4693 4694
    }

4695
#if VBOX_API_VERSION < 3001000
4696 4697
    rc = machine->vtbl->SetPAEEnabled(machine,
                                      def->features[VIR_DOMAIN_FEATURE_PAE] ==
J
Ján Tomko 已提交
4698
                                      VIR_TRISTATE_SWITCH_ON);
4699
#elif VBOX_API_VERSION == 3001000
E
Eric Blake 已提交
4700
    rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
4701
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
J
Ján Tomko 已提交
4702
                                       VIR_TRISTATE_SWITCH_ON);
4703
#elif VBOX_API_VERSION >= 3002000
E
Eric Blake 已提交
4704
    rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
4705
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
J
Ján Tomko 已提交
4706
                                       VIR_TRISTATE_SWITCH_ON);
E
Eric Blake 已提交
4707 4708
#endif
    if (NS_FAILED(rc)) {
4709 4710
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not change PAE status to: %s, rc=%08x"),
J
Ján Tomko 已提交
4711
                       (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_TRISTATE_SWITCH_ON)
4712
                       ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
4713 4714 4715 4716
    }

    machine->vtbl->GetBIOSSettings(machine, &bios);
    if (bios) {
4717 4718
        rc = bios->vtbl->SetACPIEnabled(bios,
                                        def->features[VIR_DOMAIN_FEATURE_ACPI] ==
J
Ján Tomko 已提交
4719
                                        VIR_TRISTATE_SWITCH_ON);
E
Eric Blake 已提交
4720
        if (NS_FAILED(rc)) {
4721 4722
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change ACPI status to: %s, rc=%08x"),
J
Ján Tomko 已提交
4723
                           (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_TRISTATE_SWITCH_ON)
4724
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
4725
        }
4726 4727
        rc = bios->vtbl->SetIOAPICEnabled(bios,
                                          def->features[VIR_DOMAIN_FEATURE_APIC] ==
J
Ján Tomko 已提交
4728
                                          VIR_TRISTATE_SWITCH_ON);
E
Eric Blake 已提交
4729
        if (NS_FAILED(rc)) {
4730 4731
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change APIC status to: %s, rc=%08x"),
J
Ján Tomko 已提交
4732
                           (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_TRISTATE_SWITCH_ON)
4733
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
4734
        }
E
Eric Blake 已提交
4735 4736 4737 4738 4739 4740
        VBOX_RELEASE(bios);
    }

    /* Register the machine before attaching other devices to it */
    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
4741 4742
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
4743 4744 4745 4746 4747 4748 4749
        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
     */
4750
    machine->vtbl->GetId(machine, &mchiid.value);
4751
    VBOX_SESSION_OPEN(mchiid.value, machine);
E
Eric Blake 已提交
4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762
    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 已提交
4763
    vboxAttachSharedFolder(def, data, machine);
4764

4765 4766 4767 4768
    /* Save the machine settings made till now and close the
     * session. also free up the mchiid variable used.
     */
    rc = machine->vtbl->SaveSettings(machine);
4769
    VBOX_SESSION_CLOSE();
4770
    vboxIIDUnalloc(&mchiid);
4771

4772 4773
    ret = virGetDomain(conn, def->name, def->uuid);
    VBOX_RELEASE(machine);
4774

4775
    vboxIIDUnalloc(&iid);
4776 4777
    virDomainDefFree(def);

4778
    return ret;
4779

4780
 cleanup:
4781
    VBOX_RELEASE(machine);
4782
    vboxIIDUnalloc(&iid);
4783 4784 4785 4786
    virDomainDefFree(def);
    return NULL;
}

4787
static int
4788
vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
4789
{
4790
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
4791
    IMachine *machine    = NULL;
4792
    vboxIID iid = VBOX_IID_INITIALIZER;
4793
    nsresult rc;
4794
#if VBOX_API_VERSION >= 4000000
4795 4796
    vboxArray media = VBOX_ARRAY_INITIALIZER;
#endif
4797 4798 4799 4800
    /* 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);
4801

4802
    vboxIIDFromUUID(&iid, dom->uuid);
4803

4804
#if VBOX_API_VERSION < 4000000
4805 4806 4807
    /* 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
4808 4809 4810 4811
     * 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.
4812 4813 4814
     */
    {
        PRUnichar *hddcnameUtf16 = NULL;
4815

4816 4817
        char *hddcname;
        ignore_value(VIR_STRDUP(hddcname, "IDE"));
4818 4819
        VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
        VIR_FREE(hddcname);
4820

4821
        /* Open a Session for the machine */
4822
        rc = VBOX_SESSION_OPEN(iid.value, machine);
4823 4824 4825 4826
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {

4827
# if VBOX_API_VERSION < 3001000
4828 4829 4830 4831
                /* 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);
4832
# else  /* VBOX_API_VERSION >= 3001000 */
4833 4834 4835
                /* get all the controller first, then the attachments and
                 * remove them all so that the machine can be undefined
                 */
4836
                vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
4837
                size_t i = 0, j = 0;
4838

4839 4840
                vboxArrayGet(&storageControllers, machine,
                             machine->vtbl->GetStorageControllers);
4841

4842 4843
                for (i = 0; i < storageControllers.count; i++) {
                    IStorageController *strCtl = storageControllers.items[i];
4844
                    PRUnichar *strCtlName = NULL;
4845
                    vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
4846 4847 4848 4849 4850

                    if (!strCtl)
                        continue;

                    strCtl->vtbl->GetName(strCtl, &strCtlName);
4851 4852 4853
                    vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                                           machine->vtbl->GetMediumAttachmentsOfController,
                                           strCtlName);
4854

4855 4856
                    for (j = 0; j < mediumAttachments.count; j++) {
                        IMediumAttachment *medAtt = mediumAttachments.items[j];
4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872
                        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);
                        }
                    }
4873

4874 4875
                    vboxArrayRelease(&storageControllers);

4876 4877
                    machine->vtbl->RemoveStorageController(machine, strCtlName);
                    VBOX_UTF16_FREE(strCtlName);
4878
                }
4879 4880

                vboxArrayRelease(&storageControllers);
4881
# endif /* VBOX_API_VERSION >= 3001000 */
4882 4883

                machine->vtbl->SaveSettings(machine);
4884
            }
4885
            VBOX_SESSION_CLOSE();
4886
        }
4887 4888
        VBOX_UTF16_FREE(hddcnameUtf16);
    }
4889
#endif
4890

4891
#if VBOX_API_VERSION < 4000000
4892
    rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
4893
#else /* VBOX_API_VERSION >= 4000000 */
4894 4895
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
4896 4897
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
4898 4899 4900 4901 4902 4903 4904 4905 4906
        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);
4907
#endif /* VBOX_API_VERSION >= 4000000 */
4908
    DEBUGIID("UUID of machine being undefined", iid.value);
4909

4910
    if (NS_SUCCEEDED(rc)) {
4911
#if VBOX_API_VERSION < 4000000
4912
        machine->vtbl->DeleteSettings(machine);
4913
#else /* VBOX_API_VERSION >= 4000000 */
4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926
        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);

4927
#  if VBOX_API_VERSION < 4003000
4928
        ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
R
Ryota Ozaki 已提交
4929 4930 4931
#  else
        ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
#  endif
4932
# else
4933 4934 4935
        /* 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 };
4936
#  if VBOX_API_VERSION < 4003000
4937
        machine->vtbl->Delete(machine, 0, array, &progress);
R
Ryota Ozaki 已提交
4938 4939 4940
#  else
        machine->vtbl->DeleteConfig(machine, 0, array, &progress);
#  endif
4941 4942 4943 4944 4945
# endif
        if (progress != NULL) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
4946
#endif /* VBOX_API_VERSION >= 4000000 */
4947 4948
        ret = 0;
    } else {
4949 4950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not delete the domain, rc=%08x"), (unsigned)rc);
4951 4952
    }

4953
#if VBOX_API_VERSION >= 4000000
4954 4955
    vboxArrayUnalloc(&media);
#endif
4956
    vboxIIDUnalloc(&iid);
4957
    VBOX_RELEASE(machine);
4958 4959 4960 4961

    return ret;
}

4962 4963 4964 4965 4966 4967
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

4968 4969
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
4970 4971
                                      int mediaChangeOnly ATTRIBUTE_UNUSED)
{
4972
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
4973
    IMachine *machine    = NULL;
4974
    vboxIID iid = VBOX_IID_INITIALIZER;
4975 4976 4977
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
4978
    nsresult rc;
4979

4980
    if (VIR_ALLOC(def) < 0)
4981 4982
        return ret;

4983
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
4984 4985
        goto cleanup;

4986 4987
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
4988
    if (dev == NULL)
4989 4990
        goto cleanup;

4991
    vboxIIDFromUUID(&iid, dom->uuid);
4992
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
4993
    if (NS_FAILED(rc)) {
4994 4995
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
4996 4997
        goto cleanup;
    }
4998

4999 5000
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5001

5002 5003
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5004
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5005
        } else {
5006
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5007 5008 5009 5010 5011
        }
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5012
#if VBOX_API_VERSION < 3001000
5013 5014 5015
                    const char *src = virDomainDiskGetSource(dev->data.disk);
                    int type = virDomainDiskGetType(dev->data.disk);

5016
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
5017
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
5018 5019 5020 5021 5022 5023 5024 5025 5026
                            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;
5027 5028
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5029

5030
                                VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
5031

5032 5033
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
5034
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5035 5036
                                }
                                if (dvdImage) {
5037
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5038
                                    if (NS_FAILED(rc)) {
5039 5040 5041
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
5042
                                                       src, (unsigned)rc);
5043 5044 5045
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
5046
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5047
                                        if (NS_FAILED(rc)) {
5048 5049
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
5050
                                                           src, (unsigned)rc);
5051
                                        } else {
5052
                                            ret = 0;
5053
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5054 5055
                                        }
                                    }
5056 5057

                                    VBOX_MEDIUM_RELEASE(dvdImage);
5058
                                }
5059
                                vboxIIDUnalloc(&dvduuid);
5060 5061
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
5062
                            }
E
Eric Blake 已提交
5063
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5064 5065
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
5066
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
5067 5068 5069 5070 5071 5072 5073
                            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;
5074 5075
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5076
                                    VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
5077 5078 5079 5080 5081 5082 5083
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
5084
                                                                             fdemptyuuid.value,
5085 5086
                                                                             &floppyImage);
                                    }
5087

5088
                                    if (floppyImage) {
5089
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5090
                                        if (NS_FAILED(rc)) {
5091 5092 5093
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
5094
                                                           src, (unsigned)rc);
5095
                                        } else {
5096
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5097
                                            if (NS_FAILED(rc)) {
5098 5099
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
5100
                                                               src, (unsigned)rc);
5101
                                            } else {
5102
                                                ret = 0;
5103
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
5104 5105
                                            }
                                        }
5106
                                        VBOX_MEDIUM_RELEASE(floppyImage);
5107
                                    }
5108
                                    vboxIIDUnalloc(&fduuid);
5109
                                    VBOX_UTF16_FREE(fdfileUtf16);
5110
                                }
5111
                                VBOX_RELEASE(floppyDrive);
5112
                            }
E
Eric Blake 已提交
5113
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5114
                        }
5115
                    }
5116 5117
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5118 5119 5120 5121
                } 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) {
5122 5123
                        }
                    }
M
Matthias Bolte 已提交
5124 5125 5126 5127 5128 5129 5130 5131 5132 5133
                } 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;

5134
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
5135 5136
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable);
5137
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5138 5139
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable, PR_FALSE);
5140
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5141 5142

                    if (NS_FAILED(rc)) {
5143 5144 5145
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5146 5147 5148 5149 5150 5151
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
5152
                }
5153 5154
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5155
            }
5156
            VBOX_SESSION_CLOSE();
5157 5158 5159
        }
    }

5160
 cleanup:
5161
    vboxIIDUnalloc(&iid);
5162 5163 5164 5165 5166
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5167 5168
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
{
5169 5170 5171
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

5172 5173 5174 5175 5176 5177
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5178
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5179 5180
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5181 5182 5183
        return -1;
    }

5184 5185 5186 5187
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
5188 5189
                                       unsigned int flags)
{
5190 5191 5192
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5193

5194
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5195 5196
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5197 5198 5199 5200
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5201 5202
}

5203 5204
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
{
5205
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5206
    IMachine *machine    = NULL;
5207
    vboxIID iid = VBOX_IID_INITIALIZER;
5208 5209 5210
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5211
    nsresult rc;
5212

5213
    if (VIR_ALLOC(def) < 0)
5214 5215
        return ret;

5216
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5217 5218
        goto cleanup;

5219 5220
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5221
    if (dev == NULL)
5222 5223
        goto cleanup;

5224
    vboxIIDFromUUID(&iid, dom->uuid);
5225
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5226
    if (NS_FAILED(rc)) {
5227 5228
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5229 5230
        goto cleanup;
    }
5231

5232 5233
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5234

5235 5236
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5237
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5238
        } else {
5239
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5240
        }
5241

5242 5243 5244 5245
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5246
#if VBOX_API_VERSION < 3001000
5247 5248
                    int type = virDomainDiskGetType(dev->data.disk);

5249
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
5250
                        if (type == VIR_STORAGE_TYPE_FILE) {
5251 5252 5253 5254 5255 5256 5257 5258 5259
                            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)) {
5260 5261 5262
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5263 5264 5265 5266 5267
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
E
Eric Blake 已提交
5268
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5269 5270
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
5271
                        if (type == VIR_STORAGE_TYPE_FILE) {
5272 5273 5274 5275 5276 5277 5278 5279
                            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);
5280
                                    if (NS_FAILED(rc)) {
5281 5282 5283 5284
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5285 5286 5287
                                    } else {
                                        ret = 0;
                                    }
5288 5289 5290 5291 5292
                                } 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;
5293
                                }
5294
                                VBOX_RELEASE(floppyDrive);
5295
                            }
E
Eric Blake 已提交
5296
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5297
                        }
5298
                    }
5299 5300
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5301 5302 5303 5304
                } 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) {
5305 5306
                        }
                    }
M
Matthias Bolte 已提交
5307 5308 5309 5310 5311 5312 5313 5314 5315
                } 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)) {
5316 5317 5318
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5319 5320 5321 5322 5323
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5324
                }
5325 5326
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5327
            }
5328
            VBOX_SESSION_CLOSE();
5329 5330 5331
        }
    }

5332
 cleanup:
5333
    vboxIIDUnalloc(&iid);
5334 5335 5336 5337 5338
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5339 5340 5341 5342 5343 5344
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5345
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5346 5347
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5348 5349 5350 5351 5352 5353
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5354 5355 5356 5357 5358
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5359
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5360 5361 5362 5363 5364 5365 5366 5367
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5368 5369 5370
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5371 5372 5373 5374 5375 5376
        goto error;
    }

    if (count == 0)
        goto out;

5377
    if (VIR_ALLOC_N(list, count) < 0)
J
Jiri Denemark 已提交
5378 5379
        goto error;

5380
#if VBOX_API_VERSION < 4000000
5381
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5382
#else /* VBOX_API_VERSION >= 4000000 */
5383
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
5384
#endif /* VBOX_API_VERSION >= 4000000 */
J
Jiri Denemark 已提交
5385
    if (NS_FAILED(rc) || !list[0]) {
5386 5387 5388
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5389 5390 5391 5392 5393 5394
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5395
        vboxArray children = VBOX_ARRAY_INITIALIZER;
5396
        size_t i;
J
Jiri Denemark 已提交
5397 5398

        if (!list[next]) {
5399 5400
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5401 5402 5403
            goto error;
        }

5404 5405
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5406
        if (NS_FAILED(rc)) {
5407 5408
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5409 5410
            goto error;
        }
5411 5412 5413
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5414 5415
                continue;
            if (top == count) {
5416 5417
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5418
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5419 5420
                goto error;
            }
5421 5422
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5423
        }
5424
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5425 5426
    }

5427
 out:
J
Jiri Denemark 已提交
5428 5429 5430
    *snapshots = list;
    return count;

5431
 error:
J
Jiri Denemark 已提交
5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450
    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;
5451
    size_t i;
J
Jiri Denemark 已提交
5452 5453 5454 5455 5456 5457 5458 5459 5460 5461

    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) {
5462 5463
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476
            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) {
5477 5478 5479
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
5480 5481 5482
        goto cleanup;
    }

5483
 cleanup:
J
Jiri Denemark 已提交
5484 5485 5486 5487 5488 5489 5490 5491 5492 5493
    if (count > 0) {
        for (i = 0; i < count; i++) {
            if (snapshots[i] != snapshot)
                VBOX_RELEASE(snapshots[i]);
        }
    }
    VIR_FREE(snapshots);
    return snapshot;
}

5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 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
#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]);
5745 5746 5747 5748 5749
            if (parentUuid == NULL) {
                VIR_FREE(readWriteDisk);
                goto cleanup;
            }

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 5961 5962 5963 5964 5965 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
            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 已提交
6451 6452 6453
static virDomainSnapshotPtr
vboxDomainSnapshotCreateXML(virDomainPtr dom,
                            const char *xmlDesc,
6454
                            unsigned int flags)
J
Jiri Denemark 已提交
6455 6456 6457
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
6458
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6459 6460 6461 6462 6463 6464 6465 6466
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
6467
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
6468 6469 6470 6471
    nsresult result;
#else
    PRInt32 result;
#endif
6472 6473 6474 6475
#if VBOX_API_VERSION >= 4002000
    bool isCurrent = false;
#endif

J
Jiri Denemark 已提交
6476

6477
    /* VBox has no snapshot metadata, so this flag is trivial.  */
6478 6479 6480
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
                  VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT, NULL);
6481

6482
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
6483 6484 6485
                                                data->xmlopt, -1,
                                                VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
                                                VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE)))
J
Jiri Denemark 已提交
6486 6487
        goto cleanup;

6488

6489
    vboxIIDFromUUID(&domiid, dom->uuid);
6490
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6491
    if (NS_FAILED(rc)) {
6492 6493
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6494 6495 6496
        goto cleanup;
    }

6497 6498 6499 6500 6501 6502 6503 6504 6505 6506
#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 已提交
6507 6508
    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6509 6510
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6511 6512 6513 6514 6515
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
6516
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
6517
    } else {
6518
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6519
    }
6520

J
Jiri Denemark 已提交
6521 6522 6523
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6524 6525 6526
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545
        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) {
6546 6547
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6548 6549 6550 6551 6552 6553
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6554 6555
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6556 6557 6558 6559 6560
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6561 6562
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
6563 6564 6565 6566 6567 6568
                  dom->name);
        goto cleanup;
    }

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

6569
 cleanup:
J
Jiri Denemark 已提交
6570 6571 6572 6573
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
6574
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6575
    VBOX_RELEASE(machine);
6576
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6577 6578 6579 6580
    virDomainSnapshotDefFree(def);
    return ret;
}

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
#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;
6653 6654 6655 6656
    for (i = 0; i < def->ndisks; i++) {
        if (VIR_ALLOC(def->disks[i].src) < 0)
            goto cleanup;
    }
6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754

    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",
6755
                                       _("cannot get medium attachment type"));
6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783
                        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) {
6784 6785 6786 6787 6788
        for (i = 0; i < def->ndisks; i++) {
            VIR_FREE(def->disks[i].src);
        }
        VIR_FREE(def->disks);
        def->ndisks = 0;
6789 6790 6791 6792 6793 6794 6795 6796 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
    }
    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++) {
6862 6863
            virDomainDiskDefPtr diskDef = virDomainDiskDefNew();
            if (!diskDef)
6864
                goto cleanup;
6865
            def->dom->disks[i] = diskDef;
6866 6867 6868 6869 6870 6871 6872 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 6971 6972 6973 6974 6975
        }
    } 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)
6976
            def->dom->disks[diskCount]->src->readonly = true;
6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999
        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++)
7000
            virDomainDiskDefFree(def->dom->disks[i]);
7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011
        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 已提交
7012
static char *
7013 7014
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
7015 7016 7017
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
7018
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7019 7020 7021 7022 7023 7024 7025 7026 7027 7028
    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];
7029 7030 7031 7032
#if VBOX_API_VERSION >=4002000
    PRUint32 memorySize                 = 0;
    PRUint32 CPUCount                 = 0;
#endif
J
Jiri Denemark 已提交
7033

7034 7035
    virCheckFlags(0, NULL);

7036
    vboxIIDFromUUID(&domiid, dom->uuid);
7037
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
7038
    if (NS_FAILED(rc)) {
7039 7040
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7041 7042 7043 7044 7045 7046
        goto cleanup;
    }

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

7047
    if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0)
7048
        goto cleanup;
7049 7050
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
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 7078 7079 7080 7081
#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 已提交
7082 7083
    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
7084 7085 7086
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7087 7088 7089 7090 7091
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
7092 7093 7094 7095
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
7096 7097 7098 7099 7100
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
7101 7102 7103
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7104 7105 7106 7107 7108 7109 7110
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
7111 7112 7113
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7114 7115 7116 7117 7118
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
7119 7120 7121
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
7122 7123 7124 7125
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
7126 7127
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
7128
            goto cleanup;
7129 7130
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
7131 7132 7133 7134
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
7135 7136 7137
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7138 7139 7140 7141 7142 7143 7144 7145
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

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

7149
 cleanup:
J
Jiri Denemark 已提交
7150 7151 7152 7153
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
7154
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7155 7156 7157 7158 7159
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
7160
                      unsigned int flags)
J
Jiri Denemark 已提交
7161 7162
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7163
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7164 7165 7166 7167
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

7168 7169
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
7170

7171
    vboxIIDFromUUID(&iid, dom->uuid);
7172
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7173
    if (NS_FAILED(rc)) {
7174 7175
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7176 7177 7178
        goto cleanup;
    }

7179 7180 7181 7182 7183 7184
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
7185 7186
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
7187 7188 7189
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7190 7191 7192
        goto cleanup;
    }

7193 7194 7195 7196 7197
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
7198

7199
 cleanup:
J
Jiri Denemark 已提交
7200
    VBOX_RELEASE(machine);
7201
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7202 7203 7204 7205 7206 7207 7208
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
7209
                            unsigned int flags)
J
Jiri Denemark 已提交
7210 7211
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7212
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7213 7214 7215 7216
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
7217
    size_t i;
J
Jiri Denemark 已提交
7218

7219 7220
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
7221

7222
    vboxIIDFromUUID(&iid, dom->uuid);
7223
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7224
    if (NS_FAILED(rc)) {
7225 7226
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7227 7228 7229
        goto cleanup;
    }

7230 7231 7232 7233 7234
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

7235 7236 7237
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

7238
        if (VIR_ALLOC_N(snapshots, 1) < 0)
7239
            goto cleanup;
7240
#if VBOX_API_VERSION < 4000000
7241
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
7242
#else /* VBOX_API_VERSION >= 4000000 */
7243
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
7244
#endif /* VBOX_API_VERSION >= 4000000 */
7245
        if (NS_FAILED(rc) || !snapshots[0]) {
7246 7247 7248
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
7249 7250 7251 7252 7253 7254 7255
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
7256 7257 7258 7259 7260 7261 7262 7263 7264 7265

    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) {
7266 7267
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
7268 7269 7270 7271
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
7272 7273
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
7274 7275
            goto cleanup;
        }
7276
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
7277 7278 7279 7280 7281 7282 7283
    }

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

7284
 cleanup:
J
Jiri Denemark 已提交
7285 7286 7287 7288 7289 7290
    if (count > 0) {
        for (i = 0; i < count; i++)
            VBOX_RELEASE(snapshots[i]);
    }
    VIR_FREE(snapshots);
    VBOX_RELEASE(machine);
7291
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7292 7293 7294 7295 7296 7297
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
7298
                               unsigned int flags)
J
Jiri Denemark 已提交
7299 7300
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
7301
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7302 7303 7304 7305
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

7306 7307
    virCheckFlags(0, NULL);

7308
    vboxIIDFromUUID(&iid, dom->uuid);
7309
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7310
    if (NS_FAILED(rc)) {
7311 7312
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7313 7314 7315 7316 7317 7318 7319 7320
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

7321
 cleanup:
J
Jiri Denemark 已提交
7322 7323
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
7324
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7325 7326 7327 7328 7329
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
7330
                             unsigned int flags)
J
Jiri Denemark 已提交
7331 7332
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7333
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7334 7335 7336 7337
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

7338 7339
    virCheckFlags(0, -1);

7340
    vboxIIDFromUUID(&iid, dom->uuid);
7341
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
7342
    if (NS_FAILED(rc)) {
7343 7344
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7345 7346 7347 7348 7349
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
7350 7351
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
7352 7353 7354 7355 7356 7357 7358 7359
        goto cleanup;
    }

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

7360
 cleanup:
J
Jiri Denemark 已提交
7361
    VBOX_RELEASE(machine);
7362
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7363 7364 7365
    return ret;
}

7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384
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)) {
7385 7386
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7387 7388 7389 7390 7391 7392 7393 7394
        goto cleanup;
    }

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

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
7395 7396 7397
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
7398 7399 7400
        goto cleanup;
    }
    if (!parent) {
7401 7402 7403
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
7404 7405 7406 7407 7408
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7409 7410 7411
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
7412 7413 7414 7415 7416 7417 7418 7419 7420 7421
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

7422
 cleanup:
7423 7424 7425 7426 7427 7428 7429 7430 7431
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

J
Jiri Denemark 已提交
7432 7433
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
7434
                          unsigned int flags)
J
Jiri Denemark 已提交
7435 7436
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
7437
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7438 7439 7440 7441 7442 7443
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

7444 7445
    virCheckFlags(0, NULL);

7446
    vboxIIDFromUUID(&iid, dom->uuid);
7447
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
7448
    if (NS_FAILED(rc)) {
7449 7450
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7451 7452 7453 7454 7455
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
7456 7457
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
7458 7459 7460 7461
        goto cleanup;
    }

    if (!snapshot) {
7462 7463
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
7464 7465 7466 7467 7468
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7469 7470
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

7482
 cleanup:
J
Jiri Denemark 已提交
7483 7484 7485 7486
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
7487
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7488 7489 7490
    return ret;
}

7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509
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)) {
7510 7511
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7512 7513 7514 7515 7516 7517 7518 7519
        goto cleanup;
    }

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
7520 7521
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
7522 7523 7524 7525 7526 7527 7528 7529 7530
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7531 7532
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543
        goto cleanup;
    }

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

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

7544
 cleanup:
7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569
    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)) {
7570 7571
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7572 7573 7574 7575 7576 7577 7578 7579 7580
        goto cleanup;
    }

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

    ret = 0;

7581
 cleanup:
7582 7583 7584 7585 7586 7587
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

7588
#if VBOX_API_VERSION < 3001000
J
Jiri Denemark 已提交
7589 7590 7591 7592 7593 7594
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7595
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7596 7597
    nsresult rc;

7598 7599
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
7600 7601
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
7602 7603 7604
        goto cleanup;
    }

7605
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
7606
    if (NS_FAILED(rc)) {
7607 7608
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
7609 7610 7611 7612 7613
        goto cleanup;
    }

    ret = 0;

7614
 cleanup:
7615
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629
    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;
7630
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7631

7632 7633
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
7634 7635
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
7636 7637 7638 7639 7640
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
7641 7642
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
7643 7644 7645 7646 7647
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
7648 7649
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
7650 7651 7652
        goto cleanup;
    }

7653
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
7654 7655 7656
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
7657 7658 7659
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7660 7661 7662 7663 7664 7665
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
7666 7667
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
7668
        } else {
7669 7670 7671
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
7672 7673 7674 7675 7676 7677 7678
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
7679 7680
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
7681 7682 7683 7684 7685
        goto cleanup;
    }

    ret = 0;

7686
 cleanup:
J
Jiri Denemark 已提交
7687 7688
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
7689
    VBOX_SESSION_CLOSE();
7690
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7691 7692 7693 7694 7695 7696
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
7697
                           unsigned int flags)
J
Jiri Denemark 已提交
7698 7699 7700
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7701
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7702 7703 7704 7705 7706 7707 7708
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

7709 7710
    virCheckFlags(0, -1);

7711
    vboxIIDFromUUID(&domiid, dom->uuid);
7712
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
7713
    if (NS_FAILED(rc)) {
7714 7715
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7716 7717 7718 7719 7720 7721 7722 7723 7724
        goto cleanup;
    }

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

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
7725 7726 7727
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7728 7729 7730 7731 7732
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
7733 7734 7735
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7736 7737 7738 7739 7740
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
7741 7742
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
7743 7744 7745 7746 7747
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
7748 7749
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762
        goto cleanup;
    }

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

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

7763
 cleanup:
J
Jiri Denemark 已提交
7764 7765
    VBOX_RELEASE(prevSnapshot);
    VBOX_RELEASE(newSnapshot);
7766
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7767 7768 7769 7770 7771 7772 7773 7774 7775
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
7776
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7777 7778
    int ret = -1;
    nsresult rc;
7779
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
7780 7781 7782 7783 7784
    nsresult result;
#else
    PRInt32 result;
#endif

7785 7786
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
7787 7788
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
7789 7790 7791
        goto cleanup;
    }

7792
#if VBOX_API_VERSION < 3001000
7793
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
7794
#else
7795
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
7796 7797 7798
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
7799 7800
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
7801
        } else {
7802 7803
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
7804 7805 7806 7807 7808 7809 7810
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
7811 7812
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
7813 7814 7815 7816 7817
        goto cleanup;
    }

    ret = 0;

7818
 cleanup:
J
Jiri Denemark 已提交
7819
    VBOX_RELEASE(progress);
7820
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7821 7822 7823 7824 7825 7826 7827 7828
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
7829
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
7830 7831
    int ret = -1;
    nsresult rc;
7832
    size_t i;
J
Jiri Denemark 已提交
7833

7834
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
7835
    if (NS_FAILED(rc)) {
7836 7837
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
7838 7839 7840
        goto cleanup;
    }

7841 7842 7843
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
7844 7845 7846 7847
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

7848
 cleanup:
7849
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
7850 7851 7852
    return ret;
}

7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872
#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);
7873
    virDomainSnapshotDefPtr def = NULL;
7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888
    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;
7889

7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064
    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);
8065
                    VIR_FREE(disk);
8066 8067 8068 8069 8070 8071
                    goto cleanup;
                }
                VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
                disk->uuid = uuid;
                VBOX_UTF16_FREE(uuidUtf16);

8072 8073
                if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) {
                    VIR_FREE(disk);
8074
                    goto cleanup;
8075
                }
8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 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 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307

                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
8308

J
Jiri Denemark 已提交
8309 8310 8311 8312 8313 8314
static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
8315
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
8316 8317 8318 8319 8320
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;
8321
    vboxArray snapChildren = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
8322

8323 8324
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
8325

8326
    vboxIIDFromUUID(&domiid, dom->uuid);
8327
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
8328
    if (NS_FAILED(rc)) {
8329 8330
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
8331 8332 8333 8334 8335 8336 8337 8338 8339
        goto cleanup;
    }

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

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
8340 8341
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
8342 8343 8344
        goto cleanup;
    }

8345 8346 8347
    /* In case we just want to delete the metadata, we will edit the vbox file in order
     *to remove the node concerning the snapshot
    */
8348
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363
        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
        }
8364 8365 8366
        goto cleanup;
    }

J
Jiri Denemark 已提交
8367 8368
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
8369 8370
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
8371 8372 8373
        goto cleanup;
    }

8374
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
8375 8376 8377
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
8378 8379 8380
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
8381 8382 8383 8384 8385 8386 8387 8388
        goto cleanup;
    }

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

8389
 cleanup:
J
Jiri Denemark 已提交
8390 8391
    VBOX_RELEASE(console);
    VBOX_RELEASE(snap);
8392
    vboxIIDUnalloc(&domiid);
8393
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
8394 8395 8396
    return ret;
}

8397
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
8398
    /* No Callback support for VirtualBox 2.2.* series */
8399
    /* No Callback support for VirtualBox 4.* series */
8400
#else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
8401 8402

/* Functions needed for Callbacks */
8403
static nsresult PR_COM_METHOD
8404
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8405 8406
                                 PRUnichar *machineId, PRUint32 state)
{
8407 8408 8409 8410 8411 8412
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

8413
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
8414 8415 8416 8417 8418 8419 8420
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
8421
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
8422 8423 8424

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
8425
            virObjectEventPtr ev;
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

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

8456
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
8457

8458
            if (ev)
8459
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
8460 8461 8462 8463 8464 8465 8466 8467
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

8468
static nsresult PR_COM_METHOD
8469
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8470 8471
                                PRUnichar *machineId)
{
8472
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8473 8474 8475 8476 8477
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

8478
static nsresult PR_COM_METHOD
8479
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8480 8481 8482
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
8483
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
8484
{
8485
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
8486 8487 8488 8489 8490 8491 8492
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

8493
static nsresult PR_COM_METHOD
8494 8495
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
8496 8497
                              PRUnichar *key, PRUnichar *value)
{
8498
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8499 8500 8501 8502 8503 8504 8505
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

8506
# if VBOX_API_VERSION < 3001000
8507
static nsresult PR_COM_METHOD
8508 8509 8510 8511
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
8512
{
8513 8514
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
8515 8516 8517 8518
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
8519 8520
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
8521

8522
static nsresult PR_COM_METHOD
8523
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8524 8525
                                PRUnichar *machineId, PRBool registered)
{
8526 8527 8528 8529 8530 8531
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

8532
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
8533 8534 8535 8536 8537 8538 8539
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
8540
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
8541 8542 8543

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
8544
            virObjectEventPtr ev;
8545 8546

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
8547
             * event because the when the machine is de-registered the call
8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559
             * 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;
            }

8560
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
8561

8562
            if (ev)
8563
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
8564 8565 8566 8567 8568 8569 8570 8571
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

8572
static nsresult PR_COM_METHOD
8573 8574 8575
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
8576
{
8577
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
8578 8579 8580 8581 8582
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

8583
static nsresult PR_COM_METHOD
8584 8585
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
8586 8587
                            PRUnichar *snapshotId)
{
8588
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8589 8590 8591 8592 8593 8594
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8595
static nsresult PR_COM_METHOD
8596 8597
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
8598 8599
                                PRUnichar *snapshotId)
{
8600
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8601 8602 8603 8604 8605 8606
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8607
static nsresult PR_COM_METHOD
8608 8609
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
8610 8611
                             PRUnichar *snapshotId)
{
8612
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8613 8614 8615 8616 8617 8618
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8619
static nsresult PR_COM_METHOD
8620
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8621 8622 8623
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
8624
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8625 8626 8627 8628 8629 8630 8631 8632
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

8633
static nsresult PR_COM_METHOD
8634
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
8635
{
8636 8637 8638 8639
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

8640
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
8641 8642 8643 8644

    return c;
}

8645 8646 8647
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
8648 8649 8650 8651 8652 8653 8654 8655 8656
    nsresult c;

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

8657
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
8658 8659 8660 8661

    return c;
}

8662 8663 8664
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
8665 8666 8667 8668 8669
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
8670 8671
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
8672 8673 8674
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

8675
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
8676 8677 8678 8679 8680

        return NS_OK;
    }


8681
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
8682 8683 8684 8685 8686 8687
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


8688
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
8689 8690
    IVirtualBoxCallback *vboxCallback = NULL;

8691
    /* Allocate, Initialize and return a valid
8692 8693 8694
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
8695
        VIR_FREE(vboxCallback);
8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706
        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;
8707
# if VBOX_API_VERSION < 3001000
8708
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
8709 8710
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
8711 8712 8713
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
8714
# if VBOX_API_VERSION < 3002000
8715
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
8716
# else /* VBOX_API_VERSION >= 3002000 */
8717
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
8718
# endif /* VBOX_API_VERSION >= 3002000 */
8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730
        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,
8731 8732
                             void *opaque ATTRIBUTE_UNUSED)
{
8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744
    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);
    }
}

8745 8746 8747 8748 8749 8750
static int
vboxConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
{
8751
    VBOX_OBJECT_CHECK(conn, int, -1);
8752
    int vboxRet          = -1;
8753
    nsresult rc;
8754 8755 8756 8757 8758 8759

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

8760
    if (data->vboxCallback == NULL) {
8761
        data->vboxCallback = vboxAllocCallbackObj();
8762 8763 8764 8765
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
8766 8767
            }
        }
8768 8769 8770
    } else {
        vboxRet = 0;
    }
8771

8772 8773 8774 8775 8776 8777 8778
    /* 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);
8779

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

8783 8784 8785 8786 8787
        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
             */
8788

8789
            ret = virDomainEventStateRegister(conn, data->domainEvents,
8790
                                              callback, opaque, freecb);
8791
            VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
8792
                      "callback: %p, opaque: %p, "
8793
                      "freecb: %p)", ret, conn, callback,
8794
                      opaque, freecb);
8795 8796 8797 8798 8799 8800
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
8801
        return 0;
8802 8803 8804 8805 8806 8807 8808 8809
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

8810 8811 8812 8813
static int
vboxConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
{
8814
    VBOX_OBJECT_CHECK(conn, int, -1);
8815
    int cnt;
8816 8817 8818 8819 8820 8821

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

8822 8823
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
8824

8825 8826 8827
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
8828

8829 8830 8831
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
8832 8833 8834 8835
    }

    vboxDriverUnlock(data);

8836 8837 8838
    if (cnt >= 0)
        ret = 0;

8839 8840 8841
    return ret;
}

8842 8843 8844 8845 8846
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
8847 8848
                                             virFreeCallback freecb)
{
8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886
    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
             */

8887
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
8888 8889
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
8890
                ret = -1;
8891
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
8892
                      "callback: %p, opaque: %p, "
8893
                      "freecb: %p)", ret, conn, callback,
8894
                      opaque, freecb);
8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

8910 8911 8912 8913
static int
vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
{
8914
    VBOX_OBJECT_CHECK(conn, int, -1);
8915
    int cnt;
8916 8917 8918 8919 8920 8921

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

8922
    cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
8923
                                          callbackID);
8924

8925 8926 8927
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
8928

8929 8930 8931
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
8932 8933 8934 8935
    }

    vboxDriverUnlock(data);

8936 8937 8938
    if (cnt >= 0)
        ret = 0;

8939 8940 8941
    return ret;
}

8942
#endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
8943

8944 8945 8946 8947 8948
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
8949 8950
                                        unsigned int flags)
{
8951 8952
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
8953 8954
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

8955 8956 8957 8958 8959 8960 8961 8962
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

8963
    VIR_DEBUG("network initialized");
8964 8965 8966
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

8967
 cleanup:
8968 8969 8970
    return VIR_DRV_OPEN_DECLINED;
}

8971 8972
static int vboxNetworkClose(virConnectPtr conn)
{
8973
    VIR_DEBUG("network uninitialized");
8974 8975 8976 8977
    conn->networkPrivateData = NULL;
    return 0;
}

8978 8979
static int vboxConnectNumOfNetworks(virConnectPtr conn)
{
8980
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
8981
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
8982
    size_t i = 0;
8983

8984
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
8985

8986 8987 8988 8989
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
8990
            PRUint32 interfaceType = 0;
8991

8992
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8993 8994
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
8995

8996
                networkInterface->vtbl->GetStatus(networkInterface, &status);
8997

8998 8999
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
9000 9001 9002 9003
            }
        }
    }

9004 9005
    vboxArrayRelease(&networkInterfaces);

9006 9007
    VBOX_RELEASE(host);

9008
    VIR_DEBUG("numActive: %d", ret);
9009
    return ret;
9010 9011
}

9012
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
9013
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9014
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9015
    size_t i = 0;
9016

9017 9018 9019 9020
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
9021

9022
        if (networkInterface) {
9023
            PRUint32 interfaceType = 0;
9024

9025
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9026

9027 9028
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9029

9030
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9031

9032 9033 9034
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
9035

9036
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
9037
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
9038

9039
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
9040
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
9041
                        ret++;
9042

9043 9044
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
9045 9046 9047 9048 9049
                }
            }
        }
    }

9050
    vboxArrayRelease(&networkInterfaces);
9051

9052
    VBOX_RELEASE(host);
9053

9054 9055
    return ret;
}
9056

9057 9058
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn)
{
9059
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9060
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9061
    size_t i = 0;
9062

9063
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
9064

9065 9066 9067 9068
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
9069
            PRUint32 interfaceType = 0;
9070

9071
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9072 9073
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9074

9075
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9076

9077 9078
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
9079 9080 9081 9082
            }
        }
    }

9083 9084
    vboxArrayRelease(&networkInterfaces);

9085 9086
    VBOX_RELEASE(host);

9087
    VIR_DEBUG("numActive: %d", ret);
9088
    return ret;
9089 9090
}

9091
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
9092
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
9093
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
9094
    size_t i = 0;
9095

9096 9097 9098 9099
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
9100

9101
        if (networkInterface) {
9102
            PRUint32 interfaceType = 0;
9103

9104
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9105

9106 9107
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
9108

9109
                networkInterface->vtbl->GetStatus(networkInterface, &status);
9110

9111 9112 9113
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
9114

9115
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
9116
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
9117

9118
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
9119
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
9120
                        ret++;
9121

9122 9123
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
9124 9125 9126 9127 9128
                }
            }
        }
    }

9129
    vboxArrayRelease(&networkInterfaces);
9130 9131 9132 9133

    VBOX_RELEASE(host);

    return ret;
9134 9135
}

9136 9137 9138
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
9139
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
9140
    vboxIID iid = VBOX_IID_INITIALIZER;
9141

9142
    vboxIIDFromUUID(&iid, uuid);
9143

9144 9145 9146
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
9147
    IHostNetworkInterface *networkInterface = NULL;
9148

9149
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
9150 9151
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9152

9153
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9154

9155 9156 9157
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
9158

9159 9160
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
9161

9162
            ret = virGetNetwork(conn, nameUtf8, uuid);
9163

9164
            VIR_DEBUG("Network Name: %s", nameUtf8);
9165
            DEBUGIID("Network UUID", iid.value);
9166

9167 9168
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
9169
        }
9170 9171

        VBOX_RELEASE(networkInterface);
9172 9173
    }

9174 9175
    VBOX_RELEASE(host);

9176
    vboxIIDUnalloc(&iid);
9177 9178 9179
    return ret;
}

9180 9181 9182
static virNetworkPtr
vboxNetworkLookupByName(virConnectPtr conn, const char *name)
{
9183 9184 9185
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9186

9187
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
9188

9189
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
9190

9191 9192
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9193

9194
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9195

9196 9197
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
9198
            vboxIID iid = VBOX_IID_INITIALIZER;
9199

9200 9201
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
9202
            ret = virGetNetwork(conn, name, uuid);
9203
            VIR_DEBUG("Network Name: %s", name);
9204

9205 9206
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
9207
        }
9208 9209

        VBOX_RELEASE(networkInterface);
9210 9211
    }

9212 9213 9214
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

9215 9216 9217
    return ret;
}

9218 9219 9220
static virNetworkPtr
vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
{
9221 9222 9223 9224
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9225
    nsresult rc;
9226

9227
    virNetworkDefPtr def = virNetworkDefParseString(xml);
9228 9229
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
9230

9231
    if ((!def) ||
9232
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
9233
        (def->nips == 0 || !def->ips))
9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244
        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)
9245
        goto cleanup;
9246

9247 9248 9249 9250 9251 9252
    /* 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.
     */
9253

9254
#if VBOX_API_VERSION == 2002000
9255
    if (STREQ(def->name, "vboxnet0")) {
9256
        PRUint32 interfaceType = 0;
9257

9258 9259
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9260

9261 9262 9263 9264 9265 9266
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
9267
#else /* VBOX_API_VERSION != 2002000 */
9268 9269 9270 9271
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
9272

9273 9274 9275 9276
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
9277
    }
9278
#endif /* VBOX_API_VERSION != 2002000 */
9279

9280 9281 9282 9283
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
9284
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295

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

E
Eric Blake 已提交
9297
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9298

9299 9300 9301
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
9302
        if ((ipdef->nranges >= 1) &&
9303 9304
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
9305 9306 9307 9308 9309 9310 9311 9312 9313 9314
            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);
9315
                VIR_DEBUG("couldn't find dhcp server so creating one");
9316 9317 9318 9319 9320 9321 9322 9323
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

9324 9325 9326 9327
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
9328 9329 9330 9331 9332 9333 9334 9335 9336 9337

                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;
                }
9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362

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

9364
        if ((ipdef->nhosts >= 1) &&
9365
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
9366 9367
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
9368

9369 9370
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
9371 9372 9373 9374 9375 9376

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
9377

9378 9379 9380 9381
            /* 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
             */
9382
#if VBOX_API_VERSION < 4002000
9383 9384 9385
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
9386 9387 9388 9389 9390
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
9391

9392 9393 9394
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
9395
#if VBOX_API_VERSION < 4002000
9396 9397
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
9398 9399 9400 9401
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
9402
        }
9403

9404 9405 9406 9407 9408
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
9409
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
9410
        }
9411 9412 9413 9414

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
9415 9416
    }

9417 9418 9419 9420
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9421
 cleanup:
9422 9423 9424 9425
    virNetworkDefFree(def);
    return ret;
}

9426 9427
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml)
{
9428 9429 9430
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

9431 9432
static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml)
{
9433 9434 9435
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

9436 9437 9438
static int
vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface)
{
9439
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
9440
    char *networkNameUtf8 = NULL;
9441 9442
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9443 9444 9445 9446 9447 9448 9449 9450 9451

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

9452
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9453 9454
        goto cleanup;

9455
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9456

9457
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9458

9459 9460
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9461

9462
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9463

9464 9465 9466
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
9467

9468
#if VBOX_API_VERSION != 2002000
9469 9470 9471
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
9472

9473
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
9474

9475
                if (iidUtf16) {
9476
# if VBOX_API_VERSION == 3000000
9477 9478 9479
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
9480
# else  /* VBOX_API_VERSION > 3000000 */
9481
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
9482
# endif /* VBOX_API_VERSION > 3000000 */
9483 9484
                    VBOX_UTF16_FREE(iidUtf16);
                }
9485

9486 9487 9488 9489 9490
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
9491
#endif /* VBOX_API_VERSION != 2002000 */
9492

E
Eric Blake 已提交
9493
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9494 9495 9496 9497 9498 9499 9500 9501 9502 9503

            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);
9504 9505
            }

9506 9507
            VBOX_UTF16_FREE(networkNameUtf16);

9508
        }
9509
        VBOX_RELEASE(networkInterface);
9510 9511
    }

9512 9513 9514
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9515 9516
    ret = 0;

9517
 cleanup:
9518 9519 9520 9521
    VIR_FREE(networkNameUtf8);
    return ret;
}

9522 9523
static int vboxNetworkUndefine(virNetworkPtr network)
{
9524 9525 9526
    return vboxNetworkUndefineDestroy(network, true);
}

9527 9528
static int vboxNetworkCreate(virNetworkPtr network)
{
9529
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
9530
    char *networkNameUtf8 = NULL;
9531 9532
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9533 9534 9535 9536 9537 9538 9539 9540

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

9541
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9542 9543
        goto cleanup;

9544
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9545

9546
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9547

9548 9549
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9550

9551
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9552

9553 9554 9555
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
9556 9557


E
Eric Blake 已提交
9558
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9559

9560 9561 9562 9563 9564
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
9565

9566
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
9567

9568
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
9569

9570 9571 9572 9573
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
9574

9575 9576
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
9577 9578
            }

9579
            VBOX_UTF16_FREE(networkNameUtf16);
9580
        }
9581 9582

        VBOX_RELEASE(networkInterface);
9583 9584
    }

9585 9586 9587
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9588 9589
    ret = 0;

9590
 cleanup:
9591 9592 9593 9594
    VIR_FREE(networkNameUtf8);
    return ret;
}

9595 9596
static int vboxNetworkDestroy(virNetworkPtr network)
{
9597
    return vboxNetworkUndefineDestroy(network, false);
9598 9599
}

9600
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
9601 9602
                                   unsigned int flags)
{
9603
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
9604
    virNetworkDefPtr def  = NULL;
9605
    virNetworkIpDefPtr ipdef = NULL;
9606
    char *networkNameUtf8 = NULL;
9607 9608
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9609

E
Eric Blake 已提交
9610 9611
    virCheckFlags(0, NULL);

9612
    if (VIR_ALLOC(def) < 0)
9613
        goto cleanup;
9614
    if (VIR_ALLOC(ipdef) < 0)
9615 9616 9617
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
9618

9619
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9620 9621
        goto cleanup;

9622
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9623

9624
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9625

9626 9627
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9628

9629
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9630

9631
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
9632
            if (VIR_STRDUP(def->name, network->name) >= 0) {
9633 9634
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
9635
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
9636

9637 9638
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
9639

E
Eric Blake 已提交
9640
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9641

9642
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
9643

9644 9645 9646 9647
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
9648
                    ipdef->nranges = 1;
9649
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >= 0) {
9650 9651 9652 9653
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
9654
                        bool errorOccurred = false;
9655

9656 9657 9658 9659 9660 9661 9662
                        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
                         */
9663
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9664
                                                     &ipdef->address) < 0 ||
9665
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
9666
                                                     &ipdef->netmask) < 0 ||
9667
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
9668
                                                     &ipdef->ranges[0].start) < 0 ||
9669
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
9670
                                                     &ipdef->ranges[0].end) < 0) {
9671 9672
                            errorOccurred = true;
                        }
9673 9674 9675 9676 9677

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
9678 9679 9680 9681

                        if (errorOccurred) {
                            goto cleanup;
                        }
9682
                    } else {
9683
                        ipdef->nranges = 0;
9684
                    }
9685

9686
                    ipdef->nhosts = 1;
9687
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >= 0) {
9688
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
9689 9690
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
9691
                        } else {
9692 9693
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
9694
                            bool errorOccurred = false;
9695

9696
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
9697 9698
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

9699
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
9700 9701

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9702
                                                         &ipdef->hosts[0].ip) < 0) {
9703 9704
                                errorOccurred = true;
                            }
9705

9706 9707
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
9708 9709 9710 9711

                            if (errorOccurred) {
                                goto cleanup;
                            }
9712 9713
                        }
                    } else {
9714
                        ipdef->nhosts = 0;
9715
                    }
9716 9717 9718 9719 9720

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
9721
                    bool errorOccurred = false;
9722 9723 9724 9725

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

9726
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
9727
                                                 &ipdef->netmask) < 0 ||
9728
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9729
                                                 &ipdef->address) < 0) {
9730 9731
                        errorOccurred = true;
                    }
9732 9733 9734

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
9735 9736 9737 9738

                    if (errorOccurred) {
                        goto cleanup;
                    }
9739 9740
                }

9741 9742
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
9743
                VBOX_UTF16_FREE(networkNameUtf16);
9744 9745
            }
        }
9746 9747

        VBOX_RELEASE(networkInterface);
9748 9749
    }

9750 9751 9752
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9753
    ret = virNetworkDefFormat(def, 0);
9754

9755
 cleanup:
9756
    virNetworkDefFree(def);
9757 9758 9759 9760
    VIR_FREE(networkNameUtf8);
    return ret;
}

9761 9762 9763 9764
/**
 * The Storage Functions here on
 */

9765 9766 9767
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
9768
{
9769 9770
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
9771 9772
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

9773
    if (STRNEQ(conn->driver->name, "VBOX"))
9774
        return VIR_DRV_OPEN_DECLINED;
9775 9776 9777 9778

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
9779
        return VIR_DRV_OPEN_ERROR;
9780

9781
    VIR_DEBUG("vbox storage initialized");
9782 9783 9784 9785
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

9786 9787
static int vboxStorageClose(virConnectPtr conn)
{
9788
    VIR_DEBUG("vbox storage uninitialized");
9789 9790 9791 9792
    conn->storagePrivateData = NULL;
    return 0;
}

9793 9794
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
9795 9796 9797 9798 9799 9800 9801 9802

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

9803 9804
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
9805 9806
    int numActive = 0;

9807 9808 9809
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
9810 9811 9812
    return numActive;
}

9813 9814 9815
static virStoragePoolPtr
vboxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
9816 9817 9818 9819 9820 9821 9822 9823 9824 9825
    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";

9826
        ignore_value(virUUIDParse(uuidstr, uuid));
9827

9828
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
9829 9830 9831 9832 9833
    }

    return ret;
}

9834 9835
static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
9836
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
9837
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
9838 9839
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
9840
    size_t i;
9841

9842
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
9843
    if (NS_SUCCEEDED(rc)) {
9844 9845
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
9846 9847
            if (hardDisk) {
                PRUint32 hddstate;
9848

9849 9850 9851
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
9852 9853
            }
        }
9854 9855 9856 9857

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
9858
    } else {
9859
        ret = -1;
9860 9861 9862
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
9863 9864
    }

9865
    return ret;
9866 9867 9868
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
9869
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
9870
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
9871 9872
    PRUint32 numActive     = 0;
    nsresult rc;
9873
    size_t i;
9874

9875
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
9876
    if (NS_SUCCEEDED(rc)) {
9877 9878
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
9879

9880 9881 9882 9883
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
9884

9885 9886 9887
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
9888

9889 9890
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
9891

9892
                    if (nameUtf8) {
9893
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
9894
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
9895 9896 9897
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
9898 9899 9900 9901
                    }
                }
            }
        }
9902 9903 9904 9905

        vboxArrayRelease(&hardDisks);

        ret = numActive;
9906
    } else {
9907
        ret = -1;
9908 9909 9910
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
9911 9912
    }

9913
    return ret;
9914 9915
}

9916 9917 9918
static virStorageVolPtr
vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
{
9919
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
9920
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
9921
    nsresult rc;
9922
    size_t i;
9923

9924
    if (!name)
9925
        return ret;
9926

9927
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
9928
    if (NS_SUCCEEDED(rc)) {
9929 9930
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
9931

9932 9933 9934 9935
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
9936

9937 9938 9939
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
9940

9941 9942 9943 9944
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
9945

9946
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
9947 9948 9949
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
9950

9951 9952 9953 9954
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
9955

9956 9957
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
9958

9959 9960 9961 9962
                            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);
9963 9964
                        }

9965
                        vboxIIDUnalloc(&hddIID);
9966 9967
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
9968
                    }
9969

J
John Ferlan 已提交
9970
                    VBOX_UTF8_FREE(nameUtf8);
9971 9972 9973
                }
            }
        }
9974

9975
        vboxArrayRelease(&hardDisks);
9976 9977 9978 9979 9980
    }

    return ret;
}

9981 9982 9983
static virStorageVolPtr
vboxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
9984
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
9985 9986
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
9987 9988 9989
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

9990 9991 9992
    if (!key)
        return ret;

9993
    if (virUUIDParse(key, uuid) < 0) {
9994 9995
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
9996
        return NULL;
9997 9998
    }

9999
    vboxIIDFromUUID(&hddIID, uuid);
10000
#if VBOX_API_VERSION < 4000000
10001
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10002
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10003 10004
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10005 10006 10007 10008
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10009
#endif /* VBOX_API_VERSION >= 4000000 */
10010 10011
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10012

10013 10014 10015 10016
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
10017

10018 10019
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
10020

10021
            if (hddNameUtf8) {
10022
                if (vboxConnectNumOfStoragePools(conn) == 1) {
10023 10024
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
10025
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
10026 10027 10028 10029
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
10030 10031
                }

10032 10033
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
10034 10035 10036

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
10037 10038
            }
        }
10039 10040

        VBOX_MEDIUM_RELEASE(hardDisk);
10041 10042
    }

10043
    vboxIIDUnalloc(&hddIID);
10044 10045 10046
    return ret;
}

10047 10048 10049
static virStorageVolPtr
vboxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
10050
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
10051 10052 10053 10054
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

10055 10056
    if (!path)
        return ret;
10057

10058
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
10059

10060 10061
    if (!hddPathUtf16)
        return ret;
10062

10063
#if VBOX_API_VERSION < 4000000
10064
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
10065
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10066 10067
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
10068 10069 10070 10071
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10072
#endif /* VBOX_API_VERSION >= 4000000 */
10073 10074
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10075

10076 10077 10078 10079
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
10080

10081
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
10082

10083 10084 10085 10086
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
10087

10088 10089 10090 10091
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
10092

10093 10094 10095 10096
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
10097

10098 10099 10100
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
10101
                    if (vboxConnectNumOfStoragePools(conn) == 1)
10102 10103
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
10104

10105 10106 10107
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
10108
                }
10109

10110
                vboxIIDUnalloc(&hddIID);
10111 10112
            }

J
John Ferlan 已提交
10113
            VBOX_UTF8_FREE(hddNameUtf8);
10114
        }
10115 10116

        VBOX_MEDIUM_RELEASE(hardDisk);
10117 10118
    }

10119 10120
    VBOX_UTF16_FREE(hddPathUtf16);

10121 10122 10123 10124 10125
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
10126 10127
                                                unsigned int flags)
{
10128
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
10129
    virStorageVolDefPtr  def  = NULL;
10130 10131
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
10132 10133 10134
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
10135 10136
    virCheckFlags(0, NULL);

10137 10138 10139 10140 10141 10142 10143 10144
    /* 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;

10145
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
10146 10147
        goto cleanup;

10148 10149
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
10150
        goto cleanup;
10151

10152 10153
    /* For now only the vmdk, vpc and vdi type harddisk
     * variants can be created.  For historical reason, we default to vdi */
10154 10155 10156 10157 10158 10159 10160
    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);
    }
10161

10162
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
10163

10164 10165
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
10166

10167 10168 10169
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
10170 10171
            PRUint64   logicalSize = VIR_DIV_UP(def->target.capacity,
                                                1024 * 1024);
10172
            PRUint32   variant     = HardDiskVariant_Standard;
10173

10174
            if (def->target.capacity == def->target.allocation)
10175
                variant = HardDiskVariant_Fixed;
10176

10177
#if VBOX_API_VERSION < 4003000
10178
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
R
Ryota Ozaki 已提交
10179 10180 10181
#else
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
#endif
10182
            if (NS_SUCCEEDED(rc) && progress) {
10183
#if VBOX_API_VERSION == 2002000
10184
                nsresult resultCode;
10185
#else
10186
                PRInt32  resultCode;
10187 10188
#endif

10189 10190
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
10191

10192
                if (NS_SUCCEEDED(resultCode)) {
10193 10194 10195
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
10196

10197
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
10198
                    if (NS_SUCCEEDED(rc)) {
10199 10200
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
10201

10202 10203
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
10204
                    }
10205 10206

                    vboxIIDUnalloc(&hddIID);
10207 10208
                }

10209
                VBOX_RELEASE(progress);
10210
            }
10211
        }
10212 10213
    }

10214 10215 10216
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

10217
 cleanup:
10218 10219 10220 10221 10222
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
10223 10224
                                unsigned int flags)
{
10225
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
10226 10227
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
10228 10229 10230
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
10231 10232
    size_t i = 0;
    size_t j = 0;
10233

E
Eric Blake 已提交
10234 10235
    virCheckFlags(0, -1);

10236
    if (virUUIDParse(vol->key, uuid) < 0) {
10237 10238
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10239 10240
        return -1;
    }
10241

10242
    vboxIIDFromUUID(&hddIID, uuid);
10243
#if VBOX_API_VERSION < 4000000
10244
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10245
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10246 10247
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10248 10249 10250 10251
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10252
#endif /* VBOX_API_VERSION >= 4000000 */
10253 10254
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10255

10256 10257 10258
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
10259 10260
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;

10261
#if VBOX_API_VERSION < 3001000
10262
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
10263
#else  /* VBOX_API_VERSION >= 3001000 */
10264
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
10265
#endif /* VBOX_API_VERSION >= 3001000 */
10266

10267
#if VBOX_API_VERSION == 2002000 && defined WIN32
10268 10269 10270 10271 10272 10273
            /* 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 已提交
10274
             * we divide the size of the SafeArray by two, to compensate for
10275 10276
             * this workaround in VirtualBox */
            machineIds.count /= 2;
10277
#endif /* VBOX_API_VERSION >= 2002000 */
10278

10279
            machineIdsSize = machineIds.count;
10280

10281
            for (i = 0; i < machineIds.count; i++) {
10282
                IMachine *machine = NULL;
10283 10284 10285
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
10286

10287
#if VBOX_API_VERSION >= 4000000
10288 10289
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
10290 10291
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
10292 10293 10294 10295 10296 10297
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

10298
                if (NS_SUCCEEDED(rc)) {
10299

10300 10301
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
10302
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
10303

10304
#if VBOX_API_VERSION < 3001000
10305 10306
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
10307
#else  /* VBOX_API_VERSION >= 3001000 */
10308 10309
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
10310
#endif /* VBOX_API_VERSION >= 3001000 */
10311 10312
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
10313 10314 10315 10316

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

10317
#if VBOX_API_VERSION < 3001000
10318
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
10319
#else  /* VBOX_API_VERSION >= 3001000 */
10320
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
10321
#endif /* VBOX_API_VERSION >= 3001000 */
10322
                                if (NS_SUCCEEDED(rc) && hdd) {
10323
                                    vboxIID iid = VBOX_IID_INITIALIZER;
10324

10325 10326
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
10327

10328 10329
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
10330

10331
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
10332 10333 10334 10335
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

10336
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
10337 10338 10339 10340 10341

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

10342
#if VBOX_API_VERSION < 3001000
10343
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
10344
#else  /* VBOX_API_VERSION >= 3001000 */
10345
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
10346
#endif /* VBOX_API_VERSION >= 3001000 */
10347 10348
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
10349
                                                VIR_DEBUG("saving machine settings");
10350
                                            }
10351

10352 10353
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
10354
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
10355
                                            }
10356

J
John Ferlan 已提交
10357
                                            VBOX_UTF16_FREE(controller);
10358
                                        }
10359
                                        vboxIIDUnalloc(&iid);
10360
                                    }
10361
                                    VBOX_MEDIUM_RELEASE(hdd);
10362 10363 10364
                                }
                            }
                        }
10365
                        vboxArrayRelease(&hddAttachments);
10366
                        VBOX_RELEASE(machine);
10367
                    }
10368
                    VBOX_SESSION_CLOSE();
10369
                }
10370 10371

                vboxIIDUnalloc(&machineId);
10372
            }
10373

10374
            vboxArrayUnalloc(&machineIds);
10375

10376 10377 10378
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
10379

10380 10381 10382
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
10383
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
10384
                    ret = 0;
10385 10386 10387
                }
            }
        }
10388 10389

        VBOX_MEDIUM_RELEASE(hardDisk);
10390 10391
    }

10392
    vboxIIDUnalloc(&hddIID);
10393

10394 10395 10396
    return ret;
}

10397 10398 10399
static int
vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
{
10400
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
10401
    IHardDisk *hardDisk  = NULL;
10402 10403
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10404 10405
    nsresult rc;

10406
    if (!info)
10407
        return ret;
10408

10409
    if (virUUIDParse(vol->key, uuid) < 0) {
10410 10411
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10412
        return ret;
10413
    }
10414

10415
    vboxIIDFromUUID(&hddIID, uuid);
10416
#if VBOX_API_VERSION < 4000000
10417
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10418
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10419 10420
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10421 10422 10423 10424
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10425
#endif /* VBOX_API_VERSION >= 4000000 */
10426 10427
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10428

10429 10430
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
10431
#if VBOX_API_VERSION < 4000000
10432 10433
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
10434
#else /* VBOX_API_VERSION >= 4000000 */
10435 10436
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
10437
#endif /* VBOX_API_VERSION >= 4000000 */
10438

10439
            info->type = VIR_STORAGE_VOL_FILE;
10440

10441
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
10442
#if VBOX_API_VERSION < 4000000
10443
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
10444
#else /* VBOX_API_VERSION >= 4000000 */
10445
            info->capacity = hddLogicalSize;
10446
#endif /* VBOX_API_VERSION >= 4000000 */
10447

10448 10449
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
10450

10451
            ret = 0;
10452

10453 10454 10455 10456
            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);
10457
        }
10458 10459

        VBOX_MEDIUM_RELEASE(hardDisk);
10460 10461
    }

10462
    vboxIIDUnalloc(&hddIID);
10463

10464 10465 10466
    return ret;
}

E
Eric Blake 已提交
10467 10468
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
10469
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
10470
    IHardDisk *hardDisk  = NULL;
10471 10472
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10473 10474 10475 10476 10477
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
10478 10479
    virCheckFlags(0, NULL);

10480 10481 10482
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

10483
    if (virUUIDParse(vol->key, uuid) < 0) {
10484 10485
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10486
        return ret;
10487
    }
10488

10489
    vboxIIDFromUUID(&hddIID, uuid);
10490
#if VBOX_API_VERSION < 4000000
10491
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10492
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10493 10494
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10495 10496 10497 10498
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10499
#endif /* VBOX_API_VERSION >= 4000000 */
10500 10501 10502 10503 10504 10505
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
10506
#if VBOX_API_VERSION < 4000000
10507 10508
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
10509
#else /* VBOX_API_VERSION >= 4000000 */
10510 10511
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
10512
#endif /* VBOX_API_VERSION >= 4000000 */
10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523

            /* 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);
10524
            if (NS_SUCCEEDED(rc) && defOk) {
10525
#if VBOX_API_VERSION < 4000000
10526
                def.target.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
10527
#else /* VBOX_API_VERSION >= 4000000 */
10528
                def.target.capacity = hddLogicalSize;
10529
#endif /* VBOX_API_VERSION >= 4000000 */
10530
            } else
10531 10532 10533 10534
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
10535
                def.target.allocation = hddActualSize;
10536 10537 10538
            else
                defOk = 0;

10539
            if (VIR_STRDUP(def.name, vol->name) < 0)
10540 10541
                defOk = 0;

10542
            if (VIR_STRDUP(def.key, vol->key) < 0)
10543 10544 10545 10546 10547 10548 10549 10550 10551
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

10552
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
10553 10554 10555 10556 10557

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
10558 10559
                    else if (STRCASEEQ("vdi", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VDI;
10560
                    else
10561
                        def.target.format = VIR_STORAGE_FILE_RAW;
10562

10563
                    VBOX_UTF8_FREE(hddFormatUtf8);
10564 10565
                }

10566 10567 10568
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
10569 10570
            }
        }
10571 10572

        VBOX_MEDIUM_RELEASE(hardDisk);
10573 10574
    }

10575
    vboxIIDUnalloc(&hddIID);
10576

10577
    if (defOk)
10578
        ret = virStorageVolDefFormat(&pool, &def);
10579 10580 10581 10582 10583

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
10584
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
10585
    IHardDisk *hardDisk  = NULL;
10586 10587
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10588 10589
    nsresult rc;

10590
    if (virUUIDParse(vol->key, uuid) < 0) {
10591 10592
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10593
        return ret;
10594
    }
10595

10596
    vboxIIDFromUUID(&hddIID, uuid);
10597
#if VBOX_API_VERSION < 4000000
10598
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10599
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10600 10601
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10602 10603 10604 10605
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10606
#endif /* VBOX_API_VERSION >= 4000000 */
10607 10608
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10609

10610 10611 10612 10613
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
10614

10615
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
10616

10617 10618
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
10619

10620
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
10621

10622 10623 10624
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
10625

10626
                VBOX_UTF8_FREE(hddLocationUtf8);
10627 10628
            }

10629
            VBOX_UTF16_FREE(hddLocationUtf16);
10630
        }
10631 10632

        VBOX_MEDIUM_RELEASE(hardDisk);
10633 10634
    }

10635
    vboxIIDUnalloc(&hddIID);
10636

10637 10638
    return ret;
}
10639

10640
#if VBOX_API_VERSION >= 4000000
10641 10642 10643 10644
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
10645
                     unsigned int flags)
10646 10647 10648 10649 10650 10651 10652 10653 10654 10655
{
    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 已提交
10656 10657
    virCheckFlags(0, NULL);

10658 10659 10660
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
10661 10662
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
10663 10664 10665 10666 10667
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
10668 10669
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
10670 10671 10672 10673 10674
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
10675 10676 10677
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
10678 10679 10680 10681 10682 10683 10684 10685 10686
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }

10687 10688
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706
        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;
10707
# if VBOX_API_VERSION >= 4003000
R
Ryota Ozaki 已提交
10708 10709
                PRInt32 xOrigin, yOrigin;
# endif
10710 10711 10712

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
10713
# if VBOX_API_VERSION < 4003000
10714
                                                        &bitsPerPixel);
R
Ryota Ozaki 已提交
10715 10716 10717 10718
# else
                                                        &bitsPerPixel,
                                                        &xOrigin, &yOrigin);
# endif
10719 10720

                if (NS_FAILED(rc) || !width || !height) {
10721 10722
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
10723 10724 10725 10726 10727 10728 10729 10730
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
10731 10732
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747
                    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;
                }

10748 10749 10750
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;

E
Eric Blake 已提交
10751
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
10752 10753
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
10754
                    VIR_FREE(ret);
10755
                }
10756
 endjob:
10757 10758 10759 10760 10761 10762 10763 10764 10765
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
10766
    unlink(tmp);
10767 10768 10769 10770 10771
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
10772
#endif /* VBOX_API_VERSION >= 4000000 */
10773

10774 10775 10776

#define MATCH(FLAG) (flags & (FLAG))
static int
10777 10778 10779
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
10780 10781 10782 10783 10784 10785 10786 10787 10788
{
    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;
10789
    size_t i;
10790 10791 10792 10793 10794 10795
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
10796
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810

    /* 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)
10811
            goto cleanup;
10812 10813 10814 10815 10816 10817 10818

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
10819 10820
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
10821 10822 10823 10824 10825
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
10826
        goto cleanup;
10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843

    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 已提交
10844
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
10845 10846 10847 10848 10849
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
10850
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
10851 10852
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
10853
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
10854
                                       _("could not get snapshot count for listed domains"));
10855 10856 10857 10858 10859 10860 10861 10862 10863 10864
                        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 已提交
10865
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915
                    !((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;

10916
 cleanup:
10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930
    if (doms) {
        for (i = 0; i < count; i++) {
            if (doms[i])
                virDomainFree(doms[i]);
        }
    }
    VIR_FREE(doms);

    vboxArrayRelease(&machines);
    return ret;
}
#undef MATCH


10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951
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)
{
10952 10953 10954 10955
    unsigned long long freeMem;
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;
    return freeMem;
10956 10957
}

10958

10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972
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 已提交
10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045
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 已提交
11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076
#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 */

T
Taowei 已提交
11077 11078 11079 11080 11081
static void* _handleGetMachines(IVirtualBox *vboxObj)
{
    return vboxObj->vtbl->GetMachines;
}

T
Taowei 已提交
11082 11083 11084 11085 11086
static nsresult _nsisupportsRelease(nsISupports *nsi)
{
    return nsi->vtbl->Release(nsi);
}

T
Taowei 已提交
11087 11088 11089 11090 11091 11092
static nsresult
_virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16)
{
    return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16);
}

T
Taowei 已提交
11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110
#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 已提交
11111 11112 11113 11114 11115 11116
static nsresult
_virtualboxGetSystemProperties(IVirtualBox *vboxObj, ISystemProperties **systemProperties)
{
    return vboxObj->vtbl->GetSystemProperties(vboxObj, systemProperties);
}

T
Taowei 已提交
11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128
static nsresult
_machineGetAccessible(IMachine *machine, PRBool *isAccessible)
{
    return machine->vtbl->GetAccessible(machine, isAccessible);
}

static nsresult
_machineGetState(IMachine *machine, PRUint32 *state)
{
    return machine->vtbl->GetState(machine, state);
}

T
Taowei 已提交
11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140
static nsresult
_machineGetName(IMachine *machine, PRUnichar **name)
{
    return machine->vtbl->GetName(machine, name);
}

static nsresult
_machineGetId(IMachine *machine, vboxIIDUnion *iidu)
{
    return machine->vtbl->GetId(machine, &IID_MEMBER(value));
}

T
Taowei 已提交
11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198
#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 已提交
11199 11200 11201 11202 11203 11204
static nsresult
_systemPropertiesGetMaxGuestCPUCount(ISystemProperties *systemProperties, PRUint32 *maxCPUCount)
{
    return systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, maxCPUCount);
}

T
Taowei 已提交
11205 11206 11207 11208 11209 11210
static bool _machineStateOnline(PRUint32 state)
{
    return ((state >= MachineState_FirstOnline) &&
            (state <= MachineState_LastOnline));
}

T
Taowei 已提交
11211 11212 11213 11214 11215 11216 11217 11218 11219 11220
static vboxUniformedPFN _UPFN = {
    .Initialize = _pfnInitialize,
    .Uninitialize = _pfnUninitialize,
    .ComUnallocMem = _pfnComUnallocMem,
    .Utf16Free = _pfnUtf16Free,
    .Utf8Free = _pfnUtf8Free,
    .Utf16ToUtf8 = _pfnUtf16ToUtf8,
    .Utf8ToUtf16 = _pfnUtf8ToUtf16,
};

T
Taowei 已提交
11221 11222 11223 11224 11225 11226 11227 11228 11229 11230
static vboxUniformedIID _UIID = {
    .vboxIIDInitialize = _vboxIIDInitialize,
    .vboxIIDUnalloc = _vboxIIDUnalloc,
    .vboxIIDToUUID = _vboxIIDToUUID,
    .vboxIIDFromUUID = _vboxIIDFromUUID,
    .vboxIIDIsEqual = _vboxIIDIsEqual,
    .vboxIIDFromArrayItem = _vboxIIDFromArrayItem,
    .DEBUGIID = _DEBUGIID,
};

T
Taowei 已提交
11231 11232 11233 11234 11235 11236
static vboxUniformedArray _UArray = {
    .vboxArrayGet = vboxArrayGet,
    .vboxArrayRelease = vboxArrayRelease,
    .handleGetMachines = _handleGetMachines,
};

T
Taowei 已提交
11237 11238 11239 11240
static vboxUniformednsISupports _nsUISupports = {
    .Release = _nsisupportsRelease,
};

T
Taowei 已提交
11241 11242
static vboxUniformedIVirtualBox _UIVirtualBox = {
    .GetVersion = _virtualboxGetVersion,
T
Taowei 已提交
11243
    .GetMachine = _virtualboxGetMachine,
T
Taowei 已提交
11244
    .GetSystemProperties = _virtualboxGetSystemProperties,
T
Taowei 已提交
11245 11246
};

T
Taowei 已提交
11247 11248 11249
static vboxUniformedIMachine _UIMachine = {
    .GetAccessible = _machineGetAccessible,
    .GetState = _machineGetState,
T
Taowei 已提交
11250 11251
    .GetName = _machineGetName,
    .GetId = _machineGetId,
T
Taowei 已提交
11252 11253
};

T
Taowei 已提交
11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266
static vboxUniformedISession _UISession = {
    .OpenExisting = _sessionOpenExisting,
    .GetConsole = _sessionGetConsole,
    .Close = _sessionClose,
};

static vboxUniformedIConsole _UIConsole = {
    .SaveState = _consoleSaveState,
};

static vboxUniformedIProgress _UIProgress = {
    .WaitForCompletion = _progressWaitForCompletion,
    .GetResultCode = _progressGetResultCode,
T
Taowei 已提交
11267 11268
};

T
Taowei 已提交
11269 11270 11271 11272
static vboxUniformedISystemProperties _UISystemProperties = {
    .GetMaxGuestCPUCount = _systemPropertiesGetMaxGuestCPUCount,
};

T
Taowei 已提交
11273 11274 11275 11276
static uniformedMachineStateChecker _machineStateChecker = {
    .Online = _machineStateOnline,
};

T
Taowei 已提交
11277 11278 11279 11280 11281 11282 11283
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 已提交
11284
    pVBoxAPI->UIID = _UIID;
T
Taowei 已提交
11285
    pVBoxAPI->UArray = _UArray;
T
Taowei 已提交
11286
    pVBoxAPI->nsUISupports = _nsUISupports;
T
Taowei 已提交
11287
    pVBoxAPI->UIVirtualBox = _UIVirtualBox;
T
Taowei 已提交
11288
    pVBoxAPI->UIMachine = _UIMachine;
T
Taowei 已提交
11289 11290 11291
    pVBoxAPI->UISession = _UISession;
    pVBoxAPI->UIConsole = _UIConsole;
    pVBoxAPI->UIProgress = _UIProgress;
T
Taowei 已提交
11292
    pVBoxAPI->UISystemProperties = _UISystemProperties;
T
Taowei 已提交
11293
    pVBoxAPI->machineStateChecker = _machineStateChecker;
T
Taowei 已提交
11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306

#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 已提交
11307 11308 11309 11310 11311 11312
#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 已提交
11313
}
11314

11315 11316 11317 11318
/**
 * Function Tables
 */

11319
virDriver NAME(Driver) = {
11320 11321
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
11322 11323 11324
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
11325
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
11326
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
11327
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
11328 11329 11330 11331
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
11332 11333 11334 11335 11336 11337 11338
    .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 */
11339
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
11340 11341
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
11342
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
11343 11344 11345 11346 11347 11348 11349 11350 11351 11352
    .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 */
11353 11354
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
11355 11356 11357 11358
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
11359
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
11360 11361 11362 11363 11364
    .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 */
11365 11366
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
11367
#if VBOX_API_VERSION >= 4000000
11368
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
11369
#endif
11370
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
11371 11372
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
11373
#endif
11374 11375
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
11376 11377 11378
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
11379
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
11380 11381
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
11382
#endif
11383 11384 11385 11386 11387 11388
    .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 */
11389
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
11390
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
11391 11392
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
11393 11394
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
11395
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
11396
    .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */
11397
};
11398 11399 11400

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
11401 11402
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
11403 11404 11405 11406
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
11407 11408 11409 11410 11411 11412 11413 11414
    .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 */
11415
};
11416 11417 11418

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
11419 11420
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
11421 11422
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434
    .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 */
11435
};