vbox_tmpl.c 417.1 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 257
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);

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

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

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

273 274
#endif

275
#if VBOX_API_VERSION == 2002000
276

277 278
static void nsIDtoChar(unsigned char *uuid, const nsID *iid)
{
279 280 281
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
282
    size_t i;
283 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

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

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

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

318 319
static void nsIDFromChar(nsID *iid, const unsigned char *uuid)
{
320 321 322
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
323
    size_t i;
324 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

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

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

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

359
# ifdef WIN32
360

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    iid->value = NULL;
}

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

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

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

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

    iid->value = &iid->backing;

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

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

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

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

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

    iid->value = &iid->backing;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

599
    vboxIIDUnalloc_v3_x(data, iid);
600

601
    virUUIDFormat(uuid, utf8);
602

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

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

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

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

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

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

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

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

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

655 656 657 658 659 660 661 662

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

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

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

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

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

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

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

717
    name = virIndexToDiskName(total, prefix);
718

719
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
720
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
721
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
722 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
          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;

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

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

    total = virDiskNameToIndex(deviceName);

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

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

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

779
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
          "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,
800 801
                                     PRUint32 *maxSlotPerPort)
{
802 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
    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
 */
846 847
static int PRUnicharToInt(PRUnichar *strUtf16)
{
848 849 850 851 852 853 854 855 856 857
    char *strUtf8 = NULL;
    int ret = 0;

    if (!strUtf16)
        return -1;

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

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

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

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

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

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

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

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

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

    result = 0;

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

    return result;
}

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

934 935 936 937 938
    virDomainPtr dom;

    virCheckFlags(0, NULL);

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

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

    return dom;
}

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

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

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

975 976
        if (!machine)
            continue;
977

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

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

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

986
                PRUint32 state;
987

988
                matched = 1;
989

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

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

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

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

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

1016
    vboxArrayRelease(&machines);
1017 1018

    return ret;
1019 1020
}

1021

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

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

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

        if (!machine)
            continue;

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

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

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

1059
                PRUint32 state;
1060

1061
                matched = 1;
1062

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

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

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

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

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

1085 1086 1087 1088
    return ret;
}


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

    ret = 1;

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


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

    ret = 0;

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

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

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

1158 1159
    if (!machine)
        goto cleanup;
1160

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

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

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

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

1201
    PRBool isAccessible = PR_FALSE;
1202

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

1211 1212
    if (!machine)
        goto cleanup;
1213

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

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

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

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

1256 1257
    virCheckFlags(0, -1);

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

1266 1267
    if (!machine)
        goto cleanup;
1268

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

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

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

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

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


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

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

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

1325 1326
    if (!machine)
        goto cleanup;
1327

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

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

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

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

1366 1367
    virCheckFlags(0, -1);

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

1376 1377
    if (!machine)
        goto cleanup;
1378

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

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

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

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

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

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

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

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

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

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

1451 1452
    if (!machine)
        goto cleanup;
1453

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

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

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

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

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

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

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

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

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

1534 1535
        if (!machine)
            continue;
1536

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

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


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

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

1576
                ret = 0;
1577 1578
            }

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

    }

1587
    vboxArrayRelease(&machines);
1588

1589
 cleanup:
1590 1591 1592
    return ret;
}

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

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

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

    if (reason)
        *reason = 0;

    ret = 0;

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

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

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

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

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

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

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

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

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

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

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

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

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

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

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

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

    if (!USBDeviceFilters)
        return;

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

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

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

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

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

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

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

    return;

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

    goto release_filters;
1851 1852
}

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

1861 1862
    /* Flags checked by virDomainDefFormat */

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

2003 2004 2005 2006 2007
                VBOX_RELEASE(bios);
            }

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

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

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

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

2052
                def->ngraphics = 0;
2053

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

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

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

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

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

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

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

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

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

2106 2107
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2108

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

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

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

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

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

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

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

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

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

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

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

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

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

2242 2243 2244 2245
            VBOX_UTF16_FREE(hddBusUtf16);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            /* get the attachment details here */
2362 2363
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2364 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
                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;
                }
2397

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

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

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

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

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

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

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

2462
            vboxArrayRelease(&mediumAttachments);
2463

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

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

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

            def->nfss = 0;

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

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

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

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

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

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

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

                    ++def->nfss;
                }
            }

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

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

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

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

2545 2546 2547
                    VBOX_RELEASE(adapter);
                }
            }
2548

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                            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;

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

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

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

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

                        netAdpIncCnt++;

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

                    VBOX_RELEASE(adapter);
2670
                }
2671
            }
2672

2673
            /* dump sound card if active */
2674

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

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

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

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

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

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

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

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

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

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

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

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

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

2817
                    VBOX_RELEASE(serialPort);
2818
                }
2819
            }
2820

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

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

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

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

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

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

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

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

2876 2877 2878 2879
                        serialPortIncCount++;

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

2882 2883 2884
                    VBOX_RELEASE(serialPort);
                }
            }
2885

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

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

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

                    VBOX_RELEASE(parallelPort);
2902
                }
2903
            }
2904

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

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

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

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

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

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

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

2946 2947 2948 2949
                        parallelPortIncCount++;

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

                    VBOX_RELEASE(parallelPort);
2953
                }
2954
            }
2955

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

E
Eric Blake 已提交
3069 3070

static int
3071
vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3072
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3073 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
{
    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);

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

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

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

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

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

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

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

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

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

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

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

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

    VBOX_RELEASE(progress);

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

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

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

3241 3242
    virCheckFlags(0, -1);

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

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

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

3260 3261
        if (!machine)
            continue;
3262

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

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

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

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

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

3297
 cleanup:
3298 3299 3300
    return ret;
}

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

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

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

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

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

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

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

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

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

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

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

3407
                    VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
3408

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

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

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

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

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

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

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

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

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

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

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

E
Eric Blake 已提交
3572 3573
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
3574
                                                                  &fduuid.value);
E
Eric Blake 已提交
3575
                            if (NS_FAILED(rc)) {
3576 3577 3578
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
3579
                                               src, (unsigned)rc);
E
Eric Blake 已提交
3580 3581
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
3582
                                                                   fduuid.value);
E
Eric Blake 已提交
3583
                                if (NS_FAILED(rc)) {
3584 3585 3586
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
3587
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
3588
                                } else {
3589
                                    DEBUGIID("floppyImage UUID", fduuid.value);
3590 3591
                                }
                            }
E
Eric Blake 已提交
3592
                            VBOX_MEDIUM_RELEASE(floppyImage);
3593
                        }
3594
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
3595
                        VBOX_UTF16_FREE(fdfileUtf16);
3596
                    }
E
Eric Blake 已提交
3597
                    VBOX_RELEASE(floppyDrive);
3598
                }
E
Eric Blake 已提交
3599
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3600
            }
3601
        }
E
Eric Blake 已提交
3602
    }
3603
#else  /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615
    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 */
3616
    {
E
Eric Blake 已提交
3617 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
        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);
    }
3652

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if (!USBDeviceFilters)
        return;
4484
#endif
4485

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4777
    return ret;
4778

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

4786 4787 4788 4789 4790 4791
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

4792 4793
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
4794 4795
                                      int mediaChangeOnly ATTRIBUTE_UNUSED)
{
4796
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
4797
    IMachine *machine    = NULL;
4798
    vboxIID iid = VBOX_IID_INITIALIZER;
4799 4800 4801
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
4802
    nsresult rc;
4803

4804
    if (VIR_ALLOC(def) < 0)
4805 4806
        return ret;

4807
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
4808 4809
        goto cleanup;

4810 4811
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
4812
    if (dev == NULL)
4813 4814
        goto cleanup;

4815
    vboxIIDFromUUID(&iid, dom->uuid);
4816
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
4817
    if (NS_FAILED(rc)) {
4818 4819
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
4820 4821
        goto cleanup;
    }
4822

4823 4824
    if (machine) {
        machine->vtbl->GetState(machine, &state);
4825

4826 4827
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
4828
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
4829
        } else {
4830
            rc = VBOX_SESSION_OPEN(iid.value, machine);
4831 4832 4833 4834 4835
        }
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
4836
#if VBOX_API_VERSION < 3001000
4837 4838 4839
                    const char *src = virDomainDiskGetSource(dev->data.disk);
                    int type = virDomainDiskGetType(dev->data.disk);

4840
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
4841
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
4842 4843 4844 4845 4846 4847 4848 4849 4850
                            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;
4851 4852
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
4853

4854
                                VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
4855

4856 4857
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
4858
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
4859 4860
                                }
                                if (dvdImage) {
4861
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
4862
                                    if (NS_FAILED(rc)) {
4863 4864 4865
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
4866
                                                       src, (unsigned)rc);
4867 4868 4869
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
4870
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
4871
                                        if (NS_FAILED(rc)) {
4872 4873
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
4874
                                                           src, (unsigned)rc);
4875
                                        } else {
4876
                                            ret = 0;
4877
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
4878 4879
                                        }
                                    }
4880 4881

                                    VBOX_MEDIUM_RELEASE(dvdImage);
4882
                                }
4883
                                vboxIIDUnalloc(&dvduuid);
4884 4885
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
4886
                            }
E
Eric Blake 已提交
4887
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
4888 4889
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
4890
                        if (type == VIR_STORAGE_TYPE_FILE && src) {
4891 4892 4893 4894 4895 4896 4897
                            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;
4898 4899
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
4900
                                    VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
4901 4902 4903 4904 4905 4906 4907
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
4908
                                                                             fdemptyuuid.value,
4909 4910
                                                                             &floppyImage);
                                    }
4911

4912
                                    if (floppyImage) {
4913
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
4914
                                        if (NS_FAILED(rc)) {
4915 4916 4917
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
4918
                                                           src, (unsigned)rc);
4919
                                        } else {
4920
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
4921
                                            if (NS_FAILED(rc)) {
4922 4923
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
4924
                                                               src, (unsigned)rc);
4925
                                            } else {
4926
                                                ret = 0;
4927
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
4928 4929
                                            }
                                        }
4930
                                        VBOX_MEDIUM_RELEASE(floppyImage);
4931
                                    }
4932
                                    vboxIIDUnalloc(&fduuid);
4933
                                    VBOX_UTF16_FREE(fdfileUtf16);
4934
                                }
4935
                                VBOX_RELEASE(floppyDrive);
4936
                            }
E
Eric Blake 已提交
4937
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
4938
                        }
4939
                    }
4940 4941
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
4942 4943 4944 4945
                } 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) {
4946 4947
                        }
                    }
