~ubuntu-branches/ubuntu/trusty/virtualbox-ose/trusty

« back to all changes in this revision

Viewing changes to src/VBox/Main/MachineImpl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-12-18 16:44:29 UTC
  • mfrom: (0.3.3 upstream) (0.4.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091218164429-jd34ccexpv5na11a
Tags: 3.1.2-dfsg-1ubuntu1
* Merge from Debian unstable (LP: #498219), remaining changes:
  - Disable update action
    - debian/patches/u01-disable-update-action.dpatch
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
* Fixes the following bugs:
  - Kernel module fails to build with Linux >= 2.6.32 (LP: #474625)
  - X.Org drivers need to be rebuilt against X-Server 1.7 (LP: #495935)
  - The *-source packages try to build the kernel modules even though the
    kernel headers aren't available (LP: #473334)
* Replace *-source packages with transitional packages for *-dkms.
* Adapt u01-disable-update-action.dpatch and u02-lp-integration.dpatch for
  new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
#include "VirtualBoxImpl.h"
40
40
#include "MachineImpl.h"
41
41
#include "ProgressImpl.h"
42
 
#include "HardDiskAttachmentImpl.h"
 
42
#include "MediumAttachmentImpl.h"
 
43
#include "MediumImpl.h"
43
44
#include "USBControllerImpl.h"
44
45
#include "HostImpl.h"
45
 
#include "SystemPropertiesImpl.h"
46
46
#include "SharedFolderImpl.h"
47
47
#include "GuestOSTypeImpl.h"
48
48
#include "VirtualBoxErrorInfoImpl.h"
53
53
# include "USBProxyService.h"
54
54
#endif
55
55
 
56
 
#include "VirtualBoxXMLUtil.h"
57
 
 
58
56
#include "Logging.h"
59
57
#include "Performance.h"
60
58
 
74
72
#include <VBox/err.h>
75
73
#include <VBox/param.h>
76
74
#include <VBox/settings.h>
 
75
#include <VBox/ssm.h>
77
76
 
78
77
#ifdef VBOX_WITH_GUEST_PROPS
79
78
# include <VBox/HostServices/GuestPropertySvc.h>
93
92
// defines / prototypes
94
93
/////////////////////////////////////////////////////////////////////////////
95
94
 
96
 
// globals
97
 
/////////////////////////////////////////////////////////////////////////////
98
 
 
99
 
/**
100
 
 *  @note The template is NOT completely valid according to VBOX_XML_SCHEMA
101
 
 *  (when loading a newly created settings file, validation will be turned off)
102
 
 */
103
 
static const char gDefaultMachineConfig[] =
104
 
{
105
 
    "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" RTFILE_LINEFEED
106
 
    "<!-- Sun VirtualBox Machine Configuration -->" RTFILE_LINEFEED
107
 
    "<VirtualBox xmlns=\"" VBOX_XML_NAMESPACE "\" "
108
 
        "version=\"" VBOX_XML_VERSION_FULL "\">" RTFILE_LINEFEED
109
 
    "</VirtualBox>" RTFILE_LINEFEED
110
 
};
111
 
 
112
 
/**
113
 
 *  Progress callback handler for lengthy operations
114
 
 *  (corresponds to the FNRTPROGRESS typedef).
115
 
 *
116
 
 *  @param uPercentage  Completetion precentage (0-100).
117
 
 *  @param pvUser       Pointer to the Progress instance.
118
 
 */
119
 
static DECLCALLBACK(int) progressCallback (unsigned uPercentage, void *pvUser)
120
 
{
121
 
    Progress *progress = static_cast<Progress*>(pvUser);
122
 
 
123
 
    /* update the progress object */
124
 
    if (progress)
125
 
        progress->setCurrentOperationProgress(uPercentage);
126
 
 
127
 
    return VINF_SUCCESS;
128
 
}
129
 
 
130
95
/////////////////////////////////////////////////////////////////////////////
131
96
// Machine::Data structure
132
97
/////////////////////////////////////////////////////////////////////////////
138
103
    /* mUuid is initialized in Machine::init() */
139
104
 
140
105
    mMachineState = MachineState_PoweredOff;
141
 
    RTTimeNow (&mLastStateChange);
 
106
    RTTimeNow(&mLastStateChange);
142
107
 
143
108
    mMachineStateDeps = 0;
144
109
    mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
155
120
{
156
121
    if (mMachineStateDepsSem != NIL_RTSEMEVENTMULTI)
157
122
    {
158
 
        RTSemEventMultiDestroy (mMachineStateDepsSem);
 
123
        RTSemEventMultiDestroy(mMachineStateDepsSem);
159
124
        mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
160
125
    }
161
126
}
169
134
    /* default values for a newly created machine */
170
135
 
171
136
    mNameSync = TRUE;
 
137
    mTeleporterEnabled = FALSE;
 
138
    mTeleporterPort = 0;
172
139
 
173
140
    /* mName, mOSTypeId, mSnapshotFolder, mSnapshotFolderFull are initialized in
174
141
     * Machine::init() */
192
159
    mStatisticsUpdateInterval = 0;
193
160
    mVRAMSize = 8;
194
161
    mAccelerate3DEnabled = false;
 
162
    mAccelerate2DVideoEnabled = false;
195
163
    mMonitorCount = 1;
196
164
    mHWVirtExEnabled = true;
197
165
    mHWVirtExNestedPagingEnabled = false;
198
166
    mHWVirtExVPIDEnabled = false;
 
167
#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
 
168
    mHWVirtExExclusive = false;
 
169
#else
 
170
    mHWVirtExExclusive = true;
 
171
#endif
 
172
#if HC_ARCH_BITS == 64 || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
 
173
    mPAEEnabled = true;
 
174
#else
199
175
    mPAEEnabled = false;
 
176
#endif
 
177
    mSyntheticCpu = false;
200
178
    mPropertyServiceActive = false;
201
179
 
202
180
    /* default boot order: floppy - DVD - HDD */
203
181
    mBootOrder [0] = DeviceType_Floppy;
204
182
    mBootOrder [1] = DeviceType_DVD;
205
183
    mBootOrder [2] = DeviceType_HardDisk;
206
 
    for (size_t i = 3; i < RT_ELEMENTS (mBootOrder); i++)
 
184
    for (size_t i = 3; i < RT_ELEMENTS (mBootOrder); ++i)
207
185
        mBootOrder [i] = DeviceType_Null;
208
186
 
209
187
    mClipboardMode = ClipboardMode_Bidirectional;
210
188
    mGuestPropertyNotificationPatterns = "";
 
189
 
 
190
    mFirmwareType = FirmwareType_BIOS;
211
191
}
212
192
 
213
193
Machine::HWData::~HWData()
214
194
{
215
195
}
216
196
 
217
 
bool Machine::HWData::operator== (const HWData &that) const
 
197
bool Machine::HWData::operator==(const HWData &that) const
218
198
{
219
199
    if (this == &that)
220
200
        return true;
221
201
 
222
202
    if (mHWVersion != that.mHWVersion ||
 
203
        mHardwareUUID != that.mHardwareUUID ||
223
204
        mMemorySize != that.mMemorySize ||
224
205
        mMemoryBalloonSize != that.mMemoryBalloonSize ||
225
206
        mStatisticsUpdateInterval != that.mStatisticsUpdateInterval ||
226
207
        mVRAMSize != that.mVRAMSize ||
 
208
        mFirmwareType != that.mFirmwareType ||
227
209
        mAccelerate3DEnabled != that.mAccelerate3DEnabled ||
 
210
        mAccelerate2DVideoEnabled != that.mAccelerate2DVideoEnabled ||
228
211
        mMonitorCount != that.mMonitorCount ||
229
212
        mHWVirtExEnabled != that.mHWVirtExEnabled ||
230
213
        mHWVirtExNestedPagingEnabled != that.mHWVirtExNestedPagingEnabled ||
231
214
        mHWVirtExVPIDEnabled != that.mHWVirtExVPIDEnabled ||
 
215
        mHWVirtExExclusive != that.mHWVirtExExclusive ||
232
216
        mPAEEnabled != that.mPAEEnabled ||
 
217
        mSyntheticCpu != that.mSyntheticCpu ||
233
218
        mCPUCount != that.mCPUCount ||
234
219
        mClipboardMode != that.mClipboardMode)
235
220
        return false;
236
221
 
237
 
    for (size_t i = 0; i < RT_ELEMENTS (mBootOrder); ++ i)
 
222
    for (size_t i = 0; i < RT_ELEMENTS (mBootOrder); ++i)
238
223
        if (mBootOrder [i] != that.mBootOrder [i])
239
224
            return false;
240
225
 
255
240
        SharedFolderList::iterator thatIt = thatFolders.begin();
256
241
        while (thatIt != thatFolders.end())
257
242
        {
258
 
            if ((*it)->name() == (*thatIt)->name() &&
259
 
                RTPathCompare (Utf8Str ((*it)->hostPath()),
260
 
                               Utf8Str ((*thatIt)->hostPath())) == 0)
 
243
            if (    (*it)->getName() == (*thatIt)->getName()
 
244
                 && RTPathCompare(Utf8Str((*it)->getHostPath()).c_str(),
 
245
                                  Utf8Str((*thatIt)->getHostPath()).c_str()
 
246
                                 ) == 0)
261
247
            {
262
248
                thatFolders.erase (thatIt);
263
249
                found = true;
264
250
                break;
265
251
            }
266
252
            else
267
 
                ++ thatIt;
 
253
                ++thatIt;
268
254
        }
269
255
        if (found)
270
256
            it = folders.erase (it);
281
267
// Machine::HDData structure
282
268
/////////////////////////////////////////////////////////////////////////////
283
269
 
284
 
Machine::HDData::HDData()
285
 
{
286
 
}
287
 
 
288
 
Machine::HDData::~HDData()
289
 
{
290
 
}
291
 
 
292
 
bool Machine::HDData::operator== (const HDData &that) const
 
270
Machine::MediaData::MediaData()
 
271
{
 
272
}
 
273
 
 
274
Machine::MediaData::~MediaData()
 
275
{
 
276
}
 
277
 
 
278
bool Machine::MediaData::operator==(const MediaData &that) const
293
279
{
294
280
    if (this == &that)
295
281
        return true;
311
297
        AttachmentList::iterator thatIt = thatAtts.begin();
312
298
        while (thatIt != thatAtts.end())
313
299
        {
314
 
            if ((*it)->controller() == (*thatIt)->controller() &&
315
 
                (*it)->port() == (*thatIt)->port() &&
316
 
                (*it)->device() == (*thatIt)->device() &&
317
 
                (*it)->hardDisk().equalsTo ((*thatIt)->hardDisk()))
 
300
            if (    (*it)->matches((*thatIt)->getControllerName(),
 
301
                                   (*thatIt)->getPort(),
 
302
                                   (*thatIt)->getDevice())
 
303
                 && (*it)->getPassthrough() == (*thatIt)->getPassthrough()
 
304
                 && (*it)->getMedium().equalsTo((*thatIt)->getMedium())
 
305
               )
318
306
            {
319
 
                thatAtts.erase (thatIt);
 
307
                thatAtts.erase(thatIt);
320
308
                found = true;
321
309
                break;
322
310
            }
323
311
            else
324
 
                ++ thatIt;
 
312
                ++thatIt;
325
313
        }
326
314
        if (found)
327
315
            it = atts.erase (it);
347
335
 
348
336
HRESULT Machine::FinalConstruct()
349
337
{
350
 
    LogFlowThisFunc (("\n"));
 
338
    LogFlowThisFunc(("\n"));
351
339
    return S_OK;
352
340
}
353
341
 
354
342
void Machine::FinalRelease()
355
343
{
356
 
    LogFlowThisFunc (("\n"));
 
344
    LogFlowThisFunc(("\n"));
357
345
    uninit();
358
346
}
359
347
 
380
368
 *
381
369
 *  @return  Success indicator. if not S_OK, the machine object is invalid
382
370
 */
383
 
HRESULT Machine::init (VirtualBox *aParent, CBSTR aConfigFile,
384
 
                       InitMode aMode, CBSTR aName /* = NULL */,
385
 
                       GuestOSType *aOsType /* = NULL */,
386
 
                       BOOL aNameSync /* = TRUE */,
387
 
                       const Guid *aId /* = NULL */)
 
371
HRESULT Machine::init(VirtualBox *aParent,
 
372
                      const Utf8Str &strConfigFile,
 
373
                      InitMode aMode,
 
374
                      CBSTR aName /* = NULL */,
 
375
                      GuestOSType *aOsType /* = NULL */,
 
376
                      BOOL aNameSync /* = TRUE */,
 
377
                      const Guid *aId /* = NULL */)
388
378
{
389
379
    LogFlowThisFuncEnter();
390
 
    LogFlowThisFunc (("aConfigFile='%ls', aMode=%d\n", aConfigFile, aMode));
 
380
    LogFlowThisFunc (("aConfigFile='%s', aMode=%d\n", strConfigFile.raw(), aMode));
391
381
 
392
382
    AssertReturn (aParent, E_INVALIDARG);
393
 
    AssertReturn (aConfigFile, E_INVALIDARG);
394
 
    AssertReturn (aMode != Init_New || (aName != NULL && *aName != '\0'),
 
383
    AssertReturn (!strConfigFile.isEmpty(), E_INVALIDARG);
 
384
    AssertReturn(aMode != Init_New || (aName != NULL && *aName != '\0'),
395
385
                  E_INVALIDARG);
396
 
    AssertReturn (aMode != Init_Registered || aId != NULL, E_FAIL);
 
386
    AssertReturn(aMode != Init_Registered || aId != NULL, E_FAIL);
397
387
 
398
388
    /* Enclose the state transition NotReady->InInit->Ready */
399
 
    AutoInitSpan autoInitSpan (this);
400
 
    AssertReturn (autoInitSpan.isOk(), E_FAIL);
 
389
    AutoInitSpan autoInitSpan(this);
 
390
    AssertReturn(autoInitSpan.isOk(), E_FAIL);
401
391
 
402
392
    HRESULT rc = S_OK;
403
393
 
404
394
    /* share the parent weakly */
405
 
    unconst (mParent) = aParent;
 
395
    unconst(mParent) = aParent;
406
396
 
407
397
    /* register with parent early, since uninit() will unconditionally
408
398
     * unregister on failure */
412
402
     * allocated later by initDataAndChildObjects() */
413
403
    mData.allocate();
414
404
 
 
405
    mData->m_pMachineConfigFile = NULL;
 
406
 
415
407
    /* memorize the config file name (as provided) */
416
 
    mData->mConfigFile = aConfigFile;
 
408
    mData->m_strConfigFile = strConfigFile;
417
409
 
418
410
    /* get the full file name */
419
 
    Utf8Str configFileFull;
420
 
    int vrc = mParent->calculateFullPath (Utf8Str (aConfigFile), configFileFull);
421
 
    if (RT_FAILURE (vrc))
422
 
        return setError (VBOX_E_FILE_ERROR,
423
 
            tr ("Invalid machine settings file name '%ls' (%Rrc)"),
424
 
            aConfigFile, vrc);
425
 
 
426
 
    mData->mConfigFileFull = configFileFull;
 
411
    int vrc1 = mParent->calculateFullPath(strConfigFile, mData->m_strConfigFileFull);
 
412
    if (RT_FAILURE(vrc1))
 
413
        return setError(VBOX_E_FILE_ERROR,
 
414
                        tr("Invalid machine settings file name '%s' (%Rrc)"),
 
415
                        strConfigFile.raw(),
 
416
                        vrc1);
427
417
 
428
418
    if (aMode == Init_Registered)
429
419
    {
431
421
 
432
422
        /* store the supplied UUID (will be used to check for UUID consistency
433
423
         * in loadSettings() */
434
 
        unconst (mData->mUuid) = *aId;
 
424
        unconst(mData->mUuid) = *aId;
 
425
 
 
426
        // now load the settings from XML:
435
427
        rc = registeredInit();
436
428
    }
437
429
    else
438
430
    {
439
 
        if (aMode == Init_Existing)
 
431
        if (aMode == Init_Import)
440
432
        {
441
 
            /* lock the settings file */
442
 
            rc = lockConfig();
 
433
            // we're reading the settings file below
443
434
        }
444
435
        else if (aMode == Init_New)
445
436
        {
446
437
            /* check for the file existence */
447
438
            RTFILE f = NIL_RTFILE;
448
 
            int vrc = RTFileOpen (&f, configFileFull, RTFILE_O_READ);
449
 
            if (RT_SUCCESS (vrc) || vrc == VERR_SHARING_VIOLATION)
 
439
            int vrc = RTFileOpen(&f, mData->m_strConfigFileFull.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
440
            if (    RT_SUCCESS(vrc)
 
441
                 || vrc == VERR_SHARING_VIOLATION
 
442
               )
450
443
            {
451
 
                rc = setError (VBOX_E_FILE_ERROR,
452
 
                    tr ("Machine settings file '%s' already exists"),
453
 
                    configFileFull.raw());
454
 
                if (RT_SUCCESS (vrc))
455
 
                    RTFileClose (f);
 
444
                rc = setError(VBOX_E_FILE_ERROR,
 
445
                              tr("Machine settings file '%s' already exists"),
 
446
                              mData->m_strConfigFileFull.raw());
 
447
                if (RT_SUCCESS(vrc))
 
448
                    RTFileClose(f);
456
449
            }
457
450
            else
458
451
            {
459
 
                if (vrc != VERR_FILE_NOT_FOUND && vrc != VERR_PATH_NOT_FOUND)
460
 
                    rc = setError (VBOX_E_FILE_ERROR,
461
 
                        tr ("Invalid machine settings file name '%ls' (%Rrc)"),
462
 
                        mData->mConfigFileFull.raw(), vrc);
 
452
                if (     vrc != VERR_FILE_NOT_FOUND
 
453
                      && vrc != VERR_PATH_NOT_FOUND
 
454
                   )
 
455
                    rc = setError(VBOX_E_FILE_ERROR,
 
456
                                  tr("Invalid machine settings file name '%s' (%Rrc)"),
 
457
                                  mData->m_strConfigFileFull.raw(),
 
458
                                  vrc);
463
459
            }
 
460
 
 
461
            // create an empty machine config
 
462
            mData->m_pMachineConfigFile = new settings::MachineConfigFile(NULL);
464
463
        }
465
464
        else
466
465
            AssertFailed();
467
466
 
468
 
        if (SUCCEEDED (rc))
 
467
        if (SUCCEEDED(rc))
469
468
            rc = initDataAndChildObjects();
470
469
 
471
 
        if (SUCCEEDED (rc))
 
470
        if (SUCCEEDED(rc))
472
471
        {
473
472
            /* set to true now to cause uninit() to call
474
473
             * uninitDataAndChildObjects() on failure */
476
475
 
477
476
            if (aMode != Init_New)
478
477
            {
479
 
                rc = loadSettings (false /* aRegistered */);
 
478
                rc = loadSettings(false /* aRegistered */);
480
479
            }
481
480
            else
482
481
            {
483
482
                /* create the machine UUID */
484
483
                if (aId)
485
 
                    unconst (mData->mUuid) = *aId;
 
484
                    unconst(mData->mUuid) = *aId;
486
485
                else
487
 
                    unconst (mData->mUuid).create();
 
486
                    unconst(mData->mUuid).create();
488
487
 
489
488
                /* memorize the provided new machine's name */
490
489
                mUserData->mName = aName;
492
491
 
493
492
                /* initialize the default snapshots folder
494
493
                 * (note: depends on the name value set above!) */
495
 
                rc = COMSETTER(SnapshotFolder) (NULL);
496
 
                AssertComRC (rc);
 
494
                rc = COMSETTER(SnapshotFolder)(NULL);
 
495
                AssertComRC(rc);
497
496
 
498
497
                if (aOsType)
499
498
                {
504
503
                    mBIOSSettings->applyDefaults (aOsType);
505
504
 
506
505
                    /* Apply network adapters defaults */
507
 
                    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); ++ slot)
 
506
                    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); ++slot)
508
507
                        mNetworkAdapters [slot]->applyDefaults (aOsType);
 
508
 
 
509
                    /* Apply serial port defaults */
 
510
                    for (ULONG slot = 0; slot < RT_ELEMENTS (mSerialPorts); ++slot)
 
511
                        mSerialPorts [slot]->applyDefaults (aOsType);
509
512
                }
510
 
 
511
 
                /* The default is that the VM has at least one IDE controller
512
 
                 * which can't be disabled (because of the DVD stuff which is
513
 
                 * not in the StorageDevice implementation at the moment)
514
 
                 */
515
 
                ComPtr<IStorageController> pController;
516
 
                rc = AddStorageController(Bstr("IDE"), StorageBus_IDE, pController.asOutParam());
517
 
                CheckComRCReturnRC(rc);
518
 
                ComObjPtr<StorageController> ctl;
519
 
                rc = getStorageControllerByName(Bstr("IDE"), ctl, true);
520
 
                CheckComRCReturnRC(rc);
521
 
                ctl->COMSETTER(ControllerType)(StorageControllerType_PIIX4);
522
513
            }
523
514
 
524
515
            /* commit all changes made during the initialization */
525
 
            if (SUCCEEDED (rc))
 
516
            if (SUCCEEDED(rc))
526
517
                commit();
527
518
        }
528
519
    }
529
520
 
530
521
    /* Confirm a successful initialization when it's the case */
531
 
    if (SUCCEEDED (rc))
 
522
    if (SUCCEEDED(rc))
532
523
    {
533
524
        if (mData->mAccessible)
534
525
            autoInitSpan.setSucceeded();
536
527
            autoInitSpan.setLimited();
537
528
    }
538
529
 
539
 
    LogFlowThisFunc (("mName='%ls', mRegistered=%RTbool, mAccessible=%RTbool "
 
530
    LogFlowThisFunc(("mName='%ls', mRegistered=%RTbool, mAccessible=%RTbool "
540
531
                      "rc=%08X\n",
541
532
                      !!mUserData ? mUserData->mName.raw() : NULL,
542
533
                      mData->mRegistered, mData->mAccessible, rc));
560
551
 */
561
552
HRESULT Machine::registeredInit()
562
553
{
563
 
    AssertReturn (mType == IsMachine, E_FAIL);
564
 
    AssertReturn (!mData->mUuid.isEmpty(), E_FAIL);
565
 
    AssertReturn (!mData->mAccessible, E_FAIL);
566
 
 
567
 
    HRESULT rc = lockConfig();
568
 
 
569
 
    if (SUCCEEDED (rc))
570
 
        rc = initDataAndChildObjects();
571
 
 
572
 
    if (SUCCEEDED (rc))
 
554
    AssertReturn(mType == IsMachine, E_FAIL);
 
555
    AssertReturn(!mData->mUuid.isEmpty(), E_FAIL);
 
556
    AssertReturn(!mData->mAccessible, E_FAIL);
 
557
 
 
558
    HRESULT rc = initDataAndChildObjects();
 
559
 
 
560
    if (SUCCEEDED(rc))
573
561
    {
574
562
        /* Temporarily reset the registered flag in order to let setters
575
563
         * potentially called from loadSettings() succeed (isMutable() used in
577
565
         * is TRUE). */
578
566
        mData->mRegistered = FALSE;
579
567
 
580
 
        rc = loadSettings (true /* aRegistered */);
 
568
        rc = loadSettings(true /* aRegistered */);
581
569
 
582
570
        /* Restore the registered flag (even on failure) */
583
571
        mData->mRegistered = TRUE;
584
 
 
585
 
        if (FAILED (rc))
586
 
            unlockConfig();
587
572
    }
588
573
 
589
 
    if (SUCCEEDED (rc))
 
574
    if (SUCCEEDED(rc))
590
575
    {
591
576
        /* Set mAccessible to TRUE only if we successfully locked and loaded
592
577
         * the settings file */
603
588
 
604
589
        /* fetch the current error info */
605
590
        mData->mAccessError = com::ErrorInfo();
606
 
        LogWarning (("Machine {%RTuuid} is inaccessible! [%ls]\n",
607
 
                     mData->mUuid.raw(),
608
 
                     mData->mAccessError.getText().raw()));
 
591
        LogWarning(("Machine {%RTuuid} is inaccessible! [%ls]\n",
 
592
                    mData->mUuid.raw(),
 
593
                    mData->mAccessError.getText().raw()));
609
594
 
610
595
        /* rollback all changes */
611
596
        rollback (false /* aNotify */);
638
623
    Assert (!isWriteLockOnCurrentThread());
639
624
 
640
625
    /* Enclose the state transition Ready->InUninit->NotReady */
641
 
    AutoUninitSpan autoUninitSpan (this);
 
626
    AutoUninitSpan autoUninitSpan(this);
642
627
    if (autoUninitSpan.uninitDone())
643
628
        return;
644
629
 
645
630
    Assert (mType == IsMachine);
646
631
    Assert (!!mData);
647
632
 
648
 
    LogFlowThisFunc (("initFailed()=%d\n", autoUninitSpan.initFailed()));
649
 
    LogFlowThisFunc (("mRegistered=%d\n", mData->mRegistered));
 
633
    LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed()));
 
634
    LogFlowThisFunc(("mRegistered=%d\n", mData->mRegistered));
650
635
 
651
636
    /* Enter this object lock because there may be a SessionMachine instance
652
637
     * somewhere around, that shares our data and lock but doesn't use our
670
655
         * after we return from this method (it expects the Machine instance is
671
656
         * still valid). We'll call it ourselves below.
672
657
         */
673
 
        LogWarningThisFunc (("Session machine is not NULL (%p), "
 
658
        LogWarningThisFunc(("Session machine is not NULL (%p), "
674
659
                             "the direct session is still open!\n",
675
660
                             (SessionMachine *) mData->mSession.mMachine));
676
661
 
677
662
        if (Global::IsOnlineOrTransient (mData->mMachineState))
678
663
        {
679
 
            LogWarningThisFunc (("Setting state to Aborted!\n"));
 
664
            LogWarningThisFunc(("Setting state to Aborted!\n"));
680
665
            /* set machine state using SessionMachine reimplementation */
681
666
            static_cast <Machine *> (mData->mSession.mMachine)
682
667
                ->setMachineState (MachineState_Aborted);
694
679
    /* the lock is no more necessary (SessionMachine is uninitialized) */
695
680
    alock.leave();
696
681
 
697
 
    /* make sure the configuration is unlocked */
698
 
    unlockConfig();
699
 
 
700
682
    if (isModified())
701
683
    {
702
 
        LogWarningThisFunc (("Discarding unsaved settings changes!\n"));
 
684
        LogWarningThisFunc(("Discarding unsaved settings changes!\n"));
703
685
        rollback (false /* aNotify */);
704
686
    }
705
687
 
719
701
 
720
702
STDMETHODIMP Machine::COMGETTER(Parent) (IVirtualBox **aParent)
721
703
{
722
 
    CheckComArgOutPointerValid (aParent);
 
704
    CheckComArgOutPointerValid(aParent);
723
705
 
724
 
    AutoLimitedCaller autoCaller (this);
725
 
    CheckComRCReturnRC (autoCaller.rc());
 
706
    AutoLimitedCaller autoCaller(this);
 
707
    CheckComRCReturnRC(autoCaller.rc());
726
708
 
727
709
    /* mParent is constant during life time, no need to lock */
728
 
    mParent.queryInterfaceTo (aParent);
 
710
    mParent.queryInterfaceTo(aParent);
729
711
 
730
712
    return S_OK;
731
713
}
732
714
 
733
715
STDMETHODIMP Machine::COMGETTER(Accessible) (BOOL *aAccessible)
734
716
{
735
 
    CheckComArgOutPointerValid (aAccessible);
736
 
 
737
 
    AutoLimitedCaller autoCaller (this);
738
 
    CheckComRCReturnRC (autoCaller.rc());
739
 
 
740
 
    AutoWriteLock alock (this);
 
717
    CheckComArgOutPointerValid(aAccessible);
 
718
 
 
719
    AutoLimitedCaller autoCaller(this);
 
720
    CheckComRCReturnRC(autoCaller.rc());
 
721
 
 
722
    LogFlowThisFunc(("ENTER\n"));
 
723
 
 
724
    AutoWriteLock alock(this);
741
725
 
742
726
    HRESULT rc = S_OK;
743
727
 
745
729
    {
746
730
        /* try to initialize the VM once more if not accessible */
747
731
 
748
 
        AutoReinitSpan autoReinitSpan (this);
749
 
        AssertReturn (autoReinitSpan.isOk(), E_FAIL);
 
732
        AutoReinitSpan autoReinitSpan(this);
 
733
        AssertReturn(autoReinitSpan.isOk(), E_FAIL);
 
734
 
 
735
#ifdef DEBUG
 
736
        LogFlowThisFunc(("Dumping media backreferences\n"));
 
737
        mParent->dumpAllBackRefs();
 
738
#endif
 
739
 
 
740
        if (mData->m_pMachineConfigFile)
 
741
        {
 
742
            // @todo why are we parsing this several times?
 
743
            // this is hugely inefficient
 
744
            delete mData->m_pMachineConfigFile;
 
745
            mData->m_pMachineConfigFile = NULL;
 
746
        }
750
747
 
751
748
        rc = registeredInit();
752
749
 
753
 
        if (SUCCEEDED (rc) && mData->mAccessible)
 
750
        if (SUCCEEDED(rc) && mData->mAccessible)
754
751
        {
755
752
            autoReinitSpan.setSucceeded();
756
753
 
757
754
            /* make sure interesting parties will notice the accessibility
758
755
             * state change */
759
 
            mParent->onMachineStateChange (mData->mUuid, mData->mMachineState);
760
 
            mParent->onMachineDataChange (mData->mUuid);
 
756
            mParent->onMachineStateChange(mData->mUuid, mData->mMachineState);
 
757
            mParent->onMachineDataChange(mData->mUuid);
761
758
        }
762
759
    }
763
760
 
764
 
    if (SUCCEEDED (rc))
 
761
    if (SUCCEEDED(rc))
765
762
        *aAccessible = mData->mAccessible;
766
763
 
 
764
    LogFlowThisFuncLeave();
 
765
 
767
766
    return rc;
768
767
}
769
768
 
770
769
STDMETHODIMP Machine::COMGETTER(AccessError) (IVirtualBoxErrorInfo **aAccessError)
771
770
{
772
 
    CheckComArgOutPointerValid (aAccessError);
773
 
 
774
 
    AutoLimitedCaller autoCaller (this);
775
 
    CheckComRCReturnRC (autoCaller.rc());
776
 
 
777
 
    AutoReadLock alock (this);
 
771
    CheckComArgOutPointerValid(aAccessError);
 
772
 
 
773
    AutoLimitedCaller autoCaller(this);
 
774
    CheckComRCReturnRC(autoCaller.rc());
 
775
 
 
776
    AutoReadLock alock(this);
778
777
 
779
778
    if (mData->mAccessible || !mData->mAccessError.isBasicAvailable())
780
779
    {
785
784
 
786
785
    HRESULT rc = S_OK;
787
786
 
788
 
    ComObjPtr <VirtualBoxErrorInfo> errorInfo;
 
787
    ComObjPtr<VirtualBoxErrorInfo> errorInfo;
789
788
    rc = errorInfo.createObject();
790
 
    if (SUCCEEDED (rc))
 
789
    if (SUCCEEDED(rc))
791
790
    {
792
791
        errorInfo->init (mData->mAccessError.getResultCode(),
793
792
                         mData->mAccessError.getInterfaceID(),
794
793
                         mData->mAccessError.getComponent(),
795
794
                         mData->mAccessError.getText());
796
 
        rc = errorInfo.queryInterfaceTo (aAccessError);
 
795
        rc = errorInfo.queryInterfaceTo(aAccessError);
797
796
    }
798
797
 
799
798
    return rc;
801
800
 
802
801
STDMETHODIMP Machine::COMGETTER(Name) (BSTR *aName)
803
802
{
804
 
    CheckComArgOutPointerValid (aName);
805
 
 
806
 
    AutoCaller autoCaller (this);
807
 
    CheckComRCReturnRC (autoCaller.rc());
808
 
 
809
 
    AutoReadLock alock (this);
810
 
 
811
 
    mUserData->mName.cloneTo (aName);
 
803
    CheckComArgOutPointerValid(aName);
 
804
 
 
805
    AutoCaller autoCaller(this);
 
806
    CheckComRCReturnRC(autoCaller.rc());
 
807
 
 
808
    AutoReadLock alock(this);
 
809
 
 
810
    mUserData->mName.cloneTo(aName);
812
811
 
813
812
    return S_OK;
814
813
}
818
817
    CheckComArgNotNull (aName);
819
818
 
820
819
    if (!*aName)
821
 
        return setError (E_INVALIDARG,
822
 
            tr ("Machine name cannot be empty"));
823
 
 
824
 
    AutoCaller autoCaller (this);
825
 
    CheckComRCReturnRC (autoCaller.rc());
826
 
 
827
 
    AutoWriteLock alock (this);
828
 
 
829
 
    HRESULT rc = checkStateDependency (MutableStateDep);
830
 
    CheckComRCReturnRC (rc);
 
820
        return setError(E_INVALIDARG,
 
821
                        tr("Machine name cannot be empty"));
 
822
 
 
823
    AutoCaller autoCaller(this);
 
824
    CheckComRCReturnRC(autoCaller.rc());
 
825
 
 
826
    AutoWriteLock alock(this);
 
827
 
 
828
    HRESULT rc = checkStateDependency(MutableStateDep);
 
829
    CheckComRCReturnRC(rc);
831
830
 
832
831
    mUserData.backup();
833
832
    mUserData->mName = aName;
837
836
 
838
837
STDMETHODIMP Machine::COMGETTER(Description) (BSTR *aDescription)
839
838
{
840
 
    CheckComArgOutPointerValid (aDescription);
841
 
 
842
 
    AutoCaller autoCaller (this);
843
 
    CheckComRCReturnRC (autoCaller.rc());
844
 
 
845
 
    AutoReadLock alock (this);
846
 
 
847
 
    mUserData->mDescription.cloneTo (aDescription);
 
839
    CheckComArgOutPointerValid(aDescription);
 
840
 
 
841
    AutoCaller autoCaller(this);
 
842
    CheckComRCReturnRC(autoCaller.rc());
 
843
 
 
844
    AutoReadLock alock(this);
 
845
 
 
846
    mUserData->mDescription.cloneTo(aDescription);
848
847
 
849
848
    return S_OK;
850
849
}
851
850
 
852
851
STDMETHODIMP Machine::COMSETTER(Description) (IN_BSTR aDescription)
853
852
{
854
 
    AutoCaller autoCaller (this);
855
 
    CheckComRCReturnRC (autoCaller.rc());
856
 
 
857
 
    AutoWriteLock alock (this);
858
 
 
859
 
    HRESULT rc = checkStateDependency (MutableStateDep);
860
 
    CheckComRCReturnRC (rc);
 
853
    AutoCaller autoCaller(this);
 
854
    CheckComRCReturnRC(autoCaller.rc());
 
855
 
 
856
    AutoWriteLock alock(this);
 
857
 
 
858
    HRESULT rc = checkStateDependency(MutableStateDep);
 
859
    CheckComRCReturnRC(rc);
861
860
 
862
861
    mUserData.backup();
863
862
    mUserData->mDescription = aDescription;
867
866
 
868
867
STDMETHODIMP Machine::COMGETTER(Id) (BSTR *aId)
869
868
{
870
 
    CheckComArgOutPointerValid (aId);
871
 
 
872
 
    AutoLimitedCaller autoCaller (this);
873
 
    CheckComRCReturnRC (autoCaller.rc());
874
 
 
875
 
    AutoReadLock alock (this);
876
 
 
877
 
    mData->mUuid.toUtf16().cloneTo (aId);
 
869
    CheckComArgOutPointerValid(aId);
 
870
 
 
871
    AutoLimitedCaller autoCaller(this);
 
872
    CheckComRCReturnRC(autoCaller.rc());
 
873
 
 
874
    AutoReadLock alock(this);
 
875
 
 
876
    mData->mUuid.toUtf16().cloneTo(aId);
878
877
 
879
878
    return S_OK;
880
879
}
881
880
 
882
881
STDMETHODIMP Machine::COMGETTER(OSTypeId) (BSTR *aOSTypeId)
883
882
{
884
 
    CheckComArgOutPointerValid (aOSTypeId);
885
 
 
886
 
    AutoCaller autoCaller (this);
887
 
    CheckComRCReturnRC (autoCaller.rc());
888
 
 
889
 
    AutoReadLock alock (this);
890
 
 
891
 
    mUserData->mOSTypeId.cloneTo (aOSTypeId);
 
883
    CheckComArgOutPointerValid(aOSTypeId);
 
884
 
 
885
    AutoCaller autoCaller(this);
 
886
    CheckComRCReturnRC(autoCaller.rc());
 
887
 
 
888
    AutoReadLock alock(this);
 
889
 
 
890
    mUserData->mOSTypeId.cloneTo(aOSTypeId);
892
891
 
893
892
    return S_OK;
894
893
}
897
896
{
898
897
    CheckComArgNotNull (aOSTypeId);
899
898
 
900
 
    AutoCaller autoCaller (this);
901
 
    CheckComRCReturnRC (autoCaller.rc());
 
899
    AutoCaller autoCaller(this);
 
900
    CheckComRCReturnRC(autoCaller.rc());
902
901
 
903
902
    /* look up the object by Id to check it is valid */
904
 
    ComPtr <IGuestOSType> guestOSType;
 
903
    ComPtr<IGuestOSType> guestOSType;
905
904
    HRESULT rc = mParent->GetGuestOSType (aOSTypeId,
906
905
                                          guestOSType.asOutParam());
907
 
    CheckComRCReturnRC (rc);
 
906
    CheckComRCReturnRC(rc);
908
907
 
909
908
    /* when setting, always use the "etalon" value for consistency -- lookup
910
909
     * by ID is case-insensitive and the input value may have different case */
911
910
    Bstr osTypeId;
912
911
    rc = guestOSType->COMGETTER(Id) (osTypeId.asOutParam());
913
 
    CheckComRCReturnRC (rc);
914
 
 
915
 
    AutoWriteLock alock (this);
916
 
 
917
 
    rc = checkStateDependency (MutableStateDep);
918
 
    CheckComRCReturnRC (rc);
 
912
    CheckComRCReturnRC(rc);
 
913
 
 
914
    AutoWriteLock alock(this);
 
915
 
 
916
    rc = checkStateDependency(MutableStateDep);
 
917
    CheckComRCReturnRC(rc);
919
918
 
920
919
    mUserData.backup();
921
920
    mUserData->mOSTypeId = osTypeId;
923
922
    return S_OK;
924
923
}
925
924
 
 
925
 
 
926
STDMETHODIMP Machine::COMGETTER(FirmwareType) (FirmwareType_T *aFirmwareType)
 
927
{
 
928
    CheckComArgOutPointerValid(aFirmwareType);
 
929
 
 
930
    AutoCaller autoCaller(this);
 
931
    CheckComRCReturnRC(autoCaller.rc());
 
932
 
 
933
    AutoReadLock alock(this);
 
934
 
 
935
    *aFirmwareType = mHWData->mFirmwareType;
 
936
 
 
937
    return S_OK;
 
938
}
 
939
 
 
940
STDMETHODIMP Machine::COMSETTER(FirmwareType) (FirmwareType_T aFirmwareType)
 
941
{
 
942
    AutoCaller autoCaller(this);
 
943
    CheckComRCReturnRC(autoCaller.rc());
 
944
    AutoWriteLock alock(this);
 
945
 
 
946
    int rc = checkStateDependency(MutableStateDep);
 
947
    CheckComRCReturnRC(rc);
 
948
 
 
949
    mHWData.backup();
 
950
    mHWData->mFirmwareType = aFirmwareType;
 
951
 
 
952
    return S_OK;
 
953
}
 
954
 
926
955
STDMETHODIMP Machine::COMGETTER(HardwareVersion) (BSTR *aHWVersion)
927
956
{
928
957
    if (!aHWVersion)
929
958
        return E_POINTER;
930
959
 
931
 
    AutoCaller autoCaller (this);
932
 
    CheckComRCReturnRC (autoCaller.rc());
933
 
 
934
 
    AutoReadLock alock (this);
935
 
 
936
 
    mHWData->mHWVersion.cloneTo (aHWVersion);
 
960
    AutoCaller autoCaller(this);
 
961
    CheckComRCReturnRC(autoCaller.rc());
 
962
 
 
963
    AutoReadLock alock(this);
 
964
 
 
965
    mHWData->mHWVersion.cloneTo(aHWVersion);
937
966
 
938
967
    return S_OK;
939
968
}
944
973
    Utf8Str hwVersion = aHWVersion;
945
974
    if (    hwVersion.compare ("1") != 0
946
975
        &&  hwVersion.compare ("2") != 0)
947
 
        return setError (E_INVALIDARG,
948
 
            tr ("Invalid hardware version: %ls\n"), aHWVersion);
949
 
 
950
 
    AutoCaller autoCaller (this);
951
 
    CheckComRCReturnRC (autoCaller.rc());
952
 
 
953
 
    AutoWriteLock alock (this);
954
 
 
955
 
    HRESULT rc = checkStateDependency (MutableStateDep);
956
 
    CheckComRCReturnRC (rc);
 
976
        return setError(E_INVALIDARG,
 
977
                        tr("Invalid hardware version: %ls\n"), aHWVersion);
 
978
 
 
979
    AutoCaller autoCaller(this);
 
980
    CheckComRCReturnRC(autoCaller.rc());
 
981
 
 
982
    AutoWriteLock alock(this);
 
983
 
 
984
    HRESULT rc = checkStateDependency(MutableStateDep);
 
985
    CheckComRCReturnRC(rc);
957
986
 
958
987
    mHWData.backup();
959
988
    mHWData->mHWVersion = hwVersion;
961
990
    return S_OK;
962
991
}
963
992
 
 
993
STDMETHODIMP Machine::COMGETTER(HardwareUUID)(BSTR *aUUID)
 
994
{
 
995
    CheckComArgOutPointerValid(aUUID);
 
996
 
 
997
    AutoCaller autoCaller(this);
 
998
    CheckComRCReturnRC(autoCaller.rc());
 
999
 
 
1000
    AutoReadLock alock(this);
 
1001
 
 
1002
    if (!mHWData->mHardwareUUID.isEmpty())
 
1003
        mHWData->mHardwareUUID.toUtf16().cloneTo(aUUID);
 
1004
    else
 
1005
        mData->mUuid.toUtf16().cloneTo(aUUID);
 
1006
 
 
1007
    return S_OK;
 
1008
}
 
1009
 
 
1010
STDMETHODIMP Machine::COMSETTER(HardwareUUID) (IN_BSTR aUUID)
 
1011
{
 
1012
    Guid hardwareUUID(aUUID);
 
1013
    if (hardwareUUID.isEmpty())
 
1014
        return E_INVALIDARG;
 
1015
 
 
1016
    AutoCaller autoCaller(this);
 
1017
    CheckComRCReturnRC(autoCaller.rc());
 
1018
 
 
1019
    AutoWriteLock alock(this);
 
1020
 
 
1021
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1022
    CheckComRCReturnRC(rc);
 
1023
 
 
1024
    mHWData.backup();
 
1025
    if (hardwareUUID == mData->mUuid)
 
1026
        mHWData->mHardwareUUID.clear();
 
1027
    else
 
1028
        mHWData->mHardwareUUID = hardwareUUID;
 
1029
 
 
1030
    return S_OK;
 
1031
}
 
1032
 
964
1033
STDMETHODIMP Machine::COMGETTER(MemorySize) (ULONG *memorySize)
965
1034
{
966
1035
    if (!memorySize)
967
1036
        return E_POINTER;
968
1037
 
969
 
    AutoCaller autoCaller (this);
970
 
    CheckComRCReturnRC (autoCaller.rc());
 
1038
    AutoCaller autoCaller(this);
 
1039
    CheckComRCReturnRC(autoCaller.rc());
971
1040
 
972
 
    AutoReadLock alock (this);
 
1041
    AutoReadLock alock(this);
973
1042
 
974
1043
    *memorySize = mHWData->mMemorySize;
975
1044
 
979
1048
STDMETHODIMP Machine::COMSETTER(MemorySize) (ULONG memorySize)
980
1049
{
981
1050
    /* check RAM limits */
982
 
    if (memorySize < MM_RAM_MIN_IN_MB ||
983
 
        memorySize > MM_RAM_MAX_IN_MB)
984
 
        return setError (E_INVALIDARG,
985
 
            tr ("Invalid RAM size: %lu MB (must be in range [%lu, %lu] MB)"),
986
 
                memorySize, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
987
 
 
988
 
    AutoCaller autoCaller (this);
989
 
    CheckComRCReturnRC (autoCaller.rc());
990
 
 
991
 
    AutoWriteLock alock (this);
992
 
 
993
 
    HRESULT rc = checkStateDependency (MutableStateDep);
994
 
    CheckComRCReturnRC (rc);
 
1051
    if (    memorySize < MM_RAM_MIN_IN_MB
 
1052
         || memorySize > MM_RAM_MAX_IN_MB
 
1053
       )
 
1054
        return setError(E_INVALIDARG,
 
1055
                        tr("Invalid RAM size: %lu MB (must be in range [%lu, %lu] MB)"),
 
1056
                        memorySize, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
 
1057
 
 
1058
    AutoCaller autoCaller(this);
 
1059
    CheckComRCReturnRC(autoCaller.rc());
 
1060
 
 
1061
    AutoWriteLock alock(this);
 
1062
 
 
1063
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1064
    CheckComRCReturnRC(rc);
995
1065
 
996
1066
    mHWData.backup();
997
1067
    mHWData->mMemorySize = memorySize;
1004
1074
    if (!CPUCount)
1005
1075
        return E_POINTER;
1006
1076
 
1007
 
    AutoCaller autoCaller (this);
1008
 
    CheckComRCReturnRC (autoCaller.rc());
 
1077
    AutoCaller autoCaller(this);
 
1078
    CheckComRCReturnRC(autoCaller.rc());
1009
1079
 
1010
 
    AutoReadLock alock (this);
 
1080
    AutoReadLock alock(this);
1011
1081
 
1012
1082
    *CPUCount = mHWData->mCPUCount;
1013
1083
 
1017
1087
STDMETHODIMP Machine::COMSETTER(CPUCount) (ULONG CPUCount)
1018
1088
{
1019
1089
    /* check RAM limits */
1020
 
    if (CPUCount < SchemaDefs::MinCPUCount ||
1021
 
        CPUCount > SchemaDefs::MaxCPUCount)
1022
 
        return setError (E_INVALIDARG,
1023
 
            tr ("Invalid virtual CPU count: %lu (must be in range [%lu, %lu])"),
1024
 
                CPUCount, SchemaDefs::MinCPUCount, SchemaDefs::MaxCPUCount);
1025
 
 
1026
 
    AutoCaller autoCaller (this);
1027
 
    CheckComRCReturnRC (autoCaller.rc());
1028
 
 
1029
 
    AutoWriteLock alock (this);
1030
 
 
1031
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1032
 
    CheckComRCReturnRC (rc);
 
1090
    if (    CPUCount < SchemaDefs::MinCPUCount
 
1091
         || CPUCount > SchemaDefs::MaxCPUCount
 
1092
       )
 
1093
        return setError(E_INVALIDARG,
 
1094
                        tr("Invalid virtual CPU count: %lu (must be in range [%lu, %lu])"),
 
1095
                        CPUCount, SchemaDefs::MinCPUCount, SchemaDefs::MaxCPUCount);
 
1096
 
 
1097
    AutoCaller autoCaller(this);
 
1098
    CheckComRCReturnRC(autoCaller.rc());
 
1099
 
 
1100
    AutoWriteLock alock(this);
 
1101
 
 
1102
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1103
    CheckComRCReturnRC(rc);
1033
1104
 
1034
1105
    mHWData.backup();
1035
1106
    mHWData->mCPUCount = CPUCount;
1042
1113
    if (!memorySize)
1043
1114
        return E_POINTER;
1044
1115
 
1045
 
    AutoCaller autoCaller (this);
1046
 
    CheckComRCReturnRC (autoCaller.rc());
 
1116
    AutoCaller autoCaller(this);
 
1117
    CheckComRCReturnRC(autoCaller.rc());
1047
1118
 
1048
 
    AutoReadLock alock (this);
 
1119
    AutoReadLock alock(this);
1049
1120
 
1050
1121
    *memorySize = mHWData->mVRAMSize;
1051
1122
 
1057
1128
    /* check VRAM limits */
1058
1129
    if (memorySize < SchemaDefs::MinGuestVRAM ||
1059
1130
        memorySize > SchemaDefs::MaxGuestVRAM)
1060
 
        return setError (E_INVALIDARG,
1061
 
            tr ("Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
1062
 
                memorySize, SchemaDefs::MinGuestVRAM, SchemaDefs::MaxGuestVRAM);
1063
 
 
1064
 
    AutoCaller autoCaller (this);
1065
 
    CheckComRCReturnRC (autoCaller.rc());
1066
 
 
1067
 
    AutoWriteLock alock (this);
1068
 
 
1069
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1070
 
    CheckComRCReturnRC (rc);
 
1131
        return setError(E_INVALIDARG,
 
1132
                        tr("Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
 
1133
                        memorySize, SchemaDefs::MinGuestVRAM, SchemaDefs::MaxGuestVRAM);
 
1134
 
 
1135
    AutoCaller autoCaller(this);
 
1136
    CheckComRCReturnRC(autoCaller.rc());
 
1137
 
 
1138
    AutoWriteLock alock(this);
 
1139
 
 
1140
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1141
    CheckComRCReturnRC(rc);
1071
1142
 
1072
1143
    mHWData.backup();
1073
1144
    mHWData->mVRAMSize = memorySize;
1081
1152
    if (!memoryBalloonSize)
1082
1153
        return E_POINTER;
1083
1154
 
1084
 
    AutoCaller autoCaller (this);
1085
 
    CheckComRCReturnRC (autoCaller.rc());
 
1155
    AutoCaller autoCaller(this);
 
1156
    CheckComRCReturnRC(autoCaller.rc());
1086
1157
 
1087
 
    AutoReadLock alock (this);
 
1158
    AutoReadLock alock(this);
1088
1159
 
1089
1160
    *memoryBalloonSize = mHWData->mMemoryBalloonSize;
1090
1161
 
1096
1167
{
1097
1168
    /* check limits */
1098
1169
    if (memoryBalloonSize >= VMMDEV_MAX_MEMORY_BALLOON (mHWData->mMemorySize))
1099
 
        return setError (E_INVALIDARG,
1100
 
            tr ("Invalid memory balloon size: %lu MB (must be in range [%lu, %lu] MB)"),
1101
 
                memoryBalloonSize, 0, VMMDEV_MAX_MEMORY_BALLOON (mHWData->mMemorySize));
1102
 
 
1103
 
    AutoCaller autoCaller (this);
1104
 
    CheckComRCReturnRC (autoCaller.rc());
1105
 
 
1106
 
    AutoWriteLock alock (this);
1107
 
 
1108
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1109
 
    CheckComRCReturnRC (rc);
 
1170
        return setError(E_INVALIDARG,
 
1171
                        tr("Invalid memory balloon size: %lu MB (must be in range [%lu, %lu] MB)"),
 
1172
                        memoryBalloonSize, 0, VMMDEV_MAX_MEMORY_BALLOON (mHWData->mMemorySize));
 
1173
 
 
1174
    AutoCaller autoCaller(this);
 
1175
    CheckComRCReturnRC(autoCaller.rc());
 
1176
 
 
1177
    AutoWriteLock alock(this);
 
1178
 
 
1179
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1180
    CheckComRCReturnRC(rc);
1110
1181
 
1111
1182
    mHWData.backup();
1112
1183
    mHWData->mMemoryBalloonSize = memoryBalloonSize;
1120
1191
    if (!statisticsUpdateInterval)
1121
1192
        return E_POINTER;
1122
1193
 
1123
 
    AutoCaller autoCaller (this);
1124
 
    CheckComRCReturnRC (autoCaller.rc());
 
1194
    AutoCaller autoCaller(this);
 
1195
    CheckComRCReturnRC(autoCaller.rc());
1125
1196
 
1126
 
    AutoReadLock alock (this);
 
1197
    AutoReadLock alock(this);
1127
1198
 
1128
1199
    *statisticsUpdateInterval = mHWData->mStatisticsUpdateInterval;
1129
1200
 
1133
1204
/** @todo this method should not be public */
1134
1205
STDMETHODIMP Machine::COMSETTER(StatisticsUpdateInterval) (ULONG statisticsUpdateInterval)
1135
1206
{
1136
 
    AutoCaller autoCaller (this);
1137
 
    CheckComRCReturnRC (autoCaller.rc());
1138
 
 
1139
 
    AutoWriteLock alock (this);
1140
 
 
1141
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1142
 
    CheckComRCReturnRC (rc);
 
1207
    AutoCaller autoCaller(this);
 
1208
    CheckComRCReturnRC(autoCaller.rc());
 
1209
 
 
1210
    AutoWriteLock alock(this);
 
1211
 
 
1212
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1213
    CheckComRCReturnRC(rc);
1143
1214
 
1144
1215
    mHWData.backup();
1145
1216
    mHWData->mStatisticsUpdateInterval = statisticsUpdateInterval;
1153
1224
    if (!enabled)
1154
1225
        return E_POINTER;
1155
1226
 
1156
 
    AutoCaller autoCaller (this);
1157
 
    CheckComRCReturnRC (autoCaller.rc());
 
1227
    AutoCaller autoCaller(this);
 
1228
    CheckComRCReturnRC(autoCaller.rc());
1158
1229
 
1159
 
    AutoReadLock alock (this);
 
1230
    AutoReadLock alock(this);
1160
1231
 
1161
1232
    *enabled = mHWData->mAccelerate3DEnabled;
1162
1233
 
1165
1236
 
1166
1237
STDMETHODIMP Machine::COMSETTER(Accelerate3DEnabled)(BOOL enable)
1167
1238
{
1168
 
    AutoCaller autoCaller (this);
1169
 
    CheckComRCReturnRC (autoCaller.rc());
1170
 
 
1171
 
    AutoWriteLock alock (this);
1172
 
 
1173
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1174
 
    CheckComRCReturnRC (rc);
 
1239
    AutoCaller autoCaller(this);
 
1240
    CheckComRCReturnRC(autoCaller.rc());
 
1241
 
 
1242
    AutoWriteLock alock(this);
 
1243
 
 
1244
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1245
    CheckComRCReturnRC(rc);
1175
1246
 
1176
1247
    /** @todo check validity! */
1177
1248
 
1182
1253
}
1183
1254
 
1184
1255
 
 
1256
STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *enabled)
 
1257
{
 
1258
    if (!enabled)
 
1259
        return E_POINTER;
 
1260
 
 
1261
    AutoCaller autoCaller(this);
 
1262
    CheckComRCReturnRC(autoCaller.rc());
 
1263
 
 
1264
    AutoReadLock alock(this);
 
1265
 
 
1266
    *enabled = mHWData->mAccelerate2DVideoEnabled;
 
1267
 
 
1268
    return S_OK;
 
1269
}
 
1270
 
 
1271
STDMETHODIMP Machine::COMSETTER(Accelerate2DVideoEnabled)(BOOL enable)
 
1272
{
 
1273
    AutoCaller autoCaller(this);
 
1274
    CheckComRCReturnRC(autoCaller.rc());
 
1275
 
 
1276
    AutoWriteLock alock(this);
 
1277
 
 
1278
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1279
    CheckComRCReturnRC(rc);
 
1280
 
 
1281
    /** @todo check validity! */
 
1282
 
 
1283
    mHWData.backup();
 
1284
    mHWData->mAccelerate2DVideoEnabled = enable;
 
1285
 
 
1286
    return S_OK;
 
1287
}
 
1288
 
1185
1289
STDMETHODIMP Machine::COMGETTER(MonitorCount) (ULONG *monitorCount)
1186
1290
{
1187
1291
    if (!monitorCount)
1188
1292
        return E_POINTER;
1189
1293
 
1190
 
    AutoCaller autoCaller (this);
1191
 
    CheckComRCReturnRC (autoCaller.rc());
 
1294
    AutoCaller autoCaller(this);
 
1295
    CheckComRCReturnRC(autoCaller.rc());
1192
1296
 
1193
 
    AutoReadLock alock (this);
 
1297
    AutoReadLock alock(this);
1194
1298
 
1195
1299
    *monitorCount = mHWData->mMonitorCount;
1196
1300
 
1201
1305
{
1202
1306
    /* make sure monitor count is a sensible number */
1203
1307
    if (monitorCount < 1 || monitorCount > SchemaDefs::MaxGuestMonitors)
1204
 
        return setError (E_INVALIDARG,
1205
 
            tr ("Invalid monitor count: %lu (must be in range [%lu, %lu])"),
1206
 
                monitorCount, 1, SchemaDefs::MaxGuestMonitors);
1207
 
 
1208
 
    AutoCaller autoCaller (this);
1209
 
    CheckComRCReturnRC (autoCaller.rc());
1210
 
 
1211
 
    AutoWriteLock alock (this);
1212
 
 
1213
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1214
 
    CheckComRCReturnRC (rc);
 
1308
        return setError(E_INVALIDARG,
 
1309
                        tr("Invalid monitor count: %lu (must be in range [%lu, %lu])"),
 
1310
                        monitorCount, 1, SchemaDefs::MaxGuestMonitors);
 
1311
 
 
1312
    AutoCaller autoCaller(this);
 
1313
    CheckComRCReturnRC(autoCaller.rc());
 
1314
 
 
1315
    AutoWriteLock alock(this);
 
1316
 
 
1317
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1318
    CheckComRCReturnRC(rc);
1215
1319
 
1216
1320
    mHWData.backup();
1217
1321
    mHWData->mMonitorCount = monitorCount;
1224
1328
    if (!biosSettings)
1225
1329
        return E_POINTER;
1226
1330
 
1227
 
    AutoCaller autoCaller (this);
1228
 
    CheckComRCReturnRC (autoCaller.rc());
 
1331
    AutoCaller autoCaller(this);
 
1332
    CheckComRCReturnRC(autoCaller.rc());
1229
1333
 
1230
1334
    /* mBIOSSettings is constant during life time, no need to lock */
1231
 
    mBIOSSettings.queryInterfaceTo (biosSettings);
1232
 
 
1233
 
    return S_OK;
1234
 
}
1235
 
 
1236
 
STDMETHODIMP Machine::COMGETTER(HWVirtExEnabled)(BOOL *enabled)
1237
 
{
1238
 
    if (!enabled)
1239
 
        return E_POINTER;
1240
 
 
1241
 
    AutoCaller autoCaller (this);
1242
 
    CheckComRCReturnRC (autoCaller.rc());
1243
 
 
1244
 
    AutoReadLock alock (this);
1245
 
 
1246
 
    *enabled = mHWData->mHWVirtExEnabled;
1247
 
 
1248
 
    return S_OK;
1249
 
}
1250
 
 
1251
 
STDMETHODIMP Machine::COMSETTER(HWVirtExEnabled)(BOOL enable)
1252
 
{
1253
 
    AutoCaller autoCaller (this);
1254
 
    CheckComRCReturnRC (autoCaller.rc());
1255
 
 
1256
 
    AutoWriteLock alock (this);
1257
 
 
1258
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1259
 
    CheckComRCReturnRC (rc);
1260
 
 
1261
 
    /** @todo check validity! */
1262
 
 
1263
 
    mHWData.backup();
1264
 
    mHWData->mHWVirtExEnabled = enable;
1265
 
 
1266
 
    return S_OK;
1267
 
}
1268
 
 
1269
 
STDMETHODIMP Machine::COMGETTER(HWVirtExNestedPagingEnabled)(BOOL *enabled)
1270
 
{
1271
 
    if (!enabled)
1272
 
        return E_POINTER;
1273
 
 
1274
 
    AutoCaller autoCaller (this);
1275
 
    CheckComRCReturnRC (autoCaller.rc());
1276
 
 
1277
 
    AutoReadLock alock (this);
1278
 
 
1279
 
    *enabled = mHWData->mHWVirtExNestedPagingEnabled;
1280
 
 
1281
 
    return S_OK;
1282
 
}
1283
 
 
1284
 
STDMETHODIMP Machine::COMSETTER(HWVirtExNestedPagingEnabled)(BOOL enable)
1285
 
{
1286
 
    AutoCaller autoCaller (this);
1287
 
    CheckComRCReturnRC (autoCaller.rc());
1288
 
 
1289
 
    AutoWriteLock alock (this);
1290
 
 
1291
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1292
 
    CheckComRCReturnRC (rc);
1293
 
 
1294
 
    /** @todo check validity! */
1295
 
 
1296
 
    mHWData.backup();
1297
 
    mHWData->mHWVirtExNestedPagingEnabled = enable;
1298
 
 
1299
 
    return S_OK;
1300
 
}
1301
 
 
1302
 
STDMETHODIMP Machine::COMGETTER(HWVirtExVPIDEnabled)(BOOL *enabled)
1303
 
{
1304
 
    if (!enabled)
1305
 
        return E_POINTER;
1306
 
 
1307
 
    AutoCaller autoCaller (this);
1308
 
    CheckComRCReturnRC (autoCaller.rc());
1309
 
 
1310
 
    AutoReadLock alock (this);
1311
 
 
1312
 
    *enabled = mHWData->mHWVirtExVPIDEnabled;
1313
 
 
1314
 
    return S_OK;
1315
 
}
1316
 
 
1317
 
STDMETHODIMP Machine::COMSETTER(HWVirtExVPIDEnabled)(BOOL enable)
1318
 
{
1319
 
    AutoCaller autoCaller (this);
1320
 
    CheckComRCReturnRC (autoCaller.rc());
1321
 
 
1322
 
    AutoWriteLock alock (this);
1323
 
 
1324
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1325
 
    CheckComRCReturnRC (rc);
1326
 
 
1327
 
    /** @todo check validity! */
1328
 
 
1329
 
    mHWData.backup();
1330
 
    mHWData->mHWVirtExVPIDEnabled = enable;
1331
 
 
1332
 
    return S_OK;
1333
 
}
1334
 
 
1335
 
STDMETHODIMP Machine::COMGETTER(PAEEnabled)(BOOL *enabled)
1336
 
{
1337
 
    if (!enabled)
1338
 
        return E_POINTER;
1339
 
 
1340
 
    AutoCaller autoCaller (this);
1341
 
    CheckComRCReturnRC (autoCaller.rc());
1342
 
 
1343
 
    AutoReadLock alock (this);
1344
 
 
1345
 
    *enabled = mHWData->mPAEEnabled;
1346
 
 
1347
 
    return S_OK;
1348
 
}
1349
 
 
1350
 
STDMETHODIMP Machine::COMSETTER(PAEEnabled)(BOOL enable)
1351
 
{
1352
 
    AutoCaller autoCaller (this);
1353
 
    CheckComRCReturnRC (autoCaller.rc());
1354
 
 
1355
 
    AutoWriteLock alock (this);
1356
 
 
1357
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1358
 
    CheckComRCReturnRC (rc);
1359
 
 
1360
 
    /** @todo check validity! */
1361
 
 
1362
 
    mHWData.backup();
1363
 
    mHWData->mPAEEnabled = enable;
1364
 
 
 
1335
    mBIOSSettings.queryInterfaceTo(biosSettings);
 
1336
 
 
1337
    return S_OK;
 
1338
}
 
1339
 
 
1340
STDMETHODIMP Machine::GetCpuProperty(CpuPropertyType_T property, BOOL *aVal)
 
1341
{
 
1342
    if (!aVal)
 
1343
        return E_POINTER;
 
1344
 
 
1345
    AutoCaller autoCaller(this);
 
1346
    CheckComRCReturnRC(autoCaller.rc());
 
1347
 
 
1348
    AutoReadLock alock(this);
 
1349
 
 
1350
    switch(property)
 
1351
    {
 
1352
    case CpuPropertyType_PAE:
 
1353
        *aVal = mHWData->mPAEEnabled;
 
1354
        break;
 
1355
 
 
1356
    case CpuPropertyType_Synthetic:
 
1357
        *aVal = mHWData->mSyntheticCpu;
 
1358
        break;
 
1359
 
 
1360
    default:
 
1361
        return E_INVALIDARG;
 
1362
    }
 
1363
    return S_OK;
 
1364
}
 
1365
 
 
1366
STDMETHODIMP Machine::SetCpuProperty(CpuPropertyType_T property, BOOL aVal)
 
1367
{
 
1368
    AutoCaller autoCaller(this);
 
1369
    CheckComRCReturnRC(autoCaller.rc());
 
1370
 
 
1371
    AutoWriteLock alock(this);
 
1372
 
 
1373
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1374
    CheckComRCReturnRC(rc);
 
1375
 
 
1376
    switch(property)
 
1377
    {
 
1378
    case CpuPropertyType_PAE:
 
1379
        mHWData->mPAEEnabled = !!aVal;
 
1380
        break;
 
1381
 
 
1382
    case CpuPropertyType_Synthetic:
 
1383
        mHWData->mSyntheticCpu = !!aVal;
 
1384
        break;
 
1385
 
 
1386
    default:
 
1387
        return E_INVALIDARG;
 
1388
    }
 
1389
    return S_OK;
 
1390
}
 
1391
 
 
1392
STDMETHODIMP Machine::GetCpuIdLeaf(ULONG aId, ULONG *aValEax, ULONG *aValEbx, ULONG *aValEcx, ULONG *aValEdx)
 
1393
{
 
1394
    CheckComArgOutPointerValid(aValEax);
 
1395
    CheckComArgOutPointerValid(aValEbx);
 
1396
    CheckComArgOutPointerValid(aValEcx);
 
1397
    CheckComArgOutPointerValid(aValEdx);
 
1398
 
 
1399
    AutoCaller autoCaller(this);
 
1400
    CheckComRCReturnRC(autoCaller.rc());
 
1401
 
 
1402
    AutoReadLock alock(this);
 
1403
 
 
1404
    switch(aId)
 
1405
    {
 
1406
        case 0x0:
 
1407
        case 0x1:
 
1408
        case 0x2:
 
1409
        case 0x3:
 
1410
        case 0x4:
 
1411
        case 0x5:
 
1412
        case 0x6:
 
1413
        case 0x7:
 
1414
        case 0x8:
 
1415
        case 0x9:
 
1416
        case 0xA:
 
1417
            if (mHWData->mCpuIdStdLeafs[aId].ulId != aId)
 
1418
                return setError(E_INVALIDARG, tr("CpuId override leaf %#x is not set"), aId);
 
1419
 
 
1420
            *aValEax = mHWData->mCpuIdStdLeafs[aId].ulEax;
 
1421
            *aValEbx = mHWData->mCpuIdStdLeafs[aId].ulEbx;
 
1422
            *aValEcx = mHWData->mCpuIdStdLeafs[aId].ulEcx;
 
1423
            *aValEdx = mHWData->mCpuIdStdLeafs[aId].ulEdx;
 
1424
            break;
 
1425
 
 
1426
        case 0x80000000:
 
1427
        case 0x80000001:
 
1428
        case 0x80000002:
 
1429
        case 0x80000003:
 
1430
        case 0x80000004:
 
1431
        case 0x80000005:
 
1432
        case 0x80000006:
 
1433
        case 0x80000007:
 
1434
        case 0x80000008:
 
1435
        case 0x80000009:
 
1436
        case 0x8000000A:
 
1437
            if (mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulId != aId)
 
1438
                return setError(E_INVALIDARG, tr("CpuId override leaf %#x is not set"), aId);
 
1439
 
 
1440
            *aValEax = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEax;
 
1441
            *aValEbx = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEbx;
 
1442
            *aValEcx = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEcx;
 
1443
            *aValEdx = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEdx;
 
1444
            break;
 
1445
 
 
1446
        default:
 
1447
            return setError(E_INVALIDARG, tr("CpuId override leaf %#x is out of range"), aId);
 
1448
    }
 
1449
    return S_OK;
 
1450
}
 
1451
 
 
1452
STDMETHODIMP Machine::SetCpuIdLeaf(ULONG aId, ULONG aValEax, ULONG aValEbx, ULONG aValEcx, ULONG aValEdx)
 
1453
{
 
1454
    AutoCaller autoCaller(this);
 
1455
    CheckComRCReturnRC(autoCaller.rc());
 
1456
 
 
1457
    AutoWriteLock alock(this);
 
1458
 
 
1459
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1460
    CheckComRCReturnRC(rc);
 
1461
 
 
1462
    switch(aId)
 
1463
    {
 
1464
        case 0x0:
 
1465
        case 0x1:
 
1466
        case 0x2:
 
1467
        case 0x3:
 
1468
        case 0x4:
 
1469
        case 0x5:
 
1470
        case 0x6:
 
1471
        case 0x7:
 
1472
        case 0x8:
 
1473
        case 0x9:
 
1474
        case 0xA:
 
1475
            AssertCompile(RT_ELEMENTS(mHWData->mCpuIdStdLeafs) == 0xA);
 
1476
            AssertRelease(aId < RT_ELEMENTS(mHWData->mCpuIdStdLeafs));
 
1477
            mHWData->mCpuIdStdLeafs[aId].ulId  = aId;
 
1478
            mHWData->mCpuIdStdLeafs[aId].ulEax = aValEax;
 
1479
            mHWData->mCpuIdStdLeafs[aId].ulEbx = aValEbx;
 
1480
            mHWData->mCpuIdStdLeafs[aId].ulEcx = aValEcx;
 
1481
            mHWData->mCpuIdStdLeafs[aId].ulEdx = aValEdx;
 
1482
            break;
 
1483
 
 
1484
        case 0x80000000:
 
1485
        case 0x80000001:
 
1486
        case 0x80000002:
 
1487
        case 0x80000003:
 
1488
        case 0x80000004:
 
1489
        case 0x80000005:
 
1490
        case 0x80000006:
 
1491
        case 0x80000007:
 
1492
        case 0x80000008:
 
1493
        case 0x80000009:
 
1494
        case 0x8000000A:
 
1495
            AssertCompile(RT_ELEMENTS(mHWData->mCpuIdExtLeafs) == 0xA);
 
1496
            AssertRelease(aId - 0x80000000 < RT_ELEMENTS(mHWData->mCpuIdExtLeafs));
 
1497
            mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulId  = aId;
 
1498
            mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEax = aValEax;
 
1499
            mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEbx = aValEbx;
 
1500
            mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEcx = aValEcx;
 
1501
            mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEdx = aValEdx;
 
1502
            break;
 
1503
 
 
1504
        default:
 
1505
            return setError(E_INVALIDARG, tr("CpuId override leaf %#x is out of range"), aId);
 
1506
    }
 
1507
    return S_OK;
 
1508
}
 
1509
 
 
1510
STDMETHODIMP Machine::RemoveCpuIdLeaf(ULONG aId)
 
1511
{
 
1512
    AutoCaller autoCaller(this);
 
1513
    CheckComRCReturnRC(autoCaller.rc());
 
1514
 
 
1515
    AutoWriteLock alock(this);
 
1516
 
 
1517
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1518
    CheckComRCReturnRC(rc);
 
1519
 
 
1520
    switch(aId)
 
1521
    {
 
1522
        case 0x0:
 
1523
        case 0x1:
 
1524
        case 0x2:
 
1525
        case 0x3:
 
1526
        case 0x4:
 
1527
        case 0x5:
 
1528
        case 0x6:
 
1529
        case 0x7:
 
1530
        case 0x8:
 
1531
        case 0x9:
 
1532
        case 0xA:
 
1533
            AssertCompile(RT_ELEMENTS(mHWData->mCpuIdStdLeafs) == 0xA);
 
1534
            AssertRelease(aId < RT_ELEMENTS(mHWData->mCpuIdStdLeafs));
 
1535
            /* Invalidate leaf. */
 
1536
            mHWData->mCpuIdStdLeafs[aId].ulId = UINT32_MAX;
 
1537
            break;
 
1538
 
 
1539
        case 0x80000000:
 
1540
        case 0x80000001:
 
1541
        case 0x80000002:
 
1542
        case 0x80000003:
 
1543
        case 0x80000004:
 
1544
        case 0x80000005:
 
1545
        case 0x80000006:
 
1546
        case 0x80000007:
 
1547
        case 0x80000008:
 
1548
        case 0x80000009:
 
1549
        case 0x8000000A:
 
1550
            AssertCompile(RT_ELEMENTS(mHWData->mCpuIdExtLeafs) == 0xA);
 
1551
            AssertRelease(aId - 0x80000000 < RT_ELEMENTS(mHWData->mCpuIdExtLeafs));
 
1552
            /* Invalidate leaf. */
 
1553
            mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulId = UINT32_MAX;
 
1554
            break;
 
1555
 
 
1556
        default:
 
1557
            return setError(E_INVALIDARG, tr("CpuId override leaf %#x is out of range"), aId);
 
1558
    }
 
1559
    return S_OK;
 
1560
}
 
1561
 
 
1562
STDMETHODIMP Machine::RemoveAllCpuIdLeafs()
 
1563
{
 
1564
    AutoCaller autoCaller(this);
 
1565
    CheckComRCReturnRC(autoCaller.rc());
 
1566
 
 
1567
    AutoWriteLock alock(this);
 
1568
 
 
1569
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1570
    CheckComRCReturnRC(rc);
 
1571
 
 
1572
    /* Invalidate all standard leafs. */
 
1573
    for (unsigned i = 0; i < RT_ELEMENTS(mHWData->mCpuIdStdLeafs); i++)
 
1574
        mHWData->mCpuIdStdLeafs[i].ulId = UINT32_MAX;
 
1575
 
 
1576
    /* Invalidate all extended leafs. */
 
1577
    for (unsigned i = 0; i < RT_ELEMENTS(mHWData->mCpuIdExtLeafs); i++)
 
1578
        mHWData->mCpuIdExtLeafs[i].ulId = UINT32_MAX;
 
1579
 
 
1580
    return S_OK;
 
1581
}
 
1582
 
 
1583
STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL *aVal)
 
1584
{
 
1585
    if (!aVal)
 
1586
        return E_POINTER;
 
1587
 
 
1588
    AutoCaller autoCaller(this);
 
1589
    CheckComRCReturnRC(autoCaller.rc());
 
1590
 
 
1591
    AutoReadLock alock(this);
 
1592
 
 
1593
    switch(property)
 
1594
    {
 
1595
    case HWVirtExPropertyType_Enabled:
 
1596
        *aVal = mHWData->mHWVirtExEnabled;
 
1597
        break;
 
1598
 
 
1599
    case HWVirtExPropertyType_Exclusive:
 
1600
        *aVal = mHWData->mHWVirtExExclusive;
 
1601
        break;
 
1602
 
 
1603
    case HWVirtExPropertyType_VPID:
 
1604
        *aVal = mHWData->mHWVirtExVPIDEnabled;
 
1605
        break;
 
1606
 
 
1607
    case HWVirtExPropertyType_NestedPaging:
 
1608
        *aVal = mHWData->mHWVirtExNestedPagingEnabled;
 
1609
        break;
 
1610
 
 
1611
    default:
 
1612
        return E_INVALIDARG;
 
1613
    }
 
1614
    return S_OK;
 
1615
}
 
1616
 
 
1617
STDMETHODIMP Machine::SetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL aVal)
 
1618
{
 
1619
    AutoCaller autoCaller(this);
 
1620
    CheckComRCReturnRC(autoCaller.rc());
 
1621
 
 
1622
    AutoWriteLock alock(this);
 
1623
 
 
1624
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1625
    CheckComRCReturnRC(rc);
 
1626
 
 
1627
    switch(property)
 
1628
    {
 
1629
    case HWVirtExPropertyType_Enabled:
 
1630
        mHWData.backup();
 
1631
        mHWData->mHWVirtExEnabled = !!aVal;
 
1632
        break;
 
1633
 
 
1634
    case HWVirtExPropertyType_Exclusive:
 
1635
        mHWData.backup();
 
1636
        mHWData->mHWVirtExExclusive = !!aVal;
 
1637
        break;
 
1638
 
 
1639
    case HWVirtExPropertyType_VPID:
 
1640
        mHWData.backup();
 
1641
        mHWData->mHWVirtExVPIDEnabled = !!aVal;
 
1642
        break;
 
1643
 
 
1644
    case HWVirtExPropertyType_NestedPaging:
 
1645
        mHWData.backup();
 
1646
        mHWData->mHWVirtExNestedPagingEnabled = !!aVal;
 
1647
        break;
 
1648
 
 
1649
    default:
 
1650
        return E_INVALIDARG;
 
1651
    }
1365
1652
    return S_OK;
1366
1653
}
1367
1654
 
1368
1655
STDMETHODIMP Machine::COMGETTER(SnapshotFolder) (BSTR *aSnapshotFolder)
1369
1656
{
1370
 
    CheckComArgOutPointerValid (aSnapshotFolder);
1371
 
 
1372
 
    AutoCaller autoCaller (this);
1373
 
    CheckComRCReturnRC (autoCaller.rc());
1374
 
 
1375
 
    AutoReadLock alock (this);
1376
 
 
1377
 
    mUserData->mSnapshotFolderFull.cloneTo (aSnapshotFolder);
 
1657
    CheckComArgOutPointerValid(aSnapshotFolder);
 
1658
 
 
1659
    AutoCaller autoCaller(this);
 
1660
    CheckComRCReturnRC(autoCaller.rc());
 
1661
 
 
1662
    AutoReadLock alock(this);
 
1663
 
 
1664
    mUserData->mSnapshotFolderFull.cloneTo(aSnapshotFolder);
1378
1665
 
1379
1666
    return S_OK;
1380
1667
}
1389
1676
     *     place is #saveSettings().
1390
1677
     */
1391
1678
 
1392
 
    AutoCaller autoCaller (this);
1393
 
    CheckComRCReturnRC (autoCaller.rc());
1394
 
 
1395
 
    AutoWriteLock alock (this);
1396
 
 
1397
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1398
 
    CheckComRCReturnRC (rc);
 
1679
    AutoCaller autoCaller(this);
 
1680
    CheckComRCReturnRC(autoCaller.rc());
 
1681
 
 
1682
    AutoWriteLock alock(this);
 
1683
 
 
1684
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1685
    CheckComRCReturnRC(rc);
1399
1686
 
1400
1687
    if (!mData->mCurrentSnapshot.isNull())
1401
 
        return setError (E_FAIL,
1402
 
            tr ("The snapshot folder of a machine with snapshots cannot "
1403
 
                "be changed (please discard all snapshots first)"));
 
1688
        return setError(E_FAIL,
 
1689
                        tr("The snapshot folder of a machine with snapshots cannot be changed (please delete all snapshots first)"));
1404
1690
 
1405
1691
    Utf8Str snapshotFolder = aSnapshotFolder;
1406
1692
 
1419
1705
        }
1420
1706
    }
1421
1707
 
1422
 
    int vrc = calculateFullPath (snapshotFolder, snapshotFolder);
1423
 
    if (RT_FAILURE (vrc))
1424
 
        return setError (E_FAIL,
1425
 
            tr ("Invalid snapshot folder '%ls' (%Rrc)"),
1426
 
                aSnapshotFolder, vrc);
 
1708
    int vrc = calculateFullPath(snapshotFolder, snapshotFolder);
 
1709
    if (RT_FAILURE(vrc))
 
1710
        return setError(E_FAIL,
 
1711
                        tr("Invalid snapshot folder '%ls' (%Rrc)"),
 
1712
                        aSnapshotFolder, vrc);
1427
1713
 
1428
1714
    mUserData.backup();
1429
1715
    mUserData->mSnapshotFolder = aSnapshotFolder;
1432
1718
    return S_OK;
1433
1719
}
1434
1720
 
1435
 
STDMETHODIMP Machine::
1436
 
COMGETTER(HardDiskAttachments) (ComSafeArrayOut(IHardDiskAttachment *, aAttachments))
 
1721
STDMETHODIMP Machine::COMGETTER(MediumAttachments)(ComSafeArrayOut(IMediumAttachment*, aAttachments))
1437
1722
{
1438
 
    if (ComSafeArrayOutIsNull (aAttachments))
 
1723
    if (ComSafeArrayOutIsNull(aAttachments))
1439
1724
        return E_POINTER;
1440
1725
 
1441
 
    AutoCaller autoCaller (this);
1442
 
    CheckComRCReturnRC (autoCaller.rc());
1443
 
 
1444
 
    AutoReadLock alock (this);
1445
 
 
1446
 
    SafeIfaceArray<IHardDiskAttachment> attachments (mHDData->mAttachments);
1447
 
    attachments.detachTo (ComSafeArrayOutArg (aAttachments));
 
1726
    AutoCaller autoCaller(this);
 
1727
    CheckComRCReturnRC(autoCaller.rc());
 
1728
 
 
1729
    AutoReadLock alock(this);
 
1730
 
 
1731
    SafeIfaceArray<IMediumAttachment> attachments(mMediaData->mAttachments);
 
1732
    attachments.detachTo(ComSafeArrayOutArg(aAttachments));
1448
1733
 
1449
1734
    return S_OK;
1450
1735
}
1455
1740
    if (!vrdpServer)
1456
1741
        return E_POINTER;
1457
1742
 
1458
 
    AutoCaller autoCaller (this);
1459
 
    CheckComRCReturnRC (autoCaller.rc());
 
1743
    AutoCaller autoCaller(this);
 
1744
    CheckComRCReturnRC(autoCaller.rc());
1460
1745
 
1461
 
    AutoReadLock alock (this);
 
1746
    AutoReadLock alock(this);
1462
1747
 
1463
1748
    Assert (!!mVRDPServer);
1464
 
    mVRDPServer.queryInterfaceTo (vrdpServer);
 
1749
    mVRDPServer.queryInterfaceTo(vrdpServer);
1465
1750
 
1466
1751
    return S_OK;
1467
1752
#else
1470
1755
#endif
1471
1756
}
1472
1757
 
1473
 
STDMETHODIMP Machine::COMGETTER(DVDDrive) (IDVDDrive **dvdDrive)
1474
 
{
1475
 
    if (!dvdDrive)
1476
 
        return E_POINTER;
1477
 
 
1478
 
    AutoCaller autoCaller (this);
1479
 
    CheckComRCReturnRC (autoCaller.rc());
1480
 
 
1481
 
    AutoReadLock alock (this);
1482
 
 
1483
 
    Assert (!!mDVDDrive);
1484
 
    mDVDDrive.queryInterfaceTo (dvdDrive);
1485
 
    return S_OK;
1486
 
}
1487
 
 
1488
 
STDMETHODIMP Machine::COMGETTER(FloppyDrive) (IFloppyDrive **floppyDrive)
1489
 
{
1490
 
    if (!floppyDrive)
1491
 
        return E_POINTER;
1492
 
 
1493
 
    AutoCaller autoCaller (this);
1494
 
    CheckComRCReturnRC (autoCaller.rc());
1495
 
 
1496
 
    AutoReadLock alock (this);
1497
 
 
1498
 
    Assert (!!mFloppyDrive);
1499
 
    mFloppyDrive.queryInterfaceTo (floppyDrive);
1500
 
    return S_OK;
1501
 
}
1502
 
 
1503
1758
STDMETHODIMP Machine::COMGETTER(AudioAdapter)(IAudioAdapter **audioAdapter)
1504
1759
{
1505
1760
    if (!audioAdapter)
1506
1761
        return E_POINTER;
1507
1762
 
1508
 
    AutoCaller autoCaller (this);
1509
 
    CheckComRCReturnRC (autoCaller.rc());
1510
 
 
1511
 
    AutoReadLock alock (this);
1512
 
 
1513
 
    mAudioAdapter.queryInterfaceTo (audioAdapter);
 
1763
    AutoCaller autoCaller(this);
 
1764
    CheckComRCReturnRC(autoCaller.rc());
 
1765
 
 
1766
    AutoReadLock alock(this);
 
1767
 
 
1768
    mAudioAdapter.queryInterfaceTo(audioAdapter);
1514
1769
    return S_OK;
1515
1770
}
1516
1771
 
1517
1772
STDMETHODIMP Machine::COMGETTER(USBController) (IUSBController **aUSBController)
1518
1773
{
1519
1774
#ifdef VBOX_WITH_USB
1520
 
    CheckComArgOutPointerValid (aUSBController);
 
1775
    CheckComArgOutPointerValid(aUSBController);
1521
1776
 
1522
 
    AutoCaller autoCaller (this);
1523
 
    CheckComRCReturnRC (autoCaller.rc());
 
1777
    AutoCaller autoCaller(this);
 
1778
    CheckComRCReturnRC(autoCaller.rc());
1524
1779
 
1525
1780
    MultiResult rc = mParent->host()->checkUSBProxyService();
1526
 
    CheckComRCReturnRC (rc);
1527
 
 
1528
 
    AutoReadLock alock (this);
1529
 
 
1530
 
    return rc = mUSBController.queryInterfaceTo (aUSBController);
 
1781
    CheckComRCReturnRC(rc);
 
1782
 
 
1783
    AutoReadLock alock(this);
 
1784
 
 
1785
    return rc = mUSBController.queryInterfaceTo(aUSBController);
1531
1786
#else
1532
1787
    /* Note: The GUI depends on this method returning E_NOTIMPL with no
1533
1788
     * extended error info to indicate that USB is simply not available
1539
1794
 
1540
1795
STDMETHODIMP Machine::COMGETTER(SettingsFilePath) (BSTR *aFilePath)
1541
1796
{
1542
 
    CheckComArgOutPointerValid (aFilePath);
1543
 
 
1544
 
    AutoLimitedCaller autoCaller (this);
1545
 
    CheckComRCReturnRC (autoCaller.rc());
1546
 
 
1547
 
    AutoReadLock alock (this);
1548
 
 
1549
 
    mData->mConfigFileFull.cloneTo (aFilePath);
1550
 
    return S_OK;
1551
 
}
1552
 
 
1553
 
STDMETHODIMP Machine::
1554
 
COMGETTER(SettingsFileVersion) (BSTR *aSettingsFileVersion)
1555
 
{
1556
 
    CheckComArgOutPointerValid (aSettingsFileVersion);
1557
 
 
1558
 
    AutoCaller autoCaller (this);
1559
 
    CheckComRCReturnRC (autoCaller.rc());
1560
 
 
1561
 
    AutoReadLock alock (this);
1562
 
 
1563
 
    mData->mSettingsFileVersion.cloneTo (aSettingsFileVersion);
 
1797
    CheckComArgOutPointerValid(aFilePath);
 
1798
 
 
1799
    AutoLimitedCaller autoCaller(this);
 
1800
    CheckComRCReturnRC(autoCaller.rc());
 
1801
 
 
1802
    AutoReadLock alock(this);
 
1803
 
 
1804
    mData->m_strConfigFileFull.cloneTo(aFilePath);
1564
1805
    return S_OK;
1565
1806
}
1566
1807
 
1567
1808
STDMETHODIMP Machine::COMGETTER(SettingsModified) (BOOL *aModified)
1568
1809
{
1569
 
    CheckComArgOutPointerValid (aModified);
1570
 
 
1571
 
    AutoCaller autoCaller (this);
1572
 
    CheckComRCReturnRC (autoCaller.rc());
1573
 
 
1574
 
    AutoWriteLock alock (this);
1575
 
 
1576
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1577
 
    CheckComRCReturnRC (rc);
1578
 
 
1579
 
    if (!isConfigLocked())
1580
 
    {
1581
 
        /*
1582
 
         *  if we're ready and isConfigLocked() is FALSE then it means
1583
 
         *  that no config file exists yet, so always return TRUE
1584
 
         */
 
1810
    CheckComArgOutPointerValid(aModified);
 
1811
 
 
1812
    AutoCaller autoCaller(this);
 
1813
    CheckComRCReturnRC(autoCaller.rc());
 
1814
 
 
1815
    AutoWriteLock alock(this);
 
1816
 
 
1817
    HRESULT rc = checkStateDependency(MutableStateDep);
 
1818
    CheckComRCReturnRC(rc);
 
1819
 
 
1820
    if (mData->mInitMode == Init_New)
 
1821
          /*
 
1822
           *  if this is a new machine then no config file exists yet, so always return TRUE
 
1823
           */
1585
1824
        *aModified = TRUE;
1586
 
    }
1587
1825
    else
1588
 
    {
1589
1826
        *aModified = isModified();
1590
 
    }
1591
1827
 
1592
1828
    return S_OK;
1593
1829
}
1594
1830
 
1595
1831
STDMETHODIMP Machine::COMGETTER(SessionState) (SessionState_T *aSessionState)
1596
1832
{
1597
 
    CheckComArgOutPointerValid (aSessionState);
1598
 
 
1599
 
    AutoCaller autoCaller (this);
1600
 
    CheckComRCReturnRC (autoCaller.rc());
1601
 
 
1602
 
    AutoReadLock alock (this);
 
1833
    CheckComArgOutPointerValid(aSessionState);
 
1834
 
 
1835
    AutoCaller autoCaller(this);
 
1836
    CheckComRCReturnRC(autoCaller.rc());
 
1837
 
 
1838
    AutoReadLock alock(this);
1603
1839
 
1604
1840
    *aSessionState = mData->mSession.mState;
1605
1841
 
1608
1844
 
1609
1845
STDMETHODIMP Machine::COMGETTER(SessionType) (BSTR *aSessionType)
1610
1846
{
1611
 
    CheckComArgOutPointerValid (aSessionType);
1612
 
 
1613
 
    AutoCaller autoCaller (this);
1614
 
    CheckComRCReturnRC (autoCaller.rc());
1615
 
 
1616
 
    AutoReadLock alock (this);
 
1847
    CheckComArgOutPointerValid(aSessionType);
 
1848
 
 
1849
    AutoCaller autoCaller(this);
 
1850
    CheckComRCReturnRC(autoCaller.rc());
 
1851
 
 
1852
    AutoReadLock alock(this);
1617
1853
 
1618
1854
    if (mData->mSession.mType.isNull())
1619
1855
        Bstr("").cloneTo(aSessionType);
1620
1856
    else
1621
 
        mData->mSession.mType.cloneTo (aSessionType);
 
1857
        mData->mSession.mType.cloneTo(aSessionType);
1622
1858
 
1623
1859
    return S_OK;
1624
1860
}
1625
1861
 
1626
1862
STDMETHODIMP Machine::COMGETTER(SessionPid) (ULONG *aSessionPid)
1627
1863
{
1628
 
    CheckComArgOutPointerValid (aSessionPid);
1629
 
 
1630
 
    AutoCaller autoCaller (this);
1631
 
    CheckComRCReturnRC (autoCaller.rc());
1632
 
 
1633
 
    AutoReadLock alock (this);
 
1864
    CheckComArgOutPointerValid(aSessionPid);
 
1865
 
 
1866
    AutoCaller autoCaller(this);
 
1867
    CheckComRCReturnRC(autoCaller.rc());
 
1868
 
 
1869
    AutoReadLock alock(this);
1634
1870
 
1635
1871
    *aSessionPid = mData->mSession.mPid;
1636
1872
 
1642
1878
    if (!machineState)
1643
1879
        return E_POINTER;
1644
1880
 
1645
 
    AutoCaller autoCaller (this);
1646
 
    CheckComRCReturnRC (autoCaller.rc());
 
1881
    AutoCaller autoCaller(this);
 
1882
    CheckComRCReturnRC(autoCaller.rc());
1647
1883
 
1648
 
    AutoReadLock alock (this);
 
1884
    AutoReadLock alock(this);
1649
1885
 
1650
1886
    *machineState = mData->mMachineState;
1651
1887
 
1654
1890
 
1655
1891
STDMETHODIMP Machine::COMGETTER(LastStateChange) (LONG64 *aLastStateChange)
1656
1892
{
1657
 
    CheckComArgOutPointerValid (aLastStateChange);
1658
 
 
1659
 
    AutoCaller autoCaller (this);
1660
 
    CheckComRCReturnRC (autoCaller.rc());
1661
 
 
1662
 
    AutoReadLock alock (this);
 
1893
    CheckComArgOutPointerValid(aLastStateChange);
 
1894
 
 
1895
    AutoCaller autoCaller(this);
 
1896
    CheckComRCReturnRC(autoCaller.rc());
 
1897
 
 
1898
    AutoReadLock alock(this);
1663
1899
 
1664
1900
    *aLastStateChange = RTTimeSpecGetMilli (&mData->mLastStateChange);
1665
1901
 
1668
1904
 
1669
1905
STDMETHODIMP Machine::COMGETTER(StateFilePath) (BSTR *aStateFilePath)
1670
1906
{
1671
 
    CheckComArgOutPointerValid (aStateFilePath);
1672
 
 
1673
 
    AutoCaller autoCaller (this);
1674
 
    CheckComRCReturnRC (autoCaller.rc());
1675
 
 
1676
 
    AutoReadLock alock (this);
 
1907
    CheckComArgOutPointerValid(aStateFilePath);
 
1908
 
 
1909
    AutoCaller autoCaller(this);
 
1910
    CheckComRCReturnRC(autoCaller.rc());
 
1911
 
 
1912
    AutoReadLock alock(this);
1677
1913
 
1678
1914
    if (mSSData->mStateFilePath.isEmpty())
1679
1915
        Bstr("").cloneTo(aStateFilePath);
1680
1916
    else
1681
 
        mSSData->mStateFilePath.cloneTo (aStateFilePath);
 
1917
        mSSData->mStateFilePath.cloneTo(aStateFilePath);
1682
1918
 
1683
1919
    return S_OK;
1684
1920
}
1685
1921
 
1686
1922
STDMETHODIMP Machine::COMGETTER(LogFolder) (BSTR *aLogFolder)
1687
1923
{
1688
 
    CheckComArgOutPointerValid (aLogFolder);
1689
 
 
1690
 
    AutoCaller autoCaller (this);
1691
 
    AssertComRCReturnRC (autoCaller.rc());
1692
 
 
1693
 
    AutoReadLock alock (this);
 
1924
    CheckComArgOutPointerValid(aLogFolder);
 
1925
 
 
1926
    AutoCaller autoCaller(this);
 
1927
    AssertComRCReturnRC(autoCaller.rc());
 
1928
 
 
1929
    AutoReadLock alock(this);
1694
1930
 
1695
1931
    Utf8Str logFolder;
1696
1932
    getLogFolder (logFolder);
1697
1933
 
1698
 
    Bstr (logFolder).cloneTo (aLogFolder);
 
1934
    Bstr (logFolder).cloneTo(aLogFolder);
1699
1935
 
1700
1936
    return S_OK;
1701
1937
}
1702
1938
 
1703
1939
STDMETHODIMP Machine::COMGETTER(CurrentSnapshot) (ISnapshot **aCurrentSnapshot)
1704
1940
{
1705
 
    CheckComArgOutPointerValid (aCurrentSnapshot);
1706
 
 
1707
 
    AutoCaller autoCaller (this);
1708
 
    CheckComRCReturnRC (autoCaller.rc());
1709
 
 
1710
 
    AutoReadLock alock (this);
1711
 
 
1712
 
    mData->mCurrentSnapshot.queryInterfaceTo (aCurrentSnapshot);
 
1941
    CheckComArgOutPointerValid(aCurrentSnapshot);
 
1942
 
 
1943
    AutoCaller autoCaller(this);
 
1944
    CheckComRCReturnRC(autoCaller.rc());
 
1945
 
 
1946
    AutoReadLock alock(this);
 
1947
 
 
1948
    mData->mCurrentSnapshot.queryInterfaceTo(aCurrentSnapshot);
1713
1949
 
1714
1950
    return S_OK;
1715
1951
}
1716
1952
 
1717
 
STDMETHODIMP Machine::COMGETTER(SnapshotCount) (ULONG *aSnapshotCount)
 
1953
STDMETHODIMP Machine::COMGETTER(SnapshotCount)(ULONG *aSnapshotCount)
1718
1954
{
1719
 
    CheckComArgOutPointerValid (aSnapshotCount);
1720
 
 
1721
 
    AutoCaller autoCaller (this);
1722
 
    CheckComRCReturnRC (autoCaller.rc());
1723
 
 
1724
 
    AutoReadLock alock (this);
1725
 
 
1726
 
    *aSnapshotCount = !mData->mFirstSnapshot ? 0 :
1727
 
                      mData->mFirstSnapshot->descendantCount() + 1 /* self */;
 
1955
    CheckComArgOutPointerValid(aSnapshotCount);
 
1956
 
 
1957
    AutoCaller autoCaller(this);
 
1958
    CheckComRCReturnRC(autoCaller.rc());
 
1959
 
 
1960
    AutoReadLock alock(this);
 
1961
 
 
1962
    *aSnapshotCount = mData->mFirstSnapshot.isNull()
 
1963
                          ? 0
 
1964
                          : mData->mFirstSnapshot->getAllChildrenCount() + 1;
1728
1965
 
1729
1966
    return S_OK;
1730
1967
}
1731
1968
 
1732
1969
STDMETHODIMP Machine::COMGETTER(CurrentStateModified) (BOOL *aCurrentStateModified)
1733
1970
{
1734
 
    CheckComArgOutPointerValid (aCurrentStateModified);
1735
 
 
1736
 
    AutoCaller autoCaller (this);
1737
 
    CheckComRCReturnRC (autoCaller.rc());
1738
 
 
1739
 
    AutoReadLock alock (this);
 
1971
    CheckComArgOutPointerValid(aCurrentStateModified);
 
1972
 
 
1973
    AutoCaller autoCaller(this);
 
1974
    CheckComRCReturnRC(autoCaller.rc());
 
1975
 
 
1976
    AutoReadLock alock(this);
1740
1977
 
1741
1978
    /* Note: for machines with no snapshots, we always return FALSE
1742
1979
     * (mData->mCurrentStateModified will be TRUE in this case, for historical
1743
1980
     * reasons :) */
1744
1981
 
1745
 
    *aCurrentStateModified = !mData->mFirstSnapshot ? FALSE :
1746
 
                             mData->mCurrentStateModified;
1747
 
 
1748
 
    return S_OK;
1749
 
}
1750
 
 
1751
 
STDMETHODIMP
1752
 
Machine::COMGETTER(SharedFolders) (ComSafeArrayOut (ISharedFolder *, aSharedFolders))
1753
 
{
1754
 
    CheckComArgOutSafeArrayPointerValid (aSharedFolders);
1755
 
 
1756
 
    AutoCaller autoCaller (this);
1757
 
    CheckComRCReturnRC (autoCaller.rc());
1758
 
 
1759
 
    AutoReadLock alock (this);
1760
 
 
1761
 
    SafeIfaceArray <ISharedFolder> folders (mHWData->mSharedFolders);
1762
 
    folders.detachTo (ComSafeArrayOutArg(aSharedFolders));
1763
 
 
1764
 
    return S_OK;
1765
 
}
1766
 
 
1767
 
STDMETHODIMP
1768
 
Machine::COMGETTER(ClipboardMode) (ClipboardMode_T *aClipboardMode)
1769
 
{
1770
 
    CheckComArgOutPointerValid (aClipboardMode);
1771
 
 
1772
 
    AutoCaller autoCaller (this);
1773
 
    CheckComRCReturnRC (autoCaller.rc());
1774
 
 
1775
 
    AutoReadLock alock (this);
 
1982
    *aCurrentStateModified = mData->mFirstSnapshot.isNull()
 
1983
                            ? FALSE
 
1984
                            : mData->mCurrentStateModified;
 
1985
 
 
1986
    return S_OK;
 
1987
}
 
1988
 
 
1989
STDMETHODIMP Machine::COMGETTER(SharedFolders) (ComSafeArrayOut(ISharedFolder *, aSharedFolders))
 
1990
{
 
1991
    CheckComArgOutSafeArrayPointerValid(aSharedFolders);
 
1992
 
 
1993
    AutoCaller autoCaller(this);
 
1994
    CheckComRCReturnRC(autoCaller.rc());
 
1995
 
 
1996
    AutoReadLock alock(this);
 
1997
 
 
1998
    SafeIfaceArray<ISharedFolder> folders(mHWData->mSharedFolders);
 
1999
    folders.detachTo(ComSafeArrayOutArg(aSharedFolders));
 
2000
 
 
2001
    return S_OK;
 
2002
}
 
2003
 
 
2004
STDMETHODIMP Machine::COMGETTER(ClipboardMode) (ClipboardMode_T *aClipboardMode)
 
2005
{
 
2006
    CheckComArgOutPointerValid(aClipboardMode);
 
2007
 
 
2008
    AutoCaller autoCaller(this);
 
2009
    CheckComRCReturnRC(autoCaller.rc());
 
2010
 
 
2011
    AutoReadLock alock(this);
1776
2012
 
1777
2013
    *aClipboardMode = mHWData->mClipboardMode;
1778
2014
 
1782
2018
STDMETHODIMP
1783
2019
Machine::COMSETTER(ClipboardMode) (ClipboardMode_T aClipboardMode)
1784
2020
{
1785
 
    AutoCaller autoCaller (this);
1786
 
    CheckComRCReturnRC (autoCaller.rc());
1787
 
 
1788
 
    AutoWriteLock alock (this);
1789
 
 
1790
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1791
 
    CheckComRCReturnRC (rc);
 
2021
    AutoCaller autoCaller(this);
 
2022
    CheckComRCReturnRC(autoCaller.rc());
 
2023
 
 
2024
    AutoWriteLock alock(this);
 
2025
 
 
2026
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2027
    CheckComRCReturnRC(rc);
1792
2028
 
1793
2029
    mHWData.backup();
1794
2030
    mHWData->mClipboardMode = aClipboardMode;
1797
2033
}
1798
2034
 
1799
2035
STDMETHODIMP
1800
 
Machine::COMGETTER(GuestPropertyNotificationPatterns) (BSTR *aPatterns)
 
2036
Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns)
1801
2037
{
1802
 
    CheckComArgOutPointerValid (aPatterns);
1803
 
 
1804
 
    AutoCaller autoCaller (this);
1805
 
    CheckComRCReturnRC (autoCaller.rc());
1806
 
 
1807
 
    AutoReadLock alock (this);
1808
 
 
1809
 
    mHWData->mGuestPropertyNotificationPatterns.cloneTo (aPatterns);
1810
 
 
1811
 
    return RT_LIKELY (aPatterns != NULL) ? S_OK : E_OUTOFMEMORY;
 
2038
    CheckComArgOutPointerValid(aPatterns);
 
2039
 
 
2040
    AutoCaller autoCaller(this);
 
2041
    CheckComRCReturnRC(autoCaller.rc());
 
2042
 
 
2043
    AutoReadLock alock(this);
 
2044
 
 
2045
    try
 
2046
    {
 
2047
        mHWData->mGuestPropertyNotificationPatterns.cloneTo(aPatterns);
 
2048
    }
 
2049
    catch (...)
 
2050
    {
 
2051
        return VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
 
2052
    }
 
2053
 
 
2054
    return S_OK;
1812
2055
}
1813
2056
 
1814
2057
STDMETHODIMP
1815
 
Machine::COMSETTER(GuestPropertyNotificationPatterns) (IN_BSTR aPatterns)
 
2058
Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns)
1816
2059
{
1817
 
    AssertLogRelReturn (VALID_PTR (aPatterns), E_POINTER);
1818
 
    AutoCaller autoCaller (this);
1819
 
    CheckComRCReturnRC (autoCaller.rc());
1820
 
 
1821
 
    AutoWriteLock alock (this);
1822
 
 
1823
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1824
 
    CheckComRCReturnRC (rc);
1825
 
 
1826
 
    mHWData.backup();
1827
 
    mHWData->mGuestPropertyNotificationPatterns = aPatterns;
1828
 
 
1829
 
    return RT_LIKELY (!mHWData->mGuestPropertyNotificationPatterns.isNull())
1830
 
               ? S_OK : E_OUTOFMEMORY;
 
2060
    CheckComArgNotNull(aPatterns);
 
2061
    AutoCaller autoCaller(this);
 
2062
    CheckComRCReturnRC(autoCaller.rc());
 
2063
 
 
2064
    AutoWriteLock alock(this);
 
2065
 
 
2066
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2067
    CheckComRCReturnRC(rc);
 
2068
 
 
2069
    try
 
2070
    {
 
2071
        mHWData.backup();
 
2072
        mHWData->mGuestPropertyNotificationPatterns = aPatterns;
 
2073
    }
 
2074
    catch (...)
 
2075
    {
 
2076
        rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
 
2077
    }
 
2078
    return rc;
1831
2079
}
1832
2080
 
1833
2081
STDMETHODIMP
1834
2082
Machine::COMGETTER(StorageControllers) (ComSafeArrayOut(IStorageController *, aStorageControllers))
1835
2083
{
1836
 
    CheckComArgOutSafeArrayPointerValid (aStorageControllers);
1837
 
 
1838
 
    AutoCaller autoCaller (this);
1839
 
    CheckComRCReturnRC (autoCaller.rc());
1840
 
 
1841
 
    AutoReadLock alock (this);
1842
 
 
1843
 
    SafeIfaceArray <IStorageController> ctrls (*mStorageControllers.data());
1844
 
    ctrls.detachTo (ComSafeArrayOutArg(aStorageControllers));
1845
 
 
1846
 
    return S_OK;
1847
 
}
 
2084
    CheckComArgOutSafeArrayPointerValid(aStorageControllers);
 
2085
 
 
2086
    AutoCaller autoCaller(this);
 
2087
    CheckComRCReturnRC(autoCaller.rc());
 
2088
 
 
2089
    AutoReadLock alock(this);
 
2090
 
 
2091
    SafeIfaceArray<IStorageController> ctrls (*mStorageControllers.data());
 
2092
    ctrls.detachTo(ComSafeArrayOutArg(aStorageControllers));
 
2093
 
 
2094
    return S_OK;
 
2095
}
 
2096
 
 
2097
STDMETHODIMP
 
2098
Machine::COMGETTER(TeleporterEnabled)(BOOL *aEnabled)
 
2099
{
 
2100
    CheckComArgOutPointerValid(aEnabled);
 
2101
 
 
2102
    AutoCaller autoCaller(this);
 
2103
    CheckComRCReturnRC(autoCaller.rc());
 
2104
 
 
2105
    AutoReadLock alock(this);
 
2106
 
 
2107
    *aEnabled = mUserData->mTeleporterEnabled;
 
2108
 
 
2109
    return S_OK;
 
2110
}
 
2111
 
 
2112
STDMETHODIMP
 
2113
Machine::COMSETTER(TeleporterEnabled)(BOOL aEnabled)
 
2114
{
 
2115
    AutoCaller autoCaller(this);
 
2116
    CheckComRCReturnRC(autoCaller.rc());
 
2117
 
 
2118
    AutoWriteLock alock(this);
 
2119
 
 
2120
    /* Only allow it to be set to true when PoweredOff or Aborted.
 
2121
       (Clearing it is always permitted.) */
 
2122
    if (    aEnabled
 
2123
        &&  mData->mRegistered
 
2124
        &&  (   mType != IsSessionMachine
 
2125
             || (   mData->mMachineState != MachineState_PoweredOff
 
2126
                 && mData->mMachineState != MachineState_Teleported
 
2127
                 && mData->mMachineState != MachineState_Aborted
 
2128
                )
 
2129
            )
 
2130
       )
 
2131
        return setError(VBOX_E_INVALID_VM_STATE,
 
2132
                        tr("The machine is not powered off (state is %s)"),
 
2133
                        Global::stringifyMachineState(mData->mMachineState));
 
2134
 
 
2135
    mUserData.backup();
 
2136
    mUserData->mTeleporterEnabled = aEnabled;
 
2137
 
 
2138
    return S_OK;
 
2139
}
 
2140
 
 
2141
STDMETHODIMP
 
2142
Machine::COMGETTER(TeleporterPort)(ULONG *aPort)
 
2143
{
 
2144
    CheckComArgOutPointerValid(aPort);
 
2145
 
 
2146
    AutoCaller autoCaller(this);
 
2147
    CheckComRCReturnRC(autoCaller.rc());
 
2148
 
 
2149
    AutoReadLock alock(this);
 
2150
 
 
2151
    *aPort = mUserData->mTeleporterPort;
 
2152
 
 
2153
    return S_OK;
 
2154
}
 
2155
 
 
2156
STDMETHODIMP
 
2157
Machine::COMSETTER(TeleporterPort)(ULONG aPort)
 
2158
{
 
2159
    if (aPort >= _64K)
 
2160
        return setError(E_INVALIDARG, tr("Invalid port number %d"), aPort);
 
2161
 
 
2162
    AutoCaller autoCaller(this);
 
2163
    CheckComRCReturnRC(autoCaller.rc());
 
2164
 
 
2165
    AutoWriteLock alock(this);
 
2166
 
 
2167
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2168
    CheckComRCReturnRC(rc);
 
2169
 
 
2170
    mUserData.backup();
 
2171
    mUserData->mTeleporterPort = aPort;
 
2172
 
 
2173
    return S_OK;
 
2174
}
 
2175
 
 
2176
STDMETHODIMP
 
2177
Machine::COMGETTER(TeleporterAddress)(BSTR *aAddress)
 
2178
{
 
2179
    CheckComArgOutPointerValid(aAddress);
 
2180
 
 
2181
    AutoCaller autoCaller(this);
 
2182
    CheckComRCReturnRC(autoCaller.rc());
 
2183
 
 
2184
    AutoReadLock alock(this);
 
2185
 
 
2186
    mUserData->mTeleporterAddress.cloneTo(aAddress);
 
2187
 
 
2188
    return S_OK;
 
2189
}
 
2190
 
 
2191
STDMETHODIMP
 
2192
Machine::COMSETTER(TeleporterAddress)(IN_BSTR aAddress)
 
2193
{
 
2194
    AutoCaller autoCaller(this);
 
2195
    CheckComRCReturnRC(autoCaller.rc());
 
2196
 
 
2197
    AutoWriteLock alock(this);
 
2198
 
 
2199
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2200
    CheckComRCReturnRC(rc);
 
2201
 
 
2202
    mUserData.backup();
 
2203
    mUserData->mTeleporterAddress = aAddress;
 
2204
 
 
2205
    return S_OK;
 
2206
}
 
2207
 
 
2208
STDMETHODIMP
 
2209
Machine::COMGETTER(TeleporterPassword)(BSTR *aPassword)
 
2210
{
 
2211
    CheckComArgOutPointerValid(aPassword);
 
2212
 
 
2213
    AutoCaller autoCaller(this);
 
2214
    CheckComRCReturnRC(autoCaller.rc());
 
2215
 
 
2216
    AutoReadLock alock(this);
 
2217
 
 
2218
    mUserData->mTeleporterPassword.cloneTo(aPassword);
 
2219
 
 
2220
    return S_OK;
 
2221
}
 
2222
 
 
2223
STDMETHODIMP
 
2224
Machine::COMSETTER(TeleporterPassword)(IN_BSTR aPassword)
 
2225
{
 
2226
    AutoCaller autoCaller(this);
 
2227
    CheckComRCReturnRC(autoCaller.rc());
 
2228
 
 
2229
    AutoWriteLock alock(this);
 
2230
 
 
2231
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2232
    CheckComRCReturnRC(rc);
 
2233
 
 
2234
    mUserData.backup();
 
2235
    mUserData->mTeleporterPassword = aPassword;
 
2236
 
 
2237
    return S_OK;
 
2238
}
 
2239
 
1848
2240
 
1849
2241
// IMachine methods
1850
2242
/////////////////////////////////////////////////////////////////////////////
1852
2244
STDMETHODIMP Machine::SetBootOrder (ULONG aPosition, DeviceType_T aDevice)
1853
2245
{
1854
2246
    if (aPosition < 1 || aPosition > SchemaDefs::MaxBootPosition)
1855
 
        return setError (E_INVALIDARG,
1856
 
            tr ("Invalid boot position: %lu (must be in range [1, %lu])"),
1857
 
                aPosition, SchemaDefs::MaxBootPosition);
 
2247
        return setError(E_INVALIDARG,
 
2248
                        tr ("Invalid boot position: %lu (must be in range [1, %lu])"),
 
2249
                        aPosition, SchemaDefs::MaxBootPosition);
1858
2250
 
1859
2251
    if (aDevice == DeviceType_USB)
1860
 
        return setError (E_NOTIMPL,
1861
 
            tr ("Booting from USB device is currently not supported"));
1862
 
 
1863
 
    AutoCaller autoCaller (this);
1864
 
    CheckComRCReturnRC (autoCaller.rc());
1865
 
 
1866
 
    AutoWriteLock alock (this);
1867
 
 
1868
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1869
 
    CheckComRCReturnRC (rc);
 
2252
        return setError(E_NOTIMPL,
 
2253
                        tr("Booting from USB device is currently not supported"));
 
2254
 
 
2255
    AutoCaller autoCaller(this);
 
2256
    CheckComRCReturnRC(autoCaller.rc());
 
2257
 
 
2258
    AutoWriteLock alock(this);
 
2259
 
 
2260
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2261
    CheckComRCReturnRC(rc);
1870
2262
 
1871
2263
    mHWData.backup();
1872
2264
    mHWData->mBootOrder [aPosition - 1] = aDevice;
1877
2269
STDMETHODIMP Machine::GetBootOrder (ULONG aPosition, DeviceType_T *aDevice)
1878
2270
{
1879
2271
    if (aPosition < 1 || aPosition > SchemaDefs::MaxBootPosition)
1880
 
        return setError (E_INVALIDARG,
1881
 
            tr ("Invalid boot position: %lu (must be in range [1, %lu])"),
1882
 
                aPosition, SchemaDefs::MaxBootPosition);
1883
 
 
1884
 
    AutoCaller autoCaller (this);
1885
 
    CheckComRCReturnRC (autoCaller.rc());
1886
 
 
1887
 
    AutoReadLock alock (this);
 
2272
        return setError(E_INVALIDARG,
 
2273
                       tr("Invalid boot position: %lu (must be in range [1, %lu])"),
 
2274
                       aPosition, SchemaDefs::MaxBootPosition);
 
2275
 
 
2276
    AutoCaller autoCaller(this);
 
2277
    CheckComRCReturnRC(autoCaller.rc());
 
2278
 
 
2279
    AutoReadLock alock(this);
1888
2280
 
1889
2281
    *aDevice = mHWData->mBootOrder [aPosition - 1];
1890
2282
 
1891
2283
    return S_OK;
1892
2284
}
1893
2285
 
1894
 
STDMETHODIMP Machine::AttachHardDisk(IN_BSTR aId,
1895
 
                                     IN_BSTR aControllerName, LONG aControllerPort,
1896
 
                                     LONG aDevice)
 
2286
STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
 
2287
                                   LONG aControllerPort,
 
2288
                                   LONG aDevice,
 
2289
                                   DeviceType_T aType,
 
2290
                                   IN_BSTR aId)
1897
2291
{
1898
 
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
1899
 
                     aControllerName, aControllerPort, aDevice));
1900
 
 
1901
 
    AutoCaller autoCaller (this);
1902
 
    CheckComRCReturnRC (autoCaller.rc());
1903
 
 
1904
 
    /* VirtualBox::findHardDisk() need read lock; also we want to make sure the
1905
 
     * hard disk object we pick up doesn't get unregistered before we finish. */
1906
 
    AutoReadLock vboxLock (mParent);
1907
 
    AutoWriteLock alock (this);
1908
 
 
1909
 
    HRESULT rc = checkStateDependency (MutableStateDep);
1910
 
    CheckComRCReturnRC (rc);
 
2292
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aType=%d aId=\"%ls\"\n",
 
2293
                     aControllerName, aControllerPort, aDevice, aType, aId));
 
2294
 
 
2295
    CheckComArgNotNull(aControllerName);
 
2296
    CheckComArgNotNull(aId);
 
2297
 
 
2298
    AutoCaller autoCaller(this);
 
2299
    CheckComRCReturnRC(autoCaller.rc());
 
2300
 
 
2301
    /* VirtualBox::findHardDisk() and the corresponding other methods for
 
2302
     * DVD and floppy media need *write* lock (for getting rid of unneeded
 
2303
     * host drives which got enumerated); also we want to make sure the
 
2304
     * media object we pick up doesn't get unregistered before we finish. */
 
2305
    AutoMultiWriteLock2 alock(mParent, this);
 
2306
 
 
2307
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2308
    CheckComRCReturnRC(rc);
1911
2309
 
1912
2310
    /// @todo NEWMEDIA implicit machine registration
1913
2311
    if (!mData->mRegistered)
1914
 
        return setError (VBOX_E_INVALID_OBJECT_STATE,
1915
 
            tr ("Cannot attach hard disks to an unregistered machine"));
1916
 
 
1917
 
    AssertReturn (mData->mMachineState != MachineState_Saved, E_FAIL);
1918
 
 
1919
 
    if (Global::IsOnlineOrTransient (mData->mMachineState))
1920
 
        return setError (VBOX_E_INVALID_VM_STATE,
1921
 
            tr ("Invalid machine state: %d"), mData->mMachineState);
 
2312
        return setError(VBOX_E_INVALID_OBJECT_STATE,
 
2313
                        tr("Cannot attach storage devices to an unregistered machine"));
 
2314
 
 
2315
    AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
 
2316
 
 
2317
    if (Global::IsOnlineOrTransient(mData->mMachineState))
 
2318
        return setError(VBOX_E_INVALID_VM_STATE,
 
2319
                        tr("Invalid machine state: %s"),
 
2320
                        Global::stringifyMachineState(mData->mMachineState));
1922
2321
 
1923
2322
    /* Check for an existing controller. */
1924
2323
    ComObjPtr<StorageController> ctl;
1938
2337
        || (aDevice < 0)
1939
2338
        || (aDevice >= (LONG)devicesPerPort)
1940
2339
       )
1941
 
        return setError (E_INVALIDARG,
1942
 
            tr ("The port and/or count parameter are out of range [%lu:%lu]"),
1943
 
                portCount, devicesPerPort);
 
2340
        return setError(E_INVALIDARG,
 
2341
                        tr("The port and/or count parameter are out of range [%lu:%lu]"),
 
2342
                        portCount,
 
2343
                        devicesPerPort);
1944
2344
 
1945
2345
    /* check if the device slot is already busy */
1946
 
    HDData::AttachmentList::const_iterator it =
1947
 
        std::find_if (mHDData->mAttachments.begin(),
1948
 
                      mHDData->mAttachments.end(),
1949
 
                      HardDiskAttachment::EqualsTo (aControllerName, aControllerPort, aDevice));
1950
 
 
1951
 
    if (it != mHDData->mAttachments.end())
1952
 
    {
1953
 
        ComObjPtr<HardDisk> hd = (*it)->hardDisk();
1954
 
        AutoReadLock hdLock (hd);
1955
 
        return setError (VBOX_E_OBJECT_IN_USE,
1956
 
            tr ("Hard disk '%ls' is already attached to device slot %d on "
1957
 
                "port %d of controller '%ls' of this virtual machine"),
1958
 
            hd->locationFull().raw(), aDevice, aControllerPort, aControllerName);
1959
 
    }
1960
 
 
1961
 
    Guid id(aId);
1962
 
 
1963
 
    /* find a hard disk by UUID */
1964
 
    ComObjPtr<HardDisk> hd;
1965
 
    rc = mParent->findHardDisk(&id, NULL, true /* aSetError */, &hd);
1966
 
    CheckComRCReturnRC (rc);
1967
 
 
1968
 
    AutoCaller hdCaller (hd);
1969
 
    CheckComRCReturnRC (hdCaller.rc());
1970
 
 
1971
 
    AutoWriteLock hdLock (hd);
1972
 
 
1973
 
    if (std::find_if (mHDData->mAttachments.begin(),
1974
 
                      mHDData->mAttachments.end(),
1975
 
                      HardDiskAttachment::RefersTo (hd)) !=
1976
 
            mHDData->mAttachments.end())
1977
 
    {
1978
 
        return setError (VBOX_E_OBJECT_IN_USE,
1979
 
            tr ("Hard disk '%ls' is already attached to this virtual machine"),
1980
 
            hd->locationFull().raw());
1981
 
    }
1982
 
 
1983
 
    bool indirect = hd->isReadOnly();
 
2346
    MediumAttachment *pAttachTemp;
 
2347
    if ((pAttachTemp = findAttachment(mMediaData->mAttachments,
 
2348
                                      aControllerName,
 
2349
                                      aControllerPort,
 
2350
                                      aDevice)))
 
2351
    {
 
2352
        Medium *pMedium = pAttachTemp->getMedium();
 
2353
        if (pMedium)
 
2354
        {
 
2355
            AutoReadLock mediumLock(pMedium);
 
2356
            return setError(VBOX_E_OBJECT_IN_USE,
 
2357
                            tr("Medium '%s' is already attached to device slot %d on port %d of controller '%ls' of this virtual machine"),
 
2358
                            pMedium->getLocationFull().raw(),
 
2359
                            aDevice,
 
2360
                            aControllerPort,
 
2361
                            aControllerName);
 
2362
        }
 
2363
        else
 
2364
            return setError(VBOX_E_OBJECT_IN_USE,
 
2365
                            tr("Device is already attached to slot %d on port %d of controller '%ls' of this virtual machine"),
 
2366
                            aDevice, aControllerPort, aControllerName);
 
2367
    }
 
2368
 
 
2369
    Guid uuid(aId);
 
2370
 
 
2371
    ComObjPtr<Medium> medium;
 
2372
    switch (aType)
 
2373
    {
 
2374
        case DeviceType_HardDisk:
 
2375
            /* find a hard disk by UUID */
 
2376
            rc = mParent->findHardDisk(&uuid, NULL, true /* aSetError */, &medium);
 
2377
            CheckComRCReturnRC(rc);
 
2378
            break;
 
2379
 
 
2380
        case DeviceType_DVD:
 
2381
            if (!uuid.isEmpty())
 
2382
            {
 
2383
                /* first search for host drive */
 
2384
                SafeIfaceArray<IMedium> drivevec;
 
2385
                rc = mParent->host()->COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
 
2386
                if (SUCCEEDED(rc))
 
2387
                {
 
2388
                    for (size_t i = 0; i < drivevec.size(); ++i)
 
2389
                    {
 
2390
                        /// @todo eliminate this conversion
 
2391
                        ComObjPtr<Medium> med = (Medium *)drivevec[i];
 
2392
                        if (med->getId() == uuid)
 
2393
                        {
 
2394
                            medium = med;
 
2395
                            break;
 
2396
                        }
 
2397
                    }
 
2398
                }
 
2399
 
 
2400
                if (medium.isNull())
 
2401
                {
 
2402
                    /* find a DVD image by UUID */
 
2403
                    rc = mParent->findDVDImage(&uuid, NULL, true /* aSetError */, &medium);
 
2404
                    CheckComRCReturnRC(rc);
 
2405
                }
 
2406
            }
 
2407
            else
 
2408
            {
 
2409
                /* null UUID means null medium, which needs no code */
 
2410
            }
 
2411
            break;
 
2412
 
 
2413
        case DeviceType_Floppy:
 
2414
            if (!uuid.isEmpty())
 
2415
            {
 
2416
                /* first search for host drive */
 
2417
                SafeIfaceArray<IMedium> drivevec;
 
2418
                rc = mParent->host()->COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
 
2419
                if (SUCCEEDED(rc))
 
2420
                {
 
2421
                    for (size_t i = 0; i < drivevec.size(); ++i)
 
2422
                    {
 
2423
                        /// @todo eliminate this conversion
 
2424
                        ComObjPtr<Medium> med = (Medium *)drivevec[i];
 
2425
                        if (med->getId() == uuid)
 
2426
                        {
 
2427
                            medium = med;
 
2428
                            break;
 
2429
                        }
 
2430
                    }
 
2431
                }
 
2432
 
 
2433
                if (medium.isNull())
 
2434
                {
 
2435
                    /* find a floppy image by UUID */
 
2436
                    rc = mParent->findFloppyImage(&uuid, NULL, true /* aSetError */, &medium);
 
2437
                    CheckComRCReturnRC(rc);
 
2438
                }
 
2439
            }
 
2440
            else
 
2441
            {
 
2442
                /* null UUID means null medium, which needs no code */
 
2443
            }
 
2444
            break;
 
2445
 
 
2446
        default:
 
2447
            return setError(E_INVALIDARG,
 
2448
                            tr("The device type %d is not recognized"),
 
2449
                            (int)aType);
 
2450
    }
 
2451
 
 
2452
    AutoCaller mediumCaller(medium);
 
2453
    CheckComRCReturnRC(mediumCaller.rc());
 
2454
 
 
2455
    AutoWriteLock mediumLock(medium);
 
2456
 
 
2457
    if (   (pAttachTemp = findAttachment(mMediaData->mAttachments, medium))
 
2458
        && !medium.isNull())
 
2459
    {
 
2460
        return setError(VBOX_E_OBJECT_IN_USE,
 
2461
                        tr("Medium '%s' is already attached to this virtual machine"),
 
2462
                        medium->getLocationFull().raw());
 
2463
    }
 
2464
 
 
2465
    bool indirect = false;
 
2466
    if (!medium.isNull())
 
2467
        indirect = medium->isReadOnly();
1984
2468
    bool associate = true;
1985
2469
 
1986
2470
    do
1987
2471
    {
1988
 
        if (mHDData.isBackedUp())
 
2472
        if (aType == DeviceType_HardDisk && mMediaData.isBackedUp())
1989
2473
        {
1990
 
            const HDData::AttachmentList &oldAtts =
1991
 
                mHDData.backedUpData()->mAttachments;
 
2474
            const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
1992
2475
 
1993
 
            /* check if the hard disk was attached to the VM before we started
1994
 
             * changing attachemnts in which case the attachment just needs to
 
2476
            /* check if the medium was attached to the VM before we started
 
2477
             * changing attachments in which case the attachment just needs to
1995
2478
             * be restored */
1996
 
            HDData::AttachmentList::const_iterator it =
1997
 
                std::find_if (oldAtts.begin(), oldAtts.end(),
1998
 
                              HardDiskAttachment::RefersTo (hd));
1999
 
            if (it != oldAtts.end())
 
2479
            if ((pAttachTemp = findAttachment(oldAtts, medium)))
2000
2480
            {
2001
 
                AssertReturn (!indirect, E_FAIL);
 
2481
                AssertReturn(!indirect, E_FAIL);
2002
2482
 
2003
2483
                /* see if it's the same bus/channel/device */
2004
 
                if ((*it)->device() == aDevice &&
2005
 
                    (*it)->port() == aControllerPort &&
2006
 
                    (*it)->controller() == aControllerName)
 
2484
                if (pAttachTemp->matches(aControllerName, aControllerPort, aDevice))
2007
2485
                {
2008
2486
                    /* the simplest case: restore the whole attachment
2009
 
                     * and return, nothing else to do */
2010
 
                    mHDData->mAttachments.push_back (*it);
 
2487
                    * and return, nothing else to do */
 
2488
                    mMediaData->mAttachments.push_back(pAttachTemp);
2011
2489
                    return S_OK;
2012
2490
                }
2013
2491
 
2014
2492
                /* bus/channel/device differ; we need a new attachment object,
2015
 
                 * but don't try to associate it again */
 
2493
                    * but don't try to associate it again */
2016
2494
                associate = false;
2017
2495
                break;
2018
2496
            }
2026
2504
         * attachments. Note that smart attachment is only applicable to base
2027
2505
         * hard disks. */
2028
2506
 
2029
 
        if (hd->parent().isNull())
 
2507
        if (medium->getParent().isNull())
2030
2508
        {
2031
2509
            /* first, investigate the backup copy of the current hard disk
2032
2510
             * attachments to make it possible to re-attach existing diffs to
2033
2511
             * another device slot w/o losing their contents */
2034
 
            if (mHDData.isBackedUp())
 
2512
            if (mMediaData.isBackedUp())
2035
2513
            {
2036
 
                const HDData::AttachmentList &oldAtts =
2037
 
                    mHDData.backedUpData()->mAttachments;
 
2514
                const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
2038
2515
 
2039
 
                HDData::AttachmentList::const_iterator foundIt = oldAtts.end();
 
2516
                MediaData::AttachmentList::const_iterator foundIt = oldAtts.end();
2040
2517
                uint32_t foundLevel = 0;
2041
2518
 
2042
 
                for (HDData::AttachmentList::const_iterator
2043
 
                     it = oldAtts.begin(); it != oldAtts.end(); ++ it)
 
2519
                for (MediaData::AttachmentList::const_iterator it = oldAtts.begin();
 
2520
                     it != oldAtts.end();
 
2521
                     ++it)
2044
2522
                {
2045
2523
                    uint32_t level = 0;
2046
 
                    if ((*it)->hardDisk()->root (&level).equalsTo (hd))
 
2524
                    MediumAttachment *pAttach = *it;
 
2525
                    ComObjPtr<Medium> pMedium = pAttach->getMedium();
 
2526
                    Assert(!pMedium.isNull() || pAttach->getType() != DeviceType_HardDisk);
 
2527
                    if (pMedium.isNull())
 
2528
                        continue;
 
2529
 
 
2530
                    if (pMedium->getBase(&level).equalsTo(medium))
2047
2531
                    {
2048
2532
                        /* skip the hard disk if its currently attached (we
2049
2533
                         * cannot attach the same hard disk twice) */
2050
 
                        if (std::find_if (mHDData->mAttachments.begin(),
2051
 
                                          mHDData->mAttachments.end(),
2052
 
                                          HardDiskAttachment::RefersTo (
2053
 
                                              (*it)->hardDisk())) !=
2054
 
                                mHDData->mAttachments.end())
 
2534
                        if (findAttachment(mMediaData->mAttachments,
 
2535
                                           pMedium))
2055
2536
                            continue;
2056
2537
 
2057
2538
                        /* matched device, channel and bus (i.e. attached to the
2058
2539
                         * same place) will win and immediately stop the search;
2059
2540
                         * otherwise the attachment that has the youngest
2060
 
                         * descendant of hd will be used
 
2541
                         * descendant of medium will be used
2061
2542
                         */
2062
 
                        if ((*it)->device() == aDevice &&
2063
 
                            (*it)->port() == aControllerPort &&
2064
 
                            (*it)->controller() == aControllerName)
 
2543
                        if (pAttach->matches(aControllerName, aControllerPort, aDevice))
2065
2544
                        {
2066
2545
                            /* the simplest case: restore the whole attachment
2067
2546
                             * and return, nothing else to do */
2068
 
                            mHDData->mAttachments.push_back (*it);
 
2547
                            mMediaData->mAttachments.push_back(*it);
2069
2548
                            return S_OK;
2070
2549
                        }
2071
 
                        else
2072
 
                        if (foundIt == oldAtts.end() ||
2073
 
                            level > foundLevel /* prefer younger */)
 
2550
                        else if (    foundIt == oldAtts.end()
 
2551
                                  || level > foundLevel /* prefer younger */
 
2552
                                )
2074
2553
                        {
2075
2554
                            foundIt = it;
2076
2555
                            foundLevel = level;
2081
2560
                if (foundIt != oldAtts.end())
2082
2561
                {
2083
2562
                    /* use the previously attached hard disk */
2084
 
                    hd = (*foundIt)->hardDisk();
2085
 
                    hdCaller.attach (hd);
2086
 
                    CheckComRCReturnRC (hdCaller.rc());
2087
 
                    hdLock.attach (hd);
 
2563
                    medium = (*foundIt)->getMedium();
 
2564
                    mediumCaller.attach(medium);
 
2565
                    CheckComRCReturnRC(mediumCaller.rc());
 
2566
                    mediumLock.attach(medium);
2088
2567
                    /* not implicit, doesn't require association with this VM */
2089
2568
                    indirect = false;
2090
2569
                    associate = false;
2091
 
                    /* go right to the HardDiskAttachment creation */
 
2570
                    /* go right to the MediumAttachment creation */
2092
2571
                    break;
2093
2572
                }
2094
2573
            }
2096
2575
            /* then, search through snapshots for the best diff in the given
2097
2576
             * hard disk's chain to base the new diff on */
2098
2577
 
2099
 
            ComObjPtr<HardDisk> base;
 
2578
            ComObjPtr<Medium> base;
2100
2579
            ComObjPtr<Snapshot> snap = mData->mCurrentSnapshot;
2101
2580
            while (snap)
2102
2581
            {
2103
 
                AutoReadLock snapLock (snap);
2104
 
 
2105
 
                const HDData::AttachmentList &snapAtts =
2106
 
                    snap->data().mMachine->mHDData->mAttachments;
2107
 
 
2108
 
                HDData::AttachmentList::const_iterator foundIt = snapAtts.end();
 
2582
                AutoReadLock snapLock(snap);
 
2583
 
 
2584
                const MediaData::AttachmentList &snapAtts = snap->getSnapshotMachine()->mMediaData->mAttachments;
 
2585
 
 
2586
                MediaData::AttachmentList::const_iterator foundIt = snapAtts.end();
2109
2587
                uint32_t foundLevel = 0;
2110
2588
 
2111
 
                for (HDData::AttachmentList::const_iterator
2112
 
                     it = snapAtts.begin(); it != snapAtts.end(); ++ it)
 
2589
                for (MediaData::AttachmentList::const_iterator it = snapAtts.begin();
 
2590
                     it != snapAtts.end();
 
2591
                     ++it)
2113
2592
                {
 
2593
                    MediumAttachment *pAttach = *it;
 
2594
                    ComObjPtr<Medium> pMedium = pAttach->getMedium();
 
2595
                    Assert(!pMedium.isNull() || pAttach->getType() != DeviceType_HardDisk);
 
2596
                    if (pMedium.isNull())
 
2597
                        continue;
 
2598
 
2114
2599
                    uint32_t level = 0;
2115
 
                    if ((*it)->hardDisk()->root (&level).equalsTo (hd))
 
2600
                    if (pMedium->getBase(&level).equalsTo(medium))
2116
2601
                    {
2117
2602
                        /* matched device, channel and bus (i.e. attached to the
2118
2603
                         * same place) will win and immediately stop the search;
2119
2604
                         * otherwise the attachment that has the youngest
2120
 
                         * descendant of hd will be used
 
2605
                         * descendant of medium will be used
2121
2606
                         */
2122
 
                        if ((*it)->device() == aDevice &&
2123
 
                            (*it)->port() == aControllerPort &&
2124
 
                            (*it)->controller() == aControllerName)
 
2607
                        if (    (*it)->getDevice() == aDevice
 
2608
                             && (*it)->getPort() == aControllerPort
 
2609
                             && (*it)->getControllerName() == aControllerName
 
2610
                           )
2125
2611
                        {
2126
2612
                            foundIt = it;
2127
2613
                            break;
2128
2614
                        }
2129
 
                        else
2130
 
                        if (foundIt == snapAtts.end() ||
2131
 
                            level > foundLevel /* prefer younger */)
 
2615
                        else if (    foundIt == snapAtts.end()
 
2616
                                  || level > foundLevel /* prefer younger */
 
2617
                                )
2132
2618
                        {
2133
2619
                            foundIt = it;
2134
2620
                            foundLevel = level;
2138
2624
 
2139
2625
                if (foundIt != snapAtts.end())
2140
2626
                {
2141
 
                    base = (*foundIt)->hardDisk();
 
2627
                    base = (*foundIt)->getMedium();
2142
2628
                    break;
2143
2629
                }
2144
2630
 
2148
2634
            /* found a suitable diff, use it as a base */
2149
2635
            if (!base.isNull())
2150
2636
            {
2151
 
                hd = base;
2152
 
                hdCaller.attach (hd);
2153
 
                CheckComRCReturnRC (hdCaller.rc());
2154
 
                hdLock.attach (hd);
 
2637
                medium = base;
 
2638
                mediumCaller.attach(medium);
 
2639
                CheckComRCReturnRC(mediumCaller.rc());
 
2640
                mediumLock.attach(medium);
2155
2641
            }
2156
2642
        }
2157
2643
 
2158
 
        ComObjPtr<HardDisk> diff;
 
2644
        ComObjPtr<Medium> diff;
2159
2645
        diff.createObject();
2160
2646
        rc = diff->init(mParent,
2161
 
                        hd->preferredDiffFormat(),
2162
 
                        BstrFmt ("%ls"RTPATH_SLASH_STR,
2163
 
                                 mUserData->mSnapshotFolderFull.raw()));
2164
 
        CheckComRCReturnRC (rc);
 
2647
                        medium->preferredDiffFormat().raw(),
 
2648
                        BstrFmt("%ls"RTPATH_SLASH_STR,
 
2649
                                 mUserData->mSnapshotFolderFull.raw()).raw());
 
2650
        CheckComRCReturnRC(rc);
2165
2651
 
2166
2652
        /* make sure the hard disk is not modified before createDiffStorage() */
2167
 
        rc = hd->LockRead (NULL);
2168
 
        CheckComRCReturnRC (rc);
 
2653
        rc = medium->LockRead(NULL);
 
2654
        CheckComRCReturnRC(rc);
2169
2655
 
2170
2656
        /* will leave the lock before the potentially lengthy operation, so
2171
2657
         * protect with the special state */
2172
2658
        MachineState_T oldState = mData->mMachineState;
2173
 
        setMachineState (MachineState_SettingUp);
 
2659
        setMachineState(MachineState_SettingUp);
2174
2660
 
2175
 
        hdLock.leave();
 
2661
        mediumLock.leave();
2176
2662
        alock.leave();
2177
 
        vboxLock.unlock();
2178
2663
 
2179
 
        rc = hd->createDiffStorageAndWait (diff, HardDiskVariant_Standard);
 
2664
        rc = medium->createDiffStorageAndWait(diff, MediumVariant_Standard);
2180
2665
 
2181
2666
        alock.enter();
2182
 
        hdLock.enter();
2183
 
 
2184
 
        setMachineState (oldState);
2185
 
 
2186
 
        hd->UnlockRead (NULL);
2187
 
 
2188
 
        CheckComRCReturnRC (rc);
 
2667
        mediumLock.enter();
 
2668
 
 
2669
        setMachineState(oldState);
 
2670
 
 
2671
        medium->UnlockRead(NULL);
 
2672
 
 
2673
        CheckComRCReturnRC(rc);
2189
2674
 
2190
2675
        /* use the created diff for the actual attachment */
2191
 
        hd = diff;
2192
 
        hdCaller.attach (hd);
2193
 
        CheckComRCReturnRC (hdCaller.rc());
2194
 
        hdLock.attach (hd);
 
2676
        medium = diff;
 
2677
        mediumCaller.attach(medium);
 
2678
        CheckComRCReturnRC(mediumCaller.rc());
 
2679
        mediumLock.attach(medium);
2195
2680
    }
2196
2681
    while (0);
2197
2682
 
2198
 
    ComObjPtr<HardDiskAttachment> attachment;
 
2683
    ComObjPtr<MediumAttachment> attachment;
2199
2684
    attachment.createObject();
2200
 
    rc = attachment->init (hd, aControllerName, aControllerPort, aDevice, indirect);
2201
 
    CheckComRCReturnRC (rc);
 
2685
    rc = attachment->init(this, medium, aControllerName, aControllerPort, aDevice, aType, indirect);
 
2686
    CheckComRCReturnRC(rc);
2202
2687
 
2203
 
    if (associate)
 
2688
    if (associate && !medium.isNull())
2204
2689
    {
2205
 
        /* as the last step, associate the hard disk to the VM */
2206
 
        rc = hd->attachTo (mData->mUuid);
 
2690
        /* as the last step, associate the medium to the VM */
 
2691
        rc = medium->attachTo(mData->mUuid);
2207
2692
        /* here we can fail because of Deleting, or being in process of
2208
2693
         * creating a Diff */
2209
 
        CheckComRCReturnRC (rc);
 
2694
        CheckComRCReturnRC(rc);
2210
2695
    }
2211
2696
 
2212
 
    /* sucsess: finally remember the attachment */
2213
 
    mHDData.backup();
2214
 
    mHDData->mAttachments.push_back (attachment);
 
2697
    /* success: finally remember the attachment */
 
2698
    mMediaData.backup();
 
2699
    mMediaData->mAttachments.push_back(attachment);
2215
2700
 
2216
2701
    return rc;
2217
2702
}
2218
2703
 
2219
 
STDMETHODIMP Machine::GetHardDisk(IN_BSTR aControllerName, LONG aControllerPort,
2220
 
                                  LONG aDevice, IHardDisk **aHardDisk)
2221
 
{
2222
 
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
2223
 
                     aControllerName, aControllerPort, aDevice));
2224
 
 
2225
 
    CheckComArgNotNull (aControllerName);
2226
 
    CheckComArgOutPointerValid (aHardDisk);
2227
 
 
2228
 
    AutoCaller autoCaller (this);
2229
 
    CheckComRCReturnRC (autoCaller.rc());
2230
 
 
2231
 
    AutoReadLock alock (this);
2232
 
 
2233
 
    *aHardDisk = NULL;
2234
 
 
2235
 
    HDData::AttachmentList::const_iterator it =
2236
 
        std::find_if (mHDData->mAttachments.begin(),
2237
 
                      mHDData->mAttachments.end(),
2238
 
                      HardDiskAttachment::EqualsTo (aControllerName, aControllerPort, aDevice));
2239
 
 
2240
 
    if (it == mHDData->mAttachments.end())
2241
 
        return setError (VBOX_E_OBJECT_NOT_FOUND,
2242
 
            tr ("No hard disk attached to device slot %d on port %d of controller '%ls'"),
2243
 
            aDevice, aControllerPort, aControllerName);
2244
 
 
2245
 
    (*it)->hardDisk().queryInterfaceTo (aHardDisk);
2246
 
 
2247
 
    return S_OK;
2248
 
}
2249
 
 
2250
 
STDMETHODIMP Machine::DetachHardDisk(IN_BSTR aControllerName, LONG aControllerPort,
2251
 
                                     LONG aDevice)
2252
 
{
2253
 
    CheckComArgNotNull (aControllerName);
2254
 
 
2255
 
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
2256
 
                     aControllerName, aControllerPort, aDevice));
2257
 
 
2258
 
    AutoCaller autoCaller (this);
2259
 
    CheckComRCReturnRC (autoCaller.rc());
2260
 
 
2261
 
    AutoWriteLock alock (this);
2262
 
 
2263
 
    HRESULT rc = checkStateDependency (MutableStateDep);
2264
 
    CheckComRCReturnRC (rc);
2265
 
 
2266
 
    AssertReturn (mData->mMachineState != MachineState_Saved, E_FAIL);
2267
 
 
2268
 
    if (Global::IsOnlineOrTransient (mData->mMachineState))
2269
 
        return setError (VBOX_E_INVALID_VM_STATE,
2270
 
            tr ("Invalid machine state: %d"), mData->mMachineState);
2271
 
 
2272
 
    HDData::AttachmentList::const_iterator it =
2273
 
        std::find_if (mHDData->mAttachments.begin(),
2274
 
                      mHDData->mAttachments.end(),
2275
 
                      HardDiskAttachment::EqualsTo (aControllerName, aControllerPort, aDevice));
2276
 
 
2277
 
    if (it == mHDData->mAttachments.end())
2278
 
        return setError (VBOX_E_OBJECT_NOT_FOUND,
2279
 
            tr ("No hard disk attached to device slot %d on port %d of controller '%ls'"),
2280
 
            aDevice, aControllerPort, aControllerName);
2281
 
 
2282
 
    ComObjPtr<HardDiskAttachment> hda = *it;
2283
 
    ComObjPtr<HardDisk> hd = hda->hardDisk();
2284
 
 
2285
 
    if (hda->isImplicit())
 
2704
STDMETHODIMP Machine::DetachDevice(IN_BSTR aControllerName, LONG aControllerPort,
 
2705
                                   LONG aDevice)
 
2706
{
 
2707
    CheckComArgNotNull(aControllerName);
 
2708
 
 
2709
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
 
2710
                     aControllerName, aControllerPort, aDevice));
 
2711
 
 
2712
    AutoCaller autoCaller(this);
 
2713
    CheckComRCReturnRC(autoCaller.rc());
 
2714
 
 
2715
    AutoWriteLock alock(this);
 
2716
 
 
2717
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2718
    CheckComRCReturnRC(rc);
 
2719
 
 
2720
    AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
 
2721
 
 
2722
    if (Global::IsOnlineOrTransient(mData->mMachineState))
 
2723
        return setError(VBOX_E_INVALID_VM_STATE,
 
2724
                        tr("Invalid machine state: %s"),
 
2725
                        Global::stringifyMachineState(mData->mMachineState));
 
2726
 
 
2727
    MediumAttachment *pAttach = findAttachment(mMediaData->mAttachments,
 
2728
                                               aControllerName,
 
2729
                                               aControllerPort,
 
2730
                                               aDevice);
 
2731
    if (!pAttach)
 
2732
        return setError(VBOX_E_OBJECT_NOT_FOUND,
 
2733
                        tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
 
2734
                        aDevice, aControllerPort, aControllerName);
 
2735
 
 
2736
    ComObjPtr<Medium> oldmedium = pAttach->getMedium();
 
2737
    DeviceType_T mediumType = pAttach->getType();
 
2738
 
 
2739
    if (pAttach->isImplicit())
2286
2740
    {
2287
2741
        /* attempt to implicitly delete the implicitly created diff */
2288
2742
 
2289
 
        /// @todo move the implicit flag from HardDiskAttachment to HardDisk
 
2743
        /// @todo move the implicit flag from MediumAttachment to Medium
2290
2744
        /// and forbid any hard disk operation when it is implicit. Or maybe
2291
2745
        /// a special media state for it to make it even more simple.
2292
2746
 
2293
 
        Assert (mHDData.isBackedUp());
 
2747
        Assert(mMediaData.isBackedUp());
2294
2748
 
2295
2749
        /* will leave the lock before the potentially lengthy operation, so
2296
2750
         * protect with the special state */
2297
2751
        MachineState_T oldState = mData->mMachineState;
2298
 
        setMachineState (MachineState_SettingUp);
 
2752
        setMachineState(MachineState_SettingUp);
2299
2753
 
2300
2754
        alock.leave();
2301
2755
 
2302
 
        rc = hd->deleteStorageAndWait();
 
2756
        rc = oldmedium->deleteStorageAndWait();
2303
2757
 
2304
2758
        alock.enter();
2305
2759
 
2306
 
        setMachineState (oldState);
 
2760
        setMachineState(oldState);
2307
2761
 
2308
 
        CheckComRCReturnRC (rc);
 
2762
        CheckComRCReturnRC(rc);
2309
2763
    }
2310
2764
 
2311
 
    mHDData.backup();
 
2765
    mMediaData.backup();
2312
2766
 
2313
2767
    /* we cannot use erase (it) below because backup() above will create
2314
2768
     * a copy of the list and make this copy active, but the iterator
2315
2769
     * still refers to the original and is not valid for the copy */
2316
 
    mHDData->mAttachments.remove (hda);
 
2770
    mMediaData->mAttachments.remove(pAttach);
 
2771
 
 
2772
    /* For non-hard disk media, detach straight away. */
 
2773
    if (mediumType != DeviceType_HardDisk && !oldmedium.isNull())
 
2774
        oldmedium->detachFrom(mData->mUuid);
 
2775
 
 
2776
    return S_OK;
 
2777
}
 
2778
 
 
2779
STDMETHODIMP Machine::PassthroughDevice(IN_BSTR aControllerName, LONG aControllerPort,
 
2780
                                        LONG aDevice, BOOL aPassthrough)
 
2781
{
 
2782
    CheckComArgNotNull(aControllerName);
 
2783
 
 
2784
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld aPassthrough=%d\n",
 
2785
                     aControllerName, aControllerPort, aDevice, aPassthrough));
 
2786
 
 
2787
    AutoCaller autoCaller(this);
 
2788
    CheckComRCReturnRC(autoCaller.rc());
 
2789
 
 
2790
    AutoWriteLock alock(this);
 
2791
 
 
2792
    HRESULT rc = checkStateDependency(MutableStateDep);
 
2793
    CheckComRCReturnRC(rc);
 
2794
 
 
2795
    AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
 
2796
 
 
2797
    if (Global::IsOnlineOrTransient(mData->mMachineState))
 
2798
        return setError(VBOX_E_INVALID_VM_STATE,
 
2799
                        tr("Invalid machine state: %s"),
 
2800
                        Global::stringifyMachineState(mData->mMachineState));
 
2801
 
 
2802
    MediumAttachment *pAttach = findAttachment(mMediaData->mAttachments,
 
2803
                                               aControllerName,
 
2804
                                               aControllerPort,
 
2805
                                               aDevice);
 
2806
    if (!pAttach)
 
2807
        return setError(VBOX_E_OBJECT_NOT_FOUND,
 
2808
                        tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
 
2809
                        aDevice, aControllerPort, aControllerName);
 
2810
 
 
2811
 
 
2812
    mMediaData.backup();
 
2813
 
 
2814
    AutoWriteLock attLock(pAttach);
 
2815
 
 
2816
    if (pAttach->getType() != DeviceType_DVD)
 
2817
        return setError(E_INVALIDARG,
 
2818
                        tr("Setting passthrough rejected as the device attached to device slot %d on port %d of controller '%ls' is not a DVD"),
 
2819
                        aDevice, aControllerPort, aControllerName);
 
2820
    pAttach->updatePassthrough(!!aPassthrough);
 
2821
 
 
2822
    return S_OK;
 
2823
}
 
2824
 
 
2825
STDMETHODIMP Machine::MountMedium(IN_BSTR aControllerName,
 
2826
                                  LONG aControllerPort,
 
2827
                                  LONG aDevice,
 
2828
                                  IN_BSTR aId,
 
2829
                                  BOOL aForce)
 
2830
{
 
2831
    int rc = S_OK;
 
2832
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld aForce=%d\n",
 
2833
                     aControllerName, aControllerPort, aDevice, aForce));
 
2834
 
 
2835
    CheckComArgNotNull(aControllerName);
 
2836
    CheckComArgNotNull(aId);
 
2837
 
 
2838
    AutoCaller autoCaller(this);
 
2839
    CheckComRCReturnRC(autoCaller.rc());
 
2840
 
 
2841
    AutoWriteLock alock(this);
 
2842
 
 
2843
    ComObjPtr<MediumAttachment> pAttach = findAttachment(mMediaData->mAttachments,
 
2844
                                                         aControllerName,
 
2845
                                                         aControllerPort,
 
2846
                                                         aDevice);
 
2847
    if (pAttach.isNull())
 
2848
        return setError(VBOX_E_OBJECT_NOT_FOUND,
 
2849
                        tr("No drive attached to device slot %d on port %d of controller '%ls'"),
 
2850
                        aDevice, aControllerPort, aControllerName);
 
2851
 
 
2852
    /* Remember previously mounted medium. The medium before taking the
 
2853
     * backup is not necessarily the same thing. */
 
2854
    ComObjPtr<Medium> oldmedium;
 
2855
    oldmedium = pAttach->getMedium();
 
2856
 
 
2857
    Guid uuid(aId);
 
2858
    ComObjPtr<Medium> medium;
 
2859
    DeviceType_T mediumType = pAttach->getType();
 
2860
    switch (mediumType)
 
2861
    {
 
2862
        case DeviceType_DVD:
 
2863
            if (!uuid.isEmpty())
 
2864
            {
 
2865
                /* find a DVD by host device UUID */
 
2866
                SafeIfaceArray<IMedium> drivevec;
 
2867
                rc = mParent->host()->COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
 
2868
                if (SUCCEEDED(rc))
 
2869
                {
 
2870
                    for (size_t i = 0; i < drivevec.size(); ++i)
 
2871
                    {
 
2872
                        /// @todo eliminate this conversion
 
2873
                        ComObjPtr<Medium> med = (Medium *)drivevec[i];
 
2874
                        if (uuid == med->getId())
 
2875
                        {
 
2876
                            medium = med;
 
2877
                            break;
 
2878
                        }
 
2879
                    }
 
2880
                }
 
2881
                /* find a DVD by UUID */
 
2882
                if (medium.isNull())
 
2883
                    rc = mParent->findDVDImage(&uuid, NULL, true /* aDoSetError */, &medium);
 
2884
            }
 
2885
            CheckComRCReturnRC(rc);
 
2886
            break;
 
2887
        case DeviceType_Floppy:
 
2888
            if (!uuid.isEmpty())
 
2889
            {
 
2890
                /* find a Floppy by host device UUID */
 
2891
                SafeIfaceArray<IMedium> drivevec;
 
2892
                rc = mParent->host()->COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
 
2893
                if (SUCCEEDED(rc))
 
2894
                {
 
2895
                    for (size_t i = 0; i < drivevec.size(); ++i)
 
2896
                    {
 
2897
                        /// @todo eliminate this conversion
 
2898
                        ComObjPtr<Medium> med = (Medium *)drivevec[i];
 
2899
                        if (uuid == med->getId())
 
2900
                        {
 
2901
                            medium = med;
 
2902
                            break;
 
2903
                        }
 
2904
                    }
 
2905
                }
 
2906
                /* find a Floppy by UUID */
 
2907
                if (medium.isNull())
 
2908
                    rc = mParent->findFloppyImage(&uuid, NULL, true /* aDoSetError */, &medium);
 
2909
            }
 
2910
            CheckComRCReturnRC(rc);
 
2911
            break;
 
2912
        default:
 
2913
            return setError(VBOX_E_INVALID_OBJECT_STATE,
 
2914
                            tr("Cannot change medium attached to device slot %d on port %d of controller '%ls'"),
 
2915
                            aDevice, aControllerPort, aControllerName);
 
2916
    }
 
2917
 
 
2918
    if (SUCCEEDED(rc))
 
2919
    {
 
2920
 
 
2921
        mMediaData.backup();
 
2922
        /* The backup operation makes the pAttach reference point to the
 
2923
         * old settings. Re-get the correct reference. */
 
2924
        pAttach = findAttachment(mMediaData->mAttachments,
 
2925
                                 aControllerName,
 
2926
                                 aControllerPort,
 
2927
                                 aDevice);
 
2928
        AutoWriteLock attLock(pAttach);
 
2929
        /* For non-hard disk media, detach straight away. */
 
2930
        if (mediumType != DeviceType_HardDisk && !oldmedium.isNull())
 
2931
            oldmedium->detachFrom(mData->mUuid);
 
2932
        if (!medium.isNull())
 
2933
            medium->attachTo(mData->mUuid);
 
2934
        pAttach->updateMedium(medium, false /* aImplicit */);
 
2935
    }
 
2936
 
 
2937
    alock.leave();
 
2938
    rc = onMediumChange(pAttach, aForce);
 
2939
    alock.enter();
 
2940
 
 
2941
    /* On error roll back this change only. */
 
2942
    if (FAILED(rc))
 
2943
    {
 
2944
        if (!medium.isNull())
 
2945
            medium->detachFrom(mData->mUuid);
 
2946
        pAttach = findAttachment(mMediaData->mAttachments,
 
2947
                                 aControllerName,
 
2948
                                 aControllerPort,
 
2949
                                 aDevice);
 
2950
        /* If the attachment is gone in the mean time, bail out. */
 
2951
        if (pAttach.isNull())
 
2952
            return rc;
 
2953
        AutoWriteLock attLock(pAttach);
 
2954
        /* For non-hard disk media, re-attach straight away. */
 
2955
        if (mediumType != DeviceType_HardDisk && !oldmedium.isNull())
 
2956
            oldmedium->attachTo(mData->mUuid);
 
2957
        pAttach->updateMedium(oldmedium, false /* aImplicit */);
 
2958
    }
 
2959
 
 
2960
    return rc;
 
2961
}
 
2962
 
 
2963
STDMETHODIMP Machine::GetMedium(IN_BSTR aControllerName,
 
2964
                                LONG aControllerPort,
 
2965
                                LONG aDevice,
 
2966
                                IMedium **aMedium)
 
2967
{
 
2968
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
 
2969
                     aControllerName, aControllerPort, aDevice));
 
2970
 
 
2971
    CheckComArgNotNull(aControllerName);
 
2972
    CheckComArgOutPointerValid(aMedium);
 
2973
 
 
2974
    AutoCaller autoCaller(this);
 
2975
    CheckComRCReturnRC(autoCaller.rc());
 
2976
 
 
2977
    AutoReadLock alock(this);
 
2978
 
 
2979
    *aMedium = NULL;
 
2980
 
 
2981
    ComObjPtr<MediumAttachment> pAttach = findAttachment(mMediaData->mAttachments,
 
2982
                                                         aControllerName,
 
2983
                                                         aControllerPort,
 
2984
                                                         aDevice);
 
2985
    if (pAttach.isNull())
 
2986
        return setError(VBOX_E_OBJECT_NOT_FOUND,
 
2987
                        tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
 
2988
                        aDevice, aControllerPort, aControllerName);
 
2989
 
 
2990
    pAttach->getMedium().queryInterfaceTo(aMedium);
2317
2991
 
2318
2992
    return S_OK;
2319
2993
}
2320
2994
 
2321
2995
STDMETHODIMP Machine::GetSerialPort (ULONG slot, ISerialPort **port)
2322
2996
{
2323
 
    CheckComArgOutPointerValid (port);
 
2997
    CheckComArgOutPointerValid(port);
2324
2998
    CheckComArgExpr (slot, slot < RT_ELEMENTS (mSerialPorts));
2325
2999
 
2326
 
    AutoCaller autoCaller (this);
2327
 
    CheckComRCReturnRC (autoCaller.rc());
2328
 
 
2329
 
    AutoReadLock alock (this);
2330
 
 
2331
 
    mSerialPorts [slot].queryInterfaceTo (port);
 
3000
    AutoCaller autoCaller(this);
 
3001
    CheckComRCReturnRC(autoCaller.rc());
 
3002
 
 
3003
    AutoReadLock alock(this);
 
3004
 
 
3005
    mSerialPorts [slot].queryInterfaceTo(port);
2332
3006
 
2333
3007
    return S_OK;
2334
3008
}
2335
3009
 
2336
3010
STDMETHODIMP Machine::GetParallelPort (ULONG slot, IParallelPort **port)
2337
3011
{
2338
 
    CheckComArgOutPointerValid (port);
 
3012
    CheckComArgOutPointerValid(port);
2339
3013
    CheckComArgExpr (slot, slot < RT_ELEMENTS (mParallelPorts));
2340
3014
 
2341
 
    AutoCaller autoCaller (this);
2342
 
    CheckComRCReturnRC (autoCaller.rc());
2343
 
 
2344
 
    AutoReadLock alock (this);
2345
 
 
2346
 
    mParallelPorts [slot].queryInterfaceTo (port);
 
3015
    AutoCaller autoCaller(this);
 
3016
    CheckComRCReturnRC(autoCaller.rc());
 
3017
 
 
3018
    AutoReadLock alock(this);
 
3019
 
 
3020
    mParallelPorts [slot].queryInterfaceTo(port);
2347
3021
 
2348
3022
    return S_OK;
2349
3023
}
2350
3024
 
2351
3025
STDMETHODIMP Machine::GetNetworkAdapter (ULONG slot, INetworkAdapter **adapter)
2352
3026
{
2353
 
    CheckComArgOutPointerValid (adapter);
 
3027
    CheckComArgOutPointerValid(adapter);
2354
3028
    CheckComArgExpr (slot, slot < RT_ELEMENTS (mNetworkAdapters));
2355
3029
 
2356
 
    AutoCaller autoCaller (this);
2357
 
    CheckComRCReturnRC (autoCaller.rc());
2358
 
 
2359
 
    AutoReadLock alock (this);
2360
 
 
2361
 
    mNetworkAdapters [slot].queryInterfaceTo (adapter);
2362
 
 
2363
 
    return S_OK;
2364
 
}
2365
 
 
2366
 
/**
2367
 
 *  @note Locks this object for reading.
2368
 
 */
2369
 
STDMETHODIMP Machine::GetNextExtraDataKey (IN_BSTR aKey, BSTR *aNextKey, BSTR *aNextValue)
2370
 
{
2371
 
    CheckComArgOutPointerValid (aNextKey);
2372
 
 
2373
 
    AutoCaller autoCaller (this);
2374
 
    CheckComRCReturnRC (autoCaller.rc());
2375
 
 
2376
 
    /* start with nothing found */
2377
 
    Bstr("").cloneTo(aNextKey);
2378
 
    if (aNextValue)
2379
 
        Bstr("").cloneTo(aNextValue);
2380
 
 
2381
 
    /* if we're ready and isConfigLocked() is FALSE then it means
2382
 
     * that no config file exists yet, so return shortly */
2383
 
    if (!isConfigLocked())
2384
 
        return S_OK;
2385
 
 
2386
 
    HRESULT rc = S_OK;
2387
 
 
2388
 
    Bstr bstrInKey(aKey);
2389
 
 
2390
 
    /* serialize file access (prevent writes) */
2391
 
    AutoReadLock alock (this);
2392
 
 
2393
 
    try
2394
 
    {
2395
 
        using namespace settings;
2396
 
        using namespace xml;
2397
 
 
2398
 
        /* load the settings file (we don't reuse the existing handle but
2399
 
         * request a new one to allow for concurrent multithreaded reads) */
2400
 
        File file (File::Mode_Read, Utf8Str (mData->mConfigFileFull));
2401
 
        XmlTreeBackend tree;
2402
 
 
2403
 
        rc = VirtualBox::loadSettingsTree_Again (tree, file);
2404
 
        CheckComRCReturnRC (rc);
2405
 
 
2406
 
        Key machineNode = tree.rootKey().key ("Machine");
2407
 
        Key extraDataNode = machineNode.findKey ("ExtraData");
2408
 
 
2409
 
        if (!extraDataNode.isNull())
2410
 
        {
2411
 
            Key::List items = extraDataNode.keys ("ExtraDataItem");
2412
 
            if (items.size())
2413
 
            {
2414
 
                for (Key::List::const_iterator it = items.begin();
2415
 
                     it != items.end(); ++ it)
2416
 
                {
2417
 
                    Bstr key = (*it).stringValue ("name");
2418
 
 
2419
 
                    /* if we're supposed to return the first one */
2420
 
                    if (bstrInKey.isEmpty())
2421
 
                    {
2422
 
                        key.cloneTo (aNextKey);
2423
 
                        if (aNextValue)
2424
 
                        {
2425
 
                            Bstr val = (*it).stringValue ("value");
2426
 
                            val.cloneTo (aNextValue);
2427
 
                        }
2428
 
                        return S_OK;
2429
 
                    }
2430
 
 
2431
 
                    /* did we find the key we're looking for? */
2432
 
                    if (key == bstrInKey)
2433
 
                    {
2434
 
                        ++ it;
2435
 
                        /* is there another item? */
2436
 
                        if (it != items.end())
2437
 
                        {
2438
 
                            Bstr key = (*it).stringValue ("name");
2439
 
                            key.cloneTo (aNextKey);
2440
 
                            if (aNextValue)
2441
 
                            {
2442
 
                                Bstr val = (*it).stringValue ("value");
2443
 
                                val.cloneTo (aNextValue);
2444
 
                            }
2445
 
                        }
2446
 
                        /* else it's the last one, arguments are already NULL */
2447
 
                        return S_OK;
2448
 
                    }
2449
 
                }
2450
 
            }
2451
 
        }
2452
 
 
2453
 
        /* Here we are when a) there are no items at all or b) there are items
2454
 
         * but none of them equals the requested non-NULL key. b) is an
2455
 
         * error as well as a) if the key is non-NULL. When the key is NULL
2456
 
         * (which is the case only when there are no items), we just fall
2457
 
         * through to return NULLs and S_OK. */
2458
 
 
2459
 
        if (!bstrInKey.isEmpty())
2460
 
            return setError (VBOX_E_OBJECT_NOT_FOUND,
2461
 
                tr ("Could not find the extra data key '%ls'"), bstrInKey.raw());
2462
 
    }
2463
 
    catch (...)
2464
 
    {
2465
 
        rc = VirtualBox::handleUnexpectedExceptions (RT_SRC_POS);
2466
 
    }
2467
 
 
2468
 
    return rc;
2469
 
}
2470
 
 
2471
 
/**
2472
 
 *  @note Locks this object for reading.
2473
 
 */
2474
 
STDMETHODIMP Machine::GetExtraData (IN_BSTR aKey, BSTR *aValue)
2475
 
{
2476
 
    CheckComArgNotNull (aKey);
2477
 
    CheckComArgOutPointerValid (aValue);
2478
 
 
2479
 
    AutoCaller autoCaller (this);
2480
 
    CheckComRCReturnRC (autoCaller.rc());
2481
 
 
2482
 
    /* serialize file access (prevent writes) */
2483
 
    AutoReadLock alock (this);
2484
 
 
2485
 
    /* start with nothing found */
2486
 
    Bstr("").cloneTo(aValue);
2487
 
 
2488
 
    /* if we're ready and isConfigLocked() is FALSE then it means
2489
 
     * that no config file exists yet, so return shortly */
2490
 
    if (!isConfigLocked())
2491
 
        return S_OK;
2492
 
 
2493
 
    Utf8Str val("");
2494
 
    HRESULT rc = getExtraData(Utf8Str(aKey), val);
2495
 
    if (SUCCEEDED(rc))
2496
 
        val.cloneTo (aValue);
2497
 
 
2498
 
    return rc;
2499
 
}
2500
 
 
2501
 
HRESULT Machine::getExtraData(const Utf8Str &aKey, Utf8Str &aValue)
2502
 
{
2503
 
    HRESULT rc = S_OK;
2504
 
 
2505
 
    try
2506
 
    {
2507
 
        using namespace settings;
2508
 
        using namespace xml;
2509
 
 
2510
 
        /* load the settings file (we don't reuse the existing handle but
2511
 
         * request a new one to allow for concurrent multithreaded reads) */
2512
 
        File file (File::Mode_Read, Utf8Str (mData->mConfigFileFull));
2513
 
        XmlTreeBackend tree;
2514
 
 
2515
 
        rc = VirtualBox::loadSettingsTree_Again (tree, file);
2516
 
        CheckComRCReturnRC (rc);
2517
 
 
2518
 
        Key machineNode = tree.rootKey().key ("Machine");
2519
 
        Key extraDataNode = machineNode.findKey ("ExtraData");
2520
 
 
2521
 
        if (!extraDataNode.isNull())
2522
 
        {
2523
 
            /* check if the key exists */
2524
 
            Key::List items = extraDataNode.keys ("ExtraDataItem");
2525
 
            for (Key::List::const_iterator it = items.begin();
2526
 
                 it != items.end(); ++ it)
2527
 
            {
2528
 
                if (aKey == (*it).stringValue ("name"))
2529
 
                {
2530
 
                    aValue = (*it).stringValue ("value");
2531
 
                    break;
2532
 
                }
2533
 
            }
2534
 
        }
2535
 
    }
2536
 
    catch (...)
2537
 
    {
2538
 
        rc = VirtualBox::handleUnexpectedExceptions (RT_SRC_POS);
2539
 
    }
2540
 
 
2541
 
    return rc;
2542
 
}
2543
 
 
2544
 
/**
2545
 
 *  @note Locks mParent for writing + this object for writing.
2546
 
 */
2547
 
STDMETHODIMP Machine::SetExtraData (IN_BSTR aKey, IN_BSTR aValue)
2548
 
{
2549
 
    CheckComArgNotNull (aKey);
2550
 
 
2551
 
    AutoCaller autoCaller (this);
2552
 
    CheckComRCReturnRC (autoCaller.rc());
2553
 
 
2554
 
    /* VirtualBox::onExtraDataCanChange() and saveSettings() need mParent
2555
 
     * lock (saveSettings() needs a write one). This object's write lock is
2556
 
     * also necessary to serialize file access (prevent concurrent reads and
2557
 
     * writes). */
2558
 
    AutoMultiWriteLock2 alock (mParent, this);
2559
 
 
2560
 
    if (mType == IsSnapshotMachine)
2561
 
    {
2562
 
        HRESULT rc = checkStateDependency (MutableStateDep);
2563
 
        CheckComRCReturnRC (rc);
2564
 
    }
2565
 
 
2566
 
    Bstr val;
2567
 
    if (!aValue)
2568
 
        val = (const char *)"";
2569
 
    else
2570
 
        val = aValue;
2571
 
 
2572
 
 
2573
 
    bool changed = false;
2574
 
    HRESULT rc = S_OK;
2575
 
 
2576
 
    /* If we're ready and isConfigLocked() is FALSE then it means that no
2577
 
     * config file exists yet, so call saveSettings() to create one. */
2578
 
    if (!isConfigLocked())
2579
 
    {
2580
 
        rc = saveSettings();
2581
 
        CheckComRCReturnRC (rc);
2582
 
    }
2583
 
 
2584
 
    try
2585
 
    {
2586
 
        using namespace settings;
2587
 
        using namespace xml;
2588
 
 
2589
 
        /* load the settings file */
2590
 
        File file (mData->mHandleCfgFile, Utf8Str (mData->mConfigFileFull));
2591
 
        XmlTreeBackend tree;
2592
 
 
2593
 
        rc = VirtualBox::loadSettingsTree_ForUpdate (tree, file);
2594
 
        CheckComRCReturnRC (rc);
2595
 
 
2596
 
        const Utf8Str key = aKey;
2597
 
        Bstr oldVal("");
2598
 
 
2599
 
        Key machineNode = tree.rootKey().key ("Machine");
2600
 
        Key extraDataNode = machineNode.createKey ("ExtraData");
2601
 
        Key extraDataItemNode;
2602
 
 
2603
 
        Key::List items = extraDataNode.keys ("ExtraDataItem");
2604
 
        for (Key::List::const_iterator it = items.begin();
2605
 
             it != items.end(); ++ it)
2606
 
        {
2607
 
            if (key == (*it).stringValue ("name"))
2608
 
            {
2609
 
                extraDataItemNode = *it;
2610
 
                oldVal = (*it).stringValue ("value");
2611
 
                break;
2612
 
            }
2613
 
        }
2614
 
 
2615
 
        /* When no key is found, oldVal is empty string */
2616
 
        changed = oldVal != val;
2617
 
 
2618
 
        if (changed)
2619
 
        {
2620
 
            /* ask for permission from all listeners */
2621
 
            Bstr error;
2622
 
            if (!mParent->onExtraDataCanChange (mData->mUuid, aKey, val, error))
2623
 
            {
2624
 
                const char *sep = error.isEmpty() ? "" : ": ";
2625
 
                CBSTR err = error.isNull() ? (CBSTR) L"" : error.raw();
2626
 
                LogWarningFunc (("Someone vetoed! Change refused%s%ls\n",
2627
 
                                 sep, err));
2628
 
                return setError (E_ACCESSDENIED,
2629
 
                    tr ("Could not set extra data because someone refused "
2630
 
                        "the requested change of '%ls' to '%ls'%s%ls"),
2631
 
                    aKey, val.raw(), sep, err);
2632
 
            }
2633
 
 
2634
 
            if (!val.isEmpty())
2635
 
            {
2636
 
                if (extraDataItemNode.isNull())
2637
 
                {
2638
 
                    extraDataItemNode = extraDataNode.appendKey ("ExtraDataItem");
2639
 
                    extraDataItemNode.setStringValue ("name", key);
2640
 
                }
2641
 
                extraDataItemNode.setStringValue ("value", Utf8Str (aValue));
2642
 
            }
2643
 
            else
2644
 
            {
2645
 
                /* an old value does for sure exist here (XML schema
2646
 
                 * guarantees that "value" may not absent in the
2647
 
                 * <ExtraDataItem> element) */
2648
 
                Assert (!extraDataItemNode.isNull());
2649
 
                extraDataItemNode.zap();
2650
 
            }
2651
 
 
2652
 
            /* save settings on success */
2653
 
            rc = VirtualBox::saveSettingsTree (tree, file,
2654
 
                                               mData->mSettingsFileVersion);
 
3030
    AutoCaller autoCaller(this);
 
3031
    CheckComRCReturnRC(autoCaller.rc());
 
3032
 
 
3033
    AutoReadLock alock(this);
 
3034
 
 
3035
    mNetworkAdapters[slot].queryInterfaceTo(adapter);
 
3036
 
 
3037
    return S_OK;
 
3038
}
 
3039
 
 
3040
STDMETHODIMP Machine::GetExtraDataKeys(ComSafeArrayOut(BSTR, aKeys))
 
3041
{
 
3042
    if (ComSafeArrayOutIsNull(aKeys))
 
3043
        return E_POINTER;
 
3044
 
 
3045
    AutoCaller autoCaller (this);
 
3046
    CheckComRCReturnRC (autoCaller.rc());
 
3047
 
 
3048
    AutoReadLock alock (this);
 
3049
 
 
3050
    com::SafeArray<BSTR> saKeys(mData->m_pMachineConfigFile->mapExtraDataItems.size());
 
3051
    int i = 0;
 
3052
    for (settings::ExtraDataItemsMap::const_iterator it = mData->m_pMachineConfigFile->mapExtraDataItems.begin();
 
3053
         it != mData->m_pMachineConfigFile->mapExtraDataItems.end();
 
3054
         ++it, ++i)
 
3055
    {
 
3056
        const Utf8Str &strKey = it->first;
 
3057
        strKey.cloneTo(&saKeys[i]);
 
3058
    }
 
3059
    saKeys.detachTo(ComSafeArrayOutArg(aKeys));
 
3060
 
 
3061
    return S_OK;
 
3062
  }
 
3063
 
 
3064
  /**
 
3065
   *  @note Locks this object for reading.
 
3066
   */
 
3067
STDMETHODIMP Machine::GetExtraData(IN_BSTR aKey,
 
3068
                                   BSTR *aValue)
 
3069
{
 
3070
    CheckComArgNotNull(aKey);
 
3071
    CheckComArgOutPointerValid(aValue);
 
3072
 
 
3073
    AutoCaller autoCaller (this);
 
3074
    CheckComRCReturnRC (autoCaller.rc());
 
3075
 
 
3076
    /* start with nothing found */
 
3077
    Bstr bstrResult("");
 
3078
 
 
3079
    AutoReadLock alock (this);
 
3080
 
 
3081
    settings::ExtraDataItemsMap::const_iterator it = mData->m_pMachineConfigFile->mapExtraDataItems.find(Utf8Str(aKey));
 
3082
    if (it != mData->m_pMachineConfigFile->mapExtraDataItems.end())
 
3083
        // found:
 
3084
        bstrResult = it->second; // source is a Utf8Str
 
3085
 
 
3086
    /* return the result to caller (may be empty) */
 
3087
    bstrResult.cloneTo(aValue);
 
3088
 
 
3089
    return S_OK;
 
3090
}
 
3091
 
 
3092
  /**
 
3093
   *  @note Locks mParent for writing + this object for writing.
 
3094
   */
 
3095
STDMETHODIMP Machine::SetExtraData(IN_BSTR aKey, IN_BSTR aValue)
 
3096
{
 
3097
    CheckComArgNotNull(aKey);
 
3098
 
 
3099
    AutoCaller autoCaller(this);
 
3100
    CheckComRCReturnRC (autoCaller.rc());
 
3101
 
 
3102
    Utf8Str strKey(aKey);
 
3103
    Utf8Str strValue(aValue);
 
3104
    Utf8Str strOldValue;            // empty
 
3105
 
 
3106
    // locking note: we only hold the read lock briefly to look up the old value,
 
3107
    // then release it and call the onExtraCanChange callbacks. There is a small
 
3108
    // chance of a race insofar as the callback might be called twice if two callers
 
3109
    // change the same key at the same time, but that's a much better solution
 
3110
    // than the deadlock we had here before. The actual changing of the extradata
 
3111
    // is then performed under the write lock and race-free.
 
3112
 
 
3113
    // look up the old value first; if nothing's changed then we need not do anything
 
3114
    {
 
3115
        AutoReadLock alock(this); // hold read lock only while looking up
 
3116
        settings::ExtraDataItemsMap::const_iterator it = mData->m_pMachineConfigFile->mapExtraDataItems.find(strKey);
 
3117
        if (it != mData->m_pMachineConfigFile->mapExtraDataItems.end())
 
3118
            strOldValue = it->second;
 
3119
    }
 
3120
 
 
3121
    bool fChanged;
 
3122
    if ((fChanged = (strOldValue != strValue)))
 
3123
    {
 
3124
        // ask for permission from all listeners outside the locks;
 
3125
        // onExtraDataCanChange() only briefly requests the VirtualBox
 
3126
        // lock to copy the list of callbacks to invoke
 
3127
        Bstr error;
 
3128
        Bstr bstrValue;
 
3129
        if (aValue)
 
3130
            bstrValue = aValue;
 
3131
        else
 
3132
            bstrValue = (const char *)"";
 
3133
 
 
3134
        if (!mParent->onExtraDataCanChange(mData->mUuid, aKey, bstrValue, error))
 
3135
        {
 
3136
            const char *sep = error.isEmpty() ? "" : ": ";
 
3137
            CBSTR err = error.isNull() ? (CBSTR) L"" : error.raw();
 
3138
            LogWarningFunc(("Someone vetoed! Change refused%s%ls\n",
 
3139
                            sep, err));
 
3140
            return setError(E_ACCESSDENIED,
 
3141
                            tr("Could not set extra data because someone refused the requested change of '%ls' to '%ls'%s%ls"),
 
3142
                            aKey,
 
3143
                            bstrValue.raw(),
 
3144
                            sep,
 
3145
                            err);
 
3146
        }
 
3147
 
 
3148
        // data is changing and change not vetoed: then write it out under the locks
 
3149
 
 
3150
        // saveSettings() needs VirtualBox write lock
 
3151
        AutoMultiWriteLock2 alock(mParent, this);
 
3152
 
 
3153
        if (mType == IsSnapshotMachine)
 
3154
        {
 
3155
            HRESULT rc = checkStateDependency(MutableStateDep);
2655
3156
            CheckComRCReturnRC (rc);
2656
3157
        }
2657
 
    }
2658
 
    catch (...)
2659
 
    {
2660
 
        rc = VirtualBox::handleUnexpectedExceptions (RT_SRC_POS);
2661
 
    }
2662
 
 
2663
 
    /* fire a notification */
2664
 
    if (SUCCEEDED (rc) && changed)
2665
 
        mParent->onExtraDataChange (mData->mUuid, aKey, aValue);
2666
 
 
2667
 
    return rc;
 
3158
 
 
3159
        if (strValue.isEmpty())
 
3160
            mData->m_pMachineConfigFile->mapExtraDataItems.erase(strKey);
 
3161
        else
 
3162
            mData->m_pMachineConfigFile->mapExtraDataItems[strKey] = strValue;
 
3163
                // creates a new key if needed
 
3164
 
 
3165
        /* save settings on success */
 
3166
        HRESULT rc = saveSettings();
 
3167
        CheckComRCReturnRC (rc);
 
3168
    }
 
3169
 
 
3170
    // fire notification outside the lock
 
3171
    if (fChanged)
 
3172
        mParent->onExtraDataChange(mData->mUuid, aKey, aValue);
 
3173
 
 
3174
    return S_OK;
2668
3175
}
2669
3176
 
2670
3177
STDMETHODIMP Machine::SaveSettings()
2671
3178
{
2672
 
    AutoCaller autoCaller (this);
2673
 
    CheckComRCReturnRC (autoCaller.rc());
2674
 
 
2675
 
    /* saveSettings() needs mParent lock */
2676
 
    AutoMultiWriteLock2 alock (mParent, this);
2677
 
 
2678
 
    /* when there was auto-conversion, we want to save the file even if
2679
 
     * the VM is saved */
2680
 
    StateDependency dep = mData->mSettingsFileVersion != VBOX_XML_VERSION_FULL ?
2681
 
        MutableOrSavedStateDep : MutableStateDep;
2682
 
 
2683
 
    HRESULT rc = checkStateDependency (dep);
2684
 
    CheckComRCReturnRC (rc);
2685
 
 
2686
 
    /* the settings file path may never be null */
2687
 
    ComAssertRet (mData->mConfigFileFull, E_FAIL);
2688
 
 
2689
 
    /* save all VM data excluding snapshots */
2690
 
    return saveSettings();
2691
 
}
2692
 
 
2693
 
STDMETHODIMP Machine::SaveSettingsWithBackup (BSTR *aBakFileName)
2694
 
{
2695
 
    CheckComArgOutPointerValid (aBakFileName);
2696
 
 
2697
 
    AutoCaller autoCaller (this);
2698
 
    CheckComRCReturnRC (autoCaller.rc());
2699
 
 
2700
 
    /* saveSettings() needs mParent lock */
2701
 
    AutoMultiWriteLock2 alock (mParent, this);
2702
 
 
2703
 
    /* when there was auto-conversion, we want to save the file even if
2704
 
     * the VM is saved */
2705
 
    StateDependency dep = mData->mSettingsFileVersion != VBOX_XML_VERSION_FULL ?
2706
 
        MutableOrSavedStateDep : MutableStateDep;
2707
 
 
2708
 
    HRESULT rc = checkStateDependency (dep);
2709
 
    CheckComRCReturnRC (rc);
2710
 
 
2711
 
    /* the settings file path may never be null */
2712
 
    ComAssertRet (mData->mConfigFileFull, E_FAIL);
2713
 
 
2714
 
    /* perform backup only when there was auto-conversion */
2715
 
    if (mData->mSettingsFileVersion != VBOX_XML_VERSION_FULL)
2716
 
    {
2717
 
        Bstr bakFileName;
2718
 
 
2719
 
        HRESULT rc = VirtualBox::backupSettingsFile (mData->mConfigFileFull,
2720
 
                                                     mData->mSettingsFileVersion,
2721
 
                                                     bakFileName);
2722
 
        CheckComRCReturnRC (rc);
2723
 
 
2724
 
        bakFileName.cloneTo (aBakFileName);
2725
 
    }
 
3179
    AutoCaller autoCaller(this);
 
3180
    CheckComRCReturnRC(autoCaller.rc());
 
3181
 
 
3182
    /* saveSettings() needs mParent lock */
 
3183
    AutoMultiWriteLock2 alock(mParent, this);
 
3184
 
 
3185
    /* when there was auto-conversion, we want to save the file even if
 
3186
     * the VM is saved */
 
3187
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3188
    CheckComRCReturnRC(rc);
 
3189
 
 
3190
    /* the settings file path may never be null */
 
3191
    ComAssertRet(!mData->m_strConfigFileFull.isEmpty(), E_FAIL);
2726
3192
 
2727
3193
    /* save all VM data excluding snapshots */
2728
3194
    return saveSettings();
2730
3196
 
2731
3197
STDMETHODIMP Machine::DiscardSettings()
2732
3198
{
2733
 
    AutoCaller autoCaller (this);
2734
 
    CheckComRCReturnRC (autoCaller.rc());
2735
 
 
2736
 
    AutoWriteLock alock (this);
2737
 
 
2738
 
    HRESULT rc = checkStateDependency (MutableStateDep);
2739
 
    CheckComRCReturnRC (rc);
 
3199
    AutoCaller autoCaller(this);
 
3200
    CheckComRCReturnRC(autoCaller.rc());
 
3201
 
 
3202
    AutoWriteLock alock(this);
 
3203
 
 
3204
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3205
    CheckComRCReturnRC(rc);
2740
3206
 
2741
3207
    /*
2742
3208
     *  during this rollback, the session will be notified if data has
2749
3215
 
2750
3216
STDMETHODIMP Machine::DeleteSettings()
2751
3217
{
2752
 
    AutoCaller autoCaller (this);
2753
 
    CheckComRCReturnRC (autoCaller.rc());
2754
 
 
2755
 
    AutoWriteLock alock (this);
2756
 
 
2757
 
    HRESULT rc = checkStateDependency (MutableStateDep);
2758
 
    CheckComRCReturnRC (rc);
 
3218
    AutoCaller autoCaller(this);
 
3219
    CheckComRCReturnRC(autoCaller.rc());
 
3220
 
 
3221
    AutoWriteLock alock(this);
 
3222
 
 
3223
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3224
    CheckComRCReturnRC(rc);
2759
3225
 
2760
3226
    if (mData->mRegistered)
2761
 
        return setError (VBOX_E_INVALID_VM_STATE,
2762
 
            tr ("Cannot delete settings of a registered machine"));
 
3227
        return setError(VBOX_E_INVALID_VM_STATE,
 
3228
                        tr("Cannot delete settings of a registered machine"));
2763
3229
 
2764
3230
    /* delete the settings only when the file actually exists */
2765
 
    if (isConfigLocked())
 
3231
    if (mData->m_pMachineConfigFile->fileExists())
2766
3232
    {
2767
 
        unlockConfig();
2768
 
        int vrc = RTFileDelete (Utf8Str (mData->mConfigFileFull));
2769
 
        if (RT_FAILURE (vrc))
2770
 
            return setError (VBOX_E_IPRT_ERROR,
2771
 
                tr ("Could not delete the settings file '%ls' (%Rrc)"),
2772
 
                mData->mConfigFileFull.raw(), vrc);
 
3233
        int vrc = RTFileDelete(mData->m_strConfigFileFull.c_str());
 
3234
        if (RT_FAILURE(vrc))
 
3235
            return setError(VBOX_E_IPRT_ERROR,
 
3236
                            tr("Could not delete the settings file '%s' (%Rrc)"),
 
3237
                            mData->m_strConfigFileFull.raw(),
 
3238
                            vrc);
2773
3239
 
2774
3240
        /* delete the Logs folder, nothing important should be left
2775
3241
         * there (we don't check for errors because the user might have
2776
3242
         * some private files there that we don't want to delete) */
2777
3243
        Utf8Str logFolder;
2778
 
        getLogFolder (logFolder);
2779
 
        Assert (!logFolder.isEmpty());
2780
 
        if (RTDirExists (logFolder))
 
3244
        getLogFolder(logFolder);
 
3245
        Assert(logFolder.length());
 
3246
        if (RTDirExists(logFolder.c_str()))
2781
3247
        {
2782
3248
            /* Delete all VBox.log[.N] files from the Logs folder
2783
3249
             * (this must be in sync with the rotation logic in
2784
3250
             * Console::powerUpThread()). Also, delete the VBox.png[.N]
2785
3251
             * files that may have been created by the GUI. */
2786
 
            Utf8Str log = Utf8StrFmt ("%s/VBox.log", logFolder.raw());
2787
 
            RTFileDelete (log);
2788
 
            log = Utf8StrFmt ("%s/VBox.png", logFolder.raw());
2789
 
            RTFileDelete (log);
 
3252
            Utf8Str log = Utf8StrFmt("%s/VBox.log", logFolder.raw());
 
3253
            RTFileDelete(log.c_str());
 
3254
            log = Utf8StrFmt("%s/VBox.png", logFolder.raw());
 
3255
            RTFileDelete(log.c_str());
2790
3256
            for (int i = 3; i >= 0; i--)
2791
3257
            {
2792
 
                log = Utf8StrFmt ("%s/VBox.log.%d", logFolder.raw(), i);
2793
 
                RTFileDelete (log);
2794
 
                log = Utf8StrFmt ("%s/VBox.png.%d", logFolder.raw(), i);
2795
 
                RTFileDelete (log);
 
3258
                log = Utf8StrFmt("%s/VBox.log.%d", logFolder.raw(), i);
 
3259
                RTFileDelete(log.c_str());
 
3260
                log = Utf8StrFmt("%s/VBox.png.%d", logFolder.raw(), i);
 
3261
                RTFileDelete(log.c_str());
2796
3262
            }
2797
3263
 
2798
 
            RTDirRemove (logFolder);
 
3264
            RTDirRemove(logFolder.c_str());
2799
3265
        }
2800
3266
 
2801
3267
        /* delete the Snapshots folder, nothing important should be left
2802
3268
         * there (we don't check for errors because the user might have
2803
3269
         * some private files there that we don't want to delete) */
2804
 
        Utf8Str snapshotFolder = mUserData->mSnapshotFolderFull;
2805
 
        Assert (!snapshotFolder.isEmpty());
2806
 
        if (RTDirExists (snapshotFolder))
2807
 
            RTDirRemove (snapshotFolder);
 
3270
        Utf8Str snapshotFolder(mUserData->mSnapshotFolderFull);
 
3271
        Assert(snapshotFolder.length());
 
3272
        if (RTDirExists(snapshotFolder.c_str()))
 
3273
            RTDirRemove(snapshotFolder.c_str());
2808
3274
 
2809
3275
        /* delete the directory that contains the settings file, but only
2810
3276
         * if it matches the VM name (i.e. a structure created by default in
2811
3277
         * prepareSaveSettings()) */
2812
3278
        {
2813
3279
            Utf8Str settingsDir;
2814
 
            if (isInOwnDir (&settingsDir))
2815
 
                RTDirRemove (settingsDir);
 
3280
            if (isInOwnDir(&settingsDir))
 
3281
                RTDirRemove(settingsDir.c_str());
2816
3282
        }
2817
3283
    }
2818
3284
 
2821
3287
 
2822
3288
STDMETHODIMP Machine::GetSnapshot (IN_BSTR aId, ISnapshot **aSnapshot)
2823
3289
{
2824
 
    CheckComArgOutPointerValid (aSnapshot);
2825
 
 
2826
 
    AutoCaller autoCaller (this);
2827
 
    CheckComRCReturnRC (autoCaller.rc());
2828
 
 
2829
 
    AutoReadLock alock (this);
2830
 
 
2831
 
    Guid id(aId);
2832
 
    ComObjPtr <Snapshot> snapshot;
2833
 
 
2834
 
    HRESULT rc = findSnapshot (id, snapshot, true /* aSetError */);
2835
 
    snapshot.queryInterfaceTo (aSnapshot);
 
3290
    CheckComArgOutPointerValid(aSnapshot);
 
3291
 
 
3292
    AutoCaller autoCaller(this);
 
3293
    CheckComRCReturnRC(autoCaller.rc());
 
3294
 
 
3295
    AutoReadLock alock(this);
 
3296
 
 
3297
    Guid uuid(aId);
 
3298
    ComObjPtr<Snapshot> snapshot;
 
3299
 
 
3300
    HRESULT rc = findSnapshot(uuid, snapshot, true /* aSetError */);
 
3301
    snapshot.queryInterfaceTo(aSnapshot);
2836
3302
 
2837
3303
    return rc;
2838
3304
}
2840
3306
STDMETHODIMP Machine::FindSnapshot (IN_BSTR aName, ISnapshot **aSnapshot)
2841
3307
{
2842
3308
    CheckComArgNotNull (aName);
2843
 
    CheckComArgOutPointerValid (aSnapshot);
2844
 
 
2845
 
    AutoCaller autoCaller (this);
2846
 
    CheckComRCReturnRC (autoCaller.rc());
2847
 
 
2848
 
    AutoReadLock alock (this);
2849
 
 
2850
 
    ComObjPtr <Snapshot> snapshot;
2851
 
 
2852
 
    HRESULT rc = findSnapshot (aName, snapshot, true /* aSetError */);
2853
 
    snapshot.queryInterfaceTo (aSnapshot);
 
3309
    CheckComArgOutPointerValid(aSnapshot);
 
3310
 
 
3311
    AutoCaller autoCaller(this);
 
3312
    CheckComRCReturnRC(autoCaller.rc());
 
3313
 
 
3314
    AutoReadLock alock(this);
 
3315
 
 
3316
    ComObjPtr<Snapshot> snapshot;
 
3317
 
 
3318
    HRESULT rc = findSnapshot(aName, snapshot, true /* aSetError */);
 
3319
    snapshot.queryInterfaceTo(aSnapshot);
2854
3320
 
2855
3321
    return rc;
2856
3322
}
2863
3329
    return setError (E_NOTIMPL, "Not implemented");
2864
3330
}
2865
3331
 
2866
 
STDMETHODIMP
2867
 
Machine::CreateSharedFolder (IN_BSTR aName, IN_BSTR aHostPath, BOOL aWritable)
 
3332
STDMETHODIMP Machine::CreateSharedFolder (IN_BSTR aName, IN_BSTR aHostPath, BOOL aWritable)
2868
3333
{
2869
 
    CheckComArgNotNull (aName);
2870
 
    CheckComArgNotNull (aHostPath);
2871
 
 
2872
 
    AutoCaller autoCaller (this);
2873
 
    CheckComRCReturnRC (autoCaller.rc());
2874
 
 
2875
 
    AutoWriteLock alock (this);
2876
 
 
2877
 
    HRESULT rc = checkStateDependency (MutableStateDep);
2878
 
    CheckComRCReturnRC (rc);
2879
 
 
2880
 
    ComObjPtr <SharedFolder> sharedFolder;
 
3334
    CheckComArgNotNull(aName);
 
3335
    CheckComArgNotNull(aHostPath);
 
3336
 
 
3337
    AutoCaller autoCaller(this);
 
3338
    CheckComRCReturnRC(autoCaller.rc());
 
3339
 
 
3340
    AutoWriteLock alock(this);
 
3341
 
 
3342
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3343
    CheckComRCReturnRC(rc);
 
3344
 
 
3345
    ComObjPtr<SharedFolder> sharedFolder;
2881
3346
    rc = findSharedFolder (aName, sharedFolder, false /* aSetError */);
2882
 
    if (SUCCEEDED (rc))
2883
 
        return setError (VBOX_E_OBJECT_IN_USE,
2884
 
            tr ("Shared folder named '%ls' already exists"), aName);
 
3347
    if (SUCCEEDED(rc))
 
3348
        return setError(VBOX_E_OBJECT_IN_USE,
 
3349
                        tr("Shared folder named '%ls' already exists"),
 
3350
                        aName);
2885
3351
 
2886
3352
    sharedFolder.createObject();
2887
 
    rc = sharedFolder->init (machine(), aName, aHostPath, aWritable);
2888
 
    CheckComRCReturnRC (rc);
 
3353
    rc = sharedFolder->init(getMachine(), aName, aHostPath, aWritable);
 
3354
    CheckComRCReturnRC(rc);
2889
3355
 
2890
3356
    mHWData.backup();
2891
3357
    mHWData->mSharedFolders.push_back (sharedFolder);
2901
3367
{
2902
3368
    CheckComArgNotNull (aName);
2903
3369
 
2904
 
    AutoCaller autoCaller (this);
2905
 
    CheckComRCReturnRC (autoCaller.rc());
2906
 
 
2907
 
    AutoWriteLock alock (this);
2908
 
 
2909
 
    HRESULT rc = checkStateDependency (MutableStateDep);
2910
 
    CheckComRCReturnRC (rc);
2911
 
 
2912
 
    ComObjPtr <SharedFolder> sharedFolder;
 
3370
    AutoCaller autoCaller(this);
 
3371
    CheckComRCReturnRC(autoCaller.rc());
 
3372
 
 
3373
    AutoWriteLock alock(this);
 
3374
 
 
3375
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3376
    CheckComRCReturnRC(rc);
 
3377
 
 
3378
    ComObjPtr<SharedFolder> sharedFolder;
2913
3379
    rc = findSharedFolder (aName, sharedFolder, true /* aSetError */);
2914
 
    CheckComRCReturnRC (rc);
 
3380
    CheckComRCReturnRC(rc);
2915
3381
 
2916
3382
    mHWData.backup();
2917
3383
    mHWData->mSharedFolders.remove (sharedFolder);
2925
3391
 
2926
3392
STDMETHODIMP Machine::CanShowConsoleWindow (BOOL *aCanShow)
2927
3393
{
2928
 
    CheckComArgOutPointerValid (aCanShow);
 
3394
    CheckComArgOutPointerValid(aCanShow);
2929
3395
 
2930
3396
    /* start with No */
2931
3397
    *aCanShow = FALSE;
2932
3398
 
2933
 
    AutoCaller autoCaller (this);
2934
 
    AssertComRCReturnRC (autoCaller.rc());
 
3399
    AutoCaller autoCaller(this);
 
3400
    AssertComRCReturnRC(autoCaller.rc());
2935
3401
 
2936
 
    ComPtr <IInternalSessionControl> directControl;
 
3402
    ComPtr<IInternalSessionControl> directControl;
2937
3403
    {
2938
 
        AutoReadLock alock (this);
 
3404
        AutoReadLock alock(this);
2939
3405
 
2940
3406
        if (mData->mSession.mState != SessionState_Open)
2941
 
            return setError (VBOX_E_INVALID_VM_STATE,
2942
 
                tr ("Machine session is not open (session state: %d)"),
2943
 
                mData->mSession.mState);
 
3407
            return setError(VBOX_E_INVALID_VM_STATE,
 
3408
                            tr("Machine session is not open (session state: %s)"),
 
3409
                            Global::stringifySessionState(mData->mSession.mState));
2944
3410
 
2945
3411
        directControl = mData->mSession.mDirectControl;
2946
3412
    }
2955
3421
 
2956
3422
STDMETHODIMP Machine::ShowConsoleWindow (ULONG64 *aWinId)
2957
3423
{
2958
 
    CheckComArgOutPointerValid (aWinId);
 
3424
    CheckComArgOutPointerValid(aWinId);
2959
3425
 
2960
 
    AutoCaller autoCaller (this);
 
3426
    AutoCaller autoCaller(this);
2961
3427
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
2962
3428
 
2963
 
    ComPtr <IInternalSessionControl> directControl;
 
3429
    ComPtr<IInternalSessionControl> directControl;
2964
3430
    {
2965
 
        AutoReadLock alock (this);
 
3431
        AutoReadLock alock(this);
2966
3432
 
2967
3433
        if (mData->mSession.mState != SessionState_Open)
2968
 
            return setError (E_FAIL,
2969
 
                tr ("Machine session is not open (session state: %d)"),
2970
 
                mData->mSession.mState);
 
3434
            return setError(E_FAIL,
 
3435
                            tr("Machine session is not open (session state: %s)"),
 
3436
                            Global::stringifySessionState(mData->mSession.mState));
2971
3437
 
2972
3438
        directControl = mData->mSession.mDirectControl;
2973
3439
    }
2980
3446
    return directControl->OnShowWindow (FALSE /* aCheck */, &dummy, aWinId);
2981
3447
}
2982
3448
 
2983
 
STDMETHODIMP Machine::GetGuestProperty (IN_BSTR aName, BSTR *aValue, ULONG64 *aTimestamp, BSTR *aFlags)
 
3449
STDMETHODIMP Machine::GetGuestProperty(IN_BSTR aName,
 
3450
                                       BSTR *aValue,
 
3451
                                       ULONG64 *aTimestamp,
 
3452
                                       BSTR *aFlags)
2984
3453
{
2985
3454
#if !defined (VBOX_WITH_GUEST_PROPS)
2986
3455
    ReturnComNotImplemented();
2987
3456
#else
2988
 
    CheckComArgNotNull (aName);
2989
 
    CheckComArgOutPointerValid (aValue);
2990
 
    CheckComArgOutPointerValid (aTimestamp);
2991
 
    CheckComArgOutPointerValid (aFlags);
2992
 
 
2993
 
    AutoCaller autoCaller (this);
2994
 
    CheckComRCReturnRC (autoCaller.rc());
2995
 
 
2996
 
    AutoReadLock alock (this);
 
3457
    CheckComArgNotNull(aName);
 
3458
    CheckComArgOutPointerValid(aValue);
 
3459
    CheckComArgOutPointerValid(aTimestamp);
 
3460
    CheckComArgOutPointerValid(aFlags);
 
3461
 
 
3462
    AutoCaller autoCaller(this);
 
3463
    CheckComRCReturnRC(autoCaller.rc());
 
3464
 
 
3465
    AutoReadLock alock(this);
2997
3466
 
2998
3467
    using namespace guestProp;
2999
3468
    HRESULT rc = E_FAIL;
3000
3469
 
 
3470
    Utf8Str strName(aName);
 
3471
 
3001
3472
    if (!mHWData->mPropertyServiceActive)
3002
3473
    {
3003
3474
        bool found = false;
3004
3475
        for (HWData::GuestPropertyList::const_iterator it = mHWData->mGuestProperties.begin();
3005
 
             (it != mHWData->mGuestProperties.end()) && !found; ++it)
 
3476
             (it != mHWData->mGuestProperties.end()) && !found;
 
3477
             ++it)
3006
3478
        {
3007
 
            if (it->mName == aName)
 
3479
            if (it->strName == strName)
3008
3480
            {
3009
3481
                char szFlags[MAX_FLAGS_LEN + 1];
3010
 
                it->mValue.cloneTo (aValue);
 
3482
                it->strValue.cloneTo(aValue);
3011
3483
                *aTimestamp = it->mTimestamp;
3012
 
                writeFlags (it->mFlags, szFlags);
3013
 
                Bstr (szFlags).cloneTo (aFlags);
 
3484
                writeFlags(it->mFlags, szFlags);
 
3485
                Bstr(szFlags).cloneTo(aFlags);
3014
3486
                found = true;
3015
3487
            }
3016
3488
        }
3018
3490
    }
3019
3491
    else
3020
3492
    {
3021
 
        ComPtr <IInternalSessionControl> directControl =
 
3493
        ComPtr<IInternalSessionControl> directControl =
3022
3494
            mData->mSession.mDirectControl;
3023
3495
 
3024
3496
        /* just be on the safe side when calling another process */
3052
3524
    return GetGuestProperty (aName, &dummyValue, aTimestamp, &dummyFlags);
3053
3525
}
3054
3526
 
3055
 
STDMETHODIMP Machine::SetGuestProperty (IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags)
 
3527
STDMETHODIMP Machine::SetGuestProperty(IN_BSTR aName,
 
3528
                                       IN_BSTR aValue,
 
3529
                                       IN_BSTR aFlags)
3056
3530
{
3057
3531
#if !defined (VBOX_WITH_GUEST_PROPS)
3058
3532
    ReturnComNotImplemented();
3059
3533
#else
3060
3534
    using namespace guestProp;
3061
3535
 
3062
 
    CheckComArgNotNull (aName);
3063
 
    CheckComArgNotNull (aValue);
 
3536
    CheckComArgNotNull(aName);
 
3537
    CheckComArgNotNull(aValue);
3064
3538
    if ((aFlags != NULL) && !VALID_PTR (aFlags))
3065
3539
        return E_INVALIDARG;
3066
3540
 
3067
 
    Utf8Str utf8Name (aName);
3068
 
    Utf8Str utf8Flags (aFlags);
3069
 
    Utf8Str utf8Patterns (mHWData->mGuestPropertyNotificationPatterns);
3070
 
    if (   utf8Name.isNull()
3071
 
        || ((aFlags != NULL) && utf8Flags.isNull())
3072
 
        || utf8Patterns.isNull()
3073
 
       )
3074
 
        return E_OUTOFMEMORY;
3075
 
    bool matchAll = false;
3076
 
    if (0 == utf8Patterns.length())
3077
 
        matchAll = true;
3078
 
 
3079
 
    uint32_t fFlags = NILFLAG;
3080
 
    if ((aFlags != NULL) && RT_FAILURE (validateFlags (utf8Flags.raw(), &fFlags))
3081
 
       )
3082
 
        return setError (E_INVALIDARG, tr ("Invalid flag values: '%ls'"),
3083
 
                aFlags);
3084
 
 
3085
 
    AutoCaller autoCaller (this);
3086
 
    CheckComRCReturnRC (autoCaller.rc());
3087
 
 
3088
 
    AutoWriteLock alock (this);
3089
 
 
3090
 
    HRESULT rc = checkStateDependency (MutableStateDep);
3091
 
    CheckComRCReturnRC (rc);
3092
 
 
3093
 
    rc = S_OK;
3094
 
 
3095
 
    if (!mHWData->mPropertyServiceActive)
 
3541
    HRESULT rc = S_OK;
 
3542
 
 
3543
    try
3096
3544
    {
3097
 
        bool found = false;
3098
 
        HWData::GuestProperty property;
3099
 
        property.mFlags = NILFLAG;
3100
 
        if (SUCCEEDED (rc))
 
3545
        Utf8Str utf8Name(aName);
 
3546
        Utf8Str utf8Flags(aFlags);
 
3547
 
 
3548
        AutoCaller autoCaller(this);
 
3549
        CheckComRCReturnRC(autoCaller.rc());
 
3550
 
 
3551
        AutoWriteLock alock(this);
 
3552
 
 
3553
        rc = checkStateDependency(MutableStateDep);
 
3554
        CheckComRCReturnRC(rc);
 
3555
 
 
3556
        rc = S_OK;
 
3557
        uint32_t fFlags = NILFLAG;
 
3558
        if (    (aFlags != NULL)
 
3559
             && RT_FAILURE(validateFlags (utf8Flags.raw(), &fFlags))
 
3560
           )
 
3561
            return setError(E_INVALIDARG,
 
3562
                            tr("Invalid flag values: '%ls'"),
 
3563
                            aFlags);
 
3564
 
 
3565
        if (!mHWData->mPropertyServiceActive)
3101
3566
        {
3102
 
            for (HWData::GuestPropertyList::iterator it =
3103
 
                    mHWData->mGuestProperties.begin();
3104
 
                 it != mHWData->mGuestProperties.end(); ++ it)
3105
 
                if (it->mName == aName)
 
3567
            bool found = false;
 
3568
            HWData::GuestProperty property;
 
3569
            property.mFlags = NILFLAG;
 
3570
 
 
3571
            /** @todo r=bird: see efficiency rant in PushGuestProperty. (Yeah, I know,
 
3572
             *        this is simple and do an OK job atm.) */
 
3573
            for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
 
3574
                 it != mHWData->mGuestProperties.end();
 
3575
                 ++it)
 
3576
                if (it->strName == utf8Name)
3106
3577
                {
3107
3578
                    property = *it;
3108
3579
                    if (it->mFlags & (RDONLYHOST))
3109
 
                        rc = setError (E_ACCESSDENIED,
3110
 
                            tr ("The property '%ls' cannot be changed by the host"),
3111
 
                            aName);
 
3580
                        rc = setError(E_ACCESSDENIED,
 
3581
                                      tr("The property '%ls' cannot be changed by the host"),
 
3582
                                      aName);
3112
3583
                    else
3113
3584
                    {
3114
3585
                        mHWData.backup();
3115
3586
                        /* The backup() operation invalidates our iterator, so
3116
 
                         * get a new one. */
 
3587
                        * get a new one. */
3117
3588
                        for (it = mHWData->mGuestProperties.begin();
3118
 
                            it->mName != aName; ++ it)
 
3589
                             it->strName != utf8Name;
 
3590
                             ++it)
3119
3591
                            ;
3120
3592
                        mHWData->mGuestProperties.erase (it);
3121
3593
                    }
3122
3594
                    found = true;
3123
3595
                    break;
3124
3596
                }
3125
 
        }
3126
 
        if (found && SUCCEEDED (rc))
3127
 
        {
3128
 
            if (*aValue)
 
3597
            if (found && SUCCEEDED(rc))
 
3598
            {
 
3599
                if (*aValue)
 
3600
                {
 
3601
                    RTTIMESPEC time;
 
3602
                    property.strValue = aValue;
 
3603
                    property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
 
3604
                    if (aFlags != NULL)
 
3605
                        property.mFlags = fFlags;
 
3606
                    mHWData->mGuestProperties.push_back (property);
 
3607
                }
 
3608
            }
 
3609
            else if (SUCCEEDED(rc) && *aValue)
3129
3610
            {
3130
3611
                RTTIMESPEC time;
3131
 
                property.mValue = aValue;
3132
 
                property.mTimestamp = RTTimeSpecGetNano (RTTimeNow (&time));
3133
 
                if (aFlags != NULL)
3134
 
                    property.mFlags = fFlags;
 
3612
                mHWData.backup();
 
3613
                property.strName = aName;
 
3614
                property.strValue = aValue;
 
3615
                property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
 
3616
                property.mFlags = fFlags;
3135
3617
                mHWData->mGuestProperties.push_back (property);
3136
3618
            }
 
3619
            if (   SUCCEEDED(rc)
 
3620
                && (   mHWData->mGuestPropertyNotificationPatterns.isEmpty()
 
3621
                    || RTStrSimplePatternMultiMatch(mHWData->mGuestPropertyNotificationPatterns.raw(), RTSTR_MAX,
 
3622
                                                    utf8Name.raw(), RTSTR_MAX, NULL) )
 
3623
               )
 
3624
            {
 
3625
                /** @todo r=bird: Why aren't we leaving the lock here?  The
 
3626
                 *                same code in PushGuestProperty does... */
 
3627
                mParent->onGuestPropertyChange(mData->mUuid, aName, aValue, aFlags);
 
3628
            }
3137
3629
        }
3138
 
        else if (SUCCEEDED (rc) && *aValue)
 
3630
        else
3139
3631
        {
3140
 
            RTTIMESPEC time;
3141
 
            mHWData.backup();
3142
 
            property.mName = aName;
3143
 
            property.mValue = aValue;
3144
 
            property.mTimestamp = RTTimeSpecGetNano (RTTimeNow (&time));
3145
 
            property.mFlags = fFlags;
3146
 
            mHWData->mGuestProperties.push_back (property);
 
3632
            ComPtr<IInternalSessionControl> directControl =
 
3633
                mData->mSession.mDirectControl;
 
3634
 
 
3635
            /* just be on the safe side when calling another process */
 
3636
            alock.leave();
 
3637
 
 
3638
            BSTR dummy = NULL;
 
3639
            ULONG64 dummy64;
 
3640
            if (!directControl)
 
3641
                rc = E_FAIL;
 
3642
            else
 
3643
                rc = directControl->AccessGuestProperty(aName,
 
3644
                                                        *aValue ? aValue : NULL,  /** @todo Fix when adding DeleteGuestProperty(), see defect. */
 
3645
                                                        aFlags,
 
3646
                                                        true /* isSetter */,
 
3647
                                                        &dummy, &dummy64, &dummy);
3147
3648
        }
3148
 
        if (   SUCCEEDED (rc)
3149
 
            && (   matchAll
3150
 
                || RTStrSimplePatternMultiMatch (utf8Patterns.raw(), RTSTR_MAX,
3151
 
                                                utf8Name.raw(), RTSTR_MAX, NULL)
3152
 
              )
3153
 
          )
3154
 
            mParent->onGuestPropertyChange (mData->mUuid, aName, aValue, aFlags);
3155
3649
    }
3156
 
    else
 
3650
    catch (std::bad_alloc &)
3157
3651
    {
3158
 
        ComPtr <IInternalSessionControl> directControl =
3159
 
            mData->mSession.mDirectControl;
3160
 
 
3161
 
        /* just be on the safe side when calling another process */
3162
 
        alock.leave();
3163
 
 
3164
 
        BSTR dummy = NULL;
3165
 
        ULONG64 dummy64;
3166
 
        if (!directControl)
3167
 
            rc = E_FAIL;
3168
 
        else
3169
 
            rc = directControl->AccessGuestProperty (aName, aValue, aFlags,
3170
 
                                                     true /* isSetter */,
3171
 
                                                     &dummy, &dummy64, &dummy);
 
3652
        rc = E_OUTOFMEMORY;
3172
3653
    }
 
3654
 
3173
3655
    return rc;
3174
3656
#endif /* else !defined (VBOX_WITH_GUEST_PROPS) */
3175
3657
}
3179
3661
    return SetGuestProperty (aName, aValue, NULL);
3180
3662
}
3181
3663
 
3182
 
STDMETHODIMP Machine::
3183
 
EnumerateGuestProperties (IN_BSTR aPatterns, ComSafeArrayOut (BSTR, aNames),
3184
 
                          ComSafeArrayOut (BSTR, aValues),
3185
 
                          ComSafeArrayOut (ULONG64, aTimestamps),
3186
 
                          ComSafeArrayOut (BSTR, aFlags))
 
3664
STDMETHODIMP Machine::EnumerateGuestProperties(IN_BSTR aPatterns,
 
3665
                                               ComSafeArrayOut(BSTR, aNames),
 
3666
                                               ComSafeArrayOut(BSTR, aValues),
 
3667
                                               ComSafeArrayOut(ULONG64, aTimestamps),
 
3668
                                               ComSafeArrayOut(BSTR, aFlags))
3187
3669
{
3188
3670
#if !defined (VBOX_WITH_GUEST_PROPS)
3189
3671
    ReturnComNotImplemented();
3191
3673
    if (!VALID_PTR (aPatterns) && (aPatterns != NULL))
3192
3674
        return E_POINTER;
3193
3675
 
3194
 
    CheckComArgOutSafeArrayPointerValid (aNames);
3195
 
    CheckComArgOutSafeArrayPointerValid (aValues);
3196
 
    CheckComArgOutSafeArrayPointerValid (aTimestamps);
3197
 
    CheckComArgOutSafeArrayPointerValid (aFlags);
3198
 
 
3199
 
    AutoCaller autoCaller (this);
3200
 
    CheckComRCReturnRC (autoCaller.rc());
3201
 
 
3202
 
    AutoReadLock alock (this);
 
3676
    CheckComArgOutSafeArrayPointerValid(aNames);
 
3677
    CheckComArgOutSafeArrayPointerValid(aValues);
 
3678
    CheckComArgOutSafeArrayPointerValid(aTimestamps);
 
3679
    CheckComArgOutSafeArrayPointerValid(aFlags);
 
3680
 
 
3681
    AutoCaller autoCaller(this);
 
3682
    CheckComRCReturnRC(autoCaller.rc());
 
3683
 
 
3684
    AutoReadLock alock(this);
3203
3685
 
3204
3686
    using namespace guestProp;
3205
3687
    HRESULT rc = E_FAIL;
3206
3688
 
3207
 
    bool matchAll = false;
3208
 
    if ((NULL == aPatterns) || (0 == aPatterns[0]))
3209
 
        matchAll = true;
 
3689
    Utf8Str strPatterns(aPatterns);
 
3690
 
3210
3691
    if (!mHWData->mPropertyServiceActive)
3211
3692
    {
3212
3693
 
3213
 
/*
3214
 
 * Look for matching patterns and build up a list.
3215
 
 */
 
3694
        /*
 
3695
         * Look for matching patterns and build up a list.
 
3696
         */
3216
3697
        HWData::GuestPropertyList propList;
3217
3698
        for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
3218
 
             it != mHWData->mGuestProperties.end(); ++it)
3219
 
            if (   matchAll
3220
 
                || RTStrSimplePatternMultiMatch (Utf8Str (aPatterns).raw(),
3221
 
                                                 RTSTR_MAX,
3222
 
                                                 Utf8Str (it->mName).raw(),
3223
 
                                                 RTSTR_MAX, NULL)
 
3699
             it != mHWData->mGuestProperties.end();
 
3700
             ++it)
 
3701
            if (   strPatterns.isEmpty()
 
3702
                || RTStrSimplePatternMultiMatch(strPatterns.raw(),
 
3703
                                                RTSTR_MAX,
 
3704
                                                it->strName.raw(),
 
3705
                                                RTSTR_MAX, NULL)
3224
3706
               )
3225
 
                propList.push_back (*it);
 
3707
                propList.push_back(*it);
3226
3708
 
3227
 
/*
3228
 
 * And build up the arrays for returning the property information.
3229
 
 */
 
3709
        /*
 
3710
         * And build up the arrays for returning the property information.
 
3711
         */
3230
3712
        size_t cEntries = propList.size();
3231
 
        SafeArray <BSTR> names (cEntries);
3232
 
        SafeArray <BSTR> values (cEntries);
3233
 
        SafeArray <ULONG64> timestamps (cEntries);
3234
 
        SafeArray <BSTR> flags (cEntries);
 
3713
        SafeArray<BSTR> names (cEntries);
 
3714
        SafeArray<BSTR> values (cEntries);
 
3715
        SafeArray<ULONG64> timestamps (cEntries);
 
3716
        SafeArray<BSTR> flags (cEntries);
3235
3717
        size_t iProp = 0;
3236
3718
        for (HWData::GuestPropertyList::iterator it = propList.begin();
3237
 
             it != propList.end(); ++it)
 
3719
             it != propList.end();
 
3720
             ++it)
3238
3721
        {
3239
3722
             char szFlags[MAX_FLAGS_LEN + 1];
3240
 
             it->mName.cloneTo (&names[iProp]);
3241
 
             it->mValue.cloneTo (&values[iProp]);
 
3723
             it->strName.cloneTo(&names[iProp]);
 
3724
             it->strValue.cloneTo(&values[iProp]);
3242
3725
             timestamps[iProp] = it->mTimestamp;
3243
 
             writeFlags (it->mFlags, szFlags);
3244
 
             Bstr (szFlags).cloneTo (&flags[iProp]);
 
3726
             writeFlags(it->mFlags, szFlags);
 
3727
             Bstr(szFlags).cloneTo(&flags[iProp]);
3245
3728
             ++iProp;
3246
3729
        }
3247
 
        names.detachTo (ComSafeArrayOutArg (aNames));
3248
 
        values.detachTo (ComSafeArrayOutArg (aValues));
3249
 
        timestamps.detachTo (ComSafeArrayOutArg (aTimestamps));
3250
 
        flags.detachTo (ComSafeArrayOutArg (aFlags));
 
3730
        names.detachTo(ComSafeArrayOutArg(aNames));
 
3731
        values.detachTo(ComSafeArrayOutArg(aValues));
 
3732
        timestamps.detachTo(ComSafeArrayOutArg(aTimestamps));
 
3733
        flags.detachTo(ComSafeArrayOutArg(aFlags));
3251
3734
        rc = S_OK;
3252
3735
    }
3253
3736
    else
3254
3737
    {
3255
 
        ComPtr <IInternalSessionControl> directControl =
3256
 
            mData->mSession.mDirectControl;
 
3738
        ComPtr<IInternalSessionControl> directControl = mData->mSession.mDirectControl;
3257
3739
 
3258
3740
        /* just be on the safe side when calling another process */
3259
3741
        alock.unlock();
3261
3743
        if (!directControl)
3262
3744
            rc = E_FAIL;
3263
3745
        else
3264
 
            rc = directControl->EnumerateGuestProperties (aPatterns,
3265
 
                                                          ComSafeArrayOutArg (aNames),
3266
 
                                                          ComSafeArrayOutArg (aValues),
3267
 
                                                          ComSafeArrayOutArg (aTimestamps),
3268
 
                                                          ComSafeArrayOutArg (aFlags));
 
3746
            rc = directControl->EnumerateGuestProperties(aPatterns,
 
3747
                                                         ComSafeArrayOutArg(aNames),
 
3748
                                                         ComSafeArrayOutArg(aValues),
 
3749
                                                         ComSafeArrayOutArg(aTimestamps),
 
3750
                                                         ComSafeArrayOutArg(aFlags));
3269
3751
    }
3270
3752
    return rc;
3271
3753
#endif /* else !defined (VBOX_WITH_GUEST_PROPS) */
3272
3754
}
3273
3755
 
3274
 
STDMETHODIMP Machine::
3275
 
GetHardDiskAttachmentsOfController(IN_BSTR aName, ComSafeArrayOut (IHardDiskAttachment *, aAttachments))
 
3756
STDMETHODIMP Machine::GetMediumAttachmentsOfController(IN_BSTR aName,
 
3757
                                                       ComSafeArrayOut(IMediumAttachment*, aAttachments))
3276
3758
{
3277
 
    HDData::AttachmentList atts;
 
3759
    MediaData::AttachmentList atts;
3278
3760
 
3279
 
    HRESULT rc = getHardDiskAttachmentsOfController(aName, atts);
 
3761
    HRESULT rc = getMediumAttachmentsOfController(aName, atts);
3280
3762
    CheckComRCReturnRC(rc);
3281
3763
 
3282
 
    SafeIfaceArray<IHardDiskAttachment> attachments (atts);
3283
 
    attachments.detachTo (ComSafeArrayOutArg (aAttachments));
3284
 
 
3285
 
    return S_OK;
3286
 
}
3287
 
 
3288
 
STDMETHODIMP Machine::
3289
 
AddStorageController(IN_BSTR aName,
3290
 
                     StorageBus_T aConnectionType,
3291
 
                     IStorageController **controller)
 
3764
    SafeIfaceArray<IMediumAttachment> attachments(atts);
 
3765
    attachments.detachTo(ComSafeArrayOutArg(aAttachments));
 
3766
 
 
3767
    return S_OK;
 
3768
}
 
3769
 
 
3770
STDMETHODIMP Machine::GetMediumAttachment(IN_BSTR aControllerName,
 
3771
                                          LONG aControllerPort,
 
3772
                                          LONG aDevice,
 
3773
                                          IMediumAttachment **aAttachment)
 
3774
{
 
3775
    LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%d aDevice=%d\n",
 
3776
                     aControllerName, aControllerPort, aDevice));
 
3777
 
 
3778
    CheckComArgNotNull(aControllerName);
 
3779
    CheckComArgOutPointerValid(aAttachment);
 
3780
 
 
3781
    AutoCaller autoCaller(this);
 
3782
    CheckComRCReturnRC(autoCaller.rc());
 
3783
 
 
3784
    AutoReadLock alock(this);
 
3785
 
 
3786
    *aAttachment = NULL;
 
3787
 
 
3788
    ComObjPtr<MediumAttachment> pAttach = findAttachment(mMediaData->mAttachments,
 
3789
                                                         aControllerName,
 
3790
                                                         aControllerPort,
 
3791
                                                         aDevice);
 
3792
    if (pAttach.isNull())
 
3793
        return setError(VBOX_E_OBJECT_NOT_FOUND,
 
3794
                        tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
 
3795
                        aDevice, aControllerPort, aControllerName);
 
3796
 
 
3797
    pAttach.queryInterfaceTo(aAttachment);
 
3798
 
 
3799
    return S_OK;
 
3800
}
 
3801
 
 
3802
STDMETHODIMP Machine::AddStorageController(IN_BSTR aName,
 
3803
                                           StorageBus_T aConnectionType,
 
3804
                                           IStorageController **controller)
3292
3805
{
3293
3806
    CheckComArgStrNotEmptyOrNull(aName);
3294
3807
 
3295
3808
    if (   (aConnectionType <= StorageBus_Null)
3296
 
        || (aConnectionType >  StorageBus_SCSI))
 
3809
        || (aConnectionType >  StorageBus_Floppy))
3297
3810
        return setError (E_INVALIDARG,
3298
3811
            tr ("Invalid connection type: %d"),
3299
3812
                aConnectionType);
3300
3813
 
3301
 
    AutoCaller autoCaller (this);
3302
 
    CheckComRCReturnRC (autoCaller.rc());
3303
 
 
3304
 
    AutoWriteLock alock (this);
3305
 
 
3306
 
    HRESULT rc = checkStateDependency (MutableStateDep);
3307
 
    CheckComRCReturnRC (rc);
 
3814
    AutoCaller autoCaller(this);
 
3815
    CheckComRCReturnRC(autoCaller.rc());
 
3816
 
 
3817
    AutoWriteLock alock(this);
 
3818
 
 
3819
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3820
    CheckComRCReturnRC(rc);
3308
3821
 
3309
3822
    /* try to find one with the name first. */
3310
3823
    ComObjPtr<StorageController> ctrl;
3311
3824
 
3312
3825
    rc = getStorageControllerByName (aName, ctrl, false /* aSetError */);
3313
 
    if (SUCCEEDED (rc))
 
3826
    if (SUCCEEDED(rc))
3314
3827
        return setError (VBOX_E_OBJECT_IN_USE,
3315
3828
            tr ("Storage controller named '%ls' already exists"), aName);
3316
3829
 
3317
3830
    ctrl.createObject();
3318
 
    rc = ctrl->init (this, aName, aConnectionType);
3319
 
    CheckComRCReturnRC (rc);
 
3831
 
 
3832
    /* get a new instance number for the storage controller */
 
3833
    ULONG ulInstance = 0;
 
3834
    for (StorageControllerList::const_iterator it = mStorageControllers->begin();
 
3835
         it != mStorageControllers->end();
 
3836
         ++it)
 
3837
    {
 
3838
        if ((*it)->storageBus() == aConnectionType)
 
3839
        {
 
3840
            ULONG ulCurInst = (*it)->instance();
 
3841
 
 
3842
            if (ulCurInst >= ulInstance)
 
3843
                ulInstance = ulCurInst + 1;
 
3844
        }
 
3845
    }
 
3846
 
 
3847
    rc = ctrl->init(this, aName, aConnectionType, ulInstance);
 
3848
    CheckComRCReturnRC(rc);
3320
3849
 
3321
3850
    mStorageControllers.backup();
3322
3851
    mStorageControllers->push_back (ctrl);
3330
3859
    return S_OK;
3331
3860
}
3332
3861
 
3333
 
STDMETHODIMP Machine::
3334
 
GetStorageControllerByName(IN_BSTR aName, IStorageController **aStorageController)
 
3862
STDMETHODIMP Machine::GetStorageControllerByName(IN_BSTR aName,
 
3863
                                                 IStorageController **aStorageController)
3335
3864
{
3336
3865
    CheckComArgStrNotEmptyOrNull(aName);
3337
3866
 
3338
 
    AutoCaller autoCaller (this);
3339
 
    CheckComRCReturnRC (autoCaller.rc());
3340
 
 
3341
 
    AutoReadLock alock (this);
3342
 
 
3343
 
    ComObjPtr <StorageController> ctrl;
 
3867
    AutoCaller autoCaller(this);
 
3868
    CheckComRCReturnRC(autoCaller.rc());
 
3869
 
 
3870
    AutoReadLock alock(this);
 
3871
 
 
3872
    ComObjPtr<StorageController> ctrl;
3344
3873
 
3345
3874
    HRESULT rc = getStorageControllerByName (aName, ctrl, true /* aSetError */);
3346
 
    if (SUCCEEDED (rc))
3347
 
        ctrl.queryInterfaceTo (aStorageController);
 
3875
    if (SUCCEEDED(rc))
 
3876
        ctrl.queryInterfaceTo(aStorageController);
3348
3877
 
3349
3878
    return rc;
3350
3879
}
3351
3880
 
3352
 
STDMETHODIMP Machine::
3353
 
RemoveStorageController(IN_BSTR aName)
 
3881
STDMETHODIMP Machine::GetStorageControllerByInstance(ULONG aInstance,
 
3882
                                                     IStorageController **aStorageController)
 
3883
{
 
3884
    AutoCaller autoCaller(this);
 
3885
    CheckComRCReturnRC(autoCaller.rc());
 
3886
 
 
3887
    AutoReadLock alock(this);
 
3888
 
 
3889
    for (StorageControllerList::const_iterator it = mStorageControllers->begin();
 
3890
         it != mStorageControllers->end();
 
3891
         ++it)
 
3892
    {
 
3893
        if ((*it)->instance() == aInstance)
 
3894
        {
 
3895
            (*it).queryInterfaceTo(aStorageController);
 
3896
            return S_OK;
 
3897
        }
 
3898
    }
 
3899
 
 
3900
    return setError(VBOX_E_OBJECT_NOT_FOUND,
 
3901
                    tr("Could not find a storage controller with instance number '%lu'"),
 
3902
                    aInstance);
 
3903
}
 
3904
 
 
3905
STDMETHODIMP Machine::RemoveStorageController(IN_BSTR aName)
3354
3906
{
3355
3907
    CheckComArgStrNotEmptyOrNull(aName);
3356
3908
 
3357
 
    AutoCaller autoCaller (this);
3358
 
    CheckComRCReturnRC (autoCaller.rc());
3359
 
 
3360
 
    AutoWriteLock alock (this);
3361
 
 
3362
 
    HRESULT rc = checkStateDependency (MutableStateDep);
3363
 
    CheckComRCReturnRC (rc);
3364
 
 
3365
 
    ComObjPtr <StorageController> ctrl;
 
3909
    AutoCaller autoCaller(this);
 
3910
    CheckComRCReturnRC(autoCaller.rc());
 
3911
 
 
3912
    AutoWriteLock alock(this);
 
3913
 
 
3914
    HRESULT rc = checkStateDependency(MutableStateDep);
 
3915
    CheckComRCReturnRC(rc);
 
3916
 
 
3917
    ComObjPtr<StorageController> ctrl;
3366
3918
    rc = getStorageControllerByName (aName, ctrl, true /* aSetError */);
3367
 
    CheckComRCReturnRC (rc);
 
3919
    CheckComRCReturnRC(rc);
3368
3920
 
3369
3921
    /* We can remove the controller only if there is no device attached. */
3370
3922
    /* check if the device slot is already busy */
3371
 
    for (HDData::AttachmentList::const_iterator
3372
 
         it = mHDData->mAttachments.begin();
3373
 
         it != mHDData->mAttachments.end();
3374
 
         ++ it)
 
3923
    for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
3924
         it != mMediaData->mAttachments.end();
 
3925
         ++it)
3375
3926
    {
3376
 
        if (it != mHDData->mAttachments.end())
3377
 
        {
3378
 
            if ((*it)->controller() == aName)
3379
 
                return setError (VBOX_E_OBJECT_IN_USE,
3380
 
                    tr ("Storage controller named '%ls' has still devices attached"), aName);
3381
 
        }
 
3927
        if ((*it)->getControllerName() == aName)
 
3928
            return setError(VBOX_E_OBJECT_IN_USE,
 
3929
                            tr("Storage controller named '%ls' has still devices attached"),
 
3930
                            aName);
3382
3931
    }
3383
3932
 
3384
3933
    /* We can remove it now. */
3395
3944
    return S_OK;
3396
3945
}
3397
3946
 
 
3947
/* @todo where is the right place for this? */
 
3948
#define sSSMDisplayScreenshotVer 0x00010001
 
3949
 
 
3950
static int readSavedDisplayScreenshot(Utf8Str *pStateFilePath, uint32_t u32Type, uint8_t **ppu8Data, uint32_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height)
 
3951
{
 
3952
    LogFlowFunc(("u32Type = %d [%s]\n", u32Type, pStateFilePath->raw()));
 
3953
 
 
3954
    /* @todo cache read data */
 
3955
    if (pStateFilePath->isEmpty())
 
3956
    {
 
3957
        /* No saved state data. */
 
3958
        return VERR_NOT_SUPPORTED;
 
3959
    }
 
3960
 
 
3961
    uint8_t *pu8Data = NULL;
 
3962
    uint32_t cbData = 0;
 
3963
    uint32_t u32Width = 0;
 
3964
    uint32_t u32Height = 0;
 
3965
 
 
3966
    PSSMHANDLE pSSM;
 
3967
    int rc = SSMR3Open(pStateFilePath->raw(), 0 /*fFlags*/, &pSSM);
 
3968
    if (RT_SUCCESS(rc))
 
3969
    {
 
3970
        uint32_t uVersion;
 
3971
        rc = SSMR3Seek(pSSM, "DisplayScreenshot", 1100 /*iInstance*/, &uVersion);
 
3972
        if (RT_SUCCESS(rc))
 
3973
        {
 
3974
            if (uVersion == sSSMDisplayScreenshotVer)
 
3975
            {
 
3976
                uint32_t cBlocks;
 
3977
                rc = SSMR3GetU32(pSSM, &cBlocks);
 
3978
                AssertRCReturn(rc, rc);
 
3979
 
 
3980
                for (uint32_t i = 0; i < cBlocks; i++)
 
3981
                {
 
3982
                    uint32_t cbBlock;
 
3983
                    rc = SSMR3GetU32(pSSM, &cbBlock);
 
3984
                    AssertRCBreak(rc);
 
3985
 
 
3986
                    uint32_t typeOfBlock;
 
3987
                    rc = SSMR3GetU32(pSSM, &typeOfBlock);
 
3988
                    AssertRCBreak(rc);
 
3989
 
 
3990
                    LogFlowFunc(("[%d] type %d, size %d bytes\n", i, typeOfBlock, cbBlock));
 
3991
 
 
3992
                    if (typeOfBlock == u32Type)
 
3993
                    {
 
3994
                        if (cbBlock > 2 * sizeof (uint32_t))
 
3995
                        {
 
3996
                            cbData = cbBlock - 2 * sizeof (uint32_t);
 
3997
                            pu8Data = (uint8_t *)RTMemAlloc(cbData);
 
3998
                            if (pu8Data == NULL)
 
3999
                            {
 
4000
                                rc = VERR_NO_MEMORY;
 
4001
                                break;
 
4002
                            }
 
4003
 
 
4004
                            rc = SSMR3GetU32(pSSM, &u32Width);
 
4005
                            AssertRCBreak(rc);
 
4006
                            rc = SSMR3GetU32(pSSM, &u32Height);
 
4007
                            AssertRCBreak(rc);
 
4008
                            rc = SSMR3GetMem(pSSM, pu8Data, cbData);
 
4009
                            AssertRCBreak(rc);
 
4010
                        }
 
4011
                        else
 
4012
                        {
 
4013
                            /* No saved state data. */
 
4014
                            rc = VERR_NOT_SUPPORTED;
 
4015
                        }
 
4016
 
 
4017
                        break;
 
4018
                    }
 
4019
                    else
 
4020
                    {
 
4021
                        if (cbBlock != 0)
 
4022
                        {
 
4023
                            rc = SSMR3Skip(pSSM, cbBlock);
 
4024
                            AssertRCBreak(rc);
 
4025
                        }
 
4026
                    }
 
4027
                }
 
4028
            }
 
4029
            else
 
4030
            {
 
4031
                rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
 
4032
            }
 
4033
        }
 
4034
 
 
4035
        SSMR3Close(pSSM);
 
4036
    }
 
4037
 
 
4038
    if (RT_SUCCESS(rc))
 
4039
    {
 
4040
        if (u32Type == 0 && cbData % 4 != 0)
 
4041
        {
 
4042
            /* Bitmap is 32bpp, so data is invalid. */
 
4043
            rc = VERR_SSM_UNEXPECTED_DATA;
 
4044
        }
 
4045
    }
 
4046
 
 
4047
    if (RT_SUCCESS(rc))
 
4048
    {
 
4049
        *ppu8Data = pu8Data;
 
4050
        *pcbData = cbData;
 
4051
        *pu32Width = u32Width;
 
4052
        *pu32Height = u32Height;
 
4053
        LogFlowFunc(("cbData %d, u32Width %d, u32Height %d\n", cbData, u32Width, u32Height));
 
4054
    }
 
4055
 
 
4056
    LogFlowFunc(("rc %Rrc\n", rc));
 
4057
    return rc;
 
4058
}
 
4059
 
 
4060
static void freeSavedDisplayScreenshot(uint8_t *pu8Data)
 
4061
{
 
4062
    /* @todo not necessary when caching is implemented. */
 
4063
    RTMemFree(pu8Data);
 
4064
}
 
4065
 
 
4066
STDMETHODIMP Machine::QuerySavedThumbnailSize(ULONG *aSize, ULONG *aWidth, ULONG *aHeight)
 
4067
{
 
4068
    LogFlowThisFunc(("\n"));
 
4069
 
 
4070
    CheckComArgNotNull(aSize);
 
4071
    CheckComArgNotNull(aWidth);
 
4072
    CheckComArgNotNull(aHeight);
 
4073
 
 
4074
    AutoCaller autoCaller(this);
 
4075
    CheckComRCReturnRC(autoCaller.rc());
 
4076
 
 
4077
    AutoReadLock alock(this);
 
4078
 
 
4079
    uint8_t *pu8Data = NULL;
 
4080
    uint32_t cbData = 0;
 
4081
    uint32_t u32Width = 0;
 
4082
    uint32_t u32Height = 0;
 
4083
 
 
4084
    int vrc = readSavedDisplayScreenshot(&mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
 
4085
 
 
4086
    if (RT_FAILURE(vrc))
 
4087
        return setError (VBOX_E_IPRT_ERROR,
 
4088
                         tr("Saved screenshot data is not available (%Rrc)"), vrc);
 
4089
 
 
4090
    *aSize = cbData;
 
4091
    *aWidth = u32Width;
 
4092
    *aHeight = u32Height;
 
4093
 
 
4094
    freeSavedDisplayScreenshot(pu8Data);
 
4095
 
 
4096
    return S_OK;
 
4097
}
 
4098
 
 
4099
STDMETHODIMP Machine::ReadSavedThumbnailToArray(BOOL aBGR, ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData))
 
4100
{
 
4101
    LogFlowThisFunc(("\n"));
 
4102
 
 
4103
    CheckComArgNotNull(aWidth);
 
4104
    CheckComArgNotNull(aHeight);
 
4105
    CheckComArgExpr(aData, !ComSafeArrayOutIsNull(aData));
 
4106
 
 
4107
    AutoCaller autoCaller(this);
 
4108
    CheckComRCReturnRC(autoCaller.rc());
 
4109
 
 
4110
    AutoReadLock alock(this);
 
4111
 
 
4112
    uint8_t *pu8Data = NULL;
 
4113
    uint32_t cbData = 0;
 
4114
    uint32_t u32Width = 0;
 
4115
    uint32_t u32Height = 0;
 
4116
 
 
4117
    int vrc = readSavedDisplayScreenshot(&mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
 
4118
 
 
4119
    if (RT_FAILURE(vrc))
 
4120
        return setError (VBOX_E_IPRT_ERROR,
 
4121
                         tr("Saved screenshot data is not available (%Rrc)"), vrc);
 
4122
 
 
4123
    *aWidth = u32Width;
 
4124
    *aHeight = u32Height;
 
4125
 
 
4126
    com::SafeArray<BYTE> bitmap(cbData);
 
4127
    /* Convert pixels to format expected by the API caller. */
 
4128
    if (aBGR)
 
4129
    {
 
4130
        /* [0] B, [1] G, [2] R, [3] A. */
 
4131
        for (unsigned i = 0; i < cbData; i += 4)
 
4132
        {
 
4133
            bitmap[i]     = pu8Data[i];
 
4134
            bitmap[i + 1] = pu8Data[i + 1];
 
4135
            bitmap[i + 2] = pu8Data[i + 2];
 
4136
            bitmap[i + 3] = 0xff;
 
4137
        }
 
4138
    }
 
4139
    else
 
4140
    {
 
4141
        /* [0] R, [1] G, [2] B, [3] A. */
 
4142
        for (unsigned i = 0; i < cbData; i += 4)
 
4143
        {
 
4144
            bitmap[i]     = pu8Data[i + 2];
 
4145
            bitmap[i + 1] = pu8Data[i + 1];
 
4146
            bitmap[i + 2] = pu8Data[i];
 
4147
            bitmap[i + 3] = 0xff;
 
4148
        }
 
4149
    }
 
4150
    bitmap.detachTo(ComSafeArrayOutArg(aData));
 
4151
 
 
4152
    freeSavedDisplayScreenshot(pu8Data);
 
4153
 
 
4154
    return S_OK;
 
4155
}
 
4156
 
 
4157
STDMETHODIMP Machine::QuerySavedScreenshotPNGSize(ULONG *aSize, ULONG *aWidth, ULONG *aHeight)
 
4158
{
 
4159
    LogFlowThisFunc(("\n"));
 
4160
 
 
4161
    CheckComArgNotNull(aSize);
 
4162
    CheckComArgNotNull(aWidth);
 
4163
    CheckComArgNotNull(aHeight);
 
4164
 
 
4165
    AutoCaller autoCaller(this);
 
4166
    CheckComRCReturnRC(autoCaller.rc());
 
4167
 
 
4168
    AutoReadLock alock(this);
 
4169
 
 
4170
    uint8_t *pu8Data = NULL;
 
4171
    uint32_t cbData = 0;
 
4172
    uint32_t u32Width = 0;
 
4173
    uint32_t u32Height = 0;
 
4174
 
 
4175
    int vrc = readSavedDisplayScreenshot(&mSSData->mStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
 
4176
 
 
4177
    if (RT_FAILURE(vrc))
 
4178
        return setError (VBOX_E_IPRT_ERROR,
 
4179
                         tr("Saved screenshot data is not available (%Rrc)"), vrc);
 
4180
 
 
4181
    *aSize = cbData;
 
4182
    *aWidth = u32Width;
 
4183
    *aHeight = u32Height;
 
4184
 
 
4185
    freeSavedDisplayScreenshot(pu8Data);
 
4186
 
 
4187
    return S_OK;
 
4188
}
 
4189
 
 
4190
STDMETHODIMP Machine::ReadSavedScreenshotPNGToArray(ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData))
 
4191
{
 
4192
    LogFlowThisFunc(("\n"));
 
4193
 
 
4194
    CheckComArgNotNull(aWidth);
 
4195
    CheckComArgNotNull(aHeight);
 
4196
    CheckComArgExpr(aData, !ComSafeArrayOutIsNull(aData));
 
4197
 
 
4198
    AutoCaller autoCaller(this);
 
4199
    CheckComRCReturnRC(autoCaller.rc());
 
4200
 
 
4201
    AutoReadLock alock(this);
 
4202
 
 
4203
    uint8_t *pu8Data = NULL;
 
4204
    uint32_t cbData = 0;
 
4205
    uint32_t u32Width = 0;
 
4206
    uint32_t u32Height = 0;
 
4207
 
 
4208
    int vrc = readSavedDisplayScreenshot(&mSSData->mStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
 
4209
 
 
4210
    if (RT_FAILURE(vrc))
 
4211
        return setError (VBOX_E_IPRT_ERROR,
 
4212
                         tr("Saved screenshot data is not available (%Rrc)"), vrc);
 
4213
 
 
4214
    *aWidth = u32Width;
 
4215
    *aHeight = u32Height;
 
4216
 
 
4217
    com::SafeArray<BYTE> png(cbData);
 
4218
    for (unsigned i = 0; i < cbData; i++)
 
4219
        png[i] = pu8Data[i];
 
4220
    png.detachTo(ComSafeArrayOutArg(aData));
 
4221
 
 
4222
    freeSavedDisplayScreenshot(pu8Data);
 
4223
 
 
4224
    return S_OK;
 
4225
}
 
4226
 
3398
4227
// public methods for internal purposes
3399
4228
/////////////////////////////////////////////////////////////////////////////
3400
4229
 
3405
4234
 *
3406
4235
 *  @note locks this object for reading.
3407
4236
 */
3408
 
HRESULT Machine::saveRegistryEntry (settings::Key &aEntryNode)
 
4237
HRESULT Machine::saveRegistryEntry(settings::MachineRegistryEntry &data)
3409
4238
{
3410
 
    AssertReturn (!aEntryNode.isNull(), E_FAIL);
3411
 
 
3412
 
    AutoLimitedCaller autoCaller (this);
3413
 
    AssertComRCReturnRC (autoCaller.rc());
3414
 
 
3415
 
    AutoReadLock alock (this);
3416
 
 
3417
 
    /* UUID */
3418
 
    aEntryNode.setValue <Guid> ("uuid", mData->mUuid);
3419
 
    /* settings file name (possibly, relative) */
3420
 
    aEntryNode.setValue <Bstr> ("src", mData->mConfigFile);
 
4239
    AutoLimitedCaller autoCaller(this);
 
4240
    AssertComRCReturnRC(autoCaller.rc());
 
4241
 
 
4242
    AutoReadLock alock(this);
 
4243
 
 
4244
    data.uuid = mData->mUuid;
 
4245
    data.strSettingsFile = mData->m_strConfigFile;
3421
4246
 
3422
4247
    return S_OK;
3423
4248
}
3433
4258
 *
3434
4259
 * @note Locks this object for reading.
3435
4260
 */
3436
 
int Machine::calculateFullPath (const char *aPath, Utf8Str &aResult)
 
4261
int Machine::calculateFullPath(const Utf8Str &strPath, Utf8Str &aResult)
3437
4262
{
3438
 
    AutoCaller autoCaller (this);
 
4263
    AutoCaller autoCaller(this);
3439
4264
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
3440
4265
 
3441
 
    AutoReadLock alock (this);
3442
 
 
3443
 
    AssertReturn (!mData->mConfigFileFull.isNull(), VERR_GENERAL_FAILURE);
3444
 
 
3445
 
    Utf8Str settingsDir = mData->mConfigFileFull;
3446
 
 
3447
 
    RTPathStripFilename (settingsDir.mutableRaw());
3448
 
    char folder [RTPATH_MAX];
3449
 
    int vrc = RTPathAbsEx (settingsDir, aPath, folder, sizeof (folder));
3450
 
    if (RT_SUCCESS (vrc))
 
4266
    AutoReadLock alock(this);
 
4267
 
 
4268
    AssertReturn (!mData->m_strConfigFileFull.isEmpty(), VERR_GENERAL_FAILURE);
 
4269
 
 
4270
    Utf8Str strSettingsDir = mData->m_strConfigFileFull;
 
4271
 
 
4272
    strSettingsDir.stripFilename();
 
4273
    char folder[RTPATH_MAX];
 
4274
    int vrc = RTPathAbsEx(strSettingsDir.c_str(), strPath.c_str(), folder, sizeof(folder));
 
4275
    if (RT_SUCCESS(vrc))
3451
4276
        aResult = folder;
3452
4277
 
3453
4278
    return vrc;
3464
4289
 *
3465
4290
 * @note Locks this object for reading.
3466
4291
 */
3467
 
void Machine::calculateRelativePath (const char *aPath, Utf8Str &aResult)
 
4292
void Machine::calculateRelativePath(const Utf8Str &strPath, Utf8Str &aResult)
3468
4293
{
3469
 
    AutoCaller autoCaller (this);
 
4294
    AutoCaller autoCaller(this);
3470
4295
    AssertComRCReturn (autoCaller.rc(), (void) 0);
3471
4296
 
3472
 
    AutoReadLock alock (this);
3473
 
 
3474
 
    AssertReturnVoid (!mData->mConfigFileFull.isNull());
3475
 
 
3476
 
    Utf8Str settingsDir = mData->mConfigFileFull;
3477
 
 
3478
 
    RTPathStripFilename (settingsDir.mutableRaw());
3479
 
    if (RTPathStartsWith (aPath, settingsDir))
 
4297
    AutoReadLock alock(this);
 
4298
 
 
4299
    AssertReturnVoid (!mData->m_strConfigFileFull.isEmpty());
 
4300
 
 
4301
    Utf8Str settingsDir = mData->m_strConfigFileFull;
 
4302
 
 
4303
    settingsDir.stripFilename();
 
4304
    if (RTPathStartsWith(strPath.c_str(), settingsDir.c_str()))
3480
4305
    {
3481
4306
        /* when assigning, we create a separate Utf8Str instance because both
3482
4307
         * aPath and aResult can point to the same memory location when this
3483
4308
         * func is called (if we just do aResult = aPath, aResult will be freed
3484
4309
         * first, and since its the same as aPath, an attempt to copy garbage
3485
4310
         * will be made. */
3486
 
        aResult = Utf8Str (aPath + settingsDir.length() + 1);
 
4311
        aResult = Utf8Str(strPath.c_str() + settingsDir.length() + 1);
3487
4312
    }
3488
4313
}
3489
4314
 
3493
4318
 */
3494
4319
void Machine::getLogFolder (Utf8Str &aLogFolder)
3495
4320
{
3496
 
    AutoCaller autoCaller (this);
 
4321
    AutoCaller autoCaller(this);
3497
4322
    AssertComRCReturnVoid (autoCaller.rc());
3498
4323
 
3499
 
    AutoReadLock alock (this);
 
4324
    AutoReadLock alock(this);
3500
4325
 
3501
4326
    Utf8Str settingsDir;
3502
4327
    if (isInOwnDir (&settingsDir))
3517
4342
 *  @note Locks this object for writing, calls the client process (outside the
3518
4343
 *        lock).
3519
4344
 */
3520
 
HRESULT Machine::openSession (IInternalSessionControl *aControl)
 
4345
HRESULT Machine::openSession(IInternalSessionControl *aControl)
3521
4346
{
3522
4347
    LogFlowThisFuncEnter();
3523
4348
 
3524
 
    AssertReturn (aControl, E_FAIL);
3525
 
 
3526
 
    AutoCaller autoCaller (this);
3527
 
    CheckComRCReturnRC (autoCaller.rc());
3528
 
 
3529
 
    AutoWriteLock alock (this);
 
4349
    AssertReturn(aControl, E_FAIL);
 
4350
 
 
4351
    AutoCaller autoCaller(this);
 
4352
    CheckComRCReturnRC(autoCaller.rc());
 
4353
 
 
4354
    AutoWriteLock alock(this);
3530
4355
 
3531
4356
    if (!mData->mRegistered)
3532
 
        return setError (E_UNEXPECTED,
3533
 
            tr ("The machine '%ls' is not registered"), mUserData->mName.raw());
3534
 
 
3535
 
    LogFlowThisFunc (("mSession.mState=%d\n", mData->mSession.mState));
 
4357
        return setError(E_UNEXPECTED,
 
4358
                        tr("The machine '%ls' is not registered"),
 
4359
                        mUserData->mName.raw());
 
4360
 
 
4361
    LogFlowThisFunc(("mSession.mState=%s\n", Global::stringifySessionState(mData->mSession.mState)));
 
4362
 
 
4363
    /* Hack: in case the session is closing and there is a progress object
 
4364
     * which allows waiting for the session to be closed, take the opportunity
 
4365
     * and do a limited wait (max. 1 second). This helps a lot when the system
 
4366
     * is busy and thus session closing can take a little while. */
 
4367
    if (    mData->mSession.mState == SessionState_Closing
 
4368
        &&  mData->mSession.mProgress)
 
4369
    {
 
4370
        alock.leave();
 
4371
        mData->mSession.mProgress->WaitForCompletion(1000);
 
4372
        alock.enter();
 
4373
        LogFlowThisFunc(("after waiting: mSession.mState=%s\n", Global::stringifySessionState(mData->mSession.mState)));
 
4374
    }
3536
4375
 
3537
4376
    if (mData->mSession.mState == SessionState_Open ||
3538
4377
        mData->mSession.mState == SessionState_Closing)
3539
 
        return setError (VBOX_E_INVALID_OBJECT_STATE,
3540
 
            tr ("A session for the machine '%ls' is currently open "
3541
 
                "(or being closed)"),
3542
 
            mUserData->mName.raw());
 
4378
        return setError(VBOX_E_INVALID_OBJECT_STATE,
 
4379
                        tr("A session for the machine '%ls' is currently open (or being closed)"),
 
4380
                        mUserData->mName.raw());
3543
4381
 
3544
4382
    /* may not be busy */
3545
 
    AssertReturn (!Global::IsOnlineOrTransient (mData->mMachineState), E_FAIL);
 
4383
    AssertReturn(!Global::IsOnlineOrTransient(mData->mMachineState), E_FAIL);
3546
4384
 
3547
4385
    /* get the session PID */
3548
4386
    RTPROCESS pid = NIL_RTPROCESS;
3549
 
    AssertCompile (sizeof (ULONG) == sizeof (RTPROCESS));
3550
 
    aControl->GetPID ((ULONG *) &pid);
3551
 
    Assert (pid != NIL_RTPROCESS);
 
4387
    AssertCompile(sizeof(ULONG) == sizeof(RTPROCESS));
 
4388
    aControl->GetPID((ULONG *) &pid);
 
4389
    Assert(pid != NIL_RTPROCESS);
3552
4390
 
3553
4391
    if (mData->mSession.mState == SessionState_Spawning)
3554
4392
    {
3556
4394
         * reject any other open attempts from processes other than one
3557
4395
         * started by #openRemoteSession(). */
3558
4396
 
3559
 
        LogFlowThisFunc (("mSession.mPid=%d(0x%x)\n",
 
4397
        LogFlowThisFunc(("mSession.mPid=%d(0x%x)\n",
3560
4398
                          mData->mSession.mPid, mData->mSession.mPid));
3561
 
        LogFlowThisFunc (("session.pid=%d(0x%x)\n", pid, pid));
 
4399
        LogFlowThisFunc(("session.pid=%d(0x%x)\n", pid, pid));
3562
4400
 
3563
4401
        if (mData->mSession.mPid != pid)
3564
 
            return setError (E_ACCESSDENIED,
3565
 
                tr ("An unexpected process (PID=0x%08X) has tried to open a direct "
3566
 
                    "session with the machine named '%ls', while only a process "
3567
 
                    "started by OpenRemoteSession (PID=0x%08X) is allowed"),
3568
 
                pid, mUserData->mName.raw(), mData->mSession.mPid);
 
4402
            return setError(E_ACCESSDENIED,
 
4403
                            tr("An unexpected process (PID=0x%08X) has tried to open a direct "
 
4404
                               "session with the machine named '%ls', while only a process "
 
4405
                               "started by OpenRemoteSession (PID=0x%08X) is allowed"),
 
4406
                            pid, mUserData->mName.raw(), mData->mSession.mPid);
3569
4407
    }
3570
4408
 
3571
4409
    /* create a SessionMachine object */
3572
 
    ComObjPtr <SessionMachine> sessionMachine;
 
4410
    ComObjPtr<SessionMachine> sessionMachine;
3573
4411
    sessionMachine.createObject();
3574
 
    HRESULT rc = sessionMachine->init (this);
3575
 
    AssertComRC (rc);
 
4412
    HRESULT rc = sessionMachine->init(this);
 
4413
    AssertComRC(rc);
3576
4414
 
3577
4415
    /* NOTE: doing return from this function after this point but
3578
4416
     * before the end is forbidden since it may call SessionMachine::uninit()
3580
4418
     * lock while still holding the Machine lock in alock so that a deadlock
3581
4419
     * is possible due to the wrong lock order. */
3582
4420
 
3583
 
    if (SUCCEEDED (rc))
 
4421
    if (SUCCEEDED(rc))
3584
4422
    {
3585
4423
#ifdef VBOX_WITH_RESOURCE_USAGE_API
3586
 
        registerMetrics (mParent->performanceCollector(), this, pid);
 
4424
        registerMetrics(mParent->performanceCollector(), this, pid);
3587
4425
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3588
4426
 
3589
4427
        /*
3606
4444
         */
3607
4445
        alock.leave();
3608
4446
 
3609
 
        LogFlowThisFunc (("Calling AssignMachine()...\n"));
3610
 
        rc = aControl->AssignMachine (sessionMachine);
3611
 
        LogFlowThisFunc (("AssignMachine() returned %08X\n", rc));
 
4447
        LogFlowThisFunc(("Calling AssignMachine()...\n"));
 
4448
        rc = aControl->AssignMachine(sessionMachine);
 
4449
        LogFlowThisFunc(("AssignMachine() returned %08X\n", rc));
3612
4450
 
3613
4451
        /* The failure may occur w/o any error info (from RPC), so provide one */
3614
 
        if (FAILED (rc))
3615
 
            setError (VBOX_E_VM_ERROR,
3616
 
                tr ("Failed to assign the machine to the session (%Rrc)"), rc);
 
4452
        if (FAILED(rc))
 
4453
            setError(VBOX_E_VM_ERROR,
 
4454
                tr("Failed to assign the machine to the session (%Rrc)"), rc);
3617
4455
 
3618
 
        if (SUCCEEDED (rc) && origState == SessionState_Spawning)
 
4456
        if (SUCCEEDED(rc) && origState == SessionState_Spawning)
3619
4457
        {
3620
4458
            /* complete the remote session initialization */
3621
4459
 
3622
4460
            /* get the console from the direct session */
3623
 
            ComPtr <IConsole> console;
3624
 
            rc = aControl->GetRemoteConsole (console.asOutParam());
3625
 
            ComAssertComRC (rc);
 
4461
            ComPtr<IConsole> console;
 
4462
            rc = aControl->GetRemoteConsole(console.asOutParam());
 
4463
            ComAssertComRC(rc);
3626
4464
 
3627
 
            if (SUCCEEDED (rc) && !console)
 
4465
            if (SUCCEEDED(rc) && !console)
3628
4466
            {
3629
 
                ComAssert (!!console);
 
4467
                ComAssert(!!console);
3630
4468
                rc = E_FAIL;
3631
4469
            }
3632
4470
 
3633
4471
            /* assign machine & console to the remote session */
3634
 
            if (SUCCEEDED (rc))
 
4472
            if (SUCCEEDED(rc))
3635
4473
            {
3636
4474
                /*
3637
4475
                 *  after openRemoteSession(), the first and the only
3638
4476
                 *  entry in remoteControls is that remote session
3639
4477
                 */
3640
 
                LogFlowThisFunc (("Calling AssignRemoteMachine()...\n"));
 
4478
                LogFlowThisFunc(("Calling AssignRemoteMachine()...\n"));
3641
4479
                rc = mData->mSession.mRemoteControls.front()->
3642
 
                    AssignRemoteMachine (sessionMachine, console);
3643
 
                LogFlowThisFunc (("AssignRemoteMachine() returned %08X\n", rc));
 
4480
                    AssignRemoteMachine(sessionMachine, console);
 
4481
                LogFlowThisFunc(("AssignRemoteMachine() returned %08X\n", rc));
3644
4482
 
3645
4483
                /* The failure may occur w/o any error info (from RPC), so provide one */
3646
 
                if (FAILED (rc))
3647
 
                    setError (VBOX_E_VM_ERROR,
3648
 
                        tr ("Failed to assign the machine to the remote session (%Rrc)"), rc);
 
4484
                if (FAILED(rc))
 
4485
                    setError(VBOX_E_VM_ERROR,
 
4486
                             tr("Failed to assign the machine to the remote session (%Rrc)"), rc);
3649
4487
            }
3650
4488
 
3651
 
            if (FAILED (rc))
 
4489
            if (FAILED(rc))
3652
4490
                aControl->Uninitialize();
3653
4491
        }
3654
4492
 
3667
4505
        /* We don't reset mSession.mPid here because it is necessary for
3668
4506
         * SessionMachine::uninit() to reap the child process later. */
3669
4507
 
3670
 
        if (FAILED (rc))
 
4508
        if (FAILED(rc))
3671
4509
        {
3672
4510
            /* Close the remote session, remove the remote control from the list
3673
4511
             * and reset session state to Closed (@note keep the code in sync
3687
4525
    else
3688
4526
    {
3689
4527
        /* memorize PID of the directly opened session */
3690
 
        if (SUCCEEDED (rc))
 
4528
        if (SUCCEEDED(rc))
3691
4529
            mData->mSession.mPid = pid;
3692
4530
    }
3693
4531
 
3694
 
    if (SUCCEEDED (rc))
 
4532
    if (SUCCEEDED(rc))
3695
4533
    {
3696
4534
        /* memorize the direct session control and cache IUnknown for it */
3697
4535
        mData->mSession.mDirectControl = aControl;
3702
4540
        /* request an IUnknown pointer early from the remote party for later
3703
4541
         * identity checks (it will be internally cached within mDirectControl
3704
4542
         * at least on XPCOM) */
3705
 
        ComPtr <IUnknown> unk = mData->mSession.mDirectControl;
3706
 
        NOREF (unk);
 
4543
        ComPtr<IUnknown> unk = mData->mSession.mDirectControl;
 
4544
        NOREF(unk);
3707
4545
    }
3708
4546
 
3709
4547
    if (mData->mSession.mProgress)
3710
4548
    {
3711
4549
        /* finalize the progress after setting the state, for consistency */
3712
 
        mData->mSession.mProgress->notifyComplete (rc);
 
4550
        mData->mSession.mProgress->notifyComplete(rc);
3713
4551
        mData->mSession.mProgress.setNull();
3714
4552
    }
3715
4553
 
3718
4556
    alock.leave();
3719
4557
 
3720
4558
    /* uninitialize the created session machine on failure */
3721
 
    if (FAILED (rc))
 
4559
    if (FAILED(rc))
3722
4560
        sessionMachine->uninit();
3723
4561
 
3724
 
    LogFlowThisFunc (("rc=%08X\n", rc));
 
4562
    LogFlowThisFunc(("rc=%08X\n", rc));
3725
4563
    LogFlowThisFuncLeave();
3726
4564
    return rc;
3727
4565
}
3730
4568
 *  @note Locks this object for writing, calls the client process
3731
4569
 *        (inside the lock).
3732
4570
 */
3733
 
HRESULT Machine::openRemoteSession (IInternalSessionControl *aControl,
3734
 
                                    IN_BSTR aType, IN_BSTR aEnvironment,
3735
 
                                    Progress *aProgress)
 
4571
HRESULT Machine::openRemoteSession(IInternalSessionControl *aControl,
 
4572
                                   IN_BSTR aType,
 
4573
                                   IN_BSTR aEnvironment,
 
4574
                                   Progress *aProgress)
3736
4575
{
3737
4576
    LogFlowThisFuncEnter();
3738
4577
 
3739
 
    AssertReturn (aControl, E_FAIL);
3740
 
    AssertReturn (aProgress, E_FAIL);
3741
 
 
3742
 
    AutoCaller autoCaller (this);
3743
 
    CheckComRCReturnRC (autoCaller.rc());
3744
 
 
3745
 
    AutoWriteLock alock (this);
 
4578
    AssertReturn(aControl, E_FAIL);
 
4579
    AssertReturn(aProgress, E_FAIL);
 
4580
 
 
4581
    AutoCaller autoCaller(this);
 
4582
    CheckComRCReturnRC(autoCaller.rc());
 
4583
 
 
4584
    AutoWriteLock alock(this);
3746
4585
 
3747
4586
    if (!mData->mRegistered)
3748
 
        return setError (E_UNEXPECTED,
3749
 
            tr ("The machine '%ls' is not registered"), mUserData->mName.raw());
 
4587
        return setError(E_UNEXPECTED,
 
4588
                        tr("The machine '%ls' is not registered"),
 
4589
                        mUserData->mName.raw());
3750
4590
 
3751
 
    LogFlowThisFunc (("mSession.mState=%d\n", mData->mSession.mState));
 
4591
    LogFlowThisFunc(("mSession.mState=%s\n", Global::stringifySessionState(mData->mSession.mState)));
3752
4592
 
3753
4593
    if (mData->mSession.mState == SessionState_Open ||
3754
4594
        mData->mSession.mState == SessionState_Spawning ||
3755
4595
        mData->mSession.mState == SessionState_Closing)
3756
 
        return setError (VBOX_E_INVALID_OBJECT_STATE,
3757
 
            tr ("A session for the machine '%ls' is currently open "
3758
 
                "(or being opened or closed)"),
3759
 
            mUserData->mName.raw());
 
4596
        return setError(VBOX_E_INVALID_OBJECT_STATE,
 
4597
                        tr("A session for the machine '%ls' is currently open (or being opened or closed)"),
 
4598
                        mUserData->mName.raw());
3760
4599
 
3761
4600
    /* may not be busy */
3762
 
    AssertReturn (!Global::IsOnlineOrTransient (mData->mMachineState), E_FAIL);
 
4601
    AssertReturn(!Global::IsOnlineOrTransient (mData->mMachineState), E_FAIL);
3763
4602
 
3764
4603
    /* get the path to the executable */
3765
 
    char path [RTPATH_MAX];
3766
 
    RTPathAppPrivateArch (path, RTPATH_MAX);
3767
 
    size_t sz = strlen (path);
3768
 
    path [sz++] = RTPATH_DELIMITER;
3769
 
    path [sz] = 0;
3770
 
    char *cmd = path + sz;
 
4604
    char szPath[RTPATH_MAX];
 
4605
    RTPathAppPrivateArch(szPath, RTPATH_MAX);
 
4606
    size_t sz = strlen(szPath);
 
4607
    szPath[sz++] = RTPATH_DELIMITER;
 
4608
    szPath[sz] = 0;
 
4609
    char *cmd = szPath + sz;
3771
4610
    sz = RTPATH_MAX - sz;
3772
4611
 
3773
4612
    int vrc = VINF_SUCCESS;
3782
4621
        do
3783
4622
        {
3784
4623
            /* clone the current environment */
3785
 
            int vrc2 = RTEnvClone (&env, RTENV_DEFAULT);
3786
 
            AssertRCBreakStmt (vrc2, vrc = vrc2);
 
4624
            int vrc2 = RTEnvClone(&env, RTENV_DEFAULT);
 
4625
            AssertRCBreakStmt(vrc2, vrc = vrc2);
3787
4626
 
3788
 
            newEnvStr = RTStrDup (Utf8Str (aEnvironment));
3789
 
            AssertPtrBreakStmt (newEnvStr, vrc = vrc2);
 
4627
            newEnvStr = RTStrDup(Utf8Str(aEnvironment).c_str());
 
4628
            AssertPtrBreakStmt(newEnvStr, vrc = vrc2);
3790
4629
 
3791
4630
            /* put new variables to the environment
3792
4631
             * (ignore empty variable names here since RTEnv API
3793
4632
             * intentionally doesn't do that) */
3794
4633
            char *var = newEnvStr;
3795
 
            for (char *p = newEnvStr; *p; ++ p)
 
4634
            for (char *p = newEnvStr; *p; ++p)
3796
4635
            {
3797
4636
                if (*p == '\n' && (p == newEnvStr || *(p - 1) != '\\'))
3798
4637
                {
3807
4646
                        }
3808
4647
                        else
3809
4648
                            vrc2 = RTEnvUnsetEx (env, var);
3810
 
                        if (RT_FAILURE (vrc2))
 
4649
                        if (RT_FAILURE(vrc2))
3811
4650
                            break;
3812
4651
                    }
3813
4652
                    var = p + 1;
3814
4653
                }
3815
4654
            }
3816
 
            if (RT_SUCCESS (vrc2) && *var)
 
4655
            if (RT_SUCCESS(vrc2) && *var)
3817
4656
                vrc2 = RTEnvPutEx (env, var);
3818
4657
 
3819
4658
            AssertRCBreakStmt (vrc2, vrc = vrc2);
3821
4660
        while (0);
3822
4661
 
3823
4662
        if (newEnvStr != NULL)
3824
 
            RTStrFree (newEnvStr);
 
4663
            RTStrFree(newEnvStr);
3825
4664
    }
3826
4665
 
3827
 
    Bstr type (aType);
 
4666
    Utf8Str strType(aType);
3828
4667
 
3829
4668
    /* Qt is default */
3830
4669
#ifdef VBOX_WITH_QTGUI
3831
 
    if (type == "gui" || type == "GUI/Qt")
 
4670
    if (strType == "gui" || strType == "GUI/Qt")
3832
4671
    {
3833
4672
# ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
3834
4673
        const char VirtualBox_exe[] = "../Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM";
3840
4679
 
3841
4680
        Utf8Str idStr = mData->mUuid.toString();
3842
4681
# ifdef RT_OS_WINDOWS /** @todo drop this once the RTProcCreate bug has been fixed */
3843
 
        const char * args[] = {path, "--startvm", idStr, 0 };
 
4682
        const char * args[] = {szPath, "--startvm", idStr.c_str(), 0 };
3844
4683
# else
3845
 
        Utf8Str name = mUserData->mName;
3846
 
        const char * args[] = {path, "--comment", name, "--startvm", idStr, 0 };
 
4684
        Utf8Str strName = mUserData->mName;
 
4685
        const char * args[] = {szPath, "--comment", strName.c_str(), "--startvm", idStr.c_str(), 0 };
3847
4686
# endif
3848
 
        vrc = RTProcCreate (path, args, env, 0, &pid);
 
4687
        vrc = RTProcCreate(szPath, args, env, 0, &pid);
3849
4688
    }
3850
4689
#else /* !VBOX_WITH_QTGUI */
3851
4690
    if (0)
3855
4694
    else
3856
4695
 
3857
4696
#ifdef VBOX_WITH_VBOXSDL
3858
 
    if (type == "sdl" || type == "GUI/SDL")
 
4697
    if (strType == "sdl" || strType == "GUI/SDL")
3859
4698
    {
3860
4699
        const char VBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
3861
4700
        Assert (sz >= sizeof (VBoxSDL_exe));
3863
4702
 
3864
4703
        Utf8Str idStr = mData->mUuid.toString();
3865
4704
# ifdef RT_OS_WINDOWS
3866
 
        const char * args[] = {path, "--startvm", idStr, 0 };
 
4705
        const char * args[] = {szPath, "--startvm", idStr.c_str(), 0 };
3867
4706
# else
3868
 
        Utf8Str name = mUserData->mName;
3869
 
        const char * args[] = {path, "--comment", name, "--startvm", idStr, 0 };
 
4707
        Utf8Str strName = mUserData->mName;
 
4708
        const char * args[] = {szPath, "--comment", strName.c_str(), "--startvm", idStr.c_str(), 0 };
3870
4709
# endif
3871
 
        vrc = RTProcCreate (path, args, env, 0, &pid);
 
4710
        vrc = RTProcCreate(szPath, args, env, 0, &pid);
3872
4711
    }
3873
4712
#else /* !VBOX_WITH_VBOXSDL */
3874
4713
    if (0)
3878
4717
    else
3879
4718
 
3880
4719
#ifdef VBOX_WITH_HEADLESS
3881
 
    if (   type == "headless"
3882
 
        || type == "capture"
 
4720
    if (   strType == "headless"
 
4721
        || strType == "capture"
3883
4722
#ifdef VBOX_WITH_VRDP
3884
 
        || type == "vrdp"
 
4723
        || strType == "vrdp"
3885
4724
#endif
3886
4725
       )
3887
4726
    {
3892
4731
        Utf8Str idStr = mData->mUuid.toString();
3893
4732
        /* Leave space for 2 args, as "headless" needs --vrdp off on non-OSE. */
3894
4733
# ifdef RT_OS_WINDOWS
3895
 
        const char * args[] = {path, "--startvm", idStr, 0, 0, 0 };
 
4734
        const char * args[] = {szPath, "--startvm", idStr.c_str(), 0, 0, 0 };
3896
4735
# else
3897
 
        Utf8Str name = mUserData->mName;
3898
 
        const char * args[] = {path, "--comment", name, "--startvm", idStr, 0, 0, 0 };
 
4736
        Utf8Str strName = mUserData->mName;
 
4737
        const char * args[] ={szPath, "--comment", strName.c_str(), "--startvm", idStr.c_str(), 0, 0, 0 };
3899
4738
# endif
3900
4739
#ifdef VBOX_WITH_VRDP
3901
 
        if (type == "headless")
 
4740
        if (strType == "headless")
3902
4741
        {
3903
4742
            unsigned pos = RT_ELEMENTS(args) - 3;
3904
4743
            args[pos++] = "--vrdp";
3905
4744
            args[pos] = "off";
3906
4745
        }
3907
4746
#endif
3908
 
        if (type == "capture")
 
4747
        if (strType == "capture")
3909
4748
        {
3910
4749
            unsigned pos = RT_ELEMENTS(args) - 3;
3911
4750
            args[pos] = "--capture";
3912
4751
        }
3913
 
        vrc = RTProcCreate (path, args, env, 0, &pid);
 
4752
        vrc = RTProcCreate(szPath, args, env, 0, &pid);
3914
4753
    }
3915
4754
#else /* !VBOX_WITH_HEADLESS */
3916
4755
    if (0)
3919
4758
    else
3920
4759
    {
3921
4760
        RTEnvDestroy (env);
3922
 
        return setError (E_INVALIDARG,
3923
 
            tr ("Invalid session type: '%ls'"), aType);
 
4761
        return setError(E_INVALIDARG,
 
4762
                        tr("Invalid session type: '%s'"),
 
4763
                        strType.c_str());
3924
4764
    }
3925
4765
 
3926
4766
    RTEnvDestroy (env);
3927
4767
 
3928
 
    if (RT_FAILURE (vrc))
3929
 
        return setError (VBOX_E_IPRT_ERROR,
3930
 
            tr ("Could not launch a process for the machine '%ls' (%Rrc)"),
3931
 
            mUserData->mName.raw(), vrc);
 
4768
    if (RT_FAILURE(vrc))
 
4769
        return setError(VBOX_E_IPRT_ERROR,
 
4770
                        tr("Could not launch a process for the machine '%ls' (%Rrc)"),
 
4771
                        mUserData->mName.raw(), vrc);
3932
4772
 
3933
 
    LogFlowThisFunc (("launched.pid=%d(0x%x)\n", pid, pid));
 
4773
    LogFlowThisFunc(("launched.pid=%d(0x%x)\n", pid, pid));
3934
4774
 
3935
4775
    /*
3936
4776
     *  Note that we don't leave the lock here before calling the client,
3942
4782
     */
3943
4783
 
3944
4784
    /* inform the session that it will be a remote one */
3945
 
    LogFlowThisFunc (("Calling AssignMachine (NULL)...\n"));
 
4785
    LogFlowThisFunc(("Calling AssignMachine (NULL)...\n"));
3946
4786
    HRESULT rc = aControl->AssignMachine (NULL);
3947
 
    LogFlowThisFunc (("AssignMachine (NULL) returned %08X\n", rc));
 
4787
    LogFlowThisFunc(("AssignMachine (NULL) returned %08X\n", rc));
3948
4788
 
3949
 
    if (FAILED (rc))
 
4789
    if (FAILED(rc))
3950
4790
    {
3951
4791
        /* restore the session state */
3952
4792
        mData->mSession.mState = SessionState_Closed;
3953
4793
        /* The failure may occur w/o any error info (from RPC), so provide one */
3954
 
        return setError (VBOX_E_VM_ERROR,
3955
 
            tr ("Failed to assign the machine to the session (%Rrc)"), rc);
 
4794
        return setError(VBOX_E_VM_ERROR,
 
4795
                        tr("Failed to assign the machine to the session (%Rrc)"), rc);
3956
4796
    }
3957
4797
 
3958
4798
    /* attach launch data to the machine */
3961
4801
    mData->mSession.mProgress = aProgress;
3962
4802
    mData->mSession.mPid = pid;
3963
4803
    mData->mSession.mState = SessionState_Spawning;
3964
 
    mData->mSession.mType = type;
 
4804
    mData->mSession.mType = strType;
3965
4805
 
3966
4806
    LogFlowThisFuncLeave();
3967
4807
    return S_OK;
3975
4815
{
3976
4816
    LogFlowThisFuncEnter();
3977
4817
 
3978
 
    AssertReturn (aControl, E_FAIL);
3979
 
 
3980
 
    AutoCaller autoCaller (this);
3981
 
    CheckComRCReturnRC (autoCaller.rc());
3982
 
 
3983
 
    AutoWriteLock alock (this);
 
4818
    AssertReturn(aControl, E_FAIL);
 
4819
 
 
4820
    AutoCaller autoCaller(this);
 
4821
    CheckComRCReturnRC(autoCaller.rc());
 
4822
 
 
4823
    AutoWriteLock alock(this);
3984
4824
 
3985
4825
    if (!mData->mRegistered)
3986
4826
        return setError (E_UNEXPECTED,
3987
4827
            tr ("The machine '%ls' is not registered"), mUserData->mName.raw());
3988
4828
 
3989
 
    LogFlowThisFunc (("mSession.state=%d\n", mData->mSession.mState));
 
4829
    LogFlowThisFunc(("mSession.state=%s\n", Global::stringifySessionState(mData->mSession.mState)));
3990
4830
 
3991
4831
    if (mData->mSession.mState != SessionState_Open)
3992
4832
        return setError (VBOX_E_INVALID_SESSION_STATE,
3999
4839
     *  Get the console from the direct session (note that we don't leave the
4000
4840
     *  lock here because GetRemoteConsole must not call us back).
4001
4841
     */
4002
 
    ComPtr <IConsole> console;
 
4842
    ComPtr<IConsole> console;
4003
4843
    HRESULT rc = mData->mSession.mDirectControl->
4004
4844
                     GetRemoteConsole (console.asOutParam());
4005
4845
    if (FAILED (rc))
4011
4851
 
4012
4852
    ComAssertRet (!console.isNull(), E_FAIL);
4013
4853
 
4014
 
    ComObjPtr <SessionMachine> sessionMachine = mData->mSession.mMachine;
4015
 
    AssertReturn (!sessionMachine.isNull(), E_FAIL);
 
4854
    ComObjPtr<SessionMachine> sessionMachine = mData->mSession.mMachine;
 
4855
    AssertReturn(!sessionMachine.isNull(), E_FAIL);
4016
4856
 
4017
4857
    /*
4018
4858
     *  Leave the lock before calling the client process. It's safe here
4023
4863
    alock.leave();
4024
4864
 
4025
4865
    /* attach the remote session to the machine */
4026
 
    LogFlowThisFunc (("Calling AssignRemoteMachine()...\n"));
 
4866
    LogFlowThisFunc(("Calling AssignRemoteMachine()...\n"));
4027
4867
    rc = aControl->AssignRemoteMachine (sessionMachine, console);
4028
 
    LogFlowThisFunc (("AssignRemoteMachine() returned %08X\n", rc));
 
4868
    LogFlowThisFunc(("AssignRemoteMachine() returned %08X\n", rc));
4029
4869
 
4030
4870
    /* The failure may occur w/o any error info (from RPC), so provide one */
4031
 
    if (FAILED (rc))
4032
 
        return setError (VBOX_E_VM_ERROR,
4033
 
            tr ("Failed to assign the machine to the session (%Rrc)"), rc);
 
4871
    if (FAILED(rc))
 
4872
        return setError(VBOX_E_VM_ERROR,
 
4873
                        tr("Failed to assign the machine to the session (%Rrc)"),
 
4874
                        rc);
4034
4875
 
4035
4876
    alock.enter();
4036
4877
 
4039
4880
    {
4040
4881
        aControl->Uninitialize();
4041
4882
 
4042
 
        return setError (VBOX_E_INVALID_SESSION_STATE,
4043
 
            tr ("The machine '%ls' does not have an open session"),
4044
 
            mUserData->mName.raw());
 
4883
        return setError(VBOX_E_INVALID_SESSION_STATE,
 
4884
                        tr("The machine '%ls' does not have an open session"),
 
4885
                        mUserData->mName.raw());
4045
4886
    }
4046
4887
 
4047
4888
    /* store the control in the list */
4065
4906
 * @note locks this object for reading.
4066
4907
 */
4067
4908
#if defined (RT_OS_WINDOWS)
4068
 
bool Machine::isSessionOpen (ComObjPtr <SessionMachine> &aMachine,
4069
 
                             ComPtr <IInternalSessionControl> *aControl /*= NULL*/,
 
4909
bool Machine::isSessionOpen (ComObjPtr<SessionMachine> &aMachine,
 
4910
                             ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
4070
4911
                             HANDLE *aIPCSem /*= NULL*/,
4071
4912
                             bool aAllowClosing /*= false*/)
4072
4913
#elif defined (RT_OS_OS2)
4073
 
bool Machine::isSessionOpen (ComObjPtr <SessionMachine> &aMachine,
4074
 
                             ComPtr <IInternalSessionControl> *aControl /*= NULL*/,
 
4914
bool Machine::isSessionOpen (ComObjPtr<SessionMachine> &aMachine,
 
4915
                             ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
4075
4916
                             HMTX *aIPCSem /*= NULL*/,
4076
4917
                             bool aAllowClosing /*= false*/)
4077
4918
#else
4078
 
bool Machine::isSessionOpen (ComObjPtr <SessionMachine> &aMachine,
4079
 
                             ComPtr <IInternalSessionControl> *aControl /*= NULL*/,
 
4919
bool Machine::isSessionOpen (ComObjPtr<SessionMachine> &aMachine,
 
4920
                             ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
4080
4921
                             bool aAllowClosing /*= false*/)
4081
4922
#endif
4082
4923
{
4083
 
    AutoLimitedCaller autoCaller (this);
 
4924
    AutoLimitedCaller autoCaller(this);
4084
4925
    AssertComRCReturn (autoCaller.rc(), false);
4085
4926
 
4086
4927
    /* just return false for inaccessible machines */
4087
4928
    if (autoCaller.state() != Ready)
4088
4929
        return false;
4089
4930
 
4090
 
    AutoReadLock alock (this);
 
4931
    AutoReadLock alock(this);
4091
4932
 
4092
4933
    if (mData->mSession.mState == SessionState_Open ||
4093
4934
        (aAllowClosing && mData->mSession.mState == SessionState_Closing))
4094
4935
    {
4095
 
        AssertReturn (!mData->mSession.mMachine.isNull(), false);
 
4936
        AssertReturn(!mData->mSession.mMachine.isNull(), false);
4096
4937
 
4097
4938
        aMachine = mData->mSession.mMachine;
4098
4939
 
4126
4967
bool Machine::isSessionSpawning()
4127
4968
#endif
4128
4969
{
4129
 
    AutoLimitedCaller autoCaller (this);
 
4970
    AutoLimitedCaller autoCaller(this);
4130
4971
    AssertComRCReturn (autoCaller.rc(), false);
4131
4972
 
4132
4973
    /* just return false for inaccessible machines */
4133
4974
    if (autoCaller.state() != Ready)
4134
4975
        return false;
4135
4976
 
4136
 
    AutoReadLock alock (this);
 
4977
    AutoReadLock alock(this);
4137
4978
 
4138
4979
    if (mData->mSession.mState == SessionState_Spawning)
4139
4980
    {
4141
4982
        /* Additional session data */
4142
4983
        if (aPID != NULL)
4143
4984
        {
4144
 
            AssertReturn (mData->mSession.mPid != NIL_RTPROCESS, false);
 
4985
            AssertReturn(mData->mSession.mPid != NIL_RTPROCESS, false);
4145
4986
            *aPID = mData->mSession.mPid;
4146
4987
        }
4147
4988
#endif
4167
5008
 */
4168
5009
bool Machine::checkForSpawnFailure()
4169
5010
{
4170
 
    AutoCaller autoCaller (this);
 
5011
    AutoCaller autoCaller(this);
4171
5012
    if (!autoCaller.isOk())
4172
5013
    {
4173
5014
        /* nothing to do */
4174
 
        LogFlowThisFunc (("Already uninitialized!"));
 
5015
        LogFlowThisFunc(("Already uninitialized!\n"));
4175
5016
        return true;
4176
5017
    }
4177
5018
 
4178
5019
    /* VirtualBox::addProcessToReap() needs a write lock */
4179
 
    AutoMultiWriteLock2 alock (mParent, this);
 
5020
    AutoMultiWriteLock2 alock(mParent, this);
4180
5021
 
4181
5022
    if (mData->mSession.mState != SessionState_Spawning)
4182
5023
    {
4183
5024
        /* nothing to do */
4184
 
        LogFlowThisFunc (("Not spawning any more!"));
 
5025
        LogFlowThisFunc(("Not spawning any more!\n"));
4185
5026
        return true;
4186
5027
    }
4187
5028
 
4188
5029
    HRESULT rc = S_OK;
4189
5030
 
4190
 
#if defined (RT_OS_WINDOWS) || defined (RT_OS_OS2)
 
5031
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
4191
5032
 
4192
5033
    /* the process was already unexpectedly terminated, we just need to set an
4193
5034
     * error and finalize session spawning */
4194
 
    rc = setError (E_FAIL,
4195
 
                   tr ("Virtual machine '%ls' has terminated unexpectedly "
4196
 
                       "during startup"),
4197
 
                   name().raw());
 
5035
    rc = setError(E_FAIL,
 
5036
                  tr("Virtual machine '%ls' has terminated unexpectedly during startup"),
 
5037
                  getName().raw());
4198
5038
#else
4199
5039
 
 
5040
    /* PID not yet initialized, skip check. */
 
5041
    if (mData->mSession.mPid == NIL_RTPROCESS)
 
5042
        return false;
 
5043
 
4200
5044
    RTPROCSTATUS status;
4201
 
    int vrc = ::RTProcWait (mData->mSession.mPid, RTPROCWAIT_FLAGS_NOBLOCK,
4202
 
                            &status);
 
5045
    int vrc = ::RTProcWait(mData->mSession.mPid, RTPROCWAIT_FLAGS_NOBLOCK,
 
5046
                           &status);
4203
5047
 
4204
5048
    if (vrc != VERR_PROCESS_RUNNING)
4205
 
        rc = setError (E_FAIL,
4206
 
                       tr ("Virtual machine '%ls' has terminated unexpectedly "
4207
 
                           "during startup"),
4208
 
                       name().raw());
 
5049
        rc = setError(E_FAIL,
 
5050
                      tr("Virtual machine '%ls' has terminated unexpectedly during startup"),
 
5051
                      getName().raw());
4209
5052
#endif
4210
5053
 
4211
 
    if (FAILED (rc))
 
5054
    if (FAILED(rc))
4212
5055
    {
4213
5056
        /* Close the remote session, remove the remote control from the list
4214
5057
         * and reset session state to Closed (@note keep the code in sync with
4215
5058
         * the relevant part in checkForSpawnFailure()). */
4216
5059
 
4217
 
        Assert (mData->mSession.mRemoteControls.size() == 1);
 
5060
        Assert(mData->mSession.mRemoteControls.size() == 1);
4218
5061
        if (mData->mSession.mRemoteControls.size() == 1)
4219
5062
        {
4220
5063
            ErrorInfoKeeper eik;
4225
5068
        mData->mSession.mState = SessionState_Closed;
4226
5069
 
4227
5070
        /* finalize the progress after setting the state, for consistency */
4228
 
        mData->mSession.mProgress->notifyComplete (rc);
4229
 
        mData->mSession.mProgress.setNull();
 
5071
        if (!mData->mSession.mProgress.isNull())
 
5072
        {
 
5073
            mData->mSession.mProgress->notifyComplete(rc);
 
5074
            mData->mSession.mProgress.setNull();
 
5075
        }
4230
5076
 
4231
 
        mParent->addProcessToReap (mData->mSession.mPid);
 
5077
        mParent->addProcessToReap(mData->mSession.mPid);
4232
5078
        mData->mSession.mPid = NIL_RTPROCESS;
4233
5079
 
4234
 
        mParent->onSessionStateChange (mData->mUuid, SessionState_Closed);
 
5080
        mParent->onSessionStateChange(mData->mUuid, SessionState_Closed);
4235
5081
        return true;
4236
5082
    }
4237
5083
 
4254
5100
 */
4255
5101
HRESULT Machine::trySetRegistered (BOOL aRegistered)
4256
5102
{
4257
 
    AssertReturn (mParent->isWriteLockOnCurrentThread(), E_FAIL);
4258
 
 
4259
 
    AutoLimitedCaller autoCaller (this);
4260
 
    AssertComRCReturnRC (autoCaller.rc());
4261
 
 
4262
 
    AutoWriteLock alock (this);
 
5103
    AssertReturn(mParent->isWriteLockOnCurrentThread(), E_FAIL);
 
5104
 
 
5105
    AutoLimitedCaller autoCaller(this);
 
5106
    AssertComRCReturnRC(autoCaller.rc());
 
5107
 
 
5108
    AutoWriteLock alock(this);
4263
5109
 
4264
5110
    /* wait for state dependants to drop to zero */
4265
5111
    ensureNoStateDependencies();
4271
5117
        /* A special case: the machine is not accessible. */
4272
5118
 
4273
5119
        /* inaccessible machines can only be unregistered */
4274
 
        AssertReturn (!aRegistered, E_FAIL);
 
5120
        AssertReturn(!aRegistered, E_FAIL);
4275
5121
 
4276
5122
        /* Uninitialize ourselves here because currently there may be no
4277
5123
         * unregistered that are inaccessible (this state combination is not
4286
5132
        return S_OK;
4287
5133
    }
4288
5134
 
4289
 
    AssertReturn (autoCaller.state() == Ready, E_FAIL);
4290
 
 
4291
 
    /* we will probably modify these and want to prevent concurrent
4292
 
     * modifications until we finish */
4293
 
    AutoWriteLock dvdLock (mDVDDrive);
4294
 
    AutoWriteLock floppyLock (mFloppyDrive);
 
5135
    AssertReturn(autoCaller.state() == Ready, E_FAIL);
4295
5136
 
4296
5137
    if (aRegistered)
4297
5138
    {
4298
5139
        if (mData->mRegistered)
4299
 
            return setError (VBOX_E_INVALID_OBJECT_STATE,
4300
 
                tr ("The machine '%ls' with UUID {%s} is already registered"),
4301
 
                mUserData->mName.raw(),
4302
 
                mData->mUuid.toString().raw());
 
5140
            return setError(VBOX_E_INVALID_OBJECT_STATE,
 
5141
                            tr("The machine '%ls' with UUID {%s} is already registered"),
 
5142
                            mUserData->mName.raw(),
 
5143
                            mData->mUuid.toString().raw());
4303
5144
    }
4304
5145
    else
4305
5146
    {
4306
5147
        if (mData->mMachineState == MachineState_Saved)
4307
 
            return setError (VBOX_E_INVALID_VM_STATE,
4308
 
                tr ("Cannot unregister the machine '%ls' because it "
4309
 
                    "is in the Saved state"),
4310
 
                mUserData->mName.raw());
 
5148
            return setError(VBOX_E_INVALID_VM_STATE,
 
5149
                            tr("Cannot unregister the machine '%ls' because it is in the Saved state"),
 
5150
                            mUserData->mName.raw());
4311
5151
 
4312
5152
        size_t snapshotCount = 0;
4313
5153
        if (mData->mFirstSnapshot)
4314
 
            snapshotCount = mData->mFirstSnapshot->descendantCount() + 1;
 
5154
            snapshotCount = mData->mFirstSnapshot->getAllChildrenCount() + 1;
4315
5155
        if (snapshotCount)
4316
 
            return setError (VBOX_E_INVALID_OBJECT_STATE,
4317
 
                tr ("Cannot unregister the machine '%ls' because it "
4318
 
                    "has %d snapshots"),
4319
 
                mUserData->mName.raw(), snapshotCount);
 
5156
            return setError(VBOX_E_INVALID_OBJECT_STATE,
 
5157
                            tr("Cannot unregister the machine '%ls' because it has %d snapshots"),
 
5158
                            mUserData->mName.raw(), snapshotCount);
4320
5159
 
4321
5160
        if (mData->mSession.mState != SessionState_Closed)
4322
 
            return setError (VBOX_E_INVALID_OBJECT_STATE,
4323
 
                tr ("Cannot unregister the machine '%ls' because it has an "
4324
 
                    "open session"),
4325
 
                mUserData->mName.raw());
 
5161
            return setError(VBOX_E_INVALID_OBJECT_STATE,
 
5162
                            tr("Cannot unregister the machine '%ls' because it has an open session"),
 
5163
                            mUserData->mName.raw());
4326
5164
 
4327
 
        if (mHDData->mAttachments.size() != 0)
4328
 
            return setError (VBOX_E_INVALID_OBJECT_STATE,
4329
 
                tr ("Cannot unregister the machine '%ls' because it "
4330
 
                    "has %d hard disks attached"),
4331
 
                mUserData->mName.raw(), mHDData->mAttachments.size());
 
5165
        if (mMediaData->mAttachments.size() != 0)
 
5166
            return setError(VBOX_E_INVALID_OBJECT_STATE,
 
5167
                            tr("Cannot unregister the machine '%ls' because it has %d medium attachments"),
 
5168
                            mUserData->mName.raw(),
 
5169
                            mMediaData->mAttachments.size());
4332
5170
 
4333
5171
        /* Note that we do not prevent unregistration of a DVD or Floppy image
4334
5172
         * is attached: as opposed to hard disks detaching such an image
4341
5179
    /* Ensure the settings are saved. If we are going to be registered and
4342
5180
     * isConfigLocked() is FALSE then it means that no config file exists yet,
4343
5181
     * so create it by calling saveSettings() too. */
4344
 
    if (isModified() || (aRegistered && !isConfigLocked()))
 
5182
    if (    isModified()
 
5183
         || (aRegistered && !mData->m_pMachineConfigFile->fileExists())
 
5184
       )
4345
5185
    {
4346
5186
        rc = saveSettings();
4347
 
        CheckComRCReturnRC (rc);
 
5187
        CheckComRCReturnRC(rc);
4348
5188
    }
4349
5189
 
4350
 
    /* Implicitly detach DVD/Floppy */
4351
 
    rc = mDVDDrive->unmount();
4352
 
    if (SUCCEEDED (rc))
4353
 
        rc = mFloppyDrive->unmount();
 
5190
    /* more config checking goes here */
4354
5191
 
4355
 
    if (SUCCEEDED (rc))
 
5192
    if (SUCCEEDED(rc))
4356
5193
    {
4357
5194
        /* we may have had implicit modifications we want to fix on success */
4358
5195
        commit();
4391
5228
                                     MachineState_T *aState /* = NULL */,
4392
5229
                                     BOOL *aRegistered /* = NULL */)
4393
5230
{
4394
 
    AutoCaller autoCaller (this);
4395
 
    AssertComRCReturnRC (autoCaller.rc());
4396
 
 
4397
 
    AutoWriteLock alock (this);
4398
 
 
4399
 
    HRESULT rc = checkStateDependency (aDepType);
4400
 
    CheckComRCReturnRC (rc);
 
5231
    AutoCaller autoCaller(this);
 
5232
    AssertComRCReturnRC(autoCaller.rc());
 
5233
 
 
5234
    AutoWriteLock alock(this);
 
5235
 
 
5236
    HRESULT rc = checkStateDependency(aDepType);
 
5237
    CheckComRCReturnRC(rc);
4401
5238
 
4402
5239
    {
4403
5240
        if (mData->mMachineStateChangePending != 0)
4410
5247
 
4411
5248
            AssertFailed();
4412
5249
 
4413
 
            return setError (E_ACCESSDENIED,
4414
 
                tr ("Machine state change is in progress. "
4415
 
                    "Please retry the operation later."));
 
5250
            return setError(E_ACCESSDENIED,
 
5251
                            tr("Machine state change is in progress. Please retry the operation later."));
4416
5252
        }
4417
5253
 
4418
 
        ++ mData->mMachineStateDeps;
 
5254
        ++mData->mMachineStateDeps;
4419
5255
        Assert (mData->mMachineStateDeps != 0 /* overflow */);
4420
5256
    }
4421
5257
 
4434
5270
 */
4435
5271
void Machine::releaseStateDependency()
4436
5272
{
4437
 
    AutoCaller autoCaller (this);
 
5273
    AutoCaller autoCaller(this);
4438
5274
    AssertComRCReturnVoid (autoCaller.rc());
4439
5275
 
4440
 
    AutoWriteLock alock (this);
 
5276
    AutoWriteLock alock(this);
4441
5277
 
4442
5278
    AssertReturnVoid (mData->mMachineStateDeps != 0
4443
5279
                      /* releaseStateDependency() w/o addStateDependency()? */);
4485
5321
 *  @note This method must be called from under this object's read or write
4486
5322
 *        lock.
4487
5323
 */
4488
 
HRESULT Machine::checkStateDependency (StateDependency aDepType)
 
5324
HRESULT Machine::checkStateDependency(StateDependency aDepType)
4489
5325
{
4490
5326
    switch (aDepType)
4491
5327
    {
4495
5331
        }
4496
5332
        case MutableStateDep:
4497
5333
        {
4498
 
            if (mData->mRegistered &&
4499
 
                (mType != IsSessionMachine ||
4500
 
                 mData->mMachineState > MachineState_Paused ||
4501
 
                 mData->mMachineState == MachineState_Saved))
4502
 
                return setError (VBOX_E_INVALID_VM_STATE,
4503
 
                    tr ("The machine is not mutable (state is %d)"),
4504
 
                    mData->mMachineState);
 
5334
            if (   mData->mRegistered
 
5335
                && (   mType != IsSessionMachine  /** @todo This was just convered raw; Check if Running and Paused should actually be included here... (Live Migration) */
 
5336
                    || (   mData->mMachineState != MachineState_Paused
 
5337
                        && mData->mMachineState != MachineState_Running
 
5338
                        && mData->mMachineState != MachineState_Aborted
 
5339
                        && mData->mMachineState != MachineState_Teleported
 
5340
                        && mData->mMachineState != MachineState_PoweredOff
 
5341
                       )
 
5342
                   )
 
5343
               )
 
5344
                return setError(VBOX_E_INVALID_VM_STATE,
 
5345
                                tr("The machine is not mutable (state is %s)"),
 
5346
                                Global::stringifyMachineState(mData->mMachineState));
4505
5347
            break;
4506
5348
        }
4507
5349
        case MutableOrSavedStateDep:
4508
5350
        {
4509
 
            if (mData->mRegistered &&
4510
 
                (mType != IsSessionMachine ||
4511
 
                 mData->mMachineState > MachineState_Paused))
4512
 
                return setError (VBOX_E_INVALID_VM_STATE,
4513
 
                    tr ("The machine is not mutable (state is %d)"),
4514
 
                    mData->mMachineState);
 
5351
            if (   mData->mRegistered
 
5352
                && (   mType != IsSessionMachine  /** @todo This was just convered raw; Check if Running and Paused should actually be included here... (Live Migration) */
 
5353
                    || (   mData->mMachineState != MachineState_Paused
 
5354
                        && mData->mMachineState != MachineState_Running
 
5355
                        && mData->mMachineState != MachineState_Aborted
 
5356
                        && mData->mMachineState != MachineState_Teleported
 
5357
                        && mData->mMachineState != MachineState_Saved
 
5358
                        && mData->mMachineState != MachineState_PoweredOff
 
5359
                       )
 
5360
                   )
 
5361
               )
 
5362
                return setError(VBOX_E_INVALID_VM_STATE,
 
5363
                                tr("The machine is not mutable (state is %s)"),
 
5364
                                Global::stringifyMachineState(mData->mMachineState));
4515
5365
            break;
4516
5366
        }
4517
5367
    }
4530
5380
 */
4531
5381
HRESULT Machine::initDataAndChildObjects()
4532
5382
{
4533
 
    AutoCaller autoCaller (this);
4534
 
    AssertComRCReturnRC (autoCaller.rc());
 
5383
    AutoCaller autoCaller(this);
 
5384
    AssertComRCReturnRC(autoCaller.rc());
4535
5385
    AssertComRCReturn (autoCaller.state() == InInit ||
4536
5386
                       autoCaller.state() == Limited, E_FAIL);
4537
5387
 
4538
 
    AssertReturn (!mData->mAccessible, E_FAIL);
 
5388
    AssertReturn(!mData->mAccessible, E_FAIL);
4539
5389
 
4540
5390
    /* allocate data structures */
4541
5391
    mSSData.allocate();
4542
5392
    mUserData.allocate();
4543
5393
    mHWData.allocate();
4544
 
    mHDData.allocate();
 
5394
    mMediaData.allocate();
4545
5395
    mStorageControllers.allocate();
4546
5396
 
4547
5397
    /* initialize mOSTypeId */
4548
5398
    mUserData->mOSTypeId = mParent->getUnknownOSType()->id();
4549
5399
 
4550
5400
    /* create associated BIOS settings object */
4551
 
    unconst (mBIOSSettings).createObject();
 
5401
    unconst(mBIOSSettings).createObject();
4552
5402
    mBIOSSettings->init (this);
4553
5403
 
4554
5404
#ifdef VBOX_WITH_VRDP
4555
5405
    /* create an associated VRDPServer object (default is disabled) */
4556
 
    unconst (mVRDPServer).createObject();
 
5406
    unconst(mVRDPServer).createObject();
4557
5407
    mVRDPServer->init (this);
4558
5408
#endif
4559
5409
 
4560
 
    /* create an associated DVD drive object */
4561
 
    unconst (mDVDDrive).createObject();
4562
 
    mDVDDrive->init (this);
4563
 
 
4564
 
    /* create an associated floppy drive object */
4565
 
    unconst (mFloppyDrive).createObject();
4566
 
    mFloppyDrive->init (this);
4567
 
 
4568
5410
    /* create associated serial port objects */
4569
5411
    for (ULONG slot = 0; slot < RT_ELEMENTS (mSerialPorts); slot ++)
4570
5412
    {
4571
 
        unconst (mSerialPorts [slot]).createObject();
 
5413
        unconst(mSerialPorts [slot]).createObject();
4572
5414
        mSerialPorts [slot]->init (this, slot);
4573
5415
    }
4574
5416
 
4575
5417
    /* create associated parallel port objects */
4576
5418
    for (ULONG slot = 0; slot < RT_ELEMENTS (mParallelPorts); slot ++)
4577
5419
    {
4578
 
        unconst (mParallelPorts [slot]).createObject();
 
5420
        unconst(mParallelPorts [slot]).createObject();
4579
5421
        mParallelPorts [slot]->init (this, slot);
4580
5422
    }
4581
5423
 
4582
5424
    /* create the audio adapter object (always present, default is disabled) */
4583
 
    unconst (mAudioAdapter).createObject();
 
5425
    unconst(mAudioAdapter).createObject();
4584
5426
    mAudioAdapter->init (this);
4585
5427
 
4586
5428
    /* create the USB controller object (always present, default is disabled) */
4587
 
    unconst (mUSBController).createObject();
 
5429
    unconst(mUSBController).createObject();
4588
5430
    mUSBController->init (this);
4589
5431
 
4590
5432
    /* create associated network adapter objects */
4591
5433
    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); slot ++)
4592
5434
    {
4593
 
        unconst (mNetworkAdapters [slot]).createObject();
 
5435
        unconst(mNetworkAdapters [slot]).createObject();
4594
5436
        mNetworkAdapters [slot]->init (this, slot);
4595
5437
    }
4596
5438
 
4608
5450
 */
4609
5451
void Machine::uninitDataAndChildObjects()
4610
5452
{
4611
 
    AutoCaller autoCaller (this);
 
5453
    AutoCaller autoCaller(this);
4612
5454
    AssertComRCReturnVoid (autoCaller.rc());
4613
5455
    AssertComRCReturnVoid (autoCaller.state() == InUninit ||
4614
5456
                           autoCaller.state() == Limited);
4624
5466
        if (mNetworkAdapters [slot])
4625
5467
        {
4626
5468
            mNetworkAdapters [slot]->uninit();
4627
 
            unconst (mNetworkAdapters [slot]).setNull();
 
5469
            unconst(mNetworkAdapters [slot]).setNull();
4628
5470
        }
4629
5471
    }
4630
5472
 
4631
5473
    if (mUSBController)
4632
5474
    {
4633
5475
        mUSBController->uninit();
4634
 
        unconst (mUSBController).setNull();
 
5476
        unconst(mUSBController).setNull();
4635
5477
    }
4636
5478
 
4637
5479
    if (mAudioAdapter)
4638
5480
    {
4639
5481
        mAudioAdapter->uninit();
4640
 
        unconst (mAudioAdapter).setNull();
 
5482
        unconst(mAudioAdapter).setNull();
4641
5483
    }
4642
5484
 
4643
5485
    for (ULONG slot = 0; slot < RT_ELEMENTS (mParallelPorts); slot ++)
4645
5487
        if (mParallelPorts [slot])
4646
5488
        {
4647
5489
            mParallelPorts [slot]->uninit();
4648
 
            unconst (mParallelPorts [slot]).setNull();
 
5490
            unconst(mParallelPorts [slot]).setNull();
4649
5491
        }
4650
5492
    }
4651
5493
 
4654
5496
        if (mSerialPorts [slot])
4655
5497
        {
4656
5498
            mSerialPorts [slot]->uninit();
4657
 
            unconst (mSerialPorts [slot]).setNull();
 
5499
            unconst(mSerialPorts [slot]).setNull();
4658
5500
        }
4659
5501
    }
4660
5502
 
4661
 
    if (mFloppyDrive)
4662
 
    {
4663
 
        mFloppyDrive->uninit();
4664
 
        unconst (mFloppyDrive).setNull();
4665
 
    }
4666
 
 
4667
 
    if (mDVDDrive)
4668
 
    {
4669
 
        mDVDDrive->uninit();
4670
 
        unconst (mDVDDrive).setNull();
4671
 
    }
4672
 
 
4673
5503
#ifdef VBOX_WITH_VRDP
4674
5504
    if (mVRDPServer)
4675
5505
    {
4676
5506
        mVRDPServer->uninit();
4677
 
        unconst (mVRDPServer).setNull();
 
5507
        unconst(mVRDPServer).setNull();
4678
5508
    }
4679
5509
#endif
4680
5510
 
4681
5511
    if (mBIOSSettings)
4682
5512
    {
4683
5513
        mBIOSSettings->uninit();
4684
 
        unconst (mBIOSSettings).setNull();
 
5514
        unconst(mBIOSSettings).setNull();
4685
5515
    }
4686
5516
 
4687
5517
    /* Deassociate hard disks (only when a real Machine or a SnapshotMachine
4692
5522
     * a result of unregistering or discarding the snapshot), outdated hard
4693
5523
     * disk attachments will already be uninitialized and deleted, so this
4694
5524
     * code will not affect them. */
4695
 
    if (!!mHDData && (mType == IsMachine || mType == IsSnapshotMachine))
 
5525
    if (!!mMediaData && (mType == IsMachine || mType == IsSnapshotMachine))
4696
5526
    {
4697
 
        for (HDData::AttachmentList::const_iterator it =
4698
 
                 mHDData->mAttachments.begin();
4699
 
             it != mHDData->mAttachments.end();
4700
 
             ++ it)
 
5527
        for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
5528
             it != mMediaData->mAttachments.end();
 
5529
             ++it)
4701
5530
        {
4702
 
            HRESULT rc = (*it)->hardDisk()->detachFrom (mData->mUuid,
4703
 
                                                        snapshotId());
 
5531
            ComObjPtr<Medium> hd = (*it)->getMedium();
 
5532
            if (hd.isNull())
 
5533
                continue;
 
5534
            HRESULT rc = hd->detachFrom(mData->mUuid, getSnapshotId());
4704
5535
            AssertComRC (rc);
4705
5536
        }
4706
5537
    }
4714
5545
 
4715
5546
    /* free data structures (the essential mData structure is not freed here
4716
5547
     * since it may be still in use) */
4717
 
    mHDData.free();
 
5548
    mMediaData.free();
4718
5549
    mStorageControllers.free();
4719
5550
    mHWData.free();
4720
5551
    mUserData.free();
4738
5569
{
4739
5570
    AssertReturnVoid (isWriteLockOnCurrentThread());
4740
5571
 
4741
 
    AutoWriteLock alock (this);
 
5572
    AutoWriteLock alock(this);
4742
5573
 
4743
5574
    /* Wait for all state dependants if necessary */
4744
5575
    if (mData->mMachineStateDeps != 0)
4747
5578
        if (mData->mMachineStateDepsSem == NIL_RTSEMEVENTMULTI)
4748
5579
            RTSemEventMultiCreate (&mData->mMachineStateDepsSem);
4749
5580
 
4750
 
        LogFlowThisFunc (("Waiting for state deps (%d) to drop to zero...\n",
 
5581
        LogFlowThisFunc(("Waiting for state deps (%d) to drop to zero...\n",
4751
5582
                          mData->mMachineStateDeps));
4752
5583
 
4753
 
        ++ mData->mMachineStateChangePending;
 
5584
        ++mData->mMachineStateChangePending;
4754
5585
 
4755
5586
        /* reset the semaphore before waiting, the last dependant will signal
4756
5587
         * it */
4777
5608
HRESULT Machine::setMachineState (MachineState_T aMachineState)
4778
5609
{
4779
5610
    LogFlowThisFuncEnter();
4780
 
    LogFlowThisFunc (("aMachineState=%d\n", aMachineState));
 
5611
    LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) ));
4781
5612
 
4782
 
    AutoCaller autoCaller (this);
 
5613
    AutoCaller autoCaller(this);
4783
5614
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
4784
5615
 
4785
 
    AutoWriteLock alock (this);
 
5616
    AutoWriteLock alock(this);
4786
5617
 
4787
5618
    /* wait for state dependants to drop to zero */
4788
5619
    ensureNoStateDependencies();
4793
5624
 
4794
5625
        RTTimeNow (&mData->mLastStateChange);
4795
5626
 
4796
 
        mParent->onMachineStateChange (mData->mUuid, aMachineState);
 
5627
        mParent->onMachineStateChange(mData->mUuid, aMachineState);
4797
5628
    }
4798
5629
 
4799
5630
    LogFlowThisFuncLeave();
4815
5646
 *      must be called from under the object's lock!
4816
5647
 */
4817
5648
HRESULT Machine::findSharedFolder (CBSTR aName,
4818
 
                                   ComObjPtr <SharedFolder> &aSharedFolder,
 
5649
                                   ComObjPtr<SharedFolder> &aSharedFolder,
4819
5650
                                   bool aSetError /* = false */)
4820
5651
{
4821
5652
    bool found = false;
4822
5653
    for (HWData::SharedFolderList::const_iterator it = mHWData->mSharedFolders.begin();
4823
5654
        !found && it != mHWData->mSharedFolders.end();
4824
 
        ++ it)
 
5655
        ++it)
4825
5656
    {
4826
 
        AutoWriteLock alock (*it);
4827
 
        found = (*it)->name() == aName;
 
5657
        AutoWriteLock alock(*it);
 
5658
        found = (*it)->getName() == aName;
4828
5659
        if (found)
4829
5660
            aSharedFolder = *it;
4830
5661
    }
4832
5663
    HRESULT rc = found ? S_OK : VBOX_E_OBJECT_NOT_FOUND;
4833
5664
 
4834
5665
    if (aSetError && !found)
4835
 
        setError (rc, tr ("Could not find a shared folder named '%ls'"), aName);
 
5666
        setError(rc, tr("Could not find a shared folder named '%ls'"), aName);
4836
5667
 
4837
5668
    return rc;
4838
5669
}
4848
5679
 *
4849
5680
 *  @note Doesn't lock any objects.
4850
5681
 */
4851
 
HRESULT Machine::loadSettings (bool aRegistered)
 
5682
HRESULT Machine::loadSettings(bool aRegistered)
4852
5683
{
4853
5684
    LogFlowThisFuncEnter();
4854
 
    AssertReturn (mType == IsMachine, E_FAIL);
 
5685
    AssertReturn(mType == IsMachine, E_FAIL);
4855
5686
 
4856
 
    AutoCaller autoCaller (this);
4857
 
    AssertReturn (autoCaller.state() == InInit, E_FAIL);
 
5687
    AutoCaller autoCaller(this);
 
5688
    AssertReturn(autoCaller.state() == InInit, E_FAIL);
4858
5689
 
4859
5690
    HRESULT rc = S_OK;
4860
5691
 
4861
5692
    try
4862
5693
    {
4863
 
        using namespace settings;
4864
 
        using namespace xml;
4865
 
 
4866
 
        /* no concurrent file access is possible in init() so open by handle */
4867
 
        File file (mData->mHandleCfgFile, Utf8Str (mData->mConfigFileFull));
4868
 
        XmlTreeBackend tree;
4869
 
 
4870
 
        rc = VirtualBox::loadSettingsTree_FirstTime (tree, file,
4871
 
                                                     mData->mSettingsFileVersion);
4872
 
        CheckComRCThrowRC (rc);
4873
 
 
4874
 
        Key machineNode = tree.rootKey().key ("Machine");
4875
 
 
4876
 
        /* uuid (required) */
4877
 
        Guid id = machineNode.value <Guid> ("uuid");
 
5694
        Assert(mData->m_pMachineConfigFile == NULL);
 
5695
 
 
5696
        // load and parse machine XML; this will throw on XML or logic errors
 
5697
        mData->m_pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull);
4878
5698
 
4879
5699
        /* If the stored UUID is not empty, it means the registered machine
4880
5700
         * is being loaded. Compare the loaded UUID with the stored one taken
4881
5701
         * from the global registry. */
4882
5702
        if (!mData->mUuid.isEmpty())
4883
5703
        {
4884
 
            if (mData->mUuid != id)
 
5704
            if (mData->mUuid != mData->m_pMachineConfigFile->uuid)
4885
5705
            {
4886
 
                throw setError (E_FAIL,
4887
 
                    tr ("Machine UUID {%RTuuid} in '%ls' doesn't match its "
4888
 
                        "UUID {%s} in the registry file '%ls'"),
4889
 
                    id.raw(), mData->mConfigFileFull.raw(),
4890
 
                    mData->mUuid.toString().raw(),
4891
 
                    mParent->settingsFileName().raw());
 
5706
                throw setError(E_FAIL,
 
5707
                               tr("Machine UUID {%RTuuid} in '%s' doesn't match its UUID {%s} in the registry file '%s'"),
 
5708
                               mData->m_pMachineConfigFile->uuid.raw(),
 
5709
                               mData->m_strConfigFileFull.raw(),
 
5710
                               mData->mUuid.toString().raw(),
 
5711
                               mParent->settingsFilePath().raw());
4892
5712
            }
4893
5713
        }
4894
5714
        else
4895
 
            unconst (mData->mUuid) = id;
 
5715
            unconst (mData->mUuid) = mData->m_pMachineConfigFile->uuid;
4896
5716
 
4897
5717
        /* name (required) */
4898
 
        mUserData->mName = machineNode.stringValue ("name");
 
5718
        mUserData->mName = mData->m_pMachineConfigFile->strName;
4899
5719
 
4900
5720
        /* nameSync (optional, default is true) */
4901
 
        mUserData->mNameSync = machineNode.value <bool> ("nameSync");
4902
 
 
4903
 
        /* Description (optional, default is null) */
4904
 
        {
4905
 
            Key descNode = machineNode.findKey ("Description");
4906
 
            if (!descNode.isNull())
4907
 
                mUserData->mDescription = descNode.keyStringValue();
4908
 
            else
4909
 
                mUserData->mDescription.setNull();
4910
 
        }
4911
 
 
4912
 
        /* OSType (required) */
4913
 
        {
4914
 
            mUserData->mOSTypeId = machineNode.stringValue ("OSType");
4915
 
 
4916
 
            /* look up the object by Id to check it is valid */
4917
 
            ComPtr <IGuestOSType> guestOSType;
4918
 
            rc = mParent->GetGuestOSType (mUserData->mOSTypeId,
4919
 
                                          guestOSType.asOutParam());
4920
 
            CheckComRCThrowRC (rc);
4921
 
        }
4922
 
 
4923
 
        /* stateFile (optional) */
4924
 
        {
4925
 
            Bstr stateFilePath = machineNode.stringValue ("stateFile");
4926
 
            if (stateFilePath)
4927
 
            {
4928
 
                Utf8Str stateFilePathFull = stateFilePath;
4929
 
                int vrc = calculateFullPath (stateFilePathFull, stateFilePathFull);
4930
 
                if (RT_FAILURE (vrc))
4931
 
                {
4932
 
                    throw setError (E_FAIL,
4933
 
                        tr ("Invalid saved state file path '%ls' (%Rrc)"),
4934
 
                        stateFilePath.raw(), vrc);
4935
 
                }
4936
 
                mSSData->mStateFilePath = stateFilePathFull;
4937
 
            }
4938
 
            else
4939
 
                mSSData->mStateFilePath.setNull();
4940
 
        }
4941
 
 
4942
 
        /*
4943
 
         *  currentSnapshot ID (optional)
4944
 
         *
4945
 
         *  Note that due to XML Schema constaraints, this attribute, when
4946
 
         *  present, will guaranteedly refer to an existing snapshot
4947
 
         *  definition in XML
4948
 
         */
4949
 
        Guid currentSnapshotId = machineNode.valueOr <Guid> ("currentSnapshot",
4950
 
                                                             Guid());
 
5721
        mUserData->mNameSync = mData->m_pMachineConfigFile->fNameSync;
 
5722
 
 
5723
        mUserData->mDescription = mData->m_pMachineConfigFile->strDescription;
 
5724
 
 
5725
        // guest OS type
 
5726
        mUserData->mOSTypeId = mData->m_pMachineConfigFile->strOsType;
 
5727
        /* look up the object by Id to check it is valid */
 
5728
        ComPtr<IGuestOSType> guestOSType;
 
5729
        rc = mParent->GetGuestOSType(mUserData->mOSTypeId,
 
5730
                                     guestOSType.asOutParam());
 
5731
        CheckComRCThrowRC(rc);
 
5732
 
 
5733
        // stateFile (optional)
 
5734
        if (mData->m_pMachineConfigFile->strStateFile.isEmpty())
 
5735
            mSSData->mStateFilePath.setNull();
 
5736
        else
 
5737
        {
 
5738
            Utf8Str stateFilePathFull(mData->m_pMachineConfigFile->strStateFile);
 
5739
            int vrc = calculateFullPath(stateFilePathFull, stateFilePathFull);
 
5740
            if (RT_FAILURE(vrc))
 
5741
                throw setError(E_FAIL,
 
5742
                                tr("Invalid saved state file path '%s' (%Rrc)"),
 
5743
                                mData->m_pMachineConfigFile->strStateFile.raw(),
 
5744
                                vrc);
 
5745
            mSSData->mStateFilePath = stateFilePathFull;
 
5746
        }
4951
5747
 
4952
5748
        /* snapshotFolder (optional) */
4953
 
        {
4954
 
            Bstr folder = machineNode.stringValue ("snapshotFolder");
4955
 
            rc = COMSETTER (SnapshotFolder) (folder);
4956
 
            CheckComRCThrowRC (rc);
4957
 
        }
 
5749
        rc = COMSETTER(SnapshotFolder)(Bstr(mData->m_pMachineConfigFile->strSnapshotFolder));
 
5750
        CheckComRCThrowRC(rc);
4958
5751
 
4959
5752
        /* currentStateModified (optional, default is true) */
4960
 
        mData->mCurrentStateModified = machineNode.value <bool> ("currentStateModified");
4961
 
 
4962
 
        /* lastStateChange (optional, defaults to now) */
4963
 
        {
4964
 
            RTTIMESPEC now;
4965
 
            RTTimeNow (&now);
4966
 
            mData->mLastStateChange =
4967
 
                machineNode.valueOr <RTTIMESPEC> ("lastStateChange", now);
4968
 
        }
4969
 
 
4970
 
        /* aborted (optional, default is false) */
4971
 
        bool aborted = machineNode.value <bool> ("aborted");
 
5753
        mData->mCurrentStateModified = mData->m_pMachineConfigFile->fCurrentStateModified;
 
5754
 
 
5755
        mData->mLastStateChange = mData->m_pMachineConfigFile->timeLastStateChange;
 
5756
 
 
5757
        /* teleportation */
 
5758
        mUserData->mTeleporterEnabled  = mData->m_pMachineConfigFile->fTeleporterEnabled;
 
5759
        mUserData->mTeleporterPort     = mData->m_pMachineConfigFile->uTeleporterPort;
 
5760
        mUserData->mTeleporterAddress  = mData->m_pMachineConfigFile->strTeleporterAddress;
 
5761
        mUserData->mTeleporterPassword = mData->m_pMachineConfigFile->strTeleporterPassword;
4972
5762
 
4973
5763
        /*
4974
5764
         *  note: all mUserData members must be assigned prior this point because
4978
5768
        mUserData.commitCopy();
4979
5769
 
4980
5770
        /* Snapshot node (optional) */
 
5771
        if (mData->m_pMachineConfigFile->llFirstSnapshot.size())
4981
5772
        {
4982
 
            Key snapshotNode = machineNode.findKey ("Snapshot");
4983
 
            if (!snapshotNode.isNull())
4984
 
            {
4985
 
                /* read all snapshots recursively */
4986
 
                rc = loadSnapshot (snapshotNode, currentSnapshotId, NULL);
4987
 
                CheckComRCThrowRC (rc);
4988
 
            }
 
5773
            // there can only be one root snapshot
 
5774
            Assert(mData->m_pMachineConfigFile->llFirstSnapshot.size() == 1);
 
5775
 
 
5776
            settings::Snapshot &snap = mData->m_pMachineConfigFile->llFirstSnapshot.front();
 
5777
 
 
5778
            rc = loadSnapshot(snap,
 
5779
                              mData->m_pMachineConfigFile->uuidCurrentSnapshot,
 
5780
                              NULL);        // no parent == first snapshot
 
5781
            CheckComRCThrowRC(rc);
4989
5782
        }
4990
5783
 
4991
 
        Key hardwareNode = machineNode.key("Hardware");
4992
 
 
4993
5784
        /* Hardware node (required) */
4994
 
        rc = loadHardware (hardwareNode);
4995
 
        CheckComRCThrowRC (rc);
 
5785
        rc = loadHardware(mData->m_pMachineConfigFile->hardwareMachine);
 
5786
        CheckComRCThrowRC(rc);
4996
5787
 
4997
5788
        /* Load storage controllers */
4998
 
        rc = loadStorageControllers (machineNode.key ("StorageControllers"), aRegistered);
4999
 
        CheckComRCThrowRC (rc);
 
5789
        rc = loadStorageControllers(mData->m_pMachineConfigFile->storageMachine, aRegistered);
 
5790
        CheckComRCThrowRC(rc);
5000
5791
 
5001
5792
        /*
5002
5793
         *  NOTE: the assignment below must be the last thing to do,
5003
5794
         *  otherwise it will be not possible to change the settings
5004
5795
         *  somewehere in the code above because all setters will be
5005
 
         *  blocked by checkStateDependency (MutableStateDep).
 
5796
         *  blocked by checkStateDependency(MutableStateDep).
5006
5797
         */
5007
5798
 
5008
5799
        /* set the machine state to Aborted or Saved when appropriate */
5009
 
        if (aborted)
 
5800
        if (mData->m_pMachineConfigFile->fAborted)
5010
5801
        {
5011
 
            Assert (!mSSData->mStateFilePath);
 
5802
            Assert(!mSSData->mStateFilePath.isEmpty());
5012
5803
            mSSData->mStateFilePath.setNull();
5013
5804
 
5014
5805
            /* no need to use setMachineState() during init() */
5015
5806
            mData->mMachineState = MachineState_Aborted;
5016
5807
        }
5017
 
        else if (mSSData->mStateFilePath)
 
5808
        else if (!mSSData->mStateFilePath.isEmpty())
5018
5809
        {
5019
5810
            /* no need to use setMachineState() during init() */
5020
5811
            mData->mMachineState = MachineState_Saved;
5041
5832
 *  @param aCurSnapshotId   Current snapshot ID from the settings file.
5042
5833
 *  @param aParentSnapshot  Parent snapshot.
5043
5834
 */
5044
 
HRESULT Machine::loadSnapshot (const settings::Key &aNode,
5045
 
                               const Guid &aCurSnapshotId,
5046
 
                               Snapshot *aParentSnapshot)
 
5835
HRESULT Machine::loadSnapshot(const settings::Snapshot &data,
 
5836
                              const Guid &aCurSnapshotId,
 
5837
                              Snapshot *aParentSnapshot)
5047
5838
{
5048
 
    using namespace settings;
5049
 
 
5050
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
5051
5839
    AssertReturn (mType == IsMachine, E_FAIL);
5052
5840
 
 
5841
    HRESULT rc = S_OK;
 
5842
 
 
5843
    Utf8Str strStateFile;
 
5844
    if (!data.strStateFile.isEmpty())
 
5845
    {
 
5846
        /* optional */
 
5847
        strStateFile = data.strStateFile;
 
5848
        int vrc = calculateFullPath(strStateFile, strStateFile);
 
5849
        if (RT_FAILURE(vrc))
 
5850
            return setError(E_FAIL,
 
5851
                            tr("Invalid saved state file path '%s' (%Rrc)"),
 
5852
                            strStateFile.raw(),
 
5853
                            vrc);
 
5854
    }
 
5855
 
5053
5856
    /* create a snapshot machine object */
5054
 
    ComObjPtr <SnapshotMachine> snapshotMachine;
5055
 
    snapshotMachine.createObject();
5056
 
 
5057
 
    HRESULT rc = S_OK;
5058
 
 
5059
 
    /* required */
5060
 
    Guid uuid = aNode.value <Guid> ("uuid");
5061
 
 
5062
 
    {
5063
 
        /* optional */
5064
 
        Bstr stateFilePath = aNode.stringValue ("stateFile");
5065
 
        if (stateFilePath)
5066
 
        {
5067
 
            Utf8Str stateFilePathFull = stateFilePath;
5068
 
            int vrc = calculateFullPath (stateFilePathFull, stateFilePathFull);
5069
 
            if (RT_FAILURE (vrc))
5070
 
                return setError (E_FAIL,
5071
 
                                 tr ("Invalid saved state file path '%ls' (%Rrc)"),
5072
 
                                 stateFilePath.raw(), vrc);
5073
 
 
5074
 
            stateFilePath = stateFilePathFull;
5075
 
        }
5076
 
 
5077
 
        /* Hardware node (required) */
5078
 
        Key hardwareNode = aNode.key ("Hardware");
5079
 
 
5080
 
        /* StorageControllers node (required) */
5081
 
        Key storageNode = aNode.key ("StorageControllers");
5082
 
 
5083
 
        /* initialize the snapshot machine */
5084
 
        rc = snapshotMachine->init (this, hardwareNode, storageNode,
5085
 
                                    uuid, stateFilePath);
5086
 
        CheckComRCReturnRC (rc);
5087
 
    }
 
5857
    ComObjPtr<SnapshotMachine> pSnapshotMachine;
 
5858
    pSnapshotMachine.createObject();
 
5859
    rc = pSnapshotMachine->init(this,
 
5860
                                data.hardware,
 
5861
                                data.storage,
 
5862
                                data.uuid,
 
5863
                                strStateFile);
 
5864
    CheckComRCReturnRC(rc);
5088
5865
 
5089
5866
    /* create a snapshot object */
5090
 
    ComObjPtr <Snapshot> snapshot;
5091
 
    snapshot.createObject();
5092
 
 
5093
 
    {
5094
 
        /* required */
5095
 
        Bstr name = aNode.stringValue ("name");
5096
 
 
5097
 
        /* required */
5098
 
        RTTIMESPEC timeStamp = aNode.value <RTTIMESPEC> ("timeStamp");
5099
 
 
5100
 
        /* optional */
5101
 
        Bstr description;
5102
 
        {
5103
 
            Key descNode = aNode.findKey ("Description");
5104
 
            if (!descNode.isNull())
5105
 
                description = descNode.keyStringValue();
5106
 
        }
5107
 
 
5108
 
        /* initialize the snapshot */
5109
 
        rc = snapshot->init (uuid, name, description, timeStamp,
5110
 
                             snapshotMachine, aParentSnapshot);
5111
 
        CheckComRCReturnRC (rc);
5112
 
    }
 
5867
    ComObjPtr<Snapshot> pSnapshot;
 
5868
    pSnapshot.createObject();
 
5869
    /* initialize the snapshot */
 
5870
    rc = pSnapshot->init(mParent, // VirtualBox object
 
5871
                         data.uuid,
 
5872
                         data.strName,
 
5873
                         data.strDescription,
 
5874
                         data.timestamp,
 
5875
                         pSnapshotMachine,
 
5876
                         aParentSnapshot);
 
5877
    CheckComRCReturnRC (rc);
5113
5878
 
5114
5879
    /* memorize the first snapshot if necessary */
5115
5880
    if (!mData->mFirstSnapshot)
5116
 
        mData->mFirstSnapshot = snapshot;
 
5881
        mData->mFirstSnapshot = pSnapshot;
5117
5882
 
5118
5883
    /* memorize the current snapshot when appropriate */
5119
 
    if (!mData->mCurrentSnapshot && snapshot->data().mId == aCurSnapshotId)
5120
 
        mData->mCurrentSnapshot = snapshot;
 
5884
    if (    !mData->mCurrentSnapshot
 
5885
         && pSnapshot->getId() == aCurSnapshotId
 
5886
       )
 
5887
        mData->mCurrentSnapshot = pSnapshot;
5121
5888
 
5122
 
    /* Snapshots node (optional) */
 
5889
    // now create the children
 
5890
    for (settings::SnapshotsList::const_iterator it = data.llChildSnapshots.begin();
 
5891
         it != data.llChildSnapshots.end();
 
5892
         ++it)
5123
5893
    {
5124
 
        Key snapshotsNode = aNode.findKey ("Snapshots");
5125
 
        if (!snapshotsNode.isNull())
5126
 
        {
5127
 
            Key::List children = snapshotsNode.keys ("Snapshot");
5128
 
            for (Key::List::const_iterator it = children.begin();
5129
 
                 it != children.end(); ++ it)
5130
 
            {
5131
 
                rc = loadSnapshot ((*it), aCurSnapshotId, snapshot);
5132
 
                CheckComRCBreakRC (rc);
5133
 
            }
5134
 
        }
 
5894
        const settings::Snapshot &childData = *it;
 
5895
        // recurse
 
5896
        rc = loadSnapshot(childData,
 
5897
                          aCurSnapshotId,
 
5898
                          pSnapshot);       // parent = the one we created above
 
5899
        CheckComRCReturnRC(rc);
5135
5900
    }
5136
5901
 
5137
5902
    return rc;
5140
5905
/**
5141
5906
 *  @param aNode    <Hardware> node.
5142
5907
 */
5143
 
HRESULT Machine::loadHardware (const settings::Key &aNode)
 
5908
HRESULT Machine::loadHardware(const settings::Hardware &data)
5144
5909
{
5145
 
    using namespace settings;
5146
 
 
5147
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
5148
 
    AssertReturn (mType == IsMachine || mType == IsSnapshotMachine, E_FAIL);
 
5910
    AssertReturn(mType == IsMachine || mType == IsSnapshotMachine, E_FAIL);
5149
5911
 
5150
5912
    HRESULT rc = S_OK;
5151
5913
 
5152
 
    /* The hardware version attribute (optional). */
5153
 
    mHWData->mHWVersion = aNode.stringValue ("version");
5154
 
 
5155
 
    /* CPU node (currently not required) */
 
5914
    try
5156
5915
    {
5157
 
        /* default value in case the node is not there */
5158
 
        mHWData->mHWVirtExEnabled             = true;
5159
 
        mHWData->mHWVirtExNestedPagingEnabled = false;
5160
 
        mHWData->mHWVirtExVPIDEnabled         = false;
5161
 
        mHWData->mPAEEnabled                  = false;
5162
 
 
5163
 
        Key cpuNode = aNode.findKey ("CPU");
5164
 
        if (!cpuNode.isNull())
 
5916
        /* The hardware version attribute (optional). */
 
5917
        mHWData->mHWVersion = data.strVersion;
 
5918
        mHWData->mHardwareUUID = data.uuid;
 
5919
 
 
5920
        mHWData->mHWVirtExEnabled             = data.fHardwareVirt;
 
5921
        mHWData->mHWVirtExExclusive           = data.fHardwareVirtExclusive;
 
5922
        mHWData->mHWVirtExNestedPagingEnabled = data.fNestedPaging;
 
5923
        mHWData->mHWVirtExVPIDEnabled         = data.fVPID;
 
5924
        mHWData->mPAEEnabled                  = data.fPAE;
 
5925
        mHWData->mSyntheticCpu                = data.fSyntheticCpu;
 
5926
 
 
5927
        mHWData->mCPUCount = data.cCPUs;
 
5928
 
 
5929
        // cpuid leafs
 
5930
        for (settings::CpuIdLeafsList::const_iterator it = data.llCpuIdLeafs.begin();
 
5931
            it != data.llCpuIdLeafs.end();
 
5932
            ++it)
5165
5933
        {
5166
 
            Key hwVirtExNode = cpuNode.key ("HardwareVirtEx");
5167
 
            if (!hwVirtExNode.isNull())
5168
 
            {
5169
 
                const char *enabled = hwVirtExNode.stringValue ("enabled");
5170
 
                if      (strcmp (enabled, "true") == 0)
5171
 
                    mHWData->mHWVirtExEnabled = true;
5172
 
                else
5173
 
                    mHWData->mHWVirtExEnabled = false;
5174
 
            }
5175
 
            /* HardwareVirtExNestedPaging (optional, default is false) */
5176
 
            Key HWVirtExNestedPagingNode = cpuNode.findKey ("HardwareVirtExNestedPaging");
5177
 
            if (!HWVirtExNestedPagingNode.isNull())
5178
 
            {
5179
 
                mHWData->mHWVirtExNestedPagingEnabled = HWVirtExNestedPagingNode.value <bool> ("enabled");
5180
 
            }
5181
 
 
5182
 
            /* HardwareVirtExVPID (optional, default is false) */
5183
 
            Key HWVirtExVPIDNode = cpuNode.findKey ("HardwareVirtExVPID");
5184
 
            if (!HWVirtExVPIDNode.isNull())
5185
 
            {
5186
 
                mHWData->mHWVirtExVPIDEnabled = HWVirtExVPIDNode.value <bool> ("enabled");
5187
 
            }
5188
 
 
5189
 
            /* PAE (optional, default is false) */
5190
 
            Key PAENode = cpuNode.findKey ("PAE");
5191
 
            if (!PAENode.isNull())
5192
 
            {
5193
 
                mHWData->mPAEEnabled = PAENode.value <bool> ("enabled");
5194
 
            }
5195
 
 
5196
 
            /* CPUCount (optional, default is 1) */
5197
 
            mHWData->mCPUCount = cpuNode.value <ULONG> ("count");
 
5934
            const settings::CpuIdLeaf &leaf = *it;
 
5935
 
 
5936
            switch (leaf.ulId)
 
5937
            {
 
5938
            case 0x0:
 
5939
            case 0x1:
 
5940
            case 0x2:
 
5941
            case 0x3:
 
5942
            case 0x4:
 
5943
            case 0x5:
 
5944
            case 0x6:
 
5945
            case 0x7:
 
5946
            case 0x8:
 
5947
            case 0x9:
 
5948
            case 0xA:
 
5949
                mHWData->mCpuIdStdLeafs[leaf.ulId] = leaf;
 
5950
                break;
 
5951
 
 
5952
            case 0x80000000:
 
5953
            case 0x80000001:
 
5954
            case 0x80000002:
 
5955
            case 0x80000003:
 
5956
            case 0x80000004:
 
5957
            case 0x80000005:
 
5958
            case 0x80000006:
 
5959
            case 0x80000007:
 
5960
            case 0x80000008:
 
5961
            case 0x80000009:
 
5962
            case 0x8000000A:
 
5963
                mHWData->mCpuIdExtLeafs[leaf.ulId - 0x80000000] = leaf;
 
5964
                break;
 
5965
 
 
5966
            default:
 
5967
                /* just ignore */
 
5968
                break;
 
5969
            }
5198
5970
        }
5199
 
    }
5200
 
 
5201
 
    /* Memory node (required) */
5202
 
    {
5203
 
        Key memoryNode = aNode.key ("Memory");
5204
 
 
5205
 
        mHWData->mMemorySize = memoryNode.value <ULONG> ("RAMSize");
5206
 
    }
5207
 
 
5208
 
    /* Boot node (required) */
5209
 
    {
5210
 
        /* reset all boot order positions to NoDevice */
5211
 
        for (size_t i = 0; i < RT_ELEMENTS (mHWData->mBootOrder); i++)
5212
 
            mHWData->mBootOrder [i] = DeviceType_Null;
5213
 
 
5214
 
        Key bootNode = aNode.key ("Boot");
5215
 
 
5216
 
        Key::List orderNodes = bootNode.keys ("Order");
5217
 
        for (Key::List::const_iterator it = orderNodes.begin();
5218
 
             it != orderNodes.end(); ++ it)
 
5971
 
 
5972
        mHWData->mMemorySize = data.ulMemorySizeMB;
 
5973
 
 
5974
        // boot order
 
5975
        for (size_t i = 0;
 
5976
             i < RT_ELEMENTS(mHWData->mBootOrder);
 
5977
             i++)
5219
5978
        {
5220
 
            /* position (required) */
5221
 
            /* position unicity is guaranteed by XML Schema */
5222
 
            uint32_t position = (*it).value <uint32_t> ("position");
5223
 
            -- position;
5224
 
            Assert (position < RT_ELEMENTS (mHWData->mBootOrder));
5225
 
 
5226
 
            /* device (required) */
5227
 
            const char *device = (*it).stringValue ("device");
5228
 
            if      (strcmp (device, "None") == 0)
5229
 
                mHWData->mBootOrder [position] = DeviceType_Null;
5230
 
            else if (strcmp (device, "Floppy") == 0)
5231
 
                mHWData->mBootOrder [position] = DeviceType_Floppy;
5232
 
            else if (strcmp (device, "DVD") == 0)
5233
 
                mHWData->mBootOrder [position] = DeviceType_DVD;
5234
 
            else if (strcmp (device, "HardDisk") == 0)
5235
 
                mHWData->mBootOrder [position] = DeviceType_HardDisk;
5236
 
            else if (strcmp (device, "Network") == 0)
5237
 
                mHWData->mBootOrder [position] = DeviceType_Network;
 
5979
            settings::BootOrderMap::const_iterator it = data.mapBootOrder.find(i);
 
5980
            if (it == data.mapBootOrder.end())
 
5981
                mHWData->mBootOrder[i] = DeviceType_Null;
5238
5982
            else
5239
 
                ComAssertMsgFailed (("Invalid device: %s", device));
 
5983
                mHWData->mBootOrder[i] = it->second;
5240
5984
        }
5241
 
    }
5242
 
 
5243
 
    /* Display node (required) */
5244
 
    {
5245
 
        Key displayNode = aNode.key ("Display");
5246
 
 
5247
 
        mHWData->mVRAMSize      = displayNode.value <ULONG> ("VRAMSize");
5248
 
        mHWData->mMonitorCount  = displayNode.value <ULONG> ("monitorCount");
5249
 
        mHWData->mAccelerate3DEnabled = displayNode.value <bool> ("accelerate3D");
5250
 
    }
 
5985
 
 
5986
        mHWData->mVRAMSize      = data.ulVRAMSizeMB;
 
5987
        mHWData->mMonitorCount  = data.cMonitors;
 
5988
        mHWData->mAccelerate3DEnabled = data.fAccelerate3D;
 
5989
        mHWData->mAccelerate2DVideoEnabled = data.fAccelerate2DVideo;
 
5990
        mHWData->mFirmwareType = data.firmwareType;
5251
5991
 
5252
5992
#ifdef VBOX_WITH_VRDP
5253
 
    /* RemoteDisplay */
5254
 
    rc = mVRDPServer->loadSettings (aNode);
5255
 
    CheckComRCReturnRC (rc);
 
5993
        /* RemoteDisplay */
 
5994
        rc = mVRDPServer->loadSettings(data.vrdpSettings);
 
5995
        CheckComRCReturnRC (rc);
5256
5996
#endif
5257
5997
 
5258
 
    /* BIOS */
5259
 
    rc = mBIOSSettings->loadSettings (aNode);
5260
 
    CheckComRCReturnRC (rc);
5261
 
 
5262
 
    /* DVD drive */
5263
 
    rc = mDVDDrive->loadSettings (aNode);
5264
 
    CheckComRCReturnRC (rc);
5265
 
 
5266
 
    /* Floppy drive */
5267
 
    rc = mFloppyDrive->loadSettings (aNode);
5268
 
    CheckComRCReturnRC (rc);
5269
 
 
5270
 
    /* USB Controller */
5271
 
    rc = mUSBController->loadSettings (aNode);
5272
 
    CheckComRCReturnRC (rc);
5273
 
 
5274
 
    /* Network node (required) */
5275
 
    {
5276
 
        /* we assume that all network adapters are initially disabled
5277
 
         * and detached */
5278
 
 
5279
 
        Key networkNode = aNode.key ("Network");
5280
 
 
5281
 
        rc = S_OK;
5282
 
 
5283
 
        Key::List adapters = networkNode.keys ("Adapter");
5284
 
        for (Key::List::const_iterator it = adapters.begin();
5285
 
             it != adapters.end(); ++ it)
5286
 
        {
5287
 
            /* slot number (required) */
5288
 
            /* slot unicity is guaranteed by XML Schema */
5289
 
            uint32_t slot = (*it).value <uint32_t> ("slot");
5290
 
            AssertBreak (slot < RT_ELEMENTS (mNetworkAdapters));
5291
 
 
5292
 
            rc = mNetworkAdapters [slot]->loadSettings (*it);
5293
 
            CheckComRCReturnRC (rc);
5294
 
        }
5295
 
    }
5296
 
 
5297
 
    /* Serial node (required) */
5298
 
    {
5299
 
        Key serialNode = aNode.key ("UART");
5300
 
 
5301
 
        rc = S_OK;
5302
 
 
5303
 
        Key::List ports = serialNode.keys ("Port");
5304
 
        for (Key::List::const_iterator it = ports.begin();
5305
 
             it != ports.end(); ++ it)
5306
 
        {
5307
 
            /* slot number (required) */
5308
 
            /* slot unicity is guaranteed by XML Schema */
5309
 
            uint32_t slot = (*it).value <uint32_t> ("slot");
5310
 
            AssertBreak (slot < RT_ELEMENTS (mSerialPorts));
5311
 
 
5312
 
            rc = mSerialPorts [slot]->loadSettings (*it);
5313
 
            CheckComRCReturnRC (rc);
5314
 
        }
5315
 
    }
5316
 
 
5317
 
    /* Parallel node (optional) */
5318
 
    {
5319
 
        Key parallelNode = aNode.key ("LPT");
5320
 
 
5321
 
        rc = S_OK;
5322
 
 
5323
 
        Key::List ports = parallelNode.keys ("Port");
5324
 
        for (Key::List::const_iterator it = ports.begin();
5325
 
             it != ports.end(); ++ it)
5326
 
        {
5327
 
            /* slot number (required) */
5328
 
            /* slot unicity is guaranteed by XML Schema */
5329
 
            uint32_t slot = (*it).value <uint32_t> ("slot");
5330
 
            AssertBreak (slot < RT_ELEMENTS (mSerialPorts));
5331
 
 
5332
 
            rc = mParallelPorts [slot]->loadSettings (*it);
5333
 
            CheckComRCReturnRC (rc);
5334
 
        }
5335
 
    }
5336
 
 
5337
 
    /* AudioAdapter */
5338
 
    rc = mAudioAdapter->loadSettings (aNode);
5339
 
    CheckComRCReturnRC (rc);
5340
 
 
5341
 
    /* Shared folders (required) */
5342
 
    {
5343
 
        Key sharedFoldersNode = aNode.key ("SharedFolders");
5344
 
 
5345
 
        rc = S_OK;
5346
 
 
5347
 
        Key::List folders = sharedFoldersNode.keys ("SharedFolder");
5348
 
        for (Key::List::const_iterator it = folders.begin();
5349
 
             it != folders.end(); ++ it)
5350
 
        {
5351
 
            /* folder logical name (required) */
5352
 
            Bstr name = (*it).stringValue ("name");
5353
 
            /* folder host path (required) */
5354
 
            Bstr hostPath = (*it).stringValue ("hostPath");
5355
 
 
5356
 
            bool writable = (*it).value <bool> ("writable");
5357
 
 
5358
 
            rc = CreateSharedFolder (name, hostPath, writable);
5359
 
            CheckComRCReturnRC (rc);
5360
 
        }
5361
 
    }
5362
 
 
5363
 
    /* Clipboard node (required) */
5364
 
    {
5365
 
        Key clipNode = aNode.key ("Clipboard");
5366
 
 
5367
 
        const char *mode = clipNode.stringValue ("mode");
5368
 
        if      (strcmp (mode, "Disabled") == 0)
5369
 
            mHWData->mClipboardMode = ClipboardMode_Disabled;
5370
 
        else if (strcmp (mode, "HostToGuest") == 0)
5371
 
            mHWData->mClipboardMode = ClipboardMode_HostToGuest;
5372
 
        else if (strcmp (mode, "GuestToHost") == 0)
5373
 
            mHWData->mClipboardMode = ClipboardMode_GuestToHost;
5374
 
        else if (strcmp (mode, "Bidirectional") == 0)
5375
 
            mHWData->mClipboardMode = ClipboardMode_Bidirectional;
5376
 
        else
5377
 
            AssertMsgFailed (("Invalid clipboard mode '%s'\n", mode));
5378
 
    }
5379
 
 
5380
 
    /* Guest node (required) */
5381
 
    {
5382
 
        Key guestNode = aNode.key ("Guest");
5383
 
 
5384
 
        /* optional, defaults to 0 */
5385
 
        mHWData->mMemoryBalloonSize =
5386
 
            guestNode.value <ULONG> ("memoryBalloonSize");
5387
 
        /* optional, defaults to 0 */
5388
 
        mHWData->mStatisticsUpdateInterval =
5389
 
            guestNode.value <ULONG> ("statisticsUpdateInterval");
5390
 
    }
 
5998
        /* BIOS */
 
5999
        rc = mBIOSSettings->loadSettings(data.biosSettings);
 
6000
        CheckComRCReturnRC (rc);
 
6001
 
 
6002
        /* USB Controller */
 
6003
        rc = mUSBController->loadSettings(data.usbController);
 
6004
        CheckComRCReturnRC (rc);
 
6005
 
 
6006
        // network adapters
 
6007
        for (settings::NetworkAdaptersList::const_iterator it = data.llNetworkAdapters.begin();
 
6008
            it != data.llNetworkAdapters.end();
 
6009
            ++it)
 
6010
        {
 
6011
            const settings::NetworkAdapter &nic = *it;
 
6012
 
 
6013
            /* slot unicity is guaranteed by XML Schema */
 
6014
            AssertBreak(nic.ulSlot < RT_ELEMENTS(mNetworkAdapters));
 
6015
            rc = mNetworkAdapters[nic.ulSlot]->loadSettings(nic);
 
6016
            CheckComRCReturnRC (rc);
 
6017
        }
 
6018
 
 
6019
        // serial ports
 
6020
        for (settings::SerialPortsList::const_iterator it = data.llSerialPorts.begin();
 
6021
            it != data.llSerialPorts.end();
 
6022
            ++it)
 
6023
        {
 
6024
            const settings::SerialPort &s = *it;
 
6025
 
 
6026
            AssertBreak(s.ulSlot < RT_ELEMENTS(mSerialPorts));
 
6027
            rc = mSerialPorts[s.ulSlot]->loadSettings(s);
 
6028
            CheckComRCReturnRC (rc);
 
6029
        }
 
6030
 
 
6031
        // parallel ports (optional)
 
6032
        for (settings::ParallelPortsList::const_iterator it = data.llParallelPorts.begin();
 
6033
            it != data.llParallelPorts.end();
 
6034
            ++it)
 
6035
        {
 
6036
            const settings::ParallelPort &p = *it;
 
6037
 
 
6038
            AssertBreak(p.ulSlot < RT_ELEMENTS(mParallelPorts));
 
6039
            rc = mParallelPorts[p.ulSlot]->loadSettings(p);
 
6040
            CheckComRCReturnRC (rc);
 
6041
        }
 
6042
 
 
6043
        /* AudioAdapter */
 
6044
        rc = mAudioAdapter->loadSettings(data.audioAdapter);
 
6045
        CheckComRCReturnRC (rc);
 
6046
 
 
6047
        for (settings::SharedFoldersList::const_iterator it = data.llSharedFolders.begin();
 
6048
             it != data.llSharedFolders.end();
 
6049
             ++it)
 
6050
        {
 
6051
            const settings::SharedFolder &sf = *it;
 
6052
            rc = CreateSharedFolder(Bstr(sf.strName), Bstr(sf.strHostPath), sf.fWritable);
 
6053
            CheckComRCReturnRC (rc);
 
6054
        }
 
6055
 
 
6056
        // Clipboard
 
6057
        mHWData->mClipboardMode = data.clipboardMode;
 
6058
 
 
6059
        // guest settings
 
6060
        mHWData->mMemoryBalloonSize = data.ulMemoryBalloonSize;
 
6061
        mHWData->mStatisticsUpdateInterval = data.ulStatisticsUpdateInterval;
5391
6062
 
5392
6063
#ifdef VBOX_WITH_GUEST_PROPS
5393
 
    /* Guest properties (optional) */
5394
 
    {
5395
 
        using namespace guestProp;
5396
 
 
5397
 
        Key guestPropertiesNode = aNode.findKey ("GuestProperties");
5398
 
        Bstr notificationPatterns ("");  /* We catch allocation failure below. */
5399
 
        if (!guestPropertiesNode.isNull())
 
6064
        /* Guest properties (optional) */
 
6065
        for (settings::GuestPropertiesList::const_iterator it = data.llGuestProperties.begin();
 
6066
            it != data.llGuestProperties.end();
 
6067
            ++it)
5400
6068
        {
5401
 
            Key::List properties = guestPropertiesNode.keys ("GuestProperty");
5402
 
            for (Key::List::const_iterator it = properties.begin();
5403
 
                 it != properties.end(); ++ it)
5404
 
            {
5405
 
                uint32_t fFlags = NILFLAG;
5406
 
 
5407
 
                /* property name (required) */
5408
 
                Bstr name = (*it).stringValue ("name");
5409
 
                /* property value (required) */
5410
 
                Bstr value = (*it).stringValue ("value");
5411
 
                /* property timestamp (optional, defaults to 0) */
5412
 
                ULONG64 timestamp = (*it).value<ULONG64> ("timestamp");
5413
 
                /* property flags (optional, defaults to empty) */
5414
 
                Bstr flags = (*it).stringValue ("flags");
5415
 
                Utf8Str utf8Flags (flags);
5416
 
                if (utf8Flags.isNull ())
5417
 
                    return E_OUTOFMEMORY;
5418
 
                validateFlags (utf8Flags.raw(), &fFlags);
5419
 
                HWData::GuestProperty property = { name, value, timestamp, fFlags };
5420
 
                mHWData->mGuestProperties.push_back (property);
5421
 
                /* This is just sanity, as the push_back() will probably have thrown
5422
 
                 * an exception if we are out of memory.  Note that if we run out
5423
 
                 * allocating the Bstrs above, this will be caught here as well. */
5424
 
                if (   mHWData->mGuestProperties.back().mName.isNull ()
5425
 
                    || mHWData->mGuestProperties.back().mValue.isNull ()
5426
 
                   )
5427
 
                    return E_OUTOFMEMORY;
5428
 
            }
5429
 
            notificationPatterns = guestPropertiesNode.stringValue ("notificationPatterns");
 
6069
            const settings::GuestProperty &prop = *it;
 
6070
            uint32_t fFlags = guestProp::NILFLAG;
 
6071
            guestProp::validateFlags(prop.strFlags.c_str(), &fFlags);
 
6072
            HWData::GuestProperty property = { prop.strName, prop.strValue, prop.timestamp, fFlags };
 
6073
            mHWData->mGuestProperties.push_back(property);
5430
6074
        }
 
6075
 
5431
6076
        mHWData->mPropertyServiceActive = false;
5432
 
        mHWData->mGuestPropertyNotificationPatterns = notificationPatterns;
5433
 
        if (mHWData->mGuestPropertyNotificationPatterns.isNull ())
5434
 
            return E_OUTOFMEMORY;
5435
 
    }
 
6077
        mHWData->mGuestPropertyNotificationPatterns = data.strNotificationPatterns;
5436
6078
#endif /* VBOX_WITH_GUEST_PROPS defined */
 
6079
    }
 
6080
    catch(std::bad_alloc &)
 
6081
    {
 
6082
        return E_OUTOFMEMORY;
 
6083
    }
5437
6084
 
5438
 
    AssertComRC (rc);
 
6085
    AssertComRC(rc);
5439
6086
    return rc;
5440
6087
}
5441
6088
 
5442
 
/**
5443
 
 *  @param aNode    <StorageControllers> node.
5444
 
 */
5445
 
HRESULT Machine::loadStorageControllers (const settings::Key &aNode, bool aRegistered,
5446
 
                                         const Guid *aSnapshotId /* = NULL */)
 
6089
  /**
 
6090
   *  @param aNode    <StorageControllers> node.
 
6091
   */
 
6092
HRESULT Machine::loadStorageControllers(const settings::Storage &data,
 
6093
                                        bool aRegistered,
 
6094
                                        const Guid *aSnapshotId /* = NULL */)
5447
6095
{
5448
 
    using namespace settings;
5449
 
 
5450
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
5451
6096
    AssertReturn (mType == IsMachine || mType == IsSnapshotMachine, E_FAIL);
5452
6097
 
5453
6098
    HRESULT rc = S_OK;
5454
6099
 
5455
 
    Key::List children = aNode.keys ("StorageController");
5456
 
 
5457
6100
    /* Make sure the attached hard disks don't get unregistered until we
5458
6101
     * associate them with tis machine (important for VMs loaded (opened) after
5459
6102
     * VirtualBox startup) */
5460
 
    AutoReadLock vboxLock (mParent);
 
6103
    AutoReadLock vboxLock(mParent);
5461
6104
 
5462
 
    for (Key::List::const_iterator it = children.begin();
5463
 
         it != children.end(); ++ it)
 
6105
    for (settings::StorageControllersList::const_iterator it = data.llStorageControllers.begin();
 
6106
         it != data.llStorageControllers.end();
 
6107
         ++it)
5464
6108
    {
5465
 
        Bstr controllerName = (*it).stringValue ("name");
5466
 
        const char *controllerType = (*it).stringValue ("type");
5467
 
        ULONG portCount = (*it).value <ULONG> ("PortCount");
5468
 
        StorageControllerType_T controller;
5469
 
        StorageBus_T connection;
5470
 
 
5471
 
        if (strcmp (controllerType, "AHCI") == 0)
5472
 
        {
5473
 
            connection = StorageBus_SATA;
5474
 
            controller = StorageControllerType_IntelAhci;
5475
 
        }
5476
 
        else if (strcmp (controllerType, "LsiLogic") == 0)
5477
 
        {
5478
 
            connection = StorageBus_SCSI;
5479
 
            controller = StorageControllerType_LsiLogic;
5480
 
        }
5481
 
        else if (strcmp (controllerType, "BusLogic") == 0)
5482
 
        {
5483
 
            connection = StorageBus_SCSI;
5484
 
            controller = StorageControllerType_BusLogic;
5485
 
        }
5486
 
        else if (strcmp (controllerType, "PIIX3") == 0)
5487
 
        {
5488
 
            connection = StorageBus_IDE;
5489
 
            controller = StorageControllerType_PIIX3;
5490
 
        }
5491
 
        else if (strcmp (controllerType, "PIIX4") == 0)
5492
 
        {
5493
 
            connection = StorageBus_IDE;
5494
 
            controller = StorageControllerType_PIIX4;
5495
 
        }
5496
 
        else if (strcmp (controllerType, "ICH6") == 0)
5497
 
        {
5498
 
            connection = StorageBus_IDE;
5499
 
            controller = StorageControllerType_ICH6;
5500
 
        }
5501
 
        else
5502
 
            AssertFailedReturn (E_FAIL);
5503
 
 
5504
 
        ComObjPtr<StorageController> ctl;
 
6109
        const settings::StorageController &ctlData = *it;
 
6110
 
 
6111
        ComObjPtr<StorageController> pCtl;
5505
6112
        /* Try to find one with the name first. */
5506
 
        rc = getStorageControllerByName (controllerName, ctl, false /* aSetError */);
5507
 
        if (SUCCEEDED (rc))
5508
 
            return setError (VBOX_E_OBJECT_IN_USE,
5509
 
                tr ("Storage controller named '%ls' already exists"), controllerName.raw());
5510
 
 
5511
 
        ctl.createObject();
5512
 
        rc = ctl->init (this, controllerName, connection);
5513
 
        CheckComRCReturnRC (rc);
5514
 
 
5515
 
        mStorageControllers->push_back (ctl);
5516
 
 
5517
 
        rc = ctl->COMSETTER(ControllerType)(controller);
5518
 
        CheckComRCReturnRC(rc);
5519
 
 
5520
 
        rc = ctl->COMSETTER(PortCount)(portCount);
5521
 
        CheckComRCReturnRC(rc);
 
6113
        rc = getStorageControllerByName(ctlData.strName, pCtl, false /* aSetError */);
 
6114
        if (SUCCEEDED(rc))
 
6115
            return setError(VBOX_E_OBJECT_IN_USE,
 
6116
                            tr("Storage controller named '%s' already exists"),
 
6117
                            ctlData.strName.raw());
 
6118
 
 
6119
        pCtl.createObject();
 
6120
        rc = pCtl->init(this,
 
6121
                        ctlData.strName,
 
6122
                        ctlData.storageBus,
 
6123
                        ctlData.ulInstance);
 
6124
        CheckComRCReturnRC (rc);
 
6125
 
 
6126
        mStorageControllers->push_back(pCtl);
 
6127
 
 
6128
        rc = pCtl->COMSETTER(ControllerType)(ctlData.controllerType);
 
6129
        CheckComRCReturnRC (rc);
 
6130
 
 
6131
        rc = pCtl->COMSETTER(PortCount)(ctlData.ulPortCount);
 
6132
        CheckComRCReturnRC (rc);
5522
6133
 
5523
6134
        /* Set IDE emulation settings (only for AHCI controller). */
5524
 
        if (controller == StorageControllerType_IntelAhci)
 
6135
        if (ctlData.controllerType == StorageControllerType_IntelAhci)
5525
6136
        {
5526
 
            ULONG val;
5527
 
 
5528
 
            /* ide emulation settings (optional, default to 0,1,2,3 respectively) */
5529
 
            val = (*it).valueOr <ULONG> ("IDE0MasterEmulationPort", 0);
5530
 
            rc = ctl->SetIDEEmulationPort(0, val);
5531
 
            CheckComRCReturnRC(rc);
5532
 
            val = (*it).valueOr <ULONG> ("IDE0SlaveEmulationPort", 1);
5533
 
            rc = ctl->SetIDEEmulationPort(1, val);
5534
 
            CheckComRCReturnRC(rc);
5535
 
            val = (*it).valueOr <ULONG> ("IDE1MasterEmulationPort", 2);
5536
 
            rc = ctl->SetIDEEmulationPort(2, val);
5537
 
            CheckComRCReturnRC(rc);
5538
 
            val = (*it).valueOr <ULONG> ("IDE1SlaveEmulationPort", 3);
5539
 
            rc = ctl->SetIDEEmulationPort(3, val);
5540
 
            CheckComRCReturnRC(rc);
 
6137
            if (    (FAILED(rc = pCtl->SetIDEEmulationPort(0, ctlData.lIDE0MasterEmulationPort)))
 
6138
                 || (FAILED(rc = pCtl->SetIDEEmulationPort(1, ctlData.lIDE0SlaveEmulationPort)))
 
6139
                 || (FAILED(rc = pCtl->SetIDEEmulationPort(2, ctlData.lIDE1MasterEmulationPort)))
 
6140
                 || (FAILED(rc = pCtl->SetIDEEmulationPort(3, ctlData.lIDE1SlaveEmulationPort)))
 
6141
               )
 
6142
                return rc;
5541
6143
        }
5542
6144
 
5543
6145
        /* Load the attached devices now. */
5544
 
        rc = loadStorageDevices(ctl, (*it),
5545
 
                                aRegistered, aSnapshotId);
5546
 
        CheckComRCReturnRC(rc);
 
6146
        rc = loadStorageDevices(pCtl,
 
6147
                                ctlData,
 
6148
                                aRegistered,
 
6149
                                aSnapshotId);
 
6150
        CheckComRCReturnRC (rc);
5547
6151
    }
5548
6152
 
5549
6153
    return S_OK;
5552
6156
/**
5553
6157
 * @param aNode        <HardDiskAttachments> node.
5554
6158
 * @param aRegistered  true when the machine is being loaded on VirtualBox
5555
 
 *                      startup, or when a snapshot is being loaded (wchich
5556
 
 *                      currently can happen on startup only)
 
6159
 *                     startup, or when a snapshot is being loaded (wchich
 
6160
 *                     currently can happen on startup only)
5557
6161
 * @param aSnapshotId  pointer to the snapshot ID if this is a snapshot machine
5558
6162
 *
5559
 
 * @note Lock mParent for reading and hard disks for writing before calling.
 
6163
 * @note Lock mParent  for reading and hard disks for writing before calling.
5560
6164
 */
5561
 
HRESULT Machine::loadStorageDevices (ComObjPtr<StorageController> aStorageController,
5562
 
                                     const settings::Key &aNode, bool aRegistered,
5563
 
                                     const Guid *aSnapshotId /* = NULL */)
 
6165
HRESULT Machine::loadStorageDevices(StorageController *aStorageController,
 
6166
                                    const settings::StorageController &data,
 
6167
                                    bool aRegistered,
 
6168
                                    const Guid *aSnapshotId /*= NULL*/)
5564
6169
{
5565
 
    using namespace settings;
5566
 
 
5567
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
5568
6170
    AssertReturn ((mType == IsMachine && aSnapshotId == NULL) ||
5569
6171
                  (mType == IsSnapshotMachine && aSnapshotId != NULL), E_FAIL);
5570
6172
 
5571
6173
    HRESULT rc = S_OK;
5572
6174
 
5573
 
    Key::List children = aNode.keys ("AttachedDevice");
5574
 
 
5575
 
    if (!aRegistered && children.size() > 0)
5576
 
    {
 
6175
    if (!aRegistered && data.llAttachedDevices.size() > 0)
5577
6176
        /* when the machine is being loaded (opened) from a file, it cannot
5578
6177
         * have hard disks attached (this should not happen normally,
5579
6178
         * because we don't allow to attach hard disks to an unregistered
5580
6179
         * VM at all */
5581
 
        return setError (E_FAIL,
5582
 
            tr ("Unregistered machine '%ls' cannot have hard disks attached "
5583
 
                "(found %d hard disk attachments)"),
5584
 
            mUserData->mName.raw(), children.size());
 
6180
        return setError(E_FAIL,
 
6181
                        tr("Unregistered machine '%ls' cannot have storage devices attached (found %d attachments)"),
 
6182
                        mUserData->mName.raw(),
 
6183
                        data.llAttachedDevices.size());
 
6184
 
 
6185
    /* paranoia: detect duplicate attachments */
 
6186
    for (settings::AttachedDevicesList::const_iterator it = data.llAttachedDevices.begin();
 
6187
         it != data.llAttachedDevices.end();
 
6188
         ++it)
 
6189
    {
 
6190
        for (settings::AttachedDevicesList::const_iterator it2 = it;
 
6191
             it2 != data.llAttachedDevices.end();
 
6192
             ++it2)
 
6193
        {
 
6194
            if (it == it2)
 
6195
                continue;
 
6196
 
 
6197
            if (   (*it).lPort == (*it2).lPort
 
6198
                && (*it).lDevice == (*it2).lDevice)
 
6199
            {
 
6200
                return setError(E_FAIL,
 
6201
                                tr("Duplicate attachments for storage controller '%s', port %d, device %d of the virtual machine '%ls'"),
 
6202
                                aStorageController->name().raw(), (*it).lPort, (*it).lDevice, mUserData->mName.raw());
 
6203
            }
 
6204
        }
5585
6205
    }
5586
6206
 
5587
 
    for (Key::List::const_iterator it = children.begin();
5588
 
         it != children.end(); ++ it)
 
6207
    for (settings::AttachedDevicesList::const_iterator it = data.llAttachedDevices.begin();
 
6208
         it != data.llAttachedDevices.end();
 
6209
         ++it)
5589
6210
    {
5590
 
        Key idKey = (*it).key ("Image");
5591
 
        /* hard disk uuid (required) */
5592
 
        Guid uuid = idKey.value <Guid> ("uuid");
5593
 
        /* device type (required) */
5594
 
        const char *deviceType = (*it).stringValue ("type");
5595
 
        /* channel (required) */
5596
 
        LONG port = (*it).value <LONG> ("port");
5597
 
        /* device (required) */
5598
 
        LONG device = (*it).value <LONG> ("device");
5599
 
 
5600
 
        /* We support only hard disk types at the moment.
5601
 
         * @todo: Implement support for CD/DVD drives.
5602
 
         */
5603
 
        if (strcmp(deviceType, "HardDisk") != 0)
5604
 
            return setError (E_FAIL,
5605
 
                tr ("Device at position %lu:%lu is not a hard disk: %s"),
5606
 
                port, device, deviceType);
5607
 
 
5608
 
        /* find a hard disk by UUID */
5609
 
        ComObjPtr<HardDisk> hd;
5610
 
        rc = mParent->findHardDisk(&uuid, NULL, true /* aDoSetError */, &hd);
5611
 
        CheckComRCReturnRC (rc);
5612
 
 
5613
 
        AutoWriteLock hdLock (hd);
5614
 
 
5615
 
        if (hd->type() == HardDiskType_Immutable)
 
6211
        const settings::AttachedDevice &dev = *it;
 
6212
        ComObjPtr<Medium> medium;
 
6213
 
 
6214
        switch (dev.deviceType)
 
6215
        {
 
6216
            case DeviceType_Floppy:
 
6217
                /* find a floppy by UUID */
 
6218
                if (!dev.uuid.isEmpty())
 
6219
                    rc = mParent->findFloppyImage(&dev.uuid, NULL, true /* aDoSetError */, &medium);
 
6220
                /* find a floppy by host device name */
 
6221
                else if (!dev.strHostDriveSrc.isEmpty())
 
6222
                {
 
6223
                    SafeIfaceArray<IMedium> drivevec;
 
6224
                    rc = mParent->host()->COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
 
6225
                    if (SUCCEEDED(rc))
 
6226
                    {
 
6227
                        for (size_t i = 0; i < drivevec.size(); ++i)
 
6228
                        {
 
6229
                            /// @todo eliminate this conversion
 
6230
                            ComObjPtr<Medium> med = (Medium *)drivevec[i];
 
6231
                            if (    dev.strHostDriveSrc == med->getName()
 
6232
                                ||  dev.strHostDriveSrc == med->getLocation())
 
6233
                            {
 
6234
                                medium = med;
 
6235
                                break;
 
6236
                            }
 
6237
                        }
 
6238
                    }
 
6239
                }
 
6240
                break;
 
6241
 
 
6242
            case DeviceType_DVD:
 
6243
                /* find a DVD by UUID */
 
6244
                if (!dev.uuid.isEmpty())
 
6245
                    rc = mParent->findDVDImage(&dev.uuid, NULL, true /* aDoSetError */, &medium);
 
6246
                /* find a DVD by host device name */
 
6247
                else if (!dev.strHostDriveSrc.isEmpty())
 
6248
                {
 
6249
                    SafeIfaceArray<IMedium> drivevec;
 
6250
                    rc = mParent->host()->COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
 
6251
                    if (SUCCEEDED(rc))
 
6252
                    {
 
6253
                        for (size_t i = 0; i < drivevec.size(); ++i)
 
6254
                        {
 
6255
                            Bstr hostDriveSrc(dev.strHostDriveSrc);
 
6256
                            /// @todo eliminate this conversion
 
6257
                            ComObjPtr<Medium> med = (Medium *)drivevec[i];
 
6258
                            if (    hostDriveSrc == med->getName()
 
6259
                                ||  hostDriveSrc == med->getLocation())
 
6260
                            {
 
6261
                                medium = med;
 
6262
                                break;
 
6263
                            }
 
6264
                        }
 
6265
                    }
 
6266
                }
 
6267
                break;
 
6268
 
 
6269
            case DeviceType_HardDisk:
 
6270
            {
 
6271
                /* find a hard disk by UUID */
 
6272
                rc = mParent->findHardDisk(&dev.uuid, NULL, true /* aDoSetError */, &medium);
 
6273
                if (FAILED(rc))
 
6274
                {
 
6275
                    if (mType == IsSnapshotMachine)
 
6276
                    {
 
6277
                        // wrap another error message around the "cannot find hard disk" set by findHardDisk
 
6278
                        // so the user knows that the bad disk is in a snapshot somewhere
 
6279
                        com::ErrorInfo info;
 
6280
                        return setError(E_FAIL,
 
6281
                                        tr("A differencing image of snapshot {%RTuuid} could not be found. %ls"),
 
6282
                                        aSnapshotId->raw(),
 
6283
                                        info.getText().raw());
 
6284
                    }
 
6285
                    else
 
6286
                        return rc;
 
6287
                }
 
6288
 
 
6289
                AutoWriteLock hdLock(medium);
 
6290
 
 
6291
                if (medium->getType() == MediumType_Immutable)
 
6292
                {
 
6293
                    if (mType == IsSnapshotMachine)
 
6294
                        return setError(E_FAIL,
 
6295
                                        tr("Immutable hard disk '%s' with UUID {%RTuuid} cannot be directly attached to snapshot with UUID {%RTuuid} "
 
6296
                                           "of the virtual machine '%ls' ('%s')"),
 
6297
                                        medium->getLocationFull().raw(),
 
6298
                                        dev.uuid.raw(),
 
6299
                                        aSnapshotId->raw(),
 
6300
                                        mUserData->mName.raw(),
 
6301
                                        mData->m_strConfigFileFull.raw());
 
6302
 
 
6303
                    return setError(E_FAIL,
 
6304
                                    tr("Immutable hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%ls' ('%s')"),
 
6305
                                    medium->getLocationFull().raw(),
 
6306
                                    dev.uuid.raw(),
 
6307
                                    mUserData->mName.raw(),
 
6308
                                    mData->m_strConfigFileFull.raw());
 
6309
                }
 
6310
 
 
6311
                if (    mType != IsSnapshotMachine
 
6312
                     && medium->getChildren().size() != 0
 
6313
                   )
 
6314
                    return setError(E_FAIL,
 
6315
                                    tr("Hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%ls' ('%s') "
 
6316
                                       "because it has %d differencing child hard disks"),
 
6317
                                    medium->getLocationFull().raw(),
 
6318
                                    dev.uuid.raw(),
 
6319
                                    mUserData->mName.raw(),
 
6320
                                    mData->m_strConfigFileFull.raw(),
 
6321
                                    medium->getChildren().size());
 
6322
 
 
6323
                if (findAttachment(mMediaData->mAttachments,
 
6324
                                   medium))
 
6325
                    return setError(E_FAIL,
 
6326
                                    tr("Hard disk '%s' with UUID {%RTuuid} is already attached to the virtual machine '%ls' ('%s')"),
 
6327
                                    medium->getLocationFull().raw(),
 
6328
                                    dev.uuid.raw(),
 
6329
                                    mUserData->mName.raw(),
 
6330
                                    mData->m_strConfigFileFull.raw());
 
6331
 
 
6332
                break;
 
6333
            }
 
6334
 
 
6335
            default:
 
6336
                return setError(E_FAIL,
 
6337
                                tr("Device with unknown type is attached to the virtual machine '%s' ('%s')"),
 
6338
                                medium->getLocationFull().raw(),
 
6339
                                mUserData->mName.raw(),
 
6340
                                mData->m_strConfigFileFull.raw());
 
6341
        }
 
6342
 
 
6343
        if (FAILED(rc))
 
6344
            break;
 
6345
 
 
6346
        const Bstr controllerName = aStorageController->name();
 
6347
        ComObjPtr<MediumAttachment> pAttachment;
 
6348
        pAttachment.createObject();
 
6349
        rc = pAttachment->init(this,
 
6350
                               medium,
 
6351
                               controllerName,
 
6352
                               dev.lPort,
 
6353
                               dev.lDevice,
 
6354
                               dev.deviceType,
 
6355
                               dev.fPassThrough);
 
6356
        CheckComRCBreakRC(rc);
 
6357
 
 
6358
        /* associate the medium with this machine and snapshot */
 
6359
        if (!medium.isNull())
5616
6360
        {
5617
6361
            if (mType == IsSnapshotMachine)
5618
 
                return setError (E_FAIL,
5619
 
                    tr ("Immutable hard disk '%ls' with UUID {%RTuuid} cannot be "
5620
 
                        "directly attached to snapshot with UUID {%RTuuid} "
5621
 
                        "of the virtual machine '%ls' ('%ls')"),
5622
 
                    hd->locationFull().raw(), uuid.raw(),
5623
 
                    aSnapshotId->raw(),
5624
 
                    mUserData->mName.raw(), mData->mConfigFileFull.raw());
5625
 
 
5626
 
            return setError (E_FAIL,
5627
 
                tr ("Immutable hard disk '%ls' with UUID {%RTuuid} cannot be "
5628
 
                    "directly attached to the virtual machine '%ls' ('%ls')"),
5629
 
                hd->locationFull().raw(), uuid.raw(),
5630
 
                mUserData->mName.raw(), mData->mConfigFileFull.raw());
5631
 
        }
5632
 
 
5633
 
        if (mType != IsSnapshotMachine && hd->children().size() != 0)
5634
 
            return setError (E_FAIL,
5635
 
                tr ("Hard disk '%ls' with UUID {%RTuuid} cannot be directly "
5636
 
                    "attached to the virtual machine '%ls' ('%ls') "
5637
 
                    "because it has %d differencing child hard disks"),
5638
 
                hd->locationFull().raw(), uuid.raw(),
5639
 
                mUserData->mName.raw(), mData->mConfigFileFull.raw(),
5640
 
                hd->children().size());
5641
 
 
5642
 
        if (std::find_if (mHDData->mAttachments.begin(),
5643
 
                          mHDData->mAttachments.end(),
5644
 
                          HardDiskAttachment::RefersTo (hd)) !=
5645
 
                mHDData->mAttachments.end())
5646
 
        {
5647
 
            return setError (E_FAIL,
5648
 
                tr ("Hard disk '%ls' with UUID {%RTuuid} is already attached "
5649
 
                    "to the virtual machine '%ls' ('%ls')"),
5650
 
                hd->locationFull().raw(), uuid.raw(),
5651
 
                mUserData->mName.raw(), mData->mConfigFileFull.raw());
5652
 
        }
5653
 
 
5654
 
        const Bstr controllerName = aStorageController->name();
5655
 
        ComObjPtr<HardDiskAttachment> attachment;
5656
 
        attachment.createObject();
5657
 
        rc = attachment->init (hd, controllerName, port, device);
5658
 
        CheckComRCBreakRC (rc);
5659
 
 
5660
 
        /* associate the hard disk with this machine and snapshot */
5661
 
        if (mType == IsSnapshotMachine)
5662
 
            rc = hd->attachTo (mData->mUuid, *aSnapshotId);
5663
 
        else
5664
 
            rc = hd->attachTo (mData->mUuid);
5665
 
 
5666
 
        AssertComRCBreakRC (rc);
5667
 
 
5668
 
        /* backup mHDData to let registeredInit() properly rollback on failure
 
6362
                rc = medium->attachTo(mData->mUuid, *aSnapshotId);
 
6363
            else
 
6364
                rc = medium->attachTo(mData->mUuid);
 
6365
        }
 
6366
        if (FAILED(rc))
 
6367
            break;
 
6368
 
 
6369
        /* backup mMediaData to let registeredInit() properly rollback on failure
5669
6370
         * (= limited accessibility) */
5670
6371
 
5671
 
        mHDData.backup();
5672
 
        mHDData->mAttachments.push_back (attachment);
 
6372
        mMediaData.backup();
 
6373
        mMediaData->mAttachments.push_back(pAttachment);
5673
6374
    }
5674
6375
 
5675
6376
    return rc;
5676
6377
}
5677
6378
 
5678
6379
/**
5679
 
 *  Searches for a <Snapshot> node for the given snapshot.
5680
 
 *  If the search is successful, \a aSnapshotNode will contain the found node.
5681
 
 *  In this case, \a aSnapshotsNode can be NULL meaning the found node is a
5682
 
 *  direct child of \a aMachineNode.
5683
 
 *
5684
 
 *  If the search fails, a failure is returned and both \a aSnapshotsNode and
5685
 
 *  \a aSnapshotNode are set to 0.
5686
 
 *
5687
 
 *  @param aSnapshot        Snapshot to search for.
5688
 
 *  @param aMachineNode     <Machine> node to start from.
5689
 
 *  @param aSnapshotsNode   <Snapshots> node containing the found <Snapshot> node
5690
 
 *                          (may be NULL if the caller is not interested).
5691
 
 *  @param aSnapshotNode    Found <Snapshot> node.
5692
 
 */
5693
 
HRESULT Machine::findSnapshotNode (Snapshot *aSnapshot, settings::Key &aMachineNode,
5694
 
                                   settings::Key *aSnapshotsNode,
5695
 
                                   settings::Key *aSnapshotNode)
5696
 
{
5697
 
    using namespace settings;
5698
 
 
5699
 
    AssertReturn (aSnapshot && !aMachineNode.isNull()
5700
 
                  && aSnapshotNode != NULL, E_FAIL);
5701
 
 
5702
 
    if (aSnapshotsNode)
5703
 
        aSnapshotsNode->setNull();
5704
 
    aSnapshotNode->setNull();
5705
 
 
5706
 
    // build the full uuid path (from the top parent to the given snapshot)
5707
 
    std::list <Guid> path;
5708
 
    {
5709
 
        ComObjPtr <Snapshot> parent = aSnapshot;
5710
 
        while (parent)
5711
 
        {
5712
 
            path.push_front (parent->data().mId);
5713
 
            parent = parent->parent();
5714
 
        }
5715
 
    }
5716
 
 
5717
 
    Key snapshotsNode = aMachineNode;
5718
 
    Key snapshotNode;
5719
 
 
5720
 
    for (std::list <Guid>::const_iterator it = path.begin();
5721
 
         it != path.end();
5722
 
         ++ it)
5723
 
    {
5724
 
        if (!snapshotNode.isNull())
5725
 
        {
5726
 
            /* proceed to the nested <Snapshots> node */
5727
 
            snapshotsNode = snapshotNode.key ("Snapshots");
5728
 
            snapshotNode.setNull();
5729
 
        }
5730
 
 
5731
 
        AssertReturn (!snapshotsNode.isNull(), E_FAIL);
5732
 
 
5733
 
        Key::List children = snapshotsNode.keys ("Snapshot");
5734
 
        for (Key::List::const_iterator ch = children.begin();
5735
 
             ch != children.end();
5736
 
             ++ ch)
5737
 
        {
5738
 
            Guid id = (*ch).value <Guid> ("uuid");
5739
 
            if (id == (*it))
5740
 
            {
5741
 
                /* pass over to the outer loop */
5742
 
                snapshotNode = *ch;
5743
 
                break;
5744
 
            }
5745
 
        }
5746
 
 
5747
 
        if (!snapshotNode.isNull())
5748
 
            continue;
5749
 
 
5750
 
        /* the next uuid is not found, no need to continue... */
5751
 
        AssertFailedBreak();
5752
 
    }
5753
 
 
5754
 
    // we must always succesfully find the node
5755
 
    AssertReturn (!snapshotNode.isNull(), E_FAIL);
5756
 
    AssertReturn (!snapshotsNode.isNull(), E_FAIL);
5757
 
 
5758
 
    if (aSnapshotsNode && (snapshotsNode != aMachineNode))
5759
 
        *aSnapshotsNode = snapshotsNode;
5760
 
    *aSnapshotNode = snapshotNode;
5761
 
 
5762
 
    return S_OK;
5763
 
}
5764
 
 
5765
 
/**
5766
 
 *  Returns the snapshot with the given UUID or fails of no such snapshot.
 
6380
 *  Returns the snapshot with the given UUID or fails of no such snapshot exists.
5767
6381
 *
5768
6382
 *  @param aId          snapshot UUID to find (empty UUID refers the first snapshot)
5769
6383
 *  @param aSnapshot    where to return the found snapshot
5770
6384
 *  @param aSetError    true to set extended error info on failure
5771
6385
 */
5772
 
HRESULT Machine::findSnapshot (const Guid &aId, ComObjPtr <Snapshot> &aSnapshot,
5773
 
                               bool aSetError /* = false */)
 
6386
HRESULT Machine::findSnapshot(const Guid &aId,
 
6387
                              ComObjPtr<Snapshot> &aSnapshot,
 
6388
                              bool aSetError /* = false */)
5774
6389
{
 
6390
    AutoReadLock chlock(snapshotsTreeLockHandle());
 
6391
 
5775
6392
    if (!mData->mFirstSnapshot)
5776
6393
    {
5777
6394
        if (aSetError)
5778
 
            return setError (E_FAIL,
5779
 
                tr ("This machine does not have any snapshots"));
 
6395
            return setError(E_FAIL,
 
6396
                            tr("This machine does not have any snapshots"));
5780
6397
        return E_FAIL;
5781
6398
    }
5782
6399
 
5783
6400
    if (aId.isEmpty())
5784
6401
        aSnapshot = mData->mFirstSnapshot;
5785
6402
    else
5786
 
        aSnapshot = mData->mFirstSnapshot->findChildOrSelf (aId);
 
6403
        aSnapshot = mData->mFirstSnapshot->findChildOrSelf(aId);
5787
6404
 
5788
6405
    if (!aSnapshot)
5789
6406
    {
5790
6407
        if (aSetError)
5791
 
            return setError (E_FAIL,
5792
 
                tr ("Could not find a snapshot with UUID {%s}"),
5793
 
                aId.toString().raw());
 
6408
            return setError(E_FAIL,
 
6409
                            tr("Could not find a snapshot with UUID {%s}"),
 
6410
                            aId.toString().raw());
5794
6411
        return E_FAIL;
5795
6412
    }
5796
6413
 
5804
6421
 *  @param aSnapshot    where to return the found snapshot
5805
6422
 *  @param aSetError    true to set extended error info on failure
5806
6423
 */
5807
 
HRESULT Machine::findSnapshot (IN_BSTR aName, ComObjPtr <Snapshot> &aSnapshot,
5808
 
                               bool aSetError /* = false */)
 
6424
HRESULT Machine::findSnapshot(IN_BSTR aName,
 
6425
                              ComObjPtr<Snapshot> &aSnapshot,
 
6426
                              bool aSetError /* = false */)
5809
6427
{
5810
 
    AssertReturn (aName, E_INVALIDARG);
 
6428
    AssertReturn(aName, E_INVALIDARG);
 
6429
 
 
6430
    AutoReadLock chlock(snapshotsTreeLockHandle());
5811
6431
 
5812
6432
    if (!mData->mFirstSnapshot)
5813
6433
    {
5814
6434
        if (aSetError)
5815
 
            return setError (VBOX_E_OBJECT_NOT_FOUND,
5816
 
                tr ("This machine does not have any snapshots"));
 
6435
            return setError(VBOX_E_OBJECT_NOT_FOUND,
 
6436
                            tr("This machine does not have any snapshots"));
5817
6437
        return VBOX_E_OBJECT_NOT_FOUND;
5818
6438
    }
5819
6439
 
5822
6442
    if (!aSnapshot)
5823
6443
    {
5824
6444
        if (aSetError)
5825
 
            return setError (VBOX_E_OBJECT_NOT_FOUND,
5826
 
                tr ("Could not find a snapshot named '%ls'"), aName);
 
6445
            return setError(VBOX_E_OBJECT_NOT_FOUND,
 
6446
                            tr("Could not find a snapshot named '%ls'"), aName);
5827
6447
        return VBOX_E_OBJECT_NOT_FOUND;
5828
6448
    }
5829
6449
 
5837
6457
 *  @param aStorageController    where to return the found storage controller
5838
6458
 *  @param aSetError             true to set extended error info on failure
5839
6459
 */
5840
 
HRESULT Machine::getStorageControllerByName(CBSTR aName,
5841
 
                                            ComObjPtr <StorageController> &aStorageController,
 
6460
HRESULT Machine::getStorageControllerByName(const Utf8Str &aName,
 
6461
                                            ComObjPtr<StorageController> &aStorageController,
5842
6462
                                            bool aSetError /* = false */)
5843
6463
{
5844
 
    AssertReturn (aName, E_INVALIDARG);
 
6464
    AssertReturn (!aName.isEmpty(), E_INVALIDARG);
5845
6465
 
5846
 
    for (StorageControllerList::const_iterator it =
5847
 
                mStorageControllers->begin();
5848
 
            it != mStorageControllers->end();
5849
 
            ++ it)
 
6466
    for (StorageControllerList::const_iterator it = mStorageControllers->begin();
 
6467
         it != mStorageControllers->end();
 
6468
         ++it)
5850
6469
    {
5851
6470
        if ((*it)->name() == aName)
5852
6471
        {
5856
6475
    }
5857
6476
 
5858
6477
    if (aSetError)
5859
 
        return setError (VBOX_E_OBJECT_NOT_FOUND,
5860
 
            tr ("Could not find a storage controller named '%ls'"), aName);
 
6478
        return setError(VBOX_E_OBJECT_NOT_FOUND,
 
6479
                        tr("Could not find a storage controller named '%s'"),
 
6480
                        aName.raw());
5861
6481
    return VBOX_E_OBJECT_NOT_FOUND;
5862
6482
}
5863
6483
 
5864
 
HRESULT Machine::getHardDiskAttachmentsOfController(CBSTR aName,
5865
 
                                                    HDData::AttachmentList &atts)
 
6484
HRESULT Machine::getMediumAttachmentsOfController(CBSTR aName,
 
6485
                                                  MediaData::AttachmentList &atts)
5866
6486
{
5867
 
    AutoCaller autoCaller (this);
 
6487
    AutoCaller autoCaller(this);
5868
6488
    CheckComRCReturnRC(autoCaller.rc());
5869
6489
 
5870
6490
    AutoReadLock alock(this);
5871
6491
 
5872
 
    for (HDData::AttachmentList::iterator it = mHDData->mAttachments.begin();
5873
 
         it != mHDData->mAttachments.end(); ++it)
 
6492
    for (MediaData::AttachmentList::iterator it = mMediaData->mAttachments.begin();
 
6493
         it != mMediaData->mAttachments.end();
 
6494
         ++it)
5874
6495
    {
5875
 
        if ((*it)->controller() == aName)
 
6496
        if ((*it)->getControllerName() == aName)
5876
6497
            atts.push_back(*it);
5877
6498
    }
5878
6499
 
5891
6512
 *                  value makes sense only on success.
5892
6513
 *  @param aNew     receives |true| if a virgin settings file was created.
5893
6514
 */
5894
 
HRESULT Machine::prepareSaveSettings (bool &aRenamed, bool &aNew)
 
6515
HRESULT Machine::prepareSaveSettings(bool &aRenamed,
 
6516
                                     bool &aNew)
5895
6517
{
5896
6518
    /* Note: tecnhically, mParent needs to be locked only when the machine is
5897
6519
     * registered (see prepareSaveSettings() for details) but we don't
5898
6520
     * currently differentiate it in callers of saveSettings() so we don't
5899
6521
     * make difference here too.  */
5900
 
    AssertReturn (mParent->isWriteLockOnCurrentThread(), E_FAIL);
5901
 
    AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
 
6522
    AssertReturn(mParent->isWriteLockOnCurrentThread(), E_FAIL);
 
6523
    AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
5902
6524
 
5903
6525
    HRESULT rc = S_OK;
5904
6526
 
5906
6528
 
5907
6529
    /* if we're ready and isConfigLocked() is FALSE then it means
5908
6530
     * that no config file exists yet (we will create a virgin one) */
5909
 
    aNew = !isConfigLocked();
 
6531
    aNew = !mData->m_pMachineConfigFile->fileExists();
5910
6532
 
5911
6533
    /* attempt to rename the settings file if machine name is changed */
5912
 
    if (mUserData->mNameSync &&
5913
 
        mUserData.isBackedUp() &&
5914
 
        mUserData.backedUpData()->mName != mUserData->mName)
 
6534
    if (    mUserData->mNameSync
 
6535
         && mUserData.isBackedUp()
 
6536
         && mUserData.backedUpData()->mName != mUserData->mName
 
6537
       )
5915
6538
    {
5916
6539
        aRenamed = true;
5917
6540
 
5918
 
        if (!aNew)
5919
 
        {
5920
 
            /* unlock the old config file */
5921
 
            rc = unlockConfig();
5922
 
            CheckComRCReturnRC (rc);
5923
 
        }
5924
 
 
5925
6541
        bool dirRenamed = false;
5926
6542
        bool fileRenamed = false;
5927
6543
 
5935
6551
            Utf8Str name = mUserData.backedUpData()->mName;
5936
6552
            Utf8Str newName = mUserData->mName;
5937
6553
 
5938
 
            configFile = mData->mConfigFileFull;
 
6554
            configFile = mData->m_strConfigFileFull;
5939
6555
 
5940
6556
            /* first, rename the directory if it matches the machine name */
5941
6557
            configDir = configFile;
5942
 
            RTPathStripFilename (configDir.mutableRaw());
 
6558
            configDir.stripFilename();
5943
6559
            newConfigDir = configDir;
5944
 
            if (RTPathFilename (configDir) == name)
 
6560
            if (!strcmp(RTPathFilename(configDir.c_str()), name.c_str()))
5945
6561
            {
5946
 
                RTPathStripFilename (newConfigDir.mutableRaw());
 
6562
                newConfigDir.stripFilename();
5947
6563
                newConfigDir = Utf8StrFmt ("%s%c%s",
5948
6564
                    newConfigDir.raw(), RTPATH_DELIMITER, newName.raw());
5949
6565
                /* new dir and old dir cannot be equal here because of 'if'
5953
6569
                {
5954
6570
                    /* perform real rename only if the machine is not new */
5955
6571
                    vrc = RTPathRename (configDir.raw(), newConfigDir.raw(), 0);
5956
 
                    if (RT_FAILURE (vrc))
 
6572
                    if (RT_FAILURE(vrc))
5957
6573
                    {
5958
 
                        rc = setError (E_FAIL,
5959
 
                            tr ("Could not rename the directory '%s' to '%s' "
5960
 
                                "to save the settings file (%Rrc)"),
5961
 
                            configDir.raw(), newConfigDir.raw(), vrc);
 
6574
                        rc = setError(E_FAIL,
 
6575
                                      tr("Could not rename the directory '%s' to '%s' to save the settings file (%Rrc)"),
 
6576
                                      configDir.raw(),
 
6577
                                      newConfigDir.raw(),
 
6578
                                      vrc);
5962
6579
                        break;
5963
6580
                    }
5964
6581
                    dirRenamed = true;
5972
6589
            if (newConfigFile != configFile)
5973
6590
            {
5974
6591
                /* get the path to old settings file in renamed directory */
5975
 
                configFile = Utf8StrFmt ("%s%c%s",
5976
 
                        newConfigDir.raw(), RTPATH_DELIMITER,
5977
 
                        RTPathFilename (configFile));
 
6592
                configFile = Utf8StrFmt("%s%c%s",
 
6593
                                        newConfigDir.raw(),
 
6594
                                        RTPATH_DELIMITER,
 
6595
                                        RTPathFilename(configFile.c_str()));
5978
6596
                if (!aNew)
5979
6597
                {
5980
6598
                    /* perform real rename only if the machine is not new */
5981
6599
                    vrc = RTFileRename (configFile.raw(), newConfigFile.raw(), 0);
5982
 
                    if (RT_FAILURE (vrc))
 
6600
                    if (RT_FAILURE(vrc))
5983
6601
                    {
5984
 
                        rc = setError (E_FAIL,
5985
 
                            tr ("Could not rename the settings file '%s' to '%s' "
5986
 
                                "(%Rrc)"),
5987
 
                            configFile.raw(), newConfigFile.raw(), vrc);
 
6602
                        rc = setError(E_FAIL,
 
6603
                                      tr("Could not rename the settings file '%s' to '%s' (%Rrc)"),
 
6604
                                      configFile.raw(),
 
6605
                                      newConfigFile.raw(),
 
6606
                                      vrc);
5988
6607
                        break;
5989
6608
                    }
5990
6609
                    fileRenamed = true;
5991
6610
                }
5992
6611
            }
5993
6612
 
5994
 
            /* update mConfigFileFull amd mConfigFile */
5995
 
            Bstr oldConfigFileFull = mData->mConfigFileFull;
5996
 
            Bstr oldConfigFile = mData->mConfigFile;
5997
 
            mData->mConfigFileFull = newConfigFile;
 
6613
            /* update m_strConfigFileFull amd mConfigFile */
 
6614
            Utf8Str oldConfigFileFull = mData->m_strConfigFileFull;
 
6615
            Utf8Str oldConfigFile = mData->m_strConfigFile;
 
6616
            mData->m_strConfigFileFull = newConfigFile;
5998
6617
            /* try to get the relative path for mConfigFile */
5999
6618
            Utf8Str path = newConfigFile;
6000
6619
            mParent->calculateRelativePath (path, path);
6001
 
            mData->mConfigFile = path;
 
6620
            mData->m_strConfigFile = path;
6002
6621
 
6003
6622
            /* last, try to update the global settings with the new path */
6004
6623
            if (mData->mRegistered)
6005
6624
            {
6006
 
                rc = mParent->updateSettings (configDir, newConfigDir);
6007
 
                if (FAILED (rc))
 
6625
                rc = mParent->updateSettings(configDir.c_str(), newConfigDir.c_str());
 
6626
                if (FAILED(rc))
6008
6627
                {
6009
6628
                    /* revert to old values */
6010
 
                    mData->mConfigFileFull = oldConfigFileFull;
6011
 
                    mData->mConfigFile = oldConfigFile;
 
6629
                    mData->m_strConfigFileFull = oldConfigFileFull;
 
6630
                    mData->m_strConfigFile = oldConfigFile;
6012
6631
                    break;
6013
6632
                }
6014
6633
            }
6015
6634
 
6016
6635
            /* update the snapshot folder */
6017
6636
            path = mUserData->mSnapshotFolderFull;
6018
 
            if (RTPathStartsWith (path, configDir))
 
6637
            if (RTPathStartsWith(path.c_str(), configDir.c_str()))
6019
6638
            {
6020
 
                path = Utf8StrFmt ("%s%s", newConfigDir.raw(),
6021
 
                                   path.raw() + configDir.length());
 
6639
                path = Utf8StrFmt("%s%s", newConfigDir.raw(),
 
6640
                                  path.raw() + configDir.length());
6022
6641
                mUserData->mSnapshotFolderFull = path;
6023
6642
                calculateRelativePath (path, path);
6024
6643
                mUserData->mSnapshotFolder = path;
6026
6645
 
6027
6646
            /* update the saved state file path */
6028
6647
            path = mSSData->mStateFilePath;
6029
 
            if (RTPathStartsWith (path, configDir))
 
6648
            if (RTPathStartsWith(path.c_str(), configDir.c_str()))
6030
6649
            {
6031
 
                path = Utf8StrFmt ("%s%s", newConfigDir.raw(),
6032
 
                                   path.raw() + configDir.length());
 
6650
                path = Utf8StrFmt("%s%s", newConfigDir.raw(),
 
6651
                                  path.raw() + configDir.length());
6033
6652
                mSSData->mStateFilePath = path;
6034
6653
            }
6035
6654
 
6037
6656
             * Note that saveSettings() will recognize name change
6038
6657
             * and will save all snapshots in this case. */
6039
6658
            if (mData->mFirstSnapshot)
6040
 
                mData->mFirstSnapshot->updateSavedStatePaths (configDir,
6041
 
                                                              newConfigDir);
 
6659
                mData->mFirstSnapshot->updateSavedStatePaths(configDir.c_str(),
 
6660
                                                             newConfigDir.c_str());
6042
6661
        }
6043
6662
        while (0);
6044
6663
 
6045
 
        if (FAILED (rc))
 
6664
        if (FAILED(rc))
6046
6665
        {
6047
6666
            /* silently try to rename everything back */
6048
6667
            if (fileRenamed)
6049
 
                RTFileRename (newConfigFile.raw(), configFile.raw(), 0);
 
6668
                RTFileRename(newConfigFile.raw(), configFile.raw(), 0);
6050
6669
            if (dirRenamed)
6051
 
                RTPathRename (newConfigDir.raw(), configDir.raw(), 0);
6052
 
        }
6053
 
 
6054
 
        if (!aNew)
6055
 
        {
6056
 
            /* lock the config again */
6057
 
            HRESULT rc2 = lockConfig();
6058
 
            if (SUCCEEDED (rc))
6059
 
                rc = rc2;
6060
 
        }
6061
 
 
6062
 
        CheckComRCReturnRC (rc);
 
6670
                RTPathRename(newConfigDir.raw(), configDir.raw(), 0);
 
6671
        }
 
6672
 
 
6673
        CheckComRCReturnRC(rc);
6063
6674
    }
6064
6675
 
6065
6676
    if (aNew)
6068
6679
        int vrc = VINF_SUCCESS;
6069
6680
 
6070
6681
        /* ensure the settings directory exists */
6071
 
        Utf8Str path = mData->mConfigFileFull;
6072
 
        RTPathStripFilename (path.mutableRaw());
6073
 
        if (!RTDirExists (path))
 
6682
        Utf8Str path(mData->m_strConfigFileFull);
 
6683
        path.stripFilename();
 
6684
        if (!RTDirExists(path.c_str()))
6074
6685
        {
6075
 
            vrc = RTDirCreateFullPath (path, 0777);
6076
 
            if (RT_FAILURE (vrc))
 
6686
            vrc = RTDirCreateFullPath(path.c_str(), 0777);
 
6687
            if (RT_FAILURE(vrc))
6077
6688
            {
6078
 
                return setError (E_FAIL,
6079
 
                    tr ("Could not create a directory '%s' "
6080
 
                        "to save the settings file (%Rrc)"),
6081
 
                    path.raw(), vrc);
 
6689
                return setError(E_FAIL,
 
6690
                                tr("Could not create a directory '%s' to save the settings file (%Rrc)"),
 
6691
                                path.raw(),
 
6692
                                vrc);
6082
6693
            }
6083
6694
        }
6084
6695
 
6085
6696
        /* Note: open flags must correlate with RTFileOpen() in lockConfig() */
6086
 
        path = Utf8Str (mData->mConfigFileFull);
6087
 
        vrc = RTFileOpen (&mData->mHandleCfgFile, path,
6088
 
                          RTFILE_O_READWRITE | RTFILE_O_CREATE |
6089
 
                          RTFILE_O_DENY_WRITE);
6090
 
        if (RT_SUCCESS (vrc))
6091
 
        {
6092
 
            vrc = RTFileWrite (mData->mHandleCfgFile,
6093
 
                               (void *) gDefaultMachineConfig,
6094
 
                               strlen (gDefaultMachineConfig), NULL);
6095
 
        }
6096
 
        if (RT_FAILURE (vrc))
 
6697
        path = Utf8Str(mData->m_strConfigFileFull);
 
6698
        vrc = RTFileOpen(&mData->mHandleCfgFile, path.c_str(),
 
6699
                         RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
 
6700
        if (RT_FAILURE(vrc))
6097
6701
        {
6098
6702
            mData->mHandleCfgFile = NIL_RTFILE;
6099
 
            return setError (E_FAIL,
6100
 
                tr ("Could not create the settings file '%s' (%Rrc)"),
6101
 
                path.raw(), vrc);
 
6703
            return setError(E_FAIL,
 
6704
                            tr("Could not create the settings file '%s' (%Rrc)"),
 
6705
                            path.raw(),
 
6706
                            vrc);
6102
6707
        }
6103
 
        /* we do not close the file to simulate lockConfig() */
 
6708
        RTFileClose(mData->mHandleCfgFile);
6104
6709
    }
6105
6710
 
6106
6711
    return rc;
6125
6730
 * writing. There is one exception when mParent is unused and therefore may be
6126
6731
 * left unlocked: if this machine is an unregistered one.
6127
6732
 */
6128
 
HRESULT Machine::saveSettings (int aFlags /*= 0*/)
 
6733
HRESULT Machine::saveSettings(int aFlags /*= 0*/)
6129
6734
{
6130
6735
    LogFlowThisFuncEnter();
6131
6736
 
6133
6738
     * registered (see prepareSaveSettings() for details) but we don't
6134
6739
     * currently differentiate it in callers of saveSettings() so we don't
6135
6740
     * make difference here too.  */
6136
 
    AssertReturn (mParent->isWriteLockOnCurrentThread(), E_FAIL);
6137
 
    AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
 
6741
    AssertReturn(mParent->isWriteLockOnCurrentThread(), E_FAIL);
 
6742
    AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
6138
6743
 
6139
6744
    /* make sure child objects are unable to modify the settings while we are
6140
6745
     * saving them */
6141
6746
    ensureNoStateDependencies();
6142
6747
 
6143
 
    AssertReturn (mType == IsMachine || mType == IsSessionMachine, E_FAIL);
 
6748
    AssertReturn(mType == IsMachine || mType == IsSessionMachine, E_FAIL);
6144
6749
 
6145
6750
    BOOL currentStateModified = mData->mCurrentStateModified;
6146
6751
    bool settingsModified;
6168
6773
     * creating a new settings file if this is a new machine. */
6169
6774
    bool isRenamed = false;
6170
6775
    bool isNew = false;
6171
 
    rc = prepareSaveSettings (isRenamed, isNew);
6172
 
    CheckComRCReturnRC (rc);
 
6776
    rc = prepareSaveSettings(isRenamed, isNew);
 
6777
    CheckComRCReturnRC(rc);
6173
6778
 
6174
6779
    try
6175
6780
    {
6176
 
        using namespace settings;
6177
 
        using namespace xml;
6178
 
 
6179
 
        /* this object is locked for writing to prevent concurrent reads and writes */
6180
 
        File file (mData->mHandleCfgFile, Utf8Str (mData->mConfigFileFull));
6181
 
        XmlTreeBackend tree;
6182
 
 
6183
 
        /* The newly created settings file is incomplete therefore we turn off
6184
 
         * validation. The rest is like in loadSettingsTree_ForUpdate().*/
6185
 
        rc = VirtualBox::loadSettingsTree (tree, file,
6186
 
                                           !isNew /* aValidate */,
6187
 
                                           false /* aCatchLoadErrors */,
6188
 
                                           false /* aAddDefaults */);
6189
 
        CheckComRCThrowRC (rc);
6190
 
 
6191
 
        Key machineNode = tree.rootKey().createKey ("Machine");
6192
 
 
6193
 
        /* uuid (required) */
6194
 
        Assert (!mData->mUuid.isEmpty());
6195
 
        machineNode.setValue <Guid> ("uuid", mData->mUuid);
6196
 
 
6197
 
        /* name (required) */
6198
 
        Assert (!mUserData->mName.isEmpty());
6199
 
        machineNode.setValue <Bstr> ("name", mUserData->mName);
6200
 
 
6201
 
        /* nameSync (optional, default is true) */
6202
 
        machineNode.setValueOr <bool> ("nameSync", !!mUserData->mNameSync, true);
6203
 
 
6204
 
        /* Description node (optional) */
6205
 
        if (!mUserData->mDescription.isNull())
6206
 
        {
6207
 
            Key descNode = machineNode.createKey ("Description");
6208
 
            descNode.setKeyValue <Bstr> (mUserData->mDescription);
6209
 
        }
6210
 
        else
6211
 
        {
6212
 
            Key descNode = machineNode.findKey ("Description");
6213
 
            if (!descNode.isNull())
6214
 
                descNode.zap();
6215
 
        }
6216
 
 
6217
 
        /* OSType (required) */
6218
 
        machineNode.setValue <Bstr> ("OSType", mUserData->mOSTypeId);
6219
 
 
6220
 
        /* stateFile (optional) */
6221
 
        /// @todo The reason for MachineState_Restoring below:
6222
 
        /// PushGuestProperties() is always called from Console::powerDown()
6223
 
        /// (including the case when restoring from the saved state fails) and
6224
 
        /// calls SaveSettings() to save guest properties. Since the saved state
6225
 
        /// file is still present there (and should be kept), we must save it
6226
 
        /// while in Restoring state too. However, calling SaveSettings() from
6227
 
        /// PushGuestProperties() is wrong in the first place. A proper way is
6228
 
        /// to only save guest properties node and not involve the whole save
6229
 
        /// process.
6230
 
        if (mData->mMachineState == MachineState_Saved ||
6231
 
            mData->mMachineState == MachineState_Restoring)
6232
 
        {
6233
 
            Assert (!mSSData->mStateFilePath.isEmpty());
 
6781
        mData->m_pMachineConfigFile->uuid = mData->mUuid;
 
6782
        mData->m_pMachineConfigFile->strName = mUserData->mName;
 
6783
        mData->m_pMachineConfigFile->fNameSync = !!mUserData->mNameSync;
 
6784
        mData->m_pMachineConfigFile->strDescription = mUserData->mDescription;
 
6785
        mData->m_pMachineConfigFile->strOsType = mUserData->mOSTypeId;
 
6786
 
 
6787
        if (    mData->mMachineState == MachineState_Saved
 
6788
             || mData->mMachineState == MachineState_Restoring
 
6789
                // when deleting a snapshot we may or may not have a saved state in the current state,
 
6790
                // so let's not assert here please
 
6791
             || (    (mData->mMachineState == MachineState_DeletingSnapshot)
 
6792
                  && (!mSSData->mStateFilePath.isEmpty())
 
6793
                )
 
6794
           )
 
6795
        {
 
6796
            Assert(!mSSData->mStateFilePath.isEmpty());
6234
6797
            /* try to make the file name relative to the settings file dir */
6235
 
            Utf8Str stateFilePath = mSSData->mStateFilePath;
6236
 
            calculateRelativePath (stateFilePath, stateFilePath);
6237
 
            machineNode.setStringValue ("stateFile", stateFilePath);
6238
 
        }
6239
 
        else
6240
 
        {
6241
 
            Assert (mSSData->mStateFilePath.isNull());
6242
 
            machineNode.zapValue ("stateFile");
6243
 
        }
6244
 
 
6245
 
        /* currentSnapshot ID (optional) */
6246
 
        if (!mData->mCurrentSnapshot.isNull())
6247
 
        {
6248
 
            Assert (!mData->mFirstSnapshot.isNull());
6249
 
            machineNode.setValue <Guid> ("currentSnapshot",
6250
 
                                         mData->mCurrentSnapshot->data().mId);
6251
 
        }
6252
 
        else
6253
 
        {
6254
 
            Assert (mData->mFirstSnapshot.isNull());
6255
 
            machineNode.zapValue ("currentSnapshot");
6256
 
        }
6257
 
 
6258
 
        /* snapshotFolder (optional) */
6259
 
        /// @todo use the Bstr::NullOrEmpty constant and setValueOr
6260
 
        if (!mUserData->mSnapshotFolder.isEmpty())
6261
 
            machineNode.setValue <Bstr> ("snapshotFolder", mUserData->mSnapshotFolder);
6262
 
        else
6263
 
            machineNode.zapValue ("snapshotFolder");
6264
 
 
6265
 
        /* currentStateModified (optional, default is true) */
6266
 
        machineNode.setValueOr <bool> ("currentStateModified",
6267
 
                                       !!currentStateModified, true);
6268
 
 
6269
 
        /* lastStateChange */
6270
 
        machineNode.setValue <RTTIMESPEC> ("lastStateChange",
6271
 
                                           mData->mLastStateChange);
6272
 
 
6273
 
        /* set the aborted attribute when appropriate, defaults to false */
6274
 
        machineNode.setValueOr <bool> ("aborted",
6275
 
                                       mData->mMachineState == MachineState_Aborted,
6276
 
                                       false);
6277
 
 
6278
 
        /* Hardware node (required) */
6279
 
        {
6280
 
            /* first, delete the entire node if exists */
6281
 
            Key hwNode = machineNode.findKey ("Hardware");
6282
 
            if (!hwNode.isNull())
6283
 
                hwNode.zap();
6284
 
            /* then recreate it */
6285
 
            hwNode = machineNode.createKey ("Hardware");
6286
 
 
6287
 
            rc = saveHardware (hwNode);
6288
 
            CheckComRCThrowRC (rc);
6289
 
        }
6290
 
 
6291
 
        /* StorageControllers node (required) */
6292
 
        {
6293
 
            /* first, delete the entire node if exists */
6294
 
            Key storageNode = machineNode.findKey ("StorageControllers");
6295
 
            if (!storageNode.isNull())
6296
 
                storageNode.zap();
6297
 
            /* then recreate it */
6298
 
            storageNode = machineNode.createKey ("StorageControllers");
6299
 
 
6300
 
            rc = saveStorageControllers (storageNode);
6301
 
            CheckComRCThrowRC (rc);
6302
 
        }
6303
 
 
6304
 
        /* ask to save all snapshots when the machine name was changed since
6305
 
         * it may affect saved state file paths for online snapshots (see
6306
 
         * #openConfigLoader() for details) */
6307
 
        if (isRenamed)
6308
 
        {
6309
 
            rc = saveSnapshotSettingsWorker (machineNode, NULL,
6310
 
                                             SaveSS_UpdateAllOp);
6311
 
            CheckComRCThrowRC (rc);
6312
 
        }
6313
 
 
6314
 
        /* save the settings on success */
6315
 
        rc = VirtualBox::saveSettingsTree (tree, file,
6316
 
                                           mData->mSettingsFileVersion);
6317
 
        CheckComRCThrowRC (rc);
 
6798
            calculateRelativePath(mSSData->mStateFilePath, mData->m_pMachineConfigFile->strStateFile);
 
6799
        }
 
6800
        else
 
6801
        {
 
6802
            Assert(mSSData->mStateFilePath.isEmpty());
 
6803
            mData->m_pMachineConfigFile->strStateFile.setNull();
 
6804
        }
 
6805
 
 
6806
        if (mData->mCurrentSnapshot)
 
6807
            mData->m_pMachineConfigFile->uuidCurrentSnapshot = mData->mCurrentSnapshot->getId();
 
6808
        else
 
6809
            mData->m_pMachineConfigFile->uuidCurrentSnapshot.clear();
 
6810
 
 
6811
        mData->m_pMachineConfigFile->strSnapshotFolder = mUserData->mSnapshotFolder;
 
6812
        mData->m_pMachineConfigFile->fCurrentStateModified = !!currentStateModified;
 
6813
        mData->m_pMachineConfigFile->timeLastStateChange = mData->mLastStateChange;
 
6814
        mData->m_pMachineConfigFile->fAborted = (mData->mMachineState == MachineState_Aborted);
 
6815
/// @todo Live Migration:        mData->m_pMachineConfigFile->fTeleported = (mData->mMachineState == MachineState_Teleported);
 
6816
 
 
6817
        mData->m_pMachineConfigFile->fTeleporterEnabled    = !!mUserData->mTeleporterEnabled;
 
6818
        mData->m_pMachineConfigFile->uTeleporterPort       = mUserData->mTeleporterPort;
 
6819
        mData->m_pMachineConfigFile->strTeleporterAddress  = mUserData->mTeleporterAddress;
 
6820
        mData->m_pMachineConfigFile->strTeleporterPassword = mUserData->mTeleporterPassword;
 
6821
 
 
6822
        rc = saveHardware(mData->m_pMachineConfigFile->hardwareMachine);
 
6823
        CheckComRCThrowRC(rc);
 
6824
 
 
6825
        rc = saveStorageControllers(mData->m_pMachineConfigFile->storageMachine);
 
6826
        CheckComRCThrowRC(rc);
 
6827
 
 
6828
        // save snapshots
 
6829
        rc = saveAllSnapshots();
 
6830
        CheckComRCThrowRC(rc);
 
6831
 
 
6832
        // now spit it all out
 
6833
        mData->m_pMachineConfigFile->write(mData->m_strConfigFileFull);
6318
6834
    }
6319
6835
    catch (HRESULT err)
6320
6836
    {
6326
6842
        rc = VirtualBox::handleUnexpectedExceptions (RT_SRC_POS);
6327
6843
    }
6328
6844
 
6329
 
    if (SUCCEEDED (rc))
 
6845
    if (SUCCEEDED(rc))
6330
6846
    {
6331
6847
        commit();
6332
6848
 
6342
6858
         * to the client process that creates them) and thus don't need to
6343
6859
         * inform callbacks. */
6344
6860
        if (mType == IsSessionMachine)
6345
 
            mParent->onMachineDataChange (mData->mUuid);
 
6861
            mParent->onMachineDataChange(mData->mUuid);
6346
6862
    }
6347
6863
 
6348
 
    LogFlowThisFunc (("rc=%08X\n", rc));
 
6864
    LogFlowThisFunc(("rc=%08X\n", rc));
6349
6865
    LogFlowThisFuncLeave();
6350
6866
    return rc;
6351
6867
}
6352
6868
 
6353
 
/**
6354
 
 *  Wrapper for #saveSnapshotSettingsWorker() that opens the settings file
6355
 
 *  and locates the <Machine> node in there. See #saveSnapshotSettingsWorker()
6356
 
 *  for more details.
6357
 
 *
6358
 
 *  @param aSnapshot    Snapshot to operate on
6359
 
 *  @param aOpFlags     Operation to perform, one of SaveSS_NoOp, SaveSS_AddOp
6360
 
 *                      or SaveSS_UpdateAttrsOp possibly combined with
6361
 
 *                      SaveSS_UpdateCurrentId.
6362
 
 *
6363
 
 *  @note Locks this object for writing + other child objects.
6364
 
 */
6365
 
HRESULT Machine::saveSnapshotSettings (Snapshot *aSnapshot, int aOpFlags)
 
6869
HRESULT Machine::saveAllSnapshots()
6366
6870
{
6367
 
    AutoCaller autoCaller (this);
6368
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
6369
 
 
6370
 
    AssertReturn (mType == IsMachine || mType == IsSessionMachine, E_FAIL);
6371
 
 
6372
 
    /* This object's write lock is also necessary to serialize file access
6373
 
     * (prevent concurrent reads and writes) */
6374
 
    AutoWriteLock alock (this);
6375
 
 
6376
 
    AssertReturn (isConfigLocked(), E_FAIL);
 
6871
    AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
6377
6872
 
6378
6873
    HRESULT rc = S_OK;
6379
6874
 
6380
6875
    try
6381
6876
    {
6382
 
        using namespace settings;
6383
 
        using namespace xml;
6384
 
 
6385
 
        /* load the settings file */
6386
 
        File file (mData->mHandleCfgFile, Utf8Str (mData->mConfigFileFull));
6387
 
        XmlTreeBackend tree;
6388
 
 
6389
 
        rc = VirtualBox::loadSettingsTree_ForUpdate (tree, file);
6390
 
        CheckComRCReturnRC (rc);
6391
 
 
6392
 
        Key machineNode = tree.rootKey().key ("Machine");
6393
 
 
6394
 
        rc = saveSnapshotSettingsWorker (machineNode, aSnapshot, aOpFlags);
6395
 
        CheckComRCReturnRC (rc);
6396
 
 
6397
 
        /* save settings on success */
6398
 
        rc = VirtualBox::saveSettingsTree (tree, file,
6399
 
                                           mData->mSettingsFileVersion);
6400
 
        CheckComRCReturnRC (rc);
 
6877
        mData->m_pMachineConfigFile->llFirstSnapshot.clear();
 
6878
 
 
6879
        if (mData->mFirstSnapshot)
 
6880
        {
 
6881
            settings::Snapshot snapNew;
 
6882
            mData->m_pMachineConfigFile->llFirstSnapshot.push_back(snapNew);
 
6883
 
 
6884
            // get reference to the fresh copy of the snapshot on the list and
 
6885
            // work on that copy directly to avoid excessive copying later
 
6886
            settings::Snapshot &snap = mData->m_pMachineConfigFile->llFirstSnapshot.front();
 
6887
 
 
6888
            rc = mData->mFirstSnapshot->saveSnapshot(snap, false /*aAttrsOnly*/);
 
6889
            CheckComRCThrowRC(rc);
 
6890
        }
 
6891
 
 
6892
//         if (mType == IsSessionMachine)
 
6893
//             mParent->onMachineDataChange(mData->mUuid);          @todo is this necessary?
 
6894
 
 
6895
    }
 
6896
    catch (HRESULT err)
 
6897
    {
 
6898
        /* we assume that error info is set by the thrower */
 
6899
        rc = err;
6401
6900
    }
6402
6901
    catch (...)
6403
6902
    {
6408
6907
}
6409
6908
 
6410
6909
/**
6411
 
 *  Performs the specified operation on the given snapshot
6412
 
 *  in the settings file represented by \a aMachineNode.
6413
 
 *
6414
 
 *  If \a aOpFlags = SaveSS_UpdateAllOp, \a aSnapshot can be NULL to indicate
6415
 
 *  that the whole tree of the snapshots should be updated in <Machine>.
6416
 
 *  One particular case is when the last (and the only) snapshot should be
6417
 
 *  removed (it is so when both mCurrentSnapshot and mFirstSnapshot are NULL).
6418
 
 *
6419
 
 *  \a aOp may be just SaveSS_UpdateCurrentId if only the currentSnapshot
6420
 
 *  attribute of <Machine> needs to be updated.
6421
 
 *
6422
 
 *  @param aMachineNode <Machine> node in the opened settings file.
6423
 
 *  @param aSnapshot    Snapshot to operate on.
6424
 
 *  @param aOpFlags     Operation to perform, one of SaveSS_NoOp, SaveSS_AddOp
6425
 
 *                      or SaveSS_UpdateAttrsOp possibly combined with
6426
 
 *                      SaveSS_UpdateCurrentId.
6427
 
 *
6428
 
 *  @note Must be called with this object locked for writing.
6429
 
 *        Locks child objects.
6430
 
 */
6431
 
HRESULT Machine::saveSnapshotSettingsWorker (settings::Key &aMachineNode,
6432
 
                                             Snapshot *aSnapshot, int aOpFlags)
6433
 
{
6434
 
    using namespace settings;
6435
 
 
6436
 
    AssertReturn (!aMachineNode.isNull(), E_FAIL);
6437
 
 
6438
 
    AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
6439
 
 
6440
 
    int op = aOpFlags & SaveSS_OpMask;
6441
 
    AssertReturn (
6442
 
        (aSnapshot && (op == SaveSS_AddOp || op == SaveSS_UpdateAttrsOp ||
6443
 
                       op == SaveSS_UpdateAllOp)) ||
6444
 
        (!aSnapshot && ((op == SaveSS_NoOp && (aOpFlags & SaveSS_CurrentId)) ||
6445
 
                        op == SaveSS_UpdateAllOp)),
6446
 
        E_FAIL);
6447
 
 
6448
 
    HRESULT rc = S_OK;
6449
 
 
6450
 
    bool recreateWholeTree = false;
6451
 
 
6452
 
    do
6453
 
    {
6454
 
        if (op == SaveSS_NoOp)
6455
 
            break;
6456
 
 
6457
 
        /* quick path: recreate the whole tree of the snapshots */
6458
 
        if (op == SaveSS_UpdateAllOp && aSnapshot == NULL)
6459
 
        {
6460
 
            /* first, delete the entire root snapshot node if it exists */
6461
 
            Key snapshotNode = aMachineNode.findKey ("Snapshot");
6462
 
            if (!snapshotNode.isNull())
6463
 
                snapshotNode.zap();
6464
 
 
6465
 
            /* second, if we have any snapshots left, substitute aSnapshot
6466
 
             * with the first snapshot to recreate the whole tree, otherwise
6467
 
             * break */
6468
 
            if (mData->mFirstSnapshot)
6469
 
            {
6470
 
                aSnapshot = mData->mFirstSnapshot;
6471
 
                recreateWholeTree = true;
6472
 
            }
6473
 
            else
6474
 
                break;
6475
 
        }
6476
 
 
6477
 
        Assert (!!aSnapshot);
6478
 
        ComObjPtr <Snapshot> parent = aSnapshot->parent();
6479
 
 
6480
 
        if (op == SaveSS_AddOp)
6481
 
        {
6482
 
            Key parentNode;
6483
 
 
6484
 
            if (parent)
6485
 
            {
6486
 
                rc = findSnapshotNode (parent, aMachineNode, NULL, &parentNode);
6487
 
                CheckComRCBreakRC (rc);
6488
 
 
6489
 
                ComAssertBreak (!parentNode.isNull(), rc = E_FAIL);
6490
 
            }
6491
 
 
6492
 
            do
6493
 
            {
6494
 
                Key snapshotsNode;
6495
 
 
6496
 
                if (!parentNode.isNull())
6497
 
                    snapshotsNode = parentNode.createKey ("Snapshots");
6498
 
                else
6499
 
                    snapshotsNode = aMachineNode;
6500
 
                do
6501
 
                {
6502
 
                    Key snapshotNode = snapshotsNode.appendKey ("Snapshot");
6503
 
                    rc = saveSnapshot (snapshotNode, aSnapshot, false /* aAttrsOnly */);
6504
 
                    CheckComRCBreakRC (rc);
6505
 
 
6506
 
                    /* when a new snapshot is added, this means diffs were created
6507
 
                     * for every normal/immutable hard disk of the VM, so we need to
6508
 
                     * save the current hard disk attachments */
6509
 
 
6510
 
                    Key storageNode = aMachineNode.findKey ("StorageControllers");
6511
 
                    if (!storageNode.isNull())
6512
 
                        storageNode.zap();
6513
 
                    storageNode = aMachineNode.createKey ("StorageControllers");
6514
 
 
6515
 
                    rc = saveStorageControllers (storageNode);
6516
 
                    CheckComRCBreakRC (rc);
6517
 
 
6518
 
                    if (mHDData->mAttachments.size() != 0)
6519
 
                    {
6520
 
                        /* If we have one or more attachments then we definitely
6521
 
                         * created diffs for them and associated new diffs with
6522
 
                         * current settngs. So, since we don't use saveSettings(),
6523
 
                         * we need to inform callbacks manually. */
6524
 
                        if (mType == IsSessionMachine)
6525
 
                            mParent->onMachineDataChange (mData->mUuid);
6526
 
                    }
6527
 
                }
6528
 
                while (0);
6529
 
            }
6530
 
            while (0);
6531
 
 
6532
 
            break;
6533
 
        }
6534
 
 
6535
 
        Assert ((op == SaveSS_UpdateAttrsOp && !recreateWholeTree) ||
6536
 
                op == SaveSS_UpdateAllOp);
6537
 
 
6538
 
        Key snapshotsNode;
6539
 
        Key snapshotNode;
6540
 
 
6541
 
        if (!recreateWholeTree)
6542
 
        {
6543
 
            rc = findSnapshotNode (aSnapshot, aMachineNode,
6544
 
                                   &snapshotsNode, &snapshotNode);
6545
 
            CheckComRCBreakRC (rc);
6546
 
        }
6547
 
 
6548
 
        if (snapshotsNode.isNull())
6549
 
            snapshotsNode = aMachineNode;
6550
 
 
6551
 
        if (op == SaveSS_UpdateAttrsOp)
6552
 
            rc = saveSnapshot (snapshotNode, aSnapshot, true /* aAttrsOnly */);
6553
 
        else
6554
 
        {
6555
 
            if (!snapshotNode.isNull())
6556
 
                snapshotNode.zap();
6557
 
 
6558
 
            snapshotNode = snapshotsNode.appendKey ("Snapshot");
6559
 
            rc = saveSnapshot (snapshotNode, aSnapshot, false /* aAttrsOnly */);
6560
 
            CheckComRCBreakRC (rc);
6561
 
        }
6562
 
    }
6563
 
    while (0);
6564
 
 
6565
 
    if (SUCCEEDED (rc))
6566
 
    {
6567
 
        /* update currentSnapshot when appropriate */
6568
 
        if (aOpFlags & SaveSS_CurrentId)
6569
 
        {
6570
 
            if (!mData->mCurrentSnapshot.isNull())
6571
 
                aMachineNode.setValue <Guid> ("currentSnapshot",
6572
 
                                              mData->mCurrentSnapshot->data().mId);
6573
 
            else
6574
 
                aMachineNode.zapValue ("currentSnapshot");
6575
 
        }
6576
 
        if (aOpFlags & SaveSS_CurStateModified)
6577
 
        {
6578
 
            /* defaults to true */
6579
 
            aMachineNode.setValueOr <bool> ("currentStateModified",
6580
 
                                            !!mData->mCurrentStateModified, true);
6581
 
        }
6582
 
    }
6583
 
 
6584
 
    return rc;
6585
 
}
6586
 
 
6587
 
/**
6588
 
 *  Saves the given snapshot and all its children (unless \a aAttrsOnly is true).
6589
 
 *  It is assumed that the given node is empty (unless \a aAttrsOnly is true).
6590
 
 *
6591
 
 *  @param aNode        <Snapshot> node to save the snapshot to.
6592
 
 *  @param aSnapshot    Snapshot to save.
6593
 
 *  @param aAttrsOnly   If true, only updatge user-changeable attrs.
6594
 
 */
6595
 
HRESULT Machine::saveSnapshot (settings::Key &aNode, Snapshot *aSnapshot, bool aAttrsOnly)
6596
 
{
6597
 
    using namespace settings;
6598
 
 
6599
 
    AssertReturn (!aNode.isNull() && aSnapshot, E_INVALIDARG);
6600
 
    AssertReturn (mType == IsMachine || mType == IsSessionMachine, E_FAIL);
6601
 
 
6602
 
    /* uuid (required) */
6603
 
    if (!aAttrsOnly)
6604
 
        aNode.setValue <Guid> ("uuid", aSnapshot->data().mId);
6605
 
 
6606
 
    /* name (required) */
6607
 
    aNode.setValue <Bstr> ("name", aSnapshot->data().mName);
6608
 
 
6609
 
    /* timeStamp (required) */
6610
 
    aNode.setValue <RTTIMESPEC> ("timeStamp", aSnapshot->data().mTimeStamp);
6611
 
 
6612
 
    /* Description node (optional) */
6613
 
    if (!aSnapshot->data().mDescription.isNull())
6614
 
    {
6615
 
        Key descNode = aNode.createKey ("Description");
6616
 
        descNode.setKeyValue <Bstr> (aSnapshot->data().mDescription);
6617
 
    }
6618
 
    else
6619
 
    {
6620
 
        Key descNode = aNode.findKey ("Description");
6621
 
        if (!descNode.isNull())
6622
 
            descNode.zap();
6623
 
    }
6624
 
 
6625
 
    if (aAttrsOnly)
6626
 
        return S_OK;
6627
 
 
6628
 
    /* stateFile (optional) */
6629
 
    if (aSnapshot->stateFilePath())
6630
 
    {
6631
 
        /* try to make the file name relative to the settings file dir */
6632
 
        Utf8Str stateFilePath = aSnapshot->stateFilePath();
6633
 
        calculateRelativePath (stateFilePath, stateFilePath);
6634
 
        aNode.setStringValue ("stateFile", stateFilePath);
6635
 
    }
6636
 
 
6637
 
    {
6638
 
        ComObjPtr <SnapshotMachine> snapshotMachine = aSnapshot->data().mMachine;
6639
 
        ComAssertRet (!snapshotMachine.isNull(), E_FAIL);
6640
 
 
6641
 
        /* save hardware */
6642
 
        {
6643
 
            Key hwNode = aNode.createKey ("Hardware");
6644
 
            HRESULT rc = snapshotMachine->saveHardware (hwNode);
6645
 
            CheckComRCReturnRC (rc);
6646
 
        }
6647
 
 
6648
 
        /* save hard disks. */
6649
 
        {
6650
 
            Key storageNode = aNode.createKey ("StorageControllers");
6651
 
            HRESULT rc = snapshotMachine->saveStorageControllers (storageNode);
6652
 
            CheckComRCReturnRC (rc);
6653
 
        }
6654
 
    }
6655
 
 
6656
 
    /* save children */
6657
 
    {
6658
 
        AutoWriteLock listLock (aSnapshot->childrenLock ());
6659
 
 
6660
 
        if (aSnapshot->children().size())
6661
 
        {
6662
 
            Key snapshotsNode = aNode.createKey ("Snapshots");
6663
 
 
6664
 
            HRESULT rc = S_OK;
6665
 
 
6666
 
            for (Snapshot::SnapshotList::const_iterator it = aSnapshot->children().begin();
6667
 
                 it != aSnapshot->children().end();
6668
 
                 ++ it)
6669
 
            {
6670
 
                Key snapshotNode = snapshotsNode.createKey ("Snapshot");
6671
 
                rc = saveSnapshot (snapshotNode, (*it), aAttrsOnly);
6672
 
                CheckComRCReturnRC (rc);
6673
 
            }
6674
 
        }
6675
 
    }
6676
 
 
6677
 
    return S_OK;
6678
 
}
6679
 
 
6680
 
/**
6681
6910
 *  Saves the VM hardware configuration. It is assumed that the
6682
6911
 *  given node is empty.
6683
6912
 *
6684
6913
 *  @param aNode    <Hardware> node to save the VM hardware confguration to.
6685
6914
 */
6686
 
HRESULT Machine::saveHardware (settings::Key &aNode)
 
6915
HRESULT Machine::saveHardware(settings::Hardware &data)
6687
6916
{
6688
 
    using namespace settings;
6689
 
 
6690
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
6691
 
 
6692
6917
    HRESULT rc = S_OK;
6693
6918
 
6694
 
    /* The hardware version attribute (optional).
6695
 
       Automatically upgrade from 1 to 2 when there is no saved state. (ugly!) */
6696
 
    {
6697
 
        Utf8Str hwVersion = mHWData->mHWVersion;
6698
 
        if (   hwVersion.compare ("1") == 0
6699
 
            && mSSData->mStateFilePath.isEmpty())
6700
 
            mHWData->mHWVersion = hwVersion = "2";  /** @todo Is this safe, to update mHWVersion here? If not some other point needs to be found where this can be done. */
6701
 
        if (hwVersion.compare ("2") == 0)           /** @todo get the default from the schema if possible. */
6702
 
            aNode.zapValue ("version");
6703
 
        else
6704
 
            aNode.setStringValue ("version", hwVersion.raw());
6705
 
    }
6706
 
 
6707
 
    /* CPU (optional, but always created atm) */
6708
 
    {
6709
 
        Key cpuNode = aNode.createKey ("CPU");
6710
 
        Key hwVirtExNode = cpuNode.createKey ("HardwareVirtEx");
6711
 
        const char *value = NULL;
6712
 
        if (mHWData->mHWVirtExEnabled)
6713
 
            value = "true";
6714
 
        else
6715
 
            value = "false";
6716
 
        hwVirtExNode.setStringValue ("enabled", value);
6717
 
 
6718
 
        /* Nested paging (optional, default is false) */
6719
 
        if (mHWData->mHWVirtExNestedPagingEnabled)
6720
 
        {
6721
 
            Key HWVirtExNestedPagingNode = cpuNode.createKey ("HardwareVirtExNestedPaging");
6722
 
            HWVirtExNestedPagingNode.setValue <bool> ("enabled", true);
6723
 
        }
6724
 
 
6725
 
        /* VPID (optional, default is false) */
6726
 
        if (mHWData->mHWVirtExVPIDEnabled)
6727
 
        {
6728
 
            Key HWVirtExVPIDNode = cpuNode.createKey ("HardwareVirtExVPID");
6729
 
            HWVirtExVPIDNode.setValue <bool> ("enabled", true);
6730
 
        }
6731
 
 
6732
 
        /* PAE (optional, default is false) */
6733
 
        if (mHWData->mPAEEnabled)
6734
 
        {
6735
 
            Key PAENode = cpuNode.createKey ("PAE");
6736
 
            PAENode.setValue <bool> ("enabled", true);
6737
 
        }
6738
 
 
6739
 
        /* CPU count */
6740
 
        cpuNode.setValue <ULONG> ("count", mHWData->mCPUCount);
6741
 
    }
6742
 
 
6743
 
    /* memory (required) */
6744
 
    {
6745
 
        Key memoryNode = aNode.createKey ("Memory");
6746
 
        memoryNode.setValue <ULONG> ("RAMSize", mHWData->mMemorySize);
6747
 
    }
6748
 
 
6749
 
    /* boot (required) */
6750
 
    {
6751
 
        Key bootNode = aNode.createKey ("Boot");
6752
 
 
6753
 
        for (ULONG pos = 0; pos < RT_ELEMENTS (mHWData->mBootOrder); ++ pos)
6754
 
        {
6755
 
            const char *device = NULL;
6756
 
            switch (mHWData->mBootOrder [pos])
6757
 
            {
6758
 
                case DeviceType_Null:
6759
 
                    /* skip, this is allowed for <Order> nodes
6760
 
                     * when loading, the default value NoDevice will remain */
6761
 
                    continue;
6762
 
                case DeviceType_Floppy:         device = "Floppy"; break;
6763
 
                case DeviceType_DVD:            device = "DVD"; break;
6764
 
                case DeviceType_HardDisk:       device = "HardDisk"; break;
6765
 
                case DeviceType_Network:        device = "Network"; break;
6766
 
                default:
6767
 
                {
6768
 
                    ComAssertMsgFailedRet (("Invalid boot device: %d",
6769
 
                                            mHWData->mBootOrder [pos]),
6770
 
                                            E_FAIL);
6771
 
                }
6772
 
            }
6773
 
 
6774
 
            Key orderNode = bootNode.appendKey ("Order");
6775
 
            orderNode.setValue <ULONG> ("position", pos + 1);
6776
 
            orderNode.setStringValue ("device", device);
6777
 
        }
6778
 
    }
6779
 
 
6780
 
    /* display (required) */
6781
 
    {
6782
 
        Key displayNode = aNode.createKey ("Display");
6783
 
        displayNode.setValue <ULONG> ("VRAMSize", mHWData->mVRAMSize);
6784
 
        displayNode.setValue <ULONG> ("monitorCount", mHWData->mMonitorCount);
6785
 
        displayNode.setValue <bool> ("accelerate3D", !!mHWData->mAccelerate3DEnabled);
6786
 
    }
 
6919
    try
 
6920
    {
 
6921
        /* The hardware version attribute (optional).
 
6922
            Automatically upgrade from 1 to 2 when there is no saved state. (ugly!) */
 
6923
        if (    mHWData->mHWVersion == "1"
 
6924
             && mSSData->mStateFilePath.isEmpty()
 
6925
           )
 
6926
            mHWData->mHWVersion = "2";  /** @todo Is this safe, to update mHWVersion here? If not some other point needs to be found where this can be done. */
 
6927
 
 
6928
        data.strVersion = mHWData->mHWVersion;
 
6929
        data.uuid = mHWData->mHardwareUUID;
 
6930
 
 
6931
        // CPU
 
6932
        data.fHardwareVirt          = !!mHWData->mHWVirtExEnabled;
 
6933
        data.fHardwareVirtExclusive = !!mHWData->mHWVirtExExclusive;
 
6934
        data.fNestedPaging          = !!mHWData->mHWVirtExNestedPagingEnabled;
 
6935
        data.fVPID                  = !!mHWData->mHWVirtExVPIDEnabled;
 
6936
        data.fPAE                   = !!mHWData->mPAEEnabled;
 
6937
        data.fSyntheticCpu          = !!mHWData->mSyntheticCpu;
 
6938
 
 
6939
        /* Standard and Extended CPUID leafs. */
 
6940
        data.llCpuIdLeafs.clear();
 
6941
        for (unsigned idx = 0; idx < RT_ELEMENTS(mHWData->mCpuIdStdLeafs); idx++)
 
6942
        {
 
6943
            if (mHWData->mCpuIdStdLeafs[idx].ulId != UINT32_MAX)
 
6944
                data.llCpuIdLeafs.push_back(mHWData->mCpuIdStdLeafs[idx]);
 
6945
        }
 
6946
        for (unsigned idx = 0; idx < RT_ELEMENTS(mHWData->mCpuIdExtLeafs); idx++)
 
6947
        {
 
6948
            if (mHWData->mCpuIdExtLeafs[idx].ulId != UINT32_MAX)
 
6949
                data.llCpuIdLeafs.push_back(mHWData->mCpuIdExtLeafs[idx]);
 
6950
        }
 
6951
 
 
6952
        data.cCPUs = mHWData->mCPUCount;
 
6953
 
 
6954
        // memory
 
6955
        data.ulMemorySizeMB = mHWData->mMemorySize;
 
6956
 
 
6957
        // firmware
 
6958
        data.firmwareType = mHWData->mFirmwareType;
 
6959
 
 
6960
        // boot order
 
6961
        data.mapBootOrder.clear();
 
6962
        for (size_t i = 0;
 
6963
             i < RT_ELEMENTS(mHWData->mBootOrder);
 
6964
             ++i)
 
6965
            data.mapBootOrder[i] = mHWData->mBootOrder[i];
 
6966
 
 
6967
        // display
 
6968
        data.ulVRAMSizeMB = mHWData->mVRAMSize;
 
6969
        data.cMonitors = mHWData->mMonitorCount;
 
6970
        data.fAccelerate3D = !!mHWData->mAccelerate3DEnabled;
 
6971
        data.fAccelerate2DVideo = !!mHWData->mAccelerate2DVideoEnabled;
6787
6972
 
6788
6973
#ifdef VBOX_WITH_VRDP
6789
 
    /* VRDP settings (optional) */
6790
 
    rc = mVRDPServer->saveSettings (aNode);
6791
 
    CheckComRCReturnRC (rc);
 
6974
        /* VRDP settings (optional) */
 
6975
        rc = mVRDPServer->saveSettings(data.vrdpSettings);
 
6976
        CheckComRCThrowRC(rc);
6792
6977
#endif
6793
6978
 
6794
 
    /* BIOS (required) */
6795
 
    rc = mBIOSSettings->saveSettings (aNode);
6796
 
    CheckComRCReturnRC (rc);
6797
 
 
6798
 
    /* DVD drive (required) */
6799
 
    rc = mDVDDrive->saveSettings (aNode);
6800
 
    CheckComRCReturnRC (rc);
6801
 
 
6802
 
    /* Flooppy drive (required) */
6803
 
    rc = mFloppyDrive->saveSettings (aNode);
6804
 
    CheckComRCReturnRC (rc);
6805
 
 
6806
 
    /* USB Controller (required) */
6807
 
    rc = mUSBController->saveSettings (aNode);
6808
 
    CheckComRCReturnRC (rc);
6809
 
 
6810
 
    /* Network adapters (required) */
6811
 
    {
6812
 
        Key nwNode = aNode.createKey ("Network");
6813
 
 
6814
 
        for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); ++ slot)
6815
 
        {
6816
 
            Key adapterNode = nwNode.appendKey ("Adapter");
6817
 
 
6818
 
            adapterNode.setValue <ULONG> ("slot", slot);
6819
 
 
6820
 
            rc = mNetworkAdapters [slot]->saveSettings (adapterNode);
6821
 
            CheckComRCReturnRC (rc);
6822
 
        }
6823
 
    }
6824
 
 
6825
 
    /* Serial ports */
6826
 
    {
6827
 
        Key serialNode = aNode.createKey ("UART");
6828
 
 
6829
 
        for (ULONG slot = 0; slot < RT_ELEMENTS (mSerialPorts); ++ slot)
6830
 
        {
6831
 
            Key portNode = serialNode.appendKey ("Port");
6832
 
 
6833
 
            portNode.setValue <ULONG> ("slot", slot);
6834
 
 
6835
 
            rc = mSerialPorts [slot]->saveSettings (portNode);
6836
 
            CheckComRCReturnRC (rc);
6837
 
        }
6838
 
    }
6839
 
 
6840
 
    /* Parallel ports */
6841
 
    {
6842
 
        Key parallelNode = aNode.createKey ("LPT");
6843
 
 
6844
 
        for (ULONG slot = 0; slot < RT_ELEMENTS (mParallelPorts); ++ slot)
6845
 
        {
6846
 
            Key portNode = parallelNode.appendKey ("Port");
6847
 
 
6848
 
            portNode.setValue <ULONG> ("slot", slot);
6849
 
 
6850
 
            rc = mParallelPorts [slot]->saveSettings (portNode);
6851
 
            CheckComRCReturnRC (rc);
6852
 
        }
6853
 
    }
6854
 
 
6855
 
    /* Audio adapter */
6856
 
    rc = mAudioAdapter->saveSettings (aNode);
6857
 
    CheckComRCReturnRC (rc);
6858
 
 
6859
 
    /* Shared folders */
6860
 
    {
6861
 
        Key sharedFoldersNode = aNode.createKey ("SharedFolders");
6862
 
 
 
6979
        /* BIOS (required) */
 
6980
        rc = mBIOSSettings->saveSettings(data.biosSettings);
 
6981
        CheckComRCThrowRC(rc);
 
6982
 
 
6983
        /* USB Controller (required) */
 
6984
        rc = mUSBController->saveSettings(data.usbController);
 
6985
        CheckComRCThrowRC(rc);
 
6986
 
 
6987
        /* Network adapters (required) */
 
6988
        data.llNetworkAdapters.clear();
 
6989
        for (ULONG slot = 0;
 
6990
             slot < RT_ELEMENTS(mNetworkAdapters);
 
6991
             ++slot)
 
6992
        {
 
6993
            settings::NetworkAdapter nic;
 
6994
            nic.ulSlot = slot;
 
6995
            rc = mNetworkAdapters[slot]->saveSettings(nic);
 
6996
            CheckComRCThrowRC(rc);
 
6997
 
 
6998
            data.llNetworkAdapters.push_back(nic);
 
6999
        }
 
7000
 
 
7001
        /* Serial ports */
 
7002
        data.llSerialPorts.clear();
 
7003
        for (ULONG slot = 0;
 
7004
             slot < RT_ELEMENTS(mSerialPorts);
 
7005
             ++slot)
 
7006
        {
 
7007
            settings::SerialPort s;
 
7008
            s.ulSlot = slot;
 
7009
            rc = mSerialPorts[slot]->saveSettings(s);
 
7010
            CheckComRCReturnRC (rc);
 
7011
 
 
7012
            data.llSerialPorts.push_back(s);
 
7013
        }
 
7014
 
 
7015
        /* Parallel ports */
 
7016
        data.llParallelPorts.clear();
 
7017
        for (ULONG slot = 0;
 
7018
             slot < RT_ELEMENTS(mParallelPorts);
 
7019
             ++slot)
 
7020
        {
 
7021
            settings::ParallelPort p;
 
7022
            p.ulSlot = slot;
 
7023
            rc = mParallelPorts[slot]->saveSettings(p);
 
7024
            CheckComRCReturnRC (rc);
 
7025
 
 
7026
            data.llParallelPorts.push_back(p);
 
7027
        }
 
7028
 
 
7029
        /* Audio adapter */
 
7030
        rc = mAudioAdapter->saveSettings(data.audioAdapter);
 
7031
        CheckComRCReturnRC (rc);
 
7032
 
 
7033
        /* Shared folders */
 
7034
        data.llSharedFolders.clear();
6863
7035
        for (HWData::SharedFolderList::const_iterator it = mHWData->mSharedFolders.begin();
6864
 
             it != mHWData->mSharedFolders.end();
6865
 
             ++ it)
6866
 
        {
6867
 
            ComObjPtr <SharedFolder> folder = *it;
6868
 
 
6869
 
            Key folderNode = sharedFoldersNode.appendKey ("SharedFolder");
6870
 
 
6871
 
            /* all are mandatory */
6872
 
            folderNode.setValue <Bstr> ("name", folder->name());
6873
 
            folderNode.setValue <Bstr> ("hostPath", folder->hostPath());
6874
 
            folderNode.setValue <bool> ("writable", !!folder->writable());
6875
 
        }
6876
 
    }
6877
 
 
6878
 
    /* Clipboard */
6879
 
    {
6880
 
        Key clipNode = aNode.createKey ("Clipboard");
6881
 
 
6882
 
        const char *modeStr = "Disabled";
6883
 
        switch (mHWData->mClipboardMode)
6884
 
        {
6885
 
            case ClipboardMode_Disabled:
6886
 
                /* already assigned */
6887
 
                break;
6888
 
            case ClipboardMode_HostToGuest:
6889
 
                modeStr = "HostToGuest";
6890
 
                break;
6891
 
            case ClipboardMode_GuestToHost:
6892
 
                modeStr = "GuestToHost";
6893
 
                break;
6894
 
            case ClipboardMode_Bidirectional:
6895
 
                modeStr = "Bidirectional";
6896
 
                break;
6897
 
            default:
6898
 
                ComAssertMsgFailedRet (("Clipboard mode %d is invalid",
6899
 
                                        mHWData->mClipboardMode),
6900
 
                                       E_FAIL);
6901
 
        }
6902
 
        clipNode.setStringValue ("mode", modeStr);
6903
 
    }
6904
 
 
6905
 
    /* Guest */
6906
 
    {
6907
 
        Key guestNode = aNode.createKey ("Guest");
6908
 
 
6909
 
        guestNode.setValue <ULONG> ("memoryBalloonSize",
6910
 
                                    mHWData->mMemoryBalloonSize);
6911
 
        guestNode.setValue <ULONG> ("statisticsUpdateInterval",
6912
 
                                    mHWData->mStatisticsUpdateInterval);
6913
 
    }
6914
 
 
 
7036
            it != mHWData->mSharedFolders.end();
 
7037
            ++it)
 
7038
        {
 
7039
            ComObjPtr<SharedFolder> pFolder = *it;
 
7040
            settings::SharedFolder sf;
 
7041
            sf.strName = pFolder->getName();
 
7042
            sf.strHostPath = pFolder->getHostPath();
 
7043
            sf.fWritable = !!pFolder->isWritable();
 
7044
 
 
7045
            data.llSharedFolders.push_back(sf);
 
7046
        }
 
7047
 
 
7048
        // clipboard
 
7049
        data.clipboardMode = mHWData->mClipboardMode;
 
7050
 
 
7051
        /* Guest */
 
7052
        data.ulMemoryBalloonSize = mHWData->mMemoryBalloonSize;
 
7053
        data.ulStatisticsUpdateInterval = mHWData->mStatisticsUpdateInterval;
 
7054
 
 
7055
        // guest properties
 
7056
        data.llGuestProperties.clear();
6915
7057
#ifdef VBOX_WITH_GUEST_PROPS
6916
 
    /* Guest properties */
6917
 
    try
6918
 
    {
6919
 
        using namespace guestProp;
6920
 
 
6921
 
        Key guestPropertiesNode = aNode.createKey ("GuestProperties");
6922
 
 
6923
7058
        for (HWData::GuestPropertyList::const_iterator it = mHWData->mGuestProperties.begin();
6924
 
             it != mHWData->mGuestProperties.end(); ++it)
 
7059
             it != mHWData->mGuestProperties.end();
 
7060
             ++it)
6925
7061
        {
6926
7062
            HWData::GuestProperty property = *it;
6927
7063
 
6928
 
            Key propertyNode = guestPropertiesNode.appendKey ("GuestProperty");
6929
 
            char szFlags[MAX_FLAGS_LEN + 1];
 
7064
            settings::GuestProperty prop;
 
7065
            prop.strName = property.strName;
 
7066
            prop.strValue = property.strValue;
 
7067
            prop.timestamp = property.mTimestamp;
 
7068
            char szFlags[guestProp::MAX_FLAGS_LEN + 1];
 
7069
            guestProp::writeFlags(property.mFlags, szFlags);
 
7070
            prop.strFlags = szFlags;
6930
7071
 
6931
 
            propertyNode.setValue <Bstr> ("name", property.mName);
6932
 
            propertyNode.setValue <Bstr> ("value", property.mValue);
6933
 
            propertyNode.setValue <ULONG64> ("timestamp", property.mTimestamp);
6934
 
            writeFlags (property.mFlags, szFlags);
6935
 
            Bstr flags (szFlags);
6936
 
            if (flags.isNull())
6937
 
                return E_OUTOFMEMORY;
6938
 
            propertyNode.setValue <Bstr> ("flags", flags);
 
7072
            data.llGuestProperties.push_back(prop);
6939
7073
        }
6940
 
        Bstr emptyStr ("");
6941
 
        if (emptyStr.isNull())
6942
 
            return E_OUTOFMEMORY;
6943
 
        guestPropertiesNode.setValueOr <Bstr> ("notificationPatterns",
6944
 
                                               mHWData->mGuestPropertyNotificationPatterns,
6945
 
                                               emptyStr);
 
7074
 
 
7075
        data.strNotificationPatterns = mHWData->mGuestPropertyNotificationPatterns;
 
7076
#endif /* VBOX_WITH_GUEST_PROPS defined */
6946
7077
    }
6947
 
    catch (xml::ENoMemory e)
 
7078
    catch(std::bad_alloc &)
6948
7079
    {
6949
7080
        return E_OUTOFMEMORY;
6950
7081
    }
6951
 
#endif /* VBOX_WITH_GUEST_PROPS defined */
6952
7082
 
6953
 
    AssertComRC (rc);
 
7083
    AssertComRC(rc);
6954
7084
    return rc;
6955
7085
}
6956
7086
 
6959
7089
 *
6960
7090
 *  @param aNode    <StorageControllers> node to save the VM hardware confguration to.
6961
7091
 */
6962
 
HRESULT Machine::saveStorageControllers (settings::Key &aNode)
 
7092
HRESULT Machine::saveStorageControllers(settings::Storage &data)
6963
7093
{
6964
 
    using namespace settings;
6965
 
 
6966
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
6967
 
 
6968
 
    for (StorageControllerList::const_iterator
6969
 
         it = mStorageControllers->begin();
 
7094
    data.llStorageControllers.clear();
 
7095
 
 
7096
    for (StorageControllerList::const_iterator it = mStorageControllers->begin();
6970
7097
         it != mStorageControllers->end();
6971
 
         ++ it)
 
7098
         ++it)
6972
7099
    {
6973
7100
        HRESULT rc;
6974
 
        const char *type = NULL;
6975
 
        ComObjPtr <StorageController> ctl = *it;
6976
 
 
6977
 
        Key ctlNode = aNode.appendKey ("StorageController");
6978
 
 
6979
 
        ctlNode.setValue <Bstr> ("name", ctl->name());
6980
 
 
6981
 
        switch (ctl->controllerType())
6982
 
        {
6983
 
            case StorageControllerType_IntelAhci: type = "AHCI"; break;
6984
 
            case StorageControllerType_LsiLogic: type = "LsiLogic"; break;
6985
 
            case StorageControllerType_BusLogic: type = "BusLogic"; break;
6986
 
            case StorageControllerType_PIIX3: type = "PIIX3"; break;
6987
 
            case StorageControllerType_PIIX4: type = "PIIX4"; break;
6988
 
            case StorageControllerType_ICH6: type = "ICH6"; break;
6989
 
            default:
6990
 
                ComAssertFailedRet (E_FAIL);
6991
 
        }
6992
 
 
6993
 
        ctlNode.setStringValue ("type", type);
 
7101
        ComObjPtr<StorageController> pCtl = *it;
 
7102
 
 
7103
        settings::StorageController ctl;
 
7104
        ctl.strName = pCtl->name();
 
7105
        ctl.controllerType = pCtl->controllerType();
 
7106
        ctl.storageBus = pCtl->storageBus();
 
7107
        ctl.ulInstance = pCtl->instance();
6994
7108
 
6995
7109
        /* Save the port count. */
6996
7110
        ULONG portCount;
6997
 
        rc = ctl->COMGETTER(PortCount)(&portCount);
6998
 
        ComAssertRCRet(rc, rc);
6999
 
        ctlNode.setValue <ULONG> ("PortCount", portCount);
 
7111
        rc = pCtl->COMGETTER(PortCount)(&portCount);
 
7112
        ComAssertComRCRet(rc, rc);
 
7113
        ctl.ulPortCount = portCount;
7000
7114
 
7001
7115
        /* Save IDE emulation settings. */
7002
 
        if (ctl->controllerType() == StorageControllerType_IntelAhci)
 
7116
        if (ctl.controllerType == StorageControllerType_IntelAhci)
7003
7117
        {
7004
 
            LONG uVal;
7005
 
 
7006
 
            rc = ctl->GetIDEEmulationPort(0, &uVal);
7007
 
            ComAssertRCRet(rc, rc);
7008
 
            ctlNode.setValue <LONG> ("IDE0MasterEmulationPort", uVal);
7009
 
 
7010
 
            rc = ctl->GetIDEEmulationPort(1, &uVal);
7011
 
            ComAssertRCRet(rc, rc);
7012
 
            ctlNode.setValue <LONG> ("IDE0SlaveEmulationPort", uVal);
7013
 
 
7014
 
            rc = ctl->GetIDEEmulationPort(2, &uVal);
7015
 
            ComAssertRCRet(rc, rc);
7016
 
            ctlNode.setValue <LONG> ("IDE1MasterEmulationPort", uVal);
7017
 
 
7018
 
            rc = ctl->GetIDEEmulationPort(3, &uVal);
7019
 
            ComAssertRCRet(rc, rc);
7020
 
            ctlNode.setValue <LONG> ("IDE1SlaveEmulationPort", uVal);
 
7118
            if (    (FAILED(rc = pCtl->GetIDEEmulationPort(0, (LONG*)&ctl.lIDE0MasterEmulationPort)))
 
7119
                 || (FAILED(rc = pCtl->GetIDEEmulationPort(1, (LONG*)&ctl.lIDE0SlaveEmulationPort)))
 
7120
                 || (FAILED(rc = pCtl->GetIDEEmulationPort(2, (LONG*)&ctl.lIDE1MasterEmulationPort)))
 
7121
                 || (FAILED(rc = pCtl->GetIDEEmulationPort(3, (LONG*)&ctl.lIDE1SlaveEmulationPort)))
 
7122
               )
 
7123
                ComAssertComRCRet(rc, rc);
7021
7124
        }
7022
7125
 
7023
7126
        /* save the devices now. */
7024
 
        rc = saveStorageDevices(ctl, ctlNode);
7025
 
        ComAssertRCRet(rc, rc);
 
7127
        rc = saveStorageDevices(pCtl, ctl);
 
7128
        ComAssertComRCRet(rc, rc);
 
7129
 
 
7130
        data.llStorageControllers.push_back(ctl);
7026
7131
    }
7027
7132
 
7028
7133
    return S_OK;
7030
7135
 
7031
7136
/**
7032
7137
 *  Saves the hard disk confguration.
7033
 
 *  It is assumed that the given node is empty.
7034
 
 *
7035
 
 *  @param aNode    <HardDiskAttachments> node to save the hard disk confguration to.
7036
7138
 */
7037
 
HRESULT Machine::saveStorageDevices (ComObjPtr<StorageController> aStorageController,
7038
 
                                     settings::Key &aNode)
 
7139
HRESULT Machine::saveStorageDevices(ComObjPtr<StorageController> aStorageController,
 
7140
                                    settings::StorageController &data)
7039
7141
{
7040
 
    using namespace settings;
7041
 
 
7042
 
    AssertReturn (!aNode.isNull(), E_INVALIDARG);
7043
 
 
7044
 
    HDData::AttachmentList atts;
7045
 
 
7046
 
    HRESULT rc = getHardDiskAttachmentsOfController(aStorageController->name(), atts);
7047
 
    CheckComRCReturnRC(rc);
7048
 
 
7049
 
    for (HDData::AttachmentList::const_iterator
7050
 
         it = atts.begin();
 
7142
    MediaData::AttachmentList atts;
 
7143
 
 
7144
    HRESULT rc = getMediumAttachmentsOfController(Bstr(aStorageController->name()), atts);
 
7145
    CheckComRCReturnRC (rc);
 
7146
 
 
7147
    data.llAttachedDevices.clear();
 
7148
    for (MediaData::AttachmentList::const_iterator it = atts.begin();
7051
7149
         it != atts.end();
7052
 
         ++ it)
 
7150
         ++it)
7053
7151
    {
7054
 
        Key hdNode = aNode.appendKey ("AttachedDevice");
7055
 
 
 
7152
        settings::AttachedDevice dev;
 
7153
 
 
7154
        MediumAttachment *pAttach = *it;
 
7155
        Medium *pMedium = pAttach->getMedium();
 
7156
 
 
7157
        dev.deviceType = pAttach->getType();
 
7158
        dev.lPort = pAttach->getPort();
 
7159
        dev.lDevice = pAttach->getDevice();
 
7160
        if (pMedium)
7056
7161
        {
7057
 
            /* device type. Only hard disk allowed atm. */
7058
 
            hdNode.setStringValue ("type", "HardDisk");
7059
 
            /* channel (required) */
7060
 
            hdNode.setValue <LONG> ("port", (*it)->port());
7061
 
            /* device (required) */
7062
 
            hdNode.setValue <LONG> ("device", (*it)->device());
7063
 
            /* ID of the image. */
7064
 
            Key idNode = hdNode.appendKey ("Image");
7065
 
            idNode.setValue <Guid> ("uuid", (*it)->hardDisk()->id());
 
7162
            BOOL fHostDrive = FALSE;
 
7163
            rc = pMedium->COMGETTER(HostDrive)(&fHostDrive);
 
7164
            if (FAILED(rc))
 
7165
                return rc;
 
7166
            if (fHostDrive)
 
7167
                dev.strHostDriveSrc = pMedium->getLocation();
 
7168
            else
 
7169
                dev.uuid = pMedium->getId();
 
7170
            dev.fPassThrough = pAttach->getPassthrough();
7066
7171
        }
 
7172
 
 
7173
        data.llAttachedDevices.push_back(dev);
7067
7174
    }
7068
7175
 
7069
7176
    return S_OK;
7077
7184
 *
7078
7185
 *  @note Locks objects for writing.
7079
7186
 */
7080
 
HRESULT Machine::saveStateSettings (int aFlags)
 
7187
HRESULT Machine::saveStateSettings(int aFlags)
7081
7188
{
7082
7189
    if (aFlags == 0)
7083
7190
        return S_OK;
7084
7191
 
7085
7192
    AutoCaller autoCaller (this);
7086
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
 
7193
    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
7087
7194
 
7088
7195
    /* This object's write lock is also necessary to serialize file access
7089
7196
     * (prevent concurrent reads and writes) */
7090
 
    AutoWriteLock alock (this);
7091
 
 
7092
 
    AssertReturn (isConfigLocked(), E_FAIL);
 
7197
    AutoWriteLock alock(this);
7093
7198
 
7094
7199
    HRESULT rc = S_OK;
7095
7200
 
 
7201
    Assert(mData->m_pMachineConfigFile);
 
7202
 
7096
7203
    try
7097
7204
    {
7098
 
        using namespace settings;
7099
 
        using namespace xml;
7100
 
 
7101
 
        /* load the settings file */
7102
 
        File file (mData->mHandleCfgFile, Utf8Str (mData->mConfigFileFull));
7103
 
        XmlTreeBackend tree;
7104
 
 
7105
 
        rc = VirtualBox::loadSettingsTree_ForUpdate (tree, file);
7106
 
        CheckComRCReturnRC (rc);
7107
 
 
7108
 
        Key machineNode = tree.rootKey().key ("Machine");
7109
 
 
7110
7205
        if (aFlags & SaveSTS_CurStateModified)
7111
 
        {
7112
 
            /* defaults to true */
7113
 
            machineNode.setValueOr <bool> ("currentStateModified",
7114
 
                                           !!mData->mCurrentStateModified, true);
7115
 
        }
 
7206
            mData->m_pMachineConfigFile->fCurrentStateModified = true;
7116
7207
 
7117
7208
        if (aFlags & SaveSTS_StateFilePath)
7118
7209
        {
7119
 
            if (mSSData->mStateFilePath)
7120
 
            {
 
7210
            if (!mSSData->mStateFilePath.isEmpty())
7121
7211
                /* try to make the file name relative to the settings file dir */
7122
 
                Utf8Str stateFilePath = mSSData->mStateFilePath;
7123
 
                calculateRelativePath (stateFilePath, stateFilePath);
7124
 
                machineNode.setStringValue ("stateFile", stateFilePath);
7125
 
            }
 
7212
                calculateRelativePath(mSSData->mStateFilePath, mData->m_pMachineConfigFile->strStateFile);
7126
7213
            else
7127
 
                machineNode.zapValue ("stateFile");
 
7214
                mData->m_pMachineConfigFile->strStateFile.setNull();
7128
7215
        }
7129
7216
 
7130
7217
        if (aFlags & SaveSTS_StateTimeStamp)
7131
7218
        {
7132
 
            Assert (mData->mMachineState != MachineState_Aborted ||
7133
 
                    mSSData->mStateFilePath.isNull());
7134
 
 
7135
 
            machineNode.setValue <RTTIMESPEC> ("lastStateChange",
7136
 
                                               mData->mLastStateChange);
7137
 
 
7138
 
            /* set the aborted attribute when appropriate, defaults to false */
7139
 
            machineNode.setValueOr <bool> ("aborted",
7140
 
                                           mData->mMachineState == MachineState_Aborted,
7141
 
                                           false);
 
7219
            Assert(    mData->mMachineState != MachineState_Aborted
 
7220
                    || mSSData->mStateFilePath.isEmpty());
 
7221
 
 
7222
            mData->m_pMachineConfigFile->timeLastStateChange = mData->mLastStateChange;
 
7223
 
 
7224
            mData->m_pMachineConfigFile->fAborted = (mData->mMachineState == MachineState_Aborted);
 
7225
//@todo live migration             mData->m_pMachineConfigFile->fTeleported = (mData->mMachineState == MachineState_Teleported);
7142
7226
        }
7143
7227
 
7144
 
        /* save settings on success */
7145
 
        rc = VirtualBox::saveSettingsTree (tree, file,
7146
 
                                           mData->mSettingsFileVersion);
7147
 
        CheckComRCReturnRC (rc);
 
7228
        mData->m_pMachineConfigFile->write(mData->m_strConfigFileFull);
7148
7229
    }
7149
7230
    catch (...)
7150
7231
    {
7160
7241
 *
7161
7242
 * Used when taking a snapshot or when discarding the current state.
7162
7243
 *
7163
 
 * This method assumes that mHDData contains the original hard disk attachments
 
7244
 * This method assumes that mMediaData contains the original hard disk attachments
7164
7245
 * it needs to create diffs for. On success, these attachments will be replaced
7165
7246
 * with the created diffs. On failure, #deleteImplicitDiffs() is implicitly
7166
 
 * called to delete created diffs which will also rollback mHDData and restore
 
7247
 * called to delete created diffs which will also rollback mMediaData and restore
7167
7248
 * whatever was backed up before calling this method.
7168
7249
 *
7169
7250
 * Attachments with non-normal hard disks are left as is.
7185
7266
 *
7186
7267
 * @note Locks this object for writing.
7187
7268
 */
7188
 
HRESULT Machine::createImplicitDiffs (const Bstr &aFolder,
7189
 
                                      ComObjPtr <Progress> &aProgress,
7190
 
                                      bool aOnline)
 
7269
HRESULT Machine::createImplicitDiffs(const Bstr &aFolder,
 
7270
                                     IProgress *aProgress,
 
7271
                                     ULONG aWeight,
 
7272
                                     bool aOnline)
7191
7273
{
7192
 
    AssertReturn (!aFolder.isEmpty(), E_FAIL);
7193
 
 
7194
 
    AutoCaller autoCaller (this);
 
7274
    AssertReturn(!aFolder.isEmpty(), E_FAIL);
 
7275
 
 
7276
    LogFlowThisFunc(("aFolder='%ls', aOnline=%d\n", aFolder.raw(), aOnline));
 
7277
 
 
7278
    AutoCaller autoCaller(this);
7195
7279
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
7196
7280
 
7197
 
    AutoWriteLock alock (this);
 
7281
    AutoWriteLock alock(this);
7198
7282
 
7199
7283
    /* must be in a protective state because we leave the lock below */
7200
 
    AssertReturn (mData->mMachineState == MachineState_Saving ||
7201
 
                  mData->mMachineState == MachineState_Discarding, E_FAIL);
 
7284
    AssertReturn(   mData->mMachineState == MachineState_Saving
 
7285
                 || mData->mMachineState == MachineState_LiveSnapshotting
 
7286
                 || mData->mMachineState == MachineState_RestoringSnapshot
 
7287
                 || mData->mMachineState == MachineState_DeletingSnapshot
 
7288
                 , E_FAIL);
7202
7289
 
7203
7290
    HRESULT rc = S_OK;
7204
7291
 
7205
 
    typedef std::list< ComObjPtr<HardDisk> > LockedMedia;
 
7292
    typedef std::list< ComObjPtr<Medium> > LockedMedia;
7206
7293
    LockedMedia lockedMedia;
7207
7294
 
7208
7295
    try
7211
7298
        {
7212
7299
            /* lock all attached hard disks early to detect "in use"
7213
7300
             * situations before creating actual diffs */
7214
 
            for (HDData::AttachmentList::const_iterator
7215
 
                 it = mHDData->mAttachments.begin();
7216
 
                 it != mHDData->mAttachments.end();
7217
 
                 ++ it)
 
7301
            for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
7302
                 it != mMediaData->mAttachments.end();
 
7303
                 ++it)
7218
7304
            {
7219
 
                ComObjPtr<HardDiskAttachment> hda = *it;
7220
 
                ComObjPtr<HardDisk> hd = hda->hardDisk();
7221
 
 
7222
 
                rc = hd->LockRead (NULL);
7223
 
                CheckComRCThrowRC (rc);
7224
 
 
7225
 
                lockedMedia.push_back (hd);
 
7305
                MediumAttachment* pAtt = *it;
 
7306
                if (pAtt->getType() == DeviceType_HardDisk)
 
7307
                {
 
7308
                    Medium* pHD = pAtt->getMedium();
 
7309
                    Assert(pHD);
 
7310
                    rc = pHD->LockRead (NULL);
 
7311
                    CheckComRCThrowRC(rc);
 
7312
                    lockedMedia.push_back(pHD);
 
7313
                }
7226
7314
            }
7227
7315
        }
7228
7316
 
7229
7317
        /* remember the current list (note that we don't use backup() since
7230
 
         * mHDData may be already backed up) */
7231
 
        HDData::AttachmentList atts = mHDData->mAttachments;
 
7318
         * mMediaData may be already backed up) */
 
7319
        MediaData::AttachmentList atts = mMediaData->mAttachments;
7232
7320
 
7233
7321
        /* start from scratch */
7234
 
        mHDData->mAttachments.clear();
 
7322
        mMediaData->mAttachments.clear();
7235
7323
 
7236
7324
        /* go through remembered attachments and create diffs for normal hard
7237
7325
         * disks and attach them */
7238
 
 
7239
 
        for (HDData::AttachmentList::const_iterator
7240
 
             it = atts.begin(); it != atts.end(); ++ it)
 
7326
        for (MediaData::AttachmentList::const_iterator it = atts.begin();
 
7327
             it != atts.end();
 
7328
             ++it)
7241
7329
        {
7242
 
            ComObjPtr<HardDiskAttachment> hda = *it;
7243
 
            ComObjPtr<HardDisk> hd = hda->hardDisk();
7244
 
 
7245
 
            /* type cannot be changed while attached => no need to lock */
7246
 
            if (hd->type() != HardDiskType_Normal)
 
7330
            MediumAttachment* pAtt = *it;
 
7331
 
 
7332
            DeviceType_T devType = pAtt->getType();
 
7333
            Medium* medium = pAtt->getMedium();
 
7334
 
 
7335
            if (   devType != DeviceType_HardDisk
 
7336
                || medium == NULL
 
7337
                || medium->getType() != MediumType_Normal)
7247
7338
            {
7248
7339
                /* copy the attachment as is */
7249
7340
 
7250
 
                Assert (hd->type() == HardDiskType_Writethrough);
7251
 
 
7252
 
                rc = aProgress->setNextOperation(BstrFmt(tr("Skipping writethrough hard disk '%s'"),
7253
 
                                                         hd->root()->name().raw()),
7254
 
                                                 1);        // weight
7255
 
                CheckComRCThrowRC (rc);
7256
 
 
7257
 
                mHDData->mAttachments.push_back (hda);
 
7341
                /** @todo the progress object created in Console::TakeSnaphot
 
7342
                 * only expects operations for hard disks. Later other
 
7343
                 * device types need to show up in the progress as well. */
 
7344
                if (devType == DeviceType_HardDisk)
 
7345
                {
 
7346
                    if (medium == NULL)
 
7347
                        aProgress->SetNextOperation(Bstr(tr("Skipping attachment without medium")),
 
7348
                                                    aWeight);        // weight
 
7349
                    else
 
7350
                        aProgress->SetNextOperation(BstrFmt(tr("Skipping medium '%s'"),
 
7351
                                                            medium->getBase()->getName().raw()),
 
7352
                                                    aWeight);        // weight
 
7353
                }
 
7354
 
 
7355
                mMediaData->mAttachments.push_back(pAtt);
7258
7356
                continue;
7259
7357
            }
7260
7358
 
7261
7359
            /* need a diff */
7262
 
 
7263
 
            rc = aProgress->setNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
7264
 
                                                     hd->root()->name().raw()),
7265
 
                                             1);        // weight
7266
 
            CheckComRCThrowRC (rc);
7267
 
 
7268
 
            ComObjPtr<HardDisk> diff;
 
7360
            aProgress->SetNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
 
7361
                                                medium->getBase()->getName().raw()),
 
7362
                                        aWeight);        // weight
 
7363
 
 
7364
            ComObjPtr<Medium> diff;
7269
7365
            diff.createObject();
7270
 
            rc = diff->init (mParent, hd->preferredDiffFormat(),
7271
 
                             BstrFmt ("%ls"RTPATH_SLASH_STR,
7272
 
                                      mUserData->mSnapshotFolderFull.raw()));
7273
 
            CheckComRCThrowRC (rc);
 
7366
            rc = diff->init(mParent,
 
7367
                            medium->preferredDiffFormat().raw(),
 
7368
                            BstrFmt("%ls"RTPATH_SLASH_STR,
 
7369
                                    mUserData->mSnapshotFolderFull.raw()).raw());
 
7370
            CheckComRCThrowRC(rc);
7274
7371
 
7275
7372
            /* leave the lock before the potentially lengthy operation */
7276
7373
            alock.leave();
7277
7374
 
7278
 
            rc = hd->createDiffStorageAndWait (diff, HardDiskVariant_Standard,
7279
 
                                               &aProgress);
 
7375
            rc = medium->createDiffStorageAndWait(diff,
 
7376
                                                  MediumVariant_Standard,
 
7377
                                                  NULL);
 
7378
 
 
7379
            /** @todo r=bird: How is the locking and diff image cleaned up if we fail before
 
7380
             *        the push_back?  Looks like we're going to leave medium with the
 
7381
             *        wrong kind of lock (general issue with if we fail anywhere at all)
 
7382
             *        and an orphaned VDI in the snapshots folder. */
 
7383
            // at this point, the old image is still locked for writing, but instead
 
7384
            // we need the new diff image locked for writing and lock the previously
 
7385
            // current one for reading only
 
7386
            if (aOnline)
 
7387
            {
 
7388
                diff->LockWrite(NULL);
 
7389
                mData->mSession.mLockedMedia.push_back(Data::Session::LockedMedia::value_type(ComPtr<IMedium>(diff), true));
 
7390
                medium->UnlockWrite(NULL);
 
7391
                medium->LockRead(NULL);
 
7392
                mData->mSession.mLockedMedia.push_back(Data::Session::LockedMedia::value_type(ComPtr<IMedium>(medium), false));
 
7393
            }
7280
7394
 
7281
7395
            alock.enter();
7282
7396
 
7283
 
            CheckComRCThrowRC (rc);
 
7397
            CheckComRCThrowRC(rc);
7284
7398
 
7285
 
            rc = diff->attachTo (mData->mUuid);
7286
 
            AssertComRCThrowRC (rc);
 
7399
            rc = diff->attachTo(mData->mUuid);
 
7400
            AssertComRCThrowRC(rc);
7287
7401
 
7288
7402
            /* add a new attachment */
7289
 
            ComObjPtr<HardDiskAttachment> attachment;
 
7403
            ComObjPtr<MediumAttachment> attachment;
7290
7404
            attachment.createObject();
7291
 
            rc = attachment->init (diff, hda->controller(), hda->port(),
7292
 
                                   hda->device(), true /* aImplicit */);
7293
 
            CheckComRCThrowRC (rc);
 
7405
            rc = attachment->init(this,
 
7406
                                  diff,
 
7407
                                  pAtt->getControllerName(),
 
7408
                                  pAtt->getPort(),
 
7409
                                  pAtt->getDevice(),
 
7410
                                  DeviceType_HardDisk,
 
7411
                                  true /* aImplicit */);
 
7412
            CheckComRCThrowRC(rc);
7294
7413
 
7295
 
            mHDData->mAttachments.push_back (attachment);
 
7414
            mMediaData->mAttachments.push_back(attachment);
7296
7415
        }
7297
7416
    }
7298
7417
    catch (HRESULT aRC) { rc = aRC; }
7303
7422
        ErrorInfoKeeper eik;
7304
7423
 
7305
7424
        for (LockedMedia::const_iterator it = lockedMedia.begin();
7306
 
             it != lockedMedia.end(); ++ it)
 
7425
             it != lockedMedia.end();
 
7426
             ++it)
7307
7427
        {
7308
 
            HRESULT rc2 = (*it)->UnlockRead (NULL);
7309
 
            AssertComRC (rc2);
 
7428
            HRESULT rc2 = (*it)->UnlockRead(NULL);
 
7429
            AssertComRC(rc2);
7310
7430
        }
7311
7431
    }
7312
7432
 
7313
 
    if (FAILED (rc))
 
7433
    if (FAILED(rc))
7314
7434
    {
7315
7435
        MultiResultRef mrc (rc);
7316
7436
 
7322
7442
 
7323
7443
/**
7324
7444
 * Deletes implicit differencing hard disks created either by
7325
 
 * #createImplicitDiffs() or by #AttachHardDisk() and rolls back mHDData.
 
7445
 * #createImplicitDiffs() or by #AttachMedium() and rolls back mMediaData.
7326
7446
 *
7327
 
 * Note that to delete hard disks created by #AttachHardDisk() this method is
7328
 
 * called from #fixupHardDisks() when the changes are rolled back.
 
7447
 * Note that to delete hard disks created by #AttachMedium() this method is
 
7448
 * called from #fixupMedia() when the changes are rolled back.
7329
7449
 *
7330
7450
 * @note Locks this object for writing.
7331
7451
 */
7332
7452
HRESULT Machine::deleteImplicitDiffs()
7333
7453
{
7334
 
    AutoCaller autoCaller (this);
 
7454
    AutoCaller autoCaller(this);
7335
7455
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
7336
7456
 
7337
 
    AutoWriteLock alock (this);
 
7457
    AutoWriteLock alock(this);
 
7458
    LogFlowThisFuncEnter();
7338
7459
 
7339
 
    AssertReturn (mHDData.isBackedUp(), E_FAIL);
 
7460
    AssertReturn(mMediaData.isBackedUp(), E_FAIL);
7340
7461
 
7341
7462
    HRESULT rc = S_OK;
7342
7463
 
7343
 
    HDData::AttachmentList implicitAtts;
 
7464
    MediaData::AttachmentList implicitAtts;
7344
7465
 
7345
 
    const HDData::AttachmentList &oldAtts =
7346
 
        mHDData.backedUpData()->mAttachments;
 
7466
    const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
7347
7467
 
7348
7468
    /* enumerate new attachments */
7349
 
    for (HDData::AttachmentList::const_iterator
7350
 
            it = mHDData->mAttachments.begin();
7351
 
         it != mHDData->mAttachments.end(); ++ it)
 
7469
    for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
7470
         it != mMediaData->mAttachments.end();
 
7471
         ++it)
7352
7472
    {
7353
 
        ComObjPtr<HardDisk> hd = (*it)->hardDisk();
 
7473
        ComObjPtr<Medium> hd = (*it)->getMedium();
 
7474
        if (hd.isNull())
 
7475
            continue;
7354
7476
 
7355
7477
        if ((*it)->isImplicit())
7356
7478
        {
7357
7479
            /* deassociate and mark for deletion */
7358
 
            rc = hd->detachFrom (mData->mUuid);
7359
 
            AssertComRC (rc);
 
7480
            LogFlowThisFunc(("Detaching '%s', pending deletion\n", (*it)->getLogName()));
 
7481
            rc = hd->detachFrom(mData->mUuid);
 
7482
            AssertComRC(rc);
7360
7483
            implicitAtts.push_back (*it);
7361
7484
            continue;
7362
7485
        }
7363
7486
 
7364
7487
        /* was this hard disk attached before? */
7365
 
        HDData::AttachmentList::const_iterator oldIt =
7366
 
            std::find_if(oldAtts.begin(), oldAtts.end(),
7367
 
                         HardDiskAttachment::RefersTo (hd));
7368
 
        if (oldIt == oldAtts.end())
 
7488
        if (!findAttachment(oldAtts, hd))
7369
7489
        {
7370
7490
            /* no: de-associate */
7371
 
            rc = hd->detachFrom (mData->mUuid);
7372
 
            AssertComRC (rc);
 
7491
            LogFlowThisFunc(("Detaching '%s', no deletion\n", (*it)->getLogName()));
 
7492
            rc = hd->detachFrom(mData->mUuid);
 
7493
            AssertComRC(rc);
7373
7494
            continue;
7374
7495
        }
 
7496
        LogFlowThisFunc(("Not detaching '%s'\n", (*it)->getLogName()));
7375
7497
    }
7376
7498
 
7377
7499
    /* rollback hard disk changes */
7378
 
    mHDData.rollback();
 
7500
    mMediaData.rollback();
7379
7501
 
7380
7502
    MultiResult mrc (S_OK);
7381
7503
 
7386
7508
         * operation, so protect with the special state (unless already
7387
7509
         * protected) */
7388
7510
        MachineState_T oldState = mData->mMachineState;
7389
 
        if (oldState != MachineState_Saving &&
7390
 
            oldState != MachineState_Discarding)
7391
 
        {
 
7511
        if (    oldState != MachineState_Saving
 
7512
             && oldState != MachineState_LiveSnapshotting
 
7513
             && oldState != MachineState_RestoringSnapshot
 
7514
             && oldState != MachineState_DeletingSnapshot
 
7515
           )
7392
7516
            setMachineState (MachineState_SettingUp);
7393
 
        }
7394
7517
 
7395
7518
        alock.leave();
7396
7519
 
7397
 
        for (HDData::AttachmentList::const_iterator
7398
 
                it = implicitAtts.begin();
7399
 
             it != implicitAtts.end(); ++ it)
 
7520
        for (MediaData::AttachmentList::const_iterator it = implicitAtts.begin();
 
7521
             it != implicitAtts.end();
 
7522
             ++it)
7400
7523
        {
7401
 
            ComObjPtr<HardDisk> hd = (*it)->hardDisk();
 
7524
            LogFlowThisFunc(("Deleting '%s'\n", (*it)->getLogName()));
 
7525
            ComObjPtr<Medium> hd = (*it)->getMedium();
7402
7526
 
7403
 
            mrc = hd->deleteStorageAndWait();
 
7527
            rc = hd->deleteStorageAndWait();
 
7528
#if 1 /* HACK ALERT: Just make it kind of work */ /** @todo Fix this hack properly. The LockWrite / UnlockWrite / LockRead changes aren't undone! */
 
7529
            if (rc == VBOX_E_INVALID_OBJECT_STATE)
 
7530
            {
 
7531
                LogFlowFunc(("Applying unlock hack on '%s'! FIXME!\n", (*it)->getLogName()));
 
7532
                hd->UnlockWrite(NULL);
 
7533
                rc = hd->deleteStorageAndWait();
 
7534
            }
 
7535
#endif
 
7536
            AssertMsg(SUCCEEDED(rc), ("rc=%Rhrc it=%s hd=%s\n", rc, (*it)->getLogName(), hd->getLocationFull().c_str() ));
 
7537
            mrc = rc;
7404
7538
        }
7405
7539
 
7406
7540
        alock.enter();
7415
7549
}
7416
7550
 
7417
7551
/**
 
7552
 * Looks through the given list of media attachments for one with the given parameters
 
7553
 * and returns it, or NULL if not found. The list is a parameter so that backup lists
 
7554
 * can be searched as well if needed.
 
7555
 *
 
7556
 * @param list
 
7557
 * @param aControllerName
 
7558
 * @param aControllerPort
 
7559
 * @param aDevice
 
7560
 * @return
 
7561
 */
 
7562
MediumAttachment* Machine::findAttachment(const MediaData::AttachmentList &ll,
 
7563
                                          IN_BSTR aControllerName,
 
7564
                                          LONG aControllerPort,
 
7565
                                          LONG aDevice)
 
7566
{
 
7567
   for (MediaData::AttachmentList::const_iterator it = ll.begin();
 
7568
         it != ll.end();
 
7569
         ++it)
 
7570
    {
 
7571
        MediumAttachment *pAttach = *it;
 
7572
        if (pAttach->matches(aControllerName, aControllerPort, aDevice))
 
7573
            return pAttach;
 
7574
    }
 
7575
 
 
7576
    return NULL;
 
7577
}
 
7578
 
 
7579
/**
 
7580
 * Looks through the given list of media attachments for one with the given parameters
 
7581
 * and returns it, or NULL if not found. The list is a parameter so that backup lists
 
7582
 * can be searched as well if needed.
 
7583
 *
 
7584
 * @param list
 
7585
 * @param aControllerName
 
7586
 * @param aControllerPort
 
7587
 * @param aDevice
 
7588
 * @return
 
7589
 */
 
7590
MediumAttachment* Machine::findAttachment(const MediaData::AttachmentList &ll,
 
7591
                                          ComObjPtr<Medium> pMedium)
 
7592
{
 
7593
   for (MediaData::AttachmentList::const_iterator it = ll.begin();
 
7594
         it != ll.end();
 
7595
         ++it)
 
7596
    {
 
7597
        MediumAttachment *pAttach = *it;
 
7598
        ComObjPtr<Medium> pMediumThis = pAttach->getMedium();
 
7599
        if (pMediumThis.equalsTo(pMedium))
 
7600
            return pAttach;
 
7601
    }
 
7602
 
 
7603
    return NULL;
 
7604
}
 
7605
 
 
7606
/**
 
7607
 * Looks through the given list of media attachments for one with the given parameters
 
7608
 * and returns it, or NULL if not found. The list is a parameter so that backup lists
 
7609
 * can be searched as well if needed.
 
7610
 *
 
7611
 * @param list
 
7612
 * @param aControllerName
 
7613
 * @param aControllerPort
 
7614
 * @param aDevice
 
7615
 * @return
 
7616
 */
 
7617
MediumAttachment* Machine::findAttachment(const MediaData::AttachmentList &ll,
 
7618
                                          Guid &id)
 
7619
{
 
7620
   for (MediaData::AttachmentList::const_iterator it = ll.begin();
 
7621
         it != ll.end();
 
7622
         ++it)
 
7623
    {
 
7624
        MediumAttachment *pAttach = *it;
 
7625
        ComObjPtr<Medium> pMediumThis = pAttach->getMedium();
 
7626
        if (pMediumThis->getId() == id)
 
7627
            return pAttach;
 
7628
    }
 
7629
 
 
7630
    return NULL;
 
7631
}
 
7632
 
 
7633
/**
7418
7634
 * Perform deferred hard disk detachments on success and deletion of implicitly
7419
7635
 * created diffs on failure.
7420
7636
 *
7421
 
 * Does nothing if the hard disk attachment data (mHDData) is not changed (not
 
7637
 * Does nothing if the hard disk attachment data (mMediaData) is not changed (not
7422
7638
 * backed up).
7423
7639
 *
7424
 
 * When the data is backed up, this method will commit mHDData if @a aCommit is
 
7640
 * When the data is backed up, this method will commit mMediaData if @a aCommit is
7425
7641
 * @c true and rollback it otherwise before returning.
7426
7642
 *
7427
7643
 * If @a aOnline is @c true then this method called with @a aCommit = @c true
7434
7650
 *
7435
7651
 * @note Locks this object for writing!
7436
7652
 */
7437
 
void Machine::fixupHardDisks(bool aCommit, bool aOnline /*= false*/)
 
7653
void Machine::fixupMedia(bool aCommit, bool aOnline /*= false*/)
7438
7654
{
7439
 
    AutoCaller autoCaller (this);
 
7655
    AutoCaller autoCaller(this);
7440
7656
    AssertComRCReturnVoid (autoCaller.rc());
7441
7657
 
7442
 
    AutoWriteLock alock (this);
 
7658
    AutoWriteLock alock(this);
 
7659
 
 
7660
    LogFlowThisFunc(("Entering, aCommit=%d, aOnline=%d\n", aCommit, aOnline));
 
7661
 
 
7662
    HRESULT rc = S_OK;
7443
7663
 
7444
7664
    /* no attach/detach operations -- nothing to do */
7445
 
    if (!mHDData.isBackedUp())
 
7665
    if (!mMediaData.isBackedUp())
7446
7666
        return;
7447
7667
 
7448
 
    HRESULT rc = S_OK;
7449
 
 
7450
7668
    if (aCommit)
7451
7669
    {
7452
 
        HDData::AttachmentList &oldAtts =
7453
 
            mHDData.backedUpData()->mAttachments;
 
7670
        MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
7454
7671
 
7455
7672
        /* enumerate new attachments */
7456
 
        for (HDData::AttachmentList::const_iterator
7457
 
             it = mHDData->mAttachments.begin();
7458
 
             it != mHDData->mAttachments.end(); ++ it)
 
7673
        for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
7674
             it != mMediaData->mAttachments.end();
 
7675
             ++it)
7459
7676
        {
7460
 
            ComObjPtr<HardDisk> hd = (*it)->hardDisk();
7461
 
 
7462
 
            if ((*it)->isImplicit())
 
7677
            MediumAttachment *pAttach = *it;
 
7678
 
 
7679
            pAttach->commit();
 
7680
 
 
7681
            Medium* pMedium = pAttach->getMedium();
 
7682
            bool fImplicit = pAttach->isImplicit();
 
7683
 
 
7684
            LogFlowThisFunc(("Examining current medium '%s' (implicit: %d)\n",
 
7685
                             (pMedium) ? pMedium->getName().raw() : "NULL",
 
7686
                             fImplicit));
 
7687
 
 
7688
            /** @todo convert all this Machine-based voodoo to MediumAttachment
 
7689
            * based commit logic. */
 
7690
            if (fImplicit)
7463
7691
            {
7464
7692
                /* convert implicit attachment to normal */
7465
 
                (*it)->setImplicit (false);
 
7693
                pAttach->setImplicit(false);
7466
7694
 
7467
 
                if (aOnline)
 
7695
                if (    aOnline
 
7696
                     && pMedium
 
7697
                     && pAttach->getType() == DeviceType_HardDisk
 
7698
                   )
7468
7699
                {
7469
 
                    rc = hd->LockWrite (NULL);
7470
 
                    AssertComRC (rc);
 
7700
                    rc = pMedium->LockWrite(NULL);
 
7701
                    AssertComRC(rc);
7471
7702
 
7472
 
                    mData->mSession.mLockedMedia.push_back (
7473
 
                        Data::Session::LockedMedia::value_type (
7474
 
                            ComPtr <IHardDisk> (hd), true));
 
7703
                    mData->mSession.mLockedMedia.push_back(
 
7704
                        Data::Session::LockedMedia::value_type(
 
7705
                            ComPtr<IMedium>(pMedium), true));
7475
7706
 
7476
7707
                    /* also, relock the old hard disk which is a base for the
7477
 
                     * new diff for reading if the VM is online */
 
7708
                    * new diff for reading if the VM is online */
7478
7709
 
7479
 
                    ComObjPtr<HardDisk> parent = hd->parent();
 
7710
                    ComObjPtr<Medium> parent = pMedium->getParent();
7480
7711
                    /* make the relock atomic */
7481
7712
                    AutoWriteLock parentLock (parent);
7482
 
                    rc = parent->UnlockWrite (NULL);
7483
 
                    AssertComRC (rc);
7484
 
                    rc = parent->LockRead (NULL);
7485
 
                    AssertComRC (rc);
 
7713
                    rc = parent->UnlockWrite(NULL);
 
7714
                    AssertComRC(rc);
 
7715
                    rc = parent->LockRead(NULL);
 
7716
                    AssertComRC(rc);
7486
7717
 
7487
7718
                    /* XXX actually we should replace the old entry in that
7488
 
                     * vector (write lock => read lock) but this would take
7489
 
                     * some effort. So lets just ignore the error code in
7490
 
                     * SessionMachine::unlockMedia(). */
7491
 
                    mData->mSession.mLockedMedia.push_back (
 
7719
                    * vector (write lock => read lock) but this would take
 
7720
                    * some effort. So lets just ignore the error code in
 
7721
                    * SessionMachine::unlockMedia(). */
 
7722
                    mData->mSession.mLockedMedia.push_back(
7492
7723
                        Data::Session::LockedMedia::value_type (
7493
 
                            ComPtr <IHardDisk> (parent), false));
 
7724
                            ComPtr<IMedium>(parent), false));
7494
7725
                }
7495
7726
 
7496
7727
                continue;
7497
7728
            }
7498
7729
 
7499
 
            /* was this hard disk attached before? */
7500
 
            HDData::AttachmentList::iterator oldIt =
7501
 
                std::find_if (oldAtts.begin(), oldAtts.end(),
7502
 
                              HardDiskAttachment::RefersTo (hd));
7503
 
            if (oldIt != oldAtts.end())
 
7730
            if (pMedium)
7504
7731
            {
7505
 
                /* yes: remove from old to avoid de-association */
7506
 
                oldAtts.erase (oldIt);
 
7732
                /* was this medium attached before? */
 
7733
                for (MediaData::AttachmentList::iterator oldIt = oldAtts.begin();
 
7734
                     oldIt != oldAtts.end();
 
7735
                     ++oldIt)
 
7736
                {
 
7737
                    MediumAttachment *pOldAttach = *oldIt;
 
7738
                    if (pOldAttach->getMedium().equalsTo(pMedium))
 
7739
                    {
 
7740
                        LogFlowThisFunc(("--> medium '%s' was attached before, will not remove\n", pMedium->getName().raw()));
 
7741
 
 
7742
                        /* yes: remove from old to avoid de-association */
 
7743
                        oldAtts.erase(oldIt);
 
7744
                        break;
 
7745
                    }
 
7746
                }
7507
7747
            }
7508
7748
        }
7509
7749
 
7510
7750
        /* enumerate remaining old attachments and de-associate from the
7511
7751
         * current machine state */
7512
 
        for (HDData::AttachmentList::const_iterator it = oldAtts.begin();
7513
 
             it != oldAtts.end(); ++ it)
 
7752
        for (MediaData::AttachmentList::const_iterator it = oldAtts.begin();
 
7753
             it != oldAtts.end();
 
7754
             ++it)
7514
7755
        {
7515
 
            ComObjPtr<HardDisk> hd = (*it)->hardDisk();
7516
 
 
7517
 
            /* now de-associate from the current machine state */
7518
 
            rc = hd->detachFrom (mData->mUuid);
7519
 
            AssertComRC (rc);
7520
 
 
7521
 
            if (aOnline)
 
7756
            MediumAttachment *pAttach = *it;
 
7757
            Medium* pMedium = pAttach->getMedium();
 
7758
 
 
7759
            /* Detach only hard disks, since DVD/floppy media is detached
 
7760
             * instantly in MountMedium. */
 
7761
            if (pAttach->getType() == DeviceType_HardDisk && pMedium)
7522
7762
            {
7523
 
                /* unlock since not used anymore */
7524
 
                MediaState_T state;
7525
 
                rc = hd->UnlockWrite (&state);
7526
 
                /* the disk may be alredy relocked for reading above */
7527
 
                Assert (SUCCEEDED (rc) || state == MediaState_LockedRead);
 
7763
                LogFlowThisFunc(("detaching medium '%s' from machine\n", pMedium->getName().raw()));
 
7764
 
 
7765
                /* now de-associate from the current machine state */
 
7766
                rc = pMedium->detachFrom(mData->mUuid);
 
7767
                AssertComRC(rc);
 
7768
 
 
7769
                if (    aOnline
 
7770
                     && pAttach->getType() == DeviceType_HardDisk)
 
7771
                {
 
7772
                    /* unlock since not used anymore */
 
7773
                    MediumState_T state;
 
7774
                    rc = pMedium->UnlockWrite(&state);
 
7775
                    /* the disk may be alredy relocked for reading above */
 
7776
                    Assert (SUCCEEDED(rc) || state == MediumState_LockedRead);
 
7777
                }
7528
7778
            }
7529
7779
        }
7530
7780
 
7531
7781
        /* commit the hard disk changes */
7532
 
        mHDData.commit();
 
7782
        mMediaData.commit();
7533
7783
 
7534
7784
        if (mType == IsSessionMachine)
7535
7785
        {
7536
7786
            /* attach new data to the primary machine and reshare it */
7537
 
            mPeer->mHDData.attach (mHDData);
 
7787
            mPeer->mMediaData.attach(mMediaData);
7538
7788
        }
7539
7789
    }
7540
7790
    else
7541
7791
    {
 
7792
        /* enumerate new attachments */
 
7793
        for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
7794
             it != mMediaData->mAttachments.end();
 
7795
             ++it)
 
7796
        {
 
7797
            MediumAttachment *pAttach = *it;
 
7798
            /* Fix up the backrefs for DVD/floppy media. */
 
7799
            if (pAttach->getType() != DeviceType_HardDisk)
 
7800
            {
 
7801
                Medium* pMedium = pAttach->getMedium();
 
7802
                if (pMedium)
 
7803
                {
 
7804
                    rc = pMedium->detachFrom(mData->mUuid);
 
7805
                    AssertComRC(rc);
 
7806
                }
 
7807
            }
 
7808
 
 
7809
            (*it)->rollback();
 
7810
 
 
7811
            pAttach = *it;
 
7812
            /* Fix up the backrefs for DVD/floppy media. */
 
7813
            if (pAttach->getType() != DeviceType_HardDisk)
 
7814
            {
 
7815
                Medium* pMedium = pAttach->getMedium();
 
7816
                if (pMedium)
 
7817
                {
 
7818
                    rc = pMedium->attachTo(mData->mUuid);
 
7819
                    AssertComRC(rc);
 
7820
                }
 
7821
            }
 
7822
        }
 
7823
 
 
7824
        /** @todo convert all this Machine-based voodoo to MediumAttachment
 
7825
         * based rollback logic. */
 
7826
        // @todo r=dj the below totally fails if this gets called from Machine::rollback(),
 
7827
        // which gets called if Machine::registeredInit() fails...
7542
7828
        deleteImplicitDiffs();
7543
7829
    }
7544
7830
 
7546
7832
}
7547
7833
 
7548
7834
/**
7549
 
 *  Helper to lock the machine configuration for write access.
7550
 
 *
7551
 
 *  @return S_OK or E_FAIL and sets error info on failure
7552
 
 *
7553
 
 *  @note Doesn't lock anything (must be called from this object's lock)
7554
 
 */
7555
 
HRESULT Machine::lockConfig()
7556
 
{
7557
 
    HRESULT rc = S_OK;
7558
 
 
7559
 
    if (!isConfigLocked())
7560
 
    {
7561
 
        /* open the associated config file */
7562
 
        int vrc = RTFileOpen (&mData->mHandleCfgFile,
7563
 
                              Utf8Str (mData->mConfigFileFull),
7564
 
                              RTFILE_O_READWRITE | RTFILE_O_OPEN |
7565
 
                              RTFILE_O_DENY_WRITE);
7566
 
        if (RT_FAILURE (vrc) && (vrc != VERR_FILE_NOT_FOUND))
7567
 
        {
7568
 
            /* Open the associated config file only with read access. */
7569
 
            vrc = RTFileOpen (&mData->mHandleCfgFile,
7570
 
                              Utf8Str (mData->mConfigFileFull),
7571
 
                              RTFILE_O_READ | RTFILE_O_OPEN |
7572
 
                              RTFILE_O_DENY_NONE);
7573
 
            if (RT_FAILURE (vrc))
7574
 
            {
7575
 
                /* We even cannot open it in read mode, so there's seriously
7576
 
                   something wrong. */
7577
 
                rc = setError (E_FAIL,
7578
 
                        tr ("Could not even open settings file '%ls' in read mode (%Rrc)"),
7579
 
                        mData->mConfigFile.raw(), vrc);
7580
 
            }
7581
 
            else
7582
 
            {
7583
 
                mData->mConfigFileReadonly = TRUE;
7584
 
            }
7585
 
        }
7586
 
        else
7587
 
        {
7588
 
            mData->mConfigFileReadonly = FALSE;
7589
 
        }
7590
 
 
7591
 
        if (RT_FAILURE(vrc))
7592
 
        {
7593
 
            mData->mHandleCfgFile = NIL_RTFILE;
7594
 
            mData->mConfigFileReadonly = FALSE;
7595
 
        }
7596
 
    }
7597
 
 
7598
 
    LogFlowThisFunc (("mConfigFile={%ls}, mHandleCfgFile=%d, rc=%08X\n",
7599
 
                      mData->mConfigFileFull.raw(), mData->mHandleCfgFile, rc));
7600
 
    return rc;
7601
 
}
7602
 
 
7603
 
/**
7604
 
 *  Helper to unlock the machine configuration from write access
7605
 
 *
7606
 
 *  @return S_OK
7607
 
 *
7608
 
 *  @note Doesn't lock anything.
7609
 
 *  @note Not thread safe (must be called from this object's lock).
7610
 
 */
7611
 
HRESULT Machine::unlockConfig()
7612
 
{
7613
 
    HRESULT rc = S_OK;
7614
 
 
7615
 
    if (isConfigLocked())
7616
 
    {
7617
 
        RTFileFlush (mData->mHandleCfgFile);
7618
 
        RTFileClose (mData->mHandleCfgFile);
7619
 
        /** @todo flush the directory. */
7620
 
        mData->mHandleCfgFile = NIL_RTFILE;
7621
 
        mData->mConfigFileReadonly = FALSE;
7622
 
    }
7623
 
 
7624
 
    LogFlowThisFunc (("\n"));
7625
 
 
7626
 
    return rc;
7627
 
}
7628
 
 
7629
 
/**
7630
7835
 *  Returns true if the settings file is located in the directory named exactly
7631
7836
 *  as the machine. This will be true if the machine settings structure was
7632
7837
 *  created by default in #openConfigLoader().
7637
7842
 *  @note Doesn't lock anything.
7638
7843
 *  @note Not thread safe (must be called from this object's lock).
7639
7844
 */
7640
 
bool Machine::isInOwnDir (Utf8Str *aSettingsDir /* = NULL */)
 
7845
bool Machine::isInOwnDir(Utf8Str *aSettingsDir /* = NULL */)
7641
7846
{
7642
 
    Utf8Str settingsDir = mData->mConfigFileFull;
7643
 
    RTPathStripFilename (settingsDir.mutableRaw());
7644
 
    char *dirName = RTPathFilename (settingsDir);
 
7847
    Utf8Str settingsDir = mData->m_strConfigFileFull;
 
7848
    settingsDir.stripFilename();
 
7849
    char *dirName = RTPathFilename(settingsDir.c_str());
7645
7850
 
7646
 
    AssertReturn (dirName, false);
 
7851
    AssertReturn(dirName, false);
7647
7852
 
7648
7853
    /* if we don't rename anything on name change, return false shorlty */
7649
7854
    if (!mUserData->mNameSync)
7660
7865
 */
7661
7866
bool Machine::isModified()
7662
7867
{
7663
 
    AutoCaller autoCaller (this);
 
7868
    AutoCaller autoCaller(this);
7664
7869
    AssertComRCReturn (autoCaller.rc(), false);
7665
7870
 
7666
 
    AutoReadLock alock (this);
 
7871
    AutoReadLock alock(this);
7667
7872
 
7668
7873
    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); slot ++)
7669
7874
        if (mNetworkAdapters [slot] && mNetworkAdapters [slot]->isModified())
7682
7887
        for (StorageControllerList::const_iterator it =
7683
7888
                    mStorageControllers->begin();
7684
7889
                it != mStorageControllers->end();
7685
 
                ++ it)
 
7890
                ++it)
7686
7891
        {
7687
7892
            if ((*it)->isModified())
7688
7893
                return true;
7692
7897
    return
7693
7898
        mUserData.isBackedUp() ||
7694
7899
        mHWData.isBackedUp() ||
7695
 
        mHDData.isBackedUp() ||
 
7900
        mMediaData.isBackedUp() ||
7696
7901
        mStorageControllers.isBackedUp() ||
7697
7902
#ifdef VBOX_WITH_VRDP
7698
7903
        (mVRDPServer && mVRDPServer->isModified()) ||
7699
7904
#endif
7700
 
        (mDVDDrive && mDVDDrive->isModified()) ||
7701
 
        (mFloppyDrive && mFloppyDrive->isModified()) ||
7702
7905
        (mAudioAdapter && mAudioAdapter->isModified()) ||
7703
7906
        (mUSBController && mUSBController->isModified()) ||
7704
7907
        (mBIOSSettings && mBIOSSettings->isModified());
7714
7917
 */
7715
7918
bool Machine::isReallyModified (bool aIgnoreUserData /* = false */)
7716
7919
{
7717
 
    AutoCaller autoCaller (this);
 
7920
    AutoCaller autoCaller(this);
7718
7921
    AssertComRCReturn (autoCaller.rc(), false);
7719
7922
 
7720
 
    AutoReadLock alock (this);
 
7923
    AutoReadLock alock(this);
7721
7924
 
7722
7925
    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); slot ++)
7723
7926
        if (mNetworkAdapters [slot] && mNetworkAdapters [slot]->isReallyModified())
7737
7940
        for (StorageControllerList::const_iterator
7738
7941
             it = mStorageControllers->begin();
7739
7942
             it != mStorageControllers->end();
7740
 
             ++ it)
 
7943
             ++it)
7741
7944
        {
7742
7945
            if ((*it)->isReallyModified())
7743
7946
                return true;
7752
7955
    return
7753
7956
        (!aIgnoreUserData && mUserData.hasActualChanges()) ||
7754
7957
        mHWData.hasActualChanges() ||
7755
 
        mHDData.hasActualChanges() ||
 
7958
        mMediaData.hasActualChanges() ||
7756
7959
        mStorageControllers.hasActualChanges() ||
7757
7960
#ifdef VBOX_WITH_VRDP
7758
7961
        (mVRDPServer && mVRDPServer->isReallyModified()) ||
7759
7962
#endif
7760
 
        (mDVDDrive && mDVDDrive->isReallyModified()) ||
7761
 
        (mFloppyDrive && mFloppyDrive->isReallyModified()) ||
7762
7963
        (mAudioAdapter && mAudioAdapter->isReallyModified()) ||
7763
7964
        (mUSBController && mUSBController->isReallyModified()) ||
7764
7965
        (mBIOSSettings && mBIOSSettings->isReallyModified());
7773
7974
 */
7774
7975
void Machine::rollback (bool aNotify)
7775
7976
{
7776
 
    AutoCaller autoCaller (this);
 
7977
    AutoCaller autoCaller(this);
7777
7978
    AssertComRCReturn (autoCaller.rc(), (void) 0);
7778
7979
 
7779
 
    AutoWriteLock alock (this);
 
7980
    AutoWriteLock alock(this);
7780
7981
 
7781
7982
    /* check for changes in own data */
7782
7983
 
7792
7993
            for (HWData::SharedFolderList::iterator rit =
7793
7994
                     mHWData->mSharedFolders.begin();
7794
7995
                 rit != mHWData->mSharedFolders.end() && !sharedFoldersChanged;
7795
 
                 ++ rit)
 
7996
                 ++rit)
7796
7997
            {
7797
7998
                for (HWData::SharedFolderList::iterator cit =
7798
7999
                         mHWData.backedUpData()->mSharedFolders.begin();
7799
8000
                     cit != mHWData.backedUpData()->mSharedFolders.end();
7800
 
                     ++ cit)
 
8001
                     ++cit)
7801
8002
                {
7802
 
                    if ((*cit)->name() != (*rit)->name() ||
7803
 
                        (*cit)->hostPath() != (*rit)->hostPath())
 
8003
                    if ((*cit)->getName() != (*rit)->getName() ||
 
8004
                        (*cit)->getHostPath() != (*rit)->getHostPath())
7804
8005
                    {
7805
8006
                        sharedFoldersChanged = true;
7806
8007
                        break;
7824
8025
                {
7825
8026
                    (*it)->uninit();
7826
8027
                }
7827
 
                ++ it;
 
8028
                ++it;
7828
8029
            }
7829
8030
 
7830
8031
            /* restore the list */
7838
8039
            if ((*it)->isModified())
7839
8040
                (*it)->rollback();
7840
8041
 
7841
 
            ++ it;
 
8042
            ++it;
7842
8043
        }
7843
8044
    }
7844
8045
 
7846
8047
 
7847
8048
    mHWData.rollback();
7848
8049
 
7849
 
    if (mHDData.isBackedUp())
7850
 
        fixupHardDisks(false /* aCommit */);
 
8050
    if (mMediaData.isBackedUp())
 
8051
        fixupMedia(false /* aCommit */);
7851
8052
 
7852
8053
    /* check for changes in child objects */
7853
8054
 
7854
 
    bool vrdpChanged = false, dvdChanged = false, floppyChanged = false,
7855
 
         usbChanged = false;
 
8055
    bool vrdpChanged = false, usbChanged = false;
7856
8056
 
7857
 
    ComPtr <INetworkAdapter> networkAdapters [RT_ELEMENTS (mNetworkAdapters)];
7858
 
    ComPtr <ISerialPort> serialPorts [RT_ELEMENTS (mSerialPorts)];
7859
 
    ComPtr <IParallelPort> parallelPorts [RT_ELEMENTS (mParallelPorts)];
 
8057
    ComPtr<INetworkAdapter> networkAdapters [RT_ELEMENTS (mNetworkAdapters)];
 
8058
    ComPtr<ISerialPort> serialPorts [RT_ELEMENTS (mSerialPorts)];
 
8059
    ComPtr<IParallelPort> parallelPorts [RT_ELEMENTS (mParallelPorts)];
7860
8060
 
7861
8061
    if (mBIOSSettings)
7862
8062
        mBIOSSettings->rollback();
7866
8066
        vrdpChanged = mVRDPServer->rollback();
7867
8067
#endif
7868
8068
 
7869
 
    if (mDVDDrive)
7870
 
        dvdChanged = mDVDDrive->rollback();
7871
 
 
7872
 
    if (mFloppyDrive)
7873
 
        floppyChanged = mFloppyDrive->rollback();
7874
 
 
7875
8069
    if (mAudioAdapter)
7876
8070
        mAudioAdapter->rollback();
7877
8071
 
7897
8091
    {
7898
8092
        /* inform the direct session about changes */
7899
8093
 
7900
 
        ComObjPtr <Machine> that = this;
 
8094
        ComObjPtr<Machine> that = this;
7901
8095
        alock.leave();
7902
8096
 
7903
8097
        if (sharedFoldersChanged)
7905
8099
 
7906
8100
        if (vrdpChanged)
7907
8101
            that->onVRDPServerChange();
7908
 
        if (dvdChanged)
7909
 
            that->onDVDDriveChange();
7910
 
        if (floppyChanged)
7911
 
            that->onFloppyDriveChange();
7912
8102
        if (usbChanged)
7913
8103
            that->onUSBControllerChange();
7914
8104
 
7915
8105
        for (ULONG slot = 0; slot < RT_ELEMENTS (networkAdapters); slot ++)
7916
8106
            if (networkAdapters [slot])
7917
 
                that->onNetworkAdapterChange (networkAdapters [slot]);
 
8107
                that->onNetworkAdapterChange (networkAdapters [slot], FALSE);
7918
8108
        for (ULONG slot = 0; slot < RT_ELEMENTS (serialPorts); slot ++)
7919
8109
            if (serialPorts [slot])
7920
8110
                that->onSerialPortChange (serialPorts [slot]);
7936
8126
 */
7937
8127
void Machine::commit()
7938
8128
{
7939
 
    AutoCaller autoCaller (this);
 
8129
    AutoCaller autoCaller(this);
7940
8130
    AssertComRCReturnVoid (autoCaller.rc());
7941
8131
 
7942
8132
    AutoCaller peerCaller (mPeer);
7952
8142
 
7953
8143
    mHWData.commit();
7954
8144
 
7955
 
    if (mHDData.isBackedUp())
7956
 
        fixupHardDisks(true /* aCommit */);
 
8145
    if (mMediaData.isBackedUp())
 
8146
        fixupMedia(true /* aCommit */);
7957
8147
 
7958
8148
    mBIOSSettings->commit();
7959
8149
#ifdef VBOX_WITH_VRDP
7960
8150
    mVRDPServer->commit();
7961
8151
#endif
7962
 
    mDVDDrive->commit();
7963
 
    mFloppyDrive->commit();
7964
8152
    mAudioAdapter->commit();
7965
8153
    mUSBController->commit();
7966
8154
 
8006
8194
                /* and add it to the new list */
8007
8195
                newList->push_back(peer);
8008
8196
 
8009
 
                ++ it;
 
8197
                ++it;
8010
8198
            }
8011
8199
 
8012
8200
            /* uninit old peer's controllers that are left */
8014
8202
            while (it != mPeer->mStorageControllers->end())
8015
8203
            {
8016
8204
                (*it)->uninit();
8017
 
                ++ it;
 
8205
                ++it;
8018
8206
            }
8019
8207
 
8020
8208
            /* attach new list of controllers to our peer */
8040
8228
        while (it != mStorageControllers->end())
8041
8229
        {
8042
8230
            (*it)->commit();
8043
 
            ++ it;
 
8231
            ++it;
8044
8232
        }
8045
8233
    }
8046
8234
 
8049
8237
        /* attach new data to the primary machine and reshare it */
8050
8238
        mPeer->mUserData.attach (mUserData);
8051
8239
        mPeer->mHWData.attach (mHWData);
8052
 
        /* mHDData is reshared by fixupHardDisks */
8053
 
        // mPeer->mHDData.attach (mHDData);
8054
 
        Assert (mPeer->mHDData.data() == mHDData.data());
 
8240
        /* mMediaData is reshared by fixupMedia */
 
8241
        // mPeer->mMediaData.attach(mMediaData);
 
8242
        Assert(mPeer->mMediaData.data() == mMediaData.data());
8055
8243
    }
8056
8244
}
8057
8245
 
8080
8268
    // contains just references to original objects)
8081
8269
    for (HWData::SharedFolderList::iterator it = mHWData->mSharedFolders.begin();
8082
8270
         it != mHWData->mSharedFolders.end();
8083
 
         ++ it)
 
8271
         ++it)
8084
8272
    {
8085
 
        ComObjPtr <SharedFolder> folder;
 
8273
        ComObjPtr<SharedFolder> folder;
8086
8274
        folder.createObject();
8087
 
        HRESULT rc = folder->initCopy (machine(), *it);
 
8275
        HRESULT rc = folder->initCopy(getMachine(), *it);
8088
8276
        AssertComRC (rc);
8089
8277
        *it = folder;
8090
8278
    }
8093
8281
#ifdef VBOX_WITH_VRDP
8094
8282
    mVRDPServer->copyFrom (aThat->mVRDPServer);
8095
8283
#endif
8096
 
    mDVDDrive->copyFrom (aThat->mDVDDrive);
8097
 
    mFloppyDrive->copyFrom (aThat->mFloppyDrive);
8098
8284
    mAudioAdapter->copyFrom (aThat->mAudioAdapter);
8099
8285
    mUSBController->copyFrom (aThat->mUSBController);
8100
8286
 
8103
8289
    mStorageControllers->clear();
8104
8290
    for (StorageControllerList::iterator it = aThat->mStorageControllers->begin();
8105
8291
         it != aThat->mStorageControllers->end();
8106
 
         ++ it)
 
8292
         ++it)
8107
8293
    {
8108
 
        ComObjPtr <StorageController> ctrl;
 
8294
        ComObjPtr<StorageController> ctrl;
8109
8295
        ctrl.createObject();
8110
8296
        ctrl->initCopy (this, *it);
8111
8297
        mStorageControllers->push_back(ctrl);
8170
8356
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
8171
8357
 
8172
8358
 
8173
 
/////////////////////////////////////////////////////////////////////////////
8174
 
// SessionMachine class
8175
 
/////////////////////////////////////////////////////////////////////////////
8176
 
 
8177
 
/** Task structure for asynchronous VM operations */
8178
 
struct SessionMachine::Task
8179
 
{
8180
 
    Task (SessionMachine *m, Progress *p)
8181
 
        : machine (m), progress (p)
8182
 
        , state (m->mData->mMachineState) // save the current machine state
8183
 
        , subTask (false)
8184
 
    {}
8185
 
 
8186
 
    void modifyLastState (MachineState_T s)
8187
 
    {
8188
 
        *const_cast <MachineState_T *> (&state) = s;
8189
 
    }
8190
 
 
8191
 
    virtual void handler() = 0;
8192
 
 
8193
 
    ComObjPtr <SessionMachine> machine;
8194
 
    ComObjPtr <Progress> progress;
8195
 
    const MachineState_T state;
8196
 
 
8197
 
    bool subTask : 1;
8198
 
};
8199
 
 
8200
 
/** Take snapshot task */
8201
 
struct SessionMachine::TakeSnapshotTask : public SessionMachine::Task
8202
 
{
8203
 
    TakeSnapshotTask (SessionMachine *m)
8204
 
        : Task (m, NULL) {}
8205
 
 
8206
 
    void handler() { machine->takeSnapshotHandler (*this); }
8207
 
};
8208
 
 
8209
 
/** Discard snapshot task */
8210
 
struct SessionMachine::DiscardSnapshotTask : public SessionMachine::Task
8211
 
{
8212
 
    DiscardSnapshotTask (SessionMachine *m, Progress *p, Snapshot *s)
8213
 
        : Task (m, p)
8214
 
        , snapshot (s) {}
8215
 
 
8216
 
    DiscardSnapshotTask (const Task &task, Snapshot *s)
8217
 
        : Task (task)
8218
 
        , snapshot (s) {}
8219
 
 
8220
 
    void handler() { machine->discardSnapshotHandler (*this); }
8221
 
 
8222
 
    ComObjPtr <Snapshot> snapshot;
8223
 
};
8224
 
 
8225
 
/** Discard current state task */
8226
 
struct SessionMachine::DiscardCurrentStateTask : public SessionMachine::Task
8227
 
{
8228
 
    DiscardCurrentStateTask (SessionMachine *m, Progress *p,
8229
 
                             bool discardCurSnapshot)
8230
 
        : Task (m, p), discardCurrentSnapshot (discardCurSnapshot) {}
8231
 
 
8232
 
    void handler() { machine->discardCurrentStateHandler (*this); }
8233
 
 
8234
 
    const bool discardCurrentSnapshot;
8235
 
};
8236
 
 
8237
8359
////////////////////////////////////////////////////////////////////////////////
8238
8360
 
8239
 
DEFINE_EMPTY_CTOR_DTOR (SessionMachine)
 
8361
DEFINE_EMPTY_CTOR_DTOR(SessionMachine)
8240
8362
 
8241
8363
HRESULT SessionMachine::FinalConstruct()
8242
8364
{
8243
 
    LogFlowThisFunc (("\n"));
 
8365
    LogFlowThisFunc(("\n"));
8244
8366
 
8245
8367
    /* set the proper type to indicate we're the SessionMachine instance */
8246
 
    unconst (mType) = IsSessionMachine;
 
8368
    unconst(mType) = IsSessionMachine;
8247
8369
 
8248
8370
#if defined(RT_OS_WINDOWS)
8249
8371
    mIPCSem = NULL;
8260
8382
 
8261
8383
void SessionMachine::FinalRelease()
8262
8384
{
8263
 
    LogFlowThisFunc (("\n"));
 
8385
    LogFlowThisFunc(("\n"));
8264
8386
 
8265
8387
    uninit (Uninit::Unexpected);
8266
8388
}
8271
8393
HRESULT SessionMachine::init (Machine *aMachine)
8272
8394
{
8273
8395
    LogFlowThisFuncEnter();
8274
 
    LogFlowThisFunc (("mName={%ls}\n", aMachine->mUserData->mName.raw()));
8275
 
 
8276
 
    AssertReturn (aMachine, E_INVALIDARG);
8277
 
 
8278
 
    AssertReturn (aMachine->lockHandle()->isWriteLockOnCurrentThread(), E_FAIL);
 
8396
    LogFlowThisFunc(("mName={%ls}\n", aMachine->mUserData->mName.raw()));
 
8397
 
 
8398
    AssertReturn(aMachine, E_INVALIDARG);
 
8399
 
 
8400
    AssertReturn(aMachine->lockHandle()->isWriteLockOnCurrentThread(), E_FAIL);
8279
8401
 
8280
8402
    /* Enclose the state transition NotReady->InInit->Ready */
8281
 
    AutoInitSpan autoInitSpan (this);
8282
 
    AssertReturn (autoInitSpan.isOk(), E_FAIL);
 
8403
    AutoInitSpan autoInitSpan(this);
 
8404
    AssertReturn(autoInitSpan.isOk(), E_FAIL);
8283
8405
 
8284
8406
    /* create the interprocess semaphore */
8285
8407
#if defined(RT_OS_WINDOWS)
8286
 
    mIPCSemName = aMachine->mData->mConfigFileFull;
 
8408
    mIPCSemName = aMachine->mData->m_strConfigFileFull;
8287
8409
    for (size_t i = 0; i < mIPCSemName.length(); i++)
8288
8410
        if (mIPCSemName[i] == '\\')
8289
8411
            mIPCSemName[i] = '/';
8325
8447
        }
8326
8448
    }
8327
8449
# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
8328
 
    Utf8Str semName = aMachine->mData->mConfigFileFull;
 
8450
    Utf8Str semName = aMachine->mData->m_strConfigFileFull;
8329
8451
    char *pszSemName = NULL;
8330
8452
    RTStrUtf8ToCurrentCP (&pszSemName, semName);
8331
8453
    key_t key = ::ftok (pszSemName, 'V');
8337
8459
    int errnoSave = errno;
8338
8460
    if (mIPCSem < 0 && errnoSave == ENOSYS)
8339
8461
    {
8340
 
        setError (E_FAIL,
8341
 
                  tr ("Cannot create IPC semaphore. Most likely your host kernel lacks "
8342
 
                      "support for SysV IPC. Check the host kernel configuration for "
8343
 
                      "CONFIG_SYSVIPC=y"));
 
8462
        setError(E_FAIL,
 
8463
                 tr("Cannot create IPC semaphore. Most likely your host kernel lacks "
 
8464
                    "support for SysV IPC. Check the host kernel configuration for "
 
8465
                    "CONFIG_SYSVIPC=y"));
 
8466
        return E_FAIL;
 
8467
    }
 
8468
    /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing
 
8469
     * the IPC semaphores */
 
8470
    if (mIPCSem < 0 && errnoSave == ENOSPC)
 
8471
    {
 
8472
#ifdef RT_OS_LINUX
 
8473
        setError(E_FAIL,
 
8474
                 tr("Cannot create IPC semaphore because the system limit for the "
 
8475
                    "maximum number of semaphore sets (SEMMNI), or the system wide "
 
8476
                    "maximum number of sempahores (SEMMNS) would be exceeded. The "
 
8477
                    "current set of SysV IPC semaphores can be determined from "
 
8478
                    "the file /proc/sysvipc/sem"));
 
8479
#else
 
8480
        setError(E_FAIL,
 
8481
                 tr("Cannot create IPC semaphore because the system-imposed limit "
 
8482
                    "on the maximum number of allowed  semaphores or semaphore "
 
8483
                    "identifiers system-wide would be exceeded"));
 
8484
#endif
8344
8485
        return E_FAIL;
8345
8486
    }
8346
8487
    ComAssertMsgRet (mIPCSem >= 0, ("Cannot create IPC semaphore, errno=%d", errnoSave),
8354
8495
#endif
8355
8496
 
8356
8497
    /* memorize the peer Machine */
8357
 
    unconst (mPeer) = aMachine;
 
8498
    unconst(mPeer) = aMachine;
8358
8499
    /* share the parent pointer */
8359
 
    unconst (mParent) = aMachine->mParent;
 
8500
    unconst(mParent) = aMachine->mParent;
8360
8501
 
8361
8502
    /* take the pointers to data to share */
8362
8503
    mData.share (aMachine->mData);
8364
8505
 
8365
8506
    mUserData.share (aMachine->mUserData);
8366
8507
    mHWData.share (aMachine->mHWData);
8367
 
    mHDData.share (aMachine->mHDData);
 
8508
    mMediaData.share(aMachine->mMediaData);
8368
8509
 
8369
8510
    mStorageControllers.allocate();
8370
 
    StorageControllerList::const_iterator it = aMachine->mStorageControllers->begin();
8371
 
    while (it != aMachine->mStorageControllers->end())
 
8511
    for (StorageControllerList::const_iterator it = aMachine->mStorageControllers->begin();
 
8512
         it != aMachine->mStorageControllers->end();
 
8513
         ++it)
8372
8514
    {
8373
 
        ComObjPtr <StorageController> ctl;
 
8515
        ComObjPtr<StorageController> ctl;
8374
8516
        ctl.createObject();
8375
8517
        ctl->init(this, *it);
8376
8518
        mStorageControllers->push_back (ctl);
8377
 
        ++ it;
8378
8519
    }
8379
8520
 
8380
 
    unconst (mBIOSSettings).createObject();
 
8521
    unconst(mBIOSSettings).createObject();
8381
8522
    mBIOSSettings->init (this, aMachine->mBIOSSettings);
8382
8523
#ifdef VBOX_WITH_VRDP
8383
8524
    /* create another VRDPServer object that will be mutable */
8384
 
    unconst (mVRDPServer).createObject();
 
8525
    unconst(mVRDPServer).createObject();
8385
8526
    mVRDPServer->init (this, aMachine->mVRDPServer);
8386
8527
#endif
8387
 
    /* create another DVD drive object that will be mutable */
8388
 
    unconst (mDVDDrive).createObject();
8389
 
    mDVDDrive->init (this, aMachine->mDVDDrive);
8390
 
    /* create another floppy drive object that will be mutable */
8391
 
    unconst (mFloppyDrive).createObject();
8392
 
    mFloppyDrive->init (this, aMachine->mFloppyDrive);
8393
8528
    /* create another audio adapter object that will be mutable */
8394
 
    unconst (mAudioAdapter).createObject();
 
8529
    unconst(mAudioAdapter).createObject();
8395
8530
    mAudioAdapter->init (this, aMachine->mAudioAdapter);
8396
8531
    /* create a list of serial ports that will be mutable */
8397
8532
    for (ULONG slot = 0; slot < RT_ELEMENTS (mSerialPorts); slot ++)
8398
8533
    {
8399
 
        unconst (mSerialPorts [slot]).createObject();
 
8534
        unconst(mSerialPorts [slot]).createObject();
8400
8535
        mSerialPorts [slot]->init (this, aMachine->mSerialPorts [slot]);
8401
8536
    }
8402
8537
    /* create a list of parallel ports that will be mutable */
8403
8538
    for (ULONG slot = 0; slot < RT_ELEMENTS (mParallelPorts); slot ++)
8404
8539
    {
8405
 
        unconst (mParallelPorts [slot]).createObject();
 
8540
        unconst(mParallelPorts [slot]).createObject();
8406
8541
        mParallelPorts [slot]->init (this, aMachine->mParallelPorts [slot]);
8407
8542
    }
8408
8543
    /* create another USB controller object that will be mutable */
8409
 
    unconst (mUSBController).createObject();
 
8544
    unconst(mUSBController).createObject();
8410
8545
    mUSBController->init (this, aMachine->mUSBController);
8411
8546
 
8412
8547
    /* create a list of network adapters that will be mutable */
8413
8548
    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); slot ++)
8414
8549
    {
8415
 
        unconst (mNetworkAdapters [slot]).createObject();
 
8550
        unconst(mNetworkAdapters [slot]).createObject();
8416
8551
        mNetworkAdapters [slot]->init (this, aMachine->mNetworkAdapters [slot]);
8417
8552
    }
8418
8553
 
8437
8572
void SessionMachine::uninit (Uninit::Reason aReason)
8438
8573
{
8439
8574
    LogFlowThisFuncEnter();
8440
 
    LogFlowThisFunc (("reason=%d\n", aReason));
 
8575
    LogFlowThisFunc(("reason=%d\n", aReason));
8441
8576
 
8442
8577
    /*
8443
8578
     *  Strongly reference ourselves to prevent this object deletion after
8446
8581
     *  accessing any members (and before AutoUninitSpan that does it as well).
8447
8582
     *  This self reference will be released as the very last step on return.
8448
8583
     */
8449
 
    ComObjPtr <SessionMachine> selfRef = this;
 
8584
    ComObjPtr<SessionMachine> selfRef = this;
8450
8585
 
8451
8586
    /* Enclose the state transition Ready->InUninit->NotReady */
8452
 
    AutoUninitSpan autoUninitSpan (this);
 
8587
    AutoUninitSpan autoUninitSpan(this);
8453
8588
    if (autoUninitSpan.uninitDone())
8454
8589
    {
8455
 
        LogFlowThisFunc (("Already uninitialized\n"));
 
8590
        LogFlowThisFunc(("Already uninitialized\n"));
8456
8591
        LogFlowThisFuncLeave();
8457
8592
        return;
8458
8593
    }
8463
8598
         * necessary (nor it's safe) to perform the regular uninit sequense
8464
8599
         * below, the following is enough.
8465
8600
         */
8466
 
        LogFlowThisFunc (("Initialization failed.\n"));
 
8601
        LogFlowThisFunc(("Initialization failed.\n"));
8467
8602
#if defined(RT_OS_WINDOWS)
8468
8603
        if (mIPCSem)
8469
8604
            ::CloseHandle (mIPCSem);
8484
8619
#endif
8485
8620
        uninitDataAndChildObjects();
8486
8621
        mData.free();
8487
 
        unconst (mParent).setNull();
8488
 
        unconst (mPeer).setNull();
 
8622
        unconst(mParent).setNull();
 
8623
        unconst(mPeer).setNull();
8489
8624
        LogFlowThisFuncLeave();
8490
8625
        return;
8491
8626
    }
8504
8639
 
8505
8640
    if (aReason == Uninit::Abnormal)
8506
8641
    {
8507
 
        LogWarningThisFunc (("ABNORMAL client termination! (wasBusy=%d)\n",
 
8642
        LogWarningThisFunc(("ABNORMAL client termination! (wasBusy=%d)\n",
8508
8643
                             Global::IsOnlineOrTransient (lastState)));
8509
8644
 
8510
8645
        /* reset the state to Aborted */
8514
8649
 
8515
8650
    if (isModified())
8516
8651
    {
8517
 
        LogWarningThisFunc (("Discarding unsaved settings changes!\n"));
 
8652
        LogWarningThisFunc(("Discarding unsaved settings changes!\n"));
8518
8653
        rollback (false /* aNotify */);
8519
8654
    }
8520
8655
 
8521
 
    Assert (!mSnapshotData.mStateFilePath || !mSnapshotData.mSnapshot);
8522
 
    if (mSnapshotData.mStateFilePath)
 
8656
    Assert(mSnapshotData.mStateFilePath.isEmpty() || !mSnapshotData.mSnapshot);
 
8657
    if (!mSnapshotData.mStateFilePath.isEmpty())
8523
8658
    {
8524
 
        LogWarningThisFunc (("canceling failed save state request!\n"));
 
8659
        LogWarningThisFunc(("canceling failed save state request!\n"));
8525
8660
        endSavingState (FALSE /* aSuccess  */);
8526
8661
    }
8527
8662
    else if (!mSnapshotData.mSnapshot.isNull())
8528
8663
    {
8529
 
        LogWarningThisFunc (("canceling untaken snapshot!\n"));
 
8664
        LogWarningThisFunc(("canceling untaken snapshot!\n"));
8530
8665
        endTakingSnapshot (FALSE /* aSuccess  */);
8531
8666
    }
8532
8667
 
8543
8678
         * This is identical to SessionMachine::DetachAllUSBDevices except
8544
8679
         * for the aAbnormal argument. */
8545
8680
        HRESULT rc = mUSBController->notifyProxy (false /* aInsertFilters */);
8546
 
        AssertComRC (rc);
 
8681
        AssertComRC(rc);
8547
8682
        NOREF (rc);
8548
8683
 
8549
8684
        USBProxyService *service = mParent->host()->usbProxyService();
8575
8710
    /* uninitialize all remote controls */
8576
8711
    if (mData->mSession.mRemoteControls.size())
8577
8712
    {
8578
 
        LogFlowThisFunc (("Closing remote sessions (%d):\n",
 
8713
        LogFlowThisFunc(("Closing remote sessions (%d):\n",
8579
8714
                          mData->mSession.mRemoteControls.size()));
8580
8715
 
8581
8716
        Data::Session::RemoteControlList::iterator it =
8582
8717
            mData->mSession.mRemoteControls.begin();
8583
8718
        while (it != mData->mSession.mRemoteControls.end())
8584
8719
        {
8585
 
            LogFlowThisFunc (("  Calling remoteControl->Uninitialize()...\n"));
 
8720
            LogFlowThisFunc(("  Calling remoteControl->Uninitialize()...\n"));
8586
8721
            HRESULT rc = (*it)->Uninitialize();
8587
 
            LogFlowThisFunc (("  remoteControl->Uninitialize() returned %08X\n", rc));
 
8722
            LogFlowThisFunc(("  remoteControl->Uninitialize() returned %08X\n", rc));
8588
8723
            if (FAILED (rc))
8589
 
                LogWarningThisFunc (("Forgot to close the remote session?\n"));
8590
 
            ++ it;
 
8724
                LogWarningThisFunc(("Forgot to close the remote session?\n"));
 
8725
            ++it;
8591
8726
        }
8592
8727
        mData->mSession.mRemoteControls.clear();
8593
8728
    }
8605
8740
     */
8606
8741
 
8607
8742
    if ((aReason == Uninit::Unexpected))
8608
 
        LogWarningThisFunc (("Unexpected SessionMachine uninitialization!\n"));
 
8743
        LogWarningThisFunc(("Unexpected SessionMachine uninitialization!\n"));
8609
8744
 
8610
8745
    if (aReason != Uninit::Normal)
8611
8746
    {
8631
8766
    mData->mSession.mState = SessionState_Closed;
8632
8767
    mData->mSession.mType.setNull();
8633
8768
 
8634
 
    /* close the interprocess semaphore before leaving the shared lock */
 
8769
    /* close the interprocess semaphore before leaving the exclusive lock */
8635
8770
#if defined(RT_OS_WINDOWS)
8636
8771
    if (mIPCSem)
8637
8772
        ::CloseHandle (mIPCSem);
8659
8794
    /* free the essential data structure last */
8660
8795
    mData.free();
8661
8796
 
8662
 
    /* leave the shared lock before setting the below two to NULL */
 
8797
    /* leave the exclusive lock before setting the below two to NULL */
8663
8798
    alock.leave();
8664
8799
 
8665
 
    unconst (mParent).setNull();
8666
 
    unconst (mPeer).setNull();
 
8800
    unconst(mParent).setNull();
 
8801
    unconst(mPeer).setNull();
8667
8802
 
8668
8803
    LogFlowThisFuncLeave();
8669
8804
}
8677
8812
 */
8678
8813
RWLockHandle *SessionMachine::lockHandle() const
8679
8814
{
8680
 
    AssertReturn (!mPeer.isNull(), NULL);
 
8815
    AssertReturn(!mPeer.isNull(), NULL);
8681
8816
    return mPeer->lockHandle();
8682
8817
}
8683
8818
 
8689
8824
 */
8690
8825
STDMETHODIMP SessionMachine::SetRemoveSavedState(BOOL aRemove)
8691
8826
{
8692
 
    AutoCaller autoCaller (this);
 
8827
    AutoCaller autoCaller(this);
8693
8828
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8694
8829
 
8695
 
    AutoWriteLock alock (this);
 
8830
    AutoWriteLock alock(this);
8696
8831
 
8697
8832
    mRemoveSavedState = aRemove;
8698
8833
 
8712
8847
 */
8713
8848
STDMETHODIMP SessionMachine::GetIPCId (BSTR *aId)
8714
8849
{
8715
 
    AutoCaller autoCaller (this);
 
8850
    AutoCaller autoCaller(this);
8716
8851
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8717
8852
 
8718
 
    AutoReadLock alock (this);
 
8853
    AutoReadLock alock(this);
8719
8854
 
8720
8855
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
8721
 
    mIPCSemName.cloneTo (aId);
 
8856
    mIPCSemName.cloneTo(aId);
8722
8857
    return S_OK;
8723
8858
#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
8724
8859
# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
8725
 
    mIPCKey.cloneTo (aId);
 
8860
    mIPCKey.cloneTo(aId);
8726
8861
# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
8727
 
    mData->mConfigFileFull.cloneTo (aId);
 
8862
    mData->m_strConfigFileFull.cloneTo(aId);
8728
8863
# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
8729
8864
    return S_OK;
8730
8865
#else
8742
8877
                                                  BOOL *aMatched,
8743
8878
                                                  ULONG *aMaskedIfs)
8744
8879
{
8745
 
    LogFlowThisFunc (("\n"));
 
8880
    LogFlowThisFunc(("\n"));
8746
8881
 
8747
8882
    CheckComArgNotNull (aUSBDevice);
8748
 
    CheckComArgOutPointerValid (aMatched);
 
8883
    CheckComArgOutPointerValid(aMatched);
8749
8884
 
8750
 
    AutoCaller autoCaller (this);
 
8885
    AutoCaller autoCaller(this);
8751
8886
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8752
8887
 
8753
8888
#ifdef VBOX_WITH_USB
8766
8901
 */
8767
8902
STDMETHODIMP SessionMachine::CaptureUSBDevice (IN_BSTR aId)
8768
8903
{
8769
 
    LogFlowThisFunc (("\n"));
 
8904
    LogFlowThisFunc(("\n"));
8770
8905
 
8771
 
    AutoCaller autoCaller (this);
8772
 
    AssertComRCReturnRC (autoCaller.rc());
 
8906
    AutoCaller autoCaller(this);
 
8907
    AssertComRCReturnRC(autoCaller.rc());
8773
8908
 
8774
8909
#ifdef VBOX_WITH_USB
8775
8910
    /* if captureDeviceForVM() fails, it must have set extended error info */
8776
8911
    MultiResult rc = mParent->host()->checkUSBProxyService();
8777
 
    CheckComRCReturnRC (rc);
 
8912
    CheckComRCReturnRC(rc);
8778
8913
 
8779
8914
    USBProxyService *service = mParent->host()->usbProxyService();
8780
 
    AssertReturn (service, E_FAIL);
 
8915
    AssertReturn(service, E_FAIL);
8781
8916
    return service->captureDeviceForVM (this, Guid(aId));
8782
8917
#else
8783
8918
    NOREF(aId);
8790
8925
 */
8791
8926
STDMETHODIMP SessionMachine::DetachUSBDevice (IN_BSTR aId, BOOL aDone)
8792
8927
{
8793
 
    LogFlowThisFunc (("\n"));
 
8928
    LogFlowThisFunc(("\n"));
8794
8929
 
8795
 
    AutoCaller autoCaller (this);
 
8930
    AutoCaller autoCaller(this);
8796
8931
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8797
8932
 
8798
8933
#ifdef VBOX_WITH_USB
8799
8934
    USBProxyService *service = mParent->host()->usbProxyService();
8800
 
    AssertReturn (service, E_FAIL);
 
8935
    AssertReturn(service, E_FAIL);
8801
8936
    return service->detachDeviceFromVM (this, Guid(aId), !!aDone);
8802
8937
#else
8803
8938
    NOREF(aId);
8816
8951
 */
8817
8952
STDMETHODIMP SessionMachine::AutoCaptureUSBDevices()
8818
8953
{
8819
 
    LogFlowThisFunc (("\n"));
 
8954
    LogFlowThisFunc(("\n"));
8820
8955
 
8821
 
    AutoCaller autoCaller (this);
 
8956
    AutoCaller autoCaller(this);
8822
8957
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8823
8958
 
8824
8959
#ifdef VBOX_WITH_USB
8825
8960
    HRESULT rc = mUSBController->notifyProxy (true /* aInsertFilters */);
8826
 
    AssertComRC (rc);
 
8961
    AssertComRC(rc);
8827
8962
    NOREF (rc);
8828
8963
 
8829
8964
    USBProxyService *service = mParent->host()->usbProxyService();
8830
 
    AssertReturn (service, E_FAIL);
 
8965
    AssertReturn(service, E_FAIL);
8831
8966
    return service->autoCaptureDevicesForVM (this);
8832
8967
#else
8833
8968
    return S_OK;
8846
8981
 */
8847
8982
STDMETHODIMP SessionMachine::DetachAllUSBDevices (BOOL aDone)
8848
8983
{
8849
 
    LogFlowThisFunc (("\n"));
 
8984
    LogFlowThisFunc(("\n"));
8850
8985
 
8851
 
    AutoCaller autoCaller (this);
 
8986
    AutoCaller autoCaller(this);
8852
8987
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8853
8988
 
8854
8989
#ifdef VBOX_WITH_USB
8855
8990
    HRESULT rc = mUSBController->notifyProxy (false /* aInsertFilters */);
8856
 
    AssertComRC (rc);
 
8991
    AssertComRC(rc);
8857
8992
    NOREF (rc);
8858
8993
 
8859
8994
    USBProxyService *service = mParent->host()->usbProxyService();
8860
 
    AssertReturn (service, E_FAIL);
 
8995
    AssertReturn(service, E_FAIL);
8861
8996
    return service->detachAllDevicesFromVM (this, !!aDone, false /* aAbnormal */);
8862
8997
#else
8863
8998
    NOREF(aDone);
8873
9008
{
8874
9009
    LogFlowThisFuncEnter();
8875
9010
 
8876
 
    AssertReturn (aSession, E_INVALIDARG);
8877
 
    AssertReturn (aProgress, E_INVALIDARG);
8878
 
 
8879
 
    AutoCaller autoCaller (this);
8880
 
 
8881
 
    LogFlowThisFunc (("state=%d\n", autoCaller.state()));
 
9011
    AssertReturn(aSession, E_INVALIDARG);
 
9012
    AssertReturn(aProgress, E_INVALIDARG);
 
9013
 
 
9014
    AutoCaller autoCaller(this);
 
9015
 
 
9016
    LogFlowThisFunc(("callerstate=%d\n", autoCaller.state()));
8882
9017
    /*
8883
9018
     *  We don't assert below because it might happen that a non-direct session
8884
9019
     *  informs us it is closed right after we've been uninitialized -- it's ok.
8885
9020
     */
8886
 
    CheckComRCReturnRC (autoCaller.rc());
 
9021
    CheckComRCReturnRC(autoCaller.rc());
8887
9022
 
8888
9023
    /* get IInternalSessionControl interface */
8889
 
    ComPtr <IInternalSessionControl> control (aSession);
 
9024
    ComPtr<IInternalSessionControl> control (aSession);
8890
9025
 
8891
9026
    ComAssertRet (!control.isNull(), E_INVALIDARG);
8892
9027
 
8893
 
    AutoWriteLock alock (this);
 
9028
    /* Creating a Progress object requires the VirtualBox children lock, and
 
9029
     * thus locking it here is required by the lock order rules. */
 
9030
    AutoMultiWriteLock2 alock(mParent->childrenLock(), this->lockHandle());
8894
9031
 
8895
9032
    if (control.equalsTo (mData->mSession.mDirectControl))
8896
9033
    {
8906
9043
 
8907
9044
        /* set direct control to NULL to release the remote instance */
8908
9045
        mData->mSession.mDirectControl.setNull();
8909
 
        LogFlowThisFunc (("Direct control is set to NULL\n"));
 
9046
        LogFlowThisFunc(("Direct control is set to NULL\n"));
8910
9047
 
8911
9048
        /*  Create the progress object the client will use to wait until
8912
9049
         * #checkForDeath() is called to uninitialize this session object after
8913
9050
         * it releases the IPC semaphore. */
8914
 
        ComObjPtr <Progress> progress;
 
9051
        ComObjPtr<Progress> progress;
8915
9052
        progress.createObject();
8916
9053
        progress->init (mParent, static_cast <IMachine *> (mPeer),
8917
9054
                        Bstr (tr ("Closing session")), FALSE /* aCancelable */);
8918
 
        progress.queryInterfaceTo (aProgress);
 
9055
        progress.queryInterfaceTo(aProgress);
8919
9056
        mData->mSession.mProgress = progress;
8920
9057
    }
8921
9058
    else
8946
9083
{
8947
9084
    LogFlowThisFuncEnter();
8948
9085
 
8949
 
    AssertReturn (aProgress, E_INVALIDARG);
8950
 
    AssertReturn (aStateFilePath, E_POINTER);
 
9086
    AssertReturn(aProgress, E_INVALIDARG);
 
9087
    AssertReturn(aStateFilePath, E_POINTER);
8951
9088
 
8952
 
    AutoCaller autoCaller (this);
 
9089
    AutoCaller autoCaller(this);
8953
9090
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
8954
9091
 
8955
 
    AutoWriteLock alock (this);
 
9092
    AutoWriteLock alock(this);
8956
9093
 
8957
 
    AssertReturn (mData->mMachineState == MachineState_Paused &&
8958
 
                  mSnapshotData.mLastState == MachineState_Null &&
8959
 
                  mSnapshotData.mProgressId.isEmpty() &&
8960
 
                  mSnapshotData.mStateFilePath.isNull(),
8961
 
                  E_FAIL);
 
9094
    AssertReturn(    mData->mMachineState == MachineState_Paused
 
9095
                  && mSnapshotData.mLastState == MachineState_Null
 
9096
                  && mSnapshotData.mProgressId.isEmpty()
 
9097
                  && mSnapshotData.mStateFilePath.isEmpty(),
 
9098
                 E_FAIL);
8962
9099
 
8963
9100
    /* memorize the progress ID and add it to the global collection */
8964
9101
    Bstr progressId;
8984
9121
    /* set the state to Saving (this is expected by Console::SaveState()) */
8985
9122
    setMachineState (MachineState_Saving);
8986
9123
 
8987
 
    stateFilePath.cloneTo (aStateFilePath);
 
9124
    stateFilePath.cloneTo(aStateFilePath);
8988
9125
 
8989
9126
    return S_OK;
8990
9127
}
8994
9131
 */
8995
9132
STDMETHODIMP SessionMachine::EndSavingState (BOOL aSuccess)
8996
9133
{
8997
 
    LogFlowThisFunc (("\n"));
 
9134
    LogFlowThisFunc(("\n"));
8998
9135
 
8999
 
    AutoCaller autoCaller (this);
 
9136
    AutoCaller autoCaller(this);
9000
9137
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9001
9138
 
9002
9139
    /* endSavingState() need mParent lock */
9003
9140
    AutoMultiWriteLock2 alock (mParent, this);
9004
9141
 
9005
 
    AssertReturn (mData->mMachineState == MachineState_Saving &&
9006
 
                  mSnapshotData.mLastState != MachineState_Null &&
9007
 
                  !mSnapshotData.mProgressId.isEmpty() &&
9008
 
                  !mSnapshotData.mStateFilePath.isNull(),
9009
 
                  E_FAIL);
 
9142
    AssertReturn(    mData->mMachineState == MachineState_Saving
 
9143
                  && mSnapshotData.mLastState != MachineState_Null
 
9144
                  && !mSnapshotData.mProgressId.isEmpty()
 
9145
                  && !mSnapshotData.mStateFilePath.isEmpty(),
 
9146
                 E_FAIL);
9010
9147
 
9011
9148
    /*
9012
9149
     *  on success, set the state to Saved;
9027
9164
 */
9028
9165
STDMETHODIMP SessionMachine::AdoptSavedState (IN_BSTR aSavedStateFile)
9029
9166
{
9030
 
    LogFlowThisFunc (("\n"));
9031
 
 
9032
 
    AssertReturn (aSavedStateFile, E_INVALIDARG);
9033
 
 
9034
 
    AutoCaller autoCaller (this);
 
9167
    LogFlowThisFunc(("\n"));
 
9168
 
 
9169
    CheckComArgStrNotEmptyOrNull(aSavedStateFile);
 
9170
 
 
9171
    AutoCaller autoCaller(this);
9035
9172
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9036
9173
 
9037
 
    AutoWriteLock alock (this);
 
9174
    AutoWriteLock alock(this);
9038
9175
 
9039
 
    AssertReturn (mData->mMachineState == MachineState_PoweredOff ||
9040
 
                  mData->mMachineState == MachineState_Aborted,
9041
 
                  E_FAIL);
 
9176
    AssertReturn(   mData->mMachineState == MachineState_PoweredOff
 
9177
                 || mData->mMachineState == MachineState_Teleported
 
9178
                 || mData->mMachineState == MachineState_Aborted
 
9179
                 , E_FAIL); /** @todo setError. */
9042
9180
 
9043
9181
    Utf8Str stateFilePathFull = aSavedStateFile;
9044
 
    int vrc = calculateFullPath (stateFilePathFull, stateFilePathFull);
9045
 
    if (RT_FAILURE (vrc))
9046
 
        return setError (VBOX_E_FILE_ERROR,
9047
 
            tr ("Invalid saved state file path '%ls' (%Rrc)"),
9048
 
                aSavedStateFile, vrc);
 
9182
    int vrc = calculateFullPath(stateFilePathFull, stateFilePathFull);
 
9183
    if (RT_FAILURE(vrc))
 
9184
        return setError(VBOX_E_FILE_ERROR,
 
9185
                        tr("Invalid saved state file path '%ls' (%Rrc)"),
 
9186
                        aSavedStateFile,
 
9187
                        vrc);
9049
9188
 
9050
9189
    mSSData->mStateFilePath = stateFilePathFull;
9051
9190
 
9055
9194
    return setMachineState (MachineState_Saved);
9056
9195
}
9057
9196
 
9058
 
/**
9059
 
 *  @note Locks mParent + this object for writing.
9060
 
 */
9061
 
STDMETHODIMP SessionMachine::BeginTakingSnapshot (
9062
 
    IConsole *aInitiator, IN_BSTR aName, IN_BSTR aDescription,
9063
 
    IProgress *aProgress, BSTR *aStateFilePath,
9064
 
    IProgress **aServerProgress)
9065
 
{
9066
 
    LogFlowThisFuncEnter();
9067
 
 
9068
 
    AssertReturn (aInitiator && aName, E_INVALIDARG);
9069
 
    AssertReturn (aStateFilePath && aServerProgress, E_POINTER);
9070
 
 
9071
 
    LogFlowThisFunc (("aName='%ls'\n", aName));
9072
 
 
9073
 
    AutoCaller autoCaller (this);
9074
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9075
 
 
9076
 
    /* saveSettings() needs mParent lock */
9077
 
    AutoMultiWriteLock2 alock (mParent, this);
9078
 
 
9079
 
    AssertReturn ((!Global::IsOnlineOrTransient (mData->mMachineState) ||
9080
 
                   mData->mMachineState == MachineState_Paused) &&
9081
 
                  mSnapshotData.mLastState == MachineState_Null &&
9082
 
                  mSnapshotData.mSnapshot.isNull() &&
9083
 
                  mSnapshotData.mServerProgress.isNull() &&
9084
 
                  mSnapshotData.mCombinedProgress.isNull(),
9085
 
                  E_FAIL);
9086
 
 
9087
 
    bool takingSnapshotOnline = mData->mMachineState == MachineState_Paused;
9088
 
 
9089
 
    if (!takingSnapshotOnline && mData->mMachineState != MachineState_Saved)
9090
 
    {
9091
 
        /* save all current settings to ensure current changes are committed and
9092
 
         * hard disks are fixed up */
9093
 
        HRESULT rc = saveSettings();
9094
 
        CheckComRCReturnRC (rc);
9095
 
    }
9096
 
 
9097
 
    /// @todo NEWMEDIA so far, we decided to allow for Writhethrough hard disks
9098
 
    /// when taking snapshots putting all the responsibility to the user...
9099
 
#if 0
9100
 
    /* check that there are no Writethrough hard disks attached */
9101
 
    for (HDData::AttachmentList::const_iterator
9102
 
         it = mHDData->mAttachments.begin();
9103
 
         it != mHDData->mAttachments.end();
9104
 
         ++ it)
9105
 
    {
9106
 
        ComObjPtr <HardDisk> hd = (*it)->hardDisk();
9107
 
        AutoReadLock hdLock (hd);
9108
 
        if (hd->type() == HardDiskType_Writethrough)
9109
 
            return setError (E_FAIL,
9110
 
                tr ("Cannot take a snapshot because the Writethrough hard disk "
9111
 
                    "'%ls' is attached to this virtual machine"),
9112
 
                hd->locationFull().raw());
9113
 
    }
9114
 
#endif
9115
 
 
9116
 
    AssertReturn (aProgress || !takingSnapshotOnline, E_FAIL);
9117
 
 
9118
 
    /* create an ID for the snapshot */
9119
 
    Guid snapshotId;
9120
 
    snapshotId.create();
9121
 
 
9122
 
    Bstr stateFilePath;
9123
 
    /* stateFilePath is null when the machine is not online nor saved */
9124
 
    if (takingSnapshotOnline || mData->mMachineState == MachineState_Saved)
9125
 
        stateFilePath = Utf8StrFmt ("%ls%c{%RTuuid}.sav",
9126
 
                                    mUserData->mSnapshotFolderFull.raw(),
9127
 
                                    RTPATH_DELIMITER,
9128
 
                                    snapshotId.ptr());
9129
 
 
9130
 
    /* ensure the directory for the saved state file exists */
9131
 
    if (stateFilePath)
9132
 
    {
9133
 
        HRESULT rc = VirtualBox::ensureFilePathExists (Utf8Str (stateFilePath));
9134
 
        CheckComRCReturnRC (rc);
9135
 
    }
9136
 
 
9137
 
    /* create a snapshot machine object */
9138
 
    ComObjPtr <SnapshotMachine> snapshotMachine;
9139
 
    snapshotMachine.createObject();
9140
 
    HRESULT rc = snapshotMachine->init (this, snapshotId, stateFilePath);
9141
 
    AssertComRCReturn (rc, rc);
9142
 
 
9143
 
    Bstr progressDesc = BstrFmt (tr ("Taking snapshot of virtual machine '%ls'"),
9144
 
                                 mUserData->mName.raw());
9145
 
    Bstr firstOpDesc = Bstr (tr ("Preparing to take snapshot"));
9146
 
 
9147
 
    /* create a server-side progress object (it will be descriptionless when we
9148
 
     * need to combine it with the VM-side progress, i.e. when we're taking a
9149
 
     * snapshot online). The number of operations is: 1 (preparing) + # of
9150
 
     * hard disks + 1 (if the state is saved so we need to copy it)
9151
 
     */
9152
 
    ComObjPtr <Progress> serverProgress;
9153
 
    serverProgress.createObject();
9154
 
    {
9155
 
        ULONG opCount = 1 + (ULONG)mHDData->mAttachments.size();
9156
 
        if (mData->mMachineState == MachineState_Saved)
9157
 
            opCount ++;
9158
 
        if (takingSnapshotOnline)
9159
 
            rc = serverProgress->init (FALSE, opCount, firstOpDesc);
9160
 
        else
9161
 
            rc = serverProgress->init (mParent, aInitiator, progressDesc, FALSE,
9162
 
                                       opCount, firstOpDesc);
9163
 
        AssertComRCReturn (rc, rc);
9164
 
    }
9165
 
 
9166
 
    /* create a combined server-side progress object when necessary */
9167
 
    ComObjPtr <CombinedProgress> combinedProgress;
9168
 
    if (takingSnapshotOnline)
9169
 
    {
9170
 
        combinedProgress.createObject();
9171
 
        rc = combinedProgress->init (mParent, aInitiator, progressDesc,
9172
 
                                     serverProgress, aProgress);
9173
 
        AssertComRCReturn (rc, rc);
9174
 
    }
9175
 
 
9176
 
    /* create a snapshot object */
9177
 
    RTTIMESPEC time;
9178
 
    ComObjPtr <Snapshot> snapshot;
9179
 
    snapshot.createObject();
9180
 
    rc = snapshot->init (snapshotId, aName, aDescription,
9181
 
                         *RTTimeNow (&time), snapshotMachine,
9182
 
                         mData->mCurrentSnapshot);
9183
 
    AssertComRCReturnRC (rc);
9184
 
 
9185
 
    /* create and start the task on a separate thread (note that it will not
9186
 
     * start working until we release alock) */
9187
 
    TakeSnapshotTask *task = new TakeSnapshotTask (this);
9188
 
    int vrc = RTThreadCreate (NULL, taskHandler,
9189
 
                              (void *) task,
9190
 
                              0, RTTHREADTYPE_MAIN_WORKER, 0, "TakeSnapshot");
9191
 
    if (RT_FAILURE (vrc))
9192
 
    {
9193
 
        snapshot->uninit();
9194
 
        delete task;
9195
 
        ComAssertRCRet (vrc, E_FAIL);
9196
 
    }
9197
 
 
9198
 
    /* fill in the snapshot data */
9199
 
    mSnapshotData.mLastState = mData->mMachineState;
9200
 
    mSnapshotData.mSnapshot = snapshot;
9201
 
    mSnapshotData.mServerProgress = serverProgress;
9202
 
    mSnapshotData.mCombinedProgress = combinedProgress;
9203
 
 
9204
 
    /* set the state to Saving (this is expected by Console::TakeSnapshot()) */
9205
 
    setMachineState (MachineState_Saving);
9206
 
 
9207
 
    if (takingSnapshotOnline)
9208
 
        stateFilePath.cloneTo (aStateFilePath);
9209
 
    else
9210
 
        *aStateFilePath = NULL;
9211
 
 
9212
 
    serverProgress.queryInterfaceTo (aServerProgress);
9213
 
 
9214
 
    LogFlowThisFuncLeave();
9215
 
    return S_OK;
9216
 
}
9217
 
 
9218
 
/**
9219
 
 * @note Locks this object for writing.
9220
 
 */
9221
 
STDMETHODIMP SessionMachine::EndTakingSnapshot (BOOL aSuccess)
9222
 
{
9223
 
    LogFlowThisFunc (("\n"));
9224
 
 
9225
 
    AutoCaller autoCaller (this);
9226
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9227
 
 
9228
 
    AutoWriteLock alock (this);
9229
 
 
9230
 
    AssertReturn (!aSuccess ||
9231
 
                  (mData->mMachineState == MachineState_Saving &&
9232
 
                   mSnapshotData.mLastState != MachineState_Null &&
9233
 
                   !mSnapshotData.mSnapshot.isNull() &&
9234
 
                   !mSnapshotData.mServerProgress.isNull() &&
9235
 
                   !mSnapshotData.mCombinedProgress.isNull()),
9236
 
                  E_FAIL);
9237
 
 
9238
 
    /* set the state to the state we had when BeginTakingSnapshot() was called
9239
 
     * (this is expected by Console::TakeSnapshot() and
9240
 
     * Console::saveStateThread()) */
9241
 
    setMachineState (mSnapshotData.mLastState);
9242
 
 
9243
 
    return endTakingSnapshot (aSuccess);
9244
 
}
9245
 
 
9246
 
/**
9247
 
 *  @note Locks mParent + this + children objects for writing!
9248
 
 */
9249
 
STDMETHODIMP SessionMachine::DiscardSnapshot (
9250
 
    IConsole *aInitiator, IN_BSTR aId,
9251
 
    MachineState_T *aMachineState, IProgress **aProgress)
9252
 
{
9253
 
    LogFlowThisFunc (("\n"));
9254
 
 
9255
 
    Guid id(aId);
9256
 
    AssertReturn (aInitiator && !id.isEmpty(), E_INVALIDARG);
9257
 
    AssertReturn (aMachineState && aProgress, E_POINTER);
9258
 
 
9259
 
    AutoCaller autoCaller (this);
9260
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9261
 
 
9262
 
    /* saveSettings() needs mParent lock */
9263
 
    AutoMultiWriteLock2 alock (mParent, this);
9264
 
 
9265
 
    ComAssertRet (!Global::IsOnlineOrTransient (mData->mMachineState), E_FAIL);
9266
 
 
9267
 
    ComObjPtr <Snapshot> snapshot;
9268
 
    HRESULT rc = findSnapshot (id, snapshot, true /* aSetError */);
9269
 
    CheckComRCReturnRC (rc);
9270
 
 
9271
 
    AutoWriteLock snapshotLock (snapshot);
9272
 
 
9273
 
    {
9274
 
        AutoWriteLock chLock (snapshot->childrenLock());
9275
 
        size_t childrenCount = snapshot->children().size();
9276
 
        if (childrenCount > 1)
9277
 
            return setError (VBOX_E_INVALID_OBJECT_STATE,
9278
 
                tr ("Snapshot '%ls' of the machine '%ls' has more than one "
9279
 
                    "child snapshot (%d)"),
9280
 
                snapshot->data().mName.raw(), mUserData->mName.raw(),
9281
 
                childrenCount);
9282
 
    }
9283
 
 
9284
 
    /* If the snapshot being discarded is the current one, ensure current
9285
 
     * settings are committed and saved.
9286
 
     */
9287
 
    if (snapshot == mData->mCurrentSnapshot)
9288
 
    {
9289
 
        if (isModified())
9290
 
        {
9291
 
            rc = saveSettings();
9292
 
            CheckComRCReturnRC (rc);
9293
 
        }
9294
 
    }
9295
 
 
9296
 
    /* create a progress object. The number of operations is:
9297
 
     *   1 (preparing) + # of hard disks + 1 if the snapshot is online
9298
 
     */
9299
 
    ComObjPtr <Progress> progress;
9300
 
    progress.createObject();
9301
 
    rc = progress->init (mParent, aInitiator,
9302
 
                         Bstr (Utf8StrFmt (tr ("Discarding snapshot '%ls'"),
9303
 
                             snapshot->data().mName.raw())),
9304
 
                         FALSE /* aCancelable */,
9305
 
                         1 + (ULONG)snapshot->data().mMachine->mHDData->mAttachments.size() +
9306
 
                         (snapshot->stateFilePath().isNull() ? 0 : 1),
9307
 
                         Bstr (tr ("Preparing to discard snapshot")));
9308
 
    AssertComRCReturn (rc, rc);
9309
 
 
9310
 
    /* create and start the task on a separate thread */
9311
 
    DiscardSnapshotTask *task = new DiscardSnapshotTask (this, progress, snapshot);
9312
 
    int vrc = RTThreadCreate (NULL, taskHandler,
9313
 
                              (void *) task,
9314
 
                              0, RTTHREADTYPE_MAIN_WORKER, 0, "DiscardSnapshot");
9315
 
    if (RT_FAILURE (vrc))
9316
 
        delete task;
9317
 
    ComAssertRCRet (vrc, E_FAIL);
9318
 
 
9319
 
    /* set the proper machine state (note: after creating a Task instance) */
9320
 
    setMachineState (MachineState_Discarding);
9321
 
 
9322
 
    /* return the progress to the caller */
9323
 
    progress.queryInterfaceTo (aProgress);
9324
 
 
9325
 
    /* return the new state to the caller */
9326
 
    *aMachineState = mData->mMachineState;
9327
 
 
9328
 
    return S_OK;
9329
 
}
9330
 
 
9331
 
/**
9332
 
 *  @note Locks this + children objects for writing!
9333
 
 */
9334
 
STDMETHODIMP SessionMachine::DiscardCurrentState (
9335
 
    IConsole *aInitiator, MachineState_T *aMachineState, IProgress **aProgress)
9336
 
{
9337
 
    LogFlowThisFunc (("\n"));
9338
 
 
9339
 
    AssertReturn (aInitiator, E_INVALIDARG);
9340
 
    AssertReturn (aMachineState && aProgress, E_POINTER);
9341
 
 
9342
 
    AutoCaller autoCaller (this);
9343
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9344
 
 
9345
 
    AutoWriteLock alock (this);
9346
 
 
9347
 
    ComAssertRet (!Global::IsOnlineOrTransient (mData->mMachineState), E_FAIL);
9348
 
 
9349
 
    if (mData->mCurrentSnapshot.isNull())
9350
 
        return setError (VBOX_E_INVALID_OBJECT_STATE,
9351
 
            tr ("Could not discard the current state of the machine '%ls' "
9352
 
                "because it doesn't have any snapshots"),
9353
 
            mUserData->mName.raw());
9354
 
 
9355
 
    /* create a progress object. The number of operations is: 1 (preparing) + #
9356
 
     * of hard disks + 1 (if we need to copy the saved state file) */
9357
 
    ComObjPtr <Progress> progress;
9358
 
    progress.createObject();
9359
 
    {
9360
 
        ULONG opCount = 1 + (ULONG)mData->mCurrentSnapshot->data()
9361
 
                                       .mMachine->mHDData->mAttachments.size();
9362
 
        if (mData->mCurrentSnapshot->stateFilePath())
9363
 
            ++ opCount;
9364
 
        progress->init (mParent, aInitiator,
9365
 
                        Bstr (tr ("Discarding current machine state")),
9366
 
                        FALSE /* aCancelable */, opCount,
9367
 
                        Bstr (tr ("Preparing to discard current state")));
9368
 
    }
9369
 
 
9370
 
    /* create and start the task on a separate thread (note that it will not
9371
 
     * start working until we release alock) */
9372
 
    DiscardCurrentStateTask *task =
9373
 
        new DiscardCurrentStateTask (this, progress, false /* discardCurSnapshot */);
9374
 
    int vrc = RTThreadCreate (NULL, taskHandler,
9375
 
                              (void *) task,
9376
 
                              0, RTTHREADTYPE_MAIN_WORKER, 0, "DiscardCurState");
9377
 
    if (RT_FAILURE (vrc))
9378
 
    {
9379
 
        delete task;
9380
 
        ComAssertRCRet (vrc, E_FAIL);
9381
 
    }
9382
 
 
9383
 
    /* set the proper machine state (note: after creating a Task instance) */
9384
 
    setMachineState (MachineState_Discarding);
9385
 
 
9386
 
    /* return the progress to the caller */
9387
 
    progress.queryInterfaceTo (aProgress);
9388
 
 
9389
 
    /* return the new state to the caller */
9390
 
    *aMachineState = mData->mMachineState;
9391
 
 
9392
 
    return S_OK;
9393
 
}
9394
 
 
9395
 
/**
9396
 
 *  @note Locks thos object for writing!
9397
 
 */
9398
 
STDMETHODIMP SessionMachine::DiscardCurrentSnapshotAndState (
9399
 
    IConsole *aInitiator, MachineState_T *aMachineState, IProgress **aProgress)
9400
 
{
9401
 
    LogFlowThisFunc (("\n"));
9402
 
 
9403
 
    AssertReturn (aInitiator, E_INVALIDARG);
9404
 
    AssertReturn (aMachineState && aProgress, E_POINTER);
9405
 
 
9406
 
    AutoCaller autoCaller (this);
9407
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9408
 
 
9409
 
    AutoWriteLock alock (this);
9410
 
 
9411
 
    ComAssertRet (!Global::IsOnlineOrTransient (mData->mMachineState), E_FAIL);
9412
 
 
9413
 
    if (mData->mCurrentSnapshot.isNull())
9414
 
        return setError (VBOX_E_INVALID_OBJECT_STATE,
9415
 
            tr ("Could not discard the current state of the machine '%ls' "
9416
 
                "because it doesn't have any snapshots"),
9417
 
            mUserData->mName.raw());
9418
 
 
9419
 
    /* create a progress object. The number of operations is:
9420
 
     *   1 (preparing) + # of hard disks in the current snapshot +
9421
 
     *   # of hard disks in the previous snapshot +
9422
 
     *   1 if we need to copy the saved state file of the previous snapshot +
9423
 
     *   1 if the current snapshot is online
9424
 
     * or (if there is no previous snapshot):
9425
 
     *   1 (preparing) + # of hard disks in the current snapshot * 2 +
9426
 
     *   1 if we need to copy the saved state file of the current snapshot * 2
9427
 
     */
9428
 
    ComObjPtr <Progress> progress;
9429
 
    progress.createObject();
9430
 
    {
9431
 
        ComObjPtr <Snapshot> curSnapshot = mData->mCurrentSnapshot;
9432
 
        ComObjPtr <Snapshot> prevSnapshot = mData->mCurrentSnapshot->parent();
9433
 
 
9434
 
        ULONG opCount = 1;
9435
 
        if (prevSnapshot)
9436
 
        {
9437
 
            opCount += (ULONG)curSnapshot->data().mMachine->mHDData->mAttachments.size();
9438
 
            opCount += (ULONG)prevSnapshot->data().mMachine->mHDData->mAttachments.size();
9439
 
            if (prevSnapshot->stateFilePath())
9440
 
                ++ opCount;
9441
 
            if (curSnapshot->stateFilePath())
9442
 
                ++ opCount;
9443
 
        }
9444
 
        else
9445
 
        {
9446
 
            opCount +=
9447
 
                (ULONG)curSnapshot->data().mMachine->mHDData->mAttachments.size() * 2;
9448
 
            if (curSnapshot->stateFilePath())
9449
 
                opCount += 2;
9450
 
        }
9451
 
 
9452
 
        progress->init (mParent, aInitiator,
9453
 
                        Bstr (tr ("Discarding current machine snapshot and state")),
9454
 
                        FALSE /* aCancelable */, opCount,
9455
 
                        Bstr (tr ("Preparing to discard current snapshot and state")));
9456
 
    }
9457
 
 
9458
 
    /* create and start the task on a separate thread */
9459
 
    DiscardCurrentStateTask *task =
9460
 
        new DiscardCurrentStateTask (this, progress, true /* discardCurSnapshot */);
9461
 
    int vrc = RTThreadCreate (NULL, taskHandler,
9462
 
                              (void *) task,
9463
 
                              0, RTTHREADTYPE_MAIN_WORKER, 0, "DiscardCurStSnp");
9464
 
    if (RT_FAILURE (vrc))
9465
 
    {
9466
 
        delete task;
9467
 
        ComAssertRCRet (vrc, E_FAIL);
9468
 
    }
9469
 
 
9470
 
    /* set the proper machine state (note: after creating a Task instance) */
9471
 
    setMachineState (MachineState_Discarding);
9472
 
 
9473
 
    /* return the progress to the caller */
9474
 
    progress.queryInterfaceTo (aProgress);
9475
 
 
9476
 
    /* return the new state to the caller */
9477
 
    *aMachineState = mData->mMachineState;
9478
 
 
9479
 
    return S_OK;
9480
 
}
9481
 
 
9482
 
STDMETHODIMP SessionMachine::
9483
 
PullGuestProperties (ComSafeArrayOut (BSTR, aNames),
9484
 
                     ComSafeArrayOut (BSTR, aValues),
9485
 
                     ComSafeArrayOut (ULONG64, aTimestamps),
9486
 
                     ComSafeArrayOut (BSTR, aFlags))
9487
 
{
9488
 
    LogFlowThisFunc (("\n"));
 
9197
STDMETHODIMP SessionMachine::PullGuestProperties(ComSafeArrayOut(BSTR, aNames),
 
9198
                                                 ComSafeArrayOut(BSTR, aValues),
 
9199
                                                 ComSafeArrayOut(ULONG64, aTimestamps),
 
9200
                                                 ComSafeArrayOut(BSTR, aFlags))
 
9201
{
 
9202
    LogFlowThisFunc(("\n"));
9489
9203
 
9490
9204
#ifdef VBOX_WITH_GUEST_PROPS
9491
9205
    using namespace guestProp;
9492
9206
 
9493
 
    AutoCaller autoCaller (this);
 
9207
    AutoCaller autoCaller(this);
9494
9208
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9495
9209
 
9496
 
    AutoReadLock alock (this);
 
9210
    AutoReadLock alock(this);
9497
9211
 
9498
 
    AssertReturn (!ComSafeArrayOutIsNull (aNames), E_POINTER);
9499
 
    AssertReturn (!ComSafeArrayOutIsNull (aValues), E_POINTER);
9500
 
    AssertReturn (!ComSafeArrayOutIsNull (aTimestamps), E_POINTER);
9501
 
    AssertReturn (!ComSafeArrayOutIsNull (aFlags), E_POINTER);
 
9212
    AssertReturn(!ComSafeArrayOutIsNull(aNames), E_POINTER);
 
9213
    AssertReturn(!ComSafeArrayOutIsNull(aValues), E_POINTER);
 
9214
    AssertReturn(!ComSafeArrayOutIsNull(aTimestamps), E_POINTER);
 
9215
    AssertReturn(!ComSafeArrayOutIsNull(aFlags), E_POINTER);
9502
9216
 
9503
9217
    size_t cEntries = mHWData->mGuestProperties.size();
9504
 
    com::SafeArray <BSTR> names (cEntries);
9505
 
    com::SafeArray <BSTR> values (cEntries);
9506
 
    com::SafeArray <ULONG64> timestamps (cEntries);
9507
 
    com::SafeArray <BSTR> flags (cEntries);
 
9218
    com::SafeArray<BSTR> names (cEntries);
 
9219
    com::SafeArray<BSTR> values (cEntries);
 
9220
    com::SafeArray<ULONG64> timestamps (cEntries);
 
9221
    com::SafeArray<BSTR> flags (cEntries);
9508
9222
    unsigned i = 0;
9509
9223
    for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
9510
 
         it != mHWData->mGuestProperties.end(); ++it)
 
9224
         it != mHWData->mGuestProperties.end();
 
9225
         ++it)
9511
9226
    {
9512
9227
        char szFlags[MAX_FLAGS_LEN + 1];
9513
 
        it->mName.cloneTo (&names[i]);
9514
 
        it->mValue.cloneTo (&values[i]);
 
9228
        it->strName.cloneTo(&names[i]);
 
9229
        it->strValue.cloneTo(&values[i]);
9515
9230
        timestamps[i] = it->mTimestamp;
9516
 
        writeFlags (it->mFlags, szFlags);
9517
 
        Bstr (szFlags).cloneTo (&flags[i]);
 
9231
        /* If it is NULL, keep it NULL. */
 
9232
        if (it->mFlags)
 
9233
        {
 
9234
            writeFlags(it->mFlags, szFlags);
 
9235
            Bstr(szFlags).cloneTo(&flags[i]);
 
9236
        }
 
9237
        else
 
9238
            flags[i] = NULL;
9518
9239
        ++i;
9519
9240
    }
9520
 
    names.detachTo (ComSafeArrayOutArg (aNames));
9521
 
    values.detachTo (ComSafeArrayOutArg (aValues));
9522
 
    timestamps.detachTo (ComSafeArrayOutArg (aTimestamps));
9523
 
    flags.detachTo (ComSafeArrayOutArg (aFlags));
 
9241
    names.detachTo(ComSafeArrayOutArg(aNames));
 
9242
    values.detachTo(ComSafeArrayOutArg(aValues));
 
9243
    timestamps.detachTo(ComSafeArrayOutArg(aTimestamps));
 
9244
    flags.detachTo(ComSafeArrayOutArg(aFlags));
9524
9245
    mHWData->mPropertyServiceActive = true;
9525
9246
    return S_OK;
9526
9247
#else
9528
9249
#endif
9529
9250
}
9530
9251
 
9531
 
STDMETHODIMP SessionMachine::PushGuestProperties (ComSafeArrayIn (IN_BSTR, aNames),
9532
 
                                                  ComSafeArrayIn (IN_BSTR, aValues),
9533
 
                                                  ComSafeArrayIn (ULONG64, aTimestamps),
9534
 
                                                  ComSafeArrayIn (IN_BSTR, aFlags))
 
9252
STDMETHODIMP SessionMachine::PushGuestProperties(ComSafeArrayIn(IN_BSTR, aNames),
 
9253
                                                 ComSafeArrayIn(IN_BSTR, aValues),
 
9254
                                                 ComSafeArrayIn(ULONG64, aTimestamps),
 
9255
                                                 ComSafeArrayIn(IN_BSTR, aFlags))
9535
9256
{
9536
 
    LogFlowThisFunc (("\n"));
 
9257
    LogFlowThisFunc(("\n"));
9537
9258
 
9538
9259
#ifdef VBOX_WITH_GUEST_PROPS
9539
9260
    using namespace guestProp;
9540
9261
 
9541
 
    AutoCaller autoCaller (this);
9542
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9543
 
 
9544
 
    AutoWriteLock alock (this);
9545
 
 
9546
 
    /* Temporarily reset the registered flag, so that our machine state
9547
 
     * changes (i.e. mHWData.backup()) succeed.  (isMutable() used in
9548
 
     * all setters will return FALSE for a Machine instance if mRegistered
9549
 
     * is TRUE).  This is copied from registeredInit(), and may or may not be
9550
 
     * the right way to handle this. */
 
9262
    AssertReturn(!ComSafeArrayInIsNull(aNames),      E_POINTER);
 
9263
    AssertReturn(!ComSafeArrayInIsNull(aValues),     E_POINTER);
 
9264
    AssertReturn(!ComSafeArrayInIsNull(aTimestamps), E_POINTER);
 
9265
    AssertReturn(!ComSafeArrayInIsNull(aFlags),      E_POINTER);
 
9266
 
 
9267
    AutoCaller autoCaller(this);
 
9268
    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
 
9269
 
 
9270
    AutoWriteLock alock(this);
 
9271
 
 
9272
    /*
 
9273
     * Temporarily reset the registered flag, so that our machine state
 
9274
     * changes (i.e. mHWData.backup()) succeed.  (isMutable() used in all
 
9275
     * setters will return FALSE for a Machine instance if mRegistered is TRUE).
 
9276
     *
 
9277
     * This is copied from registeredInit(), and may or may not be the right
 
9278
     * way to handle this.
 
9279
     */
 
9280
    Assert(mData->mRegistered);
9551
9281
    mData->mRegistered = FALSE;
9552
 
    HRESULT rc = checkStateDependency (MutableStateDep);
9553
 
    LogRel (("checkStateDependency (MutableStateDep) returned 0x%x\n", rc));
9554
 
    CheckComRCReturnRC (rc);
9555
 
 
9556
 
    // ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
9557
 
 
9558
 
    AssertReturn (!ComSafeArrayInIsNull (aNames), E_POINTER);
9559
 
    AssertReturn (!ComSafeArrayInIsNull (aValues), E_POINTER);
9560
 
    AssertReturn (!ComSafeArrayInIsNull (aTimestamps), E_POINTER);
9561
 
    AssertReturn (!ComSafeArrayInIsNull (aFlags), E_POINTER);
9562
 
 
9563
 
    com::SafeArray <IN_BSTR> names (ComSafeArrayInArg (aNames));
9564
 
    com::SafeArray <IN_BSTR> values (ComSafeArrayInArg (aValues));
9565
 
    com::SafeArray <ULONG64> timestamps (ComSafeArrayInArg (aTimestamps));
9566
 
    com::SafeArray <IN_BSTR> flags (ComSafeArrayInArg (aFlags));
 
9282
 
 
9283
    HRESULT rc = checkStateDependency(MutableStateDep);
 
9284
    AssertLogRelMsgReturn(SUCCEEDED(rc), ("%Rhrc\n", rc), rc);
 
9285
 
 
9286
    com::SafeArray<IN_BSTR> names(     ComSafeArrayInArg(aNames));
 
9287
    com::SafeArray<IN_BSTR> values(    ComSafeArrayInArg(aValues));
 
9288
    com::SafeArray<ULONG64> timestamps(ComSafeArrayInArg(aTimestamps));
 
9289
    com::SafeArray<IN_BSTR> flags(     ComSafeArrayInArg(aFlags));
 
9290
 
9567
9291
    DiscardSettings();
9568
9292
    mHWData.backup();
9569
 
    mHWData->mGuestProperties.erase (mHWData->mGuestProperties.begin(),
 
9293
 
 
9294
    mHWData->mGuestProperties.erase(mHWData->mGuestProperties.begin(),
9570
9295
                                    mHWData->mGuestProperties.end());
9571
9296
    for (unsigned i = 0; i < names.size(); ++i)
9572
9297
    {
9573
9298
        uint32_t fFlags = NILFLAG;
9574
 
        validateFlags (Utf8Str (flags[i]).raw(), &fFlags);
 
9299
        validateFlags(Utf8Str(flags[i]).raw(), &fFlags);
9575
9300
        HWData::GuestProperty property = { names[i], values[i], timestamps[i], fFlags };
9576
 
        mHWData->mGuestProperties.push_back (property);
 
9301
        mHWData->mGuestProperties.push_back(property);
9577
9302
    }
 
9303
 
9578
9304
    mHWData->mPropertyServiceActive = false;
 
9305
 
9579
9306
    alock.unlock();
9580
9307
    SaveSettings();
 
9308
 
9581
9309
    /* Restore the mRegistered flag. */
 
9310
    alock.lock();
9582
9311
    mData->mRegistered = TRUE;
 
9312
 
9583
9313
    return S_OK;
9584
9314
#else
9585
9315
    ReturnComNotImplemented();
9586
9316
#endif
9587
9317
}
9588
9318
 
9589
 
STDMETHODIMP SessionMachine::PushGuestProperty (IN_BSTR aName, IN_BSTR aValue,
9590
 
                                                ULONG64 aTimestamp, IN_BSTR aFlags)
 
9319
STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
 
9320
                                               IN_BSTR aValue,
 
9321
                                               ULONG64 aTimestamp,
 
9322
                                               IN_BSTR aFlags)
9591
9323
{
9592
 
    LogFlowThisFunc (("\n"));
 
9324
    LogFlowThisFunc(("\n"));
9593
9325
 
9594
9326
#ifdef VBOX_WITH_GUEST_PROPS
9595
9327
    using namespace guestProp;
9596
9328
 
9597
 
    CheckComArgNotNull (aName);
9598
 
    if ((aValue != NULL) && (!VALID_PTR (aValue) || !VALID_PTR (aFlags)))
 
9329
    CheckComArgNotNull(aName);
 
9330
    if (aValue != NULL && (!VALID_PTR(aValue) || !VALID_PTR(aFlags)))
9599
9331
        return E_POINTER;  /* aValue can be NULL to indicate deletion */
9600
9332
 
9601
 
    Utf8Str utf8Name (aName);
9602
 
    Utf8Str utf8Flags (aFlags);
9603
 
    Utf8Str utf8Patterns (mHWData->mGuestPropertyNotificationPatterns);
9604
 
    if (   utf8Name.isNull()
9605
 
        || ((aFlags != NULL) && utf8Flags.isNull())
9606
 
        || utf8Patterns.isNull()
9607
 
       )
9608
 
        return E_OUTOFMEMORY;
9609
 
 
9610
 
    uint32_t fFlags = NILFLAG;
9611
 
    if ((aFlags != NULL) && RT_FAILURE (validateFlags (utf8Flags.raw(), &fFlags)))
9612
 
        return E_INVALIDARG;
9613
 
 
9614
 
    bool matchAll = false;
9615
 
    if (utf8Patterns.length() == 0)
9616
 
        matchAll = true;
9617
 
 
9618
 
    AutoCaller autoCaller (this);
9619
 
    CheckComRCReturnRC (autoCaller.rc());
9620
 
 
9621
 
    AutoWriteLock alock (this);
9622
 
 
9623
 
    HRESULT rc = checkStateDependency (MutableStateDep);
9624
 
    CheckComRCReturnRC (rc);
9625
 
 
9626
 
    mHWData.backup();
9627
 
    for (HWData::GuestPropertyList::iterator iter = mHWData->mGuestProperties.begin();
9628
 
         iter != mHWData->mGuestProperties.end(); ++iter)
9629
 
        if (aName == iter->mName)
9630
 
        {
9631
 
            mHWData->mGuestProperties.erase (iter);
9632
 
            break;
9633
 
        }
9634
 
    if (aValue != NULL)
9635
 
    {
9636
 
        HWData::GuestProperty property = { aName, aValue, aTimestamp, fFlags };
9637
 
        mHWData->mGuestProperties.push_back (property);
9638
 
    }
9639
 
 
9640
 
    /* send a callback notification if appropriate */
9641
 
    alock.leave();
9642
 
    if (   matchAll
9643
 
        || RTStrSimplePatternMultiMatch (utf8Patterns.raw(), RTSTR_MAX,
9644
 
                                         utf8Name.raw(), RTSTR_MAX, NULL)
9645
 
       )
9646
 
        mParent->onGuestPropertyChange (mData->mUuid, aName, aValue, aFlags);
9647
 
 
 
9333
    try
 
9334
    {
 
9335
        /*
 
9336
         * Convert input up front.
 
9337
         */
 
9338
        Utf8Str     utf8Name(aName);
 
9339
        uint32_t    fFlags = NILFLAG;
 
9340
        if (aFlags)
 
9341
        {
 
9342
            Utf8Str utf8Flags(aFlags);
 
9343
            int vrc = validateFlags(utf8Flags.raw(), &fFlags);
 
9344
            AssertRCReturn(vrc, E_INVALIDARG);
 
9345
        }
 
9346
 
 
9347
        /*
 
9348
         * Now grab the object lock, validate the state and do the update.
 
9349
         */
 
9350
        AutoCaller autoCaller(this);
 
9351
        CheckComRCReturnRC(autoCaller.rc());
 
9352
 
 
9353
        AutoWriteLock alock(this);
 
9354
 
 
9355
        AssertReturn(mHWData->mPropertyServiceActive, VBOX_E_INVALID_OBJECT_STATE);
 
9356
        switch (mData->mMachineState)
 
9357
        {
 
9358
            case MachineState_Paused:
 
9359
            case MachineState_Running:
 
9360
            case MachineState_Teleporting:
 
9361
            case MachineState_TeleportingPausedVM:
 
9362
            case MachineState_LiveSnapshotting:
 
9363
            case MachineState_Saving:
 
9364
                break;
 
9365
 
 
9366
            default:
 
9367
                AssertMsgFailedReturn(("%s\n", Global::stringifyMachineState(mData->mMachineState)),
 
9368
                                      VBOX_E_INVALID_VM_STATE);
 
9369
        }
 
9370
 
 
9371
        mHWData.backup();
 
9372
 
 
9373
        /** @todo r=bird: The careful memory handling doesn't work out here because
 
9374
         *  the catch block won't undo any damange we've done.  So, if push_back throws
 
9375
         *  bad_alloc then you've lost the value.
 
9376
         *
 
9377
         *  Another thing. Doing a linear search here isn't extremely efficient, esp.
 
9378
         *  since values that changes actually bubbles to the end of the list.  Using
 
9379
         *  something that has an efficient lookup and can tollerate a bit of updates
 
9380
         *  would be nice.  RTStrSpace is one suggestion (it's not perfect).  Some
 
9381
         *  combination of RTStrCache (for sharing names and getting uniqueness into
 
9382
         *  the bargain) and hash/tree is another. */
 
9383
        for (HWData::GuestPropertyList::iterator iter = mHWData->mGuestProperties.begin();
 
9384
             iter != mHWData->mGuestProperties.end();
 
9385
             ++iter)
 
9386
            if (utf8Name == iter->strName)
 
9387
            {
 
9388
                mHWData->mGuestProperties.erase(iter);
 
9389
                break;
 
9390
            }
 
9391
        if (aValue != NULL)
 
9392
        {
 
9393
            HWData::GuestProperty property = { aName, aValue, aTimestamp, fFlags };
 
9394
            mHWData->mGuestProperties.push_back(property);
 
9395
        }
 
9396
 
 
9397
        /*
 
9398
         * Send a callback notification if appropriate
 
9399
         */
 
9400
        if (    mHWData->mGuestPropertyNotificationPatterns.isEmpty()
 
9401
             || RTStrSimplePatternMultiMatch(mHWData->mGuestPropertyNotificationPatterns.raw(),
 
9402
                                             RTSTR_MAX,
 
9403
                                             utf8Name.raw(),
 
9404
                                             RTSTR_MAX, NULL)
 
9405
           )
 
9406
        {
 
9407
            alock.leave();
 
9408
 
 
9409
            mParent->onGuestPropertyChange(mData->mUuid,
 
9410
                                           aName,
 
9411
                                           aValue,
 
9412
                                           aFlags);
 
9413
        }
 
9414
    }
 
9415
    catch (...)
 
9416
    {
 
9417
        return VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
 
9418
    }
9648
9419
    return S_OK;
9649
9420
#else
9650
9421
    ReturnComNotImplemented();
9677
9448
    /* Enclose autoCaller with a block because calling uninit() from under it
9678
9449
     * will deadlock. */
9679
9450
    {
9680
 
        AutoCaller autoCaller (this);
 
9451
        AutoCaller autoCaller(this);
9681
9452
        if (!autoCaller.isOk())
9682
9453
        {
9683
9454
            /* return true if not ready, to cause the client watcher to exclude
9684
9455
             * the corresponding session from watching */
9685
 
            LogFlowThisFunc (("Already uninitialized!"));
 
9456
            LogFlowThisFunc(("Already uninitialized!\n"));
9686
9457
            return true;
9687
9458
        }
9688
9459
 
9689
 
        AutoWriteLock alock (this);
 
9460
        AutoWriteLock alock(this);
9690
9461
 
9691
9462
        /* Determine the reason of death: if the session state is Closing here,
9692
9463
         * everything is fine. Otherwise it means that the client did not call
9743
9514
/**
9744
9515
 *  @note Locks this object for reading.
9745
9516
 */
9746
 
HRESULT SessionMachine::onDVDDriveChange()
9747
 
{
9748
 
    LogFlowThisFunc (("\n"));
9749
 
 
9750
 
    AutoCaller autoCaller (this);
9751
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9752
 
 
9753
 
    ComPtr <IInternalSessionControl> directControl;
9754
 
    {
9755
 
        AutoReadLock alock (this);
9756
 
        directControl = mData->mSession.mDirectControl;
9757
 
    }
9758
 
 
9759
 
    /* ignore notifications sent after #OnSessionEnd() is called */
9760
 
    if (!directControl)
9761
 
        return S_OK;
9762
 
 
9763
 
    return directControl->OnDVDDriveChange();
9764
 
}
9765
 
 
9766
 
/**
9767
 
 *  @note Locks this object for reading.
9768
 
 */
9769
 
HRESULT SessionMachine::onFloppyDriveChange()
9770
 
{
9771
 
    LogFlowThisFunc (("\n"));
9772
 
 
9773
 
    AutoCaller autoCaller (this);
9774
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9775
 
 
9776
 
    ComPtr <IInternalSessionControl> directControl;
9777
 
    {
9778
 
        AutoReadLock alock (this);
9779
 
        directControl = mData->mSession.mDirectControl;
9780
 
    }
9781
 
 
9782
 
    /* ignore notifications sent after #OnSessionEnd() is called */
9783
 
    if (!directControl)
9784
 
        return S_OK;
9785
 
 
9786
 
    return directControl->OnFloppyDriveChange();
9787
 
}
9788
 
 
9789
 
/**
9790
 
 *  @note Locks this object for reading.
9791
 
 */
9792
 
HRESULT SessionMachine::onNetworkAdapterChange (INetworkAdapter *networkAdapter)
9793
 
{
9794
 
    LogFlowThisFunc (("\n"));
9795
 
 
9796
 
    AutoCaller autoCaller (this);
9797
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9798
 
 
9799
 
    ComPtr <IInternalSessionControl> directControl;
9800
 
    {
9801
 
        AutoReadLock alock (this);
9802
 
        directControl = mData->mSession.mDirectControl;
9803
 
    }
9804
 
 
9805
 
    /* ignore notifications sent after #OnSessionEnd() is called */
9806
 
    if (!directControl)
9807
 
        return S_OK;
9808
 
 
9809
 
    return directControl->OnNetworkAdapterChange (networkAdapter);
 
9517
HRESULT SessionMachine::onNetworkAdapterChange (INetworkAdapter *networkAdapter, BOOL changeAdapter)
 
9518
{
 
9519
    LogFlowThisFunc(("\n"));
 
9520
 
 
9521
    AutoCaller autoCaller(this);
 
9522
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
 
9523
 
 
9524
    ComPtr<IInternalSessionControl> directControl;
 
9525
    {
 
9526
        AutoReadLock alock(this);
 
9527
        directControl = mData->mSession.mDirectControl;
 
9528
    }
 
9529
 
 
9530
    /* ignore notifications sent after #OnSessionEnd() is called */
 
9531
    if (!directControl)
 
9532
        return S_OK;
 
9533
 
 
9534
    return directControl->OnNetworkAdapterChange (networkAdapter, changeAdapter);
9810
9535
}
9811
9536
 
9812
9537
/**
9814
9539
 */
9815
9540
HRESULT SessionMachine::onSerialPortChange (ISerialPort *serialPort)
9816
9541
{
9817
 
    LogFlowThisFunc (("\n"));
 
9542
    LogFlowThisFunc(("\n"));
9818
9543
 
9819
 
    AutoCaller autoCaller (this);
 
9544
    AutoCaller autoCaller(this);
9820
9545
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9821
9546
 
9822
 
    ComPtr <IInternalSessionControl> directControl;
 
9547
    ComPtr<IInternalSessionControl> directControl;
9823
9548
    {
9824
 
        AutoReadLock alock (this);
 
9549
        AutoReadLock alock(this);
9825
9550
        directControl = mData->mSession.mDirectControl;
9826
9551
    }
9827
9552
 
9837
9562
 */
9838
9563
HRESULT SessionMachine::onParallelPortChange (IParallelPort *parallelPort)
9839
9564
{
9840
 
    LogFlowThisFunc (("\n"));
 
9565
    LogFlowThisFunc(("\n"));
9841
9566
 
9842
 
    AutoCaller autoCaller (this);
 
9567
    AutoCaller autoCaller(this);
9843
9568
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9844
9569
 
9845
 
    ComPtr <IInternalSessionControl> directControl;
 
9570
    ComPtr<IInternalSessionControl> directControl;
9846
9571
    {
9847
 
        AutoReadLock alock (this);
 
9572
        AutoReadLock alock(this);
9848
9573
        directControl = mData->mSession.mDirectControl;
9849
9574
    }
9850
9575
 
9860
9585
 */
9861
9586
HRESULT SessionMachine::onStorageControllerChange ()
9862
9587
{
9863
 
    LogFlowThisFunc (("\n"));
 
9588
    LogFlowThisFunc(("\n"));
9864
9589
 
9865
 
    AutoCaller autoCaller (this);
 
9590
    AutoCaller autoCaller(this);
9866
9591
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9867
9592
 
9868
 
    ComPtr <IInternalSessionControl> directControl;
 
9593
    ComPtr<IInternalSessionControl> directControl;
9869
9594
    {
9870
 
        AutoReadLock alock (this);
 
9595
        AutoReadLock alock(this);
9871
9596
        directControl = mData->mSession.mDirectControl;
9872
9597
    }
9873
9598
 
9881
9606
/**
9882
9607
 *  @note Locks this object for reading.
9883
9608
 */
 
9609
HRESULT SessionMachine::onMediumChange(IMediumAttachment *aAttachment, BOOL aForce)
 
9610
{
 
9611
    LogFlowThisFunc(("\n"));
 
9612
 
 
9613
    AutoCaller autoCaller(this);
 
9614
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
 
9615
 
 
9616
    ComPtr<IInternalSessionControl> directControl;
 
9617
    {
 
9618
        AutoReadLock alock(this);
 
9619
        directControl = mData->mSession.mDirectControl;
 
9620
    }
 
9621
 
 
9622
    /* ignore notifications sent after #OnSessionEnd() is called */
 
9623
    if (!directControl)
 
9624
        return S_OK;
 
9625
 
 
9626
    return directControl->OnMediumChange(aAttachment, aForce);
 
9627
}
 
9628
 
 
9629
/**
 
9630
 *  @note Locks this object for reading.
 
9631
 */
9884
9632
HRESULT SessionMachine::onVRDPServerChange()
9885
9633
{
9886
 
    LogFlowThisFunc (("\n"));
 
9634
    LogFlowThisFunc(("\n"));
9887
9635
 
9888
 
    AutoCaller autoCaller (this);
 
9636
    AutoCaller autoCaller(this);
9889
9637
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9890
9638
 
9891
 
    ComPtr <IInternalSessionControl> directControl;
 
9639
    ComPtr<IInternalSessionControl> directControl;
9892
9640
    {
9893
 
        AutoReadLock alock (this);
 
9641
        AutoReadLock alock(this);
9894
9642
        directControl = mData->mSession.mDirectControl;
9895
9643
    }
9896
9644
 
9906
9654
 */
9907
9655
HRESULT SessionMachine::onUSBControllerChange()
9908
9656
{
9909
 
    LogFlowThisFunc (("\n"));
 
9657
    LogFlowThisFunc(("\n"));
9910
9658
 
9911
 
    AutoCaller autoCaller (this);
 
9659
    AutoCaller autoCaller(this);
9912
9660
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
9913
9661
 
9914
 
    ComPtr <IInternalSessionControl> directControl;
 
9662
    ComPtr<IInternalSessionControl> directControl;
9915
9663
    {
9916
 
        AutoReadLock alock (this);
 
9664
        AutoReadLock alock(this);
9917
9665
        directControl = mData->mSession.mDirectControl;
9918
9666
    }
9919
9667
 
9929
9677
 */
9930
9678
HRESULT SessionMachine::onSharedFolderChange()
9931
9679
{
9932
 
    LogFlowThisFunc (("\n"));
9933
 
 
9934
 
    AutoCaller autoCaller (this);
9935
 
    AssertComRCReturnRC (autoCaller.rc());
9936
 
 
9937
 
    ComPtr <IInternalSessionControl> directControl;
 
9680
    LogFlowThisFunc(("\n"));
 
9681
 
 
9682
    AutoCaller autoCaller(this);
 
9683
    AssertComRCReturnRC(autoCaller.rc());
 
9684
 
 
9685
    ComPtr<IInternalSessionControl> directControl;
9938
9686
    {
9939
 
        AutoReadLock alock (this);
 
9687
        AutoReadLock alock(this);
9940
9688
        directControl = mData->mSession.mDirectControl;
9941
9689
    }
9942
9690
 
9953
9701
 *
9954
9702
 *  @note Locks this object for reading.
9955
9703
 */
9956
 
bool SessionMachine::hasMatchingUSBFilter (const ComObjPtr <HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
 
9704
bool SessionMachine::hasMatchingUSBFilter (const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
9957
9705
{
9958
 
    AutoCaller autoCaller (this);
 
9706
    AutoCaller autoCaller(this);
9959
9707
    /* silently return if not ready -- this method may be called after the
9960
9708
     * direct machine session has been called */
9961
9709
    if (!autoCaller.isOk())
9962
9710
        return false;
9963
9711
 
9964
 
    AutoReadLock alock (this);
 
9712
    AutoReadLock alock(this);
9965
9713
 
9966
9714
#ifdef VBOX_WITH_USB
9967
9715
    switch (mData->mMachineState)
9968
9716
    {
9969
9717
        case MachineState_Starting:
9970
9718
        case MachineState_Restoring:
 
9719
        case MachineState_TeleportingIn:
9971
9720
        case MachineState_Paused:
9972
9721
        case MachineState_Running:
 
9722
        /** @todo Live Migration: snapshoting & teleporting. Need to fend things of
 
9723
         *        elsewhere... */
9973
9724
            return mUSBController->hasMatchingFilter (aDevice, aMaskedIfs);
9974
9725
        default: break;
9975
9726
    }
9987
9738
                                           IVirtualBoxErrorInfo *aError,
9988
9739
                                           ULONG aMaskedIfs)
9989
9740
{
9990
 
    LogFlowThisFunc (("\n"));
 
9741
    LogFlowThisFunc(("\n"));
9991
9742
 
9992
 
    AutoCaller autoCaller (this);
 
9743
    AutoCaller autoCaller(this);
9993
9744
 
9994
9745
    /* This notification may happen after the machine object has been
9995
9746
     * uninitialized (the session was closed), so don't assert. */
9996
 
    CheckComRCReturnRC (autoCaller.rc());
 
9747
    CheckComRCReturnRC(autoCaller.rc());
9997
9748
 
9998
 
    ComPtr <IInternalSessionControl> directControl;
 
9749
    ComPtr<IInternalSessionControl> directControl;
9999
9750
    {
10000
 
        AutoReadLock alock (this);
 
9751
        AutoReadLock alock(this);
10001
9752
        directControl = mData->mSession.mDirectControl;
10002
9753
    }
10003
9754
 
10019
9770
HRESULT SessionMachine::onUSBDeviceDetach (IN_BSTR aId,
10020
9771
                                           IVirtualBoxErrorInfo *aError)
10021
9772
{
10022
 
    LogFlowThisFunc (("\n"));
 
9773
    LogFlowThisFunc(("\n"));
10023
9774
 
10024
 
    AutoCaller autoCaller (this);
 
9775
    AutoCaller autoCaller(this);
10025
9776
 
10026
9777
    /* This notification may happen after the machine object has been
10027
9778
     * uninitialized (the session was closed), so don't assert. */
10028
 
    CheckComRCReturnRC (autoCaller.rc());
 
9779
    CheckComRCReturnRC(autoCaller.rc());
10029
9780
 
10030
 
    ComPtr <IInternalSessionControl> directControl;
 
9781
    ComPtr<IInternalSessionControl> directControl;
10031
9782
    {
10032
 
        AutoReadLock alock (this);
 
9783
        AutoReadLock alock(this);
10033
9784
        directControl = mData->mSession.mDirectControl;
10034
9785
    }
10035
9786
 
10061
9812
{
10062
9813
    LogFlowThisFuncEnter();
10063
9814
 
10064
 
    AutoCaller autoCaller (this);
 
9815
    AutoCaller autoCaller(this);
10065
9816
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
10066
9817
 
10067
9818
    /* saveSettings() needs mParent lock */
10079
9830
    else
10080
9831
    {
10081
9832
        /* delete the saved state file (it might have been already created) */
10082
 
        RTFileDelete (Utf8Str (mSnapshotData.mStateFilePath));
 
9833
        RTFileDelete(mSnapshotData.mStateFilePath.c_str());
10083
9834
    }
10084
9835
 
10085
9836
    /* remove the completed progress object */
10086
 
    mParent->removeProgress (mSnapshotData.mProgressId);
 
9837
    mParent->removeProgress(mSnapshotData.mProgressId);
10087
9838
 
10088
9839
    /* clear out the temporary saved state data */
10089
9840
    mSnapshotData.mLastState = MachineState_Null;
10095
9846
}
10096
9847
 
10097
9848
/**
10098
 
 * Helper method to finalize taking a snapshot. Gets called to finalize the
10099
 
 * "take snapshot" procedure.
10100
 
 *
10101
 
 * Expected to be called after completing *all* the tasks related to taking the
10102
 
 * snapshot, either successfully or unsuccessfilly.
10103
 
 *
10104
 
 * @param aSuccess  TRUE if the snapshot has been taken successfully.
10105
 
 *
10106
 
 * @note Locks this objects for writing.
10107
 
 */
10108
 
HRESULT SessionMachine::endTakingSnapshot (BOOL aSuccess)
10109
 
{
10110
 
    LogFlowThisFuncEnter();
10111
 
 
10112
 
    AutoCaller autoCaller (this);
10113
 
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
10114
 
 
10115
 
    AutoWriteLock alock (this);
10116
 
 
10117
 
    AssertReturn (!mSnapshotData.mSnapshot.isNull(), E_FAIL);
10118
 
 
10119
 
    MultiResult rc (S_OK);
10120
 
 
10121
 
    if (aSuccess)
10122
 
    {
10123
 
        /* the server progress must be completed on success */
10124
 
        Assert (mSnapshotData.mServerProgress->completed());
10125
 
 
10126
 
        mData->mCurrentSnapshot = mSnapshotData.mSnapshot;
10127
 
 
10128
 
        /* memorize the first snapshot if necessary */
10129
 
        if (!mData->mFirstSnapshot)
10130
 
            mData->mFirstSnapshot = mData->mCurrentSnapshot;
10131
 
 
10132
 
        int opFlags = SaveSS_AddOp | SaveSS_CurrentId;
10133
 
        if (!Global::IsOnline (mSnapshotData.mLastState))
10134
 
        {
10135
 
            /* the machine was powered off or saved when taking a snapshot, so
10136
 
             * reset the mCurrentStateModified flag */
10137
 
            mData->mCurrentStateModified = FALSE;
10138
 
            opFlags |= SaveSS_CurStateModified;
10139
 
        }
10140
 
 
10141
 
        rc = saveSnapshotSettings (mSnapshotData.mSnapshot, opFlags);
10142
 
    }
10143
 
 
10144
 
    if (aSuccess && SUCCEEDED (rc))
10145
 
    {
10146
 
        bool online = Global::IsOnline (mSnapshotData.mLastState);
10147
 
 
10148
 
        /* associate old hard disks with the snapshot and do locking/unlocking*/
10149
 
        fixupHardDisks(true /* aCommit */, online);
10150
 
 
10151
 
        /* inform callbacks */
10152
 
        mParent->onSnapshotTaken (mData->mUuid,
10153
 
                                  mSnapshotData.mSnapshot->data().mId);
10154
 
    }
10155
 
    else
10156
 
    {
10157
 
        /* wait for the completion of the server progress (diff VDI creation) */
10158
 
        /// @todo (dmik) later, we will definitely want to cancel it instead
10159
 
        // (when the cancel function is implemented)
10160
 
        mSnapshotData.mServerProgress->WaitForCompletion (-1);
10161
 
 
10162
 
        /* delete all differencing hard disks created (this will also attach
10163
 
         * their parents back by rolling back mHDData) */
10164
 
        fixupHardDisks(false /* aCommit */);
10165
 
 
10166
 
        /* delete the saved state file (it might have been already created) */
10167
 
        if (mSnapshotData.mSnapshot->stateFilePath())
10168
 
            RTFileDelete (Utf8Str (mSnapshotData.mSnapshot->stateFilePath()));
10169
 
 
10170
 
        mSnapshotData.mSnapshot->uninit();
10171
 
    }
10172
 
 
10173
 
    /* clear out the snapshot data */
10174
 
    mSnapshotData.mLastState = MachineState_Null;
10175
 
    mSnapshotData.mSnapshot.setNull();
10176
 
    mSnapshotData.mServerProgress.setNull();
10177
 
 
10178
 
    /* uninitialize the combined progress (to remove it from the VBox collection) */
10179
 
    if (!mSnapshotData.mCombinedProgress.isNull())
10180
 
    {
10181
 
        mSnapshotData.mCombinedProgress->uninit();
10182
 
        mSnapshotData.mCombinedProgress.setNull();
10183
 
    }
10184
 
 
10185
 
    LogFlowThisFuncLeave();
10186
 
    return rc;
10187
 
}
10188
 
 
10189
 
/**
10190
 
 * Take snapshot task handler. Must be called only by
10191
 
 * TakeSnapshotTask::handler()!
10192
 
 *
10193
 
 * The sole purpose of this task is to asynchronously create differencing VDIs
10194
 
 * and copy the saved state file (when necessary). The VM process will wait for
10195
 
 * this task to complete using the mSnapshotData.mServerProgress returned to it.
10196
 
 *
10197
 
 * @note Locks this object for writing.
10198
 
 */
10199
 
void SessionMachine::takeSnapshotHandler (TakeSnapshotTask & /* aTask */)
10200
 
{
10201
 
    LogFlowThisFuncEnter();
10202
 
 
10203
 
    AutoCaller autoCaller (this);
10204
 
 
10205
 
    LogFlowThisFunc (("state=%d\n", autoCaller.state()));
10206
 
    if (!autoCaller.isOk())
10207
 
    {
10208
 
        /* we might have been uninitialized because the session was accidentally
10209
 
         * closed by the client, so don't assert */
10210
 
        LogFlowThisFuncLeave();
10211
 
        return;
10212
 
    }
10213
 
 
10214
 
    AutoWriteLock alock (this);
10215
 
 
10216
 
    HRESULT rc = S_OK;
10217
 
 
10218
 
    bool online = Global::IsOnline (mSnapshotData.mLastState);
10219
 
 
10220
 
    LogFlowThisFunc (("Creating differencing hard disks (online=%d)...\n",
10221
 
                      online));
10222
 
 
10223
 
    mHDData.backup();
10224
 
 
10225
 
    /* create new differencing hard disks and attach them to this machine */
10226
 
    rc = createImplicitDiffs (mUserData->mSnapshotFolderFull,
10227
 
                              mSnapshotData.mServerProgress,
10228
 
                              online);
10229
 
 
10230
 
    if (SUCCEEDED (rc) && mSnapshotData.mLastState == MachineState_Saved)
10231
 
    {
10232
 
        Utf8Str stateFrom = mSSData->mStateFilePath;
10233
 
        Utf8Str stateTo = mSnapshotData.mSnapshot->stateFilePath();
10234
 
 
10235
 
        LogFlowThisFunc (("Copying the execution state from '%s' to '%s'...\n",
10236
 
                          stateFrom.raw(), stateTo.raw()));
10237
 
 
10238
 
        mSnapshotData.mServerProgress->setNextOperation(Bstr(tr("Copying the execution state")),
10239
 
                                                        1);        // weight
10240
 
 
10241
 
        /* Leave the lock before a lengthy operation (mMachineState is
10242
 
         * MachineState_Saving here) */
10243
 
 
10244
 
        alock.leave();
10245
 
 
10246
 
        /* copy the state file */
10247
 
        int vrc = RTFileCopyEx (stateFrom, stateTo, 0, progressCallback,
10248
 
                                static_cast <Progress *> (mSnapshotData.mServerProgress));
10249
 
 
10250
 
        alock.enter();
10251
 
 
10252
 
        if (RT_FAILURE (vrc))
10253
 
            rc = setError (E_FAIL,
10254
 
                tr ("Could not copy the state file '%s' to '%s' (%Rrc)"),
10255
 
                stateFrom.raw(), stateTo.raw(), vrc);
10256
 
    }
10257
 
 
10258
 
    /* we have to call endTakingSnapshot() ourselves if the snapshot was taken
10259
 
     * offline because the VM process will not do it in this case
10260
 
     */
10261
 
    if (!online)
10262
 
    {
10263
 
        LogFlowThisFunc (("Finalizing the taken snapshot (rc=%Rhrc)...\n", rc));
10264
 
 
10265
 
        {
10266
 
            ErrorInfoKeeper eik;
10267
 
 
10268
 
            setMachineState (mSnapshotData.mLastState);
10269
 
            updateMachineStateOnClient();
10270
 
        }
10271
 
 
10272
 
        /* finalize the progress after setting the state, for consistency */
10273
 
        mSnapshotData.mServerProgress->notifyComplete (rc);
10274
 
 
10275
 
        endTakingSnapshot (SUCCEEDED (rc));
10276
 
    }
10277
 
    else
10278
 
    {
10279
 
        mSnapshotData.mServerProgress->notifyComplete (rc);
10280
 
    }
10281
 
 
10282
 
    LogFlowThisFuncLeave();
10283
 
}
10284
 
 
10285
 
/**
10286
 
 * Helper struct for SessionMachine::discardSnapshotHandler().
10287
 
 */
10288
 
struct HardDiskDiscardRec
10289
 
{
10290
 
    HardDiskDiscardRec() : chain (NULL) {}
10291
 
 
10292
 
    HardDiskDiscardRec (const ComObjPtr<HardDisk> &aHd,
10293
 
                HardDisk::MergeChain *aChain = NULL)
10294
 
        : hd (aHd), chain (aChain) {}
10295
 
 
10296
 
    HardDiskDiscardRec (const ComObjPtr<HardDisk> &aHd,
10297
 
                        HardDisk::MergeChain *aChain,
10298
 
                        const ComObjPtr<HardDisk> &aReplaceHd,
10299
 
                        const ComObjPtr<HardDiskAttachment> &aReplaceHda,
10300
 
                        const Guid &aSnapshotId)
10301
 
        : hd (aHd), chain (aChain)
10302
 
        , replaceHd (aReplaceHd), replaceHda (aReplaceHda)
10303
 
        , snapshotId (aSnapshotId) {}
10304
 
 
10305
 
    ComObjPtr<HardDisk> hd;
10306
 
    HardDisk::MergeChain *chain;
10307
 
    /* these are for the replace hard disk case: */
10308
 
    ComObjPtr<HardDisk> replaceHd;
10309
 
    ComObjPtr<HardDiskAttachment> replaceHda;
10310
 
    Guid snapshotId;
10311
 
};
10312
 
 
10313
 
typedef std::list <HardDiskDiscardRec> HardDiskDiscardRecList;
10314
 
 
10315
 
/**
10316
 
 * Discard snapshot task handler. Must be called only by
10317
 
 * DiscardSnapshotTask::handler()!
10318
 
 *
10319
 
 * When aTask.subTask is true, the associated progress object is left
10320
 
 * uncompleted on success. On failure, the progress is marked as completed
10321
 
 * regardless of this parameter.
10322
 
 *
10323
 
 * @note Locks mParent + this + child objects for writing!
10324
 
 */
10325
 
void SessionMachine::discardSnapshotHandler (DiscardSnapshotTask &aTask)
10326
 
{
10327
 
    LogFlowThisFuncEnter();
10328
 
 
10329
 
    AutoCaller autoCaller (this);
10330
 
 
10331
 
    LogFlowThisFunc (("state=%d\n", autoCaller.state()));
10332
 
    if (!autoCaller.isOk())
10333
 
    {
10334
 
        /* we might have been uninitialized because the session was accidentally
10335
 
         * closed by the client, so don't assert */
10336
 
        aTask.progress->notifyComplete (
10337
 
            E_FAIL, COM_IIDOF (IMachine), getComponentName(),
10338
 
            tr ("The session has been accidentally closed"));
10339
 
 
10340
 
        LogFlowThisFuncLeave();
10341
 
        return;
10342
 
    }
10343
 
 
10344
 
    /* saveSettings() needs mParent lock */
10345
 
    AutoWriteLock vboxLock (mParent);
10346
 
 
10347
 
    /* @todo We don't need mParent lock so far so unlock() it. Better is to
10348
 
     * provide an AutoWriteLock argument that lets create a non-locking
10349
 
     * instance */
10350
 
    vboxLock.unlock();
10351
 
 
10352
 
    /* Preseve the {parent, child} lock order for this and snapshot stuff */
10353
 
    AutoMultiWriteLock3 alock (this->lockHandle(),
10354
 
                               aTask.snapshot->lockHandle(),
10355
 
                               aTask.snapshot->childrenLock());
10356
 
 
10357
 
    ComObjPtr <SnapshotMachine> sm = aTask.snapshot->data().mMachine;
10358
 
    /* no need to lock the snapshot machine since it is const by definiton */
10359
 
 
10360
 
    HRESULT rc = S_OK;
10361
 
 
10362
 
    /* save the snapshot ID (for callbacks) */
10363
 
    Guid snapshotId = aTask.snapshot->data().mId;
10364
 
 
10365
 
    HardDiskDiscardRecList toDiscard;
10366
 
 
10367
 
    bool settingsChanged = false;
10368
 
 
10369
 
    try
10370
 
    {
10371
 
        /* first pass: */
10372
 
        LogFlowThisFunc (("1: Checking hard disk merge prerequisites...\n"));
10373
 
 
10374
 
        for (HDData::AttachmentList::const_iterator it =
10375
 
             sm->mHDData->mAttachments.begin();
10376
 
             it != sm->mHDData->mAttachments.end();
10377
 
             ++ it)
10378
 
        {
10379
 
            ComObjPtr<HardDiskAttachment> hda = *it;
10380
 
            ComObjPtr<HardDisk> hd = hda->hardDisk();
10381
 
 
10382
 
            /* HardDisk::prepareDiscard() reqiuires a write lock */
10383
 
            AutoWriteLock hdLock (hd);
10384
 
 
10385
 
            if (hd->type() != HardDiskType_Normal)
10386
 
            {
10387
 
                /* skip writethrough hard disks */
10388
 
 
10389
 
                Assert (hd->type() == HardDiskType_Writethrough);
10390
 
 
10391
 
                rc = aTask.progress->setNextOperation(BstrFmt(tr("Skipping writethrough hard disk '%s'"),
10392
 
                                                              hd->root()->name().raw()),
10393
 
                                                      1); // weight
10394
 
                CheckComRCThrowRC (rc);
10395
 
 
10396
 
                continue;
10397
 
            }
10398
 
 
10399
 
            HardDisk::MergeChain *chain = NULL;
10400
 
 
10401
 
            /* needs to be discarded (merged with the child if any), check
10402
 
             * prerequisites */
10403
 
            rc = hd->prepareDiscard (chain);
10404
 
            CheckComRCThrowRC (rc);
10405
 
 
10406
 
            if (hd->parent().isNull() && chain != NULL)
10407
 
            {
10408
 
                /* it's a base hard disk so it will be a backward merge of its
10409
 
                 * only child to it (prepareDiscard() does necessary checks). We
10410
 
                 * need then to update the attachment that refers to the child
10411
 
                 * to refer to the parent insead. Don't forget to detach the
10412
 
                 * child (otherwise mergeTo() called by discard() will assert
10413
 
                 * because it will be going to delete the child) */
10414
 
 
10415
 
                /* The below assert would be nice but I don't want to move
10416
 
                 * HardDisk::MergeChain to the header just for that
10417
 
                 * Assert (!chain->isForward()); */
10418
 
 
10419
 
                Assert (hd->children().size() == 1);
10420
 
 
10421
 
                ComObjPtr<HardDisk> replaceHd = hd->children().front();
10422
 
 
10423
 
                Assert (replaceHd->backRefs().front().machineId == mData->mUuid);
10424
 
                Assert (replaceHd->backRefs().front().snapshotIds.size() <= 1);
10425
 
 
10426
 
                Guid snapshotId;
10427
 
                if (replaceHd->backRefs().front().snapshotIds.size() == 1)
10428
 
                    snapshotId = replaceHd->backRefs().front().snapshotIds.front();
10429
 
 
10430
 
                HRESULT rc2 = S_OK;
10431
 
 
10432
 
                /* adjust back references */
10433
 
                rc2 = replaceHd->detachFrom (mData->mUuid, snapshotId);
10434
 
                AssertComRC (rc2);
10435
 
 
10436
 
                rc2 = hd->attachTo (mData->mUuid, snapshotId);
10437
 
                AssertComRC (rc2);
10438
 
 
10439
 
                /* replace the hard disk in the attachment object */
10440
 
                HDData::AttachmentList::iterator it;
10441
 
                if (snapshotId.isEmpty())
10442
 
                {
10443
 
                    /* in current state */
10444
 
                    it = std::find_if (mHDData->mAttachments.begin(),
10445
 
                                       mHDData->mAttachments.end(),
10446
 
                                       HardDiskAttachment::RefersTo (replaceHd));
10447
 
                    AssertBreak (it != mHDData->mAttachments.end());
10448
 
                }
10449
 
                else
10450
 
                {
10451
 
                    /* in snapshot */
10452
 
                    ComObjPtr <Snapshot> snapshot;
10453
 
                    rc2 = findSnapshot (snapshotId, snapshot);
10454
 
                    AssertComRC (rc2);
10455
 
 
10456
 
                    /* don't lock the snapshot; cannot be modified outside */
10457
 
                    HDData::AttachmentList &snapAtts =
10458
 
                        snapshot->data().mMachine->mHDData->mAttachments;
10459
 
                    it = std::find_if (snapAtts.begin(),
10460
 
                                       snapAtts.end(),
10461
 
                                       HardDiskAttachment::RefersTo (replaceHd));
10462
 
                    AssertBreak (it != snapAtts.end());
10463
 
                }
10464
 
 
10465
 
                AutoWriteLock attLock (*it);
10466
 
                (*it)->updateHardDisk (hd, false /* aImplicit */);
10467
 
 
10468
 
                toDiscard.push_back (HardDiskDiscardRec (hd, chain, replaceHd,
10469
 
                                                         *it, snapshotId));
10470
 
                continue;
10471
 
            }
10472
 
 
10473
 
            toDiscard.push_back (HardDiskDiscardRec (hd, chain));
10474
 
        }
10475
 
 
10476
 
        /* Now we checked that we can successfully merge all normal hard disks
10477
 
         * (unless a runtime error like end-of-disc happens). Prior to
10478
 
         * performing the actual merge, we want to discard the snapshot itself
10479
 
         * and remove it from the XML file to make sure that a possible merge
10480
 
         * ruintime error will not make this snapshot inconsistent because of
10481
 
         * the partially merged or corrupted hard disks */
10482
 
 
10483
 
        /* second pass: */
10484
 
        LogFlowThisFunc (("2: Discarding snapshot...\n"));
10485
 
 
10486
 
        {
10487
 
            /* for now, the snapshot must have only one child when discarded,
10488
 
             * or no children at all */
10489
 
            ComAssertThrow (aTask.snapshot->children().size() <= 1, E_FAIL);
10490
 
 
10491
 
            ComObjPtr <Snapshot> parentSnapshot = aTask.snapshot->parent();
10492
 
 
10493
 
            /// @todo (dmik):
10494
 
            //  when we introduce clones later, discarding the snapshot
10495
 
            //  will affect the current and first snapshots of clones, if they are
10496
 
            //  direct children of this snapshot. So we will need to lock machines
10497
 
            //  associated with child snapshots as well and update mCurrentSnapshot
10498
 
            //  and/or mFirstSnapshot fields.
10499
 
 
10500
 
            if (aTask.snapshot == mData->mCurrentSnapshot)
10501
 
            {
10502
 
                /* currently, the parent snapshot must refer to the same machine */
10503
 
                /// @todo NEWMEDIA not really clear why
10504
 
                ComAssertThrow (
10505
 
                    !parentSnapshot ||
10506
 
                    parentSnapshot->data().mMachine->mData->mUuid == mData->mUuid,
10507
 
                    E_FAIL);
10508
 
                mData->mCurrentSnapshot = parentSnapshot;
10509
 
 
10510
 
                /* we've changed the base of the current state so mark it as
10511
 
                 * modified as it no longer guaranteed to be its copy */
10512
 
                mData->mCurrentStateModified = TRUE;
10513
 
            }
10514
 
 
10515
 
            if (aTask.snapshot == mData->mFirstSnapshot)
10516
 
            {
10517
 
                if (aTask.snapshot->children().size() == 1)
10518
 
                {
10519
 
                    ComObjPtr <Snapshot> childSnapshot =
10520
 
                        aTask.snapshot->children().front();
10521
 
                    ComAssertThrow (
10522
 
                        childSnapshot->data().mMachine->mData->mUuid == mData->mUuid,
10523
 
                        E_FAIL);
10524
 
                    mData->mFirstSnapshot = childSnapshot;
10525
 
                }
10526
 
                else
10527
 
                    mData->mFirstSnapshot.setNull();
10528
 
            }
10529
 
 
10530
 
            Bstr stateFilePath = aTask.snapshot->stateFilePath();
10531
 
 
10532
 
            /* Note that discarding the snapshot will deassociate it from the
10533
 
             * hard disks which will allow the merge+delete operation for them*/
10534
 
            aTask.snapshot->discard();
10535
 
 
10536
 
            rc = saveSnapshotSettings (parentSnapshot, SaveSS_UpdateAllOp |
10537
 
                                                       SaveSS_CurrentId |
10538
 
                                                       SaveSS_CurStateModified);
10539
 
            CheckComRCThrowRC (rc);
10540
 
 
10541
 
            /// @todo (dmik)
10542
 
            //  if we implement some warning mechanism later, we'll have
10543
 
            //  to return a warning if the state file path cannot be deleted
10544
 
            if (stateFilePath)
10545
 
            {
10546
 
                aTask.progress->setNextOperation(Bstr(tr("Discarding the execution state")),
10547
 
                                                 1);        // weight
10548
 
 
10549
 
                RTFileDelete (Utf8Str (stateFilePath));
10550
 
            }
10551
 
 
10552
 
            /// @todo NEWMEDIA to provide a good level of fauilt tolerance, we
10553
 
            /// should restore the shapshot in the snapshot tree if
10554
 
            /// saveSnapshotSettings fails. Actually, we may call
10555
 
            /// #saveSnapshotSettings() with a special flag that will tell it to
10556
 
            /// skip the given snapshot as if it would have been discarded and
10557
 
            /// only actually discard it if the save operation succeeds.
10558
 
        }
10559
 
 
10560
 
        /* here we come when we've irrevesibly discarded the snapshot which
10561
 
         * means that the VM settigns (our relevant changes to mData) need to be
10562
 
         * saved too */
10563
 
        /// @todo NEWMEDIA maybe save everything in one operation in place of
10564
 
        ///  saveSnapshotSettings() above
10565
 
        settingsChanged = true;
10566
 
 
10567
 
        /* third pass: */
10568
 
        LogFlowThisFunc (("3: Performing actual hard disk merging...\n"));
10569
 
 
10570
 
        /* leave the locks before the potentially lengthy operation */
10571
 
        alock.leave();
10572
 
 
10573
 
        /// @todo NEWMEDIA turn the following errors into warnings because the
10574
 
        /// snapshot itself has been already deleted (and interpret these
10575
 
        /// warnings properly on the GUI side)
10576
 
 
10577
 
        for (HardDiskDiscardRecList::iterator it = toDiscard.begin();
10578
 
             it != toDiscard.end();)
10579
 
        {
10580
 
            rc = it->hd->discard (aTask.progress, it->chain);
10581
 
            CheckComRCBreakRC (rc);
10582
 
 
10583
 
            /* prevent from calling cancelDiscard() */
10584
 
            it = toDiscard.erase (it);
10585
 
        }
10586
 
 
10587
 
        alock.enter();
10588
 
 
10589
 
        CheckComRCThrowRC (rc);
10590
 
    }
10591
 
    catch (HRESULT aRC) { rc = aRC; }
10592
 
 
10593
 
    if FAILED (rc)
10594
 
    {
10595
 
        HRESULT rc2 = S_OK;
10596
 
 
10597
 
        /* un-prepare the remaining hard disks */
10598
 
        for (HardDiskDiscardRecList::const_iterator it = toDiscard.begin();
10599
 
             it != toDiscard.end(); ++ it)
10600
 
        {
10601
 
            it->hd->cancelDiscard (it->chain);
10602
 
 
10603
 
            if (!it->replaceHd.isNull())
10604
 
            {
10605
 
                /* undo hard disk replacement */
10606
 
 
10607
 
                rc2 = it->replaceHd->attachTo (mData->mUuid, it->snapshotId);
10608
 
                AssertComRC (rc2);
10609
 
 
10610
 
                rc2 = it->hd->detachFrom (mData->mUuid, it->snapshotId);
10611
 
                AssertComRC (rc2);
10612
 
 
10613
 
                AutoWriteLock attLock (it->replaceHda);
10614
 
                it->replaceHda->updateHardDisk (it->replaceHd, false /* aImplicit */);
10615
 
            }
10616
 
        }
10617
 
    }
10618
 
 
10619
 
    if (!aTask.subTask || FAILED (rc))
10620
 
    {
10621
 
        if (!aTask.subTask)
10622
 
        {
10623
 
            /* saveSettings() below needs a VirtualBox write lock and we need to
10624
 
             * leave this object's lock to do this to follow the {parent-child}
10625
 
             * locking rule. This is the last chance to do that while we are
10626
 
             * still in a protective state which allows us to temporarily leave
10627
 
             * the lock */
10628
 
            alock.unlock();
10629
 
            vboxLock.lock();
10630
 
            alock.lock();
10631
 
 
10632
 
            /* preserve existing error info */
10633
 
            ErrorInfoKeeper eik;
10634
 
 
10635
 
            /* restore the machine state */
10636
 
            setMachineState (aTask.state);
10637
 
            updateMachineStateOnClient();
10638
 
 
10639
 
            if (settingsChanged)
10640
 
                saveSettings (SaveS_InformCallbacksAnyway);
10641
 
        }
10642
 
 
10643
 
        /* set the result (this will try to fetch current error info on failure) */
10644
 
        aTask.progress->notifyComplete (rc);
10645
 
    }
10646
 
 
10647
 
    if (SUCCEEDED (rc))
10648
 
        mParent->onSnapshotDiscarded (mData->mUuid, snapshotId);
10649
 
 
10650
 
    LogFlowThisFunc (("Done discarding snapshot (rc=%08X)\n", rc));
10651
 
    LogFlowThisFuncLeave();
10652
 
}
10653
 
 
10654
 
/**
10655
 
 * Discard current state task handler. Must be called only by
10656
 
 * DiscardCurrentStateTask::handler()!
10657
 
 *
10658
 
 * @note Locks mParent + this object for writing.
10659
 
 */
10660
 
void SessionMachine::discardCurrentStateHandler (DiscardCurrentStateTask &aTask)
10661
 
{
10662
 
    LogFlowThisFuncEnter();
10663
 
 
10664
 
    AutoCaller autoCaller (this);
10665
 
 
10666
 
    LogFlowThisFunc (("state=%d\n", autoCaller.state()));
10667
 
    if (!autoCaller.isOk())
10668
 
    {
10669
 
        /* we might have been uninitialized because the session was accidentally
10670
 
         * closed by the client, so don't assert */
10671
 
        aTask.progress->notifyComplete (
10672
 
            E_FAIL, COM_IIDOF (IMachine), getComponentName(),
10673
 
            tr ("The session has been accidentally closed"));
10674
 
 
10675
 
        LogFlowThisFuncLeave();
10676
 
        return;
10677
 
    }
10678
 
 
10679
 
    /* saveSettings() needs mParent lock */
10680
 
    AutoWriteLock vboxLock (mParent);
10681
 
 
10682
 
    /* @todo We don't need mParent lock so far so unlock() it. Better is to
10683
 
     * provide an AutoWriteLock argument that lets create a non-locking
10684
 
     * instance */
10685
 
    vboxLock.unlock();
10686
 
 
10687
 
    AutoWriteLock alock (this);
10688
 
 
10689
 
    /* discard all current changes to mUserData (name, OSType etc.) (note that
10690
 
     * the machine is powered off, so there is no need to inform the direct
10691
 
     * session) */
10692
 
    if (isModified())
10693
 
        rollback (false /* aNotify */);
10694
 
 
10695
 
    HRESULT rc = S_OK;
10696
 
 
10697
 
    bool errorInSubtask = false;
10698
 
    bool stateRestored = false;
10699
 
 
10700
 
    const bool isLastSnapshot = mData->mCurrentSnapshot->parent().isNull();
10701
 
 
10702
 
    try
10703
 
    {
10704
 
        /* discard the saved state file if the machine was Saved prior to this
10705
 
         * operation */
10706
 
        if (aTask.state == MachineState_Saved)
10707
 
        {
10708
 
            Assert (!mSSData->mStateFilePath.isEmpty());
10709
 
            RTFileDelete (Utf8Str (mSSData->mStateFilePath));
10710
 
            mSSData->mStateFilePath.setNull();
10711
 
            aTask.modifyLastState (MachineState_PoweredOff);
10712
 
            rc = saveStateSettings (SaveSTS_StateFilePath);
10713
 
            CheckComRCThrowRC (rc);
10714
 
        }
10715
 
 
10716
 
        if (aTask.discardCurrentSnapshot && !isLastSnapshot)
10717
 
        {
10718
 
            /* the "discard current snapshot and state" task is in action, the
10719
 
             * current snapshot is not the last one. Discard the current
10720
 
             * snapshot first */
10721
 
 
10722
 
            DiscardSnapshotTask subTask (aTask, mData->mCurrentSnapshot);
10723
 
            subTask.subTask = true;
10724
 
            discardSnapshotHandler (subTask);
10725
 
 
10726
 
            AutoCaller progressCaller (aTask.progress);
10727
 
            AutoReadLock progressLock (aTask.progress);
10728
 
            if (aTask.progress->completed())
10729
 
            {
10730
 
                /* the progress can be completed by a subtask only if there was
10731
 
                 * a failure */
10732
 
                rc = aTask.progress->resultCode();
10733
 
                Assert (FAILED (rc));
10734
 
                errorInSubtask = true;
10735
 
                throw rc;
10736
 
            }
10737
 
        }
10738
 
 
10739
 
        RTTIMESPEC snapshotTimeStamp;
10740
 
        RTTimeSpecSetMilli (&snapshotTimeStamp, 0);
10741
 
 
10742
 
        {
10743
 
            ComObjPtr <Snapshot> curSnapshot = mData->mCurrentSnapshot;
10744
 
            AutoReadLock snapshotLock (curSnapshot);
10745
 
 
10746
 
            /* remember the timestamp of the snapshot we're restoring from */
10747
 
            snapshotTimeStamp = curSnapshot->data().mTimeStamp;
10748
 
 
10749
 
            /* copy all hardware data from the current snapshot */
10750
 
            copyFrom (curSnapshot->data().mMachine);
10751
 
 
10752
 
            LogFlowThisFunc (("Restoring hard disks from the snapshot...\n"));
10753
 
 
10754
 
            /* restore the attachmends from the snapshot */
10755
 
            mHDData.backup();
10756
 
            mHDData->mAttachments =
10757
 
                curSnapshot->data().mMachine->mHDData->mAttachments;
10758
 
 
10759
 
            /* leave the locks before the potentially lengthy operation */
10760
 
            snapshotLock.unlock();
10761
 
            alock.leave();
10762
 
 
10763
 
            rc = createImplicitDiffs (mUserData->mSnapshotFolderFull,
10764
 
                                      aTask.progress,
10765
 
                                      false /* aOnline */);
10766
 
 
10767
 
            alock.enter();
10768
 
            snapshotLock.lock();
10769
 
 
10770
 
            CheckComRCThrowRC (rc);
10771
 
 
10772
 
            /* Note: on success, current (old) hard disks will be
10773
 
             * deassociated/deleted on #commit() called from #saveSettings() at
10774
 
             * the end. On failure, newly created implicit diffs will be
10775
 
             * deleted by #rollback() at the end. */
10776
 
 
10777
 
            /* should not have a saved state file associated at this point */
10778
 
            Assert (mSSData->mStateFilePath.isNull());
10779
 
 
10780
 
            if (curSnapshot->stateFilePath())
10781
 
            {
10782
 
                Utf8Str snapStateFilePath = curSnapshot->stateFilePath();
10783
 
 
10784
 
                Utf8Str stateFilePath = Utf8StrFmt ("%ls%c{%RTuuid}.sav",
10785
 
                    mUserData->mSnapshotFolderFull.raw(),
10786
 
                    RTPATH_DELIMITER, mData->mUuid.raw());
10787
 
 
10788
 
                LogFlowThisFunc (("Copying saved state file from '%s' to '%s'...\n",
10789
 
                                  snapStateFilePath.raw(), stateFilePath.raw()));
10790
 
 
10791
 
                aTask.progress->setNextOperation(Bstr(tr("Restoring the execution state")),
10792
 
                                                 1);        // weight
10793
 
 
10794
 
                /* leave the lock before the potentially lengthy operation */
10795
 
                snapshotLock.unlock();
10796
 
                alock.leave();
10797
 
 
10798
 
                /* copy the state file */
10799
 
                int vrc = RTFileCopyEx (snapStateFilePath, stateFilePath,
10800
 
                                        0, progressCallback, aTask.progress);
10801
 
 
10802
 
                alock.enter();
10803
 
                snapshotLock.lock();
10804
 
 
10805
 
                if (RT_SUCCESS (vrc))
10806
 
                {
10807
 
                    mSSData->mStateFilePath = stateFilePath;
10808
 
                }
10809
 
                else
10810
 
                {
10811
 
                    throw setError (E_FAIL,
10812
 
                        tr ("Could not copy the state file '%s' to '%s' (%Rrc)"),
10813
 
                        snapStateFilePath.raw(), stateFilePath.raw(), vrc);
10814
 
                }
10815
 
            }
10816
 
        }
10817
 
 
10818
 
        /* grab differencing hard disks from the old attachments that will
10819
 
         * become unused and need to be auto-deleted */
10820
 
 
10821
 
        std::list< ComObjPtr<HardDisk> > diffs;
10822
 
 
10823
 
        for (HDData::AttachmentList::const_iterator
10824
 
             it = mHDData.backedUpData()->mAttachments.begin();
10825
 
             it != mHDData.backedUpData()->mAttachments.end(); ++ it)
10826
 
        {
10827
 
            ComObjPtr<HardDisk> hd = (*it)->hardDisk();
10828
 
 
10829
 
            /* while the hard disk is attached, the number of children or the
10830
 
             * parent cannot change, so no lock */
10831
 
            if (!hd->parent().isNull() && hd->children().size() == 0)
10832
 
                diffs.push_back (hd);
10833
 
        }
10834
 
 
10835
 
        int saveFlags = 0;
10836
 
 
10837
 
        if (aTask.discardCurrentSnapshot && isLastSnapshot)
10838
 
        {
10839
 
            /* commit changes to have unused diffs deassociated from this
10840
 
             * machine before deletion (see below) */
10841
 
            commit();
10842
 
 
10843
 
            /* delete the unused diffs now (and uninit them) because discard
10844
 
             * may fail otherwise (too many children of the hard disk to be
10845
 
             * discarded) */
10846
 
            for (std::list< ComObjPtr<HardDisk> >::const_iterator
10847
 
                 it = diffs.begin(); it != diffs.end(); ++ it)
10848
 
            {
10849
 
                /// @todo for now, we ignore errors since we've already
10850
 
                /// and therefore cannot fail. Later, we may want to report a
10851
 
                /// warning through the Progress object
10852
 
                HRESULT rc2 = (*it)->deleteStorageAndWait();
10853
 
                if (SUCCEEDED (rc2))
10854
 
                    (*it)->uninit();
10855
 
            }
10856
 
 
10857
 
            /* prevent further deletion */
10858
 
            diffs.clear();
10859
 
 
10860
 
            /* discard the current snapshot and state task is in action, the
10861
 
             * current snapshot is the last one. Discard the current snapshot
10862
 
             * after discarding the current state. */
10863
 
 
10864
 
            DiscardSnapshotTask subTask (aTask, mData->mCurrentSnapshot);
10865
 
            subTask.subTask = true;
10866
 
            discardSnapshotHandler (subTask);
10867
 
 
10868
 
            AutoCaller progressCaller (aTask.progress);
10869
 
            AutoReadLock progressLock (aTask.progress);
10870
 
            if (aTask.progress->completed())
10871
 
            {
10872
 
                /* the progress can be completed by a subtask only if there
10873
 
                 * was a failure */
10874
 
                rc = aTask.progress->resultCode();
10875
 
                Assert (FAILED (rc));
10876
 
                errorInSubtask = true;
10877
 
            }
10878
 
 
10879
 
            /* we've committed already, so inform callbacks anyway to ensure
10880
 
             * they don't miss some change */
10881
 
            /// @todo NEWMEDIA check if we need this informCallbacks at all
10882
 
            /// after updating discardCurrentSnapshot functionality
10883
 
            saveFlags |= SaveS_InformCallbacksAnyway;
10884
 
        }
10885
 
 
10886
 
        /* @todo saveSettings() below needs a VirtualBox write lock and we need
10887
 
         * to leave this object's lock to do this to follow the {parent-child}
10888
 
         * locking rule. This is the last chance to do that while we are still
10889
 
         * in a protective state which allows us to temporarily leave the lock*/
10890
 
        alock.unlock();
10891
 
        vboxLock.lock();
10892
 
        alock.lock();
10893
 
 
10894
 
        /* we have already discarded the current state, so set the execution
10895
 
         * state accordingly no matter of the discard snapshot result */
10896
 
        if (mSSData->mStateFilePath)
10897
 
            setMachineState (MachineState_Saved);
10898
 
        else
10899
 
            setMachineState (MachineState_PoweredOff);
10900
 
 
10901
 
        updateMachineStateOnClient();
10902
 
        stateRestored = true;
10903
 
 
10904
 
        /* assign the timestamp from the snapshot */
10905
 
        Assert (RTTimeSpecGetMilli (&snapshotTimeStamp) != 0);
10906
 
        mData->mLastStateChange = snapshotTimeStamp;
10907
 
 
10908
 
        /* save all settings, reset the modified flag and commit. Note that we
10909
 
         * do so even if the subtask failed (errorInSubtask=true) because we've
10910
 
         * already committed machine data and deleted old diffs before
10911
 
         * discarding the current snapshot so there is no way to rollback */
10912
 
        HRESULT rc2 = saveSettings (SaveS_ResetCurStateModified | saveFlags);
10913
 
 
10914
 
        /// @todo NEWMEDIA return multiple errors
10915
 
        if (errorInSubtask)
10916
 
            throw rc;
10917
 
 
10918
 
        rc = rc2;
10919
 
 
10920
 
        if (SUCCEEDED (rc))
10921
 
        {
10922
 
            /* now, delete the unused diffs (only on success!) and uninit them*/
10923
 
            for (std::list< ComObjPtr<HardDisk> >::const_iterator
10924
 
                 it = diffs.begin(); it != diffs.end(); ++ it)
10925
 
            {
10926
 
                /// @todo for now, we ignore errors since we've already
10927
 
                /// discarded and therefore cannot fail. Later, we may want to
10928
 
                /// report a warning through the Progress object
10929
 
                HRESULT rc2 = (*it)->deleteStorageAndWait();
10930
 
                if (SUCCEEDED (rc2))
10931
 
                    (*it)->uninit();
10932
 
            }
10933
 
        }
10934
 
    }
10935
 
    catch (HRESULT aRC) { rc = aRC; }
10936
 
 
10937
 
    if (FAILED (rc))
10938
 
    {
10939
 
        /* preserve existing error info */
10940
 
        ErrorInfoKeeper eik;
10941
 
 
10942
 
        if (!errorInSubtask)
10943
 
        {
10944
 
            /* undo all changes on failure unless the subtask has done so */
10945
 
            rollback (false /* aNotify */);
10946
 
        }
10947
 
 
10948
 
        if (!stateRestored)
10949
 
        {
10950
 
            /* restore the machine state */
10951
 
            setMachineState (aTask.state);
10952
 
            updateMachineStateOnClient();
10953
 
        }
10954
 
    }
10955
 
 
10956
 
    if (!errorInSubtask)
10957
 
    {
10958
 
        /* set the result (this will try to fetch current error info on failure) */
10959
 
        aTask.progress->notifyComplete (rc);
10960
 
    }
10961
 
 
10962
 
    if (SUCCEEDED (rc))
10963
 
        mParent->onSnapshotDiscarded (mData->mUuid, Guid());
10964
 
 
10965
 
    LogFlowThisFunc (("Done discarding current state (rc=%08X)\n", rc));
10966
 
 
10967
 
    LogFlowThisFuncLeave();
10968
 
}
10969
 
 
10970
 
/**
10971
9849
 * Locks the attached media.
10972
9850
 *
10973
9851
 * All attached hard disks are locked for writing and DVD/floppy are locked for
10989
9867
 */
10990
9868
HRESULT SessionMachine::lockMedia()
10991
9869
{
10992
 
    AutoCaller autoCaller (this);
 
9870
    AutoCaller autoCaller(this);
10993
9871
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
10994
9872
 
10995
 
    AutoWriteLock alock (this);
10996
 
 
10997
 
    AssertReturn (mData->mMachineState == MachineState_Starting ||
10998
 
                  mData->mMachineState == MachineState_Restoring, E_FAIL);
10999
 
 
11000
 
    typedef std::list <ComPtr <IMedium> > MediaList;
11001
 
    MediaList mediaToCheck;
11002
 
    MediaState_T mediaState;
 
9873
    AutoWriteLock alock(this);
 
9874
 
 
9875
    AssertReturn(   mData->mMachineState == MachineState_Starting
 
9876
                 || mData->mMachineState == MachineState_Restoring
 
9877
                 || mData->mMachineState == MachineState_TeleportingIn, E_FAIL);
 
9878
 
 
9879
    typedef std::list <ComPtr<IMedium> > MediaList;
11003
9880
 
11004
9881
    try
11005
9882
    {
11006
9883
        HRESULT rc = S_OK;
11007
9884
 
11008
 
        /* lock hard disks */
11009
 
        for (HDData::AttachmentList::const_iterator it =
11010
 
                 mHDData->mAttachments.begin();
11011
 
             it != mHDData->mAttachments.end(); ++ it)
 
9885
        ErrorInfoKeeper eik(true /* aIsNull */);
 
9886
        MultiResult mrc(S_OK);
 
9887
 
 
9888
        /* Lock all medium objects attached to the VM.
 
9889
         * Get status for inaccessible media as well. */
 
9890
        for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
 
9891
             it != mMediaData->mAttachments.end();
 
9892
             ++it)
11012
9893
        {
11013
 
            ComObjPtr<HardDisk> hd = (*it)->hardDisk();
 
9894
            DeviceType_T devType = (*it)->getType();
 
9895
            ComObjPtr<Medium> medium = (*it)->getMedium();
11014
9896
 
11015
9897
            bool first = true;
11016
9898
 
11017
9899
            /** @todo split out the media locking, and put it into
11018
 
             * HardDiskImpl.cpp, as it needs this functionality too. */
11019
 
            while (!hd.isNull())
 
9900
             * MediumImpl.cpp, as it needs this functionality too. */
 
9901
            while (!medium.isNull())
11020
9902
            {
 
9903
                MediumState_T mediumState = medium->getState();
 
9904
 
 
9905
                /* accessibility check must be first, otherwise locking
 
9906
                 * interferes with getting the medium state. */
 
9907
                if (mediumState == MediumState_Inaccessible)
 
9908
                {
 
9909
                    rc = medium->RefreshState(&mediumState);
 
9910
                    CheckComRCThrowRC(rc);
 
9911
 
 
9912
                    if (mediumState == MediumState_Inaccessible)
 
9913
                    {
 
9914
                        Bstr error;
 
9915
                        rc = medium->COMGETTER(LastAccessError)(error.asOutParam());
 
9916
                        CheckComRCThrowRC(rc);
 
9917
 
 
9918
                        Bstr loc;
 
9919
                        rc = medium->COMGETTER(Location)(loc.asOutParam());
 
9920
                        CheckComRCThrowRC(rc);
 
9921
 
 
9922
                        /* collect multiple errors */
 
9923
                        eik.restore();
 
9924
 
 
9925
                        /* be in sync with MediumBase::setStateError() */
 
9926
                        Assert(!error.isEmpty());
 
9927
                        mrc = setError(E_FAIL,
 
9928
                                       tr("Medium '%ls' is not accessible. %ls"),
 
9929
                                       loc.raw(),
 
9930
                                       error.raw());
 
9931
 
 
9932
                        eik.fetch();
 
9933
                    }
 
9934
                }
 
9935
 
11021
9936
                if (first)
11022
9937
                {
11023
 
                    rc = hd->LockWrite (&mediaState);
11024
 
                    CheckComRCThrowRC (rc);
 
9938
                    if (devType != DeviceType_DVD)
 
9939
                    {
 
9940
                        /* HardDisk and Floppy medium must be locked for writing */
 
9941
                        rc = medium->LockWrite(NULL);
 
9942
                        CheckComRCThrowRC(rc);
 
9943
                    }
 
9944
                    else
 
9945
                    {
 
9946
                        /* DVD medium must be locked for reading */
 
9947
                        rc = medium->LockRead(NULL);
 
9948
                        CheckComRCThrowRC(rc);
 
9949
                    }
11025
9950
 
11026
 
                    mData->mSession.mLockedMedia.push_back (
11027
 
                        Data::Session::LockedMedia::value_type (
11028
 
                            ComPtr <IHardDisk> (hd), true));
 
9951
                    mData->mSession.mLockedMedia.push_back(
 
9952
                        Data::Session::LockedMedia::value_type(
 
9953
                            ComPtr<IMedium>(medium), true));
11029
9954
 
11030
9955
                    first = false;
11031
9956
                }
11032
9957
                else
11033
9958
                {
11034
 
                    rc = hd->LockRead (&mediaState);
11035
 
                    CheckComRCThrowRC (rc);
 
9959
                    rc = medium->LockRead(NULL);
 
9960
                    CheckComRCThrowRC(rc);
11036
9961
 
11037
 
                    mData->mSession.mLockedMedia.push_back (
11038
 
                        Data::Session::LockedMedia::value_type (
11039
 
                            ComPtr <IHardDisk> (hd), false));
 
9962
                    mData->mSession.mLockedMedia.push_back(
 
9963
                        Data::Session::LockedMedia::value_type(
 
9964
                            ComPtr<IMedium>(medium), false));
11040
9965
                }
11041
9966
 
11042
 
                if (mediaState == MediaState_Inaccessible)
11043
 
                    mediaToCheck.push_back (ComPtr <IHardDisk> (hd));
11044
9967
 
11045
9968
                /* no locks or callers here since there should be no way to
11046
9969
                 * change the hard disk parent at this point (as it is still
11047
9970
                 * attached to the machine) */
11048
 
                hd = hd->parent();
11049
 
            }
11050
 
        }
11051
 
 
11052
 
        /* lock the DVD image for reading if mounted */
11053
 
        {
11054
 
            AutoReadLock driveLock (mDVDDrive);
11055
 
            if (mDVDDrive->data()->state == DriveState_ImageMounted)
11056
 
            {
11057
 
                ComObjPtr <DVDImage> image = mDVDDrive->data()->image;
11058
 
 
11059
 
                rc = image->LockRead (&mediaState);
11060
 
                CheckComRCThrowRC (rc);
11061
 
 
11062
 
                mData->mSession.mLockedMedia.push_back (
11063
 
                    Data::Session::LockedMedia::value_type (
11064
 
                        ComPtr <IDVDImage> (image), false));
11065
 
 
11066
 
                if (mediaState == MediaState_Inaccessible)
11067
 
                    mediaToCheck.push_back (ComPtr <IDVDImage> (image));
11068
 
            }
11069
 
        }
11070
 
 
11071
 
        /* lock the floppy image for reading if mounted */
11072
 
        {
11073
 
            AutoReadLock driveLock (mFloppyDrive);
11074
 
            if (mFloppyDrive->data()->state == DriveState_ImageMounted)
11075
 
            {
11076
 
                ComObjPtr <FloppyImage> image = mFloppyDrive->data()->image;
11077
 
 
11078
 
                rc = image->LockRead (&mediaState);
11079
 
                CheckComRCThrowRC (rc);
11080
 
 
11081
 
                mData->mSession.mLockedMedia.push_back (
11082
 
                    Data::Session::LockedMedia::value_type (
11083
 
                        ComPtr <IFloppyImage> (image), false));
11084
 
 
11085
 
                if (mediaState == MediaState_Inaccessible)
11086
 
                    mediaToCheck.push_back (ComPtr <IFloppyImage> (image));
11087
 
            }
11088
 
        }
11089
 
 
11090
 
        /* SUCCEEDED locking all media, now check accessibility */
11091
 
 
11092
 
        ErrorInfoKeeper eik (true /* aIsNull */);
11093
 
        MultiResult mrc (S_OK);
11094
 
 
11095
 
        /* perform a check of inaccessible media deferred above */
11096
 
        for (MediaList::const_iterator
11097
 
             it = mediaToCheck.begin();
11098
 
             it != mediaToCheck.end(); ++ it)
11099
 
        {
11100
 
            MediaState_T mediaState;
11101
 
            rc = (*it)->COMGETTER(State) (&mediaState);
11102
 
            CheckComRCThrowRC (rc);
11103
 
 
11104
 
            Assert (mediaState == MediaState_LockedRead ||
11105
 
                    mediaState == MediaState_LockedWrite);
11106
 
 
11107
 
            /* Note that we locked the medium already, so use the error
11108
 
             * value to see if there was an accessibility failure */
11109
 
 
11110
 
            Bstr error;
11111
 
            rc = (*it)->COMGETTER(LastAccessError) (error.asOutParam());
11112
 
            CheckComRCThrowRC (rc);
11113
 
 
11114
 
            if (!error.isEmpty())
11115
 
            {
11116
 
                Bstr loc;
11117
 
                rc = (*it)->COMGETTER(Location) (loc.asOutParam());
11118
 
                CheckComRCThrowRC (rc);
11119
 
 
11120
 
                /* collect multiple errors */
11121
 
                eik.restore();
11122
 
 
11123
 
                /* be in sync with MediumBase::setStateError() */
11124
 
                Assert (!error.isEmpty());
11125
 
                mrc = setError (E_FAIL,
11126
 
                    tr ("Medium '%ls' is not accessible. %ls"),
11127
 
                    loc.raw(), error.raw());
11128
 
 
11129
 
                eik.fetch();
 
9971
                medium = medium->getParent();
11130
9972
            }
11131
9973
        }
11132
9974
 
11133
9975
        eik.restore();
11134
 
        CheckComRCThrowRC ((HRESULT) mrc);
 
9976
        CheckComRCThrowRC((HRESULT)mrc);
11135
9977
    }
11136
9978
    catch (HRESULT aRC)
11137
9979
    {
11148
9990
 */
11149
9991
void SessionMachine::unlockMedia()
11150
9992
{
11151
 
    AutoCaller autoCaller (this);
 
9993
    AutoCaller autoCaller(this);
11152
9994
    AssertComRCReturnVoid (autoCaller.rc());
11153
9995
 
11154
 
    AutoWriteLock alock (this);
 
9996
    AutoWriteLock alock(this);
11155
9997
 
11156
9998
    /* we may be holding important error info on the current thread;
11157
9999
     * preserve it */
11161
10003
 
11162
10004
    for (Data::Session::LockedMedia::const_iterator
11163
10005
         it = mData->mSession.mLockedMedia.begin();
11164
 
         it != mData->mSession.mLockedMedia.end(); ++ it)
 
10006
         it != mData->mSession.mLockedMedia.end(); ++it)
11165
10007
    {
11166
 
        MediaState_T state;
 
10008
        MediumState_T state;
11167
10009
        if (it->second)
11168
10010
            rc = it->first->UnlockWrite (&state);
11169
10011
        else
11170
10012
            rc = it->first->UnlockRead (&state);
11171
10013
 
11172
10014
        /* The second can happen if an object was re-locked in
11173
 
         * Machine::fixupHardDisks(). The last can happen when e.g a DVD/Floppy
 
10015
         * Machine::fixupMedia(). The last can happen when e.g a DVD/Floppy
11174
10016
         * image was unmounted at runtime. */
11175
 
        Assert (SUCCEEDED (rc) || state == MediaState_LockedRead || state == MediaState_Created);
 
10017
        Assert (SUCCEEDED(rc) || state == MediumState_LockedRead || state == MediumState_Created);
11176
10018
    }
11177
10019
 
11178
10020
    mData->mSession.mLockedMedia.clear();
11186
10028
HRESULT SessionMachine::setMachineState (MachineState_T aMachineState)
11187
10029
{
11188
10030
    LogFlowThisFuncEnter();
11189
 
    LogFlowThisFunc (("aMachineState=%d\n", aMachineState));
 
10031
    LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) ));
11190
10032
 
11191
 
    AutoCaller autoCaller (this);
 
10033
    AutoCaller autoCaller(this);
11192
10034
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
11193
10035
 
11194
 
    AutoWriteLock alock (this);
 
10036
    AutoWriteLock alock(this);
11195
10037
 
11196
10038
    MachineState_T oldMachineState = mData->mMachineState;
11197
10039
 
11198
 
    AssertMsgReturn (oldMachineState != aMachineState,
11199
 
                     ("oldMachineState=%d, aMachineState=%d\n",
11200
 
                      oldMachineState, aMachineState), E_FAIL);
 
10040
    AssertMsgReturn(oldMachineState != aMachineState,
 
10041
                    ("oldMachineState=%s, aMachineState=%s\n",
 
10042
                     Global::stringifyMachineState(oldMachineState), Global::stringifyMachineState(aMachineState)),
 
10043
                    E_FAIL);
11201
10044
 
11202
10045
    HRESULT rc = S_OK;
11203
10046
 
11206
10049
 
11207
10050
    /* detect some state transitions */
11208
10051
 
11209
 
    if ((oldMachineState == MachineState_Saved &&
11210
 
           aMachineState == MachineState_Restoring) ||
11211
 
        (oldMachineState < MachineState_Running /* any other OFF state */ &&
11212
 
           aMachineState == MachineState_Starting))
 
10052
    if (   (   oldMachineState == MachineState_Saved
 
10053
            && aMachineState   == MachineState_Restoring)
 
10054
        || (   (   oldMachineState == MachineState_PoweredOff
 
10055
                || oldMachineState == MachineState_Teleported
 
10056
                || oldMachineState == MachineState_Aborted
 
10057
               )
 
10058
            && (   aMachineState   == MachineState_TeleportingIn
 
10059
                || aMachineState   == MachineState_Starting
 
10060
               )
 
10061
           )
 
10062
       )
11213
10063
    {
11214
10064
        /* The EMT thread is about to start */
11215
10065
 
11218
10068
        /// @todo NEWMEDIA don't let mDVDDrive and other children
11219
10069
        /// change anything when in the Starting/Restoring state
11220
10070
    }
11221
 
    else
11222
 
    if (oldMachineState >= MachineState_Running &&
11223
 
        oldMachineState != MachineState_Discarding &&
11224
 
        oldMachineState != MachineState_SettingUp &&
11225
 
        aMachineState < MachineState_Running &&
11226
 
        /* ignore PoweredOff->Saving->PoweredOff transition when taking a
11227
 
         * snapshot */
11228
 
        (mSnapshotData.mSnapshot.isNull() ||
11229
 
         mSnapshotData.mLastState >= MachineState_Running))
 
10071
    else if (   (   oldMachineState == MachineState_Running
 
10072
                 || oldMachineState == MachineState_Paused
 
10073
                 || oldMachineState == MachineState_Teleporting
 
10074
                 || oldMachineState == MachineState_LiveSnapshotting
 
10075
                 || oldMachineState == MachineState_Stuck
 
10076
                 || oldMachineState == MachineState_Starting
 
10077
                 || oldMachineState == MachineState_Stopping
 
10078
                 || oldMachineState == MachineState_Saving
 
10079
                 || oldMachineState == MachineState_Restoring
 
10080
                 || oldMachineState == MachineState_TeleportingPausedVM
 
10081
                 || oldMachineState == MachineState_TeleportingIn
 
10082
                 )
 
10083
             && (   aMachineState == MachineState_PoweredOff
 
10084
                 || aMachineState == MachineState_Saved
 
10085
                 || aMachineState == MachineState_Teleported
 
10086
                 || aMachineState == MachineState_Aborted
 
10087
                )
 
10088
             /* ignore PoweredOff->Saving->PoweredOff transition when taking a
 
10089
              * snapshot */
 
10090
             && (   mSnapshotData.mSnapshot.isNull()
 
10091
                 || mSnapshotData.mLastState >= MachineState_Running /** @todo Live Migration: clean up (lazy bird) */
 
10092
                )
 
10093
            )
11230
10094
    {
11231
10095
        /* The EMT thread has just stopped, unlock attached media. Note that as
11232
10096
         * opposed to locking that is done from Console, we do unlocking here
11250
10114
            deleteSavedState = true;
11251
10115
        }
11252
10116
    }
11253
 
    else
11254
 
    if (oldMachineState == MachineState_Saved &&
11255
 
        (aMachineState == MachineState_PoweredOff ||
11256
 
         aMachineState == MachineState_Aborted))
 
10117
    else if (   oldMachineState == MachineState_Saved
 
10118
             && (   aMachineState == MachineState_PoweredOff
 
10119
                 || aMachineState == MachineState_Aborted
 
10120
                 || aMachineState == MachineState_Teleported
 
10121
                )
 
10122
            )
11257
10123
    {
11258
10124
        /*
11259
10125
         *  delete the saved state after Console::DiscardSavedState() is called
11276
10142
        stsFlags |= SaveSTS_CurStateModified;
11277
10143
    }
11278
10144
 
11279
 
    if (aMachineState == MachineState_Starting ||
11280
 
        aMachineState == MachineState_Restoring)
 
10145
    if (   aMachineState == MachineState_Starting
 
10146
        || aMachineState == MachineState_Restoring
 
10147
        || aMachineState == MachineState_TeleportingIn
 
10148
       )
11281
10149
    {
11282
10150
        /* set the current state modified flag to indicate that the current
11283
10151
         * state is no more identical to the state in the
11293
10161
    {
11294
10162
        if (mRemoveSavedState)
11295
10163
        {
11296
 
            Assert (!mSSData->mStateFilePath.isEmpty());
11297
 
            RTFileDelete (Utf8Str (mSSData->mStateFilePath));
 
10164
            Assert(!mSSData->mStateFilePath.isEmpty());
 
10165
            RTFileDelete(mSSData->mStateFilePath.c_str());
11298
10166
        }
11299
10167
        mSSData->mStateFilePath.setNull();
11300
10168
        stsFlags |= SaveSTS_StateFilePath;
11303
10171
    /* redirect to the underlying peer machine */
11304
10172
    mPeer->setMachineState (aMachineState);
11305
10173
 
11306
 
    if (aMachineState == MachineState_PoweredOff ||
11307
 
        aMachineState == MachineState_Aborted ||
11308
 
        aMachineState == MachineState_Saved)
 
10174
    if (   aMachineState == MachineState_PoweredOff
 
10175
        || aMachineState == MachineState_Teleported
 
10176
        || aMachineState == MachineState_Aborted
 
10177
        || aMachineState == MachineState_Saved)
11309
10178
    {
11310
10179
        /* the machine has stopped execution
11311
10180
         * (or the saved state file was adopted) */
11312
10181
        stsFlags |= SaveSTS_StateTimeStamp;
11313
10182
    }
11314
10183
 
11315
 
    if ((oldMachineState == MachineState_PoweredOff ||
11316
 
         oldMachineState == MachineState_Aborted) &&
11317
 
        aMachineState == MachineState_Saved)
 
10184
    if (   (   oldMachineState == MachineState_PoweredOff
 
10185
            || oldMachineState == MachineState_Aborted
 
10186
            || oldMachineState == MachineState_Teleported
 
10187
           )
 
10188
        && aMachineState == MachineState_Saved)
11318
10189
    {
11319
10190
        /* the saved state file was adopted */
11320
 
        Assert (!mSSData->mStateFilePath.isNull());
 
10191
        Assert(!mSSData->mStateFilePath.isEmpty());
11321
10192
        stsFlags |= SaveSTS_StateFilePath;
11322
10193
    }
11323
10194
 
11324
10195
    rc = saveStateSettings (stsFlags);
11325
10196
 
11326
 
    if ((oldMachineState != MachineState_PoweredOff &&
11327
 
         oldMachineState != MachineState_Aborted) &&
11328
 
        (aMachineState == MachineState_PoweredOff ||
11329
 
         aMachineState == MachineState_Aborted))
 
10197
    if (   (   oldMachineState != MachineState_PoweredOff
 
10198
            && oldMachineState != MachineState_Aborted
 
10199
            && oldMachineState != MachineState_Teleported
 
10200
           )
 
10201
        && (   aMachineState == MachineState_PoweredOff
 
10202
            || aMachineState == MachineState_Aborted
 
10203
            || aMachineState == MachineState_Teleported
 
10204
           )
 
10205
       )
11330
10206
    {
11331
10207
        /* we've been shut down for any reason */
11332
10208
        /* no special action so far */
11333
10209
    }
11334
10210
 
11335
 
    LogFlowThisFunc (("rc=%08X\n", rc));
 
10211
    LogFlowThisFunc(("rc=%Rhrc [%s]\n", rc, Global::stringifyMachineState(mData->mMachineState) ));
11336
10212
    LogFlowThisFuncLeave();
11337
10213
    return rc;
11338
10214
}
11344
10220
 */
11345
10221
HRESULT SessionMachine::updateMachineStateOnClient()
11346
10222
{
11347
 
    AutoCaller autoCaller (this);
 
10223
    AutoCaller autoCaller(this);
11348
10224
    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
11349
10225
 
11350
 
    ComPtr <IInternalSessionControl> directControl;
 
10226
    ComPtr<IInternalSessionControl> directControl;
11351
10227
    {
11352
 
        AutoReadLock alock (this);
11353
 
        AssertReturn (!!mData, E_FAIL);
 
10228
        AutoReadLock alock(this);
 
10229
        AssertReturn(!!mData, E_FAIL);
11354
10230
        directControl = mData->mSession.mDirectControl;
11355
10231
 
11356
10232
        /* directControl may be already set to NULL here in #OnSessionEnd()
11365
10241
        if (mData->mSession.mState == SessionState_Closing)
11366
10242
            return S_OK;
11367
10243
 
11368
 
        AssertReturn (!directControl.isNull(), E_FAIL);
 
10244
        AssertReturn(!directControl.isNull(), E_FAIL);
11369
10245
    }
11370
10246
 
11371
10247
    return directControl->UpdateMachineState (mData->mMachineState);
11372
10248
}
11373
 
 
11374
 
/* static */
11375
 
DECLCALLBACK(int) SessionMachine::taskHandler (RTTHREAD /* thread */, void *pvUser)
11376
 
{
11377
 
    AssertReturn (pvUser, VERR_INVALID_POINTER);
11378
 
 
11379
 
    Task *task = static_cast <Task *> (pvUser);
11380
 
    task->handler();
11381
 
 
11382
 
    // it's our responsibility to delete the task
11383
 
    delete task;
11384
 
 
11385
 
    return 0;
11386
 
}
11387
 
 
11388
 
/////////////////////////////////////////////////////////////////////////////
11389
 
// SnapshotMachine class
11390
 
/////////////////////////////////////////////////////////////////////////////
11391
 
 
11392
 
DEFINE_EMPTY_CTOR_DTOR (SnapshotMachine)
11393
 
 
11394
 
HRESULT SnapshotMachine::FinalConstruct()
11395
 
{
11396
 
    LogFlowThisFunc (("\n"));
11397
 
 
11398
 
    /* set the proper type to indicate we're the SnapshotMachine instance */
11399
 
    unconst (mType) = IsSnapshotMachine;
11400
 
 
11401
 
    return S_OK;
11402
 
}
11403
 
 
11404
 
void SnapshotMachine::FinalRelease()
11405
 
{
11406
 
    LogFlowThisFunc (("\n"));
11407
 
 
11408
 
    uninit();
11409
 
}
11410
 
 
11411
 
/**
11412
 
 *  Initializes the SnapshotMachine object when taking a snapshot.
11413
 
 *
11414
 
 *  @param aSessionMachine  machine to take a snapshot from
11415
 
 *  @param aSnapshotId      snapshot ID of this snapshot machine
11416
 
 *  @param aStateFilePath   file where the execution state will be later saved
11417
 
 *                          (or NULL for the offline snapshot)
11418
 
 *
11419
 
 *  @note The aSessionMachine must be locked for writing.
11420
 
 */
11421
 
HRESULT SnapshotMachine::init (SessionMachine *aSessionMachine,
11422
 
                               IN_GUID aSnapshotId,
11423
 
                               IN_BSTR aStateFilePath)
11424
 
{
11425
 
    LogFlowThisFuncEnter();
11426
 
    LogFlowThisFunc (("mName={%ls}\n", aSessionMachine->mUserData->mName.raw()));
11427
 
 
11428
 
    AssertReturn (aSessionMachine && !Guid (aSnapshotId).isEmpty(), E_INVALIDARG);
11429
 
 
11430
 
    /* Enclose the state transition NotReady->InInit->Ready */
11431
 
    AutoInitSpan autoInitSpan (this);
11432
 
    AssertReturn (autoInitSpan.isOk(), E_FAIL);
11433
 
 
11434
 
    AssertReturn (aSessionMachine->isWriteLockOnCurrentThread(), E_FAIL);
11435
 
 
11436
 
    mSnapshotId = aSnapshotId;
11437
 
 
11438
 
    /* memorize the primary Machine instance (i.e. not SessionMachine!) */
11439
 
    unconst (mPeer) = aSessionMachine->mPeer;
11440
 
    /* share the parent pointer */
11441
 
    unconst (mParent) = mPeer->mParent;
11442
 
 
11443
 
    /* take the pointer to Data to share */
11444
 
    mData.share (mPeer->mData);
11445
 
 
11446
 
    /* take the pointer to UserData to share (our UserData must always be the
11447
 
     * same as Machine's data) */
11448
 
    mUserData.share (mPeer->mUserData);
11449
 
    /* make a private copy of all other data (recent changes from SessionMachine) */
11450
 
    mHWData.attachCopy (aSessionMachine->mHWData);
11451
 
    mHDData.attachCopy (aSessionMachine->mHDData);
11452
 
 
11453
 
    /* SSData is always unique for SnapshotMachine */
11454
 
    mSSData.allocate();
11455
 
    mSSData->mStateFilePath = aStateFilePath;
11456
 
 
11457
 
    HRESULT rc = S_OK;
11458
 
 
11459
 
    /* create copies of all shared folders (mHWData after attiching a copy
11460
 
     * contains just references to original objects) */
11461
 
    for (HWData::SharedFolderList::iterator
11462
 
         it = mHWData->mSharedFolders.begin();
11463
 
         it != mHWData->mSharedFolders.end();
11464
 
         ++ it)
11465
 
    {
11466
 
        ComObjPtr <SharedFolder> folder;
11467
 
        folder.createObject();
11468
 
        rc = folder->initCopy (this, *it);
11469
 
        CheckComRCReturnRC (rc);
11470
 
        *it = folder;
11471
 
    }
11472
 
 
11473
 
    /* associate hard disks with the snapshot
11474
 
     * (Machine::uninitDataAndChildObjects() will deassociate at destruction) */
11475
 
    for (HDData::AttachmentList::const_iterator
11476
 
         it = mHDData->mAttachments.begin();
11477
 
         it != mHDData->mAttachments.end();
11478
 
         ++ it)
11479
 
    {
11480
 
        rc = (*it)->hardDisk()->attachTo (mData->mUuid, mSnapshotId);
11481
 
        AssertComRC (rc);
11482
 
    }
11483
 
 
11484
 
    /* create copies of all storage controllers (mStorageControllerData
11485
 
     * after attaching a copy contains just references to original objects) */
11486
 
    mStorageControllers.allocate();
11487
 
    for (StorageControllerList::const_iterator
11488
 
         it = aSessionMachine->mStorageControllers->begin();
11489
 
         it != aSessionMachine->mStorageControllers->end();
11490
 
         ++ it)
11491
 
    {
11492
 
        ComObjPtr <StorageController> ctrl;
11493
 
        ctrl.createObject();
11494
 
        ctrl->initCopy (this, *it);
11495
 
        mStorageControllers->push_back(ctrl);
11496
 
    }
11497
 
 
11498
 
    /* create all other child objects that will be immutable private copies */
11499
 
 
11500
 
    unconst (mBIOSSettings).createObject();
11501
 
    mBIOSSettings->initCopy (this, mPeer->mBIOSSettings);
11502
 
 
11503
 
#ifdef VBOX_WITH_VRDP
11504
 
    unconst (mVRDPServer).createObject();
11505
 
    mVRDPServer->initCopy (this, mPeer->mVRDPServer);
11506
 
#endif
11507
 
 
11508
 
    unconst (mDVDDrive).createObject();
11509
 
    mDVDDrive->initCopy (this, mPeer->mDVDDrive);
11510
 
 
11511
 
    unconst (mFloppyDrive).createObject();
11512
 
    mFloppyDrive->initCopy (this, mPeer->mFloppyDrive);
11513
 
 
11514
 
    unconst (mAudioAdapter).createObject();
11515
 
    mAudioAdapter->initCopy (this, mPeer->mAudioAdapter);
11516
 
 
11517
 
    unconst (mUSBController).createObject();
11518
 
    mUSBController->initCopy (this, mPeer->mUSBController);
11519
 
 
11520
 
    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); slot ++)
11521
 
    {
11522
 
        unconst (mNetworkAdapters [slot]).createObject();
11523
 
        mNetworkAdapters [slot]->initCopy (this, mPeer->mNetworkAdapters [slot]);
11524
 
    }
11525
 
 
11526
 
    for (ULONG slot = 0; slot < RT_ELEMENTS (mSerialPorts); slot ++)
11527
 
    {
11528
 
        unconst (mSerialPorts [slot]).createObject();
11529
 
        mSerialPorts [slot]->initCopy (this, mPeer->mSerialPorts [slot]);
11530
 
    }
11531
 
 
11532
 
    for (ULONG slot = 0; slot < RT_ELEMENTS (mParallelPorts); slot ++)
11533
 
    {
11534
 
        unconst (mParallelPorts [slot]).createObject();
11535
 
        mParallelPorts [slot]->initCopy (this, mPeer->mParallelPorts [slot]);
11536
 
    }
11537
 
 
11538
 
    /* Confirm a successful initialization when it's the case */
11539
 
    autoInitSpan.setSucceeded();
11540
 
 
11541
 
    LogFlowThisFuncLeave();
11542
 
    return S_OK;
11543
 
}
11544
 
 
11545
 
/**
11546
 
 *  Initializes the SnapshotMachine object when loading from the settings file.
11547
 
 *
11548
 
 *  @param aMachine machine the snapshot belngs to
11549
 
 *  @param aHWNode          <Hardware> node
11550
 
 *  @param aHDAsNode        <HardDiskAttachments> node
11551
 
 *  @param aSnapshotId      snapshot ID of this snapshot machine
11552
 
 *  @param aStateFilePath   file where the execution state is saved
11553
 
 *                          (or NULL for the offline snapshot)
11554
 
 *
11555
 
 *  @note Doesn't lock anything.
11556
 
 */
11557
 
HRESULT SnapshotMachine::init (Machine *aMachine,
11558
 
                               const settings::Key &aHWNode,
11559
 
                               const settings::Key &aHDAsNode,
11560
 
                               IN_GUID aSnapshotId, IN_BSTR aStateFilePath)
11561
 
{
11562
 
    LogFlowThisFuncEnter();
11563
 
    LogFlowThisFunc (("mName={%ls}\n", aMachine->mUserData->mName.raw()));
11564
 
 
11565
 
    AssertReturn (aMachine && !aHWNode.isNull() && !aHDAsNode.isNull() &&
11566
 
                  !Guid (aSnapshotId).isEmpty(),
11567
 
                  E_INVALIDARG);
11568
 
 
11569
 
    /* Enclose the state transition NotReady->InInit->Ready */
11570
 
    AutoInitSpan autoInitSpan (this);
11571
 
    AssertReturn (autoInitSpan.isOk(), E_FAIL);
11572
 
 
11573
 
    /* Don't need to lock aMachine when VirtualBox is starting up */
11574
 
 
11575
 
    mSnapshotId = aSnapshotId;
11576
 
 
11577
 
    /* memorize the primary Machine instance */
11578
 
    unconst (mPeer) = aMachine;
11579
 
    /* share the parent pointer */
11580
 
    unconst (mParent) = mPeer->mParent;
11581
 
 
11582
 
    /* take the pointer to Data to share */
11583
 
    mData.share (mPeer->mData);
11584
 
    /*
11585
 
     *  take the pointer to UserData to share
11586
 
     *  (our UserData must always be the same as Machine's data)
11587
 
     */
11588
 
    mUserData.share (mPeer->mUserData);
11589
 
    /* allocate private copies of all other data (will be loaded from settings) */
11590
 
    mHWData.allocate();
11591
 
    mHDData.allocate();
11592
 
    mStorageControllers.allocate();
11593
 
 
11594
 
    /* SSData is always unique for SnapshotMachine */
11595
 
    mSSData.allocate();
11596
 
    mSSData->mStateFilePath = aStateFilePath;
11597
 
 
11598
 
    /* create all other child objects that will be immutable private copies */
11599
 
 
11600
 
    unconst (mBIOSSettings).createObject();
11601
 
    mBIOSSettings->init (this);
11602
 
 
11603
 
#ifdef VBOX_WITH_VRDP
11604
 
    unconst (mVRDPServer).createObject();
11605
 
    mVRDPServer->init (this);
11606
 
#endif
11607
 
 
11608
 
    unconst (mDVDDrive).createObject();
11609
 
    mDVDDrive->init (this);
11610
 
 
11611
 
    unconst (mFloppyDrive).createObject();
11612
 
    mFloppyDrive->init (this);
11613
 
 
11614
 
    unconst (mAudioAdapter).createObject();
11615
 
    mAudioAdapter->init (this);
11616
 
 
11617
 
    unconst (mUSBController).createObject();
11618
 
    mUSBController->init (this);
11619
 
 
11620
 
    for (ULONG slot = 0; slot < RT_ELEMENTS (mNetworkAdapters); slot ++)
11621
 
    {
11622
 
        unconst (mNetworkAdapters [slot]).createObject();
11623
 
        mNetworkAdapters [slot]->init (this, slot);
11624
 
    }
11625
 
 
11626
 
    for (ULONG slot = 0; slot < RT_ELEMENTS (mSerialPorts); slot ++)
11627
 
    {
11628
 
        unconst (mSerialPorts [slot]).createObject();
11629
 
        mSerialPorts [slot]->init (this, slot);
11630
 
    }
11631
 
 
11632
 
    for (ULONG slot = 0; slot < RT_ELEMENTS (mParallelPorts); slot ++)
11633
 
    {
11634
 
        unconst (mParallelPorts [slot]).createObject();
11635
 
        mParallelPorts [slot]->init (this, slot);
11636
 
    }
11637
 
 
11638
 
    /* load hardware and harddisk settings */
11639
 
 
11640
 
    HRESULT rc = loadHardware (aHWNode);
11641
 
    if (SUCCEEDED (rc))
11642
 
        rc = loadStorageControllers (aHDAsNode, true /* aRegistered */, &mSnapshotId);
11643
 
 
11644
 
    if (SUCCEEDED (rc))
11645
 
    {
11646
 
        /* commit all changes made during the initialization */
11647
 
        commit();
11648
 
    }
11649
 
 
11650
 
    /* Confirm a successful initialization when it's the case */
11651
 
    if (SUCCEEDED (rc))
11652
 
        autoInitSpan.setSucceeded();
11653
 
 
11654
 
    LogFlowThisFuncLeave();
11655
 
    return rc;
11656
 
}
11657
 
 
11658
 
/**
11659
 
 *  Uninitializes this SnapshotMachine object.
11660
 
 */
11661
 
void SnapshotMachine::uninit()
11662
 
{
11663
 
    LogFlowThisFuncEnter();
11664
 
 
11665
 
    /* Enclose the state transition Ready->InUninit->NotReady */
11666
 
    AutoUninitSpan autoUninitSpan (this);
11667
 
    if (autoUninitSpan.uninitDone())
11668
 
        return;
11669
 
 
11670
 
    uninitDataAndChildObjects();
11671
 
 
11672
 
    /* free the essential data structure last */
11673
 
    mData.free();
11674
 
 
11675
 
    unconst (mParent).setNull();
11676
 
    unconst (mPeer).setNull();
11677
 
 
11678
 
    LogFlowThisFuncLeave();
11679
 
}
11680
 
 
11681
 
// util::Lockable interface
11682
 
////////////////////////////////////////////////////////////////////////////////
11683
 
 
11684
 
/**
11685
 
 *  Overrides VirtualBoxBase::lockHandle() in order to share the lock handle
11686
 
 *  with the primary Machine instance (mPeer).
11687
 
 */
11688
 
RWLockHandle *SnapshotMachine::lockHandle() const
11689
 
{
11690
 
    AssertReturn (!mPeer.isNull(), NULL);
11691
 
    return mPeer->lockHandle();
11692
 
}
11693
 
 
11694
 
// public methods only for internal purposes
11695
 
////////////////////////////////////////////////////////////////////////////////
11696
 
 
11697
 
/**
11698
 
 *  Called by the snapshot object associated with this SnapshotMachine when
11699
 
 *  snapshot data such as name or description is changed.
11700
 
 *
11701
 
 *  @note Locks this object for writing.
11702
 
 */
11703
 
HRESULT SnapshotMachine::onSnapshotChange (Snapshot *aSnapshot)
11704
 
{
11705
 
    AutoWriteLock alock (this);
11706
 
 
11707
 
    mPeer->saveSnapshotSettings (aSnapshot, SaveSS_UpdateAttrsOp);
11708
 
 
11709
 
    /* inform callbacks */
11710
 
    mParent->onSnapshotChange (mData->mUuid, aSnapshot->data().mId);
11711
 
 
11712
 
    return S_OK;
11713
 
}
11714
 
/* vi: set tabstop=4 shiftwidth=4 expandtab: */