M
Matthias Bolte 已提交
4948 4949 4950 4951 4952 4953 4954 4955 4956 4957
                } 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;

4958
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
4959 4960
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable);
4961
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
4962 4963
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable, PR_FALSE);
4964
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
4965 4966

                    if (NS_FAILED(rc)) {
4967 4968 4969
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
4970 4971 4972 4973 4974 4975
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
4976
                }
4977 4978
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
4979
            }
4980
            VBOX_SESSION_CLOSE();
4981 4982 4983
        }
    }

4984
 cleanup:
4985
    vboxIIDUnalloc(&iid);
4986 4987 4988 4989 4990
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

4991 4992
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
{
4993 4994 4995
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

4996 4997 4998 4999 5000 5001
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5002
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5003 5004
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5005 5006 5007
        return -1;
    }

5008 5009 5010 5011
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
5012 5013
                                       unsigned int flags)
{
5014 5015 5016
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5017

5018
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5019 5020
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5021 5022 5023 5024
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5025 5026
}

5027 5028
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
{
5029
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5030
    IMachine *machine    = NULL;
5031
    vboxIID iid = VBOX_IID_INITIALIZER;
5032 5033 5034
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5035
    nsresult rc;
5036

5037
    if (VIR_ALLOC(def) < 0)
5038 5039
        return ret;

5040
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5041 5042
        goto cleanup;

5043 5044
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5045
    if (dev == NULL)
5046 5047
        goto cleanup;

5048
    vboxIIDFromUUID(&iid, dom->uuid);
5049
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5050
    if (NS_FAILED(rc)) {
5051 5052
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5053 5054
        goto cleanup;
    }
5055

5056 5057
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5058

5059 5060
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5061
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5062
        } else {
5063
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5064
        }
5065

5066 5067 5068 5069
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5070
#if VBOX_API_VERSION < 3001000
5071 5072
                    int type = virDomainDiskGetType(dev->data.disk);

5073
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
5074
                        if (type == VIR_STORAGE_TYPE_FILE) {
5075 5076 5077 5078 5079 5080 5081 5082 5083
                            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)) {
5084 5085 5086
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5087 5088 5089 5090 5091
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
E
Eric Blake 已提交
5092
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5093 5094
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
E
Eric Blake 已提交
5095
                        if (type == VIR_STORAGE_TYPE_FILE) {
5096 5097 5098 5099 5100 5101 5102 5103
                            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);
5104
                                    if (NS_FAILED(rc)) {
5105 5106 5107 5108
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5109 5110 5111
                                    } else {
                                        ret = 0;
                                    }
5112 5113 5114 5115 5116
                                } 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;
5117
                                }
5118
                                VBOX_RELEASE(floppyDrive);
5119
                            }
E
Eric Blake 已提交
5120
                        } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5121
                        }
5122
                    }
5123 5124
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5125 5126 5127 5128
                } 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) {
5129 5130
                        }
                    }
M
Matthias Bolte 已提交
5131 5132 5133 5134 5135 5136 5137 5138 5139
                } 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)) {
5140 5141 5142
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5143 5144 5145 5146 5147
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5148
                }
5149 5150
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5151
            }
5152
            VBOX_SESSION_CLOSE();
5153 5154 5155
        }
    }

5156
 cleanup:
5157
    vboxIIDUnalloc(&iid);
5158 5159 5160 5161 5162
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5163 5164 5165 5166 5167 5168
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5169
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5170 5171
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5172 5173 5174 5175 5176 5177
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5178 5179 5180 5181 5182
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5183
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5184 5185 5186 5187 5188 5189 5190 5191
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5192 5193 5194
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5195 5196 5197 5198 5199 5200
        goto error;
    }

    if (count == 0)
        goto out;

5201
    if (VIR_ALLOC_N(list, count) < 0)
J
Jiri Denemark 已提交
5202 5203
        goto error;

5204
#if VBOX_API_VERSION < 4000000
5205
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5206
#else /* VBOX_API_VERSION >= 4000000 */
5207
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
5208
#endif /* VBOX_API_VERSION >= 4000000 */
J
Jiri Denemark 已提交
5209
    if (NS_FAILED(rc) || !list[0]) {
5210 5211 5212
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5213 5214 5215 5216 5217 5218
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5219
        vboxArray children = VBOX_ARRAY_INITIALIZER;
5220
        size_t i;
J
Jiri Denemark 已提交
5221 5222

        if (!list[next]) {
5223 5224
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5225 5226 5227
            goto error;
        }

5228 5229
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5230
        if (NS_FAILED(rc)) {
5231 5232
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5233 5234
            goto error;
        }
5235 5236 5237
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5238 5239
                continue;
            if (top == count) {
5240 5241
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5242
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5243 5244
                goto error;
            }
5245 5246
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5247
        }
5248
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5249 5250
    }

5251
 out:
J
Jiri Denemark 已提交
5252 5253 5254
    *snapshots = list;
    return count;

5255
 error:
J
Jiri Denemark 已提交
5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274
    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;
5275
    size_t i;
J
Jiri Denemark 已提交
5276 5277 5278 5279 5280 5281 5282 5283 5284 5285

    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) {
5286 5287
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300
            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) {
5301 5302 5303
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
5304 5305 5306
        goto cleanup;
    }

5307
 cleanup:
J
Jiri Denemark 已提交
5308 5309 5310 5311 5312 5313 5314 5315 5316 5317
    if (count > 0) {
        for (i = 0; i < count; i++) {
            if (snapshots[i] != snapshot)
                VBOX_RELEASE(snapshots[i]);
        }
    }
    VIR_FREE(snapshots);
    return snapshot;
}

5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 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
#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]);
5569 5570 5571 5572 5573
            if (parentUuid == NULL) {
                VIR_FREE(readWriteDisk);
                goto cleanup;
            }

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 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 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
            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 已提交
6275 6276 6277
static virDomainSnapshotPtr
vboxDomainSnapshotCreateXML(virDomainPtr dom,
                            const char *xmlDesc,
6278
                            unsigned int flags)
J
Jiri Denemark 已提交
6279 6280 6281
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
6282
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6283 6284 6285 6286 6287 6288 6289 6290
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
6291
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
6292 6293 6294 6295
    nsresult result;
#else
    PRInt32 result;
#endif
6296 6297 6298 6299
#if VBOX_API_VERSION >= 4002000
    bool isCurrent = false;
#endif

J
Jiri Denemark 已提交
6300

6301
    /* VBox has no snapshot metadata, so this flag is trivial.  */
6302 6303 6304
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
                  VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT, NULL);
6305

6306
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
6307 6308 6309
                                                data->xmlopt, -1,
                                                VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
                                                VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE)))
J
Jiri Denemark 已提交
6310 6311
        goto cleanup;

6312

6313
    vboxIIDFromUUID(&domiid, dom->uuid);
6314
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6315
    if (NS_FAILED(rc)) {
6316 6317
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6318 6319 6320
        goto cleanup;
    }

6321 6322 6323 6324 6325 6326 6327 6328 6329 6330
#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 已提交
6331 6332
    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6333 6334
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6335 6336 6337 6338 6339
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
6340
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
6341
    } else {
6342
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6343
    }
6344

J
Jiri Denemark 已提交
6345 6346 6347
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6348 6349 6350
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369
        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) {
6370 6371
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6372 6373 6374 6375 6376 6377
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6378 6379
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6380 6381 6382 6383 6384
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6385 6386
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
6387 6388 6389 6390 6391 6392
                  dom->name);
        goto cleanup;
    }

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

6393
 cleanup:
J
Jiri Denemark 已提交
6394 6395 6396 6397
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
6398
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6399
    VBOX_RELEASE(machine);
6400
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6401 6402 6403 6404
    virDomainSnapshotDefFree(def);
    return ret;
}

6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476
#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;
6477 6478 6479 6480
    for (i = 0; i < def->ndisks; i++) {
        if (VIR_ALLOC(def->disks[i].src) < 0)
            goto cleanup;
    }
6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578

    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",
6579
                                       _("cannot get medium attachment type"));
6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607
                        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) {
6608 6609 6610 6611 6612
        for (i = 0; i < def->ndisks; i++) {
            VIR_FREE(def->disks[i].src);
        }
        VIR_FREE(def->disks);
        def->ndisks = 0;
6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685
    }
    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++) {
6686 6687
            virDomainDiskDefPtr diskDef = virDomainDiskDefNew();
            if (!diskDef)
6688
                goto cleanup;
6689
            def->dom->disks[i] = diskDef;
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 6755 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 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799
        }
    } 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)
6800
            def->dom->disks[diskCount]->src->readonly = true;
6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823
        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++)
6824
            virDomainDiskDefFree(def->dom->disks[i]);
6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835
        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 已提交
6836
static char *
6837 6838
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
6839 6840 6841
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
6842
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6843 6844 6845 6846 6847 6848 6849 6850 6851 6852
    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];
6853 6854 6855 6856
#if VBOX_API_VERSION >=4002000
    PRUint32 memorySize                 = 0;
    PRUint32 CPUCount                 = 0;
#endif
J
Jiri Denemark 已提交
6857

6858 6859
    virCheckFlags(0, NULL);

6860
    vboxIIDFromUUID(&domiid, dom->uuid);
6861
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6862
    if (NS_FAILED(rc)) {
6863 6864
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6865 6866 6867 6868 6869 6870
        goto cleanup;
    }

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

6871
    if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0)
6872
        goto cleanup;
6873 6874
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
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
#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 已提交
6906 6907
    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
6908 6909 6910
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6911 6912 6913 6914 6915
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6916 6917 6918 6919
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
6920 6921 6922 6923 6924
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
6925 6926 6927
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6928 6929 6930 6931 6932 6933 6934
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6935 6936 6937
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6938 6939 6940 6941 6942
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
6943 6944 6945
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
6946 6947 6948 6949
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6950 6951
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
6952
            goto cleanup;
6953 6954
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
6955 6956 6957 6958
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
6959 6960 6961
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6962 6963 6964 6965 6966 6967 6968 6969
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

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

6973
 cleanup:
J
Jiri Denemark 已提交
6974 6975 6976 6977
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
6978
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6979 6980 6981 6982 6983
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
6984
                      unsigned int flags)
J
Jiri Denemark 已提交
6985 6986
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6987
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6988 6989 6990 6991
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

6992 6993
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6994

6995
    vboxIIDFromUUID(&iid, dom->uuid);
6996
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6997
    if (NS_FAILED(rc)) {
6998 6999
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7000 7001 7002
        goto cleanup;
    }

7003 7004 7005 7006 7007 7008
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
7009 7010
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
7011 7012 7013
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7014 7015 7016
        goto cleanup;
    }

7017 7018 7019 7020 7021
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
7022

7023
 cleanup:
J
Jiri Denemark 已提交
7024
    VBOX_RELEASE(machine);
7025
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7026 7027 7028 7029 7030 7031 7032
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
7033
                            unsigned int flags)
J
Jiri Denemark 已提交
7034 7035
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7036
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7037 7038 7039 7040
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
7041
    size_t i;
J
Jiri Denemark 已提交
7042

7043 7044
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
7045

7046
    vboxIIDFromUUID(&iid, dom->uuid);
7047
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7048
    if (NS_FAILED(rc)) {
7049 7050
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7051 7052 7053
        goto cleanup;
    }

7054 7055 7056 7057 7058
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

7059 7060 7061
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

7062
        if (VIR_ALLOC_N(snapshots, 1) < 0)
7063
            goto cleanup;
7064
#if VBOX_API_VERSION < 4000000
7065
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
7066
#else /* VBOX_API_VERSION >= 4000000 */
7067
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
7068
#endif /* VBOX_API_VERSION >= 4000000 */
7069
        if (NS_FAILED(rc) || !snapshots[0]) {
7070 7071 7072
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
7073 7074 7075 7076 7077 7078 7079
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
7080 7081 7082 7083 7084 7085 7086 7087 7088 7089

    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) {
7090 7091
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
7092 7093 7094 7095
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
7096 7097
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
7098 7099
            goto cleanup;
        }
7100
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
7101 7102 7103 7104 7105 7106 7107
    }

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

7108
 cleanup:
J
Jiri Denemark 已提交
7109 7110 7111 7112 7113 7114
    if (count > 0) {
        for (i = 0; i < count; i++)
            VBOX_RELEASE(snapshots[i]);
    }
    VIR_FREE(snapshots);
    VBOX_RELEASE(machine);
7115
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7116 7117 7118 7119 7120 7121
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
7122
                               unsigned int flags)
J
Jiri Denemark 已提交
7123 7124
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
7125
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7126 7127 7128 7129
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

7130 7131
    virCheckFlags(0, NULL);

7132
    vboxIIDFromUUID(&iid, dom->uuid);
7133
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
7134
    if (NS_FAILED(rc)) {
7135 7136
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7137 7138 7139 7140 7141 7142 7143 7144
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

7145
 cleanup:
J
Jiri Denemark 已提交
7146 7147
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
7148
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7149 7150 7151 7152 7153
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
7154
                             unsigned int flags)
J
Jiri Denemark 已提交
7155 7156
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7157
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7158 7159 7160 7161
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

7162 7163
    virCheckFlags(0, -1);

7164
    vboxIIDFromUUID(&iid, dom->uuid);
7165
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
7166
    if (NS_FAILED(rc)) {
7167 7168
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7169 7170 7171 7172 7173
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
7174 7175
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
7176 7177 7178 7179 7180 7181 7182 7183
        goto cleanup;
    }

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

7184
 cleanup:
J
Jiri Denemark 已提交
7185
    VBOX_RELEASE(machine);
7186
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7187 7188 7189
    return ret;
}

7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208
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)) {
7209 7210
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7211 7212 7213 7214 7215 7216 7217 7218
        goto cleanup;
    }

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

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
7219 7220 7221
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
7222 7223 7224
        goto cleanup;
    }
    if (!parent) {
7225 7226 7227
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
7228 7229 7230 7231 7232
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7233 7234 7235
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
7236 7237 7238 7239 7240 7241 7242 7243 7244 7245
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

7246
 cleanup:
7247 7248 7249 7250 7251 7252 7253 7254 7255
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

J
Jiri Denemark 已提交
7256 7257
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
7258
                          unsigned int flags)
J
Jiri Denemark 已提交
7259 7260
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
7261
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7262 7263 7264 7265 7266 7267
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

7268 7269
    virCheckFlags(0, NULL);

7270
    vboxIIDFromUUID(&iid, dom->uuid);
7271
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
7272
    if (NS_FAILED(rc)) {
7273 7274
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7275 7276 7277 7278 7279
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
7280 7281
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
7282 7283 7284 7285
        goto cleanup;
    }

    if (!snapshot) {
7286 7287
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
7288 7289 7290 7291 7292
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7293 7294
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

7306
 cleanup:
J
Jiri Denemark 已提交
7307 7308 7309 7310
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
7311
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7312 7313 7314
    return ret;
}

7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333
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)) {
7334 7335
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
7336 7337 7338 7339 7340 7341 7342 7343
        goto cleanup;
    }

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
7344 7345
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
7346 7347 7348 7349 7350 7351 7352 7353 7354
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
7355 7356
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367
        goto cleanup;
    }

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

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

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

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

    ret = 0;

7405
 cleanup:
7406 7407 7408 7409 7410 7411
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

7412
#if VBOX_API_VERSION < 3001000
J
Jiri Denemark 已提交
7413 7414 7415 7416 7417 7418
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7419
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7420 7421
    nsresult rc;

7422 7423
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
7424 7425
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
7426 7427 7428
        goto cleanup;
    }

7429
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
7430
    if (NS_FAILED(rc)) {
7431 7432
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
7433 7434 7435 7436 7437
        goto cleanup;
    }

    ret = 0;

7438
 cleanup:
7439
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453
    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;
7454
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7455

7456 7457
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
7458 7459
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
7460 7461 7462 7463 7464
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
7465 7466
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
7467 7468 7469 7470 7471
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
7472 7473
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
7474 7475 7476
        goto cleanup;
    }

7477
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
7478 7479 7480
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
7481 7482 7483
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7484 7485 7486 7487 7488 7489
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
7490 7491
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
7492
        } else {
7493 7494 7495
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
7496 7497 7498 7499 7500 7501 7502
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
7503 7504
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
7505 7506 7507 7508 7509
        goto cleanup;
    }

    ret = 0;

7510
 cleanup:
J
Jiri Denemark 已提交
7511 7512
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
7513
    VBOX_SESSION_CLOSE();
7514
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7515 7516 7517 7518 7519 7520
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
7521
                           unsigned int flags)
J
Jiri Denemark 已提交
7522 7523 7524
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
7525
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7526 7527 7528 7529 7530 7531 7532
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

7533 7534
    virCheckFlags(0, -1);

7535
    vboxIIDFromUUID(&domiid, dom->uuid);
7536
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
7537
    if (NS_FAILED(rc)) {
7538 7539
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
7540 7541 7542 7543 7544 7545 7546 7547 7548
        goto cleanup;
    }

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

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
7549 7550 7551
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
7552 7553 7554 7555 7556
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
7557 7558 7559
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
7560 7561 7562 7563 7564
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
7565 7566
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
7567 7568 7569 7570 7571
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
7572 7573
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586
        goto cleanup;
    }

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

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

7587
 cleanup:
J
Jiri Denemark 已提交
7588 7589
    VBOX_RELEASE(prevSnapshot);
    VBOX_RELEASE(newSnapshot);
7590
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
7591 7592 7593 7594 7595 7596 7597 7598 7599
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
7600
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
7601 7602
    int ret = -1;
    nsresult rc;
7603
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
7604 7605 7606 7607 7608
    nsresult result;
#else
    PRInt32 result;
#endif

7609 7610
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
7611 7612
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
7613 7614 7615
        goto cleanup;
    }

7616
#if VBOX_API_VERSION < 3001000
7617
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
7618
#else
7619
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
7620 7621 7622
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
7623 7624
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
7625
        } else {
7626 7627
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
7628 7629 7630 7631 7632 7633 7634
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
7635 7636
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
7637 7638 7639 7640 7641
        goto cleanup;
    }

    ret = 0;

7642
 cleanup:
J
Jiri Denemark 已提交
7643
    VBOX_RELEASE(progress);
7644
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
7645 7646 7647 7648 7649 7650 7651 7652
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
7653
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
7654 7655
    int ret = -1;
    nsresult rc;
7656
    size_t i;
J
Jiri Denemark 已提交
7657

7658
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
7659
    if (NS_FAILED(rc)) {
7660 7661
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
7662 7663 7664
        goto cleanup;
    }

7665 7666 7667
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
7668 7669 7670 7671
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

7672
 cleanup:
7673
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
7674 7675 7676
    return ret;
}

7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696
#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);
7697
    virDomainSnapshotDefPtr def = NULL;
7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712
    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;
7713

7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888
    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);
7889
                    VIR_FREE(disk);
7890 7891 7892 7893 7894 7895
                    goto cleanup;
                }
                VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
                disk->uuid = uuid;
                VBOX_UTF16_FREE(uuidUtf16);

7896 7897
                if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) {
                    VIR_FREE(disk);
7898
                    goto cleanup;
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 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 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

                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
8132

J
Jiri Denemark 已提交
8133 8134 8135 8136 8137 8138
static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
8139
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
8140 8141 8142 8143 8144
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;
8145
    vboxArray snapChildren = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
8146

8147 8148
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
8149

8150
    vboxIIDFromUUID(&domiid, dom->uuid);
8151
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
8152
    if (NS_FAILED(rc)) {
8153 8154
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
8155 8156 8157 8158 8159 8160 8161 8162 8163
        goto cleanup;
    }

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

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
8164 8165
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
8166 8167 8168
        goto cleanup;
    }

8169 8170 8171
    /* In case we just want to delete the metadata, we will edit the vbox file in order
     *to remove the node concerning the snapshot
    */
8172
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187
        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
        }
8188 8189 8190
        goto cleanup;
    }

J
Jiri Denemark 已提交
8191 8192
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
8193 8194
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
8195 8196 8197
        goto cleanup;
    }

8198
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
8199 8200 8201
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
8202 8203 8204
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
8205 8206 8207 8208 8209 8210 8211 8212
        goto cleanup;
    }

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

8213
 cleanup:
J
Jiri Denemark 已提交
8214 8215
    VBOX_RELEASE(console);
    VBOX_RELEASE(snap);
8216
    vboxIIDUnalloc(&domiid);
8217
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
8218 8219 8220
    return ret;
}

8221
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
8222
    /* No Callback support for VirtualBox 2.2.* series */
8223
    /* No Callback support for VirtualBox 4.* series */
8224
#else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
8225 8226

/* Functions needed for Callbacks */
8227
static nsresult PR_COM_METHOD
8228
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8229 8230
                                 PRUnichar *machineId, PRUint32 state)
{
8231 8232 8233 8234 8235 8236
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

8237
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
8238 8239 8240 8241 8242 8243 8244
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
8245
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
8246 8247 8248

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

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

8280
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
8281

8282
            if (ev)
8283
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
8284 8285 8286 8287 8288 8289 8290 8291
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

8292
static nsresult PR_COM_METHOD
8293
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8294 8295
                                PRUnichar *machineId)
{
8296
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8297 8298 8299 8300 8301
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

8302
static nsresult PR_COM_METHOD
8303
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8304 8305 8306
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
8307
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
8308
{
8309
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
8310 8311 8312 8313 8314 8315 8316
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

8317
static nsresult PR_COM_METHOD
8318 8319
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
8320 8321
                              PRUnichar *key, PRUnichar *value)
{
8322
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8323 8324 8325 8326 8327 8328 8329
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

8330
# if VBOX_API_VERSION < 3001000
8331
static nsresult PR_COM_METHOD
8332 8333 8334 8335
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
8336
{
8337 8338
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
8339 8340 8341 8342
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
8343 8344
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
8345

8346
static nsresult PR_COM_METHOD
8347
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8348 8349
                                PRUnichar *machineId, PRBool registered)
{
8350 8351 8352 8353 8354 8355
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

8356
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
8357 8358 8359 8360 8361 8362 8363
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
8364
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
8365 8366 8367

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
8368
            virObjectEventPtr ev;
8369 8370

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
8371
             * event because the when the machine is de-registered the call
8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383
             * 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;
            }

8384
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
8385

8386
            if (ev)
8387
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
8388 8389 8390 8391 8392 8393 8394 8395
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

8396
static nsresult PR_COM_METHOD
8397 8398 8399
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
8400
{
8401
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
8402 8403 8404 8405 8406
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

8407
static nsresult PR_COM_METHOD
8408 8409
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
8410 8411
                            PRUnichar *snapshotId)
{
8412
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8413 8414 8415 8416 8417 8418
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8419
static nsresult PR_COM_METHOD
8420 8421
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
8422 8423
                                PRUnichar *snapshotId)
{
8424
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8425 8426 8427 8428 8429 8430
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8431
static nsresult PR_COM_METHOD
8432 8433
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
8434 8435
                             PRUnichar *snapshotId)
{
8436
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8437 8438 8439 8440 8441 8442
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

8443
static nsresult PR_COM_METHOD
8444
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
8445 8446 8447
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
8448
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
8449 8450 8451 8452 8453 8454 8455 8456
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

8457
static nsresult PR_COM_METHOD
8458
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
8459
{
8460 8461 8462 8463
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

8464
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
8465 8466 8467 8468

    return c;
}

8469 8470 8471
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
8472 8473 8474 8475 8476 8477 8478 8479 8480
    nsresult c;

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

8481
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
8482 8483 8484 8485

    return c;
}

8486 8487 8488
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
8489 8490 8491 8492 8493
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
8494 8495
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
8496 8497 8498
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

8499
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
8500 8501 8502 8503 8504

        return NS_OK;
    }


8505
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
8506 8507 8508 8509 8510 8511
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


8512
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
8513 8514
    IVirtualBoxCallback *vboxCallback = NULL;

8515
    /* Allocate, Initialize and return a valid
8516 8517 8518
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
8519
        VIR_FREE(vboxCallback);
8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530
        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;
8531
# if VBOX_API_VERSION < 3001000
8532
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
8533 8534
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
8535 8536 8537
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
8538
# if VBOX_API_VERSION < 3002000
8539
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
8540
# else /* VBOX_API_VERSION >= 3002000 */
8541
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
8542
# endif /* VBOX_API_VERSION >= 3002000 */
8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554
        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,
8555 8556
                             void *opaque ATTRIBUTE_UNUSED)
{
8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568
    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);
    }
}

8569 8570 8571 8572 8573 8574
static int
vboxConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
{
8575
    VBOX_OBJECT_CHECK(conn, int, -1);
8576
    int vboxRet          = -1;
8577
    nsresult rc;
8578 8579 8580 8581 8582 8583

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

8584
    if (data->vboxCallback == NULL) {
8585
        data->vboxCallback = vboxAllocCallbackObj();
8586 8587 8588 8589
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
8590 8591
            }
        }
8592 8593 8594
    } else {
        vboxRet = 0;
    }
8595

8596 8597 8598 8599 8600 8601 8602
    /* 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);
8603

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

8607 8608 8609 8610 8611
        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
             */
8612

8613
            ret = virDomainEventStateRegister(conn, data->domainEvents,
8614
                                              callback, opaque, freecb);
8615
            VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
8616
                      "callback: %p, opaque: %p, "
8617
                      "freecb: %p)", ret, conn, callback,
8618
                      opaque, freecb);
8619 8620 8621 8622 8623 8624
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
8625
        return 0;
8626 8627 8628 8629 8630 8631 8632 8633
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

8634 8635 8636 8637
static int
vboxConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
{
8638
    VBOX_OBJECT_CHECK(conn, int, -1);
8639
    int cnt;
8640 8641 8642 8643 8644 8645

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

8646 8647
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
8648

8649 8650 8651
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
8652

8653 8654 8655
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
8656 8657 8658 8659
    }

    vboxDriverUnlock(data);

8660 8661 8662
    if (cnt >= 0)
        ret = 0;

8663 8664 8665
    return ret;
}

8666 8667 8668 8669 8670
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
8671 8672
                                             virFreeCallback freecb)
{
8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710
    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
             */

8711
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
8712 8713
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
8714
                ret = -1;
8715
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
8716
                      "callback: %p, opaque: %p, "
8717
                      "freecb: %p)", ret, conn, callback,
8718
                      opaque, freecb);
8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733
        }
    }

    vboxDriverUnlock(data);

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

8734 8735 8736 8737
static int
vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
{
8738
    VBOX_OBJECT_CHECK(conn, int, -1);
8739
    int cnt;
8740 8741 8742 8743 8744 8745

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

8746
    cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
8747
                                          callbackID);
8748

8749 8750 8751
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
8752

8753 8754 8755
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
8756 8757 8758 8759
    }

    vboxDriverUnlock(data);

8760 8761 8762
    if (cnt >= 0)
        ret = 0;

8763 8764 8765
    return ret;
}

8766
#endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
8767

8768 8769 8770 8771 8772
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
8773 8774
                                        unsigned int flags)
{
8775 8776
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
8777 8778
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

8779 8780 8781 8782 8783 8784 8785 8786
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

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

8787
    VIR_DEBUG("network initialized");
8788 8789 8790
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

8791
 cleanup:
8792 8793 8794
    return VIR_DRV_OPEN_DECLINED;
}

8795 8796
static int vboxNetworkClose(virConnectPtr conn)
{
8797
    VIR_DEBUG("network uninitialized");
8798 8799 8800 8801
    conn->networkPrivateData = NULL;
    return 0;
}

8802 8803
static int vboxConnectNumOfNetworks(virConnectPtr conn)
{
8804
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
8805
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
8806
    size_t i = 0;
8807

8808
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
8809

8810 8811 8812 8813
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
8814
            PRUint32 interfaceType = 0;
8815

8816
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8817 8818
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
8819

8820
                networkInterface->vtbl->GetStatus(networkInterface, &status);
8821

8822 8823
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
8824 8825 8826 8827
            }
        }
    }

8828 8829
    vboxArrayRelease(&networkInterfaces);

8830 8831
    VBOX_RELEASE(host);

8832
    VIR_DEBUG("numActive: %d", ret);
8833
    return ret;
8834 8835
}

8836
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
8837
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
8838
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
8839
    size_t i = 0;
8840

8841 8842 8843 8844
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

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

8846
        if (networkInterface) {
8847
            PRUint32 interfaceType = 0;
8848

8849
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8850

8851 8852
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
8853

8854
                networkInterface->vtbl->GetStatus(networkInterface, &status);
8855

8856 8857 8858
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
8859

8860
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
8861
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
8862

8863
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
8864
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
8865
                        ret++;
8866

8867 8868
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8869 8870 8871 8872 8873
                }
            }
        }
    }

8874
    vboxArrayRelease(&networkInterfaces);
8875

8876
    VBOX_RELEASE(host);
8877

8878 8879
    return ret;
}
8880

8881 8882
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn)
{
8883
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
8884
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
8885
    size_t i = 0;
8886

8887
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
8888

8889 8890 8891 8892
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
8893
            PRUint32 interfaceType = 0;
8894

8895
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8896 8897
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
8898

8899
                networkInterface->vtbl->GetStatus(networkInterface, &status);
8900

8901 8902
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
8903 8904 8905 8906
            }
        }
    }

8907 8908
    vboxArrayRelease(&networkInterfaces);

8909 8910
    VBOX_RELEASE(host);

8911
    VIR_DEBUG("numActive: %d", ret);
8912
    return ret;
8913 8914
}

8915
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
8916
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
8917
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
8918
    size_t i = 0;
8919

8920 8921 8922 8923
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

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

8925
        if (networkInterface) {
8926
            PRUint32 interfaceType = 0;
8927

8928
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8929

8930 8931
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
8932

8933
                networkInterface->vtbl->GetStatus(networkInterface, &status);
8934

8935 8936 8937
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
8938

8939
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
8940
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
8941

8942
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
8943
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
8944
                        ret++;
8945

8946 8947
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8948 8949 8950 8951 8952
                }
            }
        }
    }

8953
    vboxArrayRelease(&networkInterfaces);
8954 8955 8956 8957

    VBOX_RELEASE(host);

    return ret;
8958 8959
}

8960 8961 8962
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
8963
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
8964
    vboxIID iid = VBOX_IID_INITIALIZER;
8965

8966
    vboxIIDFromUUID(&iid, uuid);
8967

8968 8969 8970
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
8971
    IHostNetworkInterface *networkInterface = NULL;
8972

8973
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
8974 8975
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8976

8977
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8978

8979 8980 8981
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
8982

8983 8984
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
8985

8986
            ret = virGetNetwork(conn, nameUtf8, uuid);
8987

8988
            VIR_DEBUG("Network Name: %s", nameUtf8);
8989
            DEBUGIID("Network UUID", iid.value);
8990

8991 8992
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
8993
        }
8994 8995

        VBOX_RELEASE(networkInterface);
8996 8997
    }

8998 8999
    VBOX_RELEASE(host);

9000
    vboxIIDUnalloc(&iid);
9001 9002 9003
    return ret;
}

9004 9005 9006
static virNetworkPtr
vboxNetworkLookupByName(virConnectPtr conn, const char *name)
{
9007 9008 9009
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9010

9011
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
9012

9013
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
9014

9015 9016
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9017

9018
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9019

9020 9021
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
9022
            vboxIID iid = VBOX_IID_INITIALIZER;
9023

9024 9025
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
9026
            ret = virGetNetwork(conn, name, uuid);
9027
            VIR_DEBUG("Network Name: %s", name);
9028

9029 9030
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
9031
        }
9032 9033

        VBOX_RELEASE(networkInterface);
9034 9035
    }

9036 9037 9038
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

9039 9040 9041
    return ret;
}

9042 9043 9044
static virNetworkPtr
vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
{
9045 9046 9047 9048
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9049
    nsresult rc;
9050

9051
    virNetworkDefPtr def = virNetworkDefParseString(xml);
9052 9053
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
9054

9055
    if ((!def) ||
9056
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
9057
        (def->nips == 0 || !def->ips))
9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068
        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)
9069
        goto cleanup;
9070

9071 9072 9073 9074 9075 9076
    /* 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.
     */
9077

9078
#if VBOX_API_VERSION == 2002000
9079
    if (STREQ(def->name, "vboxnet0")) {
9080
        PRUint32 interfaceType = 0;
9081

9082 9083
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9084

9085 9086 9087 9088 9089 9090
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
9091
#else /* VBOX_API_VERSION != 2002000 */
9092 9093 9094 9095
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
9096

9097 9098 9099 9100
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
9101
    }
9102
#endif /* VBOX_API_VERSION != 2002000 */
9103

9104 9105 9106 9107
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
9108
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119

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

E
Eric Blake 已提交
9121
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9122

9123 9124 9125
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
9126
        if ((ipdef->nranges >= 1) &&
9127 9128
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
9129 9130 9131 9132 9133 9134 9135 9136 9137 9138
            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);
9139
                VIR_DEBUG("couldn't find dhcp server so creating one");
9140 9141 9142 9143 9144 9145 9146 9147
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

9148 9149 9150 9151
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
9152 9153 9154 9155 9156 9157 9158 9159 9160 9161

                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;
                }
9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186

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

9188
        if ((ipdef->nhosts >= 1) &&
9189
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
9190 9191
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
9192

9193 9194
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
9195 9196 9197 9198 9199 9200

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

9202 9203 9204 9205
            /* 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
             */
9206
#if VBOX_API_VERSION < 4002000
9207 9208 9209
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
9210 9211 9212 9213 9214
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
9215

9216 9217 9218
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
9219
#if VBOX_API_VERSION < 4002000
9220 9221
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
9222 9223 9224 9225
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
9226
        }
9227

9228 9229 9230 9231 9232
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
9233
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
9234
        }
9235 9236 9237 9238

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
9239 9240
    }

9241 9242 9243 9244
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9245
 cleanup:
9246 9247 9248 9249
    virNetworkDefFree(def);
    return ret;
}

9250 9251
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml)
{
9252 9253 9254
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

9255 9256
static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml)
{
9257 9258 9259
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

9260 9261 9262
static int
vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface)
{
9263
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
9264
    char *networkNameUtf8 = NULL;
9265 9266
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9267 9268 9269 9270 9271 9272 9273 9274 9275

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

9276
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9277 9278
        goto cleanup;

9279
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9280

9281
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9282

9283 9284
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9285

9286
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9287

9288 9289 9290
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
9291

9292
#if VBOX_API_VERSION != 2002000
9293 9294 9295
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
9296

9297
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
9298

9299
                if (iidUtf16) {
9300
# if VBOX_API_VERSION == 3000000
9301 9302 9303
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
9304
# else  /* VBOX_API_VERSION > 3000000 */
9305
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
9306
# endif /* VBOX_API_VERSION > 3000000 */
9307 9308
                    VBOX_UTF16_FREE(iidUtf16);
                }
9309

9310 9311 9312 9313 9314
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
9315
#endif /* VBOX_API_VERSION != 2002000 */
9316

E
Eric Blake 已提交
9317
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9318 9319 9320 9321 9322 9323 9324 9325 9326 9327

            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);
9328 9329
            }

9330 9331
            VBOX_UTF16_FREE(networkNameUtf16);

9332
        }
9333
        VBOX_RELEASE(networkInterface);
9334 9335
    }

9336 9337 9338
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9339 9340
    ret = 0;

9341
 cleanup:
9342 9343 9344 9345
    VIR_FREE(networkNameUtf8);
    return ret;
}

9346 9347
static int vboxNetworkUndefine(virNetworkPtr network)
{
9348 9349 9350
    return vboxNetworkUndefineDestroy(network, true);
}

9351 9352
static int vboxNetworkCreate(virNetworkPtr network)
{
9353
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
9354
    char *networkNameUtf8 = NULL;
9355 9356
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9357 9358 9359 9360 9361 9362 9363 9364

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

9365
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9366 9367
        goto cleanup;

9368
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9369

9370
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9371

9372 9373
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9374

9375
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9376

9377 9378 9379
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
9380 9381


E
Eric Blake 已提交
9382
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9383

9384 9385 9386 9387 9388
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
9389

9390
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
9391

9392
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
9393

9394 9395 9396 9397
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
9398

9399 9400
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
9401 9402
            }

9403
            VBOX_UTF16_FREE(networkNameUtf16);
9404
        }
9405 9406

        VBOX_RELEASE(networkInterface);
9407 9408
    }

9409 9410 9411
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9412 9413
    ret = 0;

9414
 cleanup:
9415 9416 9417 9418
    VIR_FREE(networkNameUtf8);
    return ret;
}

9419 9420
static int vboxNetworkDestroy(virNetworkPtr network)
{
9421
    return vboxNetworkUndefineDestroy(network, false);
9422 9423
}

9424
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
9425 9426
                                   unsigned int flags)
{
9427
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
9428
    virNetworkDefPtr def  = NULL;
9429
    virNetworkIpDefPtr ipdef = NULL;
9430
    char *networkNameUtf8 = NULL;
9431 9432
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
9433

E
Eric Blake 已提交
9434 9435
    virCheckFlags(0, NULL);

9436
    if (VIR_ALLOC(def) < 0)
9437
        goto cleanup;
9438
    if (VIR_ALLOC(ipdef) < 0)
9439 9440 9441
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
9442

9443
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
9444 9445
        goto cleanup;

9446
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
9447

9448
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
9449

9450 9451
    if (networkInterface) {
        PRUint32 interfaceType = 0;
9452

9453
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
9454

9455
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
9456
            if (VIR_STRDUP(def->name, network->name) >= 0) {
9457 9458
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
9459
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
9460

9461 9462
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
9463

E
Eric Blake 已提交
9464
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
9465

9466
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
9467

9468 9469 9470 9471
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
9472
                    ipdef->nranges = 1;
9473
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >= 0) {
9474 9475 9476 9477
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
9478
                        bool errorOccurred = false;
9479

9480 9481 9482 9483 9484 9485 9486
                        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
                         */
9487
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9488
                                                     &ipdef->address) < 0 ||
9489
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
9490
                                                     &ipdef->netmask) < 0 ||
9491
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
9492
                                                     &ipdef->ranges[0].start) < 0 ||
9493
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
9494
                                                     &ipdef->ranges[0].end) < 0) {
9495 9496
                            errorOccurred = true;
                        }
9497 9498 9499 9500 9501

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
9502 9503 9504 9505

                        if (errorOccurred) {
                            goto cleanup;
                        }
9506
                    } else {
9507
                        ipdef->nranges = 0;
9508
                    }
9509

9510
                    ipdef->nhosts = 1;
9511
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >= 0) {
9512
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
9513 9514
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
9515
                        } else {
9516 9517
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
9518
                            bool errorOccurred = false;
9519

9520
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
9521 9522
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

9523
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
9524 9525

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9526
                                                         &ipdef->hosts[0].ip) < 0) {
9527 9528
                                errorOccurred = true;
                            }
9529

9530 9531
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
9532 9533 9534 9535

                            if (errorOccurred) {
                                goto cleanup;
                            }
9536 9537
                        }
                    } else {
9538
                        ipdef->nhosts = 0;
9539
                    }
9540 9541 9542 9543 9544

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
9545
                    bool errorOccurred = false;
9546 9547 9548 9549

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

9550
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
9551
                                                 &ipdef->netmask) < 0 ||
9552
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
9553
                                                 &ipdef->address) < 0) {
9554 9555
                        errorOccurred = true;
                    }
9556 9557 9558

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
9559 9560 9561 9562

                    if (errorOccurred) {
                        goto cleanup;
                    }
9563 9564
                }

9565 9566
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
9567
                VBOX_UTF16_FREE(networkNameUtf16);
9568 9569
            }
        }
9570 9571

        VBOX_RELEASE(networkInterface);
9572 9573
    }

9574 9575 9576
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

9577
    ret = virNetworkDefFormat(def, 0);
9578

9579
 cleanup:
9580
    virNetworkDefFree(def);
9581 9582 9583 9584
    VIR_FREE(networkNameUtf8);
    return ret;
}

9585 9586 9587 9588
/**
 * The Storage Functions here on
 */

9589 9590 9591
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
9592
{
9593 9594
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
9595 9596
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

9597
    if (STRNEQ(conn->driver->name, "VBOX"))
9598
        return VIR_DRV_OPEN_DECLINED;
9599 9600 9601 9602

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
9603
        return VIR_DRV_OPEN_ERROR;
9604

9605
    VIR_DEBUG("vbox storage initialized");
9606 9607 9608 9609
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

9610 9611
static int vboxStorageClose(virConnectPtr conn)
{
9612
    VIR_DEBUG("vbox storage uninitialized");
9613 9614 9615 9616
    conn->storagePrivateData = NULL;
    return 0;
}

9617 9618
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
9619 9620 9621 9622 9623 9624 9625 9626

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

9627 9628
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
9629 9630
    int numActive = 0;

9631 9632 9633
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
9634 9635 9636
    return numActive;
}

9637 9638 9639
static virStoragePoolPtr
vboxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
9640 9641 9642 9643 9644 9645 9646 9647 9648 9649
    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";

9650
        ignore_value(virUUIDParse(uuidstr, uuid));
9651

9652
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
9653 9654 9655 9656 9657
    }

    return ret;
}

9658 9659
static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
9660
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
9661
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
9662 9663
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
9664
    size_t i;
9665

9666
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
9667
    if (NS_SUCCEEDED(rc)) {
9668 9669
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
9670 9671
            if (hardDisk) {
                PRUint32 hddstate;
9672

9673 9674 9675
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
9676 9677
            }
        }
9678 9679 9680 9681

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
9682
    } else {
9683
        ret = -1;
9684 9685 9686
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
9687 9688
    }

9689
    return ret;
9690 9691 9692
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
9693
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
9694
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
9695 9696
    PRUint32 numActive     = 0;
    nsresult rc;
9697
    size_t i;
9698

9699
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
9700
    if (NS_SUCCEEDED(rc)) {
9701 9702
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
9703

9704 9705 9706 9707
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
9708

9709 9710 9711
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
9712

9713 9714
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
9715

9716
                    if (nameUtf8) {
9717
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
9718
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
9719 9720 9721
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
9722 9723 9724 9725
                    }
                }
            }
        }
9726 9727 9728 9729

        vboxArrayRelease(&hardDisks);

        ret = numActive;
9730
    } else {
9731
        ret = -1;
9732 9733 9734
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
9735 9736
    }

9737
    return ret;
9738 9739
}

9740 9741 9742
static virStorageVolPtr
vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
{
9743
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
9744
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
9745
    nsresult rc;
9746
    size_t i;
9747

9748
    if (!name)
9749
        return ret;
9750

9751
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
9752
    if (NS_SUCCEEDED(rc)) {
9753 9754
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
9755

9756 9757 9758 9759
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
9760

9761 9762 9763
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
9764

9765 9766 9767 9768
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
9769

9770
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
9771 9772 9773
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
9774

9775 9776 9777 9778
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
9779

9780 9781
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
9782

9783 9784 9785 9786
                            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);
9787 9788
                        }

9789
                        vboxIIDUnalloc(&hddIID);
9790 9791
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
9792
                    }
9793

J
John Ferlan 已提交
9794
                    VBOX_UTF8_FREE(nameUtf8);
9795 9796 9797
                }
            }
        }
9798

9799
        vboxArrayRelease(&hardDisks);
9800 9801 9802 9803 9804
    }

    return ret;
}

9805 9806 9807
static virStorageVolPtr
vboxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
9808
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
9809 9810
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
9811 9812 9813
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

9814 9815 9816
    if (!key)
        return ret;

9817
    if (virUUIDParse(key, uuid) < 0) {
9818 9819
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
9820
        return NULL;
9821 9822
    }

9823
    vboxIIDFromUUID(&hddIID, uuid);
9824
#if VBOX_API_VERSION < 4000000
9825
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9826
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9827 9828
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9829 9830 9831 9832
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9833
#endif /* VBOX_API_VERSION >= 4000000 */
9834 9835
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9836

9837 9838 9839 9840
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
9841

9842 9843
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
9844

9845
            if (hddNameUtf8) {
9846
                if (vboxConnectNumOfStoragePools(conn) == 1) {
9847 9848
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
9849
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
9850 9851 9852 9853
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
9854 9855
                }

9856 9857
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
9858 9859 9860

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
9861 9862
            }
        }
9863 9864

        VBOX_MEDIUM_RELEASE(hardDisk);
9865 9866
    }

9867
    vboxIIDUnalloc(&hddIID);
9868 9869 9870
    return ret;
}

9871 9872 9873
static virStorageVolPtr
vboxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
9874
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
9875 9876 9877 9878
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

9879 9880
    if (!path)
        return ret;
9881

9882
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
9883

9884 9885
    if (!hddPathUtf16)
        return ret;
9886

9887
#if VBOX_API_VERSION < 4000000
9888
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
9889
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9890 9891
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
9892 9893 9894 9895
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9896
#endif /* VBOX_API_VERSION >= 4000000 */
9897 9898
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9899

9900 9901 9902 9903
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
9904

9905
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
9906

9907 9908 9909 9910
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
9911

9912 9913 9914 9915
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
9916

9917 9918 9919 9920
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
9921

9922 9923 9924
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
9925
                    if (vboxConnectNumOfStoragePools(conn) == 1)
9926 9927
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
9928

9929 9930 9931
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
9932
                }
9933

9934
                vboxIIDUnalloc(&hddIID);
9935 9936
            }

J
John Ferlan 已提交
9937
            VBOX_UTF8_FREE(hddNameUtf8);
9938
        }
9939 9940

        VBOX_MEDIUM_RELEASE(hardDisk);
9941 9942
    }

9943 9944
    VBOX_UTF16_FREE(hddPathUtf16);

9945 9946 9947 9948 9949
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
9950 9951
                                                unsigned int flags)
{
9952
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
9953
    virStorageVolDefPtr  def  = NULL;
9954 9955
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
9956 9957 9958
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
9959 9960
    virCheckFlags(0, NULL);

9961 9962 9963 9964 9965 9966 9967 9968
    /* 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;

9969
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
9970 9971
        goto cleanup;

9972 9973
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
9974
        goto cleanup;
9975

9976 9977
    /* For now only the vmdk, vpc and vdi type harddisk
     * variants can be created.  For historical reason, we default to vdi */
9978 9979 9980 9981 9982 9983 9984
    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);
    }
9985

9986
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
9987

9988 9989
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
9990

9991 9992 9993
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
9994 9995
            PRUint64   logicalSize = VIR_DIV_UP(def->target.capacity,
                                                1024 * 1024);
9996
            PRUint32   variant     = HardDiskVariant_Standard;
9997

9998
            if (def->target.capacity == def->target.allocation)
9999
                variant = HardDiskVariant_Fixed;
10000

10001
#if VBOX_API_VERSION < 4003000
10002
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
R
Ryota Ozaki 已提交
10003 10004 10005
#else
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
#endif
10006
            if (NS_SUCCEEDED(rc) && progress) {
10007
#if VBOX_API_VERSION == 2002000
10008
                nsresult resultCode;
10009
#else
10010
                PRInt32  resultCode;
10011 10012
#endif

10013 10014
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
10015

10016
                if (NS_SUCCEEDED(resultCode)) {
10017 10018 10019
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
10020

10021
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
10022
                    if (NS_SUCCEEDED(rc)) {
10023 10024
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
10025

10026 10027
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
10028
                    }
10029 10030

                    vboxIIDUnalloc(&hddIID);
10031 10032
                }

10033
                VBOX_RELEASE(progress);
10034
            }
10035
        }
10036 10037
    }

10038 10039 10040
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

10041
 cleanup:
10042 10043 10044 10045 10046
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
10047 10048
                                unsigned int flags)
{
10049
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
10050 10051
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
10052 10053 10054
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
10055 10056
    size_t i = 0;
    size_t j = 0;
10057

E
Eric Blake 已提交
10058 10059
    virCheckFlags(0, -1);

10060
    if (virUUIDParse(vol->key, uuid) < 0) {
10061 10062
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10063 10064
        return -1;
    }
10065

10066
    vboxIIDFromUUID(&hddIID, uuid);
10067
#if VBOX_API_VERSION < 4000000
10068
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10069
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10070 10071
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10072 10073 10074 10075
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10076
#endif /* VBOX_API_VERSION >= 4000000 */
10077 10078
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10079

10080 10081 10082
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
10083 10084
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;

10085
#if VBOX_API_VERSION < 3001000
10086
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
10087
#else  /* VBOX_API_VERSION >= 3001000 */
10088
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
10089
#endif /* VBOX_API_VERSION >= 3001000 */
10090

10091
#if VBOX_API_VERSION == 2002000 && defined WIN32
10092 10093 10094 10095 10096 10097
            /* 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 已提交
10098
             * we divide the size of the SafeArray by two, to compensate for
10099 10100
             * this workaround in VirtualBox */
            machineIds.count /= 2;
10101
#endif /* VBOX_API_VERSION >= 2002000 */
10102

10103
            machineIdsSize = machineIds.count;
10104

10105
            for (i = 0; i < machineIds.count; i++) {
10106
                IMachine *machine = NULL;
10107 10108 10109
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
10110

10111
#if VBOX_API_VERSION >= 4000000
10112 10113
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
10114 10115
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
10116 10117 10118 10119 10120 10121
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

10122
                if (NS_SUCCEEDED(rc)) {
10123

10124 10125
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
10126
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
10127

10128
#if VBOX_API_VERSION < 3001000
10129 10130
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
10131
#else  /* VBOX_API_VERSION >= 3001000 */
10132 10133
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
10134
#endif /* VBOX_API_VERSION >= 3001000 */
10135 10136
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
10137 10138 10139 10140

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

10141
#if VBOX_API_VERSION < 3001000
10142
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
10143
#else  /* VBOX_API_VERSION >= 3001000 */
10144
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
10145
#endif /* VBOX_API_VERSION >= 3001000 */
10146
                                if (NS_SUCCEEDED(rc) && hdd) {
10147
                                    vboxIID iid = VBOX_IID_INITIALIZER;
10148

10149 10150
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
10151

10152 10153
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
10154

10155
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
10156 10157 10158 10159
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

10160
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
10161 10162 10163 10164 10165

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

10166
#if VBOX_API_VERSION < 3001000
10167
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
10168
#else  /* VBOX_API_VERSION >= 3001000 */
10169
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
10170
#endif /* VBOX_API_VERSION >= 3001000 */
10171 10172
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
10173
                                                VIR_DEBUG("saving machine settings");
10174
                                            }
10175

10176 10177
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
10178
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
10179
                                            }
10180

J
John Ferlan 已提交
10181
                                            VBOX_UTF16_FREE(controller);
10182
                                        }
10183
                                        vboxIIDUnalloc(&iid);
10184
                                    }
10185
                                    VBOX_MEDIUM_RELEASE(hdd);
10186 10187 10188
                                }
                            }
                        }
10189
                        vboxArrayRelease(&hddAttachments);
10190
                        VBOX_RELEASE(machine);
10191
                    }
10192
                    VBOX_SESSION_CLOSE();
10193
                }
10194 10195

                vboxIIDUnalloc(&machineId);
10196
            }
10197

10198
            vboxArrayUnalloc(&machineIds);
10199

10200 10201 10202
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
10203

10204 10205 10206
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
10207
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
10208
                    ret = 0;
10209 10210 10211
                }
            }
        }
10212 10213

        VBOX_MEDIUM_RELEASE(hardDisk);
10214 10215
    }

10216
    vboxIIDUnalloc(&hddIID);
10217

10218 10219 10220
    return ret;
}

10221 10222 10223
static int
vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
{
10224
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
10225
    IHardDisk *hardDisk  = NULL;
10226 10227
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10228 10229
    nsresult rc;

10230
    if (!info)
10231
        return ret;
10232

10233
    if (virUUIDParse(vol->key, uuid) < 0) {
10234 10235
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10236
        return ret;
10237
    }
10238

10239
    vboxIIDFromUUID(&hddIID, uuid);
10240
#if VBOX_API_VERSION < 4000000
10241
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10242
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10243 10244
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10245 10246 10247 10248
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10249
#endif /* VBOX_API_VERSION >= 4000000 */
10250 10251
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10252

10253 10254
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
10255
#if VBOX_API_VERSION < 4000000
10256 10257
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
10258
#else /* VBOX_API_VERSION >= 4000000 */
10259 10260
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
10261
#endif /* VBOX_API_VERSION >= 4000000 */
10262

10263
            info->type = VIR_STORAGE_VOL_FILE;
10264

10265
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
10266
#if VBOX_API_VERSION < 4000000
10267
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
10268
#else /* VBOX_API_VERSION >= 4000000 */
10269
            info->capacity = hddLogicalSize;
10270
#endif /* VBOX_API_VERSION >= 4000000 */
10271

10272 10273
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
10274

10275
            ret = 0;
10276

10277 10278 10279 10280
            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);
10281
        }
10282 10283

        VBOX_MEDIUM_RELEASE(hardDisk);
10284 10285
    }

10286
    vboxIIDUnalloc(&hddIID);
10287

10288 10289 10290
    return ret;
}

E
Eric Blake 已提交
10291 10292
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
10293
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
10294
    IHardDisk *hardDisk  = NULL;
10295 10296
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10297 10298 10299 10300 10301
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
10302 10303
    virCheckFlags(0, NULL);

10304 10305 10306
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

10307
    if (virUUIDParse(vol->key, uuid) < 0) {
10308 10309
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10310
        return ret;
10311
    }
10312

10313
    vboxIIDFromUUID(&hddIID, uuid);
10314
#if VBOX_API_VERSION < 4000000
10315
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10316
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10317 10318
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10319 10320 10321 10322
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10323
#endif /* VBOX_API_VERSION >= 4000000 */
10324 10325 10326 10327 10328 10329
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
10330
#if VBOX_API_VERSION < 4000000
10331 10332
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
10333
#else /* VBOX_API_VERSION >= 4000000 */
10334 10335
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
10336
#endif /* VBOX_API_VERSION >= 4000000 */
10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347

            /* 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);
10348
            if (NS_SUCCEEDED(rc) && defOk) {
10349
#if VBOX_API_VERSION < 4000000
10350
                def.target.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
10351
#else /* VBOX_API_VERSION >= 4000000 */
10352
                def.target.capacity = hddLogicalSize;
10353
#endif /* VBOX_API_VERSION >= 4000000 */
10354
            } else
10355 10356 10357 10358
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
10359
                def.target.allocation = hddActualSize;
10360 10361 10362
            else
                defOk = 0;

10363
            if (VIR_STRDUP(def.name, vol->name) < 0)
10364 10365
                defOk = 0;

10366
            if (VIR_STRDUP(def.key, vol->key) < 0)
10367 10368 10369 10370 10371 10372 10373 10374 10375
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

10376
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
10377 10378 10379 10380 10381

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
10382 10383
                    else if (STRCASEEQ("vdi", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VDI;
10384
                    else
10385
                        def.target.format = VIR_STORAGE_FILE_RAW;
10386

10387
                    VBOX_UTF8_FREE(hddFormatUtf8);
10388 10389
                }

10390 10391 10392
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
10393 10394
            }
        }
10395 10396

        VBOX_MEDIUM_RELEASE(hardDisk);
10397 10398
    }

10399
    vboxIIDUnalloc(&hddIID);
10400

10401
    if (defOk)
10402
        ret = virStorageVolDefFormat(&pool, &def);
10403 10404 10405 10406 10407

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
10408
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
10409
    IHardDisk *hardDisk  = NULL;
10410 10411
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
10412 10413
    nsresult rc;

10414
    if (virUUIDParse(vol->key, uuid) < 0) {
10415 10416
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
10417
        return ret;
10418
    }
10419

10420
    vboxIIDFromUUID(&hddIID, uuid);
10421
#if VBOX_API_VERSION < 4000000
10422
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
10423
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
10424 10425
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
10426 10427 10428 10429
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
10430
#endif /* VBOX_API_VERSION >= 4000000 */
10431 10432
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
10433

10434 10435 10436 10437
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
10438

10439
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
10440

10441 10442
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
10443

10444
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
10445

10446 10447 10448
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
10449

10450
                VBOX_UTF8_FREE(hddLocationUtf8);
10451 10452
            }

10453
            VBOX_UTF16_FREE(hddLocationUtf16);
10454
        }
10455 10456

        VBOX_MEDIUM_RELEASE(hardDisk);
10457 10458
    }

10459
    vboxIIDUnalloc(&hddIID);
10460

10461 10462
    return ret;
}
10463

10464
#if VBOX_API_VERSION >= 4000000
10465 10466 10467 10468
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
10469
                     unsigned int flags)
10470 10471 10472 10473 10474 10475 10476 10477 10478 10479
{
    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 已提交
10480 10481
    virCheckFlags(0, NULL);

10482 10483 10484
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
10485 10486
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
10487 10488 10489 10490 10491
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
10492 10493
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
10494 10495 10496 10497 10498
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
10499 10500 10501
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
10502 10503 10504 10505 10506 10507 10508 10509 10510
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }

10511 10512
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530
        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;
10531
# if VBOX_API_VERSION >= 4003000
R
Ryota Ozaki 已提交
10532 10533
                PRInt32 xOrigin, yOrigin;
# endif
10534 10535 10536

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
10537
# if VBOX_API_VERSION < 4003000
10538
                                                        &bitsPerPixel);
R
Ryota Ozaki 已提交
10539 10540 10541 10542
# else
                                                        &bitsPerPixel,
                                                        &xOrigin, &yOrigin);
# endif
10543 10544

                if (NS_FAILED(rc) || !width || !height) {
10545 10546
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
10547 10548 10549 10550 10551 10552 10553 10554
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
10555 10556
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571
                    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;
                }

10572 10573 10574
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;

E
Eric Blake 已提交
10575
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
10576 10577
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
10578
                    VIR_FREE(ret);
10579
                }
10580
 endjob:
10581 10582 10583 10584 10585 10586 10587 10588 10589
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
10590
    unlink(tmp);
10591 10592 10593 10594 10595
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
10596
#endif /* VBOX_API_VERSION >= 4000000 */
10597

10598 10599 10600

#define MATCH(FLAG) (flags & (FLAG))
static int
10601 10602 10603
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
10604 10605 10606 10607 10608 10609 10610 10611 10612
{
    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;
10613
    size_t i;
10614 10615 10616 10617 10618 10619
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
10620
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634

    /* 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)
10635
            goto cleanup;
10636 10637 10638 10639 10640 10641 10642

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
10643 10644
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
10645 10646 10647 10648 10649
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
10650
        goto cleanup;
10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667

    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 已提交
10668
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
10669 10670 10671 10672 10673
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
10674
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
10675 10676
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
10677
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
10678
                                       _("could not get snapshot count for listed domains"));
10679 10680 10681 10682 10683 10684 10685 10686 10687 10688
                        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 已提交
10689
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739
                    !((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;

10740
 cleanup:
10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754
    if (doms) {
        for (i = 0; i < count; i++) {
            if (doms[i])
                virDomainFree(doms[i]);
        }
    }
    VIR_FREE(doms);

    vboxArrayRelease(&machines);
    return ret;
}
#undef MATCH


10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775
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)
{
10776 10777 10778 10779
    unsigned long long freeMem;
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;
    return freeMem;
10780 10781
}

10782

10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796
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 已提交
10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838
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 */
}

T
Taowei 已提交
10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 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 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986
#if VBOX_API_VERSION < 4000000

# if VBOX_API_VERSION < 3001000
static void
_detachDevices(vboxGlobalData *data ATTRIBUTE_UNUSED,
               IMachine *machine, PRUnichar *hddcnameUtf16)
{
    /* Disconnect all the drives if present */
    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 0);
    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 1);
    machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 1, 1);
}
# else  /* VBOX_API_VERSION >= 3001000 */
static void
_detachDevices(vboxGlobalData *data, IMachine *machine,
               PRUnichar *hddcnameUtf16 ATTRIBUTE_UNUSED)
{
    /* get all the controller first, then the attachments and
    * remove them all so that the machine can be undefined
    */
   vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
   size_t i = 0, j = 0;

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

   for (i = 0; i < storageControllers.count; i++) {
       IStorageController *strCtl = storageControllers.items[i];
       PRUnichar *strCtlName = NULL;
       vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;

       if (!strCtl)
           continue;

       strCtl->vtbl->GetName(strCtl, &strCtlName);
       vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                              machine->vtbl->GetMediumAttachmentsOfController,
                              strCtlName);

       for (j = 0; j < mediumAttachments.count; j++) {
           IMediumAttachment *medAtt = mediumAttachments.items[j];
           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);
           }
       }
       vboxArrayRelease(&storageControllers);
       machine->vtbl->RemoveStorageController(machine, strCtlName);
       VBOX_UTF16_FREE(strCtlName);
   }
   vboxArrayRelease(&storageControllers);
}
# endif /* VBOX_API_VERSION >= 3001000 */

static nsresult
_unregisterMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine)
{
    return data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, IID_MEMBER(value), machine);
}

static void
_deleteConfig(IMachine *machine)
{
    machine->vtbl->DeleteSettings(machine);
}

#else /* VBOX_API_VERSION >= 4000000 */

static void
_detachDevices(vboxGlobalData *data ATTRIBUTE_UNUSED,
               IMachine *machine ATTRIBUTE_UNUSED,
               PRUnichar *hddcnameUtf16 ATTRIBUTE_UNUSED)
{
    vboxUnsupported();
}

static nsresult
_unregisterMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine)
{
    nsresult rc;
    vboxArray media = VBOX_ARRAY_INITIALIZER;
    rc = VBOX_OBJECT_GET_MACHINE(IID_MEMBER(value), machine);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
        return rc;
    }

    /* We're not interested in the array returned by the Unregister method,
     * but in the side effect of unregistering the virtual machine. In order
     * to call the Unregister method correctly we need to use the vboxArray
     * wrapper here. */
    rc = vboxArrayGetWithUintArg(&media, *machine, (*machine)->vtbl->Unregister,
                                 CleanupMode_DetachAllReturnNone);
    vboxArrayUnalloc(&media);
    return rc;
}

static void
_deleteConfig(IMachine *machine)
{
    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);

#  if VBOX_API_VERSION < 4003000
    ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
#  else
    ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
#  endif
# else
    /* XPCOM doesn't like NULL as an array, even when the array size is 0.
     * Instead pass it a dummy array to avoid passing NULL. */
    IMedium *array[] = { NULL };
#  if VBOX_API_VERSION < 4003000
    machine->vtbl->Delete(machine, 0, array, &progress);
#  else
    machine->vtbl->DeleteConfig(machine, 0, array, &progress);
#  endif
# endif
    if (progress != NULL) {
        progress->vtbl->WaitForCompletion(progress, -1);
        VBOX_RELEASE(progress);
    }
}

#endif /* VBOX_API_VERSION >= 4000000 */

T
Taowei 已提交
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
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 已提交
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 11046 11047 11048
#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 已提交
11049 11050 11051 11052 11053
static void* _handleGetMachines(IVirtualBox *vboxObj)
{
    return vboxObj->vtbl->GetMachines;
}

T
Taowei 已提交
11054 11055 11056 11057 11058
static nsresult _nsisupportsRelease(nsISupports *nsi)
{
    return nsi->vtbl->Release(nsi);
}

T
Taowei 已提交
11059 11060 11061 11062 11063 11064
static nsresult
_virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16)
{
    return vboxObj->vtbl->GetVersion(vboxObj, versionUtf16);
}

T
Taowei 已提交
11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082
#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 已提交
11083 11084 11085 11086 11087 11088
static nsresult
_virtualboxGetSystemProperties(IVirtualBox *vboxObj, ISystemProperties **systemProperties)
{
    return vboxObj->vtbl->GetSystemProperties(vboxObj, systemProperties);
}

T
Taowei 已提交
11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100
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 已提交
11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112
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 已提交
11113 11114 11115 11116 11117 11118
static nsresult
_machineSaveSettings(IMachine *machine)
{
    return machine->vtbl->SaveSettings(machine);
}

T
Taowei 已提交
11119 11120
#if VBOX_API_VERSION < 4000000

T
Taowei 已提交
11121 11122 11123 11124 11125 11126
static nsresult
_sessionOpen(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED)
{
    return data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, IID_MEMBER(value));
}

T
Taowei 已提交
11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140
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 */

T
Taowei 已提交
11141 11142 11143 11144 11145 11146
static nsresult
_sessionOpen(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine)
{
    return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write);
}

T
Taowei 已提交
11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166
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);
}

T
Taowei 已提交
11167 11168 11169 11170 11171 11172
static nsresult
_sessionGetMachine(ISession *session, IMachine **machine)
{
    return session->vtbl->GetMachine(session, machine);
}

T
Taowei 已提交
11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194
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 已提交
11195 11196 11197 11198 11199 11200
static nsresult
_systemPropertiesGetMaxGuestCPUCount(ISystemProperties *systemProperties, PRUint32 *maxCPUCount)
{
    return systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, maxCPUCount);
}

T
Taowei 已提交
11201 11202 11203 11204 11205 11206
static bool _machineStateOnline(PRUint32 state)
{
    return ((state >= MachineState_FirstOnline) &&
            (state <= MachineState_LastOnline));
}

T
Taowei 已提交
11207 11208 11209 11210 11211 11212 11213 11214 11215 11216
static vboxUniformedPFN _UPFN = {
    .Initialize = _pfnInitialize,
    .Uninitialize = _pfnUninitialize,
    .ComUnallocMem = _pfnComUnallocMem,
    .Utf16Free = _pfnUtf16Free,
    .Utf8Free = _pfnUtf8Free,
    .Utf16ToUtf8 = _pfnUtf16ToUtf8,
    .Utf8ToUtf16 = _pfnUtf8ToUtf16,
};

T
Taowei 已提交
11217 11218 11219 11220 11221 11222 11223 11224 11225 11226
static vboxUniformedIID _UIID = {
    .vboxIIDInitialize = _vboxIIDInitialize,
    .vboxIIDUnalloc = _vboxIIDUnalloc,
    .vboxIIDToUUID = _vboxIIDToUUID,
    .vboxIIDFromUUID = _vboxIIDFromUUID,
    .vboxIIDIsEqual = _vboxIIDIsEqual,
    .vboxIIDFromArrayItem = _vboxIIDFromArrayItem,
    .DEBUGIID = _DEBUGIID,
};

T
Taowei 已提交
11227 11228 11229 11230 11231 11232
static vboxUniformedArray _UArray = {
    .vboxArrayGet = vboxArrayGet,
    .vboxArrayRelease = vboxArrayRelease,
    .handleGetMachines = _handleGetMachines,
};

T
Taowei 已提交
11233 11234 11235 11236
static vboxUniformednsISupports _nsUISupports = {
    .Release = _nsisupportsRelease,
};

T
Taowei 已提交
11237 11238
static vboxUniformedIVirtualBox _UIVirtualBox = {
    .GetVersion = _virtualboxGetVersion,
T
Taowei 已提交
11239
    .GetMachine = _virtualboxGetMachine,
T
Taowei 已提交
11240
    .GetSystemProperties = _virtualboxGetSystemProperties,
T
Taowei 已提交
11241 11242
};

T
Taowei 已提交
11243 11244 11245
static vboxUniformedIMachine _UIMachine = {
    .GetAccessible = _machineGetAccessible,
    .GetState = _machineGetState,
T
Taowei 已提交
11246 11247
    .GetName = _machineGetName,
    .GetId = _machineGetId,
T
Taowei 已提交
11248
    .SaveSettings = _machineSaveSettings,
T
Taowei 已提交
11249 11250
};

T
Taowei 已提交
11251
static vboxUniformedISession _UISession = {
T
Taowei 已提交
11252
    .Open = _sessionOpen,
T
Taowei 已提交
11253 11254
    .OpenExisting = _sessionOpenExisting,
    .GetConsole = _sessionGetConsole,
T
Taowei 已提交
11255
    .GetMachine = _sessionGetMachine,
T
Taowei 已提交
11256 11257 11258 11259 11260 11261 11262 11263 11264 11265
    .Close = _sessionClose,
};

static vboxUniformedIConsole _UIConsole = {
    .SaveState = _consoleSaveState,
};

static vboxUniformedIProgress _UIProgress = {
    .WaitForCompletion = _progressWaitForCompletion,
    .GetResultCode = _progressGetResultCode,
T
Taowei 已提交
11266 11267
};

T
Taowei 已提交
11268 11269 11270 11271
static vboxUniformedISystemProperties _UISystemProperties = {
    .GetMaxGuestCPUCount = _systemPropertiesGetMaxGuestCPUCount,
};

T
Taowei 已提交
11272 11273 11274 11275
static uniformedMachineStateChecker _machineStateChecker = {
    .Online = _machineStateOnline,
};

T
Taowei 已提交
11276 11277 11278 11279 11280 11281
void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
{
    pVBoxAPI->APIVersion = VBOX_API_VERSION;
    pVBoxAPI->XPCOMCVersion = VBOX_XPCOMC_VERSION;
    pVBoxAPI->initializeDomainEvent = _initializeDomainEvent;
    pVBoxAPI->registerGlobalData = _registerGlobalData;
T
Taowei 已提交
11282 11283 11284
    pVBoxAPI->detachDevices = _detachDevices;
    pVBoxAPI->unregisterMachine = _unregisterMachine;
    pVBoxAPI->deleteConfig = _deleteConfig;
T
Taowei 已提交
11285
    pVBoxAPI->UPFN = _UPFN;
T
Taowei 已提交
11286
    pVBoxAPI->UIID = _UIID;
T
Taowei 已提交
11287
    pVBoxAPI->UArray = _UArray;
T
Taowei 已提交
11288
    pVBoxAPI->nsUISupports = _nsUISupports;
T
Taowei 已提交
11289
    pVBoxAPI->UIVirtualBox = _UIVirtualBox;
T
Taowei 已提交
11290
    pVBoxAPI->UIMachine = _UIMachine;
T
Taowei 已提交
11291 11292 11293
    pVBoxAPI->UISession = _UISession;
    pVBoxAPI->UIConsole = _UIConsole;
    pVBoxAPI->UIProgress = _UIProgress;
T
Taowei 已提交
11294
    pVBoxAPI->UISystemProperties = _UISystemProperties;
T
Taowei 已提交
11295
    pVBoxAPI->machineStateChecker = _machineStateChecker;
T
Taowei 已提交
11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308

#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 已提交
11309 11310 11311
#if VBOX_API_VERSION >= 4000000
    /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
    pVBoxAPI->getMachineForSession = 1;
T
Taowei 已提交
11312
    pVBoxAPI->detachDevicesExplicitly = 0;
T
Taowei 已提交
11313 11314
#else /* VBOX_API_VERSION < 4000000 */
    pVBoxAPI->getMachineForSession = 0;
T
Taowei 已提交
11315
    pVBoxAPI->detachDevicesExplicitly = 1;
T
Taowei 已提交
11316
#endif /* VBOX_API_VERSION < 4000000 */
T
Taowei 已提交
11317
}
11318

11319 11320 11321 11322
/**
 * Function Tables
 */

11323
virDriver NAME(Driver) = {
11324 11325
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
11326 11327 11328
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
11329
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
11330
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
11331
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
11332 11333 11334 11335
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
11336 11337 11338 11339 11340 11341 11342
    .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 */
11343
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
11344 11345
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
11346
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
11347 11348 11349 11350 11351 11352 11353 11354 11355 11356
    .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 */
11357 11358
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
11359 11360 11361 11362
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
11363
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
11364 11365 11366 11367 11368
    .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 */
11369 11370
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
11371
#if VBOX_API_VERSION >= 4000000
11372
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
11373
#endif
11374
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
11375 11376
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
11377
#endif
11378 11379
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
11380 11381 11382
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
11383
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
11384 11385
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
11386
#endif
11387 11388 11389 11390 11391 11392
    .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 */
11393
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
11394
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
11395 11396
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
11397 11398
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
11399
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
11400
    .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */
11401
};
11402 11403 11404

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
11405 11406
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
11407 11408 11409 11410
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
11411 11412 11413 11414 11415 11416 11417 11418
    .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 */
11419
};
11420 11421 11422

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
11423 11424
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
11425 11426
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438
    .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 */
11439
